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

Commit 752d2635 authored by Chris Wilson's avatar Chris Wilson Committed by Dave Airlie
Browse files

drm: Take lock around probes for drm_fb_helper_hotplug_event



We need to hold the dev->mode_config.mutex whilst detecting the output
status. But we also need to drop it for the call into
drm_fb_helper_single_fb_probe(), which indirectly acquires the lock when
attaching the fbcon.

Failure to do so exposes a race with normal output probing. Detected by
adding some warnings that the mutex is held to the backend detect routines:

[   17.772456] WARNING: at drivers/gpu/drm/i915/intel_crt.c:471 intel_crt_detect+0x3e/0x373 [i915]()
[   17.772458] Hardware name: Latitude E6400
[   17.772460] Modules linked in: ....
[   17.772582] Pid: 11, comm: kworker/0:1 Tainted: G        W 2.6.38.4-custom.2 #8
[   17.772584] Call Trace:
[   17.772591]  [<ffffffff81046af5>] ? warn_slowpath_common+0x78/0x8c
[   17.772603]  [<ffffffffa03f3e5c>] ? intel_crt_detect+0x3e/0x373 [i915]
[   17.772612]  [<ffffffffa0355d49>] ?  drm_helper_probe_single_connector_modes+0xbf/0x2af [drm_kms_helper]
[   17.772619]  [<ffffffffa03534d5>] ?  drm_fb_helper_probe_connector_modes+0x39/0x4d [drm_kms_helper]
[   17.772625]  [<ffffffffa0354760>] ?  drm_fb_helper_hotplug_event+0xa5/0xc3 [drm_kms_helper]
[   17.772633]  [<ffffffffa035577f>] ? output_poll_execute+0x146/0x17c [drm_kms_helper]
[   17.772638]  [<ffffffff81193c01>] ? cfq_init_queue+0x247/0x345
[   17.772644]  [<ffffffffa0355639>] ? output_poll_execute+0x0/0x17c [drm_kms_helper]
[   17.772648]  [<ffffffff8105b540>] ? process_one_work+0x193/0x28e
[   17.772652]  [<ffffffff8105c6bc>] ? worker_thread+0xef/0x172
[   17.772655]  [<ffffffff8105c5cd>] ? worker_thread+0x0/0x172
[   17.772658]  [<ffffffff8105c5cd>] ? worker_thread+0x0/0x172
[   17.772663]  [<ffffffff8105f767>] ? kthread+0x7a/0x82
[   17.772668]  [<ffffffff8100a724>] ? kernel_thread_helper+0x4/0x10
[   17.772671]  [<ffffffff8105f6ed>] ? kthread+0x0/0x82
[   17.772674]  [<ffffffff8100a720>] ? kernel_thread_helper+0x0/0x10

Reported-by: default avatarFrederik Himpe <fhimpe@telenet.be>
References: https://bugs.freedesktop.org/show_bug.cgi?id=36394


Signed-off-by: default avatarChris Wilson <chris@chris-wilson.co.uk>
Signed-off-by: default avatarDave Airlie <airlied@redhat.com>
parent 8eea1be1
Loading
Loading
Loading
Loading
+22 −4
Original line number Original line Diff line number Diff line
@@ -1516,17 +1516,33 @@ bool drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper, int bpp_sel)
}
}
EXPORT_SYMBOL(drm_fb_helper_initial_config);
EXPORT_SYMBOL(drm_fb_helper_initial_config);


bool drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper)
/**
 * drm_fb_helper_hotplug_event - respond to a hotplug notification by
 *                               probing all the outputs attached to the fb.
 * @fb_helper: the drm_fb_helper
 *
 * LOCKING:
 * Called at runtime, must take mode config lock.
 *
 * Scan the connectors attached to the fb_helper and try to put together a
 * setup after *notification of a change in output configuration.
 *
 * RETURNS:
 * 0 on success and a non-zero error code otherwise.
 */
int drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper)
{
{
	struct drm_device *dev = fb_helper->dev;
	int count = 0;
	int count = 0;
	u32 max_width, max_height, bpp_sel;
	u32 max_width, max_height, bpp_sel;
	bool bound = false, crtcs_bound = false;
	bool bound = false, crtcs_bound = false;
	struct drm_crtc *crtc;
	struct drm_crtc *crtc;


	if (!fb_helper->fb)
	if (!fb_helper->fb)
		return false;
		return 0;


	list_for_each_entry(crtc, &fb_helper->dev->mode_config.crtc_list, head) {
	mutex_lock(&dev->mode_config.mutex);
	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
		if (crtc->fb)
		if (crtc->fb)
			crtcs_bound = true;
			crtcs_bound = true;
		if (crtc->fb == fb_helper->fb)
		if (crtc->fb == fb_helper->fb)
@@ -1535,7 +1551,8 @@ bool drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper)


	if (!bound && crtcs_bound) {
	if (!bound && crtcs_bound) {
		fb_helper->delayed_hotplug = true;
		fb_helper->delayed_hotplug = true;
		return false;
		mutex_unlock(&dev->mode_config.mutex);
		return 0;
	}
	}
	DRM_DEBUG_KMS("\n");
	DRM_DEBUG_KMS("\n");


@@ -1546,6 +1563,7 @@ bool drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper)
	count = drm_fb_helper_probe_connector_modes(fb_helper, max_width,
	count = drm_fb_helper_probe_connector_modes(fb_helper, max_width,
						    max_height);
						    max_height);
	drm_setup_crtcs(fb_helper);
	drm_setup_crtcs(fb_helper);
	mutex_unlock(&dev->mode_config.mutex);


	return drm_fb_helper_single_fb_probe(fb_helper, bpp_sel);
	return drm_fb_helper_single_fb_probe(fb_helper, bpp_sel);
}
}
+1 −1
Original line number Original line Diff line number Diff line
@@ -127,7 +127,7 @@ void drm_fb_helper_fill_fix(struct fb_info *info, uint32_t pitch,


int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info);
int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info);


bool drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper);
int drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper);
bool drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper, int bpp_sel);
bool drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper, int bpp_sel);
int drm_fb_helper_single_add_all_connectors(struct drm_fb_helper *fb_helper);
int drm_fb_helper_single_add_all_connectors(struct drm_fb_helper *fb_helper);
int drm_fb_helper_debug_enter(struct fb_info *info);
int drm_fb_helper_debug_enter(struct fb_info *info);