sna: Check link-status after a hotplug event

If the modeset fails, or the link subsequently fails, we need to perform
the modeset again. To signal this the kernel sends us a hotplug uevent
with a new link-status property set to bad. The kernel may have to take
some corrective action which invalidates the current mode and so the
following modeset may fail and we need to go and report to the client
for them to choose the next course of action (reconfigure the displays).
At the very least the kernel *requires* us to reapply the current mode.

Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
This commit is contained in:
Chris Wilson
2016-10-25 16:21:03 +01:00
parent 860c3664fe
commit 880917deee

View File

@@ -257,6 +257,8 @@ struct sna_output {
int connector_type;
int connector_type_id;
uint32_t link_status_idx;
uint32_t edid_idx;
uint32_t edid_blob_id;
uint32_t edid_len;
@@ -311,6 +313,8 @@ enum { /* XXX copied from hw/xfree86/modes/xf86Crtc.c */
static void __sna_output_dpms(xf86OutputPtr output, int dpms, int fixup);
static void sna_crtc_disable_cursor(struct sna *sna, struct sna_crtc *crtc);
static bool sna_crtc_flip(struct sna *sna, struct sna_crtc *crtc,
struct kgem_bo *bo, int x, int y);
static bool is_zaphod(ScrnInfoPtr scrn)
{
@@ -5140,6 +5144,8 @@ reset:
sna_output->id = compat_conn.conn.connector_id;
sna_output->is_panel = is_panel(compat_conn.conn.connector_type);
sna_output->edid_idx = find_property(sna, sna_output, "EDID");
sna_output->link_status_idx =
find_property(sna, sna_output, "link-status");
if (find_property(sna, sna_output, "scaling mode") != -1)
sna_output->add_default_modes =
xf86ReturnOptValBool(output->options, OPTION_DEFAULT_MODES, TRUE);
@@ -5302,6 +5308,45 @@ bool sna_mode_find_hotplug_connector(struct sna *sna, unsigned id)
return false;
}
static bool
output_retrain_link(struct sna *sna, struct sna_output *output)
{
struct sna_crtc *crtc = to_sna_crtc(output->base->crtc);
int crtc_x = crtc->offset & 0xffff;
int crtc_y = crtc->offset >> 16;
return sna_crtc_flip(sna, crtc, crtc->bo, crtc_x, crtc_y);
}
static bool
output_check_link(struct sna *sna, struct sna_output *output)
{
uint64_t link_status;
if (!output->base->crtc)
return true;
if (output->link_status_idx == -1)
return true;
#define LINK_STATUS_GOOD 0
link_status = output->prop_values[output->link_status_idx];
DBG(("%s: link_status=%d\n", __FUNCTION__, link_status));
if (link_status == LINK_STATUS_GOOD)
return true;
/* Perform a modeset as required for "link-status" = BAD */
if (!output_retrain_link(sna, output))
return false;
/* Query the "link-status" again to confirm the modeset */
update_properties(sna, output);
link_status = output->prop_values[output->link_status_idx];
DBG(("%s: link_status=%d after modeset\n", __FUNCTION__, link_status));
return link_status == LINK_STATUS_GOOD;
}
static bool
output_check_status(struct sna *sna, struct sna_output *output)
{
@@ -5311,9 +5356,6 @@ output_check_status(struct sna *sna, struct sna_output *output)
xf86OutputStatus status;
char *edid;
if (output->reprobe)
return false;
VG_CLEAR(compat_conn);
compat_conn.conn.connection = -1;
@@ -5330,6 +5372,12 @@ output_check_status(struct sna *sna, struct sna_output *output)
&compat_conn.conn) == 0)
output->update_properties = false;
if (!output_check_link(sna, output))
return false;
if (output->reprobe)
return false;
switch (compat_conn.conn.connection) {
case DRM_MODE_CONNECTED:
status = XF86OutputStatusConnected;