1/* $NetBSD: lock_stubs.s,v 1.12 2008/05/25 15:56:12 chs Exp $ */ 2 3/*- 4 * Copyright (c) 2002, 2007 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Jason R. Thorpe and Andrew Doran 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32/* 33 * Assembly language lock stubs. These handle the common ("easy") 34 * cases for mutexes, and provide helper routines for rwlocks. 35 * 36 * See sparc/include/mutex.h for additional comments. 37 */ 38 39#include "opt_lockdebug.h" 40 41#include <machine/asm.h> 42#include <machine/param.h> 43 44#include <sparc/sparc/vaddrs.h> 45 46#include <sparc/psl.h> 47 48#include "assym.h" 49 50curlwp = CPUINFO_VA + CPUINFO_CURLWP 51 52/* 53 * Interlock hash table, used by the R/W lock helper routines. 54 */ 55 .section .bss 56 .align 1024 57 .globl _C_LABEL(_lock_hash) 58OTYPE(_C_LABEL(_lock_hash)) 59_C_LABEL(_lock_hash): 60 .space 1024 61 62 .text 63 64#ifndef LOCKDEBUG 65 66/* 67 * void mutex_enter(kmutex_t *mtx); 68 */ 69ENTRY(mutex_enter) 70 sethi %hi(curlwp), %o3 71 ld [%o3 + %lo(curlwp)], %o3 ! current thread 72 ldstub [%o0], %o1 ! try to acquire lock 73mutex_enter_crit_start: .globl mutex_enter_crit_start 74 tst %o1 75 bnz _C_LABEL(mutex_vector_enter) ! nope, hard case 76 77 /* 78 * We now own the lock, but the owner field is not 79 * set. We need to update the lock word with the 80 * our thread pointer. We rely on the fact that the 81 * mutex code will spin or sleep while the mutex is 82 * owned "anonymously". 83 */ 84 sra %o3, 5, %o1 ! curlwp >> 5 85 sethi %hi(0xff000000), %o2 ! finish constructing 86 or %o1, %o2, %o1 ! lock word 87 st %o1, [%o0] 88mutex_enter_crit_end: .globl mutex_enter_crit_end 89 retl 90 nop 91 92/* 93 * void mutex_exit(kmutex_t *mtx); 94 * 95 * Adaptive mutexes on sparc aren't as cheap as other platforms. 96 * However, since we need to test the waiters condition, in the 97 * non-DIAGNOSTIC case we can just clear the owner field. 98 * 99 * NetBSD on sparc uses TSO (total store order), so it's safe to 100 * clear the lock and then test for waiters without worrying about 101 * memory ordering issues. 102 */ 103ENTRY(mutex_exit) 104 sethi %hi(curlwp), %o3 105 ld [%o3 + %lo(curlwp)], %o3 ! current thread 106 sra %o3, 5, %o1 ! curlwp >> 5 107 sethi %hi(0xff000000), %o2 ! finish constructing 108 or %o1, %o2, %o1 ! lock word 109 ld [%o0], %o2 ! get lock word 110 cmp %o1, %o2 ! -> 0 if we own lock 111 bne _C_LABEL(mutex_vector_exit) ! no, hard case 112 nop 113 ldub [%o0 + MTX_LOCK], %o3 ! get has-waiters indicator 114 tst %o3 ! has waiters? 115 bnz _C_LABEL(mutex_wakeup) ! yes, hard case 116 st %g0, [%o0] ! and release lock 117 retl 118 nop 119 120#if 0 /* does not work for MP yet */ 121/* 122 * void mutex_spin_enter(kmutex_t *); 123 */ 124ENTRY(mutex_spin_enter) 125 sethi %hi(CPUINFO_VA), %o4 126 ld [ %o4 + CPUINFO_MTX_COUNT ], %o5 127 sub %o5, 1, %o1 128 st %o1, [ %o4 + CPUINFO_MTX_COUNT ] 129 ldub [ %o0 + MTX_IPL ], %o2 130 rd %psr, %o1 131 sll %o2, 8, %o2 132 and %o1, PSR_PIL, %o3 133 cmp %o3, %o2 134 bge 1f 135 tst %o5 136 andn %o1, PSR_PIL, %o1 137 wr %o2, %o1, %psr 138 nop 139 nop 140 nop 141 tst %o5 1421: 143 bz,a 2f 144 st %o3, [ %o4 + CPUINFO_MTX_OLDSPL ] 1452: 146#if defined(MULTIPROCESSOR) || defined(DIAGNOSTIC) 147 ldstub [ %o0 + MTX_LOCK ], %o2 148 tst %o2 149 bnz _C_LABEL(mutex_spin_retry) 150 nop 151#endif 152 retl 153 nop 154 155/* 156 * void mutex_spin_exit(kmutex_t *); 157 */ 158ENTRY(mutex_spin_exit) 159 160#if defined(DIAGNOSTIC) 161 ldub [ %o0 + MTX_LOCK ], %o1 162 tst %o1 163 bz _C_LABEL(mutex_vector_exit) 164 nop 165 clrb [ %o0 + MTX_LOCK ] 166#elif defined(MULTIPROCESSOR) 167 clrb [ %o0 + MTX_LOCK ] 168#endif 169 sethi %hi(CPUINFO_VA), %o2 170 ld [ %o2 + CPUINFO_MTX_OLDSPL ], %o3 171 ld [ %o2 + CPUINFO_MTX_COUNT ], %o1 172 addcc %o1, 1, %o4 173 bnz 1f 174 st %o4, [ %o2 + CPUINFO_MTX_COUNT ] 175 rd %psr, %o1 176 andn %o1, PSR_PIL, %o1 177 wr %o3, %o1, %psr 178 nop 179 nop 180 nop 1811: 182 retl 183 nop 184 185#endif 186 187#endif /* LOCKDEBUG */ 188 189/* 190 * int _lock_cas(uintptr_t *ptr, uintptr_t old, uintptr_t new); 191 * 192 * Compare-and-set operation for RW locks. 193 * 194 * XXX On single CPU systems, this should use a restartable sequence: 195 * XXX there we don't need the overhead of interlocking. 196 */ 197ENTRY(_lock_cas) 198 rd %psr, %o4 ! disable interrupts 199 or %o4, PSR_PIL, %o5 200 wr %o5, 0, %psr 201 nop 202 nop 203 nop 204 srl %o0, 3, %o5 205 and %o5, 1023, %o5 206 set _C_LABEL(_lock_hash), %o3 207 add %o5, %o3, %o5 2081: 209 ldstub [%o5], %o3 ! %o5 == interlock address 210 tst %o3 211 bz,a 2f 212 nop 213 nop 214 nop 215 b,a 1b ! spin 216 nop 2172: 218 ld [%o0], %o3 ! lock value 219 cmp %o1, %o3 ! same as expected value? 220 be,a 3f ! yes, store new value 221 st %o2, [%o0] 222 stb %g0, [%o5] 223 wr %o4, 0, %psr ! enable interrupts 224 nop 225 nop 226 nop 227 retl 228 mov %g0, %o0 ! nope 2293: 230 stb %g0, [%o5] 231 wr %o4, 0, %psr ! enable interrupts 232 nop 233 nop 234 nop 235 retl 236 or %g0, 1, %o0 237