dri-devel.lists.freedesktop.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 00/36] kms locking rework
@ 2013-01-10 20:47 Daniel Vetter
  2013-01-10 20:47 ` [PATCH 01/35] drm: review locking rules in drm_crtc.c Daniel Vetter
                   ` (36 more replies)
  0 siblings, 37 replies; 45+ messages in thread
From: Daniel Vetter @ 2013-01-10 20:47 UTC (permalink / raw)
  To: DRI Development; +Cc: Daniel Vetter

Hi all,

Concurrent EDID reads and pageflips ftw!

Changes since the rfc:
- radeon/ttm/exynos prep patches/fixes merged.
- arm driver patches at least compile-tested.
- error handling fixed in a few cases, all spotted by Richard Wilbur,
- radeon/nouveau tested on one card each, didn't blow up right away.
- i-g-t extended to cover the corner-cases, seems to hold up.
- DocBook updated as a new patch on top.
- one more patch to teach the fb helpers manners and not interfere so much with
  i-g-t tests.

Imo this is ready for inclusion, so (especially driver maintainers) please
review and test.

Yours, Daniel

Daniel Vetter (35):
  drm: review locking rules in drm_crtc.c
  drm/doc: integrate drm_crtc.c kerneldoc
  drm/<drivers>: reorder framebuffer init sequence
  drm/vmwgfx: reorder framebuffer init sequence
  drm/gma500: move fbcon restore to lastclose
  drm/nouveau: protect evo_wait/evo_kick sections with a channel mutex
  drm/nouveau: try to protect nbo->pin_refcount
  drm/<drivers>: Unified handling of unimplemented fb->create_handle
  drm: encapsulate crtc->set_config calls
  drm: add drm_modeset_lock|unlock_all
  drm/i915: use drm_modeset_lock_all
  drm/gma500: use drm_modeset_lock_all
  drm/ast: use drm_modeset_lock_all
  drm/shmobile: use drm_modeset_lock_all
  drm/vmgfx: use drm_modeset_lock_all
  drm: add per-crtc locks
  drm: only take the crtc lock for ->cursor_set
  drm: only take the crtc lock for ->cursor_move
  drm: revamp locking around fb creation/destruction
  drm: create drm_framebuffer_lookup
  drm: revamp framebuffer cleanup interfaces
  drm: reference framebuffers which are on the idr
  drm: nest modeset locks within fpriv->fbs_lock
  drm: push modeset_lock_all into ->fb_create driver callbacks
  drm: don't take modeset locks in getfb ioctl
  drm: fb refcounting for dirtyfb_ioctl
  drm: refcounting for sprite framebuffers
  drm: refcounting for crtc framebuffers
  drm/i915: dump refcount into framebuffer debugfs file
  drm/vmwgfx: add proper framebuffer refcounting
  drm: optimize drm_framebuffer_remove
  drm: only grab the crtc lock for pageflips
  drm: don't hold crtc mutexes for connector ->detect callbacks
  drm/doc: updates for new framebuffer lifetime rules
  drm/fb_helper: check whether fbcon is bound

 Documentation/DocBook/drm.tmpl            |   63 ++-
 drivers/gpu/drm/ast/ast_drv.c             |    4 +-
 drivers/gpu/drm/ast/ast_drv.h             |    2 +
 drivers/gpu/drm/ast/ast_fb.c              |    1 +
 drivers/gpu/drm/ast/ast_main.c            |   12 +-
 drivers/gpu/drm/cirrus/cirrus_fbdev.c     |    1 +
 drivers/gpu/drm/cirrus/cirrus_main.c      |   12 +-
 drivers/gpu/drm/drm_crtc.c                |  792 +++++++++++++++++------------
 drivers/gpu/drm/drm_fb_cma_helper.c       |   15 +-
 drivers/gpu/drm/drm_fb_helper.c           |   65 ++-
 drivers/gpu/drm/drm_fops.c                |    1 +
 drivers/gpu/drm/exynos/exynos_drm_fbdev.c |    4 +-
 drivers/gpu/drm/gma500/framebuffer.c      |   29 +-
 drivers/gpu/drm/gma500/psb_device.c       |    8 +-
 drivers/gpu/drm/gma500/psb_drv.c          |   14 +-
 drivers/gpu/drm/i2c/ch7006_drv.c          |    2 +-
 drivers/gpu/drm/i915/i915_debugfs.c       |   15 +-
 drivers/gpu/drm/i915/intel_display.c      |   21 +-
 drivers/gpu/drm/i915/intel_dp.c           |    2 +
 drivers/gpu/drm/i915/intel_fb.c           |    5 +-
 drivers/gpu/drm/i915/intel_lvds.c         |    4 +-
 drivers/gpu/drm/i915/intel_overlay.c      |   14 +-
 drivers/gpu/drm/i915/intel_sprite.c       |    8 +-
 drivers/gpu/drm/mgag200/mgag200_fb.c      |    1 +
 drivers/gpu/drm/mgag200/mgag200_main.c    |   16 +-
 drivers/gpu/drm/nouveau/nouveau_bo.c      |   22 +-
 drivers/gpu/drm/nouveau/nouveau_bo.h      |    2 +
 drivers/gpu/drm/nouveau/nouveau_display.c |   10 +-
 drivers/gpu/drm/nouveau/nouveau_fbcon.c   |    1 +
 drivers/gpu/drm/nouveau/nv04_display.c    |    2 +-
 drivers/gpu/drm/nouveau/nv17_tv.c         |    2 +-
 drivers/gpu/drm/nouveau/nv50_display.c    |   10 +
 drivers/gpu/drm/radeon/radeon_cursor.c    |    8 +-
 drivers/gpu/drm/radeon/radeon_display.c   |    2 +-
 drivers/gpu/drm/radeon/radeon_fb.c        |    2 +
 drivers/gpu/drm/shmobile/shmob_drm_drv.c  |    4 +-
 drivers/gpu/drm/udl/udl_fb.c              |    4 +-
 drivers/gpu/drm/vmwgfx/vmwgfx_drv.c       |    2 +-
 drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c     |   38 +-
 drivers/gpu/drm/vmwgfx/vmwgfx_kms.c       |   87 ++--
 drivers/staging/omapdrm/omap_debugfs.c    |    2 +
 drivers/staging/omapdrm/omap_fb.c         |   16 +-
 drivers/staging/omapdrm/omap_fbdev.c      |    8 +-
 include/drm/drmP.h                        |   13 +
 include/drm/drm_crtc.h                    |   30 ++
 45 files changed, 830 insertions(+), 546 deletions(-)

-- 
1.7.10.4

^ permalink raw reply	[flat|nested] 45+ messages in thread

* [PATCH 01/35] drm: review locking rules in drm_crtc.c
  2013-01-10 20:47 [PATCH 00/36] kms locking rework Daniel Vetter
@ 2013-01-10 20:47 ` Daniel Vetter
  2013-01-10 20:47 ` [PATCH 02/35] drm/doc: integrate drm_crtc.c kerneldoc Daniel Vetter
                   ` (35 subsequent siblings)
  36 siblings, 0 replies; 45+ messages in thread
From: Daniel Vetter @ 2013-01-10 20:47 UTC (permalink / raw)
  To: DRI Development; +Cc: Daniel Vetter

- 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.

Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 drivers/gpu/drm/drm_crtc.c |  105 ++++++--------------------------------------
 include/drm/drmP.h         |    5 +++
 2 files changed, 18 insertions(+), 92 deletions(-)

diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index f2d667b..b970e41 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -208,8 +208,6 @@ char *drm_get_connector_status_name(enum drm_connector_status status)
  * @ptr: object pointer, used to generate unique ID
  * @type: object type
  *
- * LOCKING:
- *
  * Create a unique identifier based on @ptr in @dev's identifier space.  Used
  * for tracking modes, CRTCs and connectors.
  *
@@ -247,9 +245,6 @@ again:
  * @dev: DRM device
  * @id: ID to free
  *
- * LOCKING:
- * Caller must hold DRM mode_config lock.
- *
  * Free @id from @dev's unique identifier pool.
  */
 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
  * @dev: DRM device
  *
- * LOCKING:
- * Caller must hold mode config lock.
- *
  * Allocates an ID for the framebuffer's parent mode object, sets its mode
  * 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
- *
- * LOCKING:
- * Caller must hold mode config lock.
  */
 void drm_framebuffer_unreference(struct drm_framebuffer *fb)
 {
 	struct drm_device *dev = fb->dev;
 	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);
 }
 EXPORT_SYMBOL(drm_framebuffer_unreference);
@@ -344,15 +333,13 @@ EXPORT_SYMBOL(drm_framebuffer_reference);
  * drm_framebuffer_cleanup - remove a framebuffer object
  * @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
  * it, setting it to NULL.
  */
 void drm_framebuffer_cleanup(struct drm_framebuffer *fb)
 {
 	struct drm_device *dev = fb->dev;
+
 	/*
 	 * This could be moved to drm_framebuffer_remove(), but for
 	 * 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
  * @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
  * 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;
 	int ret;
 
+	WARN_ON(!drm_modeset_is_locked(dev));
+
 	/* remove from any CRTC */
 	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
 		if (crtc->fb == fb) {
@@ -421,9 +407,6 @@ EXPORT_SYMBOL(drm_framebuffer_remove);
  * @crtc: CRTC object to init
  * @funcs: callbacks for the new CRTC
  *
- * LOCKING:
- * Takes mode_config lock.
- *
  * Inits a new object created as base part of an driver crtc object.
  *
  * RETURNS:
@@ -460,9 +443,6 @@ EXPORT_SYMBOL(drm_crtc_init);
  * drm_crtc_cleanup - Cleans up the core crtc usage.
  * @crtc: CRTC to cleanup
  *
- * LOCKING:
- * Caller must hold mode config lock.
- *
  * Cleanup @crtc. Removes from drm modesetting space
  * does NOT free object, caller does that.
  */
@@ -484,9 +464,6 @@ EXPORT_SYMBOL(drm_crtc_cleanup);
  * @connector: connector the new mode
  * @mode: mode data
  *
- * LOCKING:
- * Caller must hold mode config lock.
- *
  * Add @mode to @connector's mode list for later use.
  */
 void drm_mode_probed_add(struct drm_connector *connector,
@@ -501,9 +478,6 @@ EXPORT_SYMBOL(drm_mode_probed_add);
  * @connector: connector list to modify
  * @mode: mode to remove
  *
- * LOCKING:
- * Caller must hold mode config lock.
- *
  * Remove @mode from @connector's mode list, then free it.
  */
 void drm_mode_remove(struct drm_connector *connector,
@@ -521,9 +495,6 @@ EXPORT_SYMBOL(drm_mode_remove);
  * @funcs: callbacks for this connector
  * @name: user visible name of the connector
  *
- * LOCKING:
- * Takes mode config lock.
- *
  * Initialises a preallocated connector. Connectors should be
  * subclassed as part of driver connector objects.
  *
@@ -577,9 +548,6 @@ EXPORT_SYMBOL(drm_connector_init);
  * drm_connector_cleanup - cleans up an initialised connector
  * @connector: connector to cleanup
  *
- * LOCKING:
- * Takes mode config lock.
- *
  * Cleans up the connector but doesn't free the object.
  */
 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)
 		drm_mode_remove(connector, mode);
 
-	mutex_lock(&dev->mode_config.mutex);
 	drm_mode_object_put(dev, &connector->base);
 	list_del(&connector->head);
 	dev->mode_config.num_connector--;
-	mutex_unlock(&dev->mode_config.mutex);
 }
 EXPORT_SYMBOL(drm_connector_cleanup);
 
@@ -721,9 +687,6 @@ EXPORT_SYMBOL(drm_plane_cleanup);
  * drm_mode_create - create a new display mode
  * @dev: DRM device
  *
- * LOCKING:
- * Caller must hold DRM mode_config lock.
- *
  * Create a new drm_display_mode, give it an ID, and return it.
  *
  * RETURNS:
@@ -751,9 +714,6 @@ EXPORT_SYMBOL(drm_mode_create);
  * @dev: DRM device
  * @mode: mode to remove
  *
- * LOCKING:
- * Caller must hold mode config lock.
- *
  * Free @mode's unique identifier, then free it.
  */
 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
  * @dev: DRM device
  *
- * LOCKING:
- * None, should happen single threaded at init time.
- *
  * Initialize @dev's mode_config structure, used for tracking the graphics
  * 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)
 {
@@ -1057,12 +1019,13 @@ EXPORT_SYMBOL(drm_mode_group_init_legacy_group);
  * drm_mode_config_cleanup - free up DRM mode_config info
  * @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 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
  */
 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
  * @in: drm_display_mode to use
  *
- * LOCKING:
- * None.
- *
  * Convert a drm_display_mode into a drm_mode_modeinfo structure to return to
  * 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
  * @in: drm_mode_modeinfo to use
  *
- * LOCKING:
- * None.
- *
  * Convert a drm_mode_modeinfo into a drm_display_mode structure to return to
  * the caller.
  *
@@ -1193,9 +1150,6 @@ static int drm_crtc_convert_umode(struct drm_display_mode *out,
  * @cmd: cmd from ioctl
  * @arg: arg from ioctl
  *
- * LOCKING:
- * Takes mode config lock.
- *
  * Construct a set of configuration description structures and return
  * them to the user, including CRTC, connector and framebuffer configuration.
  *
@@ -1381,9 +1335,6 @@ out:
  * @cmd: cmd from ioctl
  * @arg: arg from ioctl
  *
- * LOCKING:
- * Takes mode config lock.
- *
  * Construct a CRTC configuration structure to return to the user.
  *
  * Called by the user via ioctl.
@@ -1441,9 +1392,6 @@ out:
  * @cmd: cmd from ioctl
  * @arg: arg from ioctl
  *
- * LOCKING:
- * Takes mode config lock.
- *
  * Construct a connector configuration structure to return to the user.
  *
  * Called by the user via ioctl.
@@ -1618,9 +1566,6 @@ out:
  * @data: ioctl data
  * @file_priv: DRM file info
  *
- * LOCKING:
- * Takes mode config lock.
- *
  * Return an plane count and set of IDs.
  */
 int drm_mode_getplane_res(struct drm_device *dev, void *data,
@@ -1667,9 +1612,6 @@ out:
  * @data: ioctl data
  * @file_priv: DRM file info
  *
- * LOCKING:
- * Takes mode config lock.
- *
  * Return plane info, including formats supported, gamma size, any
  * current fb, etc.
  */
@@ -1735,9 +1677,6 @@ out:
  * @data: ioctl data*
  * @file_prive: DRM file info
  *
- * LOCKING:
- * Takes mode config lock.
- *
  * Set plane info, including placement, fb, scaling, and other factors.
  * Or pass a NULL fb to disable.
  */
@@ -1867,9 +1806,6 @@ out:
  * @cmd: cmd from ioctl
  * @arg: arg from ioctl
  *
- * LOCKING:
- * Takes mode config lock.
- *
  * Build a new CRTC configuration based on user request.
  *
  * Called by the user via ioctl.
@@ -2125,9 +2061,6 @@ EXPORT_SYMBOL(drm_mode_legacy_fb_format);
  * @cmd: cmd from ioctl
  * @arg: arg from ioctl
  *
- * LOCKING:
- * Takes mode config lock.
- *
  * Add a new FB to the specified CRTC, given a user request.
  *
  * 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
  * @arg: arg from ioctl
  *
- * LOCKING:
- * Takes mode config lock.
- *
  * Add a new FB to the specified CRTC, given a user request with format.
  *
  * Called by the user via ioctl.
@@ -2375,9 +2305,6 @@ out:
  * @cmd: cmd from ioctl
  * @arg: arg from ioctl
  *
- * LOCKING:
- * Takes mode config lock.
- *
  * Remove the FB specified by the user.
  *
  * Called by the user via ioctl.
@@ -2430,9 +2357,6 @@ out:
  * @cmd: cmd from ioctl
  * @arg: arg from ioctl
  *
- * LOCKING:
- * Takes mode config lock.
- *
  * Lookup the FB given its ID and return info about it.
  *
  * Called by the user via ioctl.
@@ -2549,9 +2473,6 @@ out_err1:
  * drm_fb_release - remove and free the FBs on this file
  * @filp: file * from the ioctl
  *
- * LOCKING:
- * Takes mode config lock.
- *
  * Destroy all the FBs associated with @filp.
  *
  * Called by the user via ioctl.
diff --git a/include/drm/drmP.h b/include/drm/drmP.h
index fad21c9..3c609ab 100644
--- a/include/drm/drmP.h
+++ b/include/drm/drmP.h
@@ -1276,6 +1276,11 @@ static inline int drm_device_is_unplugged(struct drm_device *dev)
 	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 */
 /*@{*/
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PATCH 02/35] drm/doc: integrate drm_crtc.c kerneldoc
  2013-01-10 20:47 [PATCH 00/36] kms locking rework Daniel Vetter
  2013-01-10 20:47 ` [PATCH 01/35] drm: review locking rules in drm_crtc.c Daniel Vetter
@ 2013-01-10 20:47 ` Daniel Vetter
  2013-01-10 20:47 ` [PATCH 03/35] drm/<drivers>: reorder framebuffer init sequence Daniel Vetter
                   ` (34 subsequent siblings)
  36 siblings, 0 replies; 45+ messages in thread
From: Daniel Vetter @ 2013-01-10 20:47 UTC (permalink / raw)
  To: DRI Development; +Cc: Daniel Vetter

And do a quick pass to adjust them to the last few (years?) of changes
...

This time actually compile-tested ;-)

Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 Documentation/DocBook/drm.tmpl |    4 ++
 drivers/gpu/drm/drm_crtc.c     |   92 +++++++++++++++++++---------------------
 2 files changed, 48 insertions(+), 48 deletions(-)

diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl
index 4ee2304..caab791 100644
--- a/Documentation/DocBook/drm.tmpl
+++ b/Documentation/DocBook/drm.tmpl
@@ -1609,6 +1609,10 @@ void intel_crt_init(struct drm_device *dev)
         make its properties available to applications.
       </para>
     </sect2>
+    <sect2>
+      <title>KMS API Functions</title>
+!Edrivers/gpu/drm/drm_crtc.c
+    </sect2>
   </sect1>
 
   <!-- Internals: kms helper functions -->
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index b970e41..8154554 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -203,10 +203,10 @@ char *drm_get_connector_status_name(enum drm_connector_status status)
 }
 
 /**
- * drm_mode_object_get - allocate a new identifier
+ * drm_mode_object_get - allocate a new modeset identifier
  * @dev: DRM device
- * @ptr: object pointer, used to generate unique ID
- * @type: object type
+ * @obj: object pointer, used to generate unique ID
+ * @obj_type: object type
  *
  * Create a unique identifier based on @ptr in @dev's identifier space.  Used
  * for tracking modes, CRTCs and connectors.
@@ -241,9 +241,9 @@ again:
 }
 
 /**
- * drm_mode_object_put - free an identifer
+ * drm_mode_object_put - free a modeset identifer
  * @dev: DRM device
- * @id: ID to free
+ * @object: object to free
  *
  * Free @id from @dev's unique identifier pool.
  */
@@ -273,6 +273,8 @@ EXPORT_SYMBOL(drm_mode_object_find);
 /**
  * drm_framebuffer_init - initialize a framebuffer
  * @dev: DRM device
+ * @fb: framebuffer to be initialized
+ * @funcs: ... with these functions
  *
  * Allocates an ID for the framebuffer's parent mode object, sets its mode
  * functions & device file and adds it to the master fd list.
@@ -309,6 +311,9 @@ static void drm_framebuffer_free(struct kref *kref)
 
 /**
  * drm_framebuffer_unreference - unref a framebuffer
+ * @fb: framebuffer to unref
+ *
+ * This functions decrements the fb's refcount and frees it if it drops to zero.
  */
 void drm_framebuffer_unreference(struct drm_framebuffer *fb)
 {
@@ -321,6 +326,7 @@ EXPORT_SYMBOL(drm_framebuffer_unreference);
 
 /**
  * drm_framebuffer_reference - incr the fb refcnt
+ * @fb: framebuffer
  */
 void drm_framebuffer_reference(struct drm_framebuffer *fb)
 {
@@ -493,7 +499,7 @@ EXPORT_SYMBOL(drm_mode_remove);
  * @dev: DRM device
  * @connector: the connector to init
  * @funcs: callbacks for this connector
- * @name: user visible name of the connector
+ * @connector_type: user visible type of the connector
  *
  * Initialises a preallocated connector. Connectors should be
  * subclassed as part of driver connector objects.
@@ -1145,10 +1151,9 @@ static int drm_crtc_convert_umode(struct drm_display_mode *out,
 
 /**
  * drm_mode_getresources - get graphics configuration
- * @inode: inode from the ioctl
- * @filp: file * from the ioctl
- * @cmd: cmd from ioctl
- * @arg: arg from ioctl
+ * @dev: drm device for the ioctl
+ * @data: data pointer for the ioctl
+ * @file_priv: drm file for the ioctl call
  *
  * Construct a set of configuration description structures and return
  * them to the user, including CRTC, connector and framebuffer configuration.
@@ -1330,10 +1335,9 @@ out:
 
 /**
  * drm_mode_getcrtc - get CRTC configuration
- * @inode: inode from the ioctl
- * @filp: file * from the ioctl
- * @cmd: cmd from ioctl
- * @arg: arg from ioctl
+ * @dev: drm device for the ioctl
+ * @data: data pointer for the ioctl
+ * @file_priv: drm file for the ioctl call
  *
  * Construct a CRTC configuration structure to return to the user.
  *
@@ -1387,10 +1391,9 @@ out:
 
 /**
  * drm_mode_getconnector - get connector configuration
- * @inode: inode from the ioctl
- * @filp: file * from the ioctl
- * @cmd: cmd from ioctl
- * @arg: arg from ioctl
+ * @dev: drm device for the ioctl
+ * @data: data pointer for the ioctl
+ * @file_priv: drm file for the ioctl call
  *
  * Construct a connector configuration structure to return to the user.
  *
@@ -1675,7 +1678,7 @@ out:
  * drm_mode_setplane - set up or tear down an plane
  * @dev: DRM device
  * @data: ioctl data*
- * @file_prive: DRM file info
+ * @file_priv: DRM file info
  *
  * Set plane info, including placement, fb, scaling, and other factors.
  * Or pass a NULL fb to disable.
@@ -1801,10 +1804,9 @@ out:
 
 /**
  * drm_mode_setcrtc - set CRTC configuration
- * @inode: inode from the ioctl
- * @filp: file * from the ioctl
- * @cmd: cmd from ioctl
- * @arg: arg from ioctl
+ * @dev: drm device for the ioctl
+ * @data: data pointer for the ioctl
+ * @file_priv: drm file for the ioctl call
  *
  * Build a new CRTC configuration based on user request.
  *
@@ -2056,10 +2058,9 @@ EXPORT_SYMBOL(drm_mode_legacy_fb_format);
 
 /**
  * drm_mode_addfb - add an FB to the graphics configuration
- * @inode: inode from the ioctl
- * @filp: file * from the ioctl
- * @cmd: cmd from ioctl
- * @arg: arg from ioctl
+ * @dev: drm device for the ioctl
+ * @data: data pointer for the ioctl
+ * @file_priv: drm file for the ioctl call
  *
  * Add a new FB to the specified CRTC, given a user request.
  *
@@ -2237,10 +2238,9 @@ static int framebuffer_check(const struct drm_mode_fb_cmd2 *r)
 
 /**
  * drm_mode_addfb2 - add an FB to the graphics configuration
- * @inode: inode from the ioctl
- * @filp: file * from the ioctl
- * @cmd: cmd from ioctl
- * @arg: arg from ioctl
+ * @dev: drm device for the ioctl
+ * @data: data pointer for the ioctl
+ * @file_priv: drm file for the ioctl call
  *
  * Add a new FB to the specified CRTC, given a user request with format.
  *
@@ -2300,10 +2300,9 @@ out:
 
 /**
  * drm_mode_rmfb - remove an FB from the configuration
- * @inode: inode from the ioctl
- * @filp: file * from the ioctl
- * @cmd: cmd from ioctl
- * @arg: arg from ioctl
+ * @dev: drm device for the ioctl
+ * @data: data pointer for the ioctl
+ * @file_priv: drm file for the ioctl call
  *
  * Remove the FB specified by the user.
  *
@@ -2352,10 +2351,9 @@ out:
 
 /**
  * drm_mode_getfb - get FB info
- * @inode: inode from the ioctl
- * @filp: file * from the ioctl
- * @cmd: cmd from ioctl
- * @arg: arg from ioctl
+ * @dev: drm device for the ioctl
+ * @data: data pointer for the ioctl
+ * @file_priv: drm file for the ioctl call
  *
  * Lookup the FB given its ID and return info about it.
  *
@@ -2471,7 +2469,7 @@ out_err1:
 
 /**
  * drm_fb_release - remove and free the FBs on this file
- * @filp: file * from the ioctl
+ * @priv: drm file for the ioctl
  *
  * Destroy all the FBs associated with @filp.
  *
@@ -2581,10 +2579,9 @@ EXPORT_SYMBOL(drm_mode_detachmode_crtc);
 
 /**
  * drm_fb_attachmode - Attach a user mode to an connector
- * @inode: inode from the ioctl
- * @filp: file * from the ioctl
- * @cmd: cmd from ioctl
- * @arg: arg from ioctl
+ * @dev: drm device for the ioctl
+ * @data: data pointer for the ioctl
+ * @file_priv: drm file for the ioctl call
  *
  * This attaches a user specified mode to an connector.
  * Called by the user via ioctl.
@@ -2636,10 +2633,9 @@ out:
 
 /**
  * drm_fb_detachmode - Detach a user specified mode from an connector
- * @inode: inode from the ioctl
- * @filp: file * from the ioctl
- * @cmd: cmd from ioctl
- * @arg: arg from ioctl
+ * @dev: drm device for the ioctl
+ * @data: data pointer for the ioctl
+ * @file_priv: drm file for the ioctl call
  *
  * Called by the user via ioctl.
  *
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PATCH 03/35] drm/<drivers>: reorder framebuffer init sequence
  2013-01-10 20:47 [PATCH 00/36] kms locking rework Daniel Vetter
  2013-01-10 20:47 ` [PATCH 01/35] drm: review locking rules in drm_crtc.c Daniel Vetter
  2013-01-10 20:47 ` [PATCH 02/35] drm/doc: integrate drm_crtc.c kerneldoc Daniel Vetter
@ 2013-01-10 20:47 ` Daniel Vetter
  2013-01-11 21:06   ` Rob Clark
  2013-01-10 20:47 ` [PATCH 04/35] drm/vmwgfx: " Daniel Vetter
                   ` (33 subsequent siblings)
  36 siblings, 1 reply; 45+ messages in thread
From: Daniel Vetter @ 2013-01-10 20:47 UTC (permalink / raw)
  To: DRI Development; +Cc: Daniel Vetter

With more fine-grained locking we can no longer rely on the big
mode_config lock to prevent concurrent access to mode resources
like framebuffers. Instead a framebuffer becomes accessible to
other threads as soon as it is added to the relevant lookup
structures. Hence it needs to be fully set up by the time drivers
call drm_framebuffer_init.

This patch here is the drivers part of that reorg. Nothing really fancy
going on safe for three special cases.

- exynos needs to be careful to properly unref all handles.
- nouveau gets a resource leak fixed for free: one of the error
  cases didn't cleanup the framebuffer, which is now moot since
  the framebuffer is only registered once it is fully set up.
- vmwgfx requires a slight reordering of operations, I'm hoping I didn't
  break anything (but it's refcount management only, so should be safe).

v2: Split out exynos, since it's a bit more hairy than expected.

v3: Drop bogus cirrus hunk noticed by Richard Wilbur.

v4: Split out vmwgfx since there's a small change in return values.

Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 drivers/gpu/drm/ast/ast_main.c            |    4 ++--
 drivers/gpu/drm/cirrus/cirrus_main.c      |    4 ++--
 drivers/gpu/drm/drm_fb_cma_helper.c       |   10 +++++-----
 drivers/gpu/drm/gma500/framebuffer.c      |    4 ++--
 drivers/gpu/drm/i915/intel_display.c      |    5 +++--
 drivers/gpu/drm/mgag200/mgag200_main.c    |    8 +++++---
 drivers/gpu/drm/nouveau/nouveau_display.c |   10 +++++-----
 drivers/gpu/drm/radeon/radeon_display.c   |    2 +-
 drivers/gpu/drm/udl/udl_fb.c              |    2 +-
 drivers/staging/omapdrm/omap_fb.c         |   16 ++++++++--------
 10 files changed, 34 insertions(+), 31 deletions(-)

diff --git a/drivers/gpu/drm/ast/ast_main.c b/drivers/gpu/drm/ast/ast_main.c
index f668e6c..d5ba709 100644
--- a/drivers/gpu/drm/ast/ast_main.c
+++ b/drivers/gpu/drm/ast/ast_main.c
@@ -266,13 +266,13 @@ int ast_framebuffer_init(struct drm_device *dev,
 {
 	int ret;
 
+	drm_helper_mode_fill_fb_struct(&ast_fb->base, mode_cmd);
+	ast_fb->obj = obj;
 	ret = drm_framebuffer_init(dev, &ast_fb->base, &ast_fb_funcs);
 	if (ret) {
 		DRM_ERROR("framebuffer init failed %d\n", ret);
 		return ret;
 	}
-	drm_helper_mode_fill_fb_struct(&ast_fb->base, mode_cmd);
-	ast_fb->obj = obj;
 	return 0;
 }
 
diff --git a/drivers/gpu/drm/cirrus/cirrus_main.c b/drivers/gpu/drm/cirrus/cirrus_main.c
index 6a9b12e..364474c 100644
--- a/drivers/gpu/drm/cirrus/cirrus_main.c
+++ b/drivers/gpu/drm/cirrus/cirrus_main.c
@@ -42,13 +42,13 @@ int cirrus_framebuffer_init(struct drm_device *dev,
 {
 	int ret;
 
+	drm_helper_mode_fill_fb_struct(&gfb->base, mode_cmd);
+	gfb->obj = obj;
 	ret = drm_framebuffer_init(dev, &gfb->base, &cirrus_fb_funcs);
 	if (ret) {
 		DRM_ERROR("drm_framebuffer_init failed: %d\n", ret);
 		return ret;
 	}
-	drm_helper_mode_fill_fb_struct(&gfb->base, mode_cmd);
-	gfb->obj = obj;
 	return 0;
 }
 
diff --git a/drivers/gpu/drm/drm_fb_cma_helper.c b/drivers/gpu/drm/drm_fb_cma_helper.c
index fd9d0af..e1e0cb0 100644
--- a/drivers/gpu/drm/drm_fb_cma_helper.c
+++ b/drivers/gpu/drm/drm_fb_cma_helper.c
@@ -85,6 +85,11 @@ static struct drm_fb_cma *drm_fb_cma_alloc(struct drm_device *dev,
 	if (!fb_cma)
 		return ERR_PTR(-ENOMEM);
 
+	drm_helper_mode_fill_fb_struct(&fb_cma->fb, mode_cmd);
+
+	for (i = 0; i < num_planes; i++)
+		fb_cma->obj[i] = obj[i];
+
 	ret = drm_framebuffer_init(dev, &fb_cma->fb, &drm_fb_cma_funcs);
 	if (ret) {
 		dev_err(dev->dev, "Failed to initalize framebuffer: %d\n", ret);
@@ -92,11 +97,6 @@ static struct drm_fb_cma *drm_fb_cma_alloc(struct drm_device *dev,
 		return ERR_PTR(ret);
 	}
 
-	drm_helper_mode_fill_fb_struct(&fb_cma->fb, mode_cmd);
-
-	for (i = 0; i < num_planes; i++)
-		fb_cma->obj[i] = obj[i];
-
 	return fb_cma;
 }
 
diff --git a/drivers/gpu/drm/gma500/framebuffer.c b/drivers/gpu/drm/gma500/framebuffer.c
index afded54..38e7e75 100644
--- a/drivers/gpu/drm/gma500/framebuffer.c
+++ b/drivers/gpu/drm/gma500/framebuffer.c
@@ -260,13 +260,13 @@ static int psb_framebuffer_init(struct drm_device *dev,
 	default:
 		return -EINVAL;
 	}
+	drm_helper_mode_fill_fb_struct(&fb->base, mode_cmd);
+	fb->gtt = gt;
 	ret = drm_framebuffer_init(dev, &fb->base, &psb_fb_funcs);
 	if (ret) {
 		dev_err(dev->dev, "framebuffer init failed: %d\n", ret);
 		return ret;
 	}
-	drm_helper_mode_fill_fb_struct(&fb->base, mode_cmd);
-	fb->gtt = gt;
 	return 0;
 }
 
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index cf0c713..b2af790 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -8387,14 +8387,15 @@ int intel_framebuffer_init(struct drm_device *dev,
 	if (mode_cmd->offsets[0] != 0)
 		return -EINVAL;
 
+	drm_helper_mode_fill_fb_struct(&intel_fb->base, mode_cmd);
+	intel_fb->obj = obj;
+
 	ret = drm_framebuffer_init(dev, &intel_fb->base, &intel_fb_funcs);
 	if (ret) {
 		DRM_ERROR("framebuffer init failed %d\n", ret);
 		return ret;
 	}
 
-	drm_helper_mode_fill_fb_struct(&intel_fb->base, mode_cmd);
-	intel_fb->obj = obj;
 	return 0;
 }
 
diff --git a/drivers/gpu/drm/mgag200/mgag200_main.c b/drivers/gpu/drm/mgag200/mgag200_main.c
index 70dd3c5..266438a 100644
--- a/drivers/gpu/drm/mgag200/mgag200_main.c
+++ b/drivers/gpu/drm/mgag200/mgag200_main.c
@@ -40,13 +40,15 @@ int mgag200_framebuffer_init(struct drm_device *dev,
 			     struct drm_mode_fb_cmd2 *mode_cmd,
 			     struct drm_gem_object *obj)
 {
-	int ret = drm_framebuffer_init(dev, &gfb->base, &mga_fb_funcs);
+	int ret;
+	
+	drm_helper_mode_fill_fb_struct(&gfb->base, mode_cmd);
+	gfb->obj = obj;
+	ret = drm_framebuffer_init(dev, &gfb->base, &mga_fb_funcs);
 	if (ret) {
 		DRM_ERROR("drm_framebuffer_init failed: %d\n", ret);
 		return ret;
 	}
-	drm_helper_mode_fill_fb_struct(&gfb->base, mode_cmd);
-	gfb->obj = obj;
 	return 0;
 }
 
diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c
index e4188f2..2591ff2 100644
--- a/drivers/gpu/drm/nouveau/nouveau_display.c
+++ b/drivers/gpu/drm/nouveau/nouveau_display.c
@@ -78,11 +78,6 @@ nouveau_framebuffer_init(struct drm_device *dev,
 	struct drm_framebuffer *fb = &nv_fb->base;
 	int ret;
 
-	ret = drm_framebuffer_init(dev, fb, &nouveau_framebuffer_funcs);
-	if (ret) {
-		return ret;
-	}
-
 	drm_helper_mode_fill_fb_struct(fb, mode_cmd);
 	nv_fb->nvbo = nvbo;
 
@@ -125,6 +120,11 @@ nouveau_framebuffer_init(struct drm_device *dev,
 		}
 	}
 
+	ret = drm_framebuffer_init(dev, fb, &nouveau_framebuffer_funcs);
+	if (ret) {
+		return ret;
+	}
+
 	return 0;
 }
 
diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c
index 1da2386..12ec3ef 100644
--- a/drivers/gpu/drm/radeon/radeon_display.c
+++ b/drivers/gpu/drm/radeon/radeon_display.c
@@ -1089,12 +1089,12 @@ radeon_framebuffer_init(struct drm_device *dev,
 {
 	int ret;
 	rfb->obj = obj;
+	drm_helper_mode_fill_fb_struct(&rfb->base, mode_cmd);
 	ret = drm_framebuffer_init(dev, &rfb->base, &radeon_fb_funcs);
 	if (ret) {
 		rfb->obj = NULL;
 		return ret;
 	}
-	drm_helper_mode_fill_fb_struct(&rfb->base, mode_cmd);
 	return 0;
 }
 
diff --git a/drivers/gpu/drm/udl/udl_fb.c b/drivers/gpu/drm/udl/udl_fb.c
index d4ab3be..829c4a7 100644
--- a/drivers/gpu/drm/udl/udl_fb.c
+++ b/drivers/gpu/drm/udl/udl_fb.c
@@ -435,8 +435,8 @@ udl_framebuffer_init(struct drm_device *dev,
 	int ret;
 
 	ufb->obj = obj;
-	ret = drm_framebuffer_init(dev, &ufb->base, &udlfb_funcs);
 	drm_helper_mode_fill_fb_struct(&ufb->base, mode_cmd);
+	ret = drm_framebuffer_init(dev, &ufb->base, &udlfb_funcs);
 	return ret;
 }
 
diff --git a/drivers/staging/omapdrm/omap_fb.c b/drivers/staging/omapdrm/omap_fb.c
index 09028e9..bf6421f 100644
--- a/drivers/staging/omapdrm/omap_fb.c
+++ b/drivers/staging/omapdrm/omap_fb.c
@@ -424,14 +424,6 @@ struct drm_framebuffer *omap_framebuffer_init(struct drm_device *dev,
 	}
 
 	fb = &omap_fb->base;
-	ret = drm_framebuffer_init(dev, fb, &omap_framebuffer_funcs);
-	if (ret) {
-		dev_err(dev->dev, "framebuffer init failed: %d\n", ret);
-		goto fail;
-	}
-
-	DBG("create: FB ID: %d (%p)", fb->base.id, fb);
-
 	omap_fb->format = format;
 
 	for (i = 0; i < n; i++) {
@@ -462,6 +454,14 @@ struct drm_framebuffer *omap_framebuffer_init(struct drm_device *dev,
 
 	drm_helper_mode_fill_fb_struct(fb, mode_cmd);
 
+	ret = drm_framebuffer_init(dev, fb, &omap_framebuffer_funcs);
+	if (ret) {
+		dev_err(dev->dev, "framebuffer init failed: %d\n", ret);
+		goto fail;
+	}
+
+	DBG("create: FB ID: %d (%p)", fb->base.id, fb);
+
 	return fb;
 
 fail:
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PATCH 04/35] drm/vmwgfx: reorder framebuffer init sequence
  2013-01-10 20:47 [PATCH 00/36] kms locking rework Daniel Vetter
                   ` (2 preceding siblings ...)
  2013-01-10 20:47 ` [PATCH 03/35] drm/<drivers>: reorder framebuffer init sequence Daniel Vetter
@ 2013-01-10 20:47 ` Daniel Vetter
  2013-01-10 20:47 ` [PATCH 05/35] drm/gma500: move fbcon restore to lastclose Daniel Vetter
                   ` (32 subsequent siblings)
  36 siblings, 0 replies; 45+ messages in thread
