1 #ifndef _ASM_IA64_SPINLOCK_H
2 #define _ASM_IA64_SPINLOCK_H
3
4 /*
5 * Copyright (C) 1998-2000 Hewlett-Packard Co
6 * Copyright (C) 1998-2000 David Mosberger-Tang <davidm@hpl.hp.com>
7 * Copyright (C) 1999 Walt Drummond <drummond@valinux.com>
8 *
9 * This file is used for SMP configurations only.
10 */
11
12 #include <linux/kernel.h>
13
14 #include <asm/system.h>
15 #include <asm/bitops.h>
16 #include <asm/atomic.h>
17
18 #undef NEW_LOCK
19
20 #ifdef NEW_LOCK
21
22 typedef struct {
23 volatile unsigned int lock;
24 } spinlock_t;
25
26 #define SPIN_LOCK_UNLOCKED (spinlock_t) { 0 }
27 #define spin_lock_init(x) ((x)->lock = 0)
28
29 /*
30 * Streamlined test_and_set_bit(0, (x)). We use test-and-test-and-set
31 * rather than a simple xchg to avoid writing the cache-line when
32 * there is contention.
33 */
34 #define spin_lock(x) \
35 { \
36 register char *addr __asm__ ("r31") = (char *) &(x)->lock; \
37 \
38 __asm__ __volatile__ ( \
39 "mov r30=1\n" \
40 "mov ar.ccv=r0\n" \
41 ";;\n" \
42 IA64_SEMFIX"cmpxchg4.acq r30=[%0],r30,ar.ccv\n" \
43 ";;\n" \
44 "cmp.ne p15,p0=r30,r0\n" \
45 "(p15) br.call.spnt.few b7=ia64_spinlock_contention\n" \
46 ";;\n" \
47 "1:\n" /* force a new bundle */ \
48 :: "r"(addr) \
49 : "ar.ccv", "ar.pfs", "b7", "p15", "r28", "r29", "r30", "memory"); \
50 }
51
52 #define spin_trylock(x) \
53 ({ \
54 register long result; \
55 \
56 __asm__ __volatile__ ( \
57 "mov ar.ccv=r0\n" \
58 ";;\n" \
59 IA64_SEMFIX"cmpxchg4.acq %0=[%2],%1,ar.ccv\n" \
60 : "=r"(result) : "r"(1), "r"(&(x)->lock) : "ar.ccv", "memory"); \
61 (result == 0); \
62 })
63
64 #define spin_is_locked(x) ((x)->lock != 0)
65 #define spin_unlock(x) do {((spinlock_t *) x)->lock = 0;} while (0)
66 #define spin_unlock_wait(x) do {} while ((x)->lock)
67
68 #else /* !NEW_LOCK */
69
70 typedef struct {
71 volatile unsigned int lock;
72 } spinlock_t;
73
74 #define SPIN_LOCK_UNLOCKED (spinlock_t) { 0 }
75 #define spin_lock_init(x) ((x)->lock = 0)
76
77 /*
78 * Streamlined test_and_set_bit(0, (x)). We use test-and-test-and-set
79 * rather than a simple xchg to avoid writing the cache-line when
80 * there is contention.
81 */
82 #define spin_lock(x) __asm__ __volatile__ ( \
83 "mov ar.ccv = r0\n" \
84 "mov r29 = 1\n" \
85 ";;\n" \
86 "1:\n" \
87 "ld4 r2 = [%0]\n" \
88 ";;\n" \
89 "cmp4.eq p0,p7 = r0,r2\n" \
90 "(p7) br.cond.spnt.few 1b \n" \
91 IA64_SEMFIX"cmpxchg4.acq r2 = [%0], r29, ar.ccv\n" \
92 ";;\n" \
93 "cmp4.eq p0,p7 = r0, r2\n" \
94 "(p7) br.cond.spnt.few 1b\n" \
95 ";;\n" \
96 :: "r"(&(x)->lock) : "r2", "r29", "memory")
97
98 #define spin_is_locked(x) ((x)->lock != 0)
99 #define spin_unlock(x) do {((spinlock_t *) x)->lock = 0; barrier(); } while (0)
100 #define spin_trylock(x) (cmpxchg_acq(&(x)->lock, 0, 1) == 0)
101 #define spin_unlock_wait(x) do { barrier(); } while ((x)->lock)
102
103 #endif /* !NEW_LOCK */
104
105 typedef struct {
106 volatile int read_counter:31;
107 volatile int write_lock:1;
108 } rwlock_t;
109 #define RW_LOCK_UNLOCKED (rwlock_t) { 0, 0 }
110
111 #define read_lock(rw) \
112 do { \
113 int tmp = 0; \
114 __asm__ __volatile__ ("1:\t"IA64_SEMFIX"fetchadd4.acq %0 = [%1], 1\n" \
115 ";;\n" \
116 "tbit.nz p6,p0 = %0, 31\n" \
117 "(p6) br.cond.sptk.few 2f\n" \
118 ".section .text.lock,\"ax\"\n" \
119 "2:\t"IA64_SEMFIX"fetchadd4.rel %0 = [%1], -1\n" \
120 ";;\n" \
121 "3:\tld4.acq %0 = [%1]\n" \
122 ";;\n" \
123 "tbit.nz p6,p0 = %0, 31\n" \
124 "(p6) br.cond.sptk.few 3b\n" \
125 "br.cond.sptk.few 1b\n" \
126 ";;\n" \
127 ".previous\n" \
128 : "=&r" (tmp) \
129 : "r" (rw): "memory"); \
130 } while(0)
131
132 #define read_unlock(rw) \
133 do { \
134 int tmp = 0; \
135 __asm__ __volatile__ (IA64_SEMFIX"fetchadd4.rel %0 = [%1], -1\n" \
136 : "=r" (tmp) \
137 : "r" (rw) \
138 : "memory"); \
139 } while(0)
140
141 #define write_lock(rw) \
142 do { \
143 __asm__ __volatile__ ( \
144 "mov ar.ccv = r0\n" \
145 "movl r29 = 0x80000000\n" \
146 ";;\n" \
147 "1:\n" \
148 "ld4 r2 = [%0]\n" \
149 ";;\n" \
150 "cmp4.eq p0,p7 = r0,r2\n" \
151 "(p7) br.cond.spnt.few 1b \n" \
152 IA64_SEMFIX"cmpxchg4.acq r2 = [%0], r29, ar.ccv\n" \
153 ";;\n" \
154 "cmp4.eq p0,p7 = r0, r2\n" \
155 "(p7) br.cond.spnt.few 1b\n" \
156 ";;\n" \
157 :: "r"(rw) : "r2", "r29", "memory"); \
158 } while(0)
159
160 /*
161 * clear_bit() has "acq" semantics; we're really need "rel" semantics,
162 * but for simplicity, we simply do a fence for now...
163 */
164 #define write_unlock(x) ({clear_bit(31, (x)); mb();})
165
166 #endif /* _ASM_IA64_SPINLOCK_H */
167