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>
This commit is contained in:
parent
8eea1be174
commit
752d2635eb
2 changed files with 23 additions and 5 deletions
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Loading…
Reference in a new issue