blob: 324329313af8db5b4ea9b235d191307f4e4d7ce2 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001#ifndef __ASM_SPINLOCK_H
2#define __ASM_SPINLOCK_H
3
4#include <asm/atomic.h>
5#include <asm/rwlock.h>
6#include <asm/page.h>
Andi Kleenfb2e2842006-09-26 10:52:32 +02007#include <asm/processor.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -07008#include <linux/compiler.h>
9
Linus Torvalds1da177e2005-04-16 15:20:36 -070010/*
11 * Your basic SMP spinlocks, allowing only a single CPU anywhere
Ingo Molnarfb1c8f92005-09-10 00:25:56 -070012 *
Linus Torvalds1da177e2005-04-16 15:20:36 -070013 * Simple spin lock operations. There are two variants, one clears IRQ's
14 * on the local processor, one does not.
15 *
16 * We make no fairness assumptions. They have a cost.
Ingo Molnarfb1c8f92005-09-10 00:25:56 -070017 *
18 * (the type definitions are in asm/spinlock_types.h)
Linus Torvalds1da177e2005-04-16 15:20:36 -070019 */
20
Andi Kleenfb2e2842006-09-26 10:52:32 +020021static inline int __raw_spin_is_locked(raw_spinlock_t *x)
22{
23 return *(volatile signed char *)(&(x)->slock) <= 0;
24}
Linus Torvalds1da177e2005-04-16 15:20:36 -070025
Ingo Molnarfb1c8f92005-09-10 00:25:56 -070026static inline void __raw_spin_lock(raw_spinlock_t *lock)
Linus Torvalds1da177e2005-04-16 15:20:36 -070027{
Andi Kleenfb2e2842006-09-26 10:52:32 +020028 asm volatile("\n1:\t"
29 LOCK_PREFIX " ; decb %0\n\t"
30 "jns 3f\n"
31 "2:\t"
32 "rep;nop\n\t"
33 "cmpb $0,%0\n\t"
34 "jle 2b\n\t"
35 "jmp 1b\n"
36 "3:\n\t"
37 : "+m" (lock->slock) : : "memory");
Linus Torvalds1da177e2005-04-16 15:20:36 -070038}
39
Ingo Molnar8a25d5d2006-07-03 00:24:54 -070040/*
41 * It is easier for the lock validator if interrupts are not re-enabled
42 * in the middle of a lock-acquire. This is a performance feature anyway
43 * so we turn it off:
Andi Kleenfb2e2842006-09-26 10:52:32 +020044 *
45 * NOTE: there's an irqs-on section here, which normally would have to be
46 * irq-traced, but on CONFIG_TRACE_IRQFLAGS we never use this variant.
Ingo Molnar8a25d5d2006-07-03 00:24:54 -070047 */
48#ifndef CONFIG_PROVE_LOCKING
Ingo Molnarfb1c8f92005-09-10 00:25:56 -070049static inline void __raw_spin_lock_flags(raw_spinlock_t *lock, unsigned long flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -070050{
Andi Kleenfb2e2842006-09-26 10:52:32 +020051 asm volatile(
52 "\n1:\t"
53 LOCK_PREFIX " ; decb %0\n\t"
54 "jns 5f\n"
55 "2:\t"
56 "testl $0x200, %1\n\t"
57 "jz 4f\n\t"
58 "sti\n"
59 "3:\t"
60 "rep;nop\n\t"
61 "cmpb $0, %0\n\t"
62 "jle 3b\n\t"
63 "cli\n\t"
64 "jmp 1b\n"
65 "4:\t"
66 "rep;nop\n\t"
67 "cmpb $0, %0\n\t"
68 "jg 1b\n\t"
69 "jmp 4b\n"
70 "5:\n\t"
71 : "+m" (lock->slock) : "r" (flags) : "memory");
Linus Torvalds1da177e2005-04-16 15:20:36 -070072}
Ingo Molnar8a25d5d2006-07-03 00:24:54 -070073#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -070074
Ingo Molnarfb1c8f92005-09-10 00:25:56 -070075static inline int __raw_spin_trylock(raw_spinlock_t *lock)
Linus Torvalds1da177e2005-04-16 15:20:36 -070076{
77 char oldval;
Andi Kleenfb2e2842006-09-26 10:52:32 +020078 asm volatile(
Linus Torvalds1da177e2005-04-16 15:20:36 -070079 "xchgb %b0,%1"
Linus Torvaldsb862f3b2006-07-08 15:24:18 -070080 :"=q" (oldval), "+m" (lock->slock)
Linus Torvalds1da177e2005-04-16 15:20:36 -070081 :"0" (0) : "memory");
82 return oldval > 0;
83}
84
Ingo Molnarfb1c8f92005-09-10 00:25:56 -070085/*
86 * __raw_spin_unlock based on writing $1 to the low byte.
87 * This method works. Despite all the confusion.
88 * (except on PPro SMP or if we are using OOSTORE, so we use xchgb there)
89 * (PPro errata 66, 92)
90 */
91
92#if !defined(CONFIG_X86_OOSTORE) && !defined(CONFIG_X86_PPRO_FENCE)
93
Ingo Molnarfb1c8f92005-09-10 00:25:56 -070094static inline void __raw_spin_unlock(raw_spinlock_t *lock)
Linus Torvalds1da177e2005-04-16 15:20:36 -070095{
Andi Kleenfb2e2842006-09-26 10:52:32 +020096 asm volatile("movb $1,%0" : "+m" (lock->slock) :: "memory");
Linus Torvalds1da177e2005-04-16 15:20:36 -070097}
98
Ingo Molnarfb1c8f92005-09-10 00:25:56 -070099#else
100
Ingo Molnarfb1c8f92005-09-10 00:25:56 -0700101static inline void __raw_spin_unlock(raw_spinlock_t *lock)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700102{
Ingo Molnarfb1c8f92005-09-10 00:25:56 -0700103 char oldval = 1;
104
Andi Kleenfb2e2842006-09-26 10:52:32 +0200105 asm volatile("xchgb %b0, %1"
106 : "=q" (oldval), "+m" (lock->slock)
107 : "0" (oldval) : "memory");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700108}
109
Ingo Molnarfb1c8f92005-09-10 00:25:56 -0700110#endif
111
Andi Kleenfb2e2842006-09-26 10:52:32 +0200112static inline void __raw_spin_unlock_wait(raw_spinlock_t *lock)
113{
114 while (__raw_spin_is_locked(lock))
115 cpu_relax();
116}
Ingo Molnarfb1c8f92005-09-10 00:25:56 -0700117
Linus Torvalds1da177e2005-04-16 15:20:36 -0700118/*
119 * Read-write spinlocks, allowing multiple readers
120 * but only one writer.
121 *
122 * NOTE! it is quite common to have readers in interrupts
123 * but no interrupt writers. For those circumstances we
124 * can "mix" irq-safe locks - any writer needs to get a
125 * irq-safe write-lock, but readers can get non-irqsafe
126 * read-locks.
Ingo Molnarfb1c8f92005-09-10 00:25:56 -0700127 *
Linus Torvalds1da177e2005-04-16 15:20:36 -0700128 * On x86, we implement read-write locks as a 32-bit counter
129 * with the high bit (sign) being the "contended" bit.
130 *
131 * The inline assembly is non-obvious. Think about it.
132 *
133 * Changed to use the same technique as rw semaphores. See
134 * semaphore.h for details. -ben
Ingo Molnarfb1c8f92005-09-10 00:25:56 -0700135 *
136 * the helpers are in arch/i386/kernel/semaphore.c
Linus Torvalds1da177e2005-04-16 15:20:36 -0700137 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700138
Ingo Molnarfb1c8f92005-09-10 00:25:56 -0700139/**
140 * read_can_lock - would read_trylock() succeed?
141 * @lock: the rwlock in question.
142 */
Andi Kleenfb2e2842006-09-26 10:52:32 +0200143static inline int __raw_read_can_lock(raw_rwlock_t *x)
144{
145 return (int)(x)->lock > 0;
146}
Ingo Molnarfb1c8f92005-09-10 00:25:56 -0700147
148/**
149 * write_can_lock - would write_trylock() succeed?
150 * @lock: the rwlock in question.
151 */
Andi Kleenfb2e2842006-09-26 10:52:32 +0200152static inline int __raw_write_can_lock(raw_rwlock_t *x)
153{
154 return (x)->lock == RW_LOCK_BIAS;
155}
Ingo Molnarfb1c8f92005-09-10 00:25:56 -0700156
157static inline void __raw_read_lock(raw_rwlock_t *rw)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700158{
Andi Kleenfb2e2842006-09-26 10:52:32 +0200159 asm volatile(LOCK_PREFIX " subl $1,(%0)\n\t"
160 "jns 1f\n"
161 "call __read_lock_failed\n\t"
162 "1:\n"
163 ::"a" (rw) : "memory");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700164}
165
Ingo Molnarfb1c8f92005-09-10 00:25:56 -0700166static inline void __raw_write_lock(raw_rwlock_t *rw)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700167{
Andi Kleenfb2e2842006-09-26 10:52:32 +0200168 asm volatile(LOCK_PREFIX " subl $" RW_LOCK_BIAS_STR ",(%0)\n\t"
169 "jz 1f\n"
170 "call __write_lock_failed\n\t"
171 "1:\n"
172 ::"a" (rw) : "memory");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173}
174
Ingo Molnarfb1c8f92005-09-10 00:25:56 -0700175static inline int __raw_read_trylock(raw_rwlock_t *lock)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700176{
177 atomic_t *count = (atomic_t *)lock;
178 atomic_dec(count);
179 if (atomic_read(count) >= 0)
180 return 1;
181 atomic_inc(count);
182 return 0;
183}
184
Ingo Molnarfb1c8f92005-09-10 00:25:56 -0700185static inline int __raw_write_trylock(raw_rwlock_t *lock)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700186{
187 atomic_t *count = (atomic_t *)lock;
188 if (atomic_sub_and_test(RW_LOCK_BIAS, count))
189 return 1;
190 atomic_add(RW_LOCK_BIAS, count);
191 return 0;
192}
193
Ingo Molnarfb1c8f92005-09-10 00:25:56 -0700194static inline void __raw_read_unlock(raw_rwlock_t *rw)
195{
Linus Torvaldsb862f3b2006-07-08 15:24:18 -0700196 asm volatile(LOCK_PREFIX "incl %0" :"+m" (rw->lock) : : "memory");
Ingo Molnarfb1c8f92005-09-10 00:25:56 -0700197}
198
199static inline void __raw_write_unlock(raw_rwlock_t *rw)
200{
Gerd Hoffmann9a0b5812006-03-23 02:59:32 -0800201 asm volatile(LOCK_PREFIX "addl $" RW_LOCK_BIAS_STR ", %0"
Linus Torvaldsb862f3b2006-07-08 15:24:18 -0700202 : "+m" (rw->lock) : : "memory");
Ingo Molnarfb1c8f92005-09-10 00:25:56 -0700203}
204
Linus Torvalds1da177e2005-04-16 15:20:36 -0700205#endif /* __ASM_SPINLOCK_H */