1 /***********************license start*************** 2 * Author: Cavium Networks 3 * 4 * Contact: support@caviumnetworks.com 5 * This file is part of the OCTEON SDK 6 * 7 * Copyright (c) 2003-2008 Cavium Networks 8 * 9 * This file is free software; you can redistribute it and/or modify 10 * it under the terms of the GNU General Public License, Version 2, as 11 * published by the Free Software Foundation. 12 * 13 * This file is distributed in the hope that it will be useful, but 14 * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty 15 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or 16 * NONINFRINGEMENT. See the GNU General Public License for more 17 * details. 18 * 19 * You should have received a copy of the GNU General Public License 20 * along with this file; if not, write to the Free Software 21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 22 * or visit http://www.gnu.org/licenses/. 23 * 24 * This file may also be available under a different license from Cavium. 25 * Contact Cavium Networks for more information 26 ***********************license end**************************************/ 27 28 /** 29 * Implementation of spinlocks for Octeon CVMX. Although similar in 30 * function to Linux kernel spinlocks, they are not compatible. 31 * Octeon CVMX spinlocks are only used to synchronize with the boot 32 * monitor and other non-Linux programs running in the system. 33 */ 34 35 #ifndef __CVMX_SPINLOCK_H__ 36 #define __CVMX_SPINLOCK_H__ 37 38 #include <asm/octeon/cvmx-asm.h> 39 40 /* Spinlocks for Octeon */ 41 42 /* define these to enable recursive spinlock debugging */ 43 /*#define CVMX_SPINLOCK_DEBUG */ 44 45 /** 46 * Spinlocks for Octeon CVMX 47 */ 48 typedef struct { 49 volatile uint32_t value; 50 } cvmx_spinlock_t; 51 52 /* note - macros not expanded in inline ASM, so values hardcoded */ 53 #define CVMX_SPINLOCK_UNLOCKED_VAL 0 54 #define CVMX_SPINLOCK_LOCKED_VAL 1 55 56 #define CVMX_SPINLOCK_UNLOCKED_INITIALIZER {CVMX_SPINLOCK_UNLOCKED_VAL} 57 58 /** 59 * Initialize a spinlock 60 * 61 * @lock: Lock to initialize 62 */ 63 static inline void cvmx_spinlock_init(cvmx_spinlock_t *lock) 64 { 65 lock->value = CVMX_SPINLOCK_UNLOCKED_VAL; 66 } 67 68 /** 69 * Return non-zero if the spinlock is currently locked 70 * 71 * @lock: Lock to check 72 * Returns Non-zero if locked 73 */ 74 static inline int cvmx_spinlock_locked(cvmx_spinlock_t *lock) 75 { 76 return lock->value != CVMX_SPINLOCK_UNLOCKED_VAL; 77 } 78 79 /** 80 * Releases lock 81 * 82 * @lock: pointer to lock structure 83 */ 84 static inline void cvmx_spinlock_unlock(cvmx_spinlock_t *lock) 85 { 86 CVMX_SYNCWS; 87 lock->value = 0; 88 CVMX_SYNCWS; 89 } 90 91 /** 92 * Attempts to take the lock, but does not spin if lock is not available. 93 * May take some time to acquire the lock even if it is available 94 * due to the ll/sc not succeeding. 95 * 96 * @lock: pointer to lock structure 97 * 98 * Returns 0: lock successfully taken 99 * 1: lock not taken, held by someone else 100 * These return values match the Linux semantics. 101 */ 102 103 static inline unsigned int cvmx_spinlock_trylock(cvmx_spinlock_t *lock) 104 { 105 unsigned int tmp; 106 107 __asm__ __volatile__(".set noreorder \n" 108 "1: ll %[tmp], %[val] \n" 109 /* if lock held, fail immediately */ 110 " bnez %[tmp], 2f \n" 111 " li %[tmp], 1 \n" 112 " sc %[tmp], %[val] \n" 113 " beqz %[tmp], 1b \n" 114 " li %[tmp], 0 \n" 115 "2: \n" 116 ".set reorder \n" : 117 [val] "+m"(lock->value), [tmp] "=&r"(tmp) 118 : : "memory"); 119 120 return tmp != 0; /* normalize to 0 or 1 */ 121 } 122 123 /** 124 * Gets lock, spins until lock is taken 125 * 126 * @lock: pointer to lock structure 127 */ 128 static inline void cvmx_spinlock_lock(cvmx_spinlock_t *lock) 129 { 130 unsigned int tmp; 131 132 __asm__ __volatile__(".set noreorder \n" 133 "1: ll %[tmp], %[val] \n" 134 " bnez %[tmp], 1b \n" 135 " li %[tmp], 1 \n" 136 " sc %[tmp], %[val] \n" 137 " beqz %[tmp], 1b \n" 138 " nop \n" 139 ".set reorder \n" : 140 [val] "+m"(lock->value), [tmp] "=&r"(tmp) 141 : : "memory"); 142 143 } 144 145 /** ******************************************************************** 146 * Bit spinlocks 147 * These spinlocks use a single bit (bit 31) of a 32 bit word for locking. 148 * The rest of the bits in the word are left undisturbed. This enables more 149 * compact data structures as only 1 bit is consumed for the lock. 150 * 151 */ 152 153 /** 154 * Gets lock, spins until lock is taken 155 * Preserves the low 31 bits of the 32 bit 156 * word used for the lock. 157 * 158 * 159 * @word: word to lock bit 31 of 160 */ 161 static inline void cvmx_spinlock_bit_lock(uint32_t *word) 162 { 163 unsigned int tmp; 164 unsigned int sav; 165 166 __asm__ __volatile__(".set noreorder \n" 167 ".set noat \n" 168 "1: ll %[tmp], %[val] \n" 169 " bbit1 %[tmp], 31, 1b \n" 170 " li $at, 1 \n" 171 " ins %[tmp], $at, 31, 1 \n" 172 " sc %[tmp], %[val] \n" 173 " beqz %[tmp], 1b \n" 174 " nop \n" 175 ".set at \n" 176 ".set reorder \n" : 177 [val] "+m"(*word), [tmp] "=&r"(tmp), [sav] "=&r"(sav) 178 : : "memory"); 179 180 } 181 182 /** 183 * Attempts to get lock, returns immediately with success/failure 184 * Preserves the low 31 bits of the 32 bit 185 * word used for the lock. 186 * 187 * 188 * @word: word to lock bit 31 of 189 * Returns 0: lock successfully taken 190 * 1: lock not taken, held by someone else 191 * These return values match the Linux semantics. 192 */ 193 static inline unsigned int cvmx_spinlock_bit_trylock(uint32_t *word) 194 { 195 unsigned int tmp; 196 197 __asm__ __volatile__(".set noreorder\n\t" 198 ".set noat\n" 199 "1: ll %[tmp], %[val] \n" 200 /* if lock held, fail immediately */ 201 " bbit1 %[tmp], 31, 2f \n" 202 " li $at, 1 \n" 203 " ins %[tmp], $at, 31, 1 \n" 204 " sc %[tmp], %[val] \n" 205 " beqz %[tmp], 1b \n" 206 " li %[tmp], 0 \n" 207 "2: \n" 208 ".set at \n" 209 ".set reorder \n" : 210 [val] "+m"(*word), [tmp] "=&r"(tmp) 211 : : "memory"); 212 213 return tmp != 0; /* normalize to 0 or 1 */ 214 } 215 216 /** 217 * Releases bit lock 218 * 219 * Unconditionally clears bit 31 of the lock word. Note that this is 220 * done non-atomically, as this implementation assumes that the rest 221 * of the bits in the word are protected by the lock. 222 * 223 * @word: word to unlock bit 31 in 224 */ 225 static inline void cvmx_spinlock_bit_unlock(uint32_t *word) 226 { 227 CVMX_SYNCWS; 228 *word &= ~(1UL << 31); 229 CVMX_SYNCWS; 230 } 231 232 #endif /* __CVMX_SPINLOCK_H__ */ 233