1/* spinlock.h: 32-bit Sparc spinlock support. 2 * 3 * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) 4 */ 5 6#ifndef __SPARC_SPINLOCK_H 7#define __SPARC_SPINLOCK_H 8 9#include <linux/threads.h> /* For NR_CPUS */ 10 11#ifndef __ASSEMBLY__ 12 13#include <asm/psr.h> 14 15/* 16 * Define this to use the verbose/debugging versions in 17 * arch/sparc/lib/debuglocks.c 18 * 19 * Be sure to make dep whenever changing this option. 20 */ 21#define SPIN_LOCK_DEBUG 22 23#ifdef SPIN_LOCK_DEBUG 24struct _spinlock_debug { 25 unsigned char lock; 26 unsigned long owner_pc; 27}; 28typedef struct _spinlock_debug spinlock_t; 29 30#define SPIN_LOCK_UNLOCKED (spinlock_t) { 0, 0 } 31#define spin_lock_init(lp) do { *(lp)= SPIN_LOCK_UNLOCKED; } while(0) 32#define spin_is_locked(lp) (*((volatile unsigned char *)(&((lp)->lock))) != 0) 33#define spin_unlock_wait(lp) do { barrier(); } while(*(volatile unsigned char *)(&(lp)->lock)) 34 35extern void _do_spin_lock(spinlock_t *lock, char *str); 36extern int _spin_trylock(spinlock_t *lock); 37extern void _do_spin_unlock(spinlock_t *lock); 38 39#define spin_trylock(lp) _spin_trylock(lp) 40#define spin_lock(lock) _do_spin_lock(lock, "spin_lock") 41#define spin_unlock(lock) _do_spin_unlock(lock) 42 43struct _rwlock_debug { 44 volatile unsigned int lock; 45 unsigned long owner_pc; 46 unsigned long reader_pc[NR_CPUS]; 47}; 48typedef struct _rwlock_debug rwlock_t; 49 50#define RW_LOCK_UNLOCKED (rwlock_t) { 0, 0, {0} } 51 52#define rwlock_init(lp) do { *(lp)= RW_LOCK_UNLOCKED; } while(0) 53 54extern void _do_read_lock(rwlock_t *rw, char *str); 55extern void _do_read_unlock(rwlock_t *rw, char *str); 56extern void _do_write_lock(rwlock_t *rw, char *str); 57extern void _do_write_unlock(rwlock_t *rw); 58 59#define read_lock(lock) \ 60do { unsigned long flags; \ 61 __save_and_cli(flags); \ 62 _do_read_lock(lock, "read_lock"); \ 63 __restore_flags(flags); \ 64} while(0) 65 66#define read_unlock(lock) \ 67do { unsigned long flags; \ 68 __save_and_cli(flags); \ 69 _do_read_unlock(lock, "read_unlock"); \ 70 __restore_flags(flags); \ 71} while(0) 72 73#define write_lock(lock) \ 74do { unsigned long flags; \ 75 __save_and_cli(flags); \ 76 _do_write_lock(lock, "write_lock"); \ 77 __restore_flags(flags); \ 78} while(0) 79 80#define write_unlock(lock) \ 81do { unsigned long flags; \ 82 __save_and_cli(flags); \ 83 _do_write_unlock(lock); \ 84 __restore_flags(flags); \ 85} while(0) 86 87#else /* !SPIN_LOCK_DEBUG */ 88 89typedef unsigned char spinlock_t; 90#define SPIN_LOCK_UNLOCKED 0 91 92#define spin_lock_init(lock) (*((unsigned char *)(lock)) = 0) 93#define spin_is_locked(lock) (*((volatile unsigned char *)(lock)) != 0) 94 95#define spin_unlock_wait(lock) \ 96do { \ 97 barrier(); \ 98} while(*((volatile unsigned char *)lock)) 99 100extern __inline__ void spin_lock(spinlock_t *lock) 101{ 102 __asm__ __volatile__( 103 "\n1:\n\t" 104 "ldstub [%0], %%g2\n\t" 105 "orcc %%g2, 0x0, %%g0\n\t" 106 "bne,a 2f\n\t" 107 " ldub [%0], %%g2\n\t" 108 ".subsection 2\n" 109 "2:\n\t" 110 "orcc %%g2, 0x0, %%g0\n\t" 111 "bne,a 2b\n\t" 112 " ldub [%0], %%g2\n\t" 113 "b,a 1b\n\t" 114 ".previous\n" 115 : /* no outputs */ 116 : "r" (lock) 117 : "g2", "memory", "cc"); 118} 119 120extern __inline__ int spin_trylock(spinlock_t *lock) 121{ 122 unsigned int result; 123 __asm__ __volatile__("ldstub [%1], %0" 124 : "=r" (result) 125 : "r" (lock) 126 : "memory"); 127 return (result == 0); 128} 129 130extern __inline__ void spin_unlock(spinlock_t *lock) 131{ 132 __asm__ __volatile__("stb %%g0, [%0]" : : "r" (lock) : "memory"); 133} 134 135typedef struct { volatile unsigned int lock; } rwlock_t; 136 137#define RW_LOCK_UNLOCKED (rwlock_t) { 0 } 138 139#define rwlock_init(lp) do { *(lp)= RW_LOCK_UNLOCKED; } while(0) 140 141 142/* Sort of like atomic_t's on Sparc, but even more clever. 143 * 144 * ------------------------------------ 145 * | 24-bit counter | wlock | rwlock_t 146 * ------------------------------------ 147 * 31 8 7 0 148 * 149 * wlock signifies the one writer is in or somebody is updating 150 * counter. For a writer, if he successfully acquires the wlock, 151 * but counter is non-zero, he has to release the lock and wait, 152 * till both counter and wlock are zero. 153 * 154 * Unfortunately this scheme limits us to ~16,000,000 cpus. 155 */ 156extern __inline__ void _read_lock(rwlock_t *rw) 157{ 158 register rwlock_t *lp asm("g1"); 159 lp = rw; 160 __asm__ __volatile__( 161 "mov %%o7, %%g4\n\t" 162 "call ___rw_read_enter\n\t" 163 " ldstub [%%g1 + 3], %%g2\n" 164 : /* no outputs */ 165 : "r" (lp) 166 : "g2", "g4", "memory", "cc"); 167} 168 169#define read_lock(lock) \ 170do { unsigned long flags; \ 171 __save_and_cli(flags); \ 172 _read_lock(lock); \ 173 __restore_flags(flags); \ 174} while(0) 175 176extern __inline__ void _read_unlock(rwlock_t *rw) 177{ 178 register rwlock_t *lp asm("g1"); 179 lp = rw; 180 __asm__ __volatile__( 181 "mov %%o7, %%g4\n\t" 182 "call ___rw_read_exit\n\t" 183 " ldstub [%%g1 + 3], %%g2\n" 184 : /* no outputs */ 185 : "r" (lp) 186 : "g2", "g4", "memory", "cc"); 187} 188 189#define read_unlock(lock) \ 190do { unsigned long flags; \ 191 __save_and_cli(flags); \ 192 _read_unlock(lock); \ 193 __restore_flags(flags); \ 194} while(0) 195 196extern __inline__ void write_lock(rwlock_t *rw) 197{ 198 register rwlock_t *lp asm("g1"); 199 lp = rw; 200 __asm__ __volatile__( 201 "mov %%o7, %%g4\n\t" 202 "call ___rw_write_enter\n\t" 203 " ldstub [%%g1 + 3], %%g2\n" 204 : /* no outputs */ 205 : "r" (lp) 206 : "g2", "g4", "memory", "cc"); 207} 208 209#define write_unlock(rw) do { (rw)->lock = 0; } while(0) 210 211#endif /* SPIN_LOCK_DEBUG */ 212 213#endif /* !(__ASSEMBLY__) */ 214 215#endif /* __SPARC_SPINLOCK_H */ 216