Commit 7394371d85699a1d6d49b61f65583d6cd902a6a2
Committed by
Dave Airlie
1 parent
da05a5a71a
Exists in
master
and in
4 other branches
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: Frederik Himpe <fhimpe@telenet.be> References: https://bugs.freedesktop.org/show_bug.cgi?id=36394 Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Signed-off-by: Dave Airlie <airlied@redhat.com>
Showing 2 changed files with 23 additions and 5 deletions Side-by-side Diff
drivers/gpu/drm/drm_fb_helper.c
... | ... | @@ -1516,17 +1516,33 @@ |
1516 | 1516 | } |
1517 | 1517 | EXPORT_SYMBOL(drm_fb_helper_initial_config); |
1518 | 1518 | |
1519 | -bool drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper) | |
1519 | +/** | |
1520 | + * drm_fb_helper_hotplug_event - respond to a hotplug notification by | |
1521 | + * probing all the outputs attached to the fb. | |
1522 | + * @fb_helper: the drm_fb_helper | |
1523 | + * | |
1524 | + * LOCKING: | |
1525 | + * Called at runtime, must take mode config lock. | |
1526 | + * | |
1527 | + * Scan the connectors attached to the fb_helper and try to put together a | |
1528 | + * setup after *notification of a change in output configuration. | |
1529 | + * | |
1530 | + * RETURNS: | |
1531 | + * 0 on success and a non-zero error code otherwise. | |
1532 | + */ | |
1533 | +int drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper) | |
1520 | 1534 | { |
1535 | + struct drm_device *dev = fb_helper->dev; | |
1521 | 1536 | int count = 0; |
1522 | 1537 | u32 max_width, max_height, bpp_sel; |
1523 | 1538 | bool bound = false, crtcs_bound = false; |
1524 | 1539 | struct drm_crtc *crtc; |
1525 | 1540 | |
1526 | 1541 | if (!fb_helper->fb) |
1527 | - return false; | |
1542 | + return 0; | |
1528 | 1543 | |
1529 | - list_for_each_entry(crtc, &fb_helper->dev->mode_config.crtc_list, head) { | |
1544 | + mutex_lock(&dev->mode_config.mutex); | |
1545 | + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { | |
1530 | 1546 | if (crtc->fb) |
1531 | 1547 | crtcs_bound = true; |
1532 | 1548 | if (crtc->fb == fb_helper->fb) |
... | ... | @@ -1535,7 +1551,8 @@ |
1535 | 1551 | |
1536 | 1552 | if (!bound && crtcs_bound) { |
1537 | 1553 | fb_helper->delayed_hotplug = true; |
1538 | - return false; | |
1554 | + mutex_unlock(&dev->mode_config.mutex); | |
1555 | + return 0; | |
1539 | 1556 | } |
1540 | 1557 | DRM_DEBUG_KMS("\n"); |
1541 | 1558 | |
... | ... | @@ -1546,6 +1563,7 @@ |
1546 | 1563 | count = drm_fb_helper_probe_connector_modes(fb_helper, max_width, |
1547 | 1564 | max_height); |
1548 | 1565 | drm_setup_crtcs(fb_helper); |
1566 | + mutex_unlock(&dev->mode_config.mutex); | |
1549 | 1567 | |
1550 | 1568 | return drm_fb_helper_single_fb_probe(fb_helper, bpp_sel); |
1551 | 1569 | } |
include/drm/drm_fb_helper.h
... | ... | @@ -127,7 +127,7 @@ |
127 | 127 | |
128 | 128 | int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info); |
129 | 129 | |
130 | -bool drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper); | |
130 | +int drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper); | |
131 | 131 | bool drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper, int bpp_sel); |
132 | 132 | int drm_fb_helper_single_add_all_connectors(struct drm_fb_helper *fb_helper); |
133 | 133 | int drm_fb_helper_debug_enter(struct fb_info *info); |