From a4dba0b12713b4d048dbdf9c52732e23c62d4a3c Mon Sep 17 00:00:00 2001
From: Thomas Gleixner <tglx@linutronix.de>
Date: Mon, 20 Jun 2011 09:03:47 +0200
Subject: [PATCH 194/327] rt: Add local irq locks

Introduce locallock. For !RT this maps to preempt_disable()/
local_irq_disable() so there is not much that changes. For RT this will
map to a spinlock. This makes preemption possible and locked "ressource"
gets the lockdep anotation it wouldn't have otherwise. The locks are
recursive for owner == current. Also, all locks user migrate_disable()
which ensures that the task is not migrated to another CPU while the lock
is held and the owner is preempted.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
---
 include/linux/local_lock_internal.h | 111 ++++++++++++++++++++++++++--
 1 file changed, 103 insertions(+), 8 deletions(-)

diff --git a/include/linux/local_lock_internal.h b/include/linux/local_lock_internal.h
index 3f02b818625e..1b8ae034946f 100644
--- a/include/linux/local_lock_internal.h
+++ b/include/linux/local_lock_internal.h
@@ -7,13 +7,39 @@
 #include <linux/lockdep.h>
 
 typedef struct {
-#ifdef CONFIG_DEBUG_LOCK_ALLOC
+#ifdef CONFIG_PREEMPT_RT
+	spinlock_t              lock;
+	struct task_struct      *owner;
+	int                     nestcnt;
+
+#elif defined(CONFIG_DEBUG_LOCK_ALLOC)
 	struct lockdep_map	dep_map;
 	struct task_struct	*owner;
 #endif
 } local_lock_t;
 
-#ifdef CONFIG_DEBUG_LOCK_ALLOC
+#ifdef CONFIG_PREEMPT_RT
+
+#define INIT_LOCAL_LOCK(lockname)	{	\
+	__SPIN_LOCK_UNLOCKED((lockname).lock),	\
+	.owner		= NULL,			\
+	.nestcnt	= 0,			\
+	}
+
+static inline void ___local_lock_init(local_lock_t *l)
+{
+	l->owner = NULL;
+	l->nestcnt = 0;
+}
+
+#define __local_lock_init(l)					\
+do {								\
+	spin_lock_init(&(l)->lock);				\
+	___local_lock_init(l);					\
+} while (0)
+
+#elif defined(CONFIG_DEBUG_LOCK_ALLOC)
+
 # define LOCAL_LOCK_DEBUG_INIT(lockname)		\
 	.dep_map = {					\
 		.name = #lockname,			\
@@ -21,7 +47,33 @@ typedef struct {
 		.lock_type = LD_LOCK_PERCPU,		\
 	},						\
 	.owner = NULL,
+#endif
+
+#ifdef CONFIG_PREEMPT_RT
 
+static inline void local_lock_acquire(local_lock_t *l)
+{
+	if (l->owner != current) {
+		spin_lock(&l->lock);
+		DEBUG_LOCKS_WARN_ON(l->owner);
+		DEBUG_LOCKS_WARN_ON(l->nestcnt);
+		l->owner = current;
+	}
+	l->nestcnt++;
+}
+
+static inline void local_lock_release(local_lock_t *l)
+{
+	DEBUG_LOCKS_WARN_ON(l->nestcnt == 0);
+	DEBUG_LOCKS_WARN_ON(l->owner != current);
+	if (--l->nestcnt)
+		return;
+
+	l->owner = NULL;
+	spin_unlock(&l->lock);
+}
+
+#elif defined(CONFIG_DEBUG_LOCK_ALLOC)
 static inline void local_lock_acquire(local_lock_t *l)
 {
 	lock_map_acquire(&l->dep_map);
@@ -47,6 +99,47 @@ static inline void local_lock_release(local_lock_t *l) { }
 static inline void local_lock_debug_init(local_lock_t *l) { }
 #endif /* !CONFIG_DEBUG_LOCK_ALLOC */
 
+#ifdef CONFIG_PREEMPT_RT
+
+#define __local_lock(lock)					\
+	do {							\
+		migrate_disable();				\
+		local_lock_acquire(this_cpu_ptr(lock));		\
+	} while (0)
+
+#define __local_unlock(lock)					\
+	do {							\
+		local_lock_release(this_cpu_ptr(lock));		\
+		migrate_enable();				\
+	} while (0)
+
+#define __local_lock_irq(lock)					\
+	do {							\
+		migrate_disable();				\
+		local_lock_acquire(this_cpu_ptr(lock));		\
+	} while (0)
+
+#define __local_lock_irqsave(lock, flags)			\
+	do {							\
+		migrate_disable();				\
+		flags = 0;					\
+		local_lock_acquire(this_cpu_ptr(lock));		\
+	} while (0)
+
+#define __local_unlock_irq(lock)				\
+	do {							\
+		local_lock_release(this_cpu_ptr(lock));		\
+		migrate_enable();				\
+	} while (0)
+
+#define __local_unlock_irqrestore(lock, flags)			\
+	do {							\
+		local_lock_release(this_cpu_ptr(lock));		\
+		migrate_enable();				\
+	} while (0)
+
+#else
+
 #define INIT_LOCAL_LOCK(lockname)	{ LOCAL_LOCK_DEBUG_INIT(lockname) }
 
 #define __local_lock_init(lock)					\
@@ -66,6 +159,12 @@ do {								\
 		local_lock_acquire(this_cpu_ptr(lock));		\
 	} while (0)
 
+#define __local_unlock(lock)					\
+	do {							\
+		local_lock_release(this_cpu_ptr(lock));		\
+		preempt_enable();				\
+	} while (0)
+
 #define __local_lock_irq(lock)					\
 	do {							\
 		local_irq_disable();				\
@@ -78,12 +177,6 @@ do {								\
 		local_lock_acquire(this_cpu_ptr(lock));		\
 	} while (0)
 
-#define __local_unlock(lock)					\
-	do {							\
-		local_lock_release(this_cpu_ptr(lock));		\
-		preempt_enable();				\
-	} while (0)
-
 #define __local_unlock_irq(lock)				\
 	do {							\
 		local_lock_release(this_cpu_ptr(lock));		\
@@ -95,3 +188,5 @@ do {								\
 		local_lock_release(this_cpu_ptr(lock));		\
 		local_irq_restore(flags);			\
 	} while (0)
+
+#endif
-- 
2.49.0

