[PATCH 2/2] Revert "v2 (Daniel):"

Daniel Vetter daniel.vetter at ffwll.ch
Thu May 29 05:59:50 PDT 2014


This should be squashed into the relevant later patches that start to
use this.

Signed-off-by: Daniel Vetter <daniel.vetter at ffwll.ch>
---
 drivers/gpu/drm/drm_crtc.c           |  4 +-
 drivers/gpu/drm/drm_modeset_lock.c   | 72 ++++++++++++++++++++++++------------
 drivers/gpu/drm/i915/intel_display.c |  3 +-
 include/drm/drm_modeset_lock.h       | 41 +++++++++++++++++++-
 include/uapi/drm/drm_mode.h          |  3 ++
 5 files changed, 95 insertions(+), 28 deletions(-)

diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index 9e826aa5fc5c..cf622f6de07c 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -39,7 +39,6 @@
 #include <drm/drm_fourcc.h>
 #include <drm/drm_modeset_lock.h>
 
-#include "drm_crtc_internal.h"
 
 /**
  * drm_modeset_lock_all - take all modeset locks
@@ -61,7 +60,7 @@ void drm_modeset_lock_all(struct drm_device *dev)
 
 	mutex_lock(&config->mutex);
 
-	drm_modeset_acquire_init(ctx);
+	drm_modeset_acquire_init(ctx, false, false);
 
 retry:
 	ret = drm_modeset_lock(&config->connection_mutex, ctx);
@@ -106,6 +105,7 @@ void drm_modeset_unlock_all(struct drm_device *dev)
 
 	config->acquire_ctx = NULL;
 	drm_modeset_drop_locks(ctx);
+	ww_acquire_fini(&ctx->ww_ctx);
 	drm_modeset_acquire_fini(ctx);
 
 	kfree(ctx);
diff --git a/drivers/gpu/drm/drm_modeset_lock.c b/drivers/gpu/drm/drm_modeset_lock.c
index 81607ccebd89..6580d6ce8f63 100644
--- a/drivers/gpu/drm/drm_modeset_lock.c
+++ b/drivers/gpu/drm/drm_modeset_lock.c
@@ -26,21 +26,32 @@
 #include <drm/drm_modeset_lock.h>
 
 
-void drm_modeset_acquire_init(struct drm_modeset_acquire_ctx *ctx)
+void drm_modeset_acquire_init(struct drm_modeset_acquire_ctx *ctx,
+		bool nolock, bool nonblock)
 {
 	ww_acquire_init(&ctx->ww_ctx, &crtc_ww_class);
 	INIT_LIST_HEAD(&ctx->locked);
+	mutex_init(&ctx->mutex);
+	ctx->nolock = nolock;
+	ctx->nonblock = nonblock;
 }
 EXPORT_SYMBOL(drm_modeset_acquire_init);
 
 void drm_modeset_acquire_fini(struct drm_modeset_acquire_ctx *ctx)
 {
-	ww_acquire_fini(&ctx->ww_ctx);
+	WARN_ON(ctx->contended);
+	/*
+	 * NOTE: it is intentional that ww_acquire_fini() is not called
+	 * here.. due to the way lock handover works in drm_atomic
+	 */
+	mutex_destroy(&ctx->mutex);
 }
 EXPORT_SYMBOL(drm_modeset_acquire_fini);
 
 void drm_modeset_drop_locks(struct drm_modeset_acquire_ctx *ctx)
 {
+	WARN_ON(ctx->contended);
+	mutex_lock(&ctx->mutex);
 	while (!list_empty(&ctx->locked)) {
 		struct drm_modeset_lock *lock;
 
@@ -49,31 +60,45 @@ void drm_modeset_drop_locks(struct drm_modeset_acquire_ctx *ctx)
 
 		drm_modeset_unlock(lock);
 	}
+	mutex_unlock(&ctx->mutex);
 }
 EXPORT_SYMBOL(drm_modeset_drop_locks);
 
 static int modeset_lock(struct drm_modeset_lock *lock,
-			struct drm_modeset_acquire_ctx *ctx,
-			bool interruptible)
+		struct drm_modeset_acquire_ctx *ctx,
+		bool interruptible, bool slow)
 {
 	int ret;
 
+	if (ctx->nolock)
+		return 0;
+
+	WARN_ON(ctx->frozen);    /* all locks should be held by now! */
+	WARN_ON(ctx->contended);
+
+retry:
 	if (interruptible) {
 		ret = ww_mutex_lock_interruptible(&lock->mutex, &ctx->ww_ctx);
+	} else if (slow) {
+		ww_mutex_lock_slow(&lock->mutex, &ctx->ww_ctx);
+		ret = 0;
 	} else {
 		ret = ww_mutex_lock(&lock->mutex, &ctx->ww_ctx);
 	}
-
-	if (ret == 0) {
+	if (!ret) {
+		if (lock->atomic_pending) {
+			/* some other pending update with dropped locks */
+			ww_mutex_unlock(&lock->mutex);
+			if (ctx->nonblock)
+				return -EBUSY;
+			wait_event(lock->event, !lock->atomic_pending);
+			goto retry;
+		}
+		lock->atomic_pending = true;
+		WARN_ON(!list_empty(&lock->head));
 		list_add(&lock->head, &ctx->locked);
 	} else if (ret == -EALREADY) {
-		/*
-		 * We already hold the lock. This is only fine if it's the lock
-		 * we've contended on.
-		 */
-		WARN_ON(ctx->contended != lock);
-		ctx->contended = NULL;
-
+		/* we already hold the lock.. this is fine */
 		ret = 0;
 	} else if (ret == -EDEADLK) {
 		ctx->contended = lock;
@@ -84,19 +109,18 @@ static int modeset_lock(struct drm_modeset_lock *lock,
 
 void drm_modeset_backoff(struct drm_modeset_acquire_ctx *ctx)
 {
-	drm_modeset_drop_locks(ctx);
+	struct drm_modeset_lock *contended = ctx->contended;
 
-	ww_mutex_lock_slow(&ctx->contended->mutex, ctx);
-}
-EXPORT_SYMBOL(drm_modeset_backoff);
+	ctx->contended = NULL;
+
+	if (WARN_ON(!contended))
+		return;
 
-void drm_modeset_backoff_interruptible(struct drm_modeset_acquire_ctx *ctx)
-{
 	drm_modeset_drop_locks(ctx);
 
-	ww_mutex_lock_slow(&ctx->contended->mutex, ctx);
+	modeset_lock(contended, ctx, false, true);
 }
-EXPORT_SYMBOL(drm_modeset_backoff_interruptible);
+EXPORT_SYMBOL(drm_modeset_backoff);
 
 /**
  * drm_modeset_lock - take modeset lock
@@ -112,7 +136,7 @@ int drm_modeset_lock(struct drm_modeset_lock *lock,
 		struct drm_modeset_acquire_ctx *ctx)
 {
 	if (ctx)
-		return modeset_lock(lock, ctx, false);
+		return modeset_lock(lock, ctx, false, false);
 
 	ww_mutex_lock(&lock->mutex, NULL);
 	return 0;
@@ -123,7 +147,7 @@ int drm_modeset_lock_interruptible(struct drm_modeset_lock *lock,
 		struct drm_modeset_acquire_ctx *ctx)
 {
 	if (ctx)
-		return modeset_lock(lock, ctx, true);
+		return modeset_lock(lock, ctx, true, false);
 
 	return ww_mutex_lock_interruptible(&lock->mutex, NULL);
 }
@@ -136,7 +160,9 @@ EXPORT_SYMBOL(drm_modeset_lock_interruptible);
 void drm_modeset_unlock(struct drm_modeset_lock *lock)
 {
 	list_del_init(&lock->head);
+	lock->atomic_pending = false;
 	ww_mutex_unlock(&lock->mutex);
+	wake_up_all(&lock->event);
 }
 EXPORT_SYMBOL(drm_modeset_unlock);
 
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 9d12e3e15dfa..ba6cbbbfe596 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -7990,7 +7990,7 @@ bool intel_get_load_detect_pipe(struct drm_connector *connector,
 		      connector->base.id, drm_get_connector_name(connector),
 		      encoder->base.id, drm_get_encoder_name(encoder));
 
-	drm_modeset_acquire_init(ctx);
+	drm_modeset_acquire_init(ctx, false, false);
 
 retry:
 	ret = drm_modeset_lock(&config->connection_mutex, ctx);
@@ -8103,6 +8103,7 @@ fail_unlock:
 	}
 
 	drm_modeset_drop_locks(ctx);
+	ww_acquire_fini(&ctx->ww_ctx);
 	drm_modeset_acquire_fini(ctx);
 
 	return false;
diff --git a/include/drm/drm_modeset_lock.h b/include/drm/drm_modeset_lock.h
index e67fb815b610..2630da3ef1b4 100644
--- a/include/drm/drm_modeset_lock.h
+++ b/include/drm/drm_modeset_lock.h
@@ -32,6 +32,15 @@ struct drm_modeset_acquire_ctx {
 
 	struct ww_acquire_ctx ww_ctx;
 
+	bool nolock : 1;
+	bool nonblock : 1;
+
+	/* just for debugging, the context is 'frozen' in drm_atomic_check()
+	 * to catch anyone who might be trying to acquire a lock after it is
+	 * too late.
+	 */
+	bool frozen : 1;
+
 	/* contended lock: if a lock is contended you should only call
 	 * drm_modeset_backoff() which drops locks and slow-locks the
 	 * contended lock.
@@ -40,6 +49,16 @@ struct drm_modeset_acquire_ctx {
 
 	/* list of 'struct drm_modeset_lock': */
 	struct list_head locked;
+
+	/* currently simply for protecting against 'locked' list manipulation
+	 * between original thread calling atomic->end() and driver thread
+	 * calling back drm_atomic_commit_unlocked().
+	 *
+	 * Other spots are sufficiently synchronized by virtue of holding
+	 * the lock's ww_mutex.  But during the lock/resource hand-over to the
+	 * driver thread (drop_locks()/grab_locks()), we cannot rely on this.
+	 */
+	struct mutex mutex;
 };
 
 /**
@@ -59,24 +78,42 @@ struct drm_modeset_lock {
 	struct ww_mutex mutex;
 
 	/**
+	 * Are we busy (pending asynchronous/NONBLOCK update)?  Any further
+	 * asynchronous update will return -EBUSY if it also needs to acquire
+	 * this lock.  While a synchronous update will block until the pending
+	 * async update completes.
+	 *
+	 * Drivers must ensure the update is completed before sending vblank
+	 * event to userspace.  Typically this just means don't send event
+	 * before drm_atomic_commit_unlocked() returns.
+	 */
+	bool atomic_pending;
+
+	/**
 	 * Resources that are locked as part of an atomic update are added
 	 * to a list (so we know what to unlock at the end).
 	 */
 	struct list_head head;
+
+	/**
+	 * For waiting on atomic_pending locks, if not a NONBLOCK operation.
+	 */
+	wait_queue_head_t event;
 };
 
 extern struct ww_class crtc_ww_class;
 
-void drm_modeset_acquire_init(struct drm_modeset_acquire_ctx *ctx);
+void drm_modeset_acquire_init(struct drm_modeset_acquire_ctx *ctx,
+		bool nolock, bool nonblock);
 void drm_modeset_acquire_fini(struct drm_modeset_acquire_ctx *ctx);
 void drm_modeset_drop_locks(struct drm_modeset_acquire_ctx *ctx);
 void drm_modeset_backoff(struct drm_modeset_acquire_ctx *ctx);
-void drm_modeset_backoff_interruptible(struct drm_modeset_acquire_ctx *ctx);
 
 static inline void drm_modeset_lock_init(struct drm_modeset_lock *lock)
 {
 	ww_mutex_init(&lock->mutex, &crtc_ww_class);
 	INIT_LIST_HEAD(&lock->head);
+	init_waitqueue_head(&lock->event);
 }
 
 static inline void drm_modeset_lock_fini(struct drm_modeset_lock *lock)
diff --git a/include/uapi/drm/drm_mode.h b/include/uapi/drm/drm_mode.h
index ded505ede145..6421edcd27a8 100644
--- a/include/uapi/drm/drm_mode.h
+++ b/include/uapi/drm/drm_mode.h
@@ -511,4 +511,7 @@ struct drm_mode_destroy_dumb {
 	uint32_t handle;
 };
 
+#define DRM_MODE_ATOMIC_NONBLOCK  0x0200
+#define DRM_MODE_ATOMIC_NOLOCK    0x8000  /* only used internally */
+
 #endif
-- 
1.9.2



More information about the dri-devel mailing list