drm: review locking rules in drm_crtc.c

- config_cleanup was confused: It claimed that callers need to hold
  the modeset lock, but the connector|encoder_cleanup helpers grabbed
  that themselves (note that crtc_cleanup did _not_ grab the modeset
  lock). Which resulted in all drivers _not_ hodling the lock. Since
  this is for single-threaded cleanup code, drop the requirement from
  docs and also drop the lock_grabbing from all _cleanup functions.

- Kill the LOCKING section in the doctype, since clearly we're not
  good enough to keep them up-to-date. And misleading locking
  documentation is worse than useless (see e.g. the comment in the
  vmgfx driver about the cleanup mess). And since for most functions
  the very first line either grabs the lock or has a WARN_ON(!locked)
  the documentation doesn't really add anything.

- Instead put in some effort into explaining the only two special
  cases a bit better: config_init and config_cleanup are both called
  from single-threaded setup/teardown code, so don't do any locking.
  It's the driver's job though to enforce this.

- Where lacking, add a WARN_ON(!is_locked). Not many places though,
  since locking around fbdev setup/teardown is through-roughly screwed
  up, and so will break almost every single WARN annotation I've tried
  to add.

- Add a drm_modeset_is_locked helper - the Grate Modset Locking Rework
  will use the compiler to assist in the big reorg by renaming the
  mode lock, so start encapsulating things. Unfortunately this ended
  up in the "wrong" header file since it needs the definition of
  struct drm_device.

v2: Drop most WARNS again - we hit them all over the place, mostly in
the setup and teardown sequences. And trying to fix it up leads to
nice deadlocks, since the locking in the setup code is really
inconsistent.

Reviewed-by: Rob Clark <rob@ti.com>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
This commit is contained in:
Daniel Vetter 2012-12-01 23:43:11 +01:00
parent 7d1f9aeff1
commit 8faf6b18a2
2 changed files with 18 additions and 92 deletions

View file

