Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2148f18f authored by Rob Clark's avatar Rob Clark Committed by Dave Airlie
Browse files

drm: fix fb-helper vs MST dangling connector ptrs (v2)

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


Cc: stable@vger.kernel.org #v3.17+
Signed-off-by: default avatarRob Clark <robdclark@gmail.com>
Signed-off-by: default avatarDave Airlie <airlied@redhat.com>
parent 1c999c47
Loading
Loading
Loading
Loading
+30 −0
Original line number Original line Diff line number Diff line
@@ -145,6 +145,31 @@ int drm_fb_helper_add_one_connector(struct drm_fb_helper *fb_helper, struct drm_
}
}
EXPORT_SYMBOL(drm_fb_helper_add_one_connector);
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,
int drm_fb_helper_remove_one_connector(struct drm_fb_helper *fb_helper,
				       struct drm_connector *connector)
				       struct drm_connector *connector)
{
{
@@ -167,6 +192,11 @@ int drm_fb_helper_remove_one_connector(struct drm_fb_helper *fb_helper,
	}
	}
	fb_helper->connector_count--;
	fb_helper->connector_count--;
	kfree(fb_helper_connector);
	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;
	return 0;
}
}
EXPORT_SYMBOL(drm_fb_helper_remove_one_connector);
EXPORT_SYMBOL(drm_fb_helper_remove_one_connector);