Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 | #ifndef __ASM_SPINLOCK_H #define __ASM_SPINLOCK_H #include <asm/system.h> #include <asm/processor.h> #include <asm/spinlock_types.h> static inline int __raw_spin_is_locked(raw_spinlock_t *x) { volatile unsigned int *a = __ldcw_align(x); return *a == 0; } #define __raw_spin_lock(lock) __raw_spin_lock_flags(lock, 0) #define __raw_spin_unlock_wait(x) \ do { cpu_relax(); } while (__raw_spin_is_locked(x)) static inline void __raw_spin_lock_flags(raw_spinlock_t *x, unsigned long flags) { volatile unsigned int *a; mb(); a = __ldcw_align(x); while (__ldcw(a) == 0) while (*a == 0) if (flags & PSW_SM_I) { local_irq_enable(); cpu_relax(); local_irq_disable(); } else cpu_relax(); mb(); } static inline void __raw_spin_unlock(raw_spinlock_t *x) { volatile unsigned int *a; mb(); a = __ldcw_align(x); *a = 1; mb(); } static inline int __raw_spin_trylock(raw_spinlock_t *x) { volatile unsigned int *a; int ret; mb(); a = __ldcw_align(x); ret = __ldcw(a) != 0; mb(); return ret; } /* * Read-write spinlocks, allowing multiple readers but only one writer. * Linux rwlocks are unfair to writers; they can be starved for an indefinite * time by readers. With care, they can also be taken in interrupt context. * * In the PA-RISC implementation, we have a spinlock and a counter. * Readers use the lock to serialise their access to the counter (which * records how many readers currently hold the lock). * Writers hold the spinlock, preventing any readers or other writers from * grabbing the rwlock. */ /* Note that we have to ensure interrupts are disabled in case we're * interrupted by some other code that wants to grab the same read lock */ static __inline__ void __raw_read_lock(raw_rwlock_t *rw) { unsigned long flags; local_irq_save(flags); __raw_spin_lock_flags(&rw->lock, flags); rw->counter++; __raw_spin_unlock(&rw->lock); local_irq_restore(flags); } /* Note that we have to ensure interrupts are disabled in case we're * interrupted by some other code that wants to grab the same read lock */ static __inline__ void __raw_read_unlock(raw_rwlock_t *rw) { unsigned long flags; local_irq_save(flags); __raw_spin_lock_flags(&rw->lock, flags); rw->counter--; __raw_spin_unlock(&rw->lock); local_irq_restore(flags); } /* Note that we have to ensure interrupts are disabled in case we're * interrupted by some other code that wants to grab the same read lock */ static __inline__ int __raw_read_trylock(raw_rwlock_t *rw) { unsigned long flags; retry: local_irq_save(flags); if (__raw_spin_trylock(&rw->lock)) { rw->counter++; __raw_spin_unlock(&rw->lock); local_irq_restore(flags); return 1; } local_irq_restore(flags); /* If write-locked, we fail to acquire the lock */ if (rw->counter < 0) return 0; /* Wait until we have a realistic chance at the lock */ while (__raw_spin_is_locked(&rw->lock) && rw->counter >= 0) cpu_relax(); goto retry; } /* Note that we have to ensure interrupts are disabled in case we're * interrupted by some other code that wants to read_trylock() this lock */ static __inline__ void __raw_write_lock(raw_rwlock_t *rw) { unsigned long flags; retry: local_irq_save(flags); __raw_spin_lock_flags(&rw->lock, flags); if (rw->counter != 0) { __raw_spin_unlock(&rw->lock); local_irq_restore(flags); while (rw->counter != 0) cpu_relax(); goto retry; } rw->counter = -1; /* mark as write-locked */ mb(); local_irq_restore(flags); } static __inline__ void __raw_write_unlock(raw_rwlock_t *rw) { rw->counter = 0; __raw_spin_unlock(&rw->lock); } /* Note that we have to ensure interrupts are disabled in case we're * interrupted by some other code that wants to read_trylock() this lock */ static __inline__ int __raw_write_trylock(raw_rwlock_t *rw) { unsigned long flags; int result = 0; local_irq_save(flags); if (__raw_spin_trylock(&rw->lock)) { if (rw->counter == 0) { rw->counter = -1; result = 1; } else { /* Read-locked. Oh well. */ __raw_spin_unlock(&rw->lock); } } local_irq_restore(flags); return result; } /* * read_can_lock - would read_trylock() succeed? * @lock: the rwlock in question. */ static __inline__ int __raw_read_can_lock(raw_rwlock_t *rw) { return rw->counter >= 0; } /* * write_can_lock - would write_trylock() succeed? * @lock: the rwlock in question. */ static __inline__ int __raw_write_can_lock(raw_rwlock_t *rw) { return !rw->counter; } #define _raw_spin_relax(lock) cpu_relax() #define _raw_read_relax(lock) cpu_relax() #define _raw_write_relax(lock) cpu_relax() #endif /* __ASM_SPINLOCK_H */ |