Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/cjb/mmc
[cris-mirror.git] / include / linux / lglock.h
blobf549056fb20bd5533555918cc1b1f9805c2cdcc3
1 /*
2 * Specialised local-global spinlock. Can only be declared as global variables
3 * to avoid overhead and keep things simple (and we don't want to start using
4 * these inside dynamically allocated structures).
6 * "local/global locks" (lglocks) can be used to:
8 * - Provide fast exclusive access to per-CPU data, with exclusive access to
9 * another CPU's data allowed but possibly subject to contention, and to
10 * provide very slow exclusive access to all per-CPU data.
11 * - Or to provide very fast and scalable read serialisation, and to provide
12 * very slow exclusive serialisation of data (not necessarily per-CPU data).
14 * Brlocks are also implemented as a short-hand notation for the latter use
15 * case.
17 * Copyright 2009, 2010, Nick Piggin, Novell Inc.
19 #ifndef __LINUX_LGLOCK_H
20 #define __LINUX_LGLOCK_H
22 #include <linux/spinlock.h>
23 #include <linux/lockdep.h>
24 #include <linux/percpu.h>
26 /* can make br locks by using local lock for read side, global lock for write */
27 #define br_lock_init(name) name##_lock_init()
28 #define br_read_lock(name) name##_local_lock()
29 #define br_read_unlock(name) name##_local_unlock()
30 #define br_write_lock(name) name##_global_lock_online()
31 #define br_write_unlock(name) name##_global_unlock_online()
33 #define DECLARE_BRLOCK(name) DECLARE_LGLOCK(name)
34 #define DEFINE_BRLOCK(name) DEFINE_LGLOCK(name)
37 #define lg_lock_init(name) name##_lock_init()
38 #define lg_local_lock(name) name##_local_lock()
39 #define lg_local_unlock(name) name##_local_unlock()
40 #define lg_local_lock_cpu(name, cpu) name##_local_lock_cpu(cpu)
41 #define lg_local_unlock_cpu(name, cpu) name##_local_unlock_cpu(cpu)
42 #define lg_global_lock(name) name##_global_lock()
43 #define lg_global_unlock(name) name##_global_unlock()
44 #define lg_global_lock_online(name) name##_global_lock_online()
45 #define lg_global_unlock_online(name) name##_global_unlock_online()
47 #ifdef CONFIG_DEBUG_LOCK_ALLOC
48 #define LOCKDEP_INIT_MAP lockdep_init_map
50 #define DEFINE_LGLOCK_LOCKDEP(name) \
51 struct lock_class_key name##_lock_key; \
52 struct lockdep_map name##_lock_dep_map; \
53 EXPORT_SYMBOL(name##_lock_dep_map)
55 #else
56 #define LOCKDEP_INIT_MAP(a, b, c, d)
58 #define DEFINE_LGLOCK_LOCKDEP(name)
59 #endif
62 #define DECLARE_LGLOCK(name) \
63 extern void name##_lock_init(void); \
64 extern void name##_local_lock(void); \
65 extern void name##_local_unlock(void); \
66 extern void name##_local_lock_cpu(int cpu); \
67 extern void name##_local_unlock_cpu(int cpu); \
68 extern void name##_global_lock(void); \
69 extern void name##_global_unlock(void); \
70 extern void name##_global_lock_online(void); \
71 extern void name##_global_unlock_online(void); \
73 #define DEFINE_LGLOCK(name) \
75 DEFINE_PER_CPU(arch_spinlock_t, name##_lock); \
76 DEFINE_LGLOCK_LOCKDEP(name); \
78 void name##_lock_init(void) { \
79 int i; \
80 LOCKDEP_INIT_MAP(&name##_lock_dep_map, #name, &name##_lock_key, 0); \
81 for_each_possible_cpu(i) { \
82 arch_spinlock_t *lock; \
83 lock = &per_cpu(name##_lock, i); \
84 *lock = (arch_spinlock_t)__ARCH_SPIN_LOCK_UNLOCKED; \
85 } \
86 } \
87 EXPORT_SYMBOL(name##_lock_init); \
89 void name##_local_lock(void) { \
90 arch_spinlock_t *lock; \
91 preempt_disable(); \
92 rwlock_acquire_read(&name##_lock_dep_map, 0, 0, _THIS_IP_); \
93 lock = &__get_cpu_var(name##_lock); \
94 arch_spin_lock(lock); \
95 } \
96 EXPORT_SYMBOL(name##_local_lock); \
98 void name##_local_unlock(void) { \
99 arch_spinlock_t *lock; \
100 rwlock_release(&name##_lock_dep_map, 1, _THIS_IP_); \
101 lock = &__get_cpu_var(name##_lock); \
102 arch_spin_unlock(lock); \
103 preempt_enable(); \
105 EXPORT_SYMBOL(name##_local_unlock); \
107 void name##_local_lock_cpu(int cpu) { \
108 arch_spinlock_t *lock; \
109 preempt_disable(); \
110 rwlock_acquire_read(&name##_lock_dep_map, 0, 0, _THIS_IP_); \
111 lock = &per_cpu(name##_lock, cpu); \
112 arch_spin_lock(lock); \
114 EXPORT_SYMBOL(name##_local_lock_cpu); \
116 void name##_local_unlock_cpu(int cpu) { \
117 arch_spinlock_t *lock; \
118 rwlock_release(&name##_lock_dep_map, 1, _THIS_IP_); \
119 lock = &per_cpu(name##_lock, cpu); \
120 arch_spin_unlock(lock); \
121 preempt_enable(); \
123 EXPORT_SYMBOL(name##_local_unlock_cpu); \
125 void name##_global_lock_online(void) { \
126 int i; \
127 preempt_disable(); \
128 rwlock_acquire(&name##_lock_dep_map, 0, 0, _RET_IP_); \
129 for_each_online_cpu(i) { \
130 arch_spinlock_t *lock; \
131 lock = &per_cpu(name##_lock, i); \
132 arch_spin_lock(lock); \
135 EXPORT_SYMBOL(name##_global_lock_online); \
137 void name##_global_unlock_online(void) { \
138 int i; \
139 rwlock_release(&name##_lock_dep_map, 1, _RET_IP_); \
140 for_each_online_cpu(i) { \
141 arch_spinlock_t *lock; \
142 lock = &per_cpu(name##_lock, i); \
143 arch_spin_unlock(lock); \
145 preempt_enable(); \
147 EXPORT_SYMBOL(name##_global_unlock_online); \
149 void name##_global_lock(void) { \
150 int i; \
151 preempt_disable(); \
152 rwlock_acquire(&name##_lock_dep_map, 0, 0, _RET_IP_); \
153 for_each_possible_cpu(i) { \
154 arch_spinlock_t *lock; \
155 lock = &per_cpu(name##_lock, i); \
156 arch_spin_lock(lock); \
159 EXPORT_SYMBOL(name##_global_lock); \
161 void name##_global_unlock(void) { \
162 int i; \
163 rwlock_release(&name##_lock_dep_map, 1, _RET_IP_); \
164 for_each_possible_cpu(i) { \
165 arch_spinlock_t *lock; \
166 lock = &per_cpu(name##_lock, i); \
167 arch_spin_unlock(lock); \
169 preempt_enable(); \
171 EXPORT_SYMBOL(name##_global_unlock);
172 #endif