diff options
author | Martin Peres <martin.peres@linux.intel.com> | 2017-04-10 16:48:21 +0300 |
---|---|---|
committer | Adam Jackson <ajax@redhat.com> | 2017-10-04 14:37:45 -0400 |
commit | 787655d5df0c8c43e5e424af3e6e35b8daf54a7d (patch) | |
tree | b37c2bfff44a47127a9c9bca124b9321cbc6999e /hw | |
parent | 126144c2355ce5a3a350f15ef97389c7f34bb6fb (diff) |
modesetting: re-set the crtc's mode when link-status goes BAD
Despite all the careful planning of the kernel, a link may become
insufficient to handle the currently-set mode. At this point, the
kernel should mark this particular configuration as being broken
and potentially prune the mode before setting the offending connector's
link-status to BAD and send the userspace a hotplug event. This may
happen right after a modeset or later on.
Upon receiving a hot-plug event, we iterate through the connectors to
re-apply the currently-set mode on all the connectors that have a
link-status property set to BAD. The kernel may be able to get the
link to work by dropping to using a lower link bpp (with the same
display bpp). However, the modeset may fail if the kernel has pruned
the mode, so to make users aware of this problem a warning is outputed
in the logs to warn about having a potentially-black display.
This patch does not modify the current behaviour of always propagating
the events to the randr clients. This allows desktop environments to
re-probe the connectors and select a new resolution based on the new
(currated) mode list if a mode disapeared. This behaviour is expected in
order to pass the Display Port compliance tests.
Signed-off-by: Martin Peres <martin.peres@linux.intel.com>
Reviewed-by: Eric Anholt <eric@anholt.net>
(cherry picked from commit bcee1b76aa0db8525b491485e90b8740763d7de6)
Diffstat (limited to 'hw')
-rw-r--r-- | hw/xfree86/drivers/modesetting/drmmode_display.c | 51 |
1 files changed, 51 insertions, 0 deletions
diff --git a/hw/xfree86/drivers/modesetting/drmmode_display.c b/hw/xfree86/drivers/modesetting/drmmode_display.c index 415c1b38d..6236fb0b6 100644 --- a/hw/xfree86/drivers/modesetting/drmmode_display.c +++ b/hw/xfree86/drivers/modesetting/drmmode_display.c @@ -2263,6 +2263,10 @@ drmmode_setup_colormap(ScreenPtr pScreen, ScrnInfoPtr pScrn) } #ifdef CONFIG_UDEV_KMS + +#define DRM_MODE_LINK_STATUS_GOOD 0 +#define DRM_MODE_LINK_STATUS_BAD 1 + static void drmmode_handle_uevents(int fd, void *closure) { @@ -2282,6 +2286,49 @@ drmmode_handle_uevents(int fd, void *closure) if (!found) return; + /* Try to re-set the mode on all the connectors with a BAD link-state: + * This may happen if a link degrades and a new modeset is necessary, using + * different link-training parameters. If the kernel found that the current + * mode is not achievable anymore, it should have pruned the mode before + * sending the hotplug event. Try to re-set the currently-set mode to keep + * the display alive, this will fail if the mode has been pruned. + * In any case, we will send randr events for the Desktop Environment to + * deal with it, if it wants to. + */ + for (i = 0; i < config->num_output; i++) { + xf86OutputPtr output = config->output[i]; + drmmode_output_private_ptr drmmode_output = output->driver_private; + uint32_t con_id = drmmode_output->mode_output->connector_id; + drmModeConnectorPtr koutput; + + /* Get an updated view of the properties for the current connector and + * look for the link-status property + */ + koutput = drmModeGetConnectorCurrent(drmmode->fd, con_id); + for (j = 0; koutput && j < koutput->count_props; j++) { + drmModePropertyPtr props; + props = drmModeGetProperty(drmmode->fd, koutput->props[j]); + if (props && props->flags & DRM_MODE_PROP_ENUM && + !strcmp(props->name, "link-status") && + koutput->prop_values[j] == DRM_MODE_LINK_STATUS_BAD) { + xf86CrtcPtr crtc = output->crtc; + if (!crtc) + continue; + + /* the connector got a link failure, re-set the current mode */ + drmmode_set_mode_major(crtc, &crtc->mode, crtc->rotation, + crtc->x, crtc->y); + + xf86DrvMsg(scrn->scrnIndex, X_WARNING, + "hotplug event: connector %u's link-state is BAD, " + "tried resetting the current mode. You may be left" + "with a black screen if this fails...\n", con_id); + } + drmModeFreeProperty(props); + } + drmModeFreeConnector(koutput); + } + mode_res = drmModeGetResources(drmmode->fd); if (!mode_res) goto out; @@ -2346,6 +2393,10 @@ out_free_res: out: RRGetInfo(xf86ScrnToScreen(scrn), TRUE); } + +#undef DRM_MODE_LINK_STATUS_BAD +#undef DRM_MODE_LINK_STATUS_GOOD + #endif void |