@ -208,8 +208,6 @@ char *drm_get_connector_status_name(enum drm_connector_status status)
* @ptr: object pointer, used to generate unique ID * @ptr: object pointer, used to generate unique ID
* @type: object type * @type: object type
* *
* LOCKING:
*
* Create a unique identifier based on @ptr in @dev's identifier space. Used * Create a unique identifier based on @ptr in @dev's identifier space. Used
* for tracking modes, CRTCs and connectors. * for tracking modes, CRTCs and connectors.
* *
@ -247,9 +245,6 @@ static int drm_mode_object_get(struct drm_device *dev,
* @dev: DRM device * @dev: DRM device
* @id: ID to free * @id: ID to free
* *
* LOCKING:
* Caller must hold DRM mode_config lock.
*
* Free @id from @dev's unique identifier pool. * Free @id from @dev's unique identifier pool.
*/ */
static void drm_mode_object_put(struct drm_device *dev, static void drm_mode_object_put(struct drm_device *dev,
@ -279,9 +274,6 @@ EXPORT_SYMBOL(drm_mode_object_find);
* drm_framebuffer_init - initialize a framebuffer * drm_framebuffer_init - initialize a framebuffer
* @dev: DRM device * @dev: DRM device
* *
* LOCKING:
* Caller must hold mode config lock.
*
* Allocates an ID for the framebuffer's parent mode object, sets its mode * Allocates an ID for the framebuffer's parent mode object, sets its mode
* functions & device file and adds it to the master fd list. * functions & device file and adds it to the master fd list.
* *
@ -317,15 +309,12 @@ static void drm_framebuffer_free(struct kref *kref)
/** /**
* drm_framebuffer_unreference - unref a framebuffer * drm_framebuffer_unreference - unref a framebuffer
*
* LOCKING:
* Caller must hold mode config lock.
*/ */
void drm_framebuffer_unreference(struct drm_framebuffer *fb) void drm_framebuffer_unreference(struct drm_framebuffer *fb)
{ {
struct drm_device *dev = fb->dev; struct drm_device *dev = fb->dev;
DRM_DEBUG("FB ID: %d\n", fb->base.id); DRM_DEBUG("FB ID: %d\n", fb->base.id);
WARN_ON(!mutex_is_locked(&dev->mode_config.mutex)); WARN_ON(!drm_modeset_is_locked(dev));
kref_put(&fb->refcount, drm_framebuffer_free); kref_put(&fb->refcount, drm_framebuffer_free);
} }
EXPORT_SYMBOL(drm_framebuffer_unreference); EXPORT_SYMBOL(drm_framebuffer_unreference);
@ -344,15 +333,13 @@ EXPORT_SYMBOL(drm_framebuffer_reference);
* drm_framebuffer_cleanup - remove a framebuffer object * drm_framebuffer_cleanup - remove a framebuffer object
* @fb: framebuffer to remove * @fb: framebuffer to remove
* *
* LOCKING:
* Caller must hold mode config lock.
*
* Scans all the CRTCs in @dev's mode_config. If they're using @fb, removes * Scans all the CRTCs in @dev's mode_config. If they're using @fb, removes
* it, setting it to NULL. * it, setting it to NULL.
*/ */
void drm_framebuffer_cleanup(struct drm_framebuffer *fb) void drm_framebuffer_cleanup(struct drm_framebuffer *fb)
{ {
struct drm_device *dev = fb->dev; struct drm_device *dev = fb->dev;
/* /*
* This could be moved to drm_framebuffer_remove(), but for * This could be moved to drm_framebuffer_remove(), but for
* debugging is nice to keep around the list of fb's that are * debugging is nice to keep around the list of fb's that are
@ -370,9 +357,6 @@ EXPORT_SYMBOL(drm_framebuffer_cleanup);
* drm_framebuffer_remove - remove and unreference a framebuffer object * drm_framebuffer_remove - remove and unreference a framebuffer object
* @fb: framebuffer to remove * @fb: framebuffer to remove
* *
* LOCKING:
* Caller must hold mode config lock.
*
* Scans all the CRTCs and planes in @dev's mode_config. If they're * Scans all the CRTCs and planes in @dev's mode_config. If they're
* using @fb, removes it, setting it to NULL. * using @fb, removes it, setting it to NULL.
*/ */
@ -384,6 +368,8 @@ void drm_framebuffer_remove(struct drm_framebuffer *fb)
struct drm_mode_set set; struct drm_mode_set set;
int ret; int ret;
WARN_ON(!drm_modeset_is_locked(dev));
/* remove from any CRTC */ /* remove from any CRTC */
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
if (crtc->fb == fb) { if (crtc->fb == fb) {
@ -421,9 +407,6 @@ EXPORT_SYMBOL(drm_framebuffer_remove);
* @crtc: CRTC object to init * @crtc: CRTC object to init
* @funcs: callbacks for the new CRTC * @funcs: callbacks for the new CRTC
* *
* LOCKING:
* Takes mode_config lock.
*
* Inits a new object created as base part of an driver crtc object. * Inits a new object created as base part of an driver crtc object.
* *
* RETURNS: * RETURNS:
@ -460,9 +443,6 @@ EXPORT_SYMBOL(drm_crtc_init);
* drm_crtc_cleanup - Cleans up the core crtc usage. * drm_crtc_cleanup - Cleans up the core crtc usage.
* @crtc: CRTC to cleanup * @crtc: CRTC to cleanup
* *
* LOCKING:
* Caller must hold mode config lock.
*
* Cleanup @crtc. Removes from drm modesetting space * Cleanup @crtc. Removes from drm modesetting space
* does NOT free object, caller does that. * does NOT free object, caller does that.
*/ */
@ -484,9 +464,6 @@ EXPORT_SYMBOL(drm_crtc_cleanup);
* @connector: connector the new mode * @connector: connector the new mode
* @mode: mode data * @mode: mode data
* *
* LOCKING:
* Caller must hold mode config lock.
*
* Add @mode to @connector's mode list for later use. * Add @mode to @connector's mode list for later use.
*/ */
void drm_mode_probed_add(struct drm_connector *connector, void drm_mode_probed_add(struct drm_connector *connector,
@ -501,9 +478,6 @@ EXPORT_SYMBOL(drm_mode_probed_add);
* @connector: connector list to modify * @connector: connector list to modify
* @mode: mode to remove * @mode: mode to remove
* *
* LOCKING:
* Caller must hold mode config lock.
*
* Remove @mode from @connector's mode list, then free it. * Remove @mode from @connector's mode list, then free it.
*/ */
void drm_mode_remove(struct drm_connector *connector, void drm_mode_remove(struct drm_connector *connector,
@ -521,9 +495,6 @@ EXPORT_SYMBOL(drm_mode_remove);
* @funcs: callbacks for this connector * @funcs: callbacks for this connector
* @name: user visible name of the connector * @name: user visible name of the connector
* *
* LOCKING:
* Takes mode config lock.
*
* Initialises a preallocated connector. Connectors should be * Initialises a preallocated connector. Connectors should be
* subclassed as part of driver connector objects. * subclassed as part of driver connector objects.
* *
@ -577,9 +548,6 @@ EXPORT_SYMBOL(drm_connector_init);
* drm_connector_cleanup - cleans up an initialised connector * drm_connector_cleanup - cleans up an initialised connector
* @connector: connector to cleanup * @connector: connector to cleanup
* *
* LOCKING:
* Takes mode config lock.
*
* Cleans up the connector but doesn't free the object. * Cleans up the connector but doesn't free the object.
*/ */
void drm_connector_cleanup(struct drm_connector *connector) void drm_connector_cleanup(struct drm_connector *connector)
@ -596,11 +564,9 @@ void drm_connector_cleanup(struct drm_connector *connector)
list_for_each_entry_safe(mode, t, &connector->user_modes, head) list_for_each_entry_safe(mode, t, &connector->user_modes, head)
drm_mode_remove(connector, mode); drm_mode_remove(connector, mode);
mutex_lock(&dev->mode_config.mutex);
drm_mode_object_put(dev, &connector->base); drm_mode_object_put(dev, &connector->base);
list_del(&connector->head); list_del(&connector->head);
dev->mode_config.num_connector--; dev->mode_config.num_connector--;
mutex_unlock(&dev->mode_config.mutex);
} }
EXPORT_SYMBOL(drm_connector_cleanup); EXPORT_SYMBOL(drm_connector_cleanup);
@ -721,9 +687,6 @@ EXPORT_SYMBOL(drm_plane_cleanup);
* drm_mode_create - create a new display mode * drm_mode_create - create a new display mode
* @dev: DRM device * @dev: DRM device
* *
* LOCKING:
* Caller must hold DRM mode_config lock.
*
* Create a new drm_display_mode, give it an ID, and return it. * Create a new drm_display_mode, give it an ID, and return it.
* *
* RETURNS: * RETURNS:
@ -751,9 +714,6 @@ EXPORT_SYMBOL(drm_mode_create);
* @dev: DRM device * @dev: DRM device
* @mode: mode to remove * @mode: mode to remove
* *
* LOCKING:
* Caller must hold mode config lock.
*
* Free @mode's unique identifier, then free it. * Free @mode's unique identifier, then free it.
*/ */
void drm_mode_destroy(struct drm_device *dev, struct drm_display_mode *mode) void drm_mode_destroy(struct drm_device *dev, struct drm_display_mode *mode)
@ -978,11 +938,13 @@ EXPORT_SYMBOL(drm_mode_create_dirty_info_property);
* drm_mode_config_init - initialize DRM mode_configuration structure * drm_mode_config_init - initialize DRM mode_configuration structure
* @dev: DRM device * @dev: DRM device
* *
* LOCKING:
* None, should happen single threaded at init time.
*
* Initialize @dev's mode_config structure, used for tracking the graphics * Initialize @dev's mode_config structure, used for tracking the graphics
* configuration of @dev. * configuration of @dev.
*
* Since this initializes the modeset locks, no locking is possible. Which is no
* problem, since this should happen single threaded at init time. It is the
* driver's problem to ensure this guarantee.
*
*/ */
void drm_mode_config_init(struct drm_device *dev) void drm_mode_config_init(struct drm_device *dev)
{ {
@ -1057,12 +1019,13 @@ EXPORT_SYMBOL(drm_mode_group_init_legacy_group);
* drm_mode_config_cleanup - free up DRM mode_config info * drm_mode_config_cleanup - free up DRM mode_config info
* @dev: DRM device * @dev: DRM device
* *
* LOCKING:
* Caller must hold mode config lock.
*
* Free up all the connectors and CRTCs associated with this DRM device, then * Free up all the connectors and CRTCs associated with this DRM device, then
* free up the framebuffers and associated buffer objects. * free up the framebuffers and associated buffer objects.
* *
* Note that since this /should/ happen single-threaded at driver/device
* teardown time, no locking is required. It's the driver's job to ensure that
* this guarantee actually holds true.
*
* FIXME: cleanup any dangling user buffer objects too * FIXME: cleanup any dangling user buffer objects too
*/ */
void drm_mode_config_cleanup(struct drm_device *dev) void drm_mode_config_cleanup(struct drm_device *dev)
@ -1112,9 +1075,6 @@ EXPORT_SYMBOL(drm_mode_config_cleanup);
* @out: drm_mode_modeinfo struct to return to the user * @out: drm_mode_modeinfo struct to return to the user
* @in: drm_display_mode to use * @in: drm_display_mode to use
* *
* LOCKING:
* None.
*
* Convert a drm_display_mode into a drm_mode_modeinfo structure to return to * Convert a drm_display_mode into a drm_mode_modeinfo structure to return to
* the user. * the user.
*/ */
@ -1151,9 +1111,6 @@ static void drm_crtc_convert_to_umode(struct drm_mode_modeinfo *out,
* @out: drm_display_mode to return to the user * @out: drm_display_mode to return to the user
* @in: drm_mode_modeinfo to use * @in: drm_mode_modeinfo to use
* *
* LOCKING:
* None.
*
* Convert a drm_mode_modeinfo into a drm_display_mode structure to return to * Convert a drm_mode_modeinfo into a drm_display_mode structure to return to
* the caller. * the caller.
* *
@ -1193,9 +1150,6 @@ static int drm_crtc_convert_umode(struct drm_display_mode *out,
* @cmd: cmd from ioctl * @cmd: cmd from ioctl
* @arg: arg from ioctl * @arg: arg from ioctl
* *
* LOCKING:
* Takes mode config lock.
*
* Construct a set of configuration description structures and return * Construct a set of configuration description structures and return
* them to the user, including CRTC, connector and framebuffer configuration. * them to the user, including CRTC, connector and framebuffer configuration.
* *
@ -1381,9 +1335,6 @@ int drm_mode_getresources(struct drm_device *dev, void *data,
* @cmd: cmd from ioctl * @cmd: cmd from ioctl
* @arg: arg from ioctl * @arg: arg from ioctl
* *
* LOCKING:
* Takes mode config lock.
*
* Construct a CRTC configuration structure to return to the user. * Construct a CRTC configuration structure to return to the user.
* *
* Called by the user via ioctl. * Called by the user via ioctl.
@ -1441,9 +1392,6 @@ int drm_mode_getcrtc(struct drm_device *dev,
* @cmd: cmd from ioctl * @cmd: cmd from ioctl
* @arg: arg from ioctl * @arg: arg from ioctl
* *
* LOCKING:
* Takes mode config lock.
*
* Construct a connector configuration structure to return to the user. * Construct a connector configuration structure to return to the user.
* *
* Called by the user via ioctl. * Called by the user via ioctl.
@ -1618,9 +1566,6 @@ int drm_mode_getencoder(struct drm_device *dev, void *data,
* @data: ioctl data * @data: ioctl data
* @file_priv: DRM file info * @file_priv: DRM file info
* *
* LOCKING:
* Takes mode config lock.
*
* Return an plane count and set of IDs. * Return an plane count and set of IDs.
*/ */
int drm_mode_getplane_res(struct drm_device *dev, void *data, int drm_mode_getplane_res(struct drm_device *dev, void *data,
@ -1667,9 +1612,6 @@ int drm_mode_getplane_res(struct drm_device *dev, void *data,
* @data: ioctl data * @data: ioctl data
* @file_priv: DRM file info * @file_priv: DRM file info
* *
* LOCKING:
* Takes mode config lock.
*
* Return plane info, including formats supported, gamma size, any * Return plane info, including formats supported, gamma size, any
* current fb, etc. * current fb, etc.
*/ */
@ -1735,9 +1677,6 @@ int drm_mode_getplane(struct drm_device *dev, void *data,
* @data: ioctl data* * @data: ioctl data*
* @file_prive: DRM file info * @file_prive: DRM file info
* *
* LOCKING:
* Takes mode config lock.
*
* Set plane info, including placement, fb, scaling, and other factors. * Set plane info, including placement, fb, scaling, and other factors.
* Or pass a NULL fb to disable. * Or pass a NULL fb to disable.
*/ */
@ -1867,9 +1806,6 @@ int drm_mode_setplane(struct drm_device *dev, void *data,
* @cmd: cmd from ioctl * @cmd: cmd from ioctl
* @arg: arg from ioctl * @arg: arg from ioctl
* *
* LOCKING:
* Takes mode config lock.
*
* Build a new CRTC configuration based on user request. * Build a new CRTC configuration based on user request.
* *
* Called by the user via ioctl. * Called by the user via ioctl.
@ -2125,9 +2061,6 @@ EXPORT_SYMBOL(drm_mode_legacy_fb_format);
* @cmd: cmd from ioctl * @cmd: cmd from ioctl
* @arg: arg from ioctl * @arg: arg from ioctl
* *
* LOCKING:
* Takes mode config lock.
*
* Add a new FB to the specified CRTC, given a user request. * Add a new FB to the specified CRTC, given a user request.
* *
* Called by the user via ioctl. * Called by the user via ioctl.
@ -2309,9 +2242,6 @@ static int framebuffer_check(const struct drm_mode_fb_cmd2 *r)
* @cmd: cmd from ioctl * @cmd: cmd from ioctl
* @arg: arg from ioctl * @arg: arg from ioctl
* *
* LOCKING:
* Takes mode config lock.
*
* Add a new FB to the specified CRTC, given a user request with format. * Add a new FB to the specified CRTC, given a user request with format.
* *
* Called by the user via ioctl. * Called by the user via ioctl.
@ -2375,9 +2305,6 @@ int drm_mode_addfb2(struct drm_device *dev,
* @cmd: cmd from ioctl * @cmd: cmd from ioctl
* @arg: arg from ioctl * @arg: arg from ioctl
* *
* LOCKING:
* Takes mode config lock.
*
* Remove the FB specified by the user. * Remove the FB specified by the user.
* *
* Called by the user via ioctl. * Called by the user via ioctl.
@ -2430,9 +2357,6 @@ int drm_mode_rmfb(struct drm_device *dev,
* @cmd: cmd from ioctl * @cmd: cmd from ioctl
* @arg: arg from ioctl * @arg: arg from ioctl
* *
* LOCKING:
* Takes mode config lock.
*
* Lookup the FB given its ID and return info about it. * Lookup the FB given its ID and return info about it.
* *
* Called by the user via ioctl. * Called by the user via ioctl.
@ -2549,9 +2473,6 @@ int drm_mode_dirtyfb_ioctl(struct drm_device *dev,
* drm_fb_release - remove and free the FBs on this file * drm_fb_release - remove and free the FBs on this file
* @filp: file * from the ioctl * @filp: file * from the ioctl
* *
* LOCKING:
* Takes mode config lock.
*
* Destroy all the FBs associated with @filp. * Destroy all the FBs associated with @filp.
* *
* Called by the user via ioctl. * Called by the user via ioctl.

View file

@ -1276,6 +1276,11 @@ static inline int drm_device_is_unplugged(struct drm_device *dev)
return ret; return ret;
} }
static inline bool drm_modeset_is_locked(struct drm_device *dev)
{
return mutex_is_locked(&dev->mode_config.mutex);
}
/******************************************************************/ /******************************************************************/
/** \name Internal function definitions */ /** \name Internal function definitions */
/*@{*/ /*@{*/