From: Daniel Vetter @ 2013-01-10 20:47 UTC (permalink / raw)
  To: DRI Development; +Cc: Daniel Vetter

vmwgfx has an oddity, when failing to reference the surface it'll
return 0, since that's what the successfull drm_framebuffer_init will
leave behind in ret. Fix this up by returning -EINVAL.

Split out from all the other driver updates due to the above tiny
semantic change. Shouldn't matter though since the reference grabbing
seemingly can't fail.

Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 drivers/gpu/drm/vmwgfx/vmwgfx_kms.c |   30 ++++++++++++++++--------------
 1 file changed, 16 insertions(+), 14 deletions(-)

diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
index 5474394..edc9792 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
@@ -681,14 +681,10 @@ static int vmw_kms_new_framebuffer_surface(struct vmw_private *dev_priv,
 		goto out_err1;
 	}
 
-	ret = drm_framebuffer_init(dev, &vfbs->base.base,
-				   &vmw_framebuffer_surface_funcs);
-	if (ret)
-		goto out_err2;
-
 	if (!vmw_surface_reference(surface)) {
 		DRM_ERROR("failed to reference surface %p\n", surface);
-		goto out_err3;
+		ret = -EINVAL;
+		goto out_err2;
 	}
 
 	/* XXX get the first 3 from the surface info */
@@ -707,10 +703,15 @@ static int vmw_kms_new_framebuffer_surface(struct vmw_private *dev_priv,
 
 	*out = &vfbs->base;
 
+	ret = drm_framebuffer_init(dev, &vfbs->base.base,
+				   &vmw_framebuffer_surface_funcs);
+	if (ret)
+		goto out_err3;
+
 	return 0;
 
 out_err3:
-	drm_framebuffer_cleanup(&vfbs->base.base);
+	vmw_surface_unreference(&surface);
 out_err2:
 	kfree(vfbs);
 out_err1:
@@ -1053,14 +1054,10 @@ static int vmw_kms_new_framebuffer_dmabuf(struct vmw_private *dev_priv,
 		goto out_err1;
 	}
 
-	ret = drm_framebuffer_init(dev, &vfbd->base.base,
-				   &vmw_framebuffer_dmabuf_funcs);
-	if (ret)
-		goto out_err2;
-
 	if (!vmw_dmabuf_reference(dmabuf)) {
 		DRM_ERROR("failed to reference dmabuf %p\n", dmabuf);
-		goto out_err3;
+		ret = -EINVAL;
+		goto out_err2;
 	}
 
 	vfbd->base.base.bits_per_pixel = mode_cmd->bpp;
@@ -1077,10 +1074,15 @@ static int vmw_kms_new_framebuffer_dmabuf(struct vmw_private *dev_priv,
 	vfbd->base.user_handle = mode_cmd->handle;
 	*out = &vfbd->base;
 
+	ret = drm_framebuffer_init(dev, &vfbd->base.base,
+				   &vmw_framebuffer_dmabuf_funcs);
+	if (ret)
+		goto out_err3;
+
 	return 0;
 
 out_err3:
-	drm_framebuffer_cleanup(&vfbd->base.base);
+	vmw_dmabuf_unreference(&dmabuf);
 out_err2:
 	kfree(vfbd);
 out_err1:
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PATCH 05/35] drm/gma500: move fbcon restore to lastclose
  2013-01-10 20:47 [PATCH 00/36] kms locking rework Daniel Vetter
                   ` (3 preceding siblings ...)
  2013-01-10 20:47 ` [PATCH 04/35] drm/vmwgfx: " Daniel Vetter
@ 2013-01-10 20:47 ` Daniel Vetter
  2013-01-10 20:47 ` [PATCH 06/35] drm/nouveau: protect evo_wait/evo_kick sections with a channel mutex Daniel Vetter
                   ` (31 subsequent siblings)
  36 siblings, 0 replies; 45+ messages in thread
From: Daniel Vetter @ 2013-01-10 20:47 UTC (permalink / raw)
  To: DRI Development; +Cc: Daniel Vetter

Doing this within the fb->destroy callback leads to a locking
nightmare. And all other drm drivers that restore the fbcon do
it in lastclose, too.

With this adjustments all fb->destroy callbacks optionally drop
references to any gem objects used as backing storage, call
drm_framebuffer_cleanup and then kfree the struct. Which nicely
simplifies the locking for framebuffer unreferencing and freeing,
since this doesn't require that we hold the mode_config lock. A
slight exception is the vmwgfx surface backed framebuffer, it also
calls drm_master_put and removes the object from a device-private
framebuffer list. Both seem to have solid locking in place already.

Conclusion is that now it is no longer required to hold the
mode_config lock while freeing a framebuffer.

v2: Drop the corresponding mutex_lock WARN check from
drm_framebuffer_unreference.

v3: Use just the mode_config lock not modeset_lock_all, due to patch
reordering.

Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 drivers/gpu/drm/drm_crtc.c           |    2 --
 drivers/gpu/drm/gma500/framebuffer.c |   24 ------------------------
 drivers/gpu/drm/gma500/psb_drv.c     |   10 ++++++++++
 3 files changed, 10 insertions(+), 26 deletions(-)

diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index 8154554..8d665fa 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -317,9 +317,7 @@ static void drm_framebuffer_free(struct kref *kref)
  */
 void drm_framebuffer_unreference(struct drm_framebuffer *fb)
 {
-	struct drm_device *dev = fb->dev;
 	DRM_DEBUG("FB ID: %d\n", fb->base.id);
-	WARN_ON(!drm_modeset_is_locked(dev));
 	kref_put(&fb->refcount, drm_framebuffer_free);
 }
 EXPORT_SYMBOL(drm_framebuffer_unreference);
diff --git a/drivers/gpu/drm/gma500/framebuffer.c b/drivers/gpu/drm/gma500/framebuffer.c
index 38e7e75..49800d2 100644
--- a/drivers/gpu/drm/gma500/framebuffer.c
+++ b/drivers/gpu/drm/gma500/framebuffer.c
@@ -668,30 +668,6 @@ static void psb_user_framebuffer_destroy(struct drm_framebuffer *fb)
 {
 	struct psb_framebuffer *psbfb = to_psb_fb(fb);
 	struct gtt_range *r = psbfb->gtt;
-	struct drm_device *dev = fb->dev;
-	struct drm_psb_private *dev_priv = dev->dev_private;
-	struct psb_fbdev *fbdev = dev_priv->fbdev;
-	struct drm_crtc *crtc;
-	int reset = 0;
-
-	/* Should never get stolen memory for a user fb */
-	WARN_ON(r->stolen);
-
-	/* Check if we are erroneously live */
-	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head)
-		if (crtc->fb == fb)
-			reset = 1;
-
-	if (reset)
-		/*
-		 * Now force a sane response before we permit the DRM CRTC
-		 * layer to do stupid things like blank the display. Instead
-		 * we reset this framebuffer as if the user had forced a reset.
-		 * We must do this before the cleanup so that the DRM layer
-		 * doesn't get a chance to stick its oar in where it isn't
-		 * wanted.
-		 */
-		drm_fb_helper_restore_fbdev_mode(&fbdev->psb_fb_helper);
 
 	/* Let DRM do its clean up */
 	drm_framebuffer_cleanup(fb);
diff --git a/drivers/gpu/drm/gma500/psb_drv.c b/drivers/gpu/drm/gma500/psb_drv.c
index dd1fbfa..dbcefe9 100644
--- a/drivers/gpu/drm/gma500/psb_drv.c
+++ b/drivers/gpu/drm/gma500/psb_drv.c
@@ -149,6 +149,16 @@ static struct drm_ioctl_desc psb_ioctls[] = {
 
 static void psb_lastclose(struct drm_device *dev)
 {
+	int ret;
+	struct drm_psb_private *dev_priv = dev->dev_private;
+	struct psb_fbdev *fbdev = dev_priv->fbdev;
+
+	mutex_lock(&dev->mode_config.mutex);
+	ret = drm_fb_helper_restore_fbdev_mode(&fbdev->psb_fb_helper);
+	if (ret)
+		DRM_DEBUG("failed to restore crtc mode\n");
+	mutex_unlock(&dev->mode_config.mutex);
+
 	return;
 }
 
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PATCH 06/35] drm/nouveau: protect evo_wait/evo_kick sections with a channel mutex
  2013-01-10 20:47 [PATCH 00/36] kms locking rework Daniel Vetter
                   ` (4 preceding siblings ...)
  2013-01-10 20:47 ` [PATCH 05/35] drm/gma500: move fbcon restore to lastclose Daniel Vetter
@ 2013-01-10 20:47 ` Daniel Vetter
  2013-01-10 20:47 ` [PATCH 07/35] drm/nouveau: try to protect nbo->pin_refcount Daniel Vetter
                   ` (30 subsequent siblings)
  36 siblings, 0 replies; 45+ messages in thread
From: Daniel Vetter @ 2013-01-10 20:47 UTC (permalink / raw)
  To: DRI Development; +Cc: Daniel Vetter

With per-crtc locks modeset operations can run in parallel, and the
cursor code uses the device-global evo master channel for hw frobbing.
But the pageflip code can also sync with the master under some
circumstances. Hence just wrap things up in a mutex to ensure that
pushbuf access doesn't intermingle.

The approach here is a bit overkill since the per-crtc channels used
to schedule the pageflips could probably be used without this pushbuf
locking, but I'm not familiar enough with the nouveau codebase to be
sure of that.

v2: Add missing mutex_init to avoid angering lockdep.

Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 drivers/gpu/drm/nouveau/nv50_display.c |   10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c
index 3587408..d4cbea1 100644
--- a/drivers/gpu/drm/nouveau/nv50_display.c
+++ b/drivers/gpu/drm/nouveau/nv50_display.c
@@ -128,6 +128,11 @@ struct nv50_dmac {
 	struct nv50_chan base;
 	dma_addr_t handle;
 	u32 *ptr;
+
+	/* Protects against concurrent pushbuf access to this channel, lock is
+	 * grabbed by evo_wait (if the pushbuf reservation is successful) and
+	 * dropped again by evo_kick. */
+	struct mutex lock;
 };
 
 static void
@@ -271,6 +276,8 @@ nv50_dmac_create(struct nouveau_object *core, u32 bclass, u8 head,
 	u32 pushbuf = *(u32 *)data;
 	int ret;
 
+	mutex_init(&dmac->lock);
+
 	dmac->ptr = pci_alloc_consistent(nv_device(core)->pdev, PAGE_SIZE,
 					&dmac->handle);
 	if (!dmac->ptr)
@@ -395,11 +402,13 @@ evo_wait(void *evoc, int nr)
 	struct nv50_dmac *dmac = evoc;
 	u32 put = nv_ro32(dmac->base.user, 0x0000) / 4;
 
+	mutex_lock(&dmac->lock);
 	if (put + nr >= (PAGE_SIZE / 4) - 8) {
 		dmac->ptr[put] = 0x20000000;
 
 		nv_wo32(dmac->base.user, 0x0000, 0x00000000);
 		if (!nv_wait(dmac->base.user, 0x0004, ~0, 0x00000000)) {
+			mutex_unlock(&dmac->lock);
 			NV_ERROR(dmac->base.user, "channel stalled\n");
 			return NULL;
 		}
@@ -415,6 +424,7 @@ evo_kick(u32 *push, void *evoc)
 {
 	struct nv50_dmac *dmac = evoc;
 	nv_wo32(dmac->base.user, 0x0000, (push - dmac->ptr) << 2);
+	mutex_unlock(&dmac->lock);
 }
 
 #define evo_mthd(p,m,s) *((p)++) = (((s) << 18) | (m))
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PATCH 07/35] drm/nouveau: try to protect nbo->pin_refcount
  2013-01-10 20:47 [PATCH 00/36] kms locking rework Daniel Vetter
                   ` (5 preceding siblings ...)
  2013-01-10 20:47 ` [PATCH 06/35] drm/nouveau: protect evo_wait/evo_kick sections with a channel mutex Daniel Vetter
@ 2013-01-10 20:47 ` Daniel Vetter
  2013-01-10 20:47 ` [PATCH 08/35] drm/<drivers>: Unified handling of unimplemented fb->create_handle Daniel Vetter
                   ` (29 subsequent siblings)
  36 siblings, 0 replies; 45+ messages in thread
From: Daniel Vetter @ 2013-01-10 20:47 UTC (permalink / raw)
  To: DRI Development; +Cc: Daniel Vetter

... by moving the bo_pin/bo_unpin manipulation of the pin_refcount
under the protection of the ttm reservation lock. pin/unpin seems
to get called from all over the place, so atm this is completely racy.

After this patch there are only a few places in cleanup functions
left which access ->pin_refcount without locking. But I'm hoping that
those are safe and some other code invariant guarantees that this
won't blow up.

In any case, I only need to fix up pin/unpin to make ->pageflip work
safely, so let's keep it at that.

Add a comment to the header to explain the new locking rule.

Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 drivers/gpu/drm/nouveau/nouveau_bo.c |   22 +++++++++++-----------
 drivers/gpu/drm/nouveau/nouveau_bo.h |    2 ++
 2 files changed, 13 insertions(+), 11 deletions(-)

diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c
index 69d7b1d..64d6e304 100644
--- a/drivers/gpu/drm/nouveau/nouveau_bo.c
+++ b/drivers/gpu/drm/nouveau/nouveau_bo.c
@@ -300,17 +300,18 @@ nouveau_bo_pin(struct nouveau_bo *nvbo, uint32_t memtype)
 	struct ttm_buffer_object *bo = &nvbo->bo;
 	int ret;
 
+	ret = ttm_bo_reserve(bo, false, false, false, 0);
+	if (ret)
+		goto out;
+
 	if (nvbo->pin_refcnt && !(memtype & (1 << bo->mem.mem_type))) {
 		NV_ERROR(drm, "bo %p pinned elsewhere: 0x%08x vs 0x%08x\n", bo,
 			 1 << bo->mem.mem_type, memtype);
-		return -EINVAL;
+		ret = -EINVAL;
+		goto out;
 	}
 
 	if (nvbo->pin_refcnt++)
-		return 0;
-
-	ret = ttm_bo_reserve(bo, false, false, false, 0);
-	if (ret)
 		goto out;
 
 	nouveau_bo_placement_set(nvbo, memtype, 0);
@@ -328,10 +329,8 @@ nouveau_bo_pin(struct nouveau_bo *nvbo, uint32_t memtype)
 			break;
 		}
 	}
-	ttm_bo_unreserve(bo);
 out:
-	if (unlikely(ret))
-		nvbo->pin_refcnt--;
+	ttm_bo_unreserve(bo);
 	return ret;
 }
 
@@ -342,13 +341,13 @@ nouveau_bo_unpin(struct nouveau_bo *nvbo)
 	struct ttm_buffer_object *bo = &nvbo->bo;
 	int ret;
 
-	if (--nvbo->pin_refcnt)
-		return 0;
-
 	ret = ttm_bo_reserve(bo, false, false, false, 0);
 	if (ret)
 		return ret;
 
+	if (--nvbo->pin_refcnt)
+		goto out;
+
 	nouveau_bo_placement_set(nvbo, bo->mem.placement, 0);
 
 	ret = nouveau_bo_validate(nvbo, false, false);
@@ -365,6 +364,7 @@ nouveau_bo_unpin(struct nouveau_bo *nvbo)
 		}
 	}
 
+out:
 	ttm_bo_unreserve(bo);
 	return ret;
 }
diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.h b/drivers/gpu/drm/nouveau/nouveau_bo.h
index 25ca379..81d00fe 100644
--- a/drivers/gpu/drm/nouveau/nouveau_bo.h
+++ b/drivers/gpu/drm/nouveau/nouveau_bo.h
@@ -28,6 +28,8 @@ struct nouveau_bo {
 	struct nouveau_drm_tile *tile;
 
 	struct drm_gem_object *gem;
+
+	/* protect by the ttm reservation lock */
 	int pin_refcnt;
 
 	struct ttm_bo_kmap_obj dma_buf_vmap;
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PATCH 08/35] drm/<drivers>: Unified handling of unimplemented fb->create_handle
  2013-01-10 20:47 [PATCH 00/36] kms locking rework Daniel Vetter
                   ` (6 preceding siblings ...)
  2013-01-10 20:47 ` [PATCH 07/35] drm/nouveau: try to protect nbo->pin_refcount Daniel Vetter
@ 2013-01-10 20:47 ` Daniel Vetter
  2013-01-18 15:00   ` Thierry Reding
  2013-01-10 20:47 ` [PATCH 09/35] drm: encapsulate crtc->set_config calls Daniel Vetter
                   ` (28 subsequent siblings)
  36 siblings, 1 reply; 45+ messages in thread
From: Daniel Vetter @ 2013-01-10 20:47 UTC (permalink / raw)
  To: DRI Development; +Cc: Daniel Vetter

Some drivers don't have real ->create_handle callbacks.

- cirrus/ast/mga200: Returns either 0 or -EINVAL.

- udl: Didn't even bother with a callback, leading to a nice
  userspace-triggerable OOPS.

- vmwgfx: This driver bothered with an implementation to return 0 as
  the handle (which is the canonical no-obj gem handle).

All have in common that ->create_handle doesn't really make too much
sense for them - that ioctl is used only for seamless fb takeover in
the radeon/nouveau/i915 ddx drivers. So allow drivers to not implement
this and return a consistent -ENODEV.

Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 drivers/gpu/drm/ast/ast_main.c         |    8 --------
 drivers/gpu/drm/cirrus/cirrus_main.c   |    8 --------
 drivers/gpu/drm/drm_crtc.c             |    5 ++++-
 drivers/gpu/drm/mgag200/mgag200_main.c |    8 --------
 drivers/gpu/drm/udl/udl_fb.c           |    1 -
 drivers/gpu/drm/vmwgfx/vmwgfx_kms.c    |   12 ------------
 6 files changed, 4 insertions(+), 38 deletions(-)

diff --git a/drivers/gpu/drm/ast/ast_main.c b/drivers/gpu/drm/ast/ast_main.c
index d5ba709..f60fd7b 100644
--- a/drivers/gpu/drm/ast/ast_main.c
+++ b/drivers/gpu/drm/ast/ast_main.c
@@ -246,16 +246,8 @@ static void ast_user_framebuffer_destroy(struct drm_framebuffer *fb)
 	kfree(fb);
 }
 
-static int ast_user_framebuffer_create_handle(struct drm_framebuffer *fb,
-					      struct drm_file *file,
-					      unsigned int *handle)
-{
-	return -EINVAL;
-}
-
 static const struct drm_framebuffer_funcs ast_fb_funcs = {
 	.destroy = ast_user_framebuffer_destroy,
-	.create_handle = ast_user_framebuffer_create_handle,
 };
 
 
diff --git a/drivers/gpu/drm/cirrus/cirrus_main.c b/drivers/gpu/drm/cirrus/cirrus_main.c
index 364474c..35cbae8 100644
--- a/drivers/gpu/drm/cirrus/cirrus_main.c
+++ b/drivers/gpu/drm/cirrus/cirrus_main.c
@@ -23,16 +23,8 @@ static void cirrus_user_framebuffer_destroy(struct drm_framebuffer *fb)
 	kfree(fb);
 }
 
-static int cirrus_user_framebuffer_create_handle(struct drm_framebuffer *fb,
-						 struct drm_file *file_priv,
-						 unsigned int *handle)
-{
-	return 0;
-}
-
 static const struct drm_framebuffer_funcs cirrus_fb_funcs = {
 	.destroy = cirrus_user_framebuffer_destroy,
-	.create_handle = cirrus_user_framebuffer_create_handle,
 };
 
 int cirrus_framebuffer_init(struct drm_device *dev,
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index 8d665fa..a9abf49 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -2384,7 +2384,10 @@ int drm_mode_getfb(struct drm_device *dev,
 	r->depth = fb->depth;
 	r->bpp = fb->bits_per_pixel;
 	r->pitch = fb->pitches[0];
-	fb->funcs->create_handle(fb, file_priv, &r->handle);
+	if (fb->funcs->create_handle)
+		ret = fb->funcs->create_handle(fb, file_priv, &r->handle);
+	else
+		ret = -ENODEV;
 
 out:
 	mutex_unlock(&dev->mode_config.mutex);
diff --git a/drivers/gpu/drm/mgag200/mgag200_main.c b/drivers/gpu/drm/mgag200/mgag200_main.c
index 266438a..64297c7 100644
--- a/drivers/gpu/drm/mgag200/mgag200_main.c
+++ b/drivers/gpu/drm/mgag200/mgag200_main.c
@@ -23,16 +23,8 @@ static void mga_user_framebuffer_destroy(struct drm_framebuffer *fb)
 	kfree(fb);
 }
 
-static int mga_user_framebuffer_create_handle(struct drm_framebuffer *fb,
-						 struct drm_file *file_priv,
-						 unsigned int *handle)
-{
-	return 0;
-}
-
 static const struct drm_framebuffer_funcs mga_fb_funcs = {
 	.destroy = mga_user_framebuffer_destroy,
-	.create_handle = mga_user_framebuffer_create_handle,
 };
 
 int mgag200_framebuffer_init(struct drm_device *dev,
diff --git a/drivers/gpu/drm/udl/udl_fb.c b/drivers/gpu/drm/udl/udl_fb.c
index 829c4a7..f8904b4 100644
--- a/drivers/gpu/drm/udl/udl_fb.c
+++ b/drivers/gpu/drm/udl/udl_fb.c
@@ -422,7 +422,6 @@ static void udl_user_framebuffer_destroy(struct drm_framebuffer *fb)
 static const struct drm_framebuffer_funcs udlfb_funcs = {
 	.destroy = udl_user_framebuffer_destroy,
 	.dirty = udl_user_framebuffer_dirty,
-	.create_handle = NULL,
 };
 
 
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
index edc9792..9c0876b 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
@@ -373,16 +373,6 @@ void vmw_kms_cursor_post_execbuf(struct vmw_private *dev_priv)
  * Generic framebuffer code
  */
 
-int vmw_framebuffer_create_handle(struct drm_framebuffer *fb,
-				  struct drm_file *file_priv,
-				  unsigned int *handle)
-{
-	if (handle)
-		*handle = 0;
-
-	return 0;
-}
-
 /*
  * Surface framebuffer code
  */
@@ -610,7 +600,6 @@ int vmw_framebuffer_surface_dirty(struct drm_framebuffer *framebuffer,
 static struct drm_framebuffer_funcs vmw_framebuffer_surface_funcs = {
 	.destroy = vmw_framebuffer_surface_destroy,
 	.dirty = vmw_framebuffer_surface_dirty,
-	.create_handle = vmw_framebuffer_create_handle,
 };
 
 static int vmw_kms_new_framebuffer_surface(struct vmw_private *dev_priv,
@@ -961,7 +950,6 @@ int vmw_framebuffer_dmabuf_dirty(struct drm_framebuffer *framebuffer,
 static struct drm_framebuffer_funcs vmw_framebuffer_dmabuf_funcs = {
 	.destroy = vmw_framebuffer_dmabuf_destroy,
 	.dirty = vmw_framebuffer_dmabuf_dirty,
-	.create_handle = vmw_framebuffer_create_handle,
 };
 
 /**
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PATCH 09/35] drm: encapsulate crtc->set_config calls
  2013-01-10 20:47 [PATCH 00/36] kms locking rework Daniel Vetter
                   ` (7 preceding siblings ...)
  2013-01-10 20:47 ` [PATCH 08/35] drm/<drivers>: Unified handling of unimplemented fb->create_handle Daniel Vetter
@ 2013-01-10 20:47 ` Daniel Vetter
  2013-01-10 20:47 ` [PATCH 10/35] drm: add drm_modeset_lock|unlock_all Daniel Vetter
                   ` (27 subsequent siblings)
  36 siblings, 0 replies; 45+ messages in thread
From: Daniel Vetter @ 2013-01-10 20:47 UTC (permalink / raw)
  To: DRI Development; +Cc: Daniel Vetter

With refcounting we need to adjust framebuffer refcounts at each
callsite - much easier to do if they all call the same little helper
function.

Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 drivers/gpu/drm/drm_crtc.c             |   19 +++++++++++++++++--
 drivers/gpu/drm/drm_fb_helper.c        |    6 +++---
 drivers/gpu/drm/i2c/ch7006_drv.c       |    2 +-
 drivers/gpu/drm/nouveau/nv04_display.c |    2 +-
 drivers/gpu/drm/nouveau/nv17_tv.c      |    2 +-
 drivers/gpu/drm/vmwgfx/vmwgfx_drv.c    |    2 +-
 include/drm/drm_crtc.h                 |    1 +
 7 files changed, 25 insertions(+), 9 deletions(-)

diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index a9abf49..7ca2f28 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -381,7 +381,7 @@ void drm_framebuffer_remove(struct drm_framebuffer *fb)
 			memset(&set, 0, sizeof(struct drm_mode_set));
 			set.crtc = crtc;
 			set.fb = NULL;
-			ret = crtc->funcs->set_config(&set);
+			ret = drm_mode_set_config_internal(&set);
 			if (ret)
 				DRM_ERROR("failed to reset crtc %p when fb was deleted\n", crtc);
 		}
@@ -1801,6 +1801,21 @@ out:
 }
 
 /**
+ * drm_mode_set_config_internal - helper to call ->set_config
+ * @set: modeset config to set
+ *
+ * This is a little helper to wrap internal calls to the ->set_config driver
+ * interface. The only thing it adds is correct refcounting dance.
+ */
+int drm_mode_set_config_internal(struct drm_mode_set *set)
+{
+	struct drm_crtc *crtc = set->crtc;
+
+	return crtc->funcs->set_config(set);
+}
+EXPORT_SYMBOL(drm_mode_set_config_internal);
+
+/**
  * drm_mode_setcrtc - set CRTC configuration
  * @dev: drm device for the ioctl
  * @data: data pointer for the ioctl
@@ -1963,7 +1978,7 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data,
 	set.connectors = connector_set;
 	set.num_connectors = crtc_req->count_connectors;
 	set.fb = fb;
-	ret = crtc->funcs->set_config(&set);
+	ret = drm_mode_set_config_internal(&set);
 
 out:
 	kfree(connector_set);
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index 954d175..82c3a9f 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -245,7 +245,7 @@ bool drm_fb_helper_restore_fbdev_mode(struct drm_fb_helper *fb_helper)
 	int i, ret;
 	for (i = 0; i < fb_helper->crtc_count; i++) {
 		struct drm_mode_set *mode_set = &fb_helper->crtc_info[i].mode_set;
-		ret = mode_set->crtc->funcs->set_config(mode_set);
+		ret = drm_mode_set_config_internal(mode_set);
 		if (ret)
 			error = true;
 	}
@@ -675,7 +675,7 @@ int drm_fb_helper_set_par(struct fb_info *info)
 	mutex_lock(&dev->mode_config.mutex);
 	for (i = 0; i < fb_helper->crtc_count; i++) {
 		crtc = fb_helper->crtc_info[i].mode_set.crtc;
-		ret = crtc->funcs->set_config(&fb_helper->crtc_info[i].mode_set);
+		ret = drm_mode_set_config_internal(&fb_helper->crtc_info[i].mode_set);
 		if (ret) {
 			mutex_unlock(&dev->mode_config.mutex);
 			return ret;
@@ -711,7 +711,7 @@ int drm_fb_helper_pan_display(struct fb_var_screeninfo *var,
 		modeset->y = var->yoffset;
 
 		if (modeset->num_connectors) {
-			ret = crtc->funcs->set_config(modeset);
+			ret = drm_mode_set_config_internal(modeset);
 			if (!ret) {
 				info->var.xoffset = var->xoffset;
 				info->var.yoffset = var->yoffset;
diff --git a/drivers/gpu/drm/i2c/ch7006_drv.c b/drivers/gpu/drm/i2c/ch7006_drv.c
index b865d07..51fa323 100644
--- a/drivers/gpu/drm/i2c/ch7006_drv.c
+++ b/drivers/gpu/drm/i2c/ch7006_drv.c
@@ -364,7 +364,7 @@ static int ch7006_encoder_set_property(struct drm_encoder *encoder,
 				.crtc = crtc,
 			};
 
-			crtc->funcs->set_config(&modeset);
+			drm_mode_set_config_internal(&modeset);
 		}
 	}
 
diff --git a/drivers/gpu/drm/nouveau/nv04_display.c b/drivers/gpu/drm/nouveau/nv04_display.c
index 2cd6fb8..4c6e9f8 100644
--- a/drivers/gpu/drm/nouveau/nv04_display.c
+++ b/drivers/gpu/drm/nouveau/nv04_display.c
@@ -140,7 +140,7 @@ nv04_display_destroy(struct drm_device *dev)
 			.crtc = crtc,
 		};
 
-		crtc->funcs->set_config(&modeset);
+		drm_mode_set_config_internal(&modeset);
 	}
 
 	/* Restore state */
diff --git a/drivers/gpu/drm/nouveau/nv17_tv.c b/drivers/gpu/drm/nouveau/nv17_tv.c
index 2ca276a..977e42b 100644
--- a/drivers/gpu/drm/nouveau/nv17_tv.c
+++ b/drivers/gpu/drm/nouveau/nv17_tv.c
@@ -768,7 +768,7 @@ static int nv17_tv_set_property(struct drm_encoder *encoder,
 				.crtc = crtc,
 			};
 
-			crtc->funcs->set_config(&modeset);
+			drm_mode_set_config_internal(&modeset);
 		}
 	}
 
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
index 161f8b2..07dfd82 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
@@ -829,7 +829,7 @@ static void vmw_lastclose(struct drm_device *dev)
 
 	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
 		set.crtc = crtc;
-		ret = crtc->funcs->set_config(&set);
+		ret = drm_mode_set_config_internal(&set);
 		WARN_ON(ret != 0);
 	}
 
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index 00d78b5..665289a 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -985,6 +985,7 @@ extern int drm_mode_getcrtc(struct drm_device *dev,
 			    void *data, struct drm_file *file_priv);
 extern int drm_mode_getconnector(struct drm_device *dev,
 			      void *data, struct drm_file *file_priv);
+extern int drm_mode_set_config_internal(struct drm_mode_set *set);
 extern int drm_mode_setcrtc(struct drm_device *dev,
 			    void *data, struct drm_file *file_priv);
 extern int drm_mode_getplane(struct drm_device *dev,
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PATCH 10/35] drm: add drm_modeset_lock|unlock_all
  2013-01-10 20:47 [PATCH 00/36] kms locking rework Daniel Vetter
                   ` (8 preceding siblings ...)
  2013-01-10 20:47 ` [PATCH 09/35] drm: encapsulate crtc->set_config calls Daniel Vetter
@ 2013-01-10 20:47 ` Daniel Vetter
  2013-01-10 20:47 ` [PATCH 11/35] drm/i915: use drm_modeset_lock_all Daniel Vetter
                   ` (26 subsequent siblings)
  36 siblings, 0 replies; 45+ messages in thread
From: Daniel Vetter @ 2013-01-10 20:47 UTC (permalink / raw)
  To: DRI Development; +Cc: Daniel Vetter

This is the first step towards introducing the new modeset locking
scheme. The plan is to put helper functions into place at all the
right places step-by-step, so that the final patch to switch on the
new locking scheme doesn't need to touch every single driver.

This helper here will serve as the shotgun solutions for all places
where a more fine-grained locking isn't (yet) implemented.

Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 drivers/gpu/drm/drm_crtc.c        |  147 +++++++++++++++++++++----------------
 drivers/gpu/drm/drm_crtc_helper.c |    8 +-
 drivers/gpu/drm/drm_fb_helper.c   |   20 ++---
 include/drm/drm_crtc.h            |    3 +
 4 files changed, 102 insertions(+), 76 deletions(-)

diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index 7ca2f28..7c8c5cd 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -37,6 +37,29 @@
 #include <drm/drm_edid.h>
 #include <drm/drm_fourcc.h>
 
+/**
+ * drm_modeset_lock_all - take all modeset locks
+ * @dev: drm device
+ *
+ * This function takes all modeset locks, suitable where a more fine-grained
+ * scheme isn't (yet) implemented.
+ */
+void drm_modeset_lock_all(struct drm_device *dev)
+{
+	mutex_lock(&dev->mode_config.mutex);
+}
+EXPORT_SYMBOL(drm_modeset_lock_all);
+
+/**
+ * drm_modeset_unlock_all - drop all modeset locks
+ * @drm: device
+ */
+void drm_modeset_unlock_all(struct drm_device *dev)
+{
+	mutex_unlock(&dev->mode_config.mutex);
+}
+EXPORT_SYMBOL(drm_modeset_unlock_all);
+
 /* Avoid boilerplate.  I'm tired of typing. */
 #define DRM_ENUM_NAME_FN(fnname, list)				\
 	char *fnname(int val)					\
@@ -425,7 +448,7 @@ int drm_crtc_init(struct drm_device *dev, struct drm_crtc *crtc,
 	crtc->funcs = funcs;
 	crtc->invert_dimensions = false;
 
-	mutex_lock(&dev->mode_config.mutex);
+	drm_modeset_lock_all(dev);
 
 	ret = drm_mode_object_get(dev, &crtc->base, DRM_MODE_OBJECT_CRTC);
 	if (ret)
@@ -437,7 +460,7 @@ int drm_crtc_init(struct drm_device *dev, struct drm_crtc *crtc,
 	dev->mode_config.num_crtc++;
 
  out:
-	mutex_unlock(&dev->mode_config.mutex);
+	drm_modeset_unlock_all(dev);
 
 	return ret;
 }
@@ -512,7 +535,7 @@ int drm_connector_init(struct drm_device *dev,
 {
 	int ret;
 
-	mutex_lock(&dev->mode_config.mutex);
+	drm_modeset_lock_all(dev);
 
 	ret = drm_mode_object_get(dev, &connector->base, DRM_MODE_OBJECT_CONNECTOR);
 	if (ret)
@@ -542,7 +565,7 @@ int drm_connector_init(struct drm_device *dev,
 				      dev->mode_config.dpms_property, 0);
 
  out:
-	mutex_unlock(&dev->mode_config.mutex);
+	drm_modeset_unlock_all(dev);
 
 	return ret;
 }
@@ -592,7 +615,7 @@ int drm_encoder_init(struct drm_device *dev,
 {
 	int ret;
 
-	mutex_lock(&dev->mode_config.mutex);
+	drm_modeset_lock_all(dev);
 
 	ret = drm_mode_object_get(dev, &encoder->base, DRM_MODE_OBJECT_ENCODER);
 	if (ret)
@@ -606,7 +629,7 @@ int drm_encoder_init(struct drm_device *dev,
 	dev->mode_config.num_encoder++;
 
  out:
-	mutex_unlock(&dev->mode_config.mutex);
+	drm_modeset_unlock_all(dev);
 
 	return ret;
 }
@@ -615,11 +638,11 @@ EXPORT_SYMBOL(drm_encoder_init);
 void drm_encoder_cleanup(struct drm_encoder *encoder)
 {
 	struct drm_device *dev = encoder->dev;
-	mutex_lock(&dev->mode_config.mutex);
+	drm_modeset_lock_all(dev);
 	drm_mode_object_put(dev, &encoder->base);
 	list_del(&encoder->head);
 	dev->mode_config.num_encoder--;
-	mutex_unlock(&dev->mode_config.mutex);
+	drm_modeset_unlock_all(dev);
 }
 EXPORT_SYMBOL(drm_encoder_cleanup);
 
@@ -631,7 +654,7 @@ int drm_plane_init(struct drm_device *dev, struct drm_plane *plane,
 {
 	int ret;
 
-	mutex_lock(&dev->mode_config.mutex);
+	drm_modeset_lock_all(dev);
 
 	ret = drm_mode_object_get(dev, &plane->base, DRM_MODE_OBJECT_PLANE);
 	if (ret)
@@ -665,7 +688,7 @@ int drm_plane_init(struct drm_device *dev, struct drm_plane *plane,
 	}
 
  out:
-	mutex_unlock(&dev->mode_config.mutex);
+	drm_modeset_unlock_all(dev);
 
 	return ret;
 }
@@ -675,7 +698,7 @@ void drm_plane_cleanup(struct drm_plane *plane)
 {
 	struct drm_device *dev = plane->dev;
 
-	mutex_lock(&dev->mode_config.mutex);
+	drm_modeset_lock_all(dev);
 	kfree(plane->format_types);
 	drm_mode_object_put(dev, &plane->base);
 	/* if not added to a list, it must be a private plane */
@@ -683,7 +706,7 @@ void drm_plane_cleanup(struct drm_plane *plane)
 		list_del(&plane->head);
 		dev->mode_config.num_plane--;
 	}
-	mutex_unlock(&dev->mode_config.mutex);
+	drm_modeset_unlock_all(dev);
 }
 EXPORT_SYMBOL(drm_plane_cleanup);
 
@@ -963,9 +986,9 @@ void drm_mode_config_init(struct drm_device *dev)
 	INIT_LIST_HEAD(&dev->mode_config.plane_list);
 	idr_init(&dev->mode_config.crtc_idr);
 
-	mutex_lock(&dev->mode_config.mutex);
+	drm_modeset_lock_all(dev);
 	drm_mode_create_standard_connector_properties(dev);
-	mutex_unlock(&dev->mode_config.mutex);
+	drm_modeset_unlock_all(dev);
 
 	/* Just to be sure */
 	dev->mode_config.num_fb = 0;
@@ -1185,7 +1208,7 @@ int drm_mode_getresources(struct drm_device *dev, void *data,
 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
 		return -EINVAL;
 
-	mutex_lock(&dev->mode_config.mutex);
+	drm_modeset_lock_all(dev);
 
 	/*
 	 * For the non-control nodes we need to limit the list of resources
@@ -1327,7 +1350,7 @@ int drm_mode_getresources(struct drm_device *dev, void *data,
 		  card_res->count_connectors, card_res->count_encoders);
 
 out:
-	mutex_unlock(&dev->mode_config.mutex);
+	drm_modeset_unlock_all(dev);
 	return ret;
 }
 
@@ -1355,7 +1378,7 @@ int drm_mode_getcrtc(struct drm_device *dev,
 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
 		return -EINVAL;
 
-	mutex_lock(&dev->mode_config.mutex);
+	drm_modeset_lock_all(dev);
 
 	obj = drm_mode_object_find(dev, crtc_resp->crtc_id,
 				   DRM_MODE_OBJECT_CRTC);
@@ -1383,7 +1406,7 @@ int drm_mode_getcrtc(struct drm_device *dev,
 	}
 
 out:
-	mutex_unlock(&dev->mode_config.mutex);
+	drm_modeset_unlock_all(dev);
 	return ret;
 }
 
@@ -1426,7 +1449,7 @@ int drm_mode_getconnector(struct drm_device *dev, void *data,
 
 	DRM_DEBUG_KMS("[CONNECTOR:%d:?]\n", out_resp->connector_id);
 
-	mutex_lock(&dev->mode_config.mutex);
+	drm_modeset_lock_all(dev);
 
 	obj = drm_mode_object_find(dev, out_resp->connector_id,
 				   DRM_MODE_OBJECT_CONNECTOR);
@@ -1523,7 +1546,7 @@ int drm_mode_getconnector(struct drm_device *dev, void *data,
 	out_resp->count_encoders = encoders_count;
 
 out:
-	mutex_unlock(&dev->mode_config.mutex);
+	drm_modeset_unlock_all(dev);
 	return ret;
 }
 
@@ -1538,7 +1561,7 @@ int drm_mode_getencoder(struct drm_device *dev, void *data,
 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
 		return -EINVAL;
 
-	mutex_lock(&dev->mode_config.mutex);
+	drm_modeset_lock_all(dev);
 	obj = drm_mode_object_find(dev, enc_resp->encoder_id,
 				   DRM_MODE_OBJECT_ENCODER);
 	if (!obj) {
@@ -1557,7 +1580,7 @@ int drm_mode_getencoder(struct drm_device *dev, void *data,
 	enc_resp->possible_clones = encoder->possible_clones;
 
 out:
-	mutex_unlock(&dev->mode_config.mutex);
+	drm_modeset_unlock_all(dev);
 	return ret;
 }
 
@@ -1581,7 +1604,7 @@ int drm_mode_getplane_res(struct drm_device *dev, void *data,
 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
 		return -EINVAL;
 
-	mutex_lock(&dev->mode_config.mutex);
+	drm_modeset_lock_all(dev);
 	config = &dev->mode_config;
 
 	/*
@@ -1603,7 +1626,7 @@ int drm_mode_getplane_res(struct drm_device *dev, void *data,
 	plane_resp->count_planes = config->num_plane;
 
 out:
-	mutex_unlock(&dev->mode_config.mutex);
+	drm_modeset_unlock_all(dev);
 	return ret;
 }
 
@@ -1628,7 +1651,7 @@ int drm_mode_getplane(struct drm_device *dev, void *data,
 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
 		return -EINVAL;
 
-	mutex_lock(&dev->mode_config.mutex);
+	drm_modeset_lock_all(dev);
 	obj = drm_mode_object_find(dev, plane_resp->plane_id,
 				   DRM_MODE_OBJECT_PLANE);
 	if (!obj) {
@@ -1668,7 +1691,7 @@ int drm_mode_getplane(struct drm_device *dev, void *data,
 	plane_resp->count_format_types = plane->format_count;
 
 out:
-	mutex_unlock(&dev->mode_config.mutex);
+	drm_modeset_unlock_all(dev);
 	return ret;
 }
 
@@ -1696,7 +1719,7 @@ int drm_mode_setplane(struct drm_device *dev, void *data,
 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
 		return -EINVAL;
 
-	mutex_lock(&dev->mode_config.mutex);
+	drm_modeset_lock_all(dev);
 
 	/*
 	 * First, find the plane, crtc, and fb objects.  If not available,
@@ -1795,7 +1818,7 @@ int drm_mode_setplane(struct drm_device *dev, void *data,
 	}
 
 out:
-	mutex_unlock(&dev->mode_config.mutex);
+	drm_modeset_unlock_all(dev);
 
 	return ret;
 }
@@ -1850,7 +1873,7 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data,
 	if (crtc_req->x > INT_MAX || crtc_req->y > INT_MAX)
 		return -ERANGE;
 
-	mutex_lock(&dev->mode_config.mutex);
+	drm_modeset_lock_all(dev);
 	obj = drm_mode_object_find(dev, crtc_req->crtc_id,
 				   DRM_MODE_OBJECT_CRTC);
 	if (!obj) {
@@ -1983,7 +2006,7 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data,
 out:
 	kfree(connector_set);
 	drm_mode_destroy(dev, mode);
-	mutex_unlock(&dev->mode_config.mutex);
+	drm_modeset_unlock_all(dev);
 	return ret;
 }
 
@@ -2001,7 +2024,7 @@ int drm_mode_cursor_ioctl(struct drm_device *dev,
 	if (!req->flags || (~DRM_MODE_CURSOR_FLAGS & req->flags))
 		return -EINVAL;
 
-	mutex_lock(&dev->mode_config.mutex);
+	drm_modeset_lock_all(dev);
 	obj = drm_mode_object_find(dev, req->crtc_id, DRM_MODE_OBJECT_CRTC);
 	if (!obj) {
 		DRM_DEBUG_KMS("Unknown CRTC ID %d\n", req->crtc_id);
@@ -2029,7 +2052,7 @@ int drm_mode_cursor_ioctl(struct drm_device *dev,
 		}
 	}
 out:
-	mutex_unlock(&dev->mode_config.mutex);
+	drm_modeset_unlock_all(dev);
 	return ret;
 }
 
@@ -2108,7 +2131,7 @@ int drm_mode_addfb(struct drm_device *dev,
 	if ((config->min_height > r.height) || (r.height > config->max_height))
 		return -EINVAL;
 
-	mutex_lock(&dev->mode_config.mutex);
+	drm_modeset_lock_all(dev);
 
 	/* TODO check buffer is sufficiently large */
 	/* TODO setup destructor callback */
@@ -2125,7 +2148,7 @@ int drm_mode_addfb(struct drm_device *dev,
 	DRM_DEBUG_KMS("[FB:%d]\n", fb->base.id);
 
 out:
-	mutex_unlock(&dev->mode_config.mutex);
+	drm_modeset_unlock_all(dev);
 	return ret;
 }
 
@@ -2293,7 +2316,7 @@ int drm_mode_addfb2(struct drm_device *dev,
 	if (ret)
 		return ret;
 
-	mutex_lock(&dev->mode_config.mutex);
+	drm_modeset_lock_all(dev);
 
 	fb = dev->mode_config.funcs->fb_create(dev, file_priv, r);
 	if (IS_ERR(fb)) {
@@ -2307,7 +2330,7 @@ int drm_mode_addfb2(struct drm_device *dev,
 	DRM_DEBUG_KMS("[FB:%d]\n", fb->base.id);
 
 out:
-	mutex_unlock(&dev->mode_config.mutex);
+	drm_modeset_unlock_all(dev);
 	return ret;
 }
 
@@ -2337,7 +2360,7 @@ int drm_mode_rmfb(struct drm_device *dev,
 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
 		return -EINVAL;
 
-	mutex_lock(&dev->mode_config.mutex);
+	drm_modeset_lock_all(dev);
 	obj = drm_mode_object_find(dev, *id, DRM_MODE_OBJECT_FB);
 	/* TODO check that we really get a framebuffer back. */
 	if (!obj) {
@@ -2358,7 +2381,7 @@ int drm_mode_rmfb(struct drm_device *dev,
 	drm_framebuffer_remove(fb);
 
 out:
-	mutex_unlock(&dev->mode_config.mutex);
+	drm_modeset_unlock_all(dev);
 	return ret;
 }
 
@@ -2386,7 +2409,7 @@ int drm_mode_getfb(struct drm_device *dev,
 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
 		return -EINVAL;
 
-	mutex_lock(&dev->mode_config.mutex);
+	drm_modeset_lock_all(dev);
 	obj = drm_mode_object_find(dev, r->fb_id, DRM_MODE_OBJECT_FB);
 	if (!obj) {
 		ret = -EINVAL;
@@ -2405,7 +2428,7 @@ int drm_mode_getfb(struct drm_device *dev,
 		ret = -ENODEV;
 
 out:
-	mutex_unlock(&dev->mode_config.mutex);
+	drm_modeset_unlock_all(dev);
 	return ret;
 }
 
@@ -2424,7 +2447,7 @@ int drm_mode_dirtyfb_ioctl(struct drm_device *dev,
 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
 		return -EINVAL;
 
-	mutex_lock(&dev->mode_config.mutex);
+	drm_modeset_lock_all(dev);
 	obj = drm_mode_object_find(dev, r->fb_id, DRM_MODE_OBJECT_FB);
 	if (!obj) {
 		ret = -EINVAL;
@@ -2478,7 +2501,7 @@ int drm_mode_dirtyfb_ioctl(struct drm_device *dev,
 out_err2:
 	kfree(clips);
 out_err1:
-	mutex_unlock(&dev->mode_config.mutex);
+	drm_modeset_unlock_all(dev);
 	return ret;
 }
 
@@ -2499,11 +2522,11 @@ void drm_fb_release(struct drm_file *priv)
 	struct drm_device *dev = priv->minor->dev;
 	struct drm_framebuffer *fb, *tfb;
 
-	mutex_lock(&dev->mode_config.mutex);
+	drm_modeset_lock_all(dev);
 	list_for_each_entry_safe(fb, tfb, &priv->fbs, filp_head) {
 		drm_framebuffer_remove(fb);
 	}
-	mutex_unlock(&dev->mode_config.mutex);
+	drm_modeset_unlock_all(dev);
 }
 
 /**
@@ -2618,7 +2641,7 @@ int drm_mode_attachmode_ioctl(struct drm_device *dev,
 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
 		return -EINVAL;
 
-	mutex_lock(&dev->mode_config.mutex);
+	drm_modeset_lock_all(dev);
 
 	obj = drm_mode_object_find(dev, mode_cmd->connector_id, DRM_MODE_OBJECT_CONNECTOR);
 	if (!obj) {
@@ -2642,7 +2665,7 @@ int drm_mode_attachmode_ioctl(struct drm_device *dev,
 
 	drm_mode_attachmode(dev, connector, mode);
 out:
-	mutex_unlock(&dev->mode_config.mutex);
+	drm_modeset_unlock_all(dev);
 	return ret;
 }
 
@@ -2671,7 +2694,7 @@ int drm_mode_detachmode_ioctl(struct drm_device *dev,
 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
 		return -EINVAL;
 
-	mutex_lock(&dev->mode_config.mutex);
+	drm_modeset_lock_all(dev);
 
 	obj = drm_mode_object_find(dev, mode_cmd->connector_id, DRM_MODE_OBJECT_CONNECTOR);
 	if (!obj) {
@@ -2688,7 +2711,7 @@ int drm_mode_detachmode_ioctl(struct drm_device *dev,
 
 	ret = drm_mode_detachmode(dev, connector, &mode);
 out:
-	mutex_unlock(&dev->mode_config.mutex);
+	drm_modeset_unlock_all(dev);
 	return ret;
 }
 
@@ -2934,7 +2957,7 @@ int drm_mode_getproperty_ioctl(struct drm_device *dev,
 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
 		return -EINVAL;
 
-	mutex_lock(&dev->mode_config.mutex);
+	drm_modeset_lock_all(dev);
 	obj = drm_mode_object_find(dev, out_resp->prop_id, DRM_MODE_OBJECT_PROPERTY);
 	if (!obj) {
 		ret = -EINVAL;
@@ -3012,7 +3035,7 @@ int drm_mode_getproperty_ioctl(struct drm_device *dev,
 		out_resp->count_enum_blobs = blob_count;
 	}
 done:
-	mutex_unlock(&dev->mode_config.mutex);
+	drm_modeset_unlock_all(dev);
 	return ret;
 }
 
@@ -3063,7 +3086,7 @@ int drm_mode_getblob_ioctl(struct drm_device *dev,
 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
 		return -EINVAL;
 
-	mutex_lock(&dev->mode_config.mutex);
+	drm_modeset_lock_all(dev);
 	obj = drm_mode_object_find(dev, out_resp->blob_id, DRM_MODE_OBJECT_BLOB);
 	if (!obj) {
 		ret = -EINVAL;
@@ -3081,7 +3104,7 @@ int drm_mode_getblob_ioctl(struct drm_device *dev,
 	out_resp->length = blob->length;
 
 done:
-	mutex_unlock(&dev->mode_config.mutex);
+	drm_modeset_unlock_all(dev);
 	return ret;
 }
 
@@ -3223,7 +3246,7 @@ int drm_mode_obj_get_properties_ioctl(struct drm_device *dev, void *data,
 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
 		return -EINVAL;
 
-	mutex_lock(&dev->mode_config.mutex);
+	drm_modeset_lock_all(dev);
 
 	obj = drm_mode_object_find(dev, arg->obj_id, arg->obj_type);
 	if (!obj) {
@@ -3260,7 +3283,7 @@ int drm_mode_obj_get_properties_ioctl(struct drm_device *dev, void *data,
 	}
 	arg->count_props = props_count;
 out:
-	mutex_unlock(&dev->mode_config.mutex);
+	drm_modeset_unlock_all(dev);
 	return ret;
 }
 
@@ -3277,7 +3300,7 @@ int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data,
 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
 		return -EINVAL;
 
-	mutex_lock(&dev->mode_config.mutex);
+	drm_modeset_lock_all(dev);
 
 	arg_obj = drm_mode_object_find(dev, arg->obj_id, arg->obj_type);
 	if (!arg_obj)
@@ -3315,7 +3338,7 @@ int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data,
 	}
 
 out:
-	mutex_unlock(&dev->mode_config.mutex);
+	drm_modeset_unlock_all(dev);
 	return ret;
 }
 
@@ -3377,7 +3400,7 @@ int drm_mode_gamma_set_ioctl(struct drm_device *dev,
 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
 		return -EINVAL;
 
-	mutex_lock(&dev->mode_config.mutex);
+	drm_modeset_lock_all(dev);
 	obj = drm_mode_object_find(dev, crtc_lut->crtc_id, DRM_MODE_OBJECT_CRTC);
 	if (!obj) {
 		ret = -EINVAL;
@@ -3418,7 +3441,7 @@ int drm_mode_gamma_set_ioctl(struct drm_device *dev,
 	crtc->funcs->gamma_set(crtc, r_base, g_base, b_base, 0, crtc->gamma_size);
 
 out:
-	mutex_unlock(&dev->mode_config.mutex);
+	drm_modeset_unlock_all(dev);
 	return ret;
 
 }
@@ -3436,7 +3459,7 @@ int drm_mode_gamma_get_ioctl(struct drm_device *dev,
 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
 		return -EINVAL;
 
-	mutex_lock(&dev->mode_config.mutex);
+	drm_modeset_lock_all(dev);
 	obj = drm_mode_object_find(dev, crtc_lut->crtc_id, DRM_MODE_OBJECT_CRTC);
 	if (!obj) {
 		ret = -EINVAL;
@@ -3469,7 +3492,7 @@ int drm_mode_gamma_get_ioctl(struct drm_device *dev,
 		goto out;
 	}
 out:
-	mutex_unlock(&dev->mode_config.mutex);
+	drm_modeset_unlock_all(dev);
 	return ret;
 }
 
@@ -3489,7 +3512,7 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev,
 	    page_flip->reserved != 0)
 		return -EINVAL;
 
-	mutex_lock(&dev->mode_config.mutex);
+	drm_modeset_lock_all(dev);
 	obj = drm_mode_object_find(dev, page_flip->crtc_id, DRM_MODE_OBJECT_CRTC);
 	if (!obj)
 		goto out;
@@ -3567,7 +3590,7 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev,
 	}
 
 out:
-	mutex_unlock(&dev->mode_config.mutex);
+	drm_modeset_unlock_all(dev);
 	return ret;
 }
 
diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c
index 7b2d378..400ef86 100644
--- a/drivers/gpu/drm/drm_crtc_helper.c
+++ b/drivers/gpu/drm/drm_crtc_helper.c
@@ -980,7 +980,7 @@ static void output_poll_execute(struct work_struct *work)
 	if (!drm_kms_helper_poll)
 		return;
 
-	mutex_lock(&dev->mode_config.mutex);
+	drm_modeset_lock_all(dev);
 	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
 
 		/* Ignore forced connectors. */
@@ -1010,7 +1010,7 @@ static void output_poll_execute(struct work_struct *work)
 			changed = true;
 	}
 
-	mutex_unlock(&dev->mode_config.mutex);
+	drm_modeset_unlock_all(dev);
 
 	if (changed)
 		drm_kms_helper_hotplug_event(dev);
@@ -1070,7 +1070,7 @@ void drm_helper_hpd_irq_event(struct drm_device *dev)
 	if (!dev->mode_config.poll_enabled)
 		return;
 
-	mutex_lock(&dev->mode_config.mutex);
+	drm_modeset_lock_all(dev);
 	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
 
 		/* Only handle HPD capable connectors. */
@@ -1088,7 +1088,7 @@ void drm_helper_hpd_irq_event(struct drm_device *dev)
 			changed = true;
 	}
 
-	mutex_unlock(&dev->mode_config.mutex);
+	drm_modeset_unlock_all(dev);
 
 	if (changed)
 		drm_kms_helper_hotplug_event(dev);
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index 82c3a9f..be0f2d6 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -337,7 +337,7 @@ static void drm_fb_helper_dpms(struct fb_info *info, int dpms_mode)
 	/*
 	 * For each CRTC in this fb, turn the connectors on/off.
 	 */
-	mutex_lock(&dev->mode_config.mutex);
+	drm_modeset_lock_all(dev);
 	for (i = 0; i < fb_helper->crtc_count; i++) {
 		crtc = fb_helper->crtc_info[i].mode_set.crtc;
 
@@ -352,7 +352,7 @@ static void drm_fb_helper_dpms(struct fb_info *info, int dpms_mode)
 				dev->mode_config.dpms_property, dpms_mode);
 		}
 	}
-	mutex_unlock(&dev->mode_config.mutex);
+	drm_modeset_unlock_all(dev);
 }
 
 int drm_fb_helper_blank(int blank, struct fb_info *info)
@@ -672,16 +672,16 @@ int drm_fb_helper_set_par(struct fb_info *info)
 		return -EINVAL;
 	}
 
-	mutex_lock(&dev->mode_config.mutex);
+	drm_modeset_lock_all(dev);
 	for (i = 0; i < fb_helper->crtc_count; i++) {
 		crtc = fb_helper->crtc_info[i].mode_set.crtc;
 		ret = drm_mode_set_config_internal(&fb_helper->crtc_info[i].mode_set);
 		if (ret) {
-			mutex_unlock(&dev->mode_config.mutex);
+			drm_modeset_unlock_all(dev);
 			return ret;
 		}
 	}
-	mutex_unlock(&dev->mode_config.mutex);
+	drm_modeset_unlock_all(dev);
 
 	if (fb_helper->delayed_hotplug) {
 		fb_helper->delayed_hotplug = false;
@@ -701,7 +701,7 @@ int drm_fb_helper_pan_display(struct fb_var_screeninfo *var,
 	int ret = 0;
 	int i;
 
-	mutex_lock(&dev->mode_config.mutex);
+	drm_modeset_lock_all(dev);
 	for (i = 0; i < fb_helper->crtc_count; i++) {
 		crtc = fb_helper->crtc_info[i].mode_set.crtc;
 
@@ -718,7 +718,7 @@ int drm_fb_helper_pan_display(struct fb_var_screeninfo *var,
 			}
 		}
 	}
-	mutex_unlock(&dev->mode_config.mutex);
+	drm_modeset_unlock_all(dev);
 	return ret;
 }
 EXPORT_SYMBOL(drm_fb_helper_pan_display);
@@ -1375,7 +1375,7 @@ int drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper)
 	if (!fb_helper->fb)
 		return 0;
 
-	mutex_lock(&dev->mode_config.mutex);
+	drm_modeset_lock_all(dev);
 	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
 		if (crtc->fb)
 			crtcs_bound++;
@@ -1385,7 +1385,7 @@ int drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper)
 
 	if (bound < crtcs_bound) {
 		fb_helper->delayed_hotplug = true;
-		mutex_unlock(&dev->mode_config.mutex);
+		drm_modeset_unlock_all(dev);
 		return 0;
 	}
 	DRM_DEBUG_KMS("\n");
@@ -1397,7 +1397,7 @@ int drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper)
 	count = drm_fb_helper_probe_connector_modes(fb_helper, max_width,
 						    max_height);
 	drm_setup_crtcs(fb_helper);
-	mutex_unlock(&dev->mode_config.mutex);
+	drm_modeset_unlock_all(dev);
 
 	return drm_fb_helper_single_fb_probe(fb_helper, bpp_sel);
 }
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index 665289a..9f0524d 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -842,6 +842,9 @@ struct drm_prop_enum_list {
 	char *name;
 };
 
+extern void drm_modeset_lock_all(struct drm_device *dev);
+extern void drm_modeset_unlock_all(struct drm_device *dev);
+
 extern int drm_crtc_init(struct drm_device *dev,
 			 struct drm_crtc *crtc,
 			 const struct drm_crtc_funcs *funcs);
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PATCH 11/35] drm/i915: use drm_modeset_lock_all
  2013-01-10 20:47 [PATCH 00/36] kms locking rework Daniel Vetter
                   ` (9 preceding siblings ...)
  2013-01-10 20:47 ` [PATCH 10/35] drm: add drm_modeset_lock|unlock_all Daniel Vetter
@ 2013-01-10 20:47 ` Daniel Vetter
  2013-01-10 20:47 ` [PATCH 12/35] drm/gma500: " Daniel Vetter
                   ` (25 subsequent siblings)
  36 siblings, 0 replies; 45+ messages in thread
From: Daniel Vetter @ 2013-01-10 20:47 UTC (permalink / raw)
  To: DRI Development; +Cc: Daniel Vetter

Two exceptions:
- debugfs files only read information which is not related to crtc, so
  can stay on the modeset_config lock.
- Same holds for the edp vdd work in intel_dp.c. Add a corresponding
  WARN_ON and a comment next to the intel_dp struct fields for
  documentation.

Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 drivers/gpu/drm/i915/intel_dp.c      |    2 ++
 drivers/gpu/drm/i915/intel_fb.c      |    4 ++--
 drivers/gpu/drm/i915/intel_lvds.c    |    4 ++--
 drivers/gpu/drm/i915/intel_overlay.c |   14 +++++++-------
 drivers/gpu/drm/i915/intel_sprite.c  |    8 ++++----
 5 files changed, 17 insertions(+), 15 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index 5f12eb2..e64c757 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -1101,6 +1101,8 @@ static void ironlake_panel_vdd_off_sync(struct intel_dp *intel_dp)
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	u32 pp;
 
+	WARN_ON(!mutex_is_locked(&dev->mode_config.mutex));
+
 	if (!intel_dp->want_panel_vdd && ironlake_edp_have_panel_vdd(intel_dp)) {
 		pp = ironlake_get_pp_control(dev_priv);
 		pp &= ~EDP_FORCE_VDD;
diff --git a/drivers/gpu/drm/i915/intel_fb.c b/drivers/gpu/drm/i915/intel_fb.c
index 71d5580..de2920f 100644
--- a/drivers/gpu/drm/i915/intel_fb.c
+++ b/drivers/gpu/drm/i915/intel_fb.c
@@ -297,7 +297,7 @@ void intel_fb_restore_mode(struct drm_device *dev)
 	struct drm_mode_config *config = &dev->mode_config;
 	struct drm_plane *plane;
 
-	mutex_lock(&dev->mode_config.mutex);
+	drm_modeset_lock_all(dev);
 
 	ret = drm_fb_helper_restore_fbdev_mode(&dev_priv->fbdev->helper);
 	if (ret)
@@ -307,5 +307,5 @@ void intel_fb_restore_mode(struct drm_device *dev)
 	list_for_each_entry(plane, &config->plane_list, head)
 		plane->funcs->disable_plane(plane);
 
-	mutex_unlock(&dev->mode_config.mutex);
+	drm_modeset_unlock_all(dev);
 }
diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c
index ef09c072..5e3f08e 100644
--- a/drivers/gpu/drm/i915/intel_lvds.c
+++ b/drivers/gpu/drm/i915/intel_lvds.c
@@ -586,9 +586,9 @@ static int intel_lid_notify(struct notifier_block *nb, unsigned long val,
 
 	dev_priv->modeset_on_lid = 0;
 
-	mutex_lock(&dev->mode_config.mutex);
+	drm_modeset_lock_all(dev);
 	intel_modeset_setup_hw_state(dev, true);
-	mutex_unlock(&dev->mode_config.mutex);
+	drm_modeset_unlock_all(dev);
 
 	return NOTIFY_OK;
 }
diff --git a/drivers/gpu/drm/i915/intel_overlay.c b/drivers/gpu/drm/i915/intel_overlay.c
index fabe0ac..1e901c3 100644
--- a/drivers/gpu/drm/i915/intel_overlay.c
+++ b/drivers/gpu/drm/i915/intel_overlay.c
@@ -1045,13 +1045,13 @@ int intel_overlay_put_image(struct drm_device *dev, void *data,
 	}
 
 	if (!(put_image_rec->flags & I915_OVERLAY_ENABLE)) {
-		mutex_lock(&dev->mode_config.mutex);
+		drm_modeset_lock_all(dev);
 		mutex_lock(&dev->struct_mutex);
 
 		ret = intel_overlay_switch_off(overlay);
 
 		mutex_unlock(&dev->struct_mutex);
-		mutex_unlock(&dev->mode_config.mutex);
+		drm_modeset_unlock_all(dev);
 
 		return ret;
 	}
@@ -1075,7 +1075,7 @@ int intel_overlay_put_image(struct drm_device *dev, void *data,
 		goto out_free;
 	}
 
-	mutex_lock(&dev->mode_config.mutex);
+	drm_modeset_lock_all(dev);
 	mutex_lock(&dev->struct_mutex);
 
 	if (new_bo->tiling_mode) {
@@ -1157,7 +1157,7 @@ int intel_overlay_put_image(struct drm_device *dev, void *data,
 		goto out_unlock;
 
 	mutex_unlock(&dev->struct_mutex);
-	mutex_unlock(&dev->mode_config.mutex);
+	drm_modeset_unlock_all(dev);
 
 	kfree(params);
 
@@ -1165,7 +1165,7 @@ int intel_overlay_put_image(struct drm_device *dev, void *data,
 
 out_unlock:
 	mutex_unlock(&dev->struct_mutex);
-	mutex_unlock(&dev->mode_config.mutex);
+	drm_modeset_unlock_all(dev);
 	drm_gem_object_unreference_unlocked(&new_bo->base);
 out_free:
 	kfree(params);
@@ -1241,7 +1241,7 @@ int intel_overlay_attrs(struct drm_device *dev, void *data,
 		return -ENODEV;
 	}
 
-	mutex_lock(&dev->mode_config.mutex);
+	drm_modeset_lock_all(dev);
 	mutex_lock(&dev->struct_mutex);
 
 	ret = -EINVAL;
@@ -1307,7 +1307,7 @@ int intel_overlay_attrs(struct drm_device *dev, void *data,
 	ret = 0;
 out_unlock:
 	mutex_unlock(&dev->struct_mutex);
-	mutex_unlock(&dev->mode_config.mutex);
+	drm_modeset_unlock_all(dev);
 
 	return ret;
 }
diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c
index d7b060e..f829306 100644
--- a/drivers/gpu/drm/i915/intel_sprite.c
+++ b/drivers/gpu/drm/i915/intel_sprite.c
@@ -593,7 +593,7 @@ int intel_sprite_set_colorkey(struct drm_device *dev, void *data,
 	if ((set->flags & (I915_SET_COLORKEY_DESTINATION | I915_SET_COLORKEY_SOURCE)) == (I915_SET_COLORKEY_DESTINATION | I915_SET_COLORKEY_SOURCE))
 		return -EINVAL;
 
-	mutex_lock(&dev->mode_config.mutex);
+	drm_modeset_lock_all(dev);
 
 	obj = drm_mode_object_find(dev, set->plane_id, DRM_MODE_OBJECT_PLANE);
 	if (!obj) {
@@ -606,7 +606,7 @@ int intel_sprite_set_colorkey(struct drm_device *dev, void *data,
 	ret = intel_plane->update_colorkey(plane, set);
 
 out_unlock:
-	mutex_unlock(&dev->mode_config.mutex);
+	drm_modeset_unlock_all(dev);
 	return ret;
 }
 
@@ -622,7 +622,7 @@ int intel_sprite_get_colorkey(struct drm_device *dev, void *data,
 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
 		return -ENODEV;
 
-	mutex_lock(&dev->mode_config.mutex);
+	drm_modeset_lock_all(dev);
 
 	obj = drm_mode_object_find(dev, get->plane_id, DRM_MODE_OBJECT_PLANE);
 	if (!obj) {
@@ -635,7 +635,7 @@ int intel_sprite_get_colorkey(struct drm_device *dev, void *data,
 	intel_plane->get_colorkey(plane, get);
 
 out_unlock:
-	mutex_unlock(&dev->mode_config.mutex);
+	drm_modeset_unlock_all(dev);
 	return ret;
 }
 
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PATCH 12/35] drm/gma500: use drm_modeset_lock_all
  2013-01-10 20:47 [PATCH 00/36] kms locking rework Daniel Vetter
                   ` (10 preceding siblings ...)
  2013-01-10 20:47 ` [PATCH 11/35] drm/i915: use drm_modeset_lock_all Daniel Vetter
@ 2013-01-10 20:47 ` Daniel Vetter
  2013-01-10 22:36   ` Alan Cox
  2013-01-10 20:47 ` [PATCH 13/35] drm/ast: " Daniel Vetter
                   ` (24 subsequent siblings)
  36 siblings, 1 reply; 45+ messages in thread
From: Daniel Vetter @ 2013-01-10 20:47 UTC (permalink / raw)
  To: DRI Development; +Cc: Daniel Vetter

Only two places:
- suspend/resume
- Some really strange mode validation tool with too much funny-lucking
  hand-rolled conversion code.
- The recently-added lastclose fbdev restore code.

Better safe than sorry, so convert both places to keep the locking
semantics as much as possible.

Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 drivers/gpu/drm/gma500/psb_device.c |    8 ++++----
 drivers/gpu/drm/gma500/psb_drv.c    |    8 ++++----
 2 files changed, 8 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/gma500/psb_device.c b/drivers/gpu/drm/gma500/psb_device.c
index b58c470..f6f534b 100644
--- a/drivers/gpu/drm/gma500/psb_device.c
+++ b/drivers/gpu/drm/gma500/psb_device.c
@@ -194,7 +194,7 @@ static int psb_save_display_registers(struct drm_device *dev)
 	regs->saveCHICKENBIT = PSB_RVDC32(DSPCHICKENBIT);
 
 	/* Save crtc and output state */
-	mutex_lock(&dev->mode_config.mutex);
+	drm_modeset_lock_all(dev);
 	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
 		if (drm_helper_crtc_in_use(crtc))
 			crtc->funcs->save(crtc);
@@ -204,7 +204,7 @@ static int psb_save_display_registers(struct drm_device *dev)
 		if (connector->funcs->save)
 			connector->funcs->save(connector);
 
-	mutex_unlock(&dev->mode_config.mutex);
+	drm_modeset_unlock_all(dev);
 	return 0;
 }
 
@@ -234,7 +234,7 @@ static int psb_restore_display_registers(struct drm_device *dev)
 	/*make sure VGA plane is off. it initializes to on after reset!*/
 	PSB_WVDC32(0x80000000, VGACNTRL);
 
-	mutex_lock(&dev->mode_config.mutex);
+	drm_modeset_lock_all(dev);
 	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head)
 		if (drm_helper_crtc_in_use(crtc))
 			crtc->funcs->restore(crtc);
@@ -243,7 +243,7 @@ static int psb_restore_display_registers(struct drm_device *dev)
 		if (connector->funcs->restore)
 			connector->funcs->restore(connector);
 
-	mutex_unlock(&dev->mode_config.mutex);
+	drm_modeset_unlock_all(dev);
 	return 0;
 }
 
diff --git a/drivers/gpu/drm/gma500/psb_drv.c b/drivers/gpu/drm/gma500/psb_drv.c
index dbcefe9..111e3df 100644
--- a/drivers/gpu/drm/gma500/psb_drv.c
+++ b/drivers/gpu/drm/gma500/psb_drv.c
@@ -153,11 +153,11 @@ static void psb_lastclose(struct drm_device *dev)
 	struct drm_psb_private *dev_priv = dev->dev_private;
 	struct psb_fbdev *fbdev = dev_priv->fbdev;
 
-	mutex_lock(&dev->mode_config.mutex);
+	drm_modeset_lock_all(dev);
 	ret = drm_fb_helper_restore_fbdev_mode(&fbdev->psb_fb_helper);
 	if (ret)
 		DRM_DEBUG("failed to restore crtc mode\n");
-	mutex_unlock(&dev->mode_config.mutex);
+	drm_modeset_unlock_all(dev);
 
 	return;
 }
@@ -486,7 +486,7 @@ static int psb_mode_operation_ioctl(struct drm_device *dev, void *data,
 	case PSB_MODE_OPERATION_MODE_VALID:
 		umode = &arg->mode;
 
-		mutex_lock(&dev->mode_config.mutex);
+		drm_modeset_lock_all(dev);
 
 		obj = drm_mode_object_find(dev, obj_id,
 					DRM_MODE_OBJECT_CONNECTOR);
@@ -535,7 +535,7 @@ static int psb_mode_operation_ioctl(struct drm_device *dev, void *data,
 		if (mode)
 			drm_mode_destroy(dev, mode);
 mode_op_out:
-		mutex_unlock(&dev->mode_config.mutex);
+		drm_modeset_unlock_all(dev);
 		return ret;
 
 	default:
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PATCH 13/35] drm/ast: use drm_modeset_lock_all
  2013-01-10 20:47 [PATCH 00/36] kms locking rework Daniel Vetter
                   ` (11 preceding siblings ...)
  2013-01-10 20:47 ` [PATCH 12/35] drm/gma500: " Daniel Vetter
@ 2013-01-10 20:47 ` Daniel Vetter
  2013-01-10 20:47 ` [PATCH 14/35] drm/shmobile: " Daniel Vetter
                   ` (23 subsequent siblings)
  36 siblings, 0 replies; 45+ messages in thread
From: Daniel Vetter @ 2013-01-10 20:47 UTC (permalink / raw)
  To: DRI Development; +Cc: Daniel Vetter

Just a call to drm_helper_resume_force_mode, obviously wants full
locking for that.

Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 drivers/gpu/drm/ast/ast_drv.c |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/ast/ast_drv.c b/drivers/gpu/drm/ast/ast_drv.c
index 31123b6..f5f24b3 100644
--- a/drivers/gpu/drm/ast/ast_drv.c
+++ b/drivers/gpu/drm/ast/ast_drv.c
@@ -95,9 +95,9 @@ static int ast_drm_thaw(struct drm_device *dev)
 	ast_post_gpu(dev);
 
 	drm_mode_config_reset(dev);
-	mutex_lock(&dev->mode_config.mutex);
+	drm_modeset_lock_all(dev);
 	drm_helper_resume_force_mode(dev);
-	mutex_unlock(&dev->mode_config.mutex);
+	drm_modeset_unlock_all(dev);
 
 	console_lock();
 	ast_fbdev_set_suspend(dev, 0);
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PATCH 14/35] drm/shmobile: use drm_modeset_lock_all
  2013-01-10 20:47 [PATCH 00/36] kms locking rework Daniel Vetter
                   ` (12 preceding siblings ...)
  2013-01-10 20:47 ` [PATCH 13/35] drm/ast: " Daniel Vetter
@ 2013-01-10 20:47 ` Daniel Vetter
  2013-01-10 20:47 ` [PATCH 15/35] drm/vmgfx: " Daniel Vetter
                   ` (22 subsequent siblings)
  36 siblings, 0 replies; 45+ messages in thread
From: Daniel Vetter @ 2013-01-10 20:47 UTC (permalink / raw)
  To: DRI Development; +Cc: Daniel Vetter

Only a resume method to account for.

v2: Fixup compilation.

Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 drivers/gpu/drm/shmobile/shmob_drm_drv.c |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/shmobile/shmob_drm_drv.c b/drivers/gpu/drm/shmobile/shmob_drm_drv.c
index 1c350fc..d701219 100644
--- a/drivers/gpu/drm/shmobile/shmob_drm_drv.c
+++ b/drivers/gpu/drm/shmobile/shmob_drm_drv.c
@@ -313,9 +313,9 @@ static int shmob_drm_pm_resume(struct device *dev)
 {
 	struct shmob_drm_device *sdev = dev_get_drvdata(dev);
 
-	mutex_lock(&sdev->ddev->mode_config.mutex);
+	drm_modeset_lock_all(sdev->ddev);
 	shmob_drm_crtc_resume(&sdev->crtc);
-	mutex_unlock(&sdev->ddev->mode_config.mutex);
+	drm_modeset_unlock_all(sdev->ddev);
 
 	drm_kms_helper_poll_enable(sdev->ddev);
 	return 0;
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PATCH 15/35] drm/vmgfx: use drm_modeset_lock_all
  2013-01-10 20:47 [PATCH 00/36] kms locking rework Daniel Vetter
                   ` (13 preceding siblings ...)
  2013-01-10 20:47 ` [PATCH 14/35] drm/shmobile: " Daniel Vetter
@ 2013-01-10 20:47 ` Daniel Vetter
  2013-01-10 20:47 ` [PATCH 16/35] drm: add per-crtc locks Daniel Vetter
                   ` (21 subsequent siblings)
  36 siblings, 0 replies; 45+ messages in thread
From: Daniel Vetter @ 2013-01-10 20:47 UTC (permalink / raw)
  To: DRI Development; +Cc: Daniel Vetter

Ok, this one here is a bit more complicated, but for an RFC I've
figured I can be a bit sloppy. So just convert ever mutex_lock call,
including the interruptible one. Since other places (e.g. in the
execbuf ioctl) take the mode_config.mutex without bothering with
interruptible handling, I've figured I should be able to get away with
this in a few more places ...

Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c |   18 ++++--------------
 1 file changed, 4 insertions(+), 14 deletions(-)

diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c
index d9fbbe1..a135498 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c
@@ -163,11 +163,7 @@ int vmw_present_ioctl(struct drm_device *dev, void *data,
 		goto out_no_copy;
 	}
 
-	ret = mutex_lock_interruptible(&dev->mode_config.mutex);
-	if (unlikely(ret != 0)) {
-		ret = -ERESTARTSYS;
-		goto out_no_mode_mutex;
-	}
+	drm_modeset_lock_all(dev);
 
 	obj = drm_mode_object_find(dev, arg->fb_id, DRM_MODE_OBJECT_FB);
 	if (!obj) {
@@ -200,8 +196,7 @@ out_no_surface:
 	ttm_read_unlock(&vmaster->lock);
 out_no_ttm_lock:
 out_no_fb:
-	mutex_unlock(&dev->mode_config.mutex);
-out_no_mode_mutex:
+	drm_modeset_unlock_all(dev);
 out_no_copy:
 	kfree(clips);
 out_clips:
@@ -251,11 +246,7 @@ int vmw_present_readback_ioctl(struct drm_device *dev, void *data,
 		goto out_no_copy;
 	}
 
-	ret = mutex_lock_interruptible(&dev->mode_config.mutex);
-	if (unlikely(ret != 0)) {
-		ret = -ERESTARTSYS;
-		goto out_no_mode_mutex;
-	}
+	drm_modeset_lock_all(dev);
 
 	obj = drm_mode_object_find(dev, arg->fb_id, DRM_MODE_OBJECT_FB);
 	if (!obj) {
@@ -282,8 +273,7 @@ int vmw_present_readback_ioctl(struct drm_device *dev, void *data,
 	ttm_read_unlock(&vmaster->lock);
 out_no_ttm_lock:
 out_no_fb:
-	mutex_unlock(&dev->mode_config.mutex);
-out_no_mode_mutex:
+	drm_modeset_unlock_all(dev);
 out_no_copy:
 	kfree(clips);
 out_clips:
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PATCH 16/35] drm: add per-crtc locks
  2013-01-10 20:47 [PATCH 00/36] kms locking rework Daniel Vetter
                   ` (14 preceding siblings ...)
  2013-01-10 20:47 ` [PATCH 15/35] drm/vmgfx: " Daniel Vetter
@ 2013-01-10 20:47 ` Daniel Vetter
  2013-01-10 20:47 ` [PATCH 17/35] drm: only take the crtc lock for ->cursor_set Daniel Vetter
                   ` (20 subsequent siblings)
  36 siblings, 0 replies; 45+ messages in thread
From: Daniel Vetter @ 2013-01-10 20:47 UTC (permalink / raw)
  To: DRI Development; +Cc: Daniel Vetter

*drumroll*

The basic idea is to protect per-crtc state which can change without
touching the output configuration with separate mutexes, i.e.  all the
input side state to a crtc like framebuffers, cursor settings or plane
configuration. Holding such a crtc lock gives a read-lock on all the
other crtc state which can be changed by e.g. a modeset.

All non-crtc state is still protected by the mode_config mutex.
Callers that need to change modeset state of a crtc (e.g. dpms or
set_mode) need to grab both the mode_config lock and nested within any
crtc locks.

Note that since there can only ever be one holder of the mode_config
lock we can grab the subordinate crtc locks in any order (if we need
to grab more than one of them). Lockdep can handle such nesting with
the mutex_lock_nest_lock call correctly.

With this functions that only touch connectors/encoders but not crtcs
only need to take the mode_config lock. The biggest such case is the
output probing, which means that we can now pageflip and move cursors
while the output probe code is reading an edid.

Most cases neatly fall into the three buckets:
- Only touches connectors and similar output state and so only needs
  the mode_config lock.
- Touches the global configuration and so needs all locks.
- Only touches the crtc input side and so only needs the crtc lock.

But a few cases that need special consideration:

- Load detection which requires a crtc. The mode_config lock already
  prevents a modeset change, so we can use any unused crtc as we like
  to do load detection. The only thing to consider is that such
  temporary state changes don't leak out to userspace through ioctls
  that only take the crtc look (like a pageflip). Hence the load
  detect code needs to grab the crtc of any output pipes it touches
  (but only if it touches state used by the pageflip or cursor
  ioctls).

- Atomic pageflip when moving planes. The first case is sane hw, where
  planes have a fixed association with crtcs - nothing needs to be
  done there. More insane^Wflexible hw needs to have plane->crtc
  mapping which is separately protect with a lock that nests within
  the crtc lock. If the plane is unused we can just assign it to the
  current crtc and continue. But if a plane is already in use by
  another crtc we can't just reassign it.

  Two solution present themselves: Either go back to a slow-path which
  takes all modeset locks, potentially incure quite a hefty delay. Or
  simply disallowing such changes in one atomic pageflip - in general
  the vblanks of two crtcs are not synced, so there's no sane way to
  atomically flip such plane changes accross more than one crtc. I'd
  heavily favour the later approach, going as far as mandating it as
  part of the ABI of such a new a nuclear pageflip.

  And if we _really_ want such semantics, we can always get them by
  introducing another pageflip mutex between the mode_config.mutex and
  the individual crtc locks. Pageflips crossing more than one crtc
  would then need to take that lock first, to lock out concurrent
  multi-crtc pageflips.

- Optimized global modeset operations: We could just take the
  mode_config lock and then lazily lock all crtc which are affected by
  a modeset operation. This has the advantage that pageflip could
  continue unhampered on unaffected crtc. But if e.g. global resources
  like plls need to be reassigned and so affect unrelated crtcs we can
  still do that - nested locking works in any order.

This patch just adds the locks and takes them in drm_modeset_lock_all,
no real locking changes yet.

v2: Need to initialize the new lock in crtc_init and lock it righ
away, for otherwise the modeset_unlock_all below will try to unlock a
not-locked mutex.

Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 drivers/gpu/drm/drm_crtc.c |   12 ++++++++++++
 include/drm/drm_crtc.h     |    9 +++++++++
 2 files changed, 21 insertions(+)

diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index 7c8c5cd..0494ff4 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -46,7 +46,12 @@
  */
 void drm_modeset_lock_all(struct drm_device *dev)
 {
+	struct drm_crtc *crtc;
+
 	mutex_lock(&dev->mode_config.mutex);
+
+	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head)
+		mutex_lock_nest_lock(&crtc->mutex, &dev->mode_config.mutex);
 }
 EXPORT_SYMBOL(drm_modeset_lock_all);
 
@@ -56,6 +61,11 @@ EXPORT_SYMBOL(drm_modeset_lock_all);
  */
 void drm_modeset_unlock_all(struct drm_device *dev)
 {
+	struct drm_crtc *crtc;
+
+	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head)
+		mutex_unlock(&crtc->mutex);
+
 	mutex_unlock(&dev->mode_config.mutex);
 }
 EXPORT_SYMBOL(drm_modeset_unlock_all);
@@ -449,6 +459,8 @@ int drm_crtc_init(struct drm_device *dev, struct drm_crtc *crtc,
 	crtc->invert_dimensions = false;
 
 	drm_modeset_lock_all(dev);
+	mutex_init(&crtc->mutex);
+	mutex_lock_nest_lock(&crtc->mutex, &dev->mode_config.mutex);
 
 	ret = drm_mode_object_get(dev, &crtc->base, DRM_MODE_OBJECT_CRTC);
 	if (ret)
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index 9f0524d..c89b116 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -390,6 +390,15 @@ struct drm_crtc {
 	struct drm_device *dev;
 	struct list_head head;
 
+	/**
+	 * crtc mutex
+	 *
+	 * This provides a read lock for the overall crtc state (mode, dpms
+	 * state, ...) and a write lock for everything which can be update
+	 * without a full modeset (fb, cursor data, ...)
+	 */
+	struct mutex mutex;
+
 	struct drm_mode_object base;
 
 	/* framebuffer the connector is currently bound to */
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PATCH 17/35] drm: only take the crtc lock for ->cursor_set
  2013-01-10 20:47 [PATCH 00/36] kms locking rework Daniel Vetter
                   ` (15 preceding siblings ...)
  2013-01-10 20:47 ` [PATCH 16/35] drm: add per-crtc locks Daniel Vetter
@ 2013-01-10 20:47 ` Daniel Vetter
  2013-01-10 20:47 ` [PATCH 18/35] drm: only take the crtc lock for ->cursor_move Daniel Vetter
                   ` (19 subsequent siblings)
  36 siblings, 0 replies; 45+ messages in thread
From: Daniel Vetter @ 2013-01-10 20:47 UTC (permalink / raw)
  To: DRI Development; +Cc: Daniel Vetter

First convert ->cursor_set to only take the crtc lock, since that
seems to be the function with the least amount of state - the core
ioctl function doesn't check anything which can change at runtime, so
we don't have any object lifetime issues to contend.

The only thing which is important is that the driver's implementation
doesn't touch any state outside of that single crtc which is not yet
properly protected by other locking:

- ast: access the global ast->cache_kmap. Luckily we only have on crtc
  on this driver, so this is fine. Add a comment.

- gma500: calls gma_power_begin|and and psb_gtt_pin|unpin, both which
  have their own locking to protect their state. Everything else is
  crtc-local.

- i915: touches a bit of global gem state, all protected by the One
  Lock to Rule Them All (dev->struct_mutex).

- nouveau: Pre-nv50 is all nice, nv50+ uses the evo channels to queue
  up all display changes. And some of these channels are device
  global. But this is fine now since the previous patch introduced an
  evo channel mutex.

- radeon: Uses some indirect register access for cursor updates, but
  with the previous patches to protect these indirect 2-register
  access patterns with a spinlock, this should be fine now, too.

- vmwgfx: I have no idea how that works - update_cursor_position
  doesn't take any per-crtc argument and I haven't figured out any
  other place where this could be set in some form of a side-channel.
  But vmwgfx definitely has more than one crtc (or at least can
  register more than one), so I have no idea how this is supposed to
  not fail with the current code already. Hence take the easy way out
  and simply acquire all locks (which requires dropping the crtc lock
  the core acquired for us). That way it's not worse off for
  consistency than the old code.

Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 drivers/gpu/drm/ast/ast_drv.h       |    2 ++
 drivers/gpu/drm/drm_crtc.c          |    6 ++++--
 drivers/gpu/drm/vmwgfx/vmwgfx_kms.c |   32 ++++++++++++++++++++++++++------
 3 files changed, 32 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/ast/ast_drv.h b/drivers/gpu/drm/ast/ast_drv.h
index 5ccf984..5284292 100644
--- a/drivers/gpu/drm/ast/ast_drv.h
+++ b/drivers/gpu/drm/ast/ast_drv.h
@@ -98,6 +98,8 @@ struct ast_private {
 
 	struct drm_gem_object *cursor_cache;
 	uint64_t cursor_cache_gpu_addr;
+	/* Acces to this cache is protected by the crtc->mutex of the only crtc
+	 * we have. */
 	struct ttm_bo_kmap_obj cache_kmap;
 	int next_cursor;
 };
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index 0494ff4..e62a12f 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -2036,7 +2036,6 @@ int drm_mode_cursor_ioctl(struct drm_device *dev,
 	if (!req->flags || (~DRM_MODE_CURSOR_FLAGS & req->flags))
 		return -EINVAL;
 
-	drm_modeset_lock_all(dev);
 	obj = drm_mode_object_find(dev, req->crtc_id, DRM_MODE_OBJECT_CRTC);
 	if (!obj) {
 		DRM_DEBUG_KMS("Unknown CRTC ID %d\n", req->crtc_id);
@@ -2051,20 +2050,23 @@ int drm_mode_cursor_ioctl(struct drm_device *dev,
 			goto out;
 		}
 		/* Turns off the cursor if handle is 0 */
+		mutex_lock(&crtc->mutex);
 		ret = crtc->funcs->cursor_set(crtc, file_priv, req->handle,
 					      req->width, req->height);
+		mutex_unlock(&crtc->mutex);
 	}
 
 	if (req->flags & DRM_MODE_CURSOR_MOVE) {
 		if (crtc->funcs->cursor_move) {
+			drm_modeset_lock_all(dev);
 			ret = crtc->funcs->cursor_move(crtc, req->x, req->y);
+			drm_modeset_unlock_all(dev);
 		} else {
 			ret = -EFAULT;
 			goto out;
 		}
 	}
 out:
-	drm_modeset_unlock_all(dev);
 	return ret;
 }
 
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
index 9c0876b..8d82e63 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
@@ -180,16 +180,29 @@ int vmw_du_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv,
 	struct vmw_dma_buffer *dmabuf = NULL;
 	int ret;
 
+	/*
+	 * FIXME: Unclear whether there's any global state touched by the
+	 * cursor_set function, especially vmw_cursor_update_position looks
+	 * suspicious. For now take the easy route and reacquire all locks. We
+	 * can do this since the caller in the drm core doesn't check anything
+	 * which is protected by any looks.
+	 */
+	mutex_unlock(&crtc->mutex);
+	drm_modeset_lock_all(dev_priv->dev);
+
 	/* A lot of the code assumes this */
-	if (handle && (width != 64 || height != 64))
-		return -EINVAL;
+	if (handle && (width != 64 || height != 64)) {
+		ret = -EINVAL;
+		goto out;
+	}
 
 	if (handle) {
 		ret = vmw_user_lookup_handle(dev_priv, tfile,
 					     handle, &surface, &dmabuf);
 		if (ret) {
 			DRM_ERROR("failed to find surface or dmabuf: %i\n", ret);
-			return -EINVAL;
+			ret = -EINVAL;
+			goto out;
 		}
 	}
 
@@ -197,7 +210,8 @@ int vmw_du_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv,
 	if (surface && !surface->snooper.image) {
 		DRM_ERROR("surface not suitable for cursor\n");
 		vmw_surface_unreference(&surface);
-		return -EINVAL;
+		ret = -EINVAL;
+		goto out;
 	}
 
 	/* takedown old cursor */
@@ -225,14 +239,20 @@ int vmw_du_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv,
 					       du->hotspot_x, du->hotspot_y);
 	} else {
 		vmw_cursor_update_position(dev_priv, false, 0, 0);
-		return 0;
+		ret = 0;
+		goto out;
 	}
 
 	vmw_cursor_update_position(dev_priv, true,
 				   du->cursor_x + du->hotspot_x,
 				   du->cursor_y + du->hotspot_y);
 
-	return 0;
+	ret = 0;
+out:
+	drm_modeset_unlock_all(dev_priv->dev);
+	mutex_lock(&crtc->mutex);
+
+	return ret;
 }
 
 int vmw_du_crtc_cursor_move(struct drm_crtc *crtc, int x, int y)
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PATCH 18/35] drm: only take the crtc lock for ->cursor_move
  2013-01-10 20:47 [PATCH 00/36] kms locking rework Daniel Vetter
                   ` (16 preceding siblings ...)
  2013-01-10 20:47 ` [PATCH 17/35] drm: only take the crtc lock for ->cursor_set Daniel Vetter
@ 2013-01-10 20:47 ` Daniel Vetter
  2013-01-10 20:48 ` [PATCH 19/35] drm: revamp locking around fb creation/destruction Daniel Vetter
                   ` (18 subsequent siblings)
  36 siblings, 0 replies; 45+ messages in thread
From: Daniel Vetter @ 2013-01-10 20:47 UTC (permalink / raw)
  To: DRI Development; +Cc: Daniel Vetter

->cursor_move uses mostly the same facilities in drivers as
->cursor_set, so pretty much nothing to fix up:

- ast/gma500/i915: They all use per-crtc registers to update the
  cursor position. ast again touches the global cursor cache, but
  that's ok since there's only one crtc.

- nouveau: nv50+ is again special, updates happen through the per-crtc
  channel (without pushbufs), so it's not protected by the new evo
  lock introduced earlier. But since this channel is per-crtc, we
  should be fine anyway.

- radeon: A bit a mess: avivo asics need a workaround when both output
  pipes are enabled, which means it'll access the crtc list. Just
  reading that flag is ok though as long as radeon _always_ grabs all
  locks when changing the crtc configuration. Which means with the
  current scheme it cannot do an optimized modeset which only locks
  the relevant crtcs. This can be fixed though by introducing a bit of
  global state with separate locks and ensure in the modeset code that
  the cursor will be updated appropriately when enabling the 2nd pipe
  (on affected asics).

- vmwgfx: I still don't understand what it's doing exactly, so apply
  the same trick for now.

v2: Fixup unlocking for the error cases, spotted by Richard Wilbur.

v3: Another error-case fixup.

Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 drivers/gpu/drm/drm_crtc.c             |   10 ++++------
 drivers/gpu/drm/radeon/radeon_cursor.c |    8 +++++++-
 drivers/gpu/drm/vmwgfx/vmwgfx_kms.c    |   13 +++++++++++++
 3 files changed, 24 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index e62a12f..457e4faf 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -2039,34 +2039,32 @@ int drm_mode_cursor_ioctl(struct drm_device *dev,
 	obj = drm_mode_object_find(dev, req->crtc_id, DRM_MODE_OBJECT_CRTC);
 	if (!obj) {
 		DRM_DEBUG_KMS("Unknown CRTC ID %d\n", req->crtc_id);
-		ret = -EINVAL;
-		goto out;
+		return -EINVAL;
 	}
 	crtc = obj_to_crtc(obj);
 
+	mutex_lock(&crtc->mutex);
 	if (req->flags & DRM_MODE_CURSOR_BO) {
 		if (!crtc->funcs->cursor_set) {
 			ret = -ENXIO;
 			goto out;
 		}
 		/* Turns off the cursor if handle is 0 */
-		mutex_lock(&crtc->mutex);
 		ret = crtc->funcs->cursor_set(crtc, file_priv, req->handle,
 					      req->width, req->height);
-		mutex_unlock(&crtc->mutex);
 	}
 
 	if (req->flags & DRM_MODE_CURSOR_MOVE) {
 		if (crtc->funcs->cursor_move) {
-			drm_modeset_lock_all(dev);
 			ret = crtc->funcs->cursor_move(crtc, req->x, req->y);
-			drm_modeset_unlock_all(dev);
 		} else {
 			ret = -EFAULT;
 			goto out;
 		}
 	}
 out:
+	mutex_unlock(&crtc->mutex);
+
 	return ret;
 }
 
diff --git a/drivers/gpu/drm/radeon/radeon_cursor.c b/drivers/gpu/drm/radeon/radeon_cursor.c
index ad6df62..c1680e6 100644
--- a/drivers/gpu/drm/radeon/radeon_cursor.c
+++ b/drivers/gpu/drm/radeon/radeon_cursor.c
@@ -245,8 +245,14 @@ int radeon_crtc_cursor_move(struct drm_crtc *crtc,
 		int i = 0;
 		struct drm_crtc *crtc_p;
 
-		/* avivo cursor image can't end on 128 pixel boundary or
+		/*
+		 * avivo cursor image can't end on 128 pixel boundary or
 		 * go past the end of the frame if both crtcs are enabled
+		 *
+		 * NOTE: It is safe to access crtc->enabled of other crtcs
+		 * without holding either the mode_config lock or the other
+		 * crtc's lock as long as write access to this flag _always_
+		 * grabs all locks.
 		 */
 		list_for_each_entry(crtc_p, &crtc->dev->mode_config.crtc_list, head) {
 			if (crtc_p->enabled)
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
index 8d82e63..3e3c7ab 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
@@ -264,10 +264,23 @@ int vmw_du_crtc_cursor_move(struct drm_crtc *crtc, int x, int y)
 	du->cursor_x = x + crtc->x;
 	du->cursor_y = y + crtc->y;
 
+	/*
+	 * FIXME: Unclear whether there's any global state touched by the
+	 * cursor_set function, especially vmw_cursor_update_position looks
+	 * suspicious. For now take the easy route and reacquire all locks. We
+	 * can do this since the caller in the drm core doesn't check anything
+	 * which is protected by any looks.
+	 */
+	mutex_unlock(&crtc->mutex);
+	drm_modeset_lock_all(dev_priv->dev);
+
 	vmw_cursor_update_position(dev_priv, shown,
 				   du->cursor_x + du->hotspot_x,
 				   du->cursor_y + du->hotspot_y);
 
+	drm_modeset_unlock_all(dev_priv->dev);
+	mutex_lock(&crtc->mutex);
+
 	return 0;
 }
 
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PATCH 19/35] drm: revamp locking around fb creation/destruction
  2013-01-10 20:47 [PATCH 00/36] kms locking rework Daniel Vetter
                   ` (17 preceding siblings ...)
  2013-01-10 20:47 ` [PATCH 18/35] drm: only take the crtc lock for ->cursor_move Daniel Vetter
@ 2013-01-10 20:48 ` Daniel Vetter
  2013-01-10 20:48 ` [PATCH 20/35] drm: create drm_framebuffer_lookup Daniel Vetter
                   ` (17 subsequent siblings)
  36 siblings, 0 replies; 45+ messages in thread
From: Daniel Vetter @ 2013-01-10 20:48 UTC (permalink / raw)
  To: DRI Development; +Cc: Daniel Vetter

Well, at least step 1. The goal here is that framebuffer objects can
survive outside of the mode_config lock, with just a reference held
as protection. The first step to get there is to introduce a special
fb_lock which protects fb lookup, creation and destruction, to make
them appear atomic.

This new fb_lock can nest within the mode_config lock. But the idea is
(once the reference counting part is completed) that we only quickly
take that fb_lock to lookup a framebuffer and grab a reference,
without any other locks involved.

vmwgfx is the only driver which does framebuffer lookups itself, also
wrap those calls to drm_mode_object_find with the new lock.

Also protect the fb_list walking in i915 and omapdrm with the new lock.

As a slight complication there's also the list of user-created fbs
attached to the file private. The problem now is that at fclose() time
we need to walk that list, eventually do a modeset call to remove the
fb from active usage (and are required to be able to take the
mode_config lock), but in the end we need to grab the new fb_lock to
remove the fb from the list. The easiest solution is to add another
mutex to protect this per-file list.

Currently that new fbs_lock nests within the modeset locks and so
appears redudant. But later patches will switch around this sequence
so that taking the modeset locks in the fb destruction path is
optional in the fastpath. Ultimately the goal is that addfb and rmfb
do not require the mode_config lock, since otherwise they have the
potential to introduce stalls in the pageflip sequence of a compositor
(if the compositor e.g. switches to a fullscreen client or if it
enables a plane). But that requires a few more steps and hoops to jump
through.

Note that framebuffer creation/destruction is now double-protected -
once by the fb_lock and in parts by the idr_lock. The later would be
unnecessariy if framebuffers would have their own idr allocator. But
that's material for another patch (series).

v2: Properly initialize the fb->filp_head list in _init, otherwise the
newly added WARN to check whether the fb isn't on a fpriv list any
more will fail for driver-private objects.

v3: Fixup two error-case unlock bugs spotted by Richard Wilbur.

Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 drivers/gpu/drm/drm_crtc.c             |  116 ++++++++++++++++++++++----------
 drivers/gpu/drm/drm_fops.c             |    1 +
 drivers/gpu/drm/i915/i915_debugfs.c    |    5 +-
 drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c  |    4 ++
 drivers/staging/omapdrm/omap_debugfs.c |    2 +
 include/drm/drmP.h                     |    8 +++
 include/drm/drm_crtc.h                 |   14 ++++
 7 files changed, 113 insertions(+), 37 deletions(-)

diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index 457e4faf..d387ddb 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -262,15 +262,21 @@ again:
 
 	mutex_lock(&dev->mode_config.idr_mutex);
 	ret = idr_get_new_above(&dev->mode_config.crtc_idr, obj, 1, &new_id);
+
+	if (!ret) {
+		/*
+		 * Set up the object linking under the protection of the idr
+		 * lock so that other users can't see inconsistent state.
+		 */
+		obj->id = new_id;
+		obj->type = obj_type;
+	}
 	mutex_unlock(&dev->mode_config.idr_mutex);
+
 	if (ret == -EAGAIN)
 		goto again;
-	else if (ret)
-		return ret;
 
-	obj->id = new_id;
-	obj->type = obj_type;
-	return 0;
+	return ret;
 }
 
 /**
@@ -312,6 +318,12 @@ EXPORT_SYMBOL(drm_mode_object_find);
  * Allocates an ID for the framebuffer's parent mode object, sets its mode
  * functions & device file and adds it to the master fd list.
  *
+ * IMPORTANT:
+ * This functions publishes the fb and makes it available for concurrent access
+ * by other users. Which means by this point the fb _must_ be fully set up -
+ * since all the fb attributes are invariant over its lifetime, no further
+ * locking but only correct reference counting is required.
+ *
  * RETURNS:
  * Zero on success, error code on failure.
  */
@@ -320,16 +332,20 @@ int drm_framebuffer_init(struct drm_device *dev, struct drm_framebuffer *fb,
 {
 	int ret;
 
+	mutex_lock(&dev->mode_config.fb_lock);
 	kref_init(&fb->refcount);
+	INIT_LIST_HEAD(&fb->filp_head);
+	fb->dev = dev;
+	fb->funcs = funcs;
 
 	ret = drm_mode_object_get(dev, &fb->base, DRM_MODE_OBJECT_FB);
 	if (ret)
-		return ret;
+		goto out;
 
-	fb->dev = dev;
-	fb->funcs = funcs;
 	dev->mode_config.num_fb++;
 	list_add(&fb->head, &dev->mode_config.fb_list);
+out:
+	mutex_unlock(&dev->mode_config.fb_lock);
 
 	return 0;
 }
@@ -385,8 +401,10 @@ void drm_framebuffer_cleanup(struct drm_framebuffer *fb)
 	 * this.)
 	 */
 	drm_mode_object_put(dev, &fb->base);
+	mutex_lock(&dev->mode_config.fb_lock);
 	list_del(&fb->head);
 	dev->mode_config.num_fb--;
+	mutex_unlock(&dev->mode_config.fb_lock);
 }
 EXPORT_SYMBOL(drm_framebuffer_cleanup);
 
@@ -406,6 +424,7 @@ void drm_framebuffer_remove(struct drm_framebuffer *fb)
 	int ret;
 
 	WARN_ON(!drm_modeset_is_locked(dev));
+	WARN_ON(!list_empty(&fb->filp_head));
 
 	/* remove from any CRTC */
 	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
@@ -432,8 +451,6 @@ void drm_framebuffer_remove(struct drm_framebuffer *fb)
 		}
 	}
 
-	list_del(&fb->filp_head);
-
 	drm_framebuffer_unreference(fb);
 }
 EXPORT_SYMBOL(drm_framebuffer_remove);
@@ -989,6 +1006,7 @@ void drm_mode_config_init(struct drm_device *dev)
 {
 	mutex_init(&dev->mode_config.mutex);
 	mutex_init(&dev->mode_config.idr_mutex);
+	mutex_init(&dev->mode_config.fb_lock);
 	INIT_LIST_HEAD(&dev->mode_config.fb_list);
 	INIT_LIST_HEAD(&dev->mode_config.crtc_list);
 	INIT_LIST_HEAD(&dev->mode_config.connector_list);
@@ -1091,6 +1109,9 @@ void drm_mode_config_cleanup(struct drm_device *dev)
 		drm_property_destroy(dev, property);
 	}
 
+	/* Single-threaded teardown context, so it's not requied to grab the
+	 * fb_lock to protect against concurrent fb_list access. Contrary, it
+	 * would actually deadlock with the drm_framebuffer_cleanup function. */
 	list_for_each_entry_safe(fb, fbt, &dev->mode_config.fb_list, head) {
 		drm_framebuffer_remove(fb);
 	}
@@ -1220,8 +1241,8 @@ int drm_mode_getresources(struct drm_device *dev, void *data,
 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
 		return -EINVAL;
 
-	drm_modeset_lock_all(dev);
 
+	mutex_lock(&file_priv->fbs_lock);
 	/*
 	 * For the non-control nodes we need to limit the list of resources
 	 * by IDs in the group list for this node
@@ -1229,6 +1250,23 @@ int drm_mode_getresources(struct drm_device *dev, void *data,
 	list_for_each(lh, &file_priv->fbs)
 		fb_count++;
 
+	/* handle this in 4 parts */
+	/* FBs */
+	if (card_res->count_fbs >= fb_count) {
+		copied = 0;
+		fb_id = (uint32_t __user *)(unsigned long)card_res->fb_id_ptr;
+		list_for_each_entry(fb, &file_priv->fbs, filp_head) {
+			if (put_user(fb->base.id, fb_id + copied)) {
+				mutex_unlock(&file_priv->fbs_lock);
+				return -EFAULT;
+			}
+			copied++;
+		}
+	}
+	card_res->count_fbs = fb_count;
+	mutex_unlock(&file_priv->fbs_lock);
+
+	drm_modeset_lock_all(dev);
 	mode_group = &file_priv->master->minor->mode_group;
 	if (file_priv->master->minor->type == DRM_MINOR_CONTROL) {
 
@@ -1252,21 +1290,6 @@ int drm_mode_getresources(struct drm_device *dev, void *data,
 	card_res->max_width = dev->mode_config.max_width;
 	card_res->min_width = dev->mode_config.min_width;
 
-	/* handle this in 4 parts */
-	/* FBs */
-	if (card_res->count_fbs >= fb_count) {
-		copied = 0;
-		fb_id = (uint32_t __user *)(unsigned long)card_res->fb_id_ptr;
-		list_for_each_entry(fb, &file_priv->fbs, filp_head) {
-			if (put_user(fb->base.id, fb_id + copied)) {
-				ret = -EFAULT;
-				goto out;
-			}
-			copied++;
-		}
-	}
-	card_res->count_fbs = fb_count;
-
 	/* CRTCs */
 	if (card_res->count_crtcs >= crtc_count) {
 		copied = 0;
@@ -1765,8 +1788,10 @@ int drm_mode_setplane(struct drm_device *dev, void *data,
 	}
 	crtc = obj_to_crtc(obj);
 
+	mutex_lock(&dev->mode_config.fb_lock);
 	obj = drm_mode_object_find(dev, plane_req->fb_id,
 				   DRM_MODE_OBJECT_FB);
+	mutex_unlock(&dev->mode_config.fb_lock);
 	if (!obj) {
 		DRM_DEBUG_KMS("Unknown framebuffer ID %d\n",
 			      plane_req->fb_id);
@@ -1908,8 +1933,10 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data,
 			}
 			fb = crtc->fb;
 		} else {
+			mutex_lock(&dev->mode_config.fb_lock);
 			obj = drm_mode_object_find(dev, crtc_req->fb_id,
 						   DRM_MODE_OBJECT_FB);
+			mutex_unlock(&dev->mode_config.fb_lock);
 			if (!obj) {
 				DRM_DEBUG_KMS("Unknown FB ID%d\n",
 						crtc_req->fb_id);
@@ -2151,16 +2178,17 @@ int drm_mode_addfb(struct drm_device *dev,
 	fb = dev->mode_config.funcs->fb_create(dev, file_priv, &r);
 	if (IS_ERR(fb)) {
 		DRM_DEBUG_KMS("could not create framebuffer\n");
-		ret = PTR_ERR(fb);
-		goto out;
+		drm_modeset_unlock_all(dev);
+		return PTR_ERR(fb);
 	}
 
+	mutex_lock(&file_priv->fbs_lock);
 	or->fb_id = fb->base.id;
 	list_add(&fb->filp_head, &file_priv->fbs);
 	DRM_DEBUG_KMS("[FB:%d]\n", fb->base.id);
-
-out:
+	mutex_unlock(&file_priv->fbs_lock);
 	drm_modeset_unlock_all(dev);
+
 	return ret;
 }
 
@@ -2333,16 +2361,18 @@ int drm_mode_addfb2(struct drm_device *dev,
 	fb = dev->mode_config.funcs->fb_create(dev, file_priv, r);
 	if (IS_ERR(fb)) {
 		DRM_DEBUG_KMS("could not create framebuffer\n");
-		ret = PTR_ERR(fb);
-		goto out;
+		drm_modeset_unlock_all(dev);
+		return PTR_ERR(fb);
 	}
 
+	mutex_lock(&file_priv->fbs_lock);
 	r->fb_id = fb->base.id;
 	list_add(&fb->filp_head, &file_priv->fbs);
 	DRM_DEBUG_KMS("[FB:%d]\n", fb->base.id);
+	mutex_unlock(&file_priv->fbs_lock);
 
-out:
 	drm_modeset_unlock_all(dev);
+
 	return ret;
 }
 
@@ -2373,27 +2403,34 @@ int drm_mode_rmfb(struct drm_device *dev,
 		return -EINVAL;
 
 	drm_modeset_lock_all(dev);
+	mutex_lock(&dev->mode_config.fb_lock);
 	obj = drm_mode_object_find(dev, *id, DRM_MODE_OBJECT_FB);
 	/* TODO check that we really get a framebuffer back. */
 	if (!obj) {
+		mutex_unlock(&dev->mode_config.fb_lock);
 		ret = -EINVAL;
 		goto out;
 	}
 	fb = obj_to_fb(obj);
+	mutex_unlock(&dev->mode_config.fb_lock);
 
+	mutex_lock(&file_priv->fbs_lock);
 	list_for_each_entry(fbl, &file_priv->fbs, filp_head)
 		if (fb == fbl)
 			found = 1;
-
 	if (!found) {
 		ret = -EINVAL;
+		mutex_unlock(&file_priv->fbs_lock);
 		goto out;
 	}
 
-	drm_framebuffer_remove(fb);
+	list_del_init(&fb->filp_head);
+	mutex_unlock(&file_priv->fbs_lock);
 
+	drm_framebuffer_remove(fb);
 out:
 	drm_modeset_unlock_all(dev);
+
 	return ret;
 }
 
@@ -2422,7 +2459,9 @@ int drm_mode_getfb(struct drm_device *dev,
 		return -EINVAL;
 
 	drm_modeset_lock_all(dev);
+	mutex_lock(&dev->mode_config.fb_lock);
 	obj = drm_mode_object_find(dev, r->fb_id, DRM_MODE_OBJECT_FB);
+	mutex_unlock(&dev->mode_config.fb_lock);
 	if (!obj) {
 		ret = -EINVAL;
 		goto out;
@@ -2460,7 +2499,9 @@ int drm_mode_dirtyfb_ioctl(struct drm_device *dev,
 		return -EINVAL;
 
 	drm_modeset_lock_all(dev);
+	mutex_lock(&dev->mode_config.fb_lock);
 	obj = drm_mode_object_find(dev, r->fb_id, DRM_MODE_OBJECT_FB);
+	mutex_unlock(&dev->mode_config.fb_lock);
 	if (!obj) {
 		ret = -EINVAL;
 		goto out_err1;
@@ -2535,9 +2576,12 @@ void drm_fb_release(struct drm_file *priv)
 	struct drm_framebuffer *fb, *tfb;
 
 	drm_modeset_lock_all(dev);
+	mutex_lock(&priv->fbs_lock);
 	list_for_each_entry_safe(fb, tfb, &priv->fbs, filp_head) {
+		list_del_init(&fb->filp_head);
 		drm_framebuffer_remove(fb);
 	}
+	mutex_unlock(&priv->fbs_lock);
 	drm_modeset_unlock_all(dev);
 }
 
@@ -3542,7 +3586,9 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev,
 	if (crtc->funcs->page_flip == NULL)
 		goto out;
 
+	mutex_lock(&dev->mode_config.fb_lock);
 	obj = drm_mode_object_find(dev, page_flip->fb_id, DRM_MODE_OBJECT_FB);
+	mutex_unlock(&dev->mode_config.fb_lock);
 	if (!obj)
 		goto out;
 	fb = obj_to_fb(obj);
diff --git a/drivers/gpu/drm/drm_fops.c b/drivers/gpu/drm/drm_fops.c
index 133b413..13fdcd1 100644
--- a/drivers/gpu/drm/drm_fops.c
+++ b/drivers/gpu/drm/drm_fops.c
@@ -276,6 +276,7 @@ static int drm_open_helper(struct inode *inode, struct file *filp,
 
 	INIT_LIST_HEAD(&priv->lhead);
 	INIT_LIST_HEAD(&priv->fbs);
+	mutex_init(&priv->fbs_lock);
 	INIT_LIST_HEAD(&priv->event_list);
 	init_waitqueue_head(&priv->event_wait);
 	priv->event_space = 4096; /* set aside 4k for event buffer */
diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
index f7d88e9..1269a46 100644
--- a/drivers/gpu/drm/i915/i915_debugfs.c
+++ b/drivers/gpu/drm/i915/i915_debugfs.c
@@ -1447,7 +1447,9 @@ static int i915_gem_framebuffer_info(struct seq_file *m, void *data)
 		   fb->base.bits_per_pixel);
 	describe_obj(m, fb->obj);
 	seq_printf(m, "\n");
+	mutex_unlock(&dev->mode_config.mutex);
 
+	mutex_lock(&dev->mode_config.fb_lock);
 	list_for_each_entry(fb, &dev->mode_config.fb_list, base.head) {
 		if (&fb->base == ifbdev->helper.fb)
 			continue;
@@ -1460,8 +1462,7 @@ static int i915_gem_framebuffer_info(struct seq_file *m, void *data)
 		describe_obj(m, fb->obj);
 		seq_printf(m, "\n");
 	}
-
-	mutex_unlock(&dev->mode_config.mutex);
+	mutex_unlock(&dev->mode_config.fb_lock);
 
 	return 0;
 }
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c
index a135498..0d6a161 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c
@@ -165,7 +165,9 @@ int vmw_present_ioctl(struct drm_device *dev, void *data,
 
 	drm_modeset_lock_all(dev);
 
+	mutex_lock(&dev->mode_config.fb_lock);
 	obj = drm_mode_object_find(dev, arg->fb_id, DRM_MODE_OBJECT_FB);
+	mutex_unlock(&dev->mode_config.fb_lock);
 	if (!obj) {
 		DRM_ERROR("Invalid framebuffer id.\n");
 		ret = -EINVAL;
@@ -248,7 +250,9 @@ int vmw_present_readback_ioctl(struct drm_device *dev, void *data,
 
 	drm_modeset_lock_all(dev);
 
+	mutex_lock(&dev->mode_config.fb_lock);
 	obj = drm_mode_object_find(dev, arg->fb_id, DRM_MODE_OBJECT_FB);
+	mutex_unlock(&dev->mode_config.fb_lock);
 	if (!obj) {
 		DRM_ERROR("Invalid framebuffer id.\n");
 		ret = -EINVAL;
diff --git a/drivers/staging/omapdrm/omap_debugfs.c b/drivers/staging/omapdrm/omap_debugfs.c
index 2f122e0..e95540b 100644
--- a/drivers/staging/omapdrm/omap_debugfs.c
+++ b/drivers/staging/omapdrm/omap_debugfs.c
@@ -72,6 +72,7 @@ static int fb_show(struct seq_file *m, void *arg)
 	seq_printf(m, "fbcon ");
 	omap_framebuffer_describe(priv->fbdev->fb, m);
 
+	mutex_lock(&dev->mode_config.fb_lock);
 	list_for_each_entry(fb, &dev->mode_config.fb_list, head) {
 		if (fb == priv->fbdev->fb)
 			continue;
@@ -79,6 +80,7 @@ static int fb_show(struct seq_file *m, void *arg)
 		seq_printf(m, "user ");
 		omap_framebuffer_describe(fb, m);
 	}
+	mutex_unlock(&dev->mode_config.fb_lock);
 
 	mutex_unlock(&dev->struct_mutex);
 	mutex_unlock(&dev->mode_config.mutex);
diff --git a/include/drm/drmP.h b/include/drm/drmP.h
index 3c609ab..e74731c 100644
--- a/include/drm/drmP.h
+++ b/include/drm/drmP.h
@@ -446,7 +446,15 @@ struct drm_file {
 	int is_master; /* this file private is a master for a minor */
 	struct drm_master *master; /* master this node is currently associated with
 				      N.B. not always minor->master */
+
+	/**
+	 * fbs - List of framebuffers associated with this file.
+	 *
+	 * Protected by fbs_lock. Note that the fbs list holds a reference on
+	 * the fb object to prevent it from untimely disappearing.
+	 */
 	struct list_head fbs;
+	struct mutex fbs_lock;
 
 	wait_queue_head_t event_wait;
 	struct list_head event_list;
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index c89b116..c35a807 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -254,6 +254,10 @@ struct drm_framebuffer {
 	 * userspace perspective.
 	 */
 	struct kref refcount;
+	/*
+	 * Place on the dev->mode_config.fb_list, access protected by
+	 * dev->mode_config.fb_lock.
+	 */
 	struct list_head head;
 	struct drm_mode_object base;
 	const struct drm_framebuffer_funcs *funcs;
@@ -780,8 +784,18 @@ struct drm_mode_config {
 	struct mutex idr_mutex; /* for IDR management */
 	struct idr crtc_idr; /* use this idr for all IDs, fb, crtc, connector, modes - just makes life easier */
 	/* this is limited to one for now */
+
+
+	/**
+	 * fb_lock - mutex to protect fb state
+	 *
+	 * Besides the global fb list his also protects the fbs list in the
+	 * file_priv
+	 */
+	struct mutex fb_lock;
 	int num_fb;
 	struct list_head fb_list;
+
 	int num_connector;
 	struct list_head connector_list;
 	int num_encoder;
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PATCH 20/35] drm: create drm_framebuffer_lookup
  2013-01-10 20:47 [PATCH 00/36] kms locking rework Daniel Vetter
                   ` (18 preceding siblings ...)
  2013-01-10 20:48 ` [PATCH 19/35] drm: revamp locking around fb creation/destruction Daniel Vetter
@ 2013-01-10 20:48 ` Daniel Vetter
  2013-01-10 20:48 ` [PATCH 21/35] drm: revamp framebuffer cleanup interfaces Daniel Vetter
                   ` (16 subsequent siblings)
  36 siblings, 0 replies; 45+ messages in thread
From: Daniel Vetter @ 2013-01-10 20:48 UTC (permalink / raw)
  To: DRI Development; +Cc: Daniel Vetter

And replace all fb lookups with it. Also add a WARN to
drm_mode_object_find since that is now no longer the blessed interface
to look up an fb. And add kerneldoc to both functions.

This only updates all callsites, but immediately drops the acquired
refence again. Hence all callers still rely on the fact that a mode fb
can't disappear while they're holding the struct mutex. Subsequent
patches will instate proper use of refcounts, and then rework the rmfb
and unref code to no longer serialize fb destruction with the
mode_config lock. We don't want that since otherwise a compositor
might end up stalling for a few frames in rmfb.

v2: Don't use kref_get_unless_zero - Greg KH doesn't like that kind of
interface.

Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 drivers/gpu/drm/drm_crtc.c            |  109 ++++++++++++++++++++++-----------
 drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c |   24 ++++----
 include/drm/drm_crtc.h                |    2 +
 3 files changed, 86 insertions(+), 49 deletions(-)

diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index d387ddb..1c13984 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -294,11 +294,24 @@ static void drm_mode_object_put(struct drm_device *dev,
 	mutex_unlock(&dev->mode_config.idr_mutex);
 }
 
+/**
+ * drm_mode_object_find - look up a drm object with static lifetime
+ * @dev: drm device
+ * @id: id of the mode object
+ * @type: type of the mode object
+ *
+ * Note that framebuffers cannot be looked up with this functions - since those
+ * are reference counted, they need special treatment.
+ */
 struct drm_mode_object *drm_mode_object_find(struct drm_device *dev,
 		uint32_t id, uint32_t type)
 {
 	struct drm_mode_object *obj = NULL;
 
+	/* Framebuffers are reference counted and need their own lookup
+	 * function.*/
+	WARN_ON(type == DRM_MODE_OBJECT_FB);
+
 	mutex_lock(&dev->mode_config.idr_mutex);
 	obj = idr_find(&dev->mode_config.crtc_idr, id);
 	if (!obj || (obj->type != type) || (obj->id != id))
@@ -359,6 +372,40 @@ static void drm_framebuffer_free(struct kref *kref)
 }
 
 /**
+ * drm_framebuffer_lookup - look up a drm framebuffer and grab a reference
+ * @dev: drm device
+ * @id: id of the fb object
+ *
+ * If successful, this grabs an additional reference to the framebuffer -
+ * callers need to make sure to eventually unreference the returned framebuffer
+ * again.
+ */
+struct drm_framebuffer *drm_framebuffer_lookup(struct drm_device *dev,
+					       uint32_t id)
+{
+	struct drm_mode_object *obj = NULL;
+	struct drm_framebuffer *fb;
+
+	mutex_lock(&dev->mode_config.fb_lock);
+
+	mutex_lock(&dev->mode_config.idr_mutex);
+	obj = idr_find(&dev->mode_config.crtc_idr, id);
+	if (!obj || (obj->type != DRM_MODE_OBJECT_FB) || (obj->id != id))
+		fb = NULL;
+	else
+		fb = obj_to_fb(obj);
+	mutex_unlock(&dev->mode_config.idr_mutex);
+
+	if (fb)
+		kref_get(&fb->refcount);
+
+	mutex_unlock(&dev->mode_config.fb_lock);
+
+	return fb;
+}
+EXPORT_SYMBOL(drm_framebuffer_lookup);
+
+/**
  * drm_framebuffer_unreference - unref a framebuffer
  * @fb: framebuffer to unref
  *
@@ -1788,17 +1835,15 @@ int drm_mode_setplane(struct drm_device *dev, void *data,
 	}
 	crtc = obj_to_crtc(obj);
 
-	mutex_lock(&dev->mode_config.fb_lock);
-	obj = drm_mode_object_find(dev, plane_req->fb_id,
-				   DRM_MODE_OBJECT_FB);
-	mutex_unlock(&dev->mode_config.fb_lock);
-	if (!obj) {
+	fb = drm_framebuffer_lookup(dev, plane_req->fb_id);
+	if (!fb) {
 		DRM_DEBUG_KMS("Unknown framebuffer ID %d\n",
 			      plane_req->fb_id);
 		ret = -ENOENT;
 		goto out;
 	}
-	fb = obj_to_fb(obj);
+	/* fb is protect by the mode_config lock, so drop the ref immediately */
+	drm_framebuffer_unreference(fb);
 
 	/* Check whether this plane supports the fb pixel format. */
 	for (i = 0; i < plane->format_count; i++)
@@ -1933,17 +1978,16 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data,
 			}
 			fb = crtc->fb;
 		} else {
-			mutex_lock(&dev->mode_config.fb_lock);
-			obj = drm_mode_object_find(dev, crtc_req->fb_id,
-						   DRM_MODE_OBJECT_FB);
-			mutex_unlock(&dev->mode_config.fb_lock);
-			if (!obj) {
+			fb = drm_framebuffer_lookup(dev, crtc_req->fb_id);
+			if (!fb) {
 				DRM_DEBUG_KMS("Unknown FB ID%d\n",
 						crtc_req->fb_id);
 				ret = -EINVAL;
 				goto out;
 			}
-			fb = obj_to_fb(obj);
+			/* fb is protect by the mode_config lock, so drop the
+			 * ref immediately */
+			drm_framebuffer_unreference(fb);
 		}
 
 		mode = drm_mode_create(dev);
@@ -2392,7 +2436,6 @@ int drm_mode_addfb2(struct drm_device *dev,
 int drm_mode_rmfb(struct drm_device *dev,
 		   void *data, struct drm_file *file_priv)
 {
-	struct drm_mode_object *obj;
 	struct drm_framebuffer *fb = NULL;
 	struct drm_framebuffer *fbl = NULL;
 	uint32_t *id = data;
@@ -2403,16 +2446,13 @@ int drm_mode_rmfb(struct drm_device *dev,
 		return -EINVAL;
 
 	drm_modeset_lock_all(dev);
-	mutex_lock(&dev->mode_config.fb_lock);
-	obj = drm_mode_object_find(dev, *id, DRM_MODE_OBJECT_FB);
-	/* TODO check that we really get a framebuffer back. */
-	if (!obj) {
-		mutex_unlock(&dev->mode_config.fb_lock);
+	fb = drm_framebuffer_lookup(dev, *id);
+	if (!fb) {
 		ret = -EINVAL;
 		goto out;
 	}
-	fb = obj_to_fb(obj);
-	mutex_unlock(&dev->mode_config.fb_lock);
+	/* fb is protect by the mode_config lock, so drop the ref immediately */
+	drm_framebuffer_unreference(fb);
 
 	mutex_lock(&file_priv->fbs_lock);
 	list_for_each_entry(fbl, &file_priv->fbs, filp_head)
@@ -2451,7 +2491,6 @@ int drm_mode_getfb(struct drm_device *dev,
 		   void *data, struct drm_file *file_priv)
 {
 	struct drm_mode_fb_cmd *r = data;
-	struct drm_mode_object *obj;
 	struct drm_framebuffer *fb;
 	int ret = 0;
 
@@ -2459,14 +2498,13 @@ int drm_mode_getfb(struct drm_device *dev,
 		return -EINVAL;
 
 	drm_modeset_lock_all(dev);
-	mutex_lock(&dev->mode_config.fb_lock);
-	obj = drm_mode_object_find(dev, r->fb_id, DRM_MODE_OBJECT_FB);
-	mutex_unlock(&dev->mode_config.fb_lock);
-	if (!obj) {
+	fb = drm_framebuffer_lookup(dev, r->fb_id);
+	if (!fb) {
 		ret = -EINVAL;
 		goto out;
 	}
-	fb = obj_to_fb(obj);
+	/* fb is protect by the mode_config lock, so drop the ref immediately */
+	drm_framebuffer_unreference(fb);
 
 	r->height = fb->height;
 	r->width = fb->width;
@@ -2489,7 +2527,6 @@ int drm_mode_dirtyfb_ioctl(struct drm_device *dev,
 	struct drm_clip_rect __user *clips_ptr;
 	struct drm_clip_rect *clips = NULL;
 	struct drm_mode_fb_dirty_cmd *r = data;
-	struct drm_mode_object *obj;
 	struct drm_framebuffer *fb;
 	unsigned flags;
 	int num_clips;
@@ -2499,14 +2536,13 @@ int drm_mode_dirtyfb_ioctl(struct drm_device *dev,
 		return -EINVAL;
 
 	drm_modeset_lock_all(dev);
-	mutex_lock(&dev->mode_config.fb_lock);
-	obj = drm_mode_object_find(dev, r->fb_id, DRM_MODE_OBJECT_FB);
-	mutex_unlock(&dev->mode_config.fb_lock);
-	if (!obj) {
+	fb = drm_framebuffer_lookup(dev, r->fb_id);
+	if (!fb) {
 		ret = -EINVAL;
 		goto out_err1;
 	}
-	fb = obj_to_fb(obj);
+	/* fb is protect by the mode_config lock, so drop the ref immediately */
+	drm_framebuffer_unreference(fb);
 
 	num_clips = r->num_clips;
 	clips_ptr = (struct drm_clip_rect __user *)(unsigned long)r->clips_ptr;
@@ -3586,12 +3622,11 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev,
 	if (crtc->funcs->page_flip == NULL)
 		goto out;
 
-	mutex_lock(&dev->mode_config.fb_lock);
-	obj = drm_mode_object_find(dev, page_flip->fb_id, DRM_MODE_OBJECT_FB);
-	mutex_unlock(&dev->mode_config.fb_lock);
-	if (!obj)
+	fb = drm_framebuffer_lookup(dev, page_flip->fb_id);
+	if (!fb)
 		goto out;
-	fb = obj_to_fb(obj);
+	/* fb is protect by the mode_config lock, so drop the ref immediately */
+	drm_framebuffer_unreference(fb);
 
 	hdisplay = crtc->mode.hdisplay;
 	vdisplay = crtc->mode.vdisplay;
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c
index 0d6a161..1b8f428 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c
@@ -131,7 +131,7 @@ int vmw_present_ioctl(struct drm_device *dev, void *data,
 	struct vmw_master *vmaster = vmw_master(file_priv->master);
 	struct drm_vmw_rect __user *clips_ptr;
 	struct drm_vmw_rect *clips = NULL;
-	struct drm_mode_object *obj;
+	struct drm_framebuffer *fb;
 	struct vmw_framebuffer *vfb;
 	struct vmw_resource *res;
 	uint32_t num_clips;
@@ -165,15 +165,15 @@ int vmw_present_ioctl(struct drm_device *dev, void *data,
 
 	drm_modeset_lock_all(dev);
 
-	mutex_lock(&dev->mode_config.fb_lock);
-	obj = drm_mode_object_find(dev, arg->fb_id, DRM_MODE_OBJECT_FB);
-	mutex_unlock(&dev->mode_config.fb_lock);
-	if (!obj) {
+	fb = drm_framebuffer_lookup(dev, arg->fb_id);
+	if (!fb) {
 		DRM_ERROR("Invalid framebuffer id.\n");
 		ret = -EINVAL;
 		goto out_no_fb;
 	}
-	vfb = vmw_framebuffer_to_vfb(obj_to_fb(obj));
+	/* fb is protect by the mode_config lock, so drop the ref immediately */
+	drm_framebuffer_unreference(fb);
+	vfb = vmw_framebuffer_to_vfb(fb);
 
 	ret = ttm_read_lock(&vmaster->lock, true);
 	if (unlikely(ret != 0))
@@ -217,7 +217,7 @@ int vmw_present_readback_ioctl(struct drm_device *dev, void *data,
 	struct vmw_master *vmaster = vmw_master(file_priv->master);
 	struct drm_vmw_rect __user *clips_ptr;
 	struct drm_vmw_rect *clips = NULL;
-	struct drm_mode_object *obj;
+	struct drm_framebuffer *fb;
 	struct vmw_framebuffer *vfb;
 	uint32_t num_clips;
 	int ret;
@@ -250,16 +250,16 @@ int vmw_present_readback_ioctl(struct drm_device *dev, void *data,
 
 	drm_modeset_lock_all(dev);
 
-	mutex_lock(&dev->mode_config.fb_lock);
-	obj = drm_mode_object_find(dev, arg->fb_id, DRM_MODE_OBJECT_FB);
-	mutex_unlock(&dev->mode_config.fb_lock);
-	if (!obj) {
+	fb = drm_framebuffer_lookup(dev, arg->fb_id);
+	if (!fb) {
 		DRM_ERROR("Invalid framebuffer id.\n");
 		ret = -EINVAL;
 		goto out_no_fb;
 	}
+	/* fb is protect by the mode_config lock, so drop the ref immediately */
+	drm_framebuffer_unreference(fb);
 
-	vfb = vmw_framebuffer_to_vfb(obj_to_fb(obj));
+	vfb = vmw_framebuffer_to_vfb(fb);
 	if (!vfb->dmabuf) {
 		DRM_ERROR("Framebuffer not dmabuf backed.\n");
 		ret = -EINVAL;
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index c35a807..7dc1b31 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -958,6 +958,8 @@ extern void drm_framebuffer_set_object(struct drm_device *dev,
 extern int drm_framebuffer_init(struct drm_device *dev,
 				struct drm_framebuffer *fb,
 				const struct drm_framebuffer_funcs *funcs);
+extern struct drm_framebuffer *drm_framebuffer_lookup(struct drm_device *dev,
+						      uint32_t id);
 extern void drm_framebuffer_unreference(struct drm_framebuffer *fb);
 extern void drm_framebuffer_reference(struct drm_framebuffer *fb);
 extern void drm_framebuffer_remove(struct drm_framebuffer *fb);
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PATCH 21/35] drm: revamp framebuffer cleanup interfaces
  2013-01-10 20:47 [PATCH 00/36] kms locking rework Daniel Vetter
                   ` (19 preceding siblings ...)
  2013-01-10 20:48 ` [PATCH 20/35] drm: create drm_framebuffer_lookup Daniel Vetter
@ 2013-01-10 20:48 ` Daniel Vetter
  2013-01-10 20:48 ` [PATCH 22/35] drm: reference framebuffers which are on the idr Daniel Vetter
                   ` (15 subsequent siblings)
  36 siblings, 0 replies; 45+ messages in thread
From: Daniel Vetter @ 2013-01-10 20:48 UTC (permalink / raw)
  To: DRI Development; +Cc: Daniel Vetter

We have two classes of framebuffer
- Created by the driver (atm only for fbdev), and the driver holds
  onto the last reference count until destruction.
- Created by userspace and associated with a given fd. These
  framebuffers will be reaped when their assoiciated fb is closed.

Now these two cases are set up differently, the framebuffers are on
different lists and hence destruction needs to clean up different
things. Also, for userspace framebuffers we remove them from any
current usage, whereas for internal framebuffers it is assumed that
the driver has done this already.

Long story short, we need two different ways to cleanup such drivers.
Three functions are involved in total:
- drm_framebuffer_remove: Convenience function which removes the fb
  from all active usage and then drops the passed-in reference.
- drm_framebuffer_unregister_private: Will remove driver-private
  framebuffers from relevant lists and drop the corresponding
  references. Should be called for driver-private framebuffers before
  dropping the last reference (or like for a lot of the drivers where
  the fbdev is embedded someplace else, before doing the cleanup
  manually).
- drm_framebuffer_cleanup: Final cleanup for both classes of fbs,
  should be called by the driver's ->destroy callback once the last
  reference is gone.

This patch just rolls out the new interfaces and updates all drivers
(by adding calls to drm_framebuffer_unregister_private at all the
right places)- no functional changes yet. Follow-on patches will move
drm core code around and update the lifetime management for
framebuffers, so that we are no longer required to keep framebuffers
alive by locking mode_config.mutex.

I've also updated the kerneldoc already.

vmwgfx seems to again be a bit special, at least I haven't figured out
how the fbdev support in that driver works. It smells like it's
external though.

v2: The i915 driver creates another private framebuffer in the
load-detect code. Adjust its cleanup code, too.

Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 drivers/gpu/drm/ast/ast_fb.c              |    1 +
 drivers/gpu/drm/cirrus/cirrus_fbdev.c     |    1 +
 drivers/gpu/drm/drm_crtc.c                |   31 ++++++++++++++++++++++++++---
 drivers/gpu/drm/drm_fb_cma_helper.c       |    5 ++++-
 drivers/gpu/drm/exynos/exynos_drm_fbdev.c |    4 +++-
 drivers/gpu/drm/gma500/framebuffer.c      |    1 +
 drivers/gpu/drm/i915/intel_display.c      |    6 ++++--
 drivers/gpu/drm/i915/intel_fb.c           |    1 +
 drivers/gpu/drm/mgag200/mgag200_fb.c      |    1 +
 drivers/gpu/drm/nouveau/nouveau_fbcon.c   |    1 +
 drivers/gpu/drm/radeon/radeon_fb.c        |    2 ++
 drivers/gpu/drm/udl/udl_fb.c              |    1 +
 drivers/staging/omapdrm/omap_fbdev.c      |    8 ++++++--
 include/drm/drm_crtc.h                    |    1 +
 14 files changed, 55 insertions(+), 9 deletions(-)

diff --git a/drivers/gpu/drm/ast/ast_fb.c b/drivers/gpu/drm/ast/ast_fb.c
index d9ec779..3e6584b 100644
--- a/drivers/gpu/drm/ast/ast_fb.c
+++ b/drivers/gpu/drm/ast/ast_fb.c
@@ -290,6 +290,7 @@ static void ast_fbdev_destroy(struct drm_device *dev,
 	drm_fb_helper_fini(&afbdev->helper);
 
 	vfree(afbdev->sysram);
+	drm_framebuffer_unregister_private(&afb->base);
 	drm_framebuffer_cleanup(&afb->base);
 }
 
diff --git a/drivers/gpu/drm/cirrus/cirrus_fbdev.c b/drivers/gpu/drm/cirrus/cirrus_fbdev.c
index 6c6b4c8..3daea0f 100644
--- a/drivers/gpu/drm/cirrus/cirrus_fbdev.c
+++ b/drivers/gpu/drm/cirrus/cirrus_fbdev.c
@@ -258,6 +258,7 @@ static int cirrus_fbdev_destroy(struct drm_device *dev,
 
 	vfree(gfbdev->sysram);
 	drm_fb_helper_fini(&gfbdev->helper);
+	drm_framebuffer_unregister_private(&gfb->base);
 	drm_framebuffer_cleanup(&gfb->base);
 
 	return 0;
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index 1c13984..4e7c362 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -68,6 +68,7 @@ void drm_modeset_unlock_all(struct drm_device *dev)
 
 	mutex_unlock(&dev->mode_config.mutex);
 }
+
 EXPORT_SYMBOL(drm_modeset_unlock_all);
 
 /* Avoid boilerplate.  I'm tired of typing. */
@@ -430,11 +431,34 @@ void drm_framebuffer_reference(struct drm_framebuffer *fb)
 EXPORT_SYMBOL(drm_framebuffer_reference);
 
 /**
+ * drm_framebuffer_unregister_private - unregister a private fb from the lookup idr
+ * @fb: fb to unregister
+ *
+ * Drivers need to call this when cleaning up driver-private framebuffers, e.g.
+ * those used for fbdev. Note that the caller must hold a reference of it's own,
+ * i.e. the object may not be destroyed through this call (since it'll lead to a
+ * locking inversion).
+ */
+void drm_framebuffer_unregister_private(struct drm_framebuffer *fb)
+{
+}
+EXPORT_SYMBOL(drm_framebuffer_unregister_private);
+
+/**
  * drm_framebuffer_cleanup - remove a framebuffer object
  * @fb: framebuffer to remove
  *
- * Scans all the CRTCs in @dev's mode_config.  If they're using @fb, removes
- * it, setting it to NULL.
+ * Cleanup references to a user-created framebuffer. This function is intended
+ * to be used from the drivers ->destroy callback.
+ *
+ * Note that this function does not remove the fb from active usuage - if it is
+ * still used anywhere, hilarity can ensue since userspace could call getfb on
+ * the id and get back -EINVAL. Obviously no concern at driver unload time.
+ *
+ * Also, the framebuffer will not be removed from the lookup idr - for
+ * user-created framebuffers this will happen in in the rmfb ioctl. For
+ * driver-private objects (e.g. for fbdev) drivers need to explicitly call
+ * drm_framebuffer_unregister_private.
  */
 void drm_framebuffer_cleanup(struct drm_framebuffer *fb)
 {
@@ -460,7 +484,8 @@ EXPORT_SYMBOL(drm_framebuffer_cleanup);
  * @fb: framebuffer to remove
  *
  * 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. Then drops the reference to the
+ * passed-in framebuffer.
  */
 void drm_framebuffer_remove(struct drm_framebuffer *fb)
 {
diff --git a/drivers/gpu/drm/drm_fb_cma_helper.c b/drivers/gpu/drm/drm_fb_cma_helper.c
index e1e0cb0..3742bc9 100644
--- a/drivers/gpu/drm/drm_fb_cma_helper.c
+++ b/drivers/gpu/drm/drm_fb_cma_helper.c
@@ -266,6 +266,7 @@ static int drm_fbdev_cma_create(struct drm_fb_helper *helper,
 	return 0;
 
 err_drm_fb_cma_destroy:
+	drm_framebuffer_unregister_private(fb);
 	drm_fb_cma_destroy(fb);
 err_framebuffer_release:
 	framebuffer_release(fbi);
@@ -370,8 +371,10 @@ void drm_fbdev_cma_fini(struct drm_fbdev_cma *fbdev_cma)
 		framebuffer_release(info);
 	}
 
-	if (fbdev_cma->fb)
+	if (fbdev_cma->fb) {
+		drm_framebuffer_unregister_private(&fbdev_cma->fb->fb);
 		drm_fb_cma_destroy(&fbdev_cma->fb->fb);
+	}
 
 	drm_fb_helper_fini(&fbdev_cma->fb_helper);
 	kfree(fbdev_cma);
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c
index 71f8673..90d335c 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c
@@ -326,8 +326,10 @@ static void exynos_drm_fbdev_destroy(struct drm_device *dev,
 	/* release drm framebuffer and real buffer */
 	if (fb_helper->fb && fb_helper->fb->funcs) {
 		fb = fb_helper->fb;
-		if (fb)
+		if (fb) {
+			drm_framebuffer_unregister_private(fb);
 			drm_framebuffer_remove(fb);
+		}
 	}
 
 	/* release linux framebuffer */
diff --git a/drivers/gpu/drm/gma500/framebuffer.c b/drivers/gpu/drm/gma500/framebuffer.c
index 49800d2..c1ef37e 100644
--- a/drivers/gpu/drm/gma500/framebuffer.c
+++ b/drivers/gpu/drm/gma500/framebuffer.c
@@ -590,6 +590,7 @@ static int psb_fbdev_destroy(struct drm_device *dev, struct psb_fbdev *fbdev)
 		framebuffer_release(info);
 	}
 	drm_fb_helper_fini(&fbdev->psb_fb_helper);
+	drm_framebuffer_unregister_private(&psbfb->base);
 	drm_framebuffer_cleanup(&psbfb->base);
 
 	if (psbfb->gtt)
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index b2af790..06fbf3e 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -6505,8 +6505,10 @@ void intel_release_load_detect_pipe(struct drm_connector *connector,
 		intel_encoder->new_crtc = NULL;
 		intel_set_mode(crtc, NULL, 0, 0, NULL);
 
-		if (old->release_fb)
-			old->release_fb->funcs->destroy(old->release_fb);
+		if (old->release_fb) {
+			drm_framebuffer_unregister_private(old->release_fb);
+			drm_framebuffer_unreference(old->release_fb);
+		}
 
 		return;
 	}
diff --git a/drivers/gpu/drm/i915/intel_fb.c b/drivers/gpu/drm/i915/intel_fb.c
index de2920f..755c274 100644
--- a/drivers/gpu/drm/i915/intel_fb.c
+++ b/drivers/gpu/drm/i915/intel_fb.c
@@ -221,6 +221,7 @@ static void intel_fbdev_destroy(struct drm_device *dev,
 
 	drm_fb_helper_fini(&ifbdev->helper);
 
+	drm_framebuffer_unregister_private(&ifb->base);
 	drm_framebuffer_cleanup(&ifb->base);
 	if (ifb->obj) {
 		drm_gem_object_unreference_unlocked(&ifb->obj->base);
diff --git a/drivers/gpu/drm/mgag200/mgag200_fb.c b/drivers/gpu/drm/mgag200/mgag200_fb.c
index 2f48648..5c69b43 100644
--- a/drivers/gpu/drm/mgag200/mgag200_fb.c
+++ b/drivers/gpu/drm/mgag200/mgag200_fb.c
@@ -247,6 +247,7 @@ static int mga_fbdev_destroy(struct drm_device *dev,
 	}
 	drm_fb_helper_fini(&mfbdev->helper);
 	vfree(mfbdev->sysram);
+	drm_framebuffer_unregister_private(&mfb->base);
 	drm_framebuffer_cleanup(&mfb->base);
 
 	return 0;
diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.c b/drivers/gpu/drm/nouveau/nouveau_fbcon.c
index 67a1a06..d4ecb4d 100644
--- a/drivers/gpu/drm/nouveau/nouveau_fbcon.c
+++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.c
@@ -433,6 +433,7 @@ nouveau_fbcon_destroy(struct drm_device *dev, struct nouveau_fbdev *fbcon)
 		nouveau_fb->nvbo = NULL;
 	}
 	drm_fb_helper_fini(&fbcon->helper);
+	drm_framebuffer_unregister_private(&nouveau_fb->base);
 	drm_framebuffer_cleanup(&nouveau_fb->base);
 	return 0;
 }
diff --git a/drivers/gpu/drm/radeon/radeon_fb.c b/drivers/gpu/drm/radeon/radeon_fb.c
index cc8489d..515e5ee 100644
--- a/drivers/gpu/drm/radeon/radeon_fb.c
+++ b/drivers/gpu/drm/radeon/radeon_fb.c
@@ -293,6 +293,7 @@ out_unref:
 	}
 	if (fb && ret) {
 		drm_gem_object_unreference(gobj);
+		drm_framebuffer_unregister_private(fb);
 		drm_framebuffer_cleanup(fb);
 		kfree(fb);
 	}
@@ -339,6 +340,7 @@ static int radeon_fbdev_destroy(struct drm_device *dev, struct radeon_fbdev *rfb
 		rfb->obj = NULL;
 	}
 	drm_fb_helper_fini(&rfbdev->helper);
+	drm_framebuffer_unregister_private(&rfb->base);
 	drm_framebuffer_cleanup(&rfb->base);
 
 	return 0;
diff --git a/drivers/gpu/drm/udl/udl_fb.c b/drivers/gpu/drm/udl/udl_fb.c
index f8904b4..caa84f1 100644
--- a/drivers/gpu/drm/udl/udl_fb.c
+++ b/drivers/gpu/drm/udl/udl_fb.c
@@ -555,6 +555,7 @@ static void udl_fbdev_destroy(struct drm_device *dev,
 		framebuffer_release(info);
 	}
 	drm_fb_helper_fini(&ufbdev->helper);
+	drm_framebuffer_unregister_private(&ufbdev->ufb.base);
 	drm_framebuffer_cleanup(&ufbdev->ufb.base);
 	drm_gem_object_unreference_unlocked(&ufbdev->ufb.obj->base);
 }
diff --git a/drivers/staging/omapdrm/omap_fbdev.c b/drivers/staging/omapdrm/omap_fbdev.c
index 8a027bb..2728e37 100644
--- a/drivers/staging/omapdrm/omap_fbdev.c
+++ b/drivers/staging/omapdrm/omap_fbdev.c
@@ -275,8 +275,10 @@ fail:
 	if (ret) {
 		if (fbi)
 			framebuffer_release(fbi);
-		if (fb)
+		if (fb) {
+			drm_framebuffer_unregister_private(fb);
 			drm_framebuffer_remove(fb);
+		}
 	}
 
 	return ret;
@@ -400,8 +402,10 @@ void omap_fbdev_free(struct drm_device *dev)
 	fbdev = to_omap_fbdev(priv->fbdev);
 
 	/* this will free the backing object */
-	if (fbdev->fb)
+	if (fbdev->fb) {
+		drm_framebuffer_unregister_private(fbdev->fb);
 		drm_framebuffer_remove(fbdev->fb);
+	}
 
 	kfree(fbdev);
 
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index 7dc1b31..66b2732 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -964,6 +964,7 @@ extern void drm_framebuffer_unreference(struct drm_framebuffer *fb);
 extern void drm_framebuffer_reference(struct drm_framebuffer *fb);
 extern void drm_framebuffer_remove(struct drm_framebuffer *fb);
 extern void drm_framebuffer_cleanup(struct drm_framebuffer *fb);
+extern void drm_framebuffer_unregister_private(struct drm_framebuffer *fb);
 extern int drmfb_probe(struct drm_device *dev, struct drm_crtc *crtc);
 extern int drmfb_remove(struct drm_device *dev, struct drm_framebuffer *fb);
 extern void drm_crtc_probe_connector_modes(struct drm_device *dev, int maxX, int maxY);
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PATCH 22/35] drm: reference framebuffers which are on the idr
  2013-01-10 20:47 [PATCH 00/36] kms locking rework Daniel Vetter
                   ` (20 preceding siblings ...)
  2013-01-10 20:48 ` [PATCH 21/35] drm: revamp framebuffer cleanup interfaces Daniel Vetter
@ 2013-01-10 20:48 ` Daniel Vetter
  2013-01-10 20:48 ` [PATCH 23/35] drm: nest modeset locks within fpriv->fbs_lock Daniel Vetter
                   ` (14 subsequent siblings)
  36 siblings, 0 replies; 45+ messages in thread
From: Daniel Vetter @ 2013-01-10 20:48 UTC (permalink / raw)
  To: DRI Development; +Cc: Daniel Vetter

Since otherwise looking and reference-counting around
drm_framebuffer_lookup will be an unmanageable mess. With this change,
an object can either be found in the idr and will stay around once we
incremented the reference counter. Or it will be gone for good and
can't be looked up using its id any more.

Atomicity is guaranteed by the dev->mode_config.fb_lock. The
newly-introduce fpriv->fbs_lock looks a bit redundant, but the next
patch will shuffle the locking order between these two locks and all
the modeset locks taken in modeset_lock_all, so we'll need it.

Also, since userspace could do really funky stuff and race e.g. a
getresources with an rmfb, we need to make sure that the kernel
doesn't fall over trying to look-up an inexistent fb, or causing
confusion by having two fbs around with the same id. Simply reset the
framebuffer id to 0, which marks it as reaped. Any lookups of that id
will fail, so the object is really gone for good from userspace's pov.

Note that we still need to protect the "remove framebuffer from all
use-cases" and the final unreference with the modeset-lock, since most
framebuffer use-sites don't implement proper reference counting yet.
We can only lift this once _all_ users are converted.

With this change, two references are held on alife, but unused
framebuffers:
- The reference for the idr lookup, created in this patch.
- For user-created framebuffers the fpriv->fbs reference, for
  driver-private fbs the driver is supposed to hold it's own last
  reference.

Note that the dev->mode_config.fb_list itself does _not_ hold a
reference onto the framebuffers (this list is essentially only used
for debugfs files). Hence if there's anything left there when the
driver has cleaned up all it's modeset resources, this is a ref-leak.
WARN about it.

Now we only need to fix up all other places to properly reference
count framebuffers.

Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 drivers/gpu/drm/drm_crtc.c |  118 ++++++++++++++++++++++++++++++--------------
 1 file changed, 80 insertions(+), 38 deletions(-)

diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index 4e7c362..b6eecd2 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -356,6 +356,9 @@ int drm_framebuffer_init(struct drm_device *dev, struct drm_framebuffer *fb,
 	if (ret)
 		goto out;
 
+	/* Grab the idr reference. */
+	drm_framebuffer_reference(fb);
+
 	dev->mode_config.num_fb++;
 	list_add(&fb->head, &dev->mode_config.fb_list);
 out:
@@ -372,6 +375,23 @@ static void drm_framebuffer_free(struct kref *kref)
 	fb->funcs->destroy(fb);
 }
 
+static struct drm_framebuffer *__drm_framebuffer_lookup(struct drm_device *dev,
+							uint32_t id)
+{
+	struct drm_mode_object *obj = NULL;
+	struct drm_framebuffer *fb;
+
+	mutex_lock(&dev->mode_config.idr_mutex);
+	obj = idr_find(&dev->mode_config.crtc_idr, id);
+	if (!obj || (obj->type != DRM_MODE_OBJECT_FB) || (obj->id != id))
+		fb = NULL;
+	else
+		fb = obj_to_fb(obj);
+	mutex_unlock(&dev->mode_config.idr_mutex);
+
+	return fb;
+}
+
 /**
  * drm_framebuffer_lookup - look up a drm framebuffer and grab a reference
  * @dev: drm device
@@ -384,22 +404,12 @@ static void drm_framebuffer_free(struct kref *kref)
 struct drm_framebuffer *drm_framebuffer_lookup(struct drm_device *dev,
 					       uint32_t id)
 {
-	struct drm_mode_object *obj = NULL;
 	struct drm_framebuffer *fb;
 
 	mutex_lock(&dev->mode_config.fb_lock);
-
-	mutex_lock(&dev->mode_config.idr_mutex);
-	obj = idr_find(&dev->mode_config.crtc_idr, id);
-	if (!obj || (obj->type != DRM_MODE_OBJECT_FB) || (obj->id != id))
-		fb = NULL;
-	else
-		fb = obj_to_fb(obj);
-	mutex_unlock(&dev->mode_config.idr_mutex);
-
+	fb = __drm_framebuffer_lookup(dev, id);
 	if (fb)
 		kref_get(&fb->refcount);
-
 	mutex_unlock(&dev->mode_config.fb_lock);
 
 	return fb;
@@ -430,6 +440,24 @@ void drm_framebuffer_reference(struct drm_framebuffer *fb)
 }
 EXPORT_SYMBOL(drm_framebuffer_reference);
 
+static void drm_framebuffer_free_bug(struct kref *kref)
+{
+	BUG();
+}
+
+/* dev->mode_config.fb_lock must be held! */
+static void __drm_framebuffer_unregister(struct drm_device *dev,
+					 struct drm_framebuffer *fb)
+{
+	mutex_lock(&dev->mode_config.idr_mutex);
+	idr_remove(&dev->mode_config.crtc_idr, fb->base.id);
+	mutex_unlock(&dev->mode_config.idr_mutex);
+
+	fb->base.id = 0;
+
+	kref_put(&fb->refcount, drm_framebuffer_free_bug);
+}
+
 /**
  * drm_framebuffer_unregister_private - unregister a private fb from the lookup idr
  * @fb: fb to unregister
@@ -441,6 +469,12 @@ EXPORT_SYMBOL(drm_framebuffer_reference);
  */
 void drm_framebuffer_unregister_private(struct drm_framebuffer *fb)
 {
+	struct drm_device *dev = fb->dev;
+
+	mutex_lock(&dev->mode_config.fb_lock);
+	/* Mark fb as reaped and drop idr ref. */
+	__drm_framebuffer_unregister(dev, fb);
+	mutex_unlock(&dev->mode_config.fb_lock);
 }
 EXPORT_SYMBOL(drm_framebuffer_unregister_private);
 
@@ -464,14 +498,6 @@ void drm_framebuffer_cleanup(struct drm_framebuffer *fb)
 {
 	struct drm_device *dev = fb->dev;
 
-	/*
-	 * This could be moved to drm_framebuffer_remove(), but for
-	 * debugging is nice to keep around the list of fb's that are
-	 * no longer associated w/ a drm_file but are not unreferenced
-	 * yet.  (i915 and omapdrm have debugfs files which will show
-	 * this.)
-	 */
-	drm_mode_object_put(dev, &fb->base);
 	mutex_lock(&dev->mode_config.fb_lock);
 	list_del(&fb->head);
 	dev->mode_config.num_fb--;
@@ -1181,9 +1207,15 @@ void drm_mode_config_cleanup(struct drm_device *dev)
 		drm_property_destroy(dev, property);
 	}
 
-	/* Single-threaded teardown context, so it's not requied to grab the
+	/*
+	 * Single-threaded teardown context, so it's not requied to grab the
 	 * fb_lock to protect against concurrent fb_list access. Contrary, it
-	 * would actually deadlock with the drm_framebuffer_cleanup function. */
+	 * would actually deadlock with the drm_framebuffer_cleanup function.
+	 *
+	 * Also, if there are any framebuffers left, that's a driver leak now,
+	 * so politely WARN about this.
+	 */
+	WARN_ON(!list_empty(&dev->mode_config.fb_list));
 	list_for_each_entry_safe(fb, fbt, &dev->mode_config.fb_list, head) {
 		drm_framebuffer_remove(fb);
 	}
@@ -2464,39 +2496,41 @@ int drm_mode_rmfb(struct drm_device *dev,
 	struct drm_framebuffer *fb = NULL;
 	struct drm_framebuffer *fbl = NULL;
 	uint32_t *id = data;
-	int ret = 0;
 	int found = 0;
 
 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
 		return -EINVAL;
 
-	drm_modeset_lock_all(dev);
-	fb = drm_framebuffer_lookup(dev, *id);
-	if (!fb) {
-		ret = -EINVAL;
-		goto out;
-	}
-	/* fb is protect by the mode_config lock, so drop the ref immediately */
-	drm_framebuffer_unreference(fb);
-
 	mutex_lock(&file_priv->fbs_lock);
+	mutex_lock(&dev->mode_config.fb_lock);
+	fb = __drm_framebuffer_lookup(dev, *id);
+	if (!fb)
+		goto fail_lookup;
+
 	list_for_each_entry(fbl, &file_priv->fbs, filp_head)
 		if (fb == fbl)
 			found = 1;
-	if (!found) {
-		ret = -EINVAL;
-		mutex_unlock(&file_priv->fbs_lock);
-		goto out;
-	}
+	if (!found)
+		goto fail_lookup;
+
+	/* Mark fb as reaped, we still have a ref from fpriv->fbs. */
+	__drm_framebuffer_unregister(dev, fb);
 
 	list_del_init(&fb->filp_head);
+	mutex_unlock(&dev->mode_config.fb_lock);
 	mutex_unlock(&file_priv->fbs_lock);
 
+	drm_modeset_lock_all(dev);
 	drm_framebuffer_remove(fb);
-out:
 	drm_modeset_unlock_all(dev);
 
-	return ret;
+	return 0;
+
+fail_lookup:
+	mutex_unlock(&dev->mode_config.fb_lock);
+	mutex_unlock(&file_priv->fbs_lock);
+
+	return -EINVAL;
 }
 
 /**
@@ -2639,7 +2673,15 @@ void drm_fb_release(struct drm_file *priv)
 	drm_modeset_lock_all(dev);
 	mutex_lock(&priv->fbs_lock);
 	list_for_each_entry_safe(fb, tfb, &priv->fbs, filp_head) {
+
+		mutex_lock(&dev->mode_config.fb_lock);
+		/* Mark fb as reaped, we still have a ref from fpriv->fbs. */
+		__drm_framebuffer_unregister(dev, fb);
+		mutex_unlock(&dev->mode_config.fb_lock);
+
 		list_del_init(&fb->filp_head);
+
+		/* This will also drop the fpriv->fbs reference. */
 		drm_framebuffer_remove(fb);
 	}
 	mutex_unlock(&priv->fbs_lock);
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PATCH 23/35] drm: nest modeset locks within fpriv->fbs_lock
  2013-01-10 20:47 [PATCH 00/36] kms locking rework Daniel Vetter
                   ` (21 preceding siblings ...)
  2013-01-10 20:48 ` [PATCH 22/35] drm: reference framebuffers which are on the idr Daniel Vetter
@ 2013-01-10 20:48 ` Daniel Vetter
  2013-01-10 20:48 ` [PATCH 24/35] drm: push modeset_lock_all into ->fb_create driver callbacks Daniel Vetter
                   ` (13 subsequent siblings)
  36 siblings, 0 replies; 45+ messages in thread
From: Daniel Vetter @ 2013-01-10 20:48 UTC (permalink / raw)
  To: DRI Development; +Cc: Daniel Vetter

Atm we still need to unconditionally take the modeset locks in the
rmfb paths. But eventually we only want to take them if there are
other users around as a slow-path. This way sane userspace avoids
blocking on edid reads and other stuff in rmfb if it ensures that the
fb isn't used anywhere by a crtc/plane.

We can do a quick check for such other users once framebuffers are
properly refcounting by locking at the refcount - if it's more than 1,
there are other users left. Again, rmfb racing against other ioctls
isn't a real problem, userspace is allowed to shoot its foot.

This patch just prepares this by moving the modeset locks to nest
within fpriv->fbs_lock. Now the distinction between the fbs_lock and
the device-global fb_lock is clear, since we need to hold the fbs_lock
outside of any modeset_locks in fb_release.

Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 drivers/gpu/drm/drm_crtc.c |    8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index b6eecd2..b2a845b 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -2282,13 +2282,13 @@ int drm_mode_addfb(struct drm_device *dev,
 		drm_modeset_unlock_all(dev);
 		return PTR_ERR(fb);
 	}
+	drm_modeset_unlock_all(dev);
 
 	mutex_lock(&file_priv->fbs_lock);
 	or->fb_id = fb->base.id;
 	list_add(&fb->filp_head, &file_priv->fbs);
 	DRM_DEBUG_KMS("[FB:%d]\n", fb->base.id);
 	mutex_unlock(&file_priv->fbs_lock);
-	drm_modeset_unlock_all(dev);
 
 	return ret;
 }
@@ -2465,6 +2465,7 @@ int drm_mode_addfb2(struct drm_device *dev,
 		drm_modeset_unlock_all(dev);
 		return PTR_ERR(fb);
 	}
+	drm_modeset_unlock_all(dev);
 
 	mutex_lock(&file_priv->fbs_lock);
 	r->fb_id = fb->base.id;
@@ -2472,7 +2473,6 @@ int drm_mode_addfb2(struct drm_device *dev,
 	DRM_DEBUG_KMS("[FB:%d]\n", fb->base.id);
 	mutex_unlock(&file_priv->fbs_lock);
 
-	drm_modeset_unlock_all(dev);
 
 	return ret;
 }
@@ -2670,7 +2670,6 @@ void drm_fb_release(struct drm_file *priv)
 	struct drm_device *dev = priv->minor->dev;
 	struct drm_framebuffer *fb, *tfb;
 
-	drm_modeset_lock_all(dev);
 	mutex_lock(&priv->fbs_lock);
 	list_for_each_entry_safe(fb, tfb, &priv->fbs, filp_head) {
 
@@ -2682,10 +2681,11 @@ void drm_fb_release(struct drm_file *priv)
 		list_del_init(&fb->filp_head);
 
 		/* This will also drop the fpriv->fbs reference. */
+		drm_modeset_lock_all(dev);
 		drm_framebuffer_remove(fb);
+		drm_modeset_unlock_all(dev);
 	}
 	mutex_unlock(&priv->fbs_lock);
-	drm_modeset_unlock_all(dev);
 }
 
 /**
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PATCH 24/35] drm: push modeset_lock_all into ->fb_create driver callbacks
  2013-01-10 20:47 [PATCH 00/36] kms locking rework Daniel Vetter
                   ` (22 preceding siblings ...)
  2013-01-10 20:48 ` [PATCH 23/35] drm: nest modeset locks within fpriv->fbs_lock Daniel Vetter
@ 2013-01-10 20:48 ` Daniel Vetter
  2013-01-10 20:48 ` [PATCH 25/35] drm: don't take modeset locks in getfb ioctl Daniel Vetter
                   ` (12 subsequent siblings)
  36 siblings, 0 replies; 45+ messages in thread
From: Daniel Vetter @ 2013-01-10 20:48 UTC (permalink / raw)
  To: DRI Development; +Cc: Daniel Vetter

And drop it where it's not needed. Most driver just lookup the gem
object, allocate an fb struct, fill in all the useful fields and then
register it with drm_framebuffer_init.

All of these operations are already separately locked, and since we
only put the fb into the fpriv->fbs list _after_ having called
->fb_create, we can't also race with rmfb. We can otoh race with other
ioctls that put the framebuffer to use, but all drivers have been
reorganized already to call drm_framebuffer_init last in the fb
creation sequence.

So essentially, we can completely remove any modeset locks from the
addfb ioctl paths. Yeah!

Also, reference-counting is solid - we get a reference from fb_create
which we transfer to the fpriv->fbs list. And after unlocking the
fpriv->fbs_lock we don't touch the framebuffer any longer. Furthermore
drm_framebuffer_init has added a 2nd reference for the idr lookup, and
any access through that table will do it's own refcounting.

Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 drivers/gpu/drm/drm_crtc.c |    9 ---------
 1 file changed, 9 deletions(-)

diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index b2a845b..60d6d87 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -2271,18 +2271,12 @@ int drm_mode_addfb(struct drm_device *dev,
 	if ((config->min_height > r.height) || (r.height > config->max_height))
 		return -EINVAL;
 
-	drm_modeset_lock_all(dev);
-
-	/* TODO check buffer is sufficiently large */
-	/* TODO setup destructor callback */
-
 	fb = dev->mode_config.funcs->fb_create(dev, file_priv, &r);
 	if (IS_ERR(fb)) {
 		DRM_DEBUG_KMS("could not create framebuffer\n");
 		drm_modeset_unlock_all(dev);
 		return PTR_ERR(fb);
 	}
-	drm_modeset_unlock_all(dev);
 
 	mutex_lock(&file_priv->fbs_lock);
 	or->fb_id = fb->base.id;
@@ -2457,15 +2451,12 @@ int drm_mode_addfb2(struct drm_device *dev,
 	if (ret)
 		return ret;
 
-	drm_modeset_lock_all(dev);
-
 	fb = dev->mode_config.funcs->fb_create(dev, file_priv, r);
 	if (IS_ERR(fb)) {
 		DRM_DEBUG_KMS("could not create framebuffer\n");
 		drm_modeset_unlock_all(dev);
 		return PTR_ERR(fb);
 	}
-	drm_modeset_unlock_all(dev);
 
 	mutex_lock(&file_priv->fbs_lock);
 	r->fb_id = fb->base.id;
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PATCH 25/35] drm: don't take modeset locks in getfb ioctl
  2013-01-10 20:47 [PATCH 00/36] kms locking rework Daniel Vetter
                   ` (23 preceding siblings ...)
  2013-01-10 20:48 ` [PATCH 24/35] drm: push modeset_lock_all into ->fb_create driver callbacks Daniel Vetter
@ 2013-01-10 20:48 ` Daniel Vetter
  2013-01-10 20:48 ` [PATCH 26/35] drm: fb refcounting for dirtyfb_ioctl Daniel Vetter
                   ` (11 subsequent siblings)
  36 siblings, 0 replies; 45+ messages in thread
From: Daniel Vetter @ 2013-01-10 20:48 UTC (permalink / raw)
  To: DRI Development; +Cc: Daniel Vetter

We only need to push the fb unreference a bit down. While at it,
properly pass the return value from ->create_handle back to userspace.

Most drivers either return -ENODEV if they don't have a concept of
buffer objects (ast, cirrus, ...) or just install a handle for the
underlying gem object (which is ok since we hold a reference on that
through the framebuffer).

v2: Split out the ->create_handle rework in the individual drivers.

Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 drivers/gpu/drm/drm_crtc.c |   15 +++++----------
 1 file changed, 5 insertions(+), 10 deletions(-)

diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index 60d6d87..8003063 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -2542,19 +2542,14 @@ int drm_mode_getfb(struct drm_device *dev,
 {
 	struct drm_mode_fb_cmd *r = data;
 	struct drm_framebuffer *fb;
-	int ret = 0;
+	int ret;
 
 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
 		return -EINVAL;
 
-	drm_modeset_lock_all(dev);
 	fb = drm_framebuffer_lookup(dev, r->fb_id);
-	if (!fb) {
-		ret = -EINVAL;
-		goto out;
-	}
-	/* fb is protect by the mode_config lock, so drop the ref immediately */
-	drm_framebuffer_unreference(fb);
+	if (!fb)
+		return -EINVAL;
 
 	r->height = fb->height;
 	r->width = fb->width;
@@ -2566,8 +2561,8 @@ int drm_mode_getfb(struct drm_device *dev,
 	else
 		ret = -ENODEV;
 
-out:
-	drm_modeset_unlock_all(dev);
+	drm_framebuffer_unreference(fb);
+
 	return ret;
 }
 
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PATCH 26/35] drm: fb refcounting for dirtyfb_ioctl
  2013-01-10 20:47 [PATCH 00/36] kms locking rework Daniel Vetter
                   ` (24 preceding siblings ...)
  2013-01-10 20:48 ` [PATCH 25/35] drm: don't take modeset locks in getfb ioctl Daniel Vetter
@ 2013-01-10 20:48 ` Daniel Vetter
  2013-01-10 20:48 ` [PATCH 27/35] drm: refcounting for sprite framebuffers Daniel Vetter
                   ` (10 subsequent siblings)
  36 siblings, 0 replies; 45+ messages in thread
From: Daniel Vetter @ 2013-01-10 20:48 UTC (permalink / raw)
  To: DRI Development; +Cc: Daniel Vetter

We only need to ensure that the fb stays around for long enough. While
at it, only grab the modeset locks when we need them (since most
drivers don't implement the dirty callback, this should help jitter
and stalls when using the generic modeset driver).

Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 drivers/gpu/drm/drm_crtc.c |   15 ++++++---------
 1 file changed, 6 insertions(+), 9 deletions(-)

diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index 8003063..ed0108e 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -2580,14 +2580,9 @@ int drm_mode_dirtyfb_ioctl(struct drm_device *dev,
 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
 		return -EINVAL;
 
-	drm_modeset_lock_all(dev);
 	fb = drm_framebuffer_lookup(dev, r->fb_id);
-	if (!fb) {
-		ret = -EINVAL;
-		goto out_err1;
-	}
-	/* fb is protect by the mode_config lock, so drop the ref immediately */
-	drm_framebuffer_unreference(fb);
+	if (!fb)
+		return -EINVAL;
 
 	num_clips = r->num_clips;
 	clips_ptr = (struct drm_clip_rect __user *)(unsigned long)r->clips_ptr;
@@ -2625,17 +2620,19 @@ int drm_mode_dirtyfb_ioctl(struct drm_device *dev,
 	}
 
 	if (fb->funcs->dirty) {
+		drm_modeset_lock_all(dev);
 		ret = fb->funcs->dirty(fb, file_priv, flags, r->color,
 				       clips, num_clips);
+		drm_modeset_unlock_all(dev);
 	} else {
 		ret = -ENOSYS;
-		goto out_err2;
 	}
 
 out_err2:
 	kfree(clips);
 out_err1:
-	drm_modeset_unlock_all(dev);
+	drm_framebuffer_unreference(fb);
+
 	return ret;
 }
 
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PATCH 27/35] drm: refcounting for sprite framebuffers
  2013-01-10 20:47 [PATCH 00/36] kms locking rework Daniel Vetter
                   ` (25 preceding siblings ...)
  2013-01-10 20:48 ` [PATCH 26/35] drm: fb refcounting for dirtyfb_ioctl Daniel Vetter
@ 2013-01-10 20:48 ` Daniel Vetter
  2013-01-10 20:48 ` [PATCH 28/35] drm: refcounting for crtc framebuffers Daniel Vetter
                   ` (9 subsequent siblings)
  36 siblings, 0 replies; 45+ messages in thread
From: Daniel Vetter @ 2013-01-10 20:48 UTC (permalink / raw)
  To: DRI Development; +Cc: Daniel Vetter

Now plane->fb holds a reference onto it's framebuffer. Nothing too
fancy going on here:
- Extract __drm_framebuffer_unreference to be called when we know
  we're not dropping the last reference, e.g. useful in the fb cleanup
  code.
- Reduce the locked sections in the set_plane ioctl to only protect
  plane->fb/plane->crtc and the driver callback (i.e. hw state).
  Everything either doesn't disappear (crtc, plane) or is refcounted
  (fb), and all the data we check is invariant over the respective
  object's lifetimes.

Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 drivers/gpu/drm/drm_crtc.c |   30 +++++++++++++++++++++---------
 1 file changed, 21 insertions(+), 9 deletions(-)

diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index ed0108e..57ddf2f 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -445,6 +445,12 @@ static void drm_framebuffer_free_bug(struct kref *kref)
 	BUG();
 }
 
+static void __drm_framebuffer_unreference(struct drm_framebuffer *fb)
+{
+	DRM_DEBUG("FB ID: %d\n", fb->base.id);
+	kref_put(&fb->refcount, drm_framebuffer_free_bug);
+}
+
 /* dev->mode_config.fb_lock must be held! */
 static void __drm_framebuffer_unregister(struct drm_device *dev,
 					 struct drm_framebuffer *fb)
@@ -455,7 +461,7 @@ static void __drm_framebuffer_unregister(struct drm_device *dev,
 
 	fb->base.id = 0;
 
-	kref_put(&fb->refcount, drm_framebuffer_free_bug);
+	__drm_framebuffer_unreference(fb);
 }
 
 /**
@@ -544,6 +550,7 @@ void drm_framebuffer_remove(struct drm_framebuffer *fb)
 			if (ret)
 				DRM_ERROR("failed to disable plane with busy fb\n");
 			/* disconnect the plane from the fb and crtc: */
+			__drm_framebuffer_unreference(plane->fb);
 			plane->fb = NULL;
 			plane->crtc = NULL;
 		}
@@ -1850,7 +1857,7 @@ int drm_mode_setplane(struct drm_device *dev, void *data,
 	struct drm_mode_object *obj;
 	struct drm_plane *plane;
 	struct drm_crtc *crtc;
-	struct drm_framebuffer *fb;
+	struct drm_framebuffer *fb = NULL, *old_fb = NULL;
 	int ret = 0;
 	unsigned int fb_width, fb_height;
 	int i;
@@ -1858,8 +1865,6 @@ int drm_mode_setplane(struct drm_device *dev, void *data,
 	if (!drm_core_check_feature(dev, DRIVER_MODESET))
 		return -EINVAL;
 
-	drm_modeset_lock_all(dev);
-
 	/*
 	 * First, find the plane, crtc, and fb objects.  If not available,
 	 * we don't bother to call the driver.
@@ -1869,16 +1874,18 @@ int drm_mode_setplane(struct drm_device *dev, void *data,
 	if (!obj) {
 		DRM_DEBUG_KMS("Unknown plane ID %d\n",
 			      plane_req->plane_id);
-		ret = -ENOENT;
-		goto out;
+		return -ENOENT;
 	}
 	plane = obj_to_plane(obj);
 
 	/* No fb means shut it down */
 	if (!plane_req->fb_id) {
+		drm_modeset_lock_all(dev);
+		old_fb = plane->fb;
 		plane->funcs->disable_plane(plane);
 		plane->crtc = NULL;
 		plane->fb = NULL;
+		drm_modeset_unlock_all(dev);
 		goto out;
 	}
 
@@ -1899,8 +1906,6 @@ int drm_mode_setplane(struct drm_device *dev, void *data,
 		ret = -ENOENT;
 		goto out;
 	}
-	/* fb is protect by the mode_config lock, so drop the ref immediately */
-	drm_framebuffer_unreference(fb);
 
 	/* Check whether this plane supports the fb pixel format. */
 	for (i = 0; i < plane->format_count; i++)
@@ -1946,18 +1951,25 @@ int drm_mode_setplane(struct drm_device *dev, void *data,
 		goto out;
 	}
 
+	drm_modeset_lock_all(dev);
 	ret = plane->funcs->update_plane(plane, crtc, fb,
 					 plane_req->crtc_x, plane_req->crtc_y,
 					 plane_req->crtc_w, plane_req->crtc_h,
 					 plane_req->src_x, plane_req->src_y,
 					 plane_req->src_w, plane_req->src_h);
 	if (!ret) {
+		old_fb = plane->fb;
+		fb = NULL;
 		plane->crtc = crtc;
 		plane->fb = fb;
 	}
+	drm_modeset_unlock_all(dev);
 
 out:
-	drm_modeset_unlock_all(dev);
+	if (fb)
+		drm_framebuffer_unreference(fb);
+	if (old_fb)
+		drm_framebuffer_unreference(old_fb);
 
 	return ret;
 }
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PATCH 28/35] drm: refcounting for crtc framebuffers
  2013-01-10 20:47 [PATCH 00/36] kms locking rework Daniel Vetter
                   ` (26 preceding siblings ...)
  2013-01-10 20:48 ` [PATCH 27/35] drm: refcounting for sprite framebuffers Daniel Vetter
@ 2013-01-10 20:48 ` Daniel Vetter
  2013-01-10 20:48 ` [PATCH 29/35] drm/i915: dump refcount into framebuffer debugfs file Daniel Vetter
                   ` (8 subsequent siblings)
  36 siblings, 0 replies; 45+ messages in thread
From: Daniel Vetter @ 2013-01-10 20:48 UTC (permalink / raw)
  To: DRI Development; +Cc: Daniel Vetter

With the prep patch to encapsulate ->set_crtc calls, this is now
rather easy. Hooray for inconsistent semantics between ->set_crtc and
->page_flip, where the driver callback is supposed to update the fb
pointer, and ->update_plane, where the drm core does the same.

Also, since the drm core functions check crtc->fb before calling into
driver callbacks, we can't really reduce the critical sections
protected by the mode_config locks.

Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 drivers/gpu/drm/drm_crtc.c |   37 ++++++++++++++++++++++++++++++-------
 1 file changed, 30 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index 57ddf2f..61adee6 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -1984,8 +1984,21 @@ out:
 int drm_mode_set_config_internal(struct drm_mode_set *set)
 {
 	struct drm_crtc *crtc = set->crtc;
+	struct drm_framebuffer *fb, *old_fb;
+	int ret;
+
+	old_fb = crtc->fb;
+	fb = set->fb;
 
-	return crtc->funcs->set_config(set);
+	ret = crtc->funcs->set_config(set);
+	if (ret == 0) {
+		if (old_fb)
+			drm_framebuffer_unreference(old_fb);
+		if (fb)
+			drm_framebuffer_reference(fb);
+	}
+
+	return ret;
 }
 EXPORT_SYMBOL(drm_mode_set_config_internal);
 
@@ -2046,6 +2059,8 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data,
 				goto out;
 			}
 			fb = crtc->fb;
+			/* Make refcounting symmetric with the lookup path. */
+			drm_framebuffer_reference(fb);
 		} else {
 			fb = drm_framebuffer_lookup(dev, crtc_req->fb_id);
 			if (!fb) {
@@ -2054,9 +2069,6 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data,
 				ret = -EINVAL;
 				goto out;
 			}
-			/* fb is protect by the mode_config lock, so drop the
-			 * ref immediately */
-			drm_framebuffer_unreference(fb);
 		}
 
 		mode = drm_mode_create(dev);
@@ -2156,6 +2168,9 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data,
 	ret = drm_mode_set_config_internal(&set);
 
 out:
+	if (fb)
+		drm_framebuffer_unreference(fb);
+
 	kfree(connector_set);
 	drm_mode_destroy(dev, mode);
 	drm_modeset_unlock_all(dev);
@@ -3656,7 +3671,7 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev,
 	struct drm_mode_crtc_page_flip *page_flip = data;
 	struct drm_mode_object *obj;
 	struct drm_crtc *crtc;
-	struct drm_framebuffer *fb;
+	struct drm_framebuffer *fb = NULL, *old_fb = NULL;
 	struct drm_pending_vblank_event *e = NULL;
 	unsigned long flags;
 	int hdisplay, vdisplay;
@@ -3687,8 +3702,6 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev,
 	fb = drm_framebuffer_lookup(dev, page_flip->fb_id);
 	if (!fb)
 		goto out;
-	/* fb is protect by the mode_config lock, so drop the ref immediately */
-	drm_framebuffer_unreference(fb);
 
 	hdisplay = crtc->mode.hdisplay;
 	vdisplay = crtc->mode.vdisplay;
@@ -3734,6 +3747,7 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev,
 			(void (*) (struct drm_pending_event *)) kfree;
 	}
 
+	old_fb = crtc->fb;
 	ret = crtc->funcs->page_flip(crtc, fb, e);
 	if (ret) {
 		if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT) {
@@ -3742,9 +3756,18 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev,
 			spin_unlock_irqrestore(&dev->event_lock, flags);
 			kfree(e);
 		}
+		/* Keep the old fb, don't unref it. */
+		old_fb = NULL;
+	} else {
+		/* Unref only the old framebuffer. */
+		fb = NULL;
 	}
 
 out:
+	if (fb)
+		drm_framebuffer_unreference(fb);
+	if (old_fb)
+		drm_framebuffer_unreference(old_fb);
 	drm_modeset_unlock_all(dev);
 	return ret;
 }
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PATCH 29/35] drm/i915: dump refcount into framebuffer debugfs file
  2013-01-10 20:47 [PATCH 00/36] kms locking rework Daniel Vetter
                   ` (27 preceding siblings ...)
  2013-01-10 20:48 ` [PATCH 28/35] drm: refcounting for crtc framebuffers Daniel Vetter
@ 2013-01-10 20:48 ` Daniel Vetter
  2013-01-11 22:20   ` Rob Clark
  2013-01-10 20:48 ` [PATCH 30/35] drm/vmwgfx: add proper framebuffer refcounting Daniel Vetter
                   ` (7 subsequent siblings)
  36 siblings, 1 reply; 45+ messages in thread
From: Daniel Vetter @ 2013-01-10 20:48 UTC (permalink / raw)
  To: DRI Development; +Cc: Daniel Vetter

Useful for checking whether the new refcounting works as advertised.

Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 drivers/gpu/drm/i915/i915_debugfs.c |   10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
index 1269a46..7576e78 100644
--- a/drivers/gpu/drm/i915/i915_debugfs.c
+++ b/drivers/gpu/drm/i915/i915_debugfs.c
@@ -1440,11 +1440,12 @@ static int i915_gem_framebuffer_info(struct seq_file *m, void *data)
 	ifbdev = dev_priv->fbdev;
 	fb = to_intel_framebuffer(ifbdev->helper.fb);
 
-	seq_printf(m, "fbcon size: %d x %d, depth %d, %d bpp, obj ",
+	seq_printf(m, "fbcon size: %d x %d, depth %d, %d bpp, refcount %d, obj ",
 		   fb->base.width,
 		   fb->base.height,
 		   fb->base.depth,
-		   fb->base.bits_per_pixel);
+		   fb->base.bits_per_pixel,
+		   atomic_read(&fb->base.refcount.refcount));
 	describe_obj(m, fb->obj);
 	seq_printf(m, "\n");
 	mutex_unlock(&dev->mode_config.mutex);
@@ -1454,11 +1455,12 @@ static int i915_gem_framebuffer_info(struct seq_file *m, void *data)
 		if (&fb->base == ifbdev->helper.fb)
 			continue;
 
-		seq_printf(m, "user size: %d x %d, depth %d, %d bpp, obj ",
+		seq_printf(m, "user size: %d x %d, depth %d, %d bpp, refcount %d, obj ",
 			   fb->base.width,
 			   fb->base.height,
 			   fb->base.depth,
-			   fb->base.bits_per_pixel);
+			   fb->base.bits_per_pixel,
+			   atomic_read(&fb->base.refcount.refcount));
 		describe_obj(m, fb->obj);
 		seq_printf(m, "\n");
 	}
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PATCH 30/35] drm/vmwgfx: add proper framebuffer refcounting
  2013-01-10 20:47 [PATCH 00/36] kms locking rework Daniel Vetter
                   ` (28 preceding siblings ...)
  2013-01-10 20:48 ` [PATCH 29/35] drm/i915: dump refcount into framebuffer debugfs file Daniel Vetter
@ 2013-01-10 20:48 ` Daniel Vetter
  2013-01-10 20:48 ` [PATCH 31/35] drm: optimize drm_framebuffer_remove Daniel Vetter
                   ` (6 subsequent siblings)
  36 siblings, 0 replies; 45+ messages in thread
From: Daniel Vetter @ 2013-01-10 20:48 UTC (permalink / raw)
  To: DRI Development; +Cc: Daniel Vetter

Afact vmwgfx already has all the right refcounting implemented on the
backing storage, and we only need to ensure that the drm fb doesn't
disappear untimely. So holding onto the fb reference from _lookup
until vmw_kms_present has completed should be enough.

Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c |    8 +++-----
 1 file changed, 3 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c
index 1b8f428..c509d40 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c
@@ -171,8 +171,6 @@ int vmw_present_ioctl(struct drm_device *dev, void *data,
 		ret = -EINVAL;
 		goto out_no_fb;
 	}
-	/* fb is protect by the mode_config lock, so drop the ref immediately */
-	drm_framebuffer_unreference(fb);
 	vfb = vmw_framebuffer_to_vfb(fb);
 
 	ret = ttm_read_lock(&vmaster->lock, true);
@@ -197,6 +195,7 @@ int vmw_present_ioctl(struct drm_device *dev, void *data,
 out_no_surface:
 	ttm_read_unlock(&vmaster->lock);
 out_no_ttm_lock:
+	drm_framebuffer_unreference(fb);
 out_no_fb:
 	drm_modeset_unlock_all(dev);
 out_no_copy:
@@ -256,14 +255,12 @@ int vmw_present_readback_ioctl(struct drm_device *dev, void *data,
 		ret = -EINVAL;
 		goto out_no_fb;
 	}
-	/* fb is protect by the mode_config lock, so drop the ref immediately */
-	drm_framebuffer_unreference(fb);
 
 	vfb = vmw_framebuffer_to_vfb(fb);
 	if (!vfb->dmabuf) {
 		DRM_ERROR("Framebuffer not dmabuf backed.\n");
 		ret = -EINVAL;
-		goto out_no_fb;
+		goto out_no_ttm_lock;
 	}
 
 	ret = ttm_read_lock(&vmaster->lock, true);
@@ -276,6 +273,7 @@ int vmw_present_readback_ioctl(struct drm_device *dev, void *data,
 
 	ttm_read_unlock(&vmaster->lock);
 out_no_ttm_lock:
+	drm_framebuffer_unreference(fb);
 out_no_fb:
 	drm_modeset_unlock_all(dev);
 out_no_copy:
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PATCH 31/35] drm: optimize drm_framebuffer_remove
  2013-01-10 20:47 [PATCH 00/36] kms locking rework Daniel Vetter
                   ` (29 preceding siblings ...)
  2013-01-10 20:48 ` [PATCH 30/35] drm/vmwgfx: add proper framebuffer refcounting Daniel Vetter
@ 2013-01-10 20:48 ` Daniel Vetter
  2013-01-10 20:48 ` [PATCH 32/35] drm: only grab the crtc lock for pageflips Daniel Vetter
                   ` (5 subsequent siblings)
  36 siblings, 0 replies; 45+ messages in thread
From: Daniel Vetter @ 2013-01-10 20:48 UTC (permalink / raw)
  To: DRI Development; +Cc: Daniel Vetter

Now that all framebuffer usage is properly refcounted, we are no
longer required to hold the modeset locks while dropping the last
reference. Hence implemented a fastpath which avoids the potential
stalls associated with grabbing mode_config.lock for the case where
there's no other reference around.

Explain in a big comment why it is safe. Also update kerneldocs with
the new locking rules around drm_framebuffer_remove.

Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 drivers/gpu/drm/drm_crtc.c |   72 +++++++++++++++++++++++++++-----------------
 1 file changed, 45 insertions(+), 27 deletions(-)

diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index 61adee6..1e238c1 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -517,7 +517,11 @@ EXPORT_SYMBOL(drm_framebuffer_cleanup);
  *
  * Scans all the CRTCs and planes in @dev's mode_config.  If they're
  * using @fb, removes it, setting it to NULL. Then drops the reference to the
- * passed-in framebuffer.
+ * passed-in framebuffer. Might take the modeset locks.
+ *
+ * Note that this function optimizes the cleanup away if the caller holds the
+ * last reference to the framebuffer. It is also guaranteed to not take the
+ * modeset locks in this case.
  */
 void drm_framebuffer_remove(struct drm_framebuffer *fb)
 {
@@ -527,33 +531,51 @@ void drm_framebuffer_remove(struct drm_framebuffer *fb)
 	struct drm_mode_set set;
 	int ret;
 
-	WARN_ON(!drm_modeset_is_locked(dev));
 	WARN_ON(!list_empty(&fb->filp_head));
 
-	/* remove from any CRTC */
-	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
-		if (crtc->fb == fb) {
-			/* should turn off the crtc */
-			memset(&set, 0, sizeof(struct drm_mode_set));
-			set.crtc = crtc;
-			set.fb = NULL;
-			ret = drm_mode_set_config_internal(&set);
-			if (ret)
-				DRM_ERROR("failed to reset crtc %p when fb was deleted\n", crtc);
+	/*
+	 * drm ABI mandates that we remove any deleted framebuffers from active
+	 * useage. But since most sane clients only remove framebuffers they no
+	 * longer need, try to optimize this away.
+	 *
+	 * Since we're holding a reference ourselves, observing a refcount of 1
+	 * means that we're the last holder and can skip it. Also, the refcount
+	 * can never increase from 1 again, so we don't need any barriers or
+	 * locks.
+	 *
+	 * Note that userspace could try to race with use and instate a new
+	 * usage _after_ we've cleared all current ones. End result will be an
+	 * in-use fb with fb-id == 0. Userspace is allowed to shoot its own foot
+	 * in this manner.
+	 */
+	if (atomic_read(&fb->refcount.refcount) > 1) {
+		drm_modeset_lock_all(dev);
+		/* remove from any CRTC */
+		list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+			if (crtc->fb == fb) {
+				/* should turn off the crtc */
+				memset(&set, 0, sizeof(struct drm_mode_set));
+				set.crtc = crtc;
+				set.fb = NULL;
+				ret = drm_mode_set_config_internal(&set);
+				if (ret)
+					DRM_ERROR("failed to reset crtc %p when fb was deleted\n", crtc);
+			}
 		}
-	}
 
-	list_for_each_entry(plane, &dev->mode_config.plane_list, head) {
-		if (plane->fb == fb) {
-			/* should turn off the crtc */
-			ret = plane->funcs->disable_plane(plane);
-			if (ret)
-				DRM_ERROR("failed to disable plane with busy fb\n");
-			/* disconnect the plane from the fb and crtc: */
-			__drm_framebuffer_unreference(plane->fb);
-			plane->fb = NULL;
-			plane->crtc = NULL;
+		list_for_each_entry(plane, &dev->mode_config.plane_list, head) {
+			if (plane->fb == fb) {
+				/* should turn off the crtc */
+				ret = plane->funcs->disable_plane(plane);
+				if (ret)
+					DRM_ERROR("failed to disable plane with busy fb\n");
+				/* disconnect the plane from the fb and crtc: */
+				__drm_framebuffer_unreference(plane->fb);
+				plane->fb = NULL;
+				plane->crtc = NULL;
+			}
 		}
+		drm_modeset_unlock_all(dev);
 	}
 
 	drm_framebuffer_unreference(fb);
@@ -2538,9 +2560,7 @@ int drm_mode_rmfb(struct drm_device *dev,
 	mutex_unlock(&dev->mode_config.fb_lock);
 	mutex_unlock(&file_priv->fbs_lock);
 
-	drm_modeset_lock_all(dev);
 	drm_framebuffer_remove(fb);
-	drm_modeset_unlock_all(dev);
 
 	return 0;
 
@@ -2691,9 +2711,7 @@ void drm_fb_release(struct drm_file *priv)
 		list_del_init(&fb->filp_head);
 
 		/* This will also drop the fpriv->fbs reference. */
-		drm_modeset_lock_all(dev);
 		drm_framebuffer_remove(fb);
-		drm_modeset_unlock_all(dev);
 	}
 	mutex_unlock(&priv->fbs_lock);
 }
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PATCH 32/35] drm: only grab the crtc lock for pageflips
  2013-01-10 20:47 [PATCH 00/36] kms locking rework Daniel Vetter
                   ` (30 preceding siblings ...)
  2013-01-10 20:48 ` [PATCH 31/35] drm: optimize drm_framebuffer_remove Daniel Vetter
@ 2013-01-10 20:48 ` Daniel Vetter
  2013-01-10 20:48 ` [PATCH 33/35] drm: don't hold crtc mutexes for connector ->detect callbacks Daniel Vetter
                   ` (4 subsequent siblings)
  36 siblings, 0 replies; 45+ messages in thread
From: Daniel Vetter @ 2013-01-10 20:48 UTC (permalink / raw)
  To: DRI Development; +Cc: Daniel Vetter

The pagelip ioctl itself is rather simply, so the hard work for this
patch is auditing all the drivers:

- exynos: Pageflip is protect with dev->struct_mutex and ...
  synchronous. But nothing fancy going on, besides a check whether the
  crtc is enabled, which should probably be somewhere in the drm core
  so that we have unified behaviour across all drivers.

- i915: hw-state is protected with dev->struct_mutex, the delayed
  unpin work together with the other stuff the pageflip complete irq
  handler needs is protected by the event_lock spinlock.

- nouveau: With the pin/unpin functions fixed, everything looks safe:
  A bit of ttm wrestling and refcounting, and a few channel accesses.
  The later are either already proteced sufficiently, or are now safe
  with the channel locking introduced to make cursor updates safe.

- radeon: The irq_get/put functions look a bit race, since the
  atomic_inc/dec isn't protect with locks. Otoh they're all per-crtc,
  so we should be safe with per-crtc locking from the drm core. Then
  there's tons of per-crtc register access, which could potentially go
  through the indirect reg acces. But that's fixed to make cursor
  updates concurrent. Bookeeping for the drm even is also protected
  with the even_lock, which also protects against the pageflip irq
  handler since radeon hw seems to have no way to queue these up
  asynchronously. Otherwise just a bit of ttm-based buffer handling
  and fencing, which is now safe with the previous patch to hold
  bdev->fence_lock while grabbing the ttm fence.

- shmob: Only one crtc. That's an easy one ...

- vmwgfx: As usual a bit special with tons different things:
  - Flippable check using is_implicit and num_implicit. Changes to
    those seem to be nicely covered with the global modeset lock, so
    we should be fine.
  - Some dirty cliprect handling stuff, or at least that is my guess.
    Looks like it's fine since either it's per-crtc, invariant or
    (like the execbuf stuff launched) protected otherwise.
  - Adding the actual flip to the fence_event list. On a quick look
    this seems to have solid locking in place, too.
  ... but generally this is all way over my head.

- imx: Impressive display of races between the page_flip
  implementation and the irq handler. Also, ipu_drm_set_base which
  gets eventually called from the irq handler to update the display
  base isn't really protected against concurrent set_config calls from
  process context.  In any case, going for per-crtc locking won't make
  this worse, so nothing to do.

- omap: Does just some prep work on per-crtc data and grabs a ref on
  the backing storage, then calls down into omap_gem_op_async which
  does some nicely-protected async callback stuff, or directly calls
  the passed-in page_flip_cb. That seems to lock most of the stuff it
  touches properly, safe for the eventually called omap_plane_dpms,
  which updates modeset state. Which will be a problem if this is
  called asynchronously, since the sync_op waiter callback code in
  omap_gem.c does not seem to take the right modeset locks. So looks a
  bit racy already with the old locking, and no worse off with the new
  per-crtc locks.

Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 drivers/gpu/drm/drm_crtc.c |    7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index 1e238c1..16ee864 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -3699,12 +3699,12 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev,
 	    page_flip->reserved != 0)
 		return -EINVAL;
 
-	drm_modeset_lock_all(dev);
 	obj = drm_mode_object_find(dev, page_flip->crtc_id, DRM_MODE_OBJECT_CRTC);
 	if (!obj)
-		goto out;
+		return -EINVAL;
 	crtc = obj_to_crtc(obj);
 
+	mutex_lock(&crtc->mutex);
 	if (crtc->fb == NULL) {
 		/* The framebuffer is currently unbound, presumably
 		 * due to a hotplug event, that userspace has not
@@ -3786,7 +3786,8 @@ out:
 		drm_framebuffer_unreference(fb);
 	if (old_fb)
 		drm_framebuffer_unreference(old_fb);
-	drm_modeset_unlock_all(dev);
+	mutex_unlock(&crtc->mutex);
+
 	return ret;
 }
 
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PATCH 33/35] drm: don't hold crtc mutexes for connector ->detect callbacks
  2013-01-10 20:47 [PATCH 00/36] kms locking rework Daniel Vetter
                   ` (31 preceding siblings ...)
  2013-01-10 20:48 ` [PATCH 32/35] drm: only grab the crtc lock for pageflips Daniel Vetter
@ 2013-01-10 20:48 ` Daniel Vetter
  2013-01-10 20:48 ` [PATCH 34/35] drm/doc: updates for new framebuffer lifetime rules Daniel Vetter
                   ` (3 subsequent siblings)
  36 siblings, 0 replies; 45+ messages in thread
From: Daniel Vetter @ 2013-01-10 20:48 UTC (permalink / raw)
  To: DRI Development; +Cc: Daniel Vetter

The coup de grace of the entire journey. No more dropped frames every
10s on my testbox!

I've tried to audit all ->detect and ->get_modes callbacks, but things
became a bit fuzzy after trying to piece together the umpteenth
implemenation. Afaict most drivers just have bog-standard output
register frobbing with a notch of i2c edid reading, nothing which
could potentially race with the newly concurrent pageflip/set_cursor
code. The big exception is load-detection code which requires a
running pipe, but radeon/nouveau seem to to this without touching any
state which can be observed from page_flip (e.g. disabled crtcs
temporarily getting enabled and so a pageflip succeeding).

The only special case I could find is the i915 load detect code. That
uses the normal modeset interface to enable the load-detect crtc, and
so userspace could try to squeeze in a pageflip on the load-detect
pipe. So we need to grab the relevant crtc mutex in there, to avoid
the temporary crtc enabling to sneak out and be visible to userspace.

Note that the sysfs files already stopped grabbing the per-crtc locks,
since I didn't want to bother with doing a interruptible
modeset_lock_all. But since there's very little in-between breakage
(essentially just the ability for userspace to pageflip on load-detect
crtcs when it shouldn't on the i915 driver) I figured I don't need to
bother.

Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 drivers/gpu/drm/drm_crtc.c           |    5 +++--
 drivers/gpu/drm/drm_crtc_helper.c    |    8 ++++----
 drivers/gpu/drm/i915/intel_display.c |   10 ++++++++--
 3 files changed, 15 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index 16ee864..8e4c574 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -1617,7 +1617,7 @@ int drm_mode_getconnector(struct drm_device *dev, void *data,
 
 	DRM_DEBUG_KMS("[CONNECTOR:%d:?]\n", out_resp->connector_id);
 
-	drm_modeset_lock_all(dev);
+	mutex_lock(&dev->mode_config.mutex);
 
 	obj = drm_mode_object_find(dev, out_resp->connector_id,
 				   DRM_MODE_OBJECT_CONNECTOR);
@@ -1714,7 +1714,8 @@ int drm_mode_getconnector(struct drm_device *dev, void *data,
 	out_resp->count_encoders = encoders_count;
 
 out:
-	drm_modeset_unlock_all(dev);
+	mutex_unlock(&dev->mode_config.mutex);
+
 	return ret;
 }
 
diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c
index 400ef86..7b2d378 100644
--- a/drivers/gpu/drm/drm_crtc_helper.c
+++ b/drivers/gpu/drm/drm_crtc_helper.c
@@ -980,7 +980,7 @@ static void output_poll_execute(struct work_struct *work)
 	if (!drm_kms_helper_poll)
 		return;
 
-	drm_modeset_lock_all(dev);
+	mutex_lock(&dev->mode_config.mutex);
 	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
 
 		/* Ignore forced connectors. */
@@ -1010,7 +1010,7 @@ static void output_poll_execute(struct work_struct *work)
 			changed = true;
 	}
 
-	drm_modeset_unlock_all(dev);
+	mutex_unlock(&dev->mode_config.mutex);
 
 	if (changed)
 		drm_kms_helper_hotplug_event(dev);
@@ -1070,7 +1070,7 @@ void drm_helper_hpd_irq_event(struct drm_device *dev)
 	if (!dev->mode_config.poll_enabled)
 		return;
 
-	drm_modeset_lock_all(dev);
+	mutex_lock(&dev->mode_config.mutex);
 	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
 
 		/* Only handle HPD capable connectors. */
@@ -1088,7 +1088,7 @@ void drm_helper_hpd_irq_event(struct drm_device *dev)
 			changed = true;
 	}
 
-	drm_modeset_unlock_all(dev);
+	mutex_unlock(&dev->mode_config.mutex);
 
 	if (changed)
 		drm_kms_helper_hotplug_event(dev);
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 06fbf3e..9095d41 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -6416,6 +6416,8 @@ bool intel_get_load_detect_pipe(struct drm_connector *connector,
 	if (encoder->crtc) {
 		crtc = encoder->crtc;
 
+		mutex_lock(&crtc->mutex);
+
 		old->dpms_mode = connector->dpms;
 		old->load_detect_temp = false;
 
@@ -6445,6 +6447,7 @@ bool intel_get_load_detect_pipe(struct drm_connector *connector,
 		return false;
 	}
 
+	mutex_lock(&crtc->mutex);
 	intel_encoder->new_crtc = to_intel_crtc(crtc);
 	to_intel_connector(connector)->new_encoder = intel_encoder;
 
@@ -6472,6 +6475,7 @@ bool intel_get_load_detect_pipe(struct drm_connector *connector,
 		DRM_DEBUG_KMS("reusing fbdev for load-detection framebuffer\n");
 	if (IS_ERR(fb)) {
 		DRM_DEBUG_KMS("failed to allocate framebuffer for load-detection\n");
+		mutex_unlock(&crtc->mutex);
 		return false;
 	}
 
@@ -6479,6 +6483,7 @@ bool intel_get_load_detect_pipe(struct drm_connector *connector,
 		DRM_DEBUG_KMS("failed to set mode on load-detect pipe\n");
 		if (old->release_fb)
 			old->release_fb->funcs->destroy(old->release_fb);
+		mutex_unlock(&crtc->mutex);
 		return false;
 	}
 
@@ -6493,14 +6498,13 @@ void intel_release_load_detect_pipe(struct drm_connector *connector,
 	struct intel_encoder *intel_encoder =
 		intel_attached_encoder(connector);
 	struct drm_encoder *encoder = &intel_encoder->base;
+	struct drm_crtc *crtc = encoder->crtc;
 
 	DRM_DEBUG_KMS("[CONNECTOR:%d:%s], [ENCODER:%d:%s]\n",
 		      connector->base.id, drm_get_connector_name(connector),
 		      encoder->base.id, drm_get_encoder_name(encoder));
 
 	if (old->load_detect_temp) {
-		struct drm_crtc *crtc = encoder->crtc;
-
 		to_intel_connector(connector)->new_encoder = NULL;
 		intel_encoder->new_crtc = NULL;
 		intel_set_mode(crtc, NULL, 0, 0, NULL);
@@ -6516,6 +6520,8 @@ void intel_release_load_detect_pipe(struct drm_connector *connector,
 	/* Switch crtc and encoder back off if necessary */
 	if (old->dpms_mode != DRM_MODE_DPMS_ON)
 		connector->funcs->dpms(connector, old->dpms_mode);
+
+	mutex_unlock(&crtc->mutex);
 }
 
 /* Returns the clock of the currently programmed mode of the given pipe. */
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PATCH 34/35] drm/doc: updates for new framebuffer lifetime rules
  2013-01-10 20:47 [PATCH 00/36] kms locking rework Daniel Vetter
                   ` (32 preceding siblings ...)
  2013-01-10 20:48 ` [PATCH 33/35] drm: don't hold crtc mutexes for connector ->detect callbacks Daniel Vetter
@ 2013-01-10 20:48 ` Daniel Vetter
  2013-01-10 20:48 ` [PATCH 35/35] drm/fb_helper: check whether fbcon is bound Daniel Vetter
                   ` (2 subsequent siblings)
  36 siblings, 0 replies; 45+ messages in thread
From: Daniel Vetter @ 2013-01-10 20:48 UTC (permalink / raw)
  To: DRI Development; +Cc: Daniel Vetter

Now that framebuffer are reference-counted for all use-sites, update
the documentation accordingly to stress the new rules for
initialization and teardown.

Also add a short paragraph about the implications for drivers of the
new locking rules.

Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 Documentation/DocBook/drm.tmpl |   59 ++++++++++++++++++++++++++++++----------
 1 file changed, 45 insertions(+), 14 deletions(-)

diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl
index caab791..6c11d77 100644
--- a/Documentation/DocBook/drm.tmpl
+++ b/Documentation/DocBook/drm.tmpl
@@ -978,10 +978,25 @@ int max_width, max_height;</synopsis>
         If the parameters are deemed valid, drivers then create, initialize and
         return an instance of struct <structname>drm_framebuffer</structname>.
         If desired the instance can be embedded in a larger driver-specific
-        structure. The new instance is initialized with a call to
-        <function>drm_framebuffer_init</function> which takes a pointer to DRM
-        frame buffer operations (struct
-        <structname>drm_framebuffer_funcs</structname>). Frame buffer operations are
+	structure. Drivers must fill its <structfield>width</structfield>,
+	<structfield>height</structfield>, <structfield>pitches</structfield>,
+        <structfield>offsets</structfield>, <structfield>depth</structfield>,
+        <structfield>bits_per_pixel</structfield> and
+        <structfield>pixel_format</structfield> fields from the values passed
+        through the <parameter>drm_mode_fb_cmd2</parameter> argument. They
+        should call the <function>drm_helper_mode_fill_fb_struct</function>
+        helper function to do so.
+      </para>
+
+      <para>
+	The initailization of the new framebuffer instance is finalized with a
+	call to <function>drm_framebuffer_init</function> which takes a pointer
+	to DRM frame buffer operations (struct
+	<structname>drm_framebuffer_funcs</structname>). Note that this function
+	publishes the framebuffer and so from this point on it can be accessed
+	concurrently from other threads. Hence it must be the last step in the
+	driver's framebuffer initialization sequence. Frame buffer operations
+	are
         <itemizedlist>
           <listitem>
             <synopsis>int (*create_handle)(struct drm_framebuffer *fb,
@@ -1022,16 +1037,16 @@ int max_width, max_height;</synopsis>
         </itemizedlist>
       </para>
       <para>
-        After initializing the <structname>drm_framebuffer</structname>
-        instance drivers must fill its <structfield>width</structfield>,
-        <structfield>height</structfield>, <structfield>pitches</structfield>,
-        <structfield>offsets</structfield>, <structfield>depth</structfield>,
-        <structfield>bits_per_pixel</structfield> and
-        <structfield>pixel_format</structfield> fields from the values passed
-        through the <parameter>drm_mode_fb_cmd2</parameter> argument. They
-        should call the <function>drm_helper_mode_fill_fb_struct</function>
-        helper function to do so.
-      </para>
+	The lifetime of a drm framebuffer is controlled with a reference count,
+	drivers can grab additional references with
+	<function>drm_framebuffer_reference</function> </para> and drop them
+	again with <function>drm_framebuffer_unreference</function>. For
+	driver-private framebuffers for which the last reference is never
+	dropped (e.g. for the fbdev framebuffer when the struct
+	<structname>drm_framebuffer</structname> is embedded into the fbdev
+	helper struct) drivers can manually clean up a framebuffer at module
+	unload time with
+	<function>drm_framebuffer_unregister_private</function>.
     </sect2>
     <sect2>
       <title>Output Polling</title>
@@ -1043,6 +1058,22 @@ int max_width, max_height;</synopsis>
         operation.
       </para>
     </sect2>
+    <sect2>
+      <title>Locking</title>
+      <para>
+        Beside some lookup structures with their own locking (which is hidden
+	behind the interface functions) most of the modeset state is protected
+	by the <code>dev-&lt;mode_config.lock</code> mutex and additionally
+	per-crtc locks to allow cursor updates, pageflips and similar operations
+	to occur concurrently with background tasks like output detection.
+	Operations which cross domains like a full modeset always grab all
+	locks. Drivers there need to protect resources shared between crtcs with
+	additional locking. They also need to be careful to always grab the
+	relevant crtc locks if a modset functions touches crtc state, e.g. for
+	load detection (which does only grab the <code>mode_config.lock</code>
+	to allow concurrent screen updates on live crtcs).
+      </para>
+    </sect2>
   </sect1>
 
   <!-- Internals: kms initialization and cleanup -->
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PATCH 35/35] drm/fb_helper: check whether fbcon is bound
  2013-01-10 20:47 [PATCH 00/36] kms locking rework Daniel Vetter
                   ` (33 preceding siblings ...)
  2013-01-10 20:48 ` [PATCH 34/35] drm/doc: updates for new framebuffer lifetime rules Daniel Vetter
@ 2013-01-10 20:48 ` Daniel Vetter
  2013-01-10 20:48 ` [PATCH 36/36] drm/i915: wake up all pageflip waiters Daniel Vetter
  2013-01-11 23:17 ` [PATCH 00/36] kms locking rework Rob Clark
  36 siblings, 0 replies; 45+ messages in thread
From: Daniel Vetter @ 2013-01-10 20:48 UTC (permalink / raw)
  To: DRI Development; +Cc: Daniel Vetter

We need to make sure that the fbcon is still bound when touching the
hw, since otherwise we might corrupt the modeset state of kms clients.
X mostly works around that with VT switching and setting the VT into
raw mode, which disables most fbcon events.

Raw kms test programs though don't do that dance, and in the future
we might want to aim to abolish CONFIG_VT anyway. So improve preventive
measures a bit. To do so, extract the existing logic for handling hotplug
events (which X can't block with the current set of tricks) and reuse
it for the fbdev blanking helper.

Long-term we really need to either scrap this all and only have a OOPS
console, or come up with a saner model for device ownership sharing
between fbdev/fbcon and kms userspace.

Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 drivers/gpu/drm/drm_fb_helper.c |   39 +++++++++++++++++++++++++++++----------
 1 file changed, 29 insertions(+), 10 deletions(-)

diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index be0f2d6..0c6e25e 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -305,6 +305,24 @@ void drm_fb_helper_restore(void)
 }
 EXPORT_SYMBOL(drm_fb_helper_restore);
 
+static bool drm_fb_helper_is_bound(struct drm_fb_helper *fb_helper)
+{
+	struct drm_device *dev = fb_helper->dev;
+	struct drm_crtc *crtc;
+	int bound = 0, crtcs_bound = 0;
+
+	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+		if (crtc->fb)
+			crtcs_bound++;
+		if (crtc->fb == fb_helper->fb)
+			bound++;
+	}
+
+	if (bound < crtcs_bound)
+		return false;
+	return true;
+}
+
 #ifdef CONFIG_MAGIC_SYSRQ
 static void drm_fb_helper_restore_work_fn(struct work_struct *ignored)
 {
@@ -338,6 +356,11 @@ static void drm_fb_helper_dpms(struct fb_info *info, int dpms_mode)
 	 * For each CRTC in this fb, turn the connectors on/off.
 	 */
 	drm_modeset_lock_all(dev);
+	if (!drm_fb_helper_is_bound(fb_helper)) {
+		drm_modeset_unlock_all(dev);
+		return;
+	}
+
 	for (i = 0; i < fb_helper->crtc_count; i++) {
 		crtc = fb_helper->crtc_info[i].mode_set.crtc;
 
@@ -702,6 +725,11 @@ int drm_fb_helper_pan_display(struct fb_var_screeninfo *var,
 	int i;
 
 	drm_modeset_lock_all(dev);
+	if (!drm_fb_helper_is_bound(fb_helper)) {
+		drm_modeset_unlock_all(dev);
+		return -EBUSY;
+	}
+
 	for (i = 0; i < fb_helper->crtc_count; i++) {
 		crtc = fb_helper->crtc_info[i].mode_set.crtc;
 
@@ -1369,21 +1397,12 @@ int drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper)
 	struct drm_device *dev = fb_helper->dev;
 	int count = 0;
 	u32 max_width, max_height, bpp_sel;
-	int bound = 0, crtcs_bound = 0;
-	struct drm_crtc *crtc;
 
 	if (!fb_helper->fb)
 		return 0;
 
 	drm_modeset_lock_all(dev);
-	list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
-		if (crtc->fb)
-			crtcs_bound++;
-		if (crtc->fb == fb_helper->fb)
-			bound++;
-	}
-
-	if (bound < crtcs_bound) {
+	if (!drm_fb_helper_is_bound(fb_helper)) {
 		fb_helper->delayed_hotplug = true;
 		drm_modeset_unlock_all(dev);
 		return 0;
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PATCH 36/36] drm/i915: wake up all pageflip waiters
  2013-01-10 20:47 [PATCH 00/36] kms locking rework Daniel Vetter
                   ` (34 preceding siblings ...)
  2013-01-10 20:48 ` [PATCH 35/35] drm/fb_helper: check whether fbcon is bound Daniel Vetter
@ 2013-01-10 20:48 ` Daniel Vetter
  2013-01-10 20:50   ` Daniel Vetter
  2013-01-11 23:17 ` [PATCH 00/36] kms locking rework Rob Clark
  36 siblings, 1 reply; 45+ messages in thread
From: Daniel Vetter @ 2013-01-10 20:48 UTC (permalink / raw)
  To: DRI Development; +Cc: Daniel Vetter

Otherwise it seems like we can get stuck with concurrent waiters.
Right now this /shouldn't/ be a problem, since all pending pageflip
waiters are serialized by the one mode_config.mutex, so there's at
most on waiter. But better paranoid than sorry, since this is tricky
code.

v2: WARN_ON(waitqueue_active) before waiting, as suggested by Chris
Wilson.

Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
---
 drivers/gpu/drm/i915/intel_display.c |    6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 9095d41..eb61fe9 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -2221,6 +2221,8 @@ intel_finish_fb(struct drm_framebuffer *old_fb)
 	bool was_interruptible = dev_priv->mm.interruptible;
 	int ret;
 
+	WARN_ON(waitqueue_active(&dev_priv->pending_flip_queue));
+
 	wait_event(dev_priv->pending_flip_queue,
 		   atomic_read(&dev_priv->mm.wedged) ||
 		   atomic_read(&obj->pending_flip) == 0);
@@ -2888,6 +2890,8 @@ static void intel_crtc_wait_for_pending_flips(struct drm_crtc *crtc)
 	if (crtc->fb == NULL)
 		return;
 
+	WARN_ON(waitqueue_active(&dev_priv->pending_flip_queue));
+
 	wait_event(dev_priv->pending_flip_queue,
 		   !intel_crtc_has_pending_flip(crtc));
 
@@ -6833,7 +6837,7 @@ static void do_intel_finish_page_flip(struct drm_device *dev,
 
 	obj = work->old_fb_obj;
 
-	wake_up(&dev_priv->pending_flip_queue);
+	wake_up_all(&dev_priv->pending_flip_queue);
 
 	queue_work(dev_priv->wq, &work->work);
 
-- 
1.7.10.4

^ permalink raw reply related	[flat|nested] 45+ messages in thread

* Re: [PATCH 36/36] drm/i915: wake up all pageflip waiters
  2013-01-10 20:48 ` [PATCH 36/36] drm/i915: wake up all pageflip waiters Daniel Vetter
@ 2013-01-10 20:50   ` Daniel Vetter
  0 siblings, 0 replies; 45+ messages in thread
From: Daniel Vetter @ 2013-01-10 20:50 UTC (permalink / raw)
  To: DRI Development; +Cc: Daniel Vetter

On Thu, Jan 10, 2013 at 9:48 PM, Daniel Vetter <daniel.vetter@ffwll.ch> wrote:
> Otherwise it seems like we can get stuck with concurrent waiters.
> Right now this /shouldn't/ be a problem, since all pending pageflip
> waiters are serialized by the one mode_config.mutex, so there's at
> most on waiter. But better paranoid than sorry, since this is tricky
> code.
>
> v2: WARN_ON(waitqueue_active) before waiting, as suggested by Chris
> Wilson.
>
> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>

Oops, this one is for i915 only, rather unrelated and merged already
anyway. Please disregard.
-Daniel
-- 
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH 12/35] drm/gma500: use drm_modeset_lock_all
  2013-01-10 20:47 ` [PATCH 12/35] drm/gma500: " Daniel Vetter
@ 2013-01-10 22:36   ` Alan Cox
  2013-01-11 13:25     ` Daniel Vetter
  0 siblings, 1 reply; 45+ messages in thread
From: Alan Cox @ 2013-01-10 22:36 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: DRI Development

On Thu, 10 Jan 2013 21:47:53 +0100
Daniel Vetter <daniel.vetter@ffwll.ch> wrote:

> Only two places:
> - suspend/resume
> - Some really strange mode validation tool with too much funny-lucking
>   hand-rolled conversion code.
> - The recently-added lastclose fbdev restore code.
> 
> Better safe than sorry, so convert both places to keep the locking
> semantics as much as possible.

Seems fine. The last close behaviour really ought to be in the core DRM
code. Telling people to discover magic incantations with sysrq is a total
fail, especially on tablets and other devices that don't *have* a sysrq
key.

Alan

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH 12/35] drm/gma500: use drm_modeset_lock_all
  2013-01-10 22:36   ` Alan Cox
@ 2013-01-11 13:25     ` Daniel Vetter
  0 siblings, 0 replies; 45+ messages in thread
From: Daniel Vetter @ 2013-01-11 13:25 UTC (permalink / raw)
  To: Alan Cox; +Cc: DRI Development

On Thu, Jan 10, 2013 at 11:36 PM, Alan Cox <alan@lxorguk.ukuu.org.uk> wrote:
> On Thu, 10 Jan 2013 21:47:53 +0100
> Daniel Vetter <daniel.vetter@ffwll.ch> wrote:
>
>> Only two places:
>> - suspend/resume
>> - Some really strange mode validation tool with too much funny-lucking
>>   hand-rolled conversion code.
>> - The recently-added lastclose fbdev restore code.
>>
>> Better safe than sorry, so convert both places to keep the locking
>> semantics as much as possible.
>
> Seems fine. The last close behaviour really ought to be in the core DRM
> code. Telling people to discover magic incantations with sysrq is a total
> fail, especially on tablets and other devices that don't *have* a sysrq
> key.

I've looked into doing that, but the fbdev emulation is an (optional)
driver internal detail. So I've opted for the 2nd best option and
unified the logic on all drivers that implement it - some (arm)
drivers don't even bother with this :(

I think the entire fbdev emulation vs native kms client stuff is ripe
for overhaul, see my other patch to prevent fbdev from causing havoc
with the i915 kernel testsuite.
-Daniel
-- 
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH 03/35] drm/<drivers>: reorder framebuffer init sequence
  2013-01-10 20:47 ` [PATCH 03/35] drm/<drivers>: reorder framebuffer init sequence Daniel Vetter
@ 2013-01-11 21:06   ` Rob Clark
  0 siblings, 0 replies; 45+ messages in thread
From: Rob Clark @ 2013-01-11 21:06 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: DRI Development

On Thu, Jan 10, 2013 at 2:47 PM, Daniel Vetter <daniel.vetter@ffwll.ch> wrote:
> With more fine-grained locking we can no longer rely on the big
> mode_config lock to prevent concurrent access to mode resources
> like framebuffers. Instead a framebuffer becomes accessible to
> other threads as soon as it is added to the relevant lookup
> structures. Hence it needs to be fully set up by the time drivers
> call drm_framebuffer_init.
>
> This patch here is the drivers part of that reorg. Nothing really fancy
> going on safe for three special cases.
>
> - exynos needs to be careful to properly unref all handles.
> - nouveau gets a resource leak fixed for free: one of the error
>   cases didn't cleanup the framebuffer, which is now moot since
>   the framebuffer is only registered once it is fully set up.
> - vmwgfx requires a slight reordering of operations, I'm hoping I didn't
>   break anything (but it's refcount management only, so should be safe).
>
> v2: Split out exynos, since it's a bit more hairy than expected.
>
> v3: Drop bogus cirrus hunk noticed by Richard Wilbur.
>
> v4: Split out vmwgfx since there's a small change in return values.
>
> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>

for the omapdrm part:

Reviewed-by: Rob Clark <rob@ti.com>

> ---
>  drivers/gpu/drm/ast/ast_main.c            |    4 ++--
>  drivers/gpu/drm/cirrus/cirrus_main.c      |    4 ++--
>  drivers/gpu/drm/drm_fb_cma_helper.c       |   10 +++++-----
>  drivers/gpu/drm/gma500/framebuffer.c      |    4 ++--
>  drivers/gpu/drm/i915/intel_display.c      |    5 +++--
>  drivers/gpu/drm/mgag200/mgag200_main.c    |    8 +++++---
>  drivers/gpu/drm/nouveau/nouveau_display.c |   10 +++++-----
>  drivers/gpu/drm/radeon/radeon_display.c   |    2 +-
>  drivers/gpu/drm/udl/udl_fb.c              |    2 +-
>  drivers/staging/omapdrm/omap_fb.c         |   16 ++++++++--------
>  10 files changed, 34 insertions(+), 31 deletions(-)
>
> diff --git a/drivers/gpu/drm/ast/ast_main.c b/drivers/gpu/drm/ast/ast_main.c
> index f668e6c..d5ba709 100644
> --- a/drivers/gpu/drm/ast/ast_main.c
> +++ b/drivers/gpu/drm/ast/ast_main.c
> @@ -266,13 +266,13 @@ int ast_framebuffer_init(struct drm_device *dev,
>  {
>         int ret;
>
> +       drm_helper_mode_fill_fb_struct(&ast_fb->base, mode_cmd);
> +       ast_fb->obj = obj;
>         ret = drm_framebuffer_init(dev, &ast_fb->base, &ast_fb_funcs);
>         if (ret) {
>                 DRM_ERROR("framebuffer init failed %d\n", ret);
>                 return ret;
>         }
> -       drm_helper_mode_fill_fb_struct(&ast_fb->base, mode_cmd);
> -       ast_fb->obj = obj;
>         return 0;
>  }
>
> diff --git a/drivers/gpu/drm/cirrus/cirrus_main.c b/drivers/gpu/drm/cirrus/cirrus_main.c
> index 6a9b12e..364474c 100644
> --- a/drivers/gpu/drm/cirrus/cirrus_main.c
> +++ b/drivers/gpu/drm/cirrus/cirrus_main.c
> @@ -42,13 +42,13 @@ int cirrus_framebuffer_init(struct drm_device *dev,
>  {
>         int ret;
>
> +       drm_helper_mode_fill_fb_struct(&gfb->base, mode_cmd);
> +       gfb->obj = obj;
>         ret = drm_framebuffer_init(dev, &gfb->base, &cirrus_fb_funcs);
>         if (ret) {
>                 DRM_ERROR("drm_framebuffer_init failed: %d\n", ret);
>                 return ret;
>         }
> -       drm_helper_mode_fill_fb_struct(&gfb->base, mode_cmd);
> -       gfb->obj = obj;
>         return 0;
>  }
>
> diff --git a/drivers/gpu/drm/drm_fb_cma_helper.c b/drivers/gpu/drm/drm_fb_cma_helper.c
> index fd9d0af..e1e0cb0 100644
> --- a/drivers/gpu/drm/drm_fb_cma_helper.c
> +++ b/drivers/gpu/drm/drm_fb_cma_helper.c
> @@ -85,6 +85,11 @@ static struct drm_fb_cma *drm_fb_cma_alloc(struct drm_device *dev,
>         if (!fb_cma)
>                 return ERR_PTR(-ENOMEM);
>
> +       drm_helper_mode_fill_fb_struct(&fb_cma->fb, mode_cmd);
> +
> +       for (i = 0; i < num_planes; i++)
> +               fb_cma->obj[i] = obj[i];
> +
>         ret = drm_framebuffer_init(dev, &fb_cma->fb, &drm_fb_cma_funcs);
>         if (ret) {
>                 dev_err(dev->dev, "Failed to initalize framebuffer: %d\n", ret);
> @@ -92,11 +97,6 @@ static struct drm_fb_cma *drm_fb_cma_alloc(struct drm_device *dev,
>                 return ERR_PTR(ret);
>         }
>
> -       drm_helper_mode_fill_fb_struct(&fb_cma->fb, mode_cmd);
> -
> -       for (i = 0; i < num_planes; i++)
> -               fb_cma->obj[i] = obj[i];
> -
>         return fb_cma;
>  }
>
> diff --git a/drivers/gpu/drm/gma500/framebuffer.c b/drivers/gpu/drm/gma500/framebuffer.c
> index afded54..38e7e75 100644
> --- a/drivers/gpu/drm/gma500/framebuffer.c
> +++ b/drivers/gpu/drm/gma500/framebuffer.c
> @@ -260,13 +260,13 @@ static int psb_framebuffer_init(struct drm_device *dev,
>         default:
>                 return -EINVAL;
>         }
> +       drm_helper_mode_fill_fb_struct(&fb->base, mode_cmd);
> +       fb->gtt = gt;
>         ret = drm_framebuffer_init(dev, &fb->base, &psb_fb_funcs);
>         if (ret) {
>                 dev_err(dev->dev, "framebuffer init failed: %d\n", ret);
>                 return ret;
>         }
> -       drm_helper_mode_fill_fb_struct(&fb->base, mode_cmd);
> -       fb->gtt = gt;
>         return 0;
>  }
>
> diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
> index cf0c713..b2af790 100644
> --- a/drivers/gpu/drm/i915/intel_display.c
> +++ b/drivers/gpu/drm/i915/intel_display.c
> @@ -8387,14 +8387,15 @@ int intel_framebuffer_init(struct drm_device *dev,
>         if (mode_cmd->offsets[0] != 0)
>                 return -EINVAL;
>
> +       drm_helper_mode_fill_fb_struct(&intel_fb->base, mode_cmd);
> +       intel_fb->obj = obj;
> +
>         ret = drm_framebuffer_init(dev, &intel_fb->base, &intel_fb_funcs);
>         if (ret) {
>                 DRM_ERROR("framebuffer init failed %d\n", ret);
>                 return ret;
>         }
>
> -       drm_helper_mode_fill_fb_struct(&intel_fb->base, mode_cmd);
> -       intel_fb->obj = obj;
>         return 0;
>  }
>
> diff --git a/drivers/gpu/drm/mgag200/mgag200_main.c b/drivers/gpu/drm/mgag200/mgag200_main.c
> index 70dd3c5..266438a 100644
> --- a/drivers/gpu/drm/mgag200/mgag200_main.c
> +++ b/drivers/gpu/drm/mgag200/mgag200_main.c
> @@ -40,13 +40,15 @@ int mgag200_framebuffer_init(struct drm_device *dev,
>                              struct drm_mode_fb_cmd2 *mode_cmd,
>                              struct drm_gem_object *obj)
>  {
> -       int ret = drm_framebuffer_init(dev, &gfb->base, &mga_fb_funcs);
> +       int ret;
> +
> +       drm_helper_mode_fill_fb_struct(&gfb->base, mode_cmd);
> +       gfb->obj = obj;
> +       ret = drm_framebuffer_init(dev, &gfb->base, &mga_fb_funcs);
>         if (ret) {
>                 DRM_ERROR("drm_framebuffer_init failed: %d\n", ret);
>                 return ret;
>         }
> -       drm_helper_mode_fill_fb_struct(&gfb->base, mode_cmd);
> -       gfb->obj = obj;
>         return 0;
>  }
>
> diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c
> index e4188f2..2591ff2 100644
> --- a/drivers/gpu/drm/nouveau/nouveau_display.c
> +++ b/drivers/gpu/drm/nouveau/nouveau_display.c
> @@ -78,11 +78,6 @@ nouveau_framebuffer_init(struct drm_device *dev,
>         struct drm_framebuffer *fb = &nv_fb->base;
>         int ret;
>
> -       ret = drm_framebuffer_init(dev, fb, &nouveau_framebuffer_funcs);
> -       if (ret) {
> -               return ret;
> -       }
> -
>         drm_helper_mode_fill_fb_struct(fb, mode_cmd);
>         nv_fb->nvbo = nvbo;
>
> @@ -125,6 +120,11 @@ nouveau_framebuffer_init(struct drm_device *dev,
>                 }
>         }
>
> +       ret = drm_framebuffer_init(dev, fb, &nouveau_framebuffer_funcs);
> +       if (ret) {
> +               return ret;
> +       }
> +
>         return 0;
>  }
>
> diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c
> index 1da2386..12ec3ef 100644
> --- a/drivers/gpu/drm/radeon/radeon_display.c
> +++ b/drivers/gpu/drm/radeon/radeon_display.c
> @@ -1089,12 +1089,12 @@ radeon_framebuffer_init(struct drm_device *dev,
>  {
>         int ret;
>         rfb->obj = obj;
> +       drm_helper_mode_fill_fb_struct(&rfb->base, mode_cmd);
>         ret = drm_framebuffer_init(dev, &rfb->base, &radeon_fb_funcs);
>         if (ret) {
>                 rfb->obj = NULL;
>                 return ret;
>         }
> -       drm_helper_mode_fill_fb_struct(&rfb->base, mode_cmd);
>         return 0;
>  }
>
> diff --git a/drivers/gpu/drm/udl/udl_fb.c b/drivers/gpu/drm/udl/udl_fb.c
> index d4ab3be..829c4a7 100644
> --- a/drivers/gpu/drm/udl/udl_fb.c
> +++ b/drivers/gpu/drm/udl/udl_fb.c
> @@ -435,8 +435,8 @@ udl_framebuffer_init(struct drm_device *dev,
>         int ret;
>
>         ufb->obj = obj;
> -       ret = drm_framebuffer_init(dev, &ufb->base, &udlfb_funcs);
>         drm_helper_mode_fill_fb_struct(&ufb->base, mode_cmd);
> +       ret = drm_framebuffer_init(dev, &ufb->base, &udlfb_funcs);
>         return ret;
>  }
>
> diff --git a/drivers/staging/omapdrm/omap_fb.c b/drivers/staging/omapdrm/omap_fb.c
> index 09028e9..bf6421f 100644
> --- a/drivers/staging/omapdrm/omap_fb.c
> +++ b/drivers/staging/omapdrm/omap_fb.c
> @@ -424,14 +424,6 @@ struct drm_framebuffer *omap_framebuffer_init(struct drm_device *dev,
>         }
>
>         fb = &omap_fb->base;
> -       ret = drm_framebuffer_init(dev, fb, &omap_framebuffer_funcs);
> -       if (ret) {
> -               dev_err(dev->dev, "framebuffer init failed: %d\n", ret);
> -               goto fail;
> -       }
> -
> -       DBG("create: FB ID: %d (%p)", fb->base.id, fb);
> -
>         omap_fb->format = format;
>
>         for (i = 0; i < n; i++) {
> @@ -462,6 +454,14 @@ struct drm_framebuffer *omap_framebuffer_init(struct drm_device *dev,
>
>         drm_helper_mode_fill_fb_struct(fb, mode_cmd);
>
> +       ret = drm_framebuffer_init(dev, fb, &omap_framebuffer_funcs);
> +       if (ret) {
> +               dev_err(dev->dev, "framebuffer init failed: %d\n", ret);
> +               goto fail;
> +       }
> +
> +       DBG("create: FB ID: %d (%p)", fb->base.id, fb);
> +
>         return fb;
>
>  fail:
> --
> 1.7.10.4
>
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH 29/35] drm/i915: dump refcount into framebuffer debugfs file
  2013-01-10 20:48 ` [PATCH 29/35] drm/i915: dump refcount into framebuffer debugfs file Daniel Vetter
@ 2013-01-11 22:20   ` Rob Clark
  0 siblings, 0 replies; 45+ messages in thread
From: Rob Clark @ 2013-01-11 22:20 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: DRI Development

On Thu, Jan 10, 2013 at 2:48 PM, Daniel Vetter <daniel.vetter@ffwll.ch> wrote:
> Useful for checking whether the new refcounting works as advertised.

looks useful.. I should probably add this to omapdrm and the cma
debugfs helper patch that I sent recently..

BR,
-R

> Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
> ---
>  drivers/gpu/drm/i915/i915_debugfs.c |   10 ++++++----
>  1 file changed, 6 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
> index 1269a46..7576e78 100644
> --- a/drivers/gpu/drm/i915/i915_debugfs.c
> +++ b/drivers/gpu/drm/i915/i915_debugfs.c
> @@ -1440,11 +1440,12 @@ static int i915_gem_framebuffer_info(struct seq_file *m, void *data)
>         ifbdev = dev_priv->fbdev;
>         fb = to_intel_framebuffer(ifbdev->helper.fb);
>
> -       seq_printf(m, "fbcon size: %d x %d, depth %d, %d bpp, obj ",
> +       seq_printf(m, "fbcon size: %d x %d, depth %d, %d bpp, refcount %d, obj ",
>                    fb->base.width,
>                    fb->base.height,
>                    fb->base.depth,
> -                  fb->base.bits_per_pixel);
> +                  fb->base.bits_per_pixel,
> +                  atomic_read(&fb->base.refcount.refcount));
>         describe_obj(m, fb->obj);
>         seq_printf(m, "\n");
>         mutex_unlock(&dev->mode_config.mutex);
> @@ -1454,11 +1455,12 @@ static int i915_gem_framebuffer_info(struct seq_file *m, void *data)
>                 if (&fb->base == ifbdev->helper.fb)
>                         continue;
>
> -               seq_printf(m, "user size: %d x %d, depth %d, %d bpp, obj ",
> +               seq_printf(m, "user size: %d x %d, depth %d, %d bpp, refcount %d, obj ",
>                            fb->base.width,
>                            fb->base.height,
>                            fb->base.depth,
> -                          fb->base.bits_per_pixel);
> +                          fb->base.bits_per_pixel,
> +                          atomic_read(&fb->base.refcount.refcount));
>                 describe_obj(m, fb->obj);
>                 seq_printf(m, "\n");
>         }
> --
> 1.7.10.4
>
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH 00/36] kms locking rework
  2013-01-10 20:47 [PATCH 00/36] kms locking rework Daniel Vetter
                   ` (35 preceding siblings ...)
  2013-01-10 20:48 ` [PATCH 36/36] drm/i915: wake up all pageflip waiters Daniel Vetter
@ 2013-01-11 23:17 ` Rob Clark
  36 siblings, 0 replies; 45+ messages in thread
From: Rob Clark @ 2013-01-11 23:17 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: DRI Development

On Thu, Jan 10, 2013 at 2:47 PM, Daniel Vetter <daniel.vetter@ffwll.ch> wrote:
> Hi all,
>
> Concurrent EDID reads and pageflips ftw!
>
> Changes since the rfc:
> - radeon/ttm/exynos prep patches/fixes merged.
> - arm driver patches at least compile-tested.
> - error handling fixed in a few cases, all spotted by Richard Wilbur,
> - radeon/nouveau tested on one card each, didn't blow up right away.
> - i-g-t extended to cover the corner-cases, seems to hold up.
> - DocBook updated as a new patch on top.
> - one more patch to teach the fb helpers manners and not interfere so much with
>   i-g-t tests.
>
> Imo this is ready for inclusion, so (especially driver maintainers) please
> review and test.

I've read through the series..  I'll have to make a few little updates
vs the dss/kms rewrite patch in omapdrm which should hopefully be
merged soon, but that shouldn't be a big deal.

Reviewed-by: Rob Clark <rob@ti.com>

> Yours, Daniel
>
> Daniel Vetter (35):
>   drm: review locking rules in drm_crtc.c
>   drm/doc: integrate drm_crtc.c kerneldoc
>   drm/<drivers>: reorder framebuffer init sequence
>   drm/vmwgfx: reorder framebuffer init sequence
>   drm/gma500: move fbcon restore to lastclose
>   drm/nouveau: protect evo_wait/evo_kick sections with a channel mutex
>   drm/nouveau: try to protect nbo->pin_refcount
>   drm/<drivers>: Unified handling of unimplemented fb->create_handle
>   drm: encapsulate crtc->set_config calls
>   drm: add drm_modeset_lock|unlock_all
>   drm/i915: use drm_modeset_lock_all
>   drm/gma500: use drm_modeset_lock_all
>   drm/ast: use drm_modeset_lock_all
>   drm/shmobile: use drm_modeset_lock_all
>   drm/vmgfx: use drm_modeset_lock_all
>   drm: add per-crtc locks
>   drm: only take the crtc lock for ->cursor_set
>   drm: only take the crtc lock for ->cursor_move
>   drm: revamp locking around fb creation/destruction
>   drm: create drm_framebuffer_lookup
>   drm: revamp framebuffer cleanup interfaces
>   drm: reference framebuffers which are on the idr
>   drm: nest modeset locks within fpriv->fbs_lock
>   drm: push modeset_lock_all into ->fb_create driver callbacks
>   drm: don't take modeset locks in getfb ioctl
>   drm: fb refcounting for dirtyfb_ioctl
>   drm: refcounting for sprite framebuffers
>   drm: refcounting for crtc framebuffers
>   drm/i915: dump refcount into framebuffer debugfs file
>   drm/vmwgfx: add proper framebuffer refcounting
>   drm: optimize drm_framebuffer_remove
>   drm: only grab the crtc lock for pageflips
>   drm: don't hold crtc mutexes for connector ->detect callbacks
>   drm/doc: updates for new framebuffer lifetime rules
>   drm/fb_helper: check whether fbcon is bound
>
>  Documentation/DocBook/drm.tmpl            |   63 ++-
>  drivers/gpu/drm/ast/ast_drv.c             |    4 +-
>  drivers/gpu/drm/ast/ast_drv.h             |    2 +
>  drivers/gpu/drm/ast/ast_fb.c              |    1 +
>  drivers/gpu/drm/ast/ast_main.c            |   12 +-
>  drivers/gpu/drm/cirrus/cirrus_fbdev.c     |    1 +
>  drivers/gpu/drm/cirrus/cirrus_main.c      |   12 +-
>  drivers/gpu/drm/drm_crtc.c                |  792 +++++++++++++++++------------
>  drivers/gpu/drm/drm_fb_cma_helper.c       |   15 +-
>  drivers/gpu/drm/drm_fb_helper.c           |   65 ++-
>  drivers/gpu/drm/drm_fops.c                |    1 +
>  drivers/gpu/drm/exynos/exynos_drm_fbdev.c |    4 +-
>  drivers/gpu/drm/gma500/framebuffer.c      |   29 +-
>  drivers/gpu/drm/gma500/psb_device.c       |    8 +-
>  drivers/gpu/drm/gma500/psb_drv.c          |   14 +-
>  drivers/gpu/drm/i2c/ch7006_drv.c          |    2 +-
>  drivers/gpu/drm/i915/i915_debugfs.c       |   15 +-
>  drivers/gpu/drm/i915/intel_display.c      |   21 +-
>  drivers/gpu/drm/i915/intel_dp.c           |    2 +
>  drivers/gpu/drm/i915/intel_fb.c           |    5 +-
>  drivers/gpu/drm/i915/intel_lvds.c         |    4 +-
>  drivers/gpu/drm/i915/intel_overlay.c      |   14 +-
>  drivers/gpu/drm/i915/intel_sprite.c       |    8 +-
>  drivers/gpu/drm/mgag200/mgag200_fb.c      |    1 +
>  drivers/gpu/drm/mgag200/mgag200_main.c    |   16 +-
>  drivers/gpu/drm/nouveau/nouveau_bo.c      |   22 +-
>  drivers/gpu/drm/nouveau/nouveau_bo.h      |    2 +
>  drivers/gpu/drm/nouveau/nouveau_display.c |   10 +-
>  drivers/gpu/drm/nouveau/nouveau_fbcon.c   |    1 +
>  drivers/gpu/drm/nouveau/nv04_display.c    |    2 +-
>  drivers/gpu/drm/nouveau/nv17_tv.c         |    2 +-
>  drivers/gpu/drm/nouveau/nv50_display.c    |   10 +
>  drivers/gpu/drm/radeon/radeon_cursor.c    |    8 +-
>  drivers/gpu/drm/radeon/radeon_display.c   |    2 +-
>  drivers/gpu/drm/radeon/radeon_fb.c        |    2 +
>  drivers/gpu/drm/shmobile/shmob_drm_drv.c  |    4 +-
>  drivers/gpu/drm/udl/udl_fb.c              |    4 +-
>  drivers/gpu/drm/vmwgfx/vmwgfx_drv.c       |    2 +-
>  drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c     |   38 +-
>  drivers/gpu/drm/vmwgfx/vmwgfx_kms.c       |   87 ++--
>  drivers/staging/omapdrm/omap_debugfs.c    |    2 +
>  drivers/staging/omapdrm/omap_fb.c         |   16 +-
>  drivers/staging/omapdrm/omap_fbdev.c      |    8 +-
>  include/drm/drmP.h                        |   13 +
>  include/drm/drm_crtc.h                    |   30 ++
>  45 files changed, 830 insertions(+), 546 deletions(-)
>
> --
> 1.7.10.4
>
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH 08/35] drm/<drivers>: Unified handling of unimplemented fb->create_handle
  2013-01-10 20:47 ` [PATCH 08/35] drm/<drivers>: Unified handling of unimplemented fb->create_handle Daniel Vetter
@ 2013-01-18 15:00   ` Thierry Reding
  2013-01-18 18:32     ` Daniel Vetter
  0 siblings, 1 reply; 45+ messages in thread
From: Thierry Reding @ 2013-01-18 15:00 UTC (permalink / raw)
  To: Daniel Vetter; +Cc: DRI Development


[-- Attachment #1.1: Type: text/plain, Size: 626 bytes --]

On Thu, Jan 10, 2013 at 09:47:49PM +0100, Daniel Vetter wrote:
[...]
> diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
> index 8d665fa..a9abf49 100644
> --- a/drivers/gpu/drm/drm_crtc.c
> +++ b/drivers/gpu/drm/drm_crtc.c
> @@ -2384,7 +2384,10 @@ int drm_mode_getfb(struct drm_device *dev,
>  	r->depth = fb->depth;
>  	r->bpp = fb->bits_per_pixel;
>  	r->pitch = fb->pitches[0];
> -	fb->funcs->create_handle(fb, file_priv, &r->handle);
> +	if (fb->funcs->create_handle)
> +		ret = fb->funcs->create_handle(fb, file_priv, &r->handle);
> +	else
> +		ret = -ENODEV;

Should this perhaps be -ENOSYS?

Thierry

[-- Attachment #1.2: Type: application/pgp-signature, Size: 836 bytes --]

[-- Attachment #2: Type: text/plain, Size: 159 bytes --]

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH 08/35] drm/<drivers>: Unified handling of unimplemented fb->create_handle
  2013-01-18 15:00   ` Thierry Reding
@ 2013-01-18 18:32     ` Daniel Vetter
  0 siblings, 0 replies; 45+ messages in thread
From: Daniel Vetter @ 2013-01-18 18:32 UTC (permalink / raw)
  To: Thierry Reding; +Cc: DRI Development

On Fri, Jan 18, 2013 at 4:00 PM, Thierry Reding
<thierry.reding@avionic-design.de> wrote:
> On Thu, Jan 10, 2013 at 09:47:49PM +0100, Daniel Vetter wrote:
> [...]
>> diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
>> index 8d665fa..a9abf49 100644
>> --- a/drivers/gpu/drm/drm_crtc.c
>> +++ b/drivers/gpu/drm/drm_crtc.c
>> @@ -2384,7 +2384,10 @@ int drm_mode_getfb(struct drm_device *dev,
>>       r->depth = fb->depth;
>>       r->bpp = fb->bits_per_pixel;
>>       r->pitch = fb->pitches[0];
>> -     fb->funcs->create_handle(fb, file_priv, &r->handle);
>> +     if (fb->funcs->create_handle)
>> +             ret = fb->funcs->create_handle(fb, file_priv, &r->handle);
>> +     else
>> +             ret = -ENODEV;
>
> Should this perhaps be -ENOSYS?

I tend to just randomly picked an errno which shouldn't ever show up
when using this ioctl on a driver which implements the callback. If
ENOSYS is the popular choice, I'll change it.
-Daniel
-- 
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 45+ messages in thread

end of thread, other threads:[~2013-01-18 18:32 UTC | newest]

Thread overview: 45+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-01-10 20:47 [PATCH 00/36] kms locking rework Daniel Vetter
2013-01-10 20:47 ` [PATCH 01/35] drm: review locking rules in drm_crtc.c Daniel Vetter
2013-01-10 20:47 ` [PATCH 02/35] drm/doc: integrate drm_crtc.c kerneldoc Daniel Vetter
2013-01-10 20:47 ` [PATCH 03/35] drm/<drivers>: reorder framebuffer init sequence Daniel Vetter
2013-01-11 21:06   ` Rob Clark
2013-01-10 20:47 ` [PATCH 04/35] drm/vmwgfx: " Daniel Vetter
2013-01-10 20:47 ` [PATCH 05/35] drm/gma500: move fbcon restore to lastclose Daniel Vetter
2013-01-10 20:47 ` [PATCH 06/35] drm/nouveau: protect evo_wait/evo_kick sections with a channel mutex Daniel Vetter
2013-01-10 20:47 ` [PATCH 07/35] drm/nouveau: try to protect nbo->pin_refcount Daniel Vetter
2013-01-10 20:47 ` [PATCH 08/35] drm/<drivers>: Unified handling of unimplemented fb->create_handle Daniel Vetter
2013-01-18 15:00   ` Thierry Reding
2013-01-18 18:32     ` Daniel Vetter
2013-01-10 20:47 ` [PATCH 09/35] drm: encapsulate crtc->set_config calls Daniel Vetter
2013-01-10 20:47 ` [PATCH 10/35] drm: add drm_modeset_lock|unlock_all Daniel Vetter
2013-01-10 20:47 ` [PATCH 11/35] drm/i915: use drm_modeset_lock_all Daniel Vetter
2013-01-10 20:47 ` [PATCH 12/35] drm/gma500: " Daniel Vetter
2013-01-10 22:36   ` Alan Cox
2013-01-11 13:25     ` Daniel Vetter
2013-01-10 20:47 ` [PATCH 13/35] drm/ast: " Daniel Vetter
2013-01-10 20:47 ` [PATCH 14/35] drm/shmobile: " Daniel Vetter
2013-01-10 20:47 ` [PATCH 15/35] drm/vmgfx: " Daniel Vetter
2013-01-10 20:47 ` [PATCH 16/35] drm: add per-crtc locks Daniel Vetter
2013-01-10 20:47 ` [PATCH 17/35] drm: only take the crtc lock for ->cursor_set Daniel Vetter
2013-01-10 20:47 ` [PATCH 18/35] drm: only take the crtc lock for ->cursor_move Daniel Vetter
2013-01-10 20:48 ` [PATCH 19/35] drm: revamp locking around fb creation/destruction Daniel Vetter
2013-01-10 20:48 ` [PATCH 20/35] drm: create drm_framebuffer_lookup Daniel Vetter
2013-01-10 20:48 ` [PATCH 21/35] drm: revamp framebuffer cleanup interfaces Daniel Vetter
2013-01-10 20:48 ` [PATCH 22/35] drm: reference framebuffers which are on the idr Daniel Vetter
2013-01-10 20:48 ` [PATCH 23/35] drm: nest modeset locks within fpriv->fbs_lock Daniel Vetter
2013-01-10 20:48 ` [PATCH 24/35] drm: push modeset_lock_all into ->fb_create driver callbacks Daniel Vetter
2013-01-10 20:48 ` [PATCH 25/35] drm: don't take modeset locks in getfb ioctl Daniel Vetter
2013-01-10 20:48 ` [PATCH 26/35] drm: fb refcounting for dirtyfb_ioctl Daniel Vetter
2013-01-10 20:48 ` [PATCH 27/35] drm: refcounting for sprite framebuffers Daniel Vetter
2013-01-10 20:48 ` [PATCH 28/35] drm: refcounting for crtc framebuffers Daniel Vetter
2013-01-10 20:48 ` [PATCH 29/35] drm/i915: dump refcount into framebuffer debugfs file Daniel Vetter
2013-01-11 22:20   ` Rob Clark
2013-01-10 20:48 ` [PATCH 30/35] drm/vmwgfx: add proper framebuffer refcounting Daniel Vetter
2013-01-10 20:48 ` [PATCH 31/35] drm: optimize drm_framebuffer_remove Daniel Vetter
2013-01-10 20:48 ` [PATCH 32/35] drm: only grab the crtc lock for pageflips Daniel Vetter
2013-01-10 20:48 ` [PATCH 33/35] drm: don't hold crtc mutexes for connector ->detect callbacks Daniel Vetter
2013-01-10 20:48 ` [PATCH 34/35] drm/doc: updates for new framebuffer lifetime rules Daniel Vetter
2013-01-10 20:48 ` [PATCH 35/35] drm/fb_helper: check whether fbcon is bound Daniel Vetter
2013-01-10 20:48 ` [PATCH 36/36] drm/i915: wake up all pageflip waiters Daniel Vetter
2013-01-10 20:50   ` Daniel Vetter
2013-01-11 23:17 ` [PATCH 00/36] kms locking rework Rob Clark

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).