Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
spinlock.h
Go to the documentation of this file.
1 /* MN10300 spinlock support
2  *
3  * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
4  * Written by David Howells ([email protected])
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public Licence
8  * as published by the Free Software Foundation; either version
9  * 2 of the Licence, or (at your option) any later version.
10  */
11 #ifndef _ASM_SPINLOCK_H
12 #define _ASM_SPINLOCK_H
13 
14 #include <linux/atomic.h>
15 #include <asm/rwlock.h>
16 #include <asm/page.h>
17 
18 /*
19  * Simple spin lock operations. There are two variants, one clears IRQ's
20  * on the local processor, one does not.
21  *
22  * We make no fairness assumptions. They have a cost.
23  */
24 
25 #define arch_spin_is_locked(x) (*(volatile signed char *)(&(x)->slock) != 0)
26 #define arch_spin_unlock_wait(x) do { barrier(); } while (arch_spin_is_locked(x))
27 
28 static inline void arch_spin_unlock(arch_spinlock_t *lock)
29 {
30  asm volatile(
31  " bclr 1,(0,%0) \n"
32  :
33  : "a"(&lock->slock)
34  : "memory", "cc");
35 }
36 
37 static inline int arch_spin_trylock(arch_spinlock_t *lock)
38 {
39  int ret;
40 
41  asm volatile(
42  " mov 1,%0 \n"
43  " bset %0,(%1) \n"
44  " bne 1f \n"
45  " clr %0 \n"
46  "1: xor 1,%0 \n"
47  : "=d"(ret)
48  : "a"(&lock->slock)
49  : "memory", "cc");
50 
51  return ret;
52 }
53 
54 static inline void arch_spin_lock(arch_spinlock_t *lock)
55 {
56  asm volatile(
57  "1: bset 1,(0,%0) \n"
58  " bne 1b \n"
59  :
60  : "a"(&lock->slock)
61  : "memory", "cc");
62 }
63 
64 static inline void arch_spin_lock_flags(arch_spinlock_t *lock,
65  unsigned long flags)
66 {
67  int temp;
68 
69  asm volatile(
70  "1: bset 1,(0,%2) \n"
71  " beq 3f \n"
72  " mov %1,epsw \n"
73  "2: mov (0,%2),%0 \n"
74  " or %0,%0 \n"
75  " bne 2b \n"
76  " mov %3,%0 \n"
77  " mov %0,epsw \n"
78  " nop \n"
79  " nop \n"
80  " bra 1b\n"
81  "3: \n"
82  : "=&d" (temp)
83  : "d" (flags), "a"(&lock->slock), "i"(EPSW_IE | MN10300_CLI_LEVEL)
84  : "memory", "cc");
85 }
86 
87 #ifdef __KERNEL__
88 
89 /*
90  * Read-write spinlocks, allowing multiple readers
91  * but only one writer.
92  *
93  * NOTE! it is quite common to have readers in interrupts
94  * but no interrupt writers. For those circumstances we
95  * can "mix" irq-safe locks - any writer needs to get a
96  * irq-safe write-lock, but readers can get non-irqsafe
97  * read-locks.
98  */
99 
104 #define arch_read_can_lock(x) ((int)(x)->lock > 0)
105 
110 #define arch_write_can_lock(x) ((x)->lock == RW_LOCK_BIAS)
111 
112 /*
113  * On mn10300, we implement read-write locks as a 32-bit counter
114  * with the high bit (sign) being the "contended" bit.
115  */
116 static inline void arch_read_lock(arch_rwlock_t *rw)
117 {
118 #if 0 //def CONFIG_MN10300_HAS_ATOMIC_OPS_UNIT
119  __build_read_lock(rw, "__read_lock_failed");
120 #else
121  {
122  atomic_t *count = (atomic_t *)rw;
123  while (atomic_dec_return(count) < 0)
124  atomic_inc(count);
125  }
126 #endif
127 }
128 
129 static inline void arch_write_lock(arch_rwlock_t *rw)
130 {
131 #if 0 //def CONFIG_MN10300_HAS_ATOMIC_OPS_UNIT
132  __build_write_lock(rw, "__write_lock_failed");
133 #else
134  {
135  atomic_t *count = (atomic_t *)rw;
136  while (!atomic_sub_and_test(RW_LOCK_BIAS, count))
137  atomic_add(RW_LOCK_BIAS, count);
138  }
139 #endif
140 }
141 
142 static inline void arch_read_unlock(arch_rwlock_t *rw)
143 {
144 #if 0 //def CONFIG_MN10300_HAS_ATOMIC_OPS_UNIT
145  __build_read_unlock(rw);
146 #else
147  {
148  atomic_t *count = (atomic_t *)rw;
149  atomic_inc(count);
150  }
151 #endif
152 }
153 
154 static inline void arch_write_unlock(arch_rwlock_t *rw)
155 {
156 #if 0 //def CONFIG_MN10300_HAS_ATOMIC_OPS_UNIT
157  __build_write_unlock(rw);
158 #else
159  {
160  atomic_t *count = (atomic_t *)rw;
161  atomic_add(RW_LOCK_BIAS, count);
162  }
163 #endif
164 }
165 
166 static inline int arch_read_trylock(arch_rwlock_t *lock)
167 {
168  atomic_t *count = (atomic_t *)lock;
169  atomic_dec(count);
170  if (atomic_read(count) >= 0)
171  return 1;
172  atomic_inc(count);
173  return 0;
174 }
175 
176 static inline int arch_write_trylock(arch_rwlock_t *lock)
177 {
178  atomic_t *count = (atomic_t *)lock;
179  if (atomic_sub_and_test(RW_LOCK_BIAS, count))
180  return 1;
181  atomic_add(RW_LOCK_BIAS, count);
182  return 0;
183 }
184 
185 #define arch_read_lock_flags(lock, flags) arch_read_lock(lock)
186 #define arch_write_lock_flags(lock, flags) arch_write_lock(lock)
187 
188 #define _raw_spin_relax(lock) cpu_relax()
189 #define _raw_read_relax(lock) cpu_relax()
190 #define _raw_write_relax(lock) cpu_relax()
191 
192 #endif /* __KERNEL__ */
193 #endif /* _ASM_SPINLOCK_H */