| From 2148f18fdb45f31ca269a7787fbc24053cd42e70 Mon Sep 17 00:00:00 2001 |
| From: Rob Clark <robdclark@gmail.com> |
| Date: Mon, 26 Jan 2015 10:11:08 -0500 |
| Subject: drm: fix fb-helper vs MST dangling connector ptrs (v2) |
| |
| From: Rob Clark <robdclark@gmail.com> |
| |
| commit 2148f18fdb45f31ca269a7787fbc24053cd42e70 upstream. |
| |
| VT switch back/forth from console to xserver (for example) has potential |
| to go horribly wrong if a dynamic DP MST connector ends up in the saved |
| modeset that is restored when switching back to fbcon. |
| |
| When removing a dynamic connector, don't forget to clean up the saved |
| state. |
| |
| v1: original |
| v2: null out set->fb if no more connectors to avoid making i915 cranky |
| |
| Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1184968 |
| Signed-off-by: Rob Clark <robdclark@gmail.com> |
| Signed-off-by: Dave Airlie <airlied@redhat.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| drivers/gpu/drm/drm_fb_helper.c | 30 ++++++++++++++++++++++++++++++ |
| 1 file changed, 30 insertions(+) |
| |
| --- a/drivers/gpu/drm/drm_fb_helper.c |
| +++ b/drivers/gpu/drm/drm_fb_helper.c |
| @@ -145,6 +145,31 @@ int drm_fb_helper_add_one_connector(stru |
| } |
| EXPORT_SYMBOL(drm_fb_helper_add_one_connector); |
| |
| +static void remove_from_modeset(struct drm_mode_set *set, |
| + struct drm_connector *connector) |
| +{ |
| + int i, j; |
| + |
| + for (i = 0; i < set->num_connectors; i++) { |
| + if (set->connectors[i] == connector) |
| + break; |
| + } |
| + |
| + if (i == set->num_connectors) |
| + return; |
| + |
| + for (j = i + 1; j < set->num_connectors; j++) { |
| + set->connectors[j - 1] = set->connectors[j]; |
| + } |
| + set->num_connectors--; |
| + |
| + /* because i915 is pissy about this.. |
| + * TODO maybe need to makes sure we set it back to !=NULL somewhere? |
| + */ |
| + if (set->num_connectors == 0) |
| + set->fb = NULL; |
| +} |
| + |
| int drm_fb_helper_remove_one_connector(struct drm_fb_helper *fb_helper, |
| struct drm_connector *connector) |
| { |
| @@ -167,6 +192,11 @@ int drm_fb_helper_remove_one_connector(s |
| } |
| fb_helper->connector_count--; |
| kfree(fb_helper_connector); |
| + |
| + /* also cleanup dangling references to the connector: */ |
| + for (i = 0; i < fb_helper->crtc_count; i++) |
| + remove_from_modeset(&fb_helper->crtc_info[i].mode_set, connector); |
| + |
| return 0; |
| } |
| EXPORT_SYMBOL(drm_fb_helper_remove_one_connector); |