aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Vetter <daniel.vetter@ffwll.ch>2016-12-18 08:35:45 -0500
committerDaniel Vetter <daniel.vetter@ffwll.ch>2017-01-30 04:17:17 -0500
commit4e5b54f127426c82dc2816340c26d951a5bb3429 (patch)
treecc3a8f7e335cf12880bc8d1a1e2066f6cfe0a68e
parent566cf877a1fcb6d6dc0126b076aad062054c2637 (diff)
drm: prevent double-(un)registration for connectors
If we're unlucky then the registration from a hotplugged connector might race with the final registration step on driver load. And since MST topology discover is asynchronous that's even somewhat likely. v2: Also update the kerneldoc for @registered! v3: Review from Chris: - Improve kerneldoc for late_register/early_unregister callbacks. - Use mutex_destroy. Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Chris Wilson <chris@chris-wilson.co.uk> Reviewed-by: Sean Paul <seanpaul@chromium.org> Reported-by: Chris Wilson <chris@chris-wilson.co.uk> Signed-off-by: Daniel Vetter <daniel.vetter@intel.com> Link: http://patchwork.freedesktop.org/patch/msgid/20161218133545.2106-1-daniel.vetter@ffwll.ch (cherry picked from commit e73ab00e9a0f1731f34d0620a9c55f5c30c4ad4e)
-rw-r--r--drivers/gpu/drm/drm_connector.c20
-rw-r--r--include/drm/drm_connector.h16
2 files changed, 30 insertions, 6 deletions
diff --git a/drivers/gpu/drm/drm_connector.c b/drivers/gpu/drm/drm_connector.c
index 5a4526289392..8be60a4576b3 100644
--- a/drivers/gpu/drm/drm_connector.c
+++ b/drivers/gpu/drm/drm_connector.c
@@ -225,6 +225,7 @@ int drm_connector_init(struct drm_device *dev,
225 225
226 INIT_LIST_HEAD(&connector->probed_modes); 226 INIT_LIST_HEAD(&connector->probed_modes);
227 INIT_LIST_HEAD(&connector->modes); 227 INIT_LIST_HEAD(&connector->modes);
228 mutex_init(&connector->mutex);
228 connector->edid_blob_ptr = NULL; 229 connector->edid_blob_ptr = NULL;
229 connector->status = connector_status_unknown; 230 connector->status = connector_status_unknown;
230 231
@@ -359,6 +360,8 @@ void drm_connector_cleanup(struct drm_connector *connector)
359 connector->funcs->atomic_destroy_state(connector, 360 connector->funcs->atomic_destroy_state(connector,
360 connector->state); 361 connector->state);
361 362
363 mutex_destroy(&connector->mutex);
364
362 memset(connector, 0, sizeof(*connector)); 365 memset(connector, 0, sizeof(*connector));
363} 366}
364EXPORT_SYMBOL(drm_connector_cleanup); 367EXPORT_SYMBOL(drm_connector_cleanup);
@@ -374,14 +377,15 @@ EXPORT_SYMBOL(drm_connector_cleanup);
374 */ 377 */
375int drm_connector_register(struct drm_connector *connector) 378int drm_connector_register(struct drm_connector *connector)
376{ 379{
377 int ret; 380 int ret = 0;
378 381
382 mutex_lock(&connector->mutex);
379 if (connector->registered) 383 if (connector->registered)
380 return 0; 384 goto unlock;
381 385
382 ret = drm_sysfs_connector_add(connector); 386 ret = drm_sysfs_connector_add(connector);
383 if (ret) 387 if (ret)
384 return ret; 388 goto unlock;
385 389
386 ret = drm_debugfs_connector_add(connector); 390 ret = drm_debugfs_connector_add(connector);
387 if (ret) { 391 if (ret) {
@@ -397,12 +401,14 @@ int drm_connector_register(struct drm_connector *connector)
397 drm_mode_object_register(connector->dev, &connector->base); 401 drm_mode_object_register(connector->dev, &connector->base);
398 402
399 connector->registered = true; 403 connector->registered = true;
400 return 0; 404 goto unlock;
401 405
402err_debugfs: 406err_debugfs:
403 drm_debugfs_connector_remove(connector); 407 drm_debugfs_connector_remove(connector);
404err_sysfs: 408err_sysfs:
405 drm_sysfs_connector_remove(connector); 409 drm_sysfs_connector_remove(connector);
410unlock:
411 mutex_unlock(&connector->mutex);
406 return ret; 412 return ret;
407} 413}
408EXPORT_SYMBOL(drm_connector_register); 414EXPORT_SYMBOL(drm_connector_register);
@@ -415,8 +421,11 @@ EXPORT_SYMBOL(drm_connector_register);
415 */ 421 */
416void drm_connector_unregister(struct drm_connector *connector) 422void drm_connector_unregister(struct drm_connector *connector)
417{ 423{
418 if (!connector->registered) 424 mutex_lock(&connector->mutex);
425 if (!connector->registered) {
426 mutex_unlock(&connector->mutex);
419 return; 427 return;
428 }
420 429
421 if (connector->funcs->early_unregister) 430 if (connector->funcs->early_unregister)
422 connector->funcs->early_unregister(connector); 431 connector->funcs->early_unregister(connector);
@@ -425,6 +434,7 @@ void drm_connector_unregister(struct drm_connector *connector)
425 drm_debugfs_connector_remove(connector); 434 drm_debugfs_connector_remove(connector);
426 435
427 connector->registered = false; 436 connector->registered = false;
437 mutex_unlock(&connector->mutex);
428} 438}
429EXPORT_SYMBOL(drm_connector_unregister); 439EXPORT_SYMBOL(drm_connector_unregister);
430 440
diff --git a/include/drm/drm_connector.h b/include/drm/drm_connector.h
index a9b95246e26e..045a97cbeba2 100644
--- a/include/drm/drm_connector.h
+++ b/include/drm/drm_connector.h
@@ -381,6 +381,8 @@ struct drm_connector_funcs {
381 * core drm connector interfaces. Everything added from this callback 381 * core drm connector interfaces. Everything added from this callback
382 * should be unregistered in the early_unregister callback. 382 * should be unregistered in the early_unregister callback.
383 * 383 *
384 * This is called while holding drm_connector->mutex.
385 *
384 * Returns: 386 * Returns:
385 * 387 *
386 * 0 on success, or a negative error code on failure. 388 * 0 on success, or a negative error code on failure.
@@ -395,6 +397,8 @@ struct drm_connector_funcs {
395 * late_register(). It is called from drm_connector_unregister(), 397 * late_register(). It is called from drm_connector_unregister(),
396 * early in the driver unload sequence to disable userspace access 398 * early in the driver unload sequence to disable userspace access
397 * before data structures are torndown. 399 * before data structures are torndown.
400 *
401 * This is called while holding drm_connector->mutex.
398 */ 402 */
399 void (*early_unregister)(struct drm_connector *connector); 403 void (*early_unregister)(struct drm_connector *connector);
400 404
@@ -559,7 +563,6 @@ struct drm_cmdline_mode {
559 * @interlace_allowed: can this connector handle interlaced modes? 563 * @interlace_allowed: can this connector handle interlaced modes?
560 * @doublescan_allowed: can this connector handle doublescan? 564 * @doublescan_allowed: can this connector handle doublescan?
561 * @stereo_allowed: can this connector handle stereo modes? 565 * @stereo_allowed: can this connector handle stereo modes?
562 * @registered: is this connector exposed (registered) with userspace?
563 * @modes: modes available on this connector (from fill_modes() + user) 566 * @modes: modes available on this connector (from fill_modes() + user)
564 * @status: one of the drm_connector_status enums (connected, not, or unknown) 567 * @status: one of the drm_connector_status enums (connected, not, or unknown)
565 * @probed_modes: list of modes derived directly from the display 568 * @probed_modes: list of modes derived directly from the display
@@ -608,6 +611,13 @@ struct drm_connector {
608 char *name; 611 char *name;
609 612
610 /** 613 /**
614 * @mutex: Lock for general connector state, but currently only protects
615 * @registered. Most of the connector state is still protected by the
616 * mutex in &drm_mode_config.
617 */
618 struct mutex mutex;
619
620 /**
611 * @index: Compacted connector index, which matches the position inside 621 * @index: Compacted connector index, which matches the position inside
612 * the mode_config.list for drivers not supporting hot-add/removing. Can 622 * the mode_config.list for drivers not supporting hot-add/removing. Can
613 * be used as an array index. It is invariant over the lifetime of the 623 * be used as an array index. It is invariant over the lifetime of the
@@ -620,6 +630,10 @@ struct drm_connector {
620 bool interlace_allowed; 630 bool interlace_allowed;
621 bool doublescan_allowed; 631 bool doublescan_allowed;
622 bool stereo_allowed; 632 bool stereo_allowed;
633 /**
634 * @registered: Is this connector exposed (registered) with userspace?
635 * Protected by @mutex.
636 */
623 bool registered; 637 bool registered;
624 struct list_head modes; /* list of modes on this connector */ 638 struct list_head modes; /* list of modes on this connector */
625 639