1*5d9d9091SRichard Lowe/* 2*5d9d9091SRichard Lowe * CDDL HEADER START 3*5d9d9091SRichard Lowe * 4*5d9d9091SRichard Lowe * The contents of this file are subject to the terms of the 5*5d9d9091SRichard Lowe * Common Development and Distribution License (the "License"). 6*5d9d9091SRichard Lowe * You may not use this file except in compliance with the License. 7*5d9d9091SRichard Lowe * 8*5d9d9091SRichard Lowe * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*5d9d9091SRichard Lowe * or http://www.opensolaris.org/os/licensing. 10*5d9d9091SRichard Lowe * See the License for the specific language governing permissions 11*5d9d9091SRichard Lowe * and limitations under the License. 12*5d9d9091SRichard Lowe * 13*5d9d9091SRichard Lowe * When distributing Covered Code, include this CDDL HEADER in each 14*5d9d9091SRichard Lowe * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*5d9d9091SRichard Lowe * If applicable, add the following below this CDDL HEADER, with the 16*5d9d9091SRichard Lowe * fields enclosed by brackets "[]" replaced with your own identifying 17*5d9d9091SRichard Lowe * information: Portions Copyright [yyyy] [name of copyright owner] 18*5d9d9091SRichard Lowe * 19*5d9d9091SRichard Lowe * CDDL HEADER END 20*5d9d9091SRichard Lowe */ 21*5d9d9091SRichard Lowe/* 22*5d9d9091SRichard Lowe * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23*5d9d9091SRichard Lowe * Use is subject to license terms. 24*5d9d9091SRichard Lowe */ 25*5d9d9091SRichard Lowe 26*5d9d9091SRichard Lowe/* 27*5d9d9091SRichard Lowe * Copyright 2019 Joyent, Inc. 28*5d9d9091SRichard Lowe * Copyright 2022 Oxide Computer Company 29*5d9d9091SRichard Lowe */ 30*5d9d9091SRichard Lowe 31*5d9d9091SRichard Lowe#include "assym.h" 32*5d9d9091SRichard Lowe 33*5d9d9091SRichard Lowe#include <sys/mutex_impl.h> 34*5d9d9091SRichard Lowe#include <sys/asm_linkage.h> 35*5d9d9091SRichard Lowe#include <sys/asm_misc.h> 36*5d9d9091SRichard Lowe#include <sys/regset.h> 37*5d9d9091SRichard Lowe#include <sys/rwlock_impl.h> 38*5d9d9091SRichard Lowe#include <sys/lockstat.h> 39*5d9d9091SRichard Lowe 40*5d9d9091SRichard Lowe 41*5d9d9091SRichard Lowe#if defined(OPTERON_ERRATUM_147) 42*5d9d9091SRichard Lowe 43*5d9d9091SRichard Lowe/* 44*5d9d9091SRichard Lowe * Leave space for an lfence to be inserted if required by a CPU which suffers 45*5d9d9091SRichard Lowe * from this erratum. Pad (with nops) the location for the lfence so that it 46*5d9d9091SRichard Lowe * is adequately aligned for atomic hotpatching. 47*5d9d9091SRichard Lowe */ 48*5d9d9091SRichard Lowe#define ERRATUM147_PATCH_POINT(name) \ 49*5d9d9091SRichard Lowe .align 4, NOP_INSTR; \ 50*5d9d9091SRichard Lowe.##name##_147_patch_point: \ 51*5d9d9091SRichard Lowe nop; \ 52*5d9d9091SRichard Lowe nop; \ 53*5d9d9091SRichard Lowe nop; \ 54*5d9d9091SRichard Lowe nop; 55*5d9d9091SRichard Lowe 56*5d9d9091SRichard Lowe#else /* defined(OPTERON_ERRATUM_147) */ 57*5d9d9091SRichard Lowe 58*5d9d9091SRichard Lowe/* Empty macro so ifdefs are not required for all of the erratum sites. */ 59*5d9d9091SRichard Lowe#define ERRATUM147_PATCH_POINT(name) 60*5d9d9091SRichard Lowe 61*5d9d9091SRichard Lowe#endif /* defined(OPTERON_ERRATUM_147) */ 62*5d9d9091SRichard Lowe 63*5d9d9091SRichard Lowe/* 64*5d9d9091SRichard Lowe * Patch point for lockstat probes. When the associated probe is disabled, it 65*5d9d9091SRichard Lowe * will 'ret' from the function. It is hotpatched to allow execution to fall 66*5d9d9091SRichard Lowe * through when the probe is enabled. 67*5d9d9091SRichard Lowe */ 68*5d9d9091SRichard Lowe#define LOCKSTAT_RET(name) \ 69*5d9d9091SRichard Lowe.##name##_lockstat_patch_point: \ 70*5d9d9091SRichard Lowe ret; 71*5d9d9091SRichard Lowe 72*5d9d9091SRichard Lowe/* 73*5d9d9091SRichard Lowe * lock_try(lp), ulock_try(lp) 74*5d9d9091SRichard Lowe * - returns non-zero on success. 75*5d9d9091SRichard Lowe * - doesn't block interrupts so don't use this to spin on a lock. 76*5d9d9091SRichard Lowe * 77*5d9d9091SRichard Lowe * ulock_try() is for a lock in the user address space. 78*5d9d9091SRichard Lowe */ 79*5d9d9091SRichard Lowe 80*5d9d9091SRichard Lowe .globl kernelbase 81*5d9d9091SRichard Lowe 82*5d9d9091SRichard Lowe ENTRY(lock_try) 83*5d9d9091SRichard Lowe movb $-1, %dl 84*5d9d9091SRichard Lowe movzbq %dl, %rax 85*5d9d9091SRichard Lowe xchgb %dl, (%rdi) 86*5d9d9091SRichard Lowe xorb %dl, %al 87*5d9d9091SRichard Lowe LOCKSTAT_RET(lock_try) 88*5d9d9091SRichard Lowe 89*5d9d9091SRichard Lowe testb %al, %al 90*5d9d9091SRichard Lowe jnz 0f 91*5d9d9091SRichard Lowe ret 92*5d9d9091SRichard Lowe0: 93*5d9d9091SRichard Lowe movq %gs:CPU_THREAD, %rdx /* rdx = thread addr */ 94*5d9d9091SRichard Lowe movq %rdi, %rsi /* rsi = lock addr */ 95*5d9d9091SRichard Lowe movl $LS_LOCK_TRY_ACQUIRE, %edi /* edi = event */ 96*5d9d9091SRichard Lowe jmp lockstat_wrapper 97*5d9d9091SRichard Lowe SET_SIZE(lock_try) 98*5d9d9091SRichard Lowe 99*5d9d9091SRichard Lowe ENTRY(lock_spin_try) 100*5d9d9091SRichard Lowe movb $-1, %dl 101*5d9d9091SRichard Lowe movzbq %dl, %rax 102*5d9d9091SRichard Lowe xchgb %dl, (%rdi) 103*5d9d9091SRichard Lowe xorb %dl, %al 104*5d9d9091SRichard Lowe ret 105*5d9d9091SRichard Lowe SET_SIZE(lock_spin_try) 106*5d9d9091SRichard Lowe 107*5d9d9091SRichard Lowe ENTRY(ulock_try) 108*5d9d9091SRichard Lowe#ifdef DEBUG 109*5d9d9091SRichard Lowe movq kernelbase(%rip), %rax 110*5d9d9091SRichard Lowe cmpq %rax, %rdi /* test uaddr < kernelbase */ 111*5d9d9091SRichard Lowe jb ulock_pass /* uaddr < kernelbase, proceed */ 112*5d9d9091SRichard Lowe 113*5d9d9091SRichard Lowe movq %rdi, %r12 /* preserve lock ptr for debugging */ 114*5d9d9091SRichard Lowe leaq .ulock_panic_msg(%rip), %rdi 115*5d9d9091SRichard Lowe pushq %rbp 116*5d9d9091SRichard Lowe movq %rsp, %rbp 117*5d9d9091SRichard Lowe xorl %eax, %eax /* clear for varargs */ 118*5d9d9091SRichard Lowe call panic 119*5d9d9091SRichard Lowe 120*5d9d9091SRichard Lowe#endif /* DEBUG */ 121*5d9d9091SRichard Lowe 122*5d9d9091SRichard Loweulock_pass: 123*5d9d9091SRichard Lowe movl $1, %eax 124*5d9d9091SRichard Lowe xchgb %al, (%rdi) 125*5d9d9091SRichard Lowe xorb $1, %al 126*5d9d9091SRichard Lowe ret 127*5d9d9091SRichard Lowe SET_SIZE(ulock_try) 128*5d9d9091SRichard Lowe 129*5d9d9091SRichard Lowe#ifdef DEBUG 130*5d9d9091SRichard Lowe .data 131*5d9d9091SRichard Lowe.ulock_panic_msg: 132*5d9d9091SRichard Lowe .string "ulock_try: Argument is above kernelbase" 133*5d9d9091SRichard Lowe .text 134*5d9d9091SRichard Lowe#endif /* DEBUG */ 135*5d9d9091SRichard Lowe 136*5d9d9091SRichard Lowe/* 137*5d9d9091SRichard Lowe * lock_clear(lp) 138*5d9d9091SRichard Lowe * - unlock lock without changing interrupt priority level. 139*5d9d9091SRichard Lowe */ 140*5d9d9091SRichard Lowe 141*5d9d9091SRichard Lowe ENTRY(lock_clear) 142*5d9d9091SRichard Lowe movb $0, (%rdi) 143*5d9d9091SRichard Lowe LOCKSTAT_RET(lock_clear) 144*5d9d9091SRichard Lowe 145*5d9d9091SRichard Lowe movq %rdi, %rsi /* rsi = lock addr */ 146*5d9d9091SRichard Lowe movq %gs:CPU_THREAD, %rdx /* rdx = thread addr */ 147*5d9d9091SRichard Lowe movl $LS_LOCK_CLEAR_RELEASE, %edi /* edi = event */ 148*5d9d9091SRichard Lowe jmp lockstat_wrapper 149*5d9d9091SRichard Lowe SET_SIZE(lock_clear) 150*5d9d9091SRichard Lowe 151*5d9d9091SRichard Lowe ENTRY(ulock_clear) 152*5d9d9091SRichard Lowe#ifdef DEBUG 153*5d9d9091SRichard Lowe movq kernelbase(%rip), %rcx 154*5d9d9091SRichard Lowe cmpq %rcx, %rdi /* test uaddr < kernelbase */ 155*5d9d9091SRichard Lowe jb ulock_clr /* uaddr < kernelbase, proceed */ 156*5d9d9091SRichard Lowe 157*5d9d9091SRichard Lowe leaq .ulock_clear_msg(%rip), %rdi 158*5d9d9091SRichard Lowe pushq %rbp 159*5d9d9091SRichard Lowe movq %rsp, %rbp 160*5d9d9091SRichard Lowe xorl %eax, %eax /* clear for varargs */ 161*5d9d9091SRichard Lowe call panic 162*5d9d9091SRichard Lowe#endif 163*5d9d9091SRichard Lowe 164*5d9d9091SRichard Loweulock_clr: 165*5d9d9091SRichard Lowe movb $0, (%rdi) 166*5d9d9091SRichard Lowe ret 167*5d9d9091SRichard Lowe SET_SIZE(ulock_clear) 168*5d9d9091SRichard Lowe 169*5d9d9091SRichard Lowe#ifdef DEBUG 170*5d9d9091SRichard Lowe .data 171*5d9d9091SRichard Lowe.ulock_clear_msg: 172*5d9d9091SRichard Lowe .string "ulock_clear: Argument is above kernelbase" 173*5d9d9091SRichard Lowe .text 174*5d9d9091SRichard Lowe#endif /* DEBUG */ 175*5d9d9091SRichard Lowe 176*5d9d9091SRichard Lowe 177*5d9d9091SRichard Lowe/* 178*5d9d9091SRichard Lowe * lock_set_spl(lock_t *lp, int new_pil, u_short *old_pil) 179*5d9d9091SRichard Lowe * Drops lp, sets pil to new_pil, stores old pil in *old_pil. 180*5d9d9091SRichard Lowe */ 181*5d9d9091SRichard Lowe 182*5d9d9091SRichard Lowe ENTRY(lock_set_spl) 183*5d9d9091SRichard Lowe pushq %rbp 184*5d9d9091SRichard Lowe movq %rsp, %rbp 185*5d9d9091SRichard Lowe subq $32, %rsp 186*5d9d9091SRichard Lowe movl %esi, 8(%rsp) /* save priority level */ 187*5d9d9091SRichard Lowe movq %rdx, 16(%rsp) /* save old pil ptr */ 188*5d9d9091SRichard Lowe movq %rdi, 24(%rsp) /* save lock pointer */ 189*5d9d9091SRichard Lowe movl %esi, %edi /* pass priority level */ 190*5d9d9091SRichard Lowe call splr /* raise priority level */ 191*5d9d9091SRichard Lowe movq 24(%rsp), %rdi /* rdi = lock addr */ 192*5d9d9091SRichard Lowe movb $-1, %dl 193*5d9d9091SRichard Lowe xchgb %dl, (%rdi) /* try to set lock */ 194*5d9d9091SRichard Lowe testb %dl, %dl /* did we get the lock? ... */ 195*5d9d9091SRichard Lowe jnz .lss_miss /* ... no, go to C for the hard case */ 196*5d9d9091SRichard Lowe movq 16(%rsp), %rdx /* rdx = old pil addr */ 197*5d9d9091SRichard Lowe movw %ax, (%rdx) /* store old pil */ 198*5d9d9091SRichard Lowe leave 199*5d9d9091SRichard Lowe LOCKSTAT_RET(lock_set_spl) 200*5d9d9091SRichard Lowe 201*5d9d9091SRichard Lowe movq %rdi, %rsi /* rsi = lock addr */ 202*5d9d9091SRichard Lowe movq %gs:CPU_THREAD, %rdx /* rdx = thread addr */ 203*5d9d9091SRichard Lowe movl $LS_LOCK_SET_SPL_ACQUIRE, %edi 204*5d9d9091SRichard Lowe jmp lockstat_wrapper 205*5d9d9091SRichard Lowe 206*5d9d9091SRichard Lowe.lss_miss: 207*5d9d9091SRichard Lowe movl 8(%rsp), %esi /* new_pil */ 208*5d9d9091SRichard Lowe movq 16(%rsp), %rdx /* old_pil_addr */ 209*5d9d9091SRichard Lowe movl %eax, %ecx /* original pil */ 210*5d9d9091SRichard Lowe leave /* unwind stack */ 211*5d9d9091SRichard Lowe jmp lock_set_spl_spin 212*5d9d9091SRichard Lowe SET_SIZE(lock_set_spl) 213*5d9d9091SRichard Lowe 214*5d9d9091SRichard Lowe/* 215*5d9d9091SRichard Lowe * void 216*5d9d9091SRichard Lowe * lock_init(lp) 217*5d9d9091SRichard Lowe */ 218*5d9d9091SRichard Lowe 219*5d9d9091SRichard Lowe ENTRY(lock_init) 220*5d9d9091SRichard Lowe movb $0, (%rdi) 221*5d9d9091SRichard Lowe ret 222*5d9d9091SRichard Lowe SET_SIZE(lock_init) 223*5d9d9091SRichard Lowe 224*5d9d9091SRichard Lowe/* 225*5d9d9091SRichard Lowe * void 226*5d9d9091SRichard Lowe * lock_set(lp) 227*5d9d9091SRichard Lowe */ 228*5d9d9091SRichard Lowe 229*5d9d9091SRichard Lowe ENTRY(lock_set) 230*5d9d9091SRichard Lowe movb $-1, %dl 231*5d9d9091SRichard Lowe xchgb %dl, (%rdi) /* try to set lock */ 232*5d9d9091SRichard Lowe testb %dl, %dl /* did we get it? */ 233*5d9d9091SRichard Lowe jnz lock_set_spin /* no, go to C for the hard case */ 234*5d9d9091SRichard Lowe LOCKSTAT_RET(lock_set) 235*5d9d9091SRichard Lowe 236*5d9d9091SRichard Lowe movq %rdi, %rsi /* rsi = lock addr */ 237*5d9d9091SRichard Lowe movq %gs:CPU_THREAD, %rdx /* rdx = thread addr */ 238*5d9d9091SRichard Lowe movl $LS_LOCK_SET_ACQUIRE, %edi 239*5d9d9091SRichard Lowe jmp lockstat_wrapper 240*5d9d9091SRichard Lowe SET_SIZE(lock_set) 241*5d9d9091SRichard Lowe 242*5d9d9091SRichard Lowe/* 243*5d9d9091SRichard Lowe * lock_clear_splx(lp, s) 244*5d9d9091SRichard Lowe */ 245*5d9d9091SRichard Lowe 246*5d9d9091SRichard Lowe ENTRY(lock_clear_splx) 247*5d9d9091SRichard Lowe pushq %rbp 248*5d9d9091SRichard Lowe movq %rsp, %rbp 249*5d9d9091SRichard Lowe pushq %rdi /* save lp across call for lockstat */ 250*5d9d9091SRichard Lowe movb $0, (%rdi) /* clear lock */ 251*5d9d9091SRichard Lowe movl %esi, %edi /* arg for splx */ 252*5d9d9091SRichard Lowe call splx /* let splx do its thing */ 253*5d9d9091SRichard Lowe popq %rsi /* retreive lp for lockstat */ 254*5d9d9091SRichard Lowe leave 255*5d9d9091SRichard Lowe LOCKSTAT_RET(lock_clear_splx) 256*5d9d9091SRichard Lowe 257*5d9d9091SRichard Lowe movq %gs:CPU_THREAD, %rdx /* rdx = thread addr */ 258*5d9d9091SRichard Lowe movl $LS_LOCK_CLEAR_SPLX_RELEASE, %edi 259*5d9d9091SRichard Lowe jmp lockstat_wrapper 260*5d9d9091SRichard Lowe SET_SIZE(lock_clear_splx) 261*5d9d9091SRichard Lowe 262*5d9d9091SRichard Lowe/* 263*5d9d9091SRichard Lowe * mutex_enter() and mutex_exit(). 264*5d9d9091SRichard Lowe * 265*5d9d9091SRichard Lowe * These routines handle the simple cases of mutex_enter() (adaptive 266*5d9d9091SRichard Lowe * lock, not held) and mutex_exit() (adaptive lock, held, no waiters). 267*5d9d9091SRichard Lowe * If anything complicated is going on we punt to mutex_vector_enter(). 268*5d9d9091SRichard Lowe * 269*5d9d9091SRichard Lowe * mutex_tryenter() is similar to mutex_enter() but returns zero if 270*5d9d9091SRichard Lowe * the lock cannot be acquired, nonzero on success. 271*5d9d9091SRichard Lowe * 272*5d9d9091SRichard Lowe * If mutex_exit() gets preempted in the window between checking waiters 273*5d9d9091SRichard Lowe * and clearing the lock, we can miss wakeups. Disabling preemption 274*5d9d9091SRichard Lowe * in the mutex code is prohibitively expensive, so instead we detect 275*5d9d9091SRichard Lowe * mutex preemption by examining the trapped PC in the interrupt path. 276*5d9d9091SRichard Lowe * If we interrupt a thread in mutex_exit() that has not yet cleared 277*5d9d9091SRichard Lowe * the lock, cmnint() resets its PC back to the beginning of 278*5d9d9091SRichard Lowe * mutex_exit() so it will check again for waiters when it resumes. 279*5d9d9091SRichard Lowe */ 280*5d9d9091SRichard Lowe 281*5d9d9091SRichard Lowe ENTRY_NP(mutex_enter) 282*5d9d9091SRichard Lowe movq %gs:CPU_THREAD, %rdx /* rdx = thread ptr */ 283*5d9d9091SRichard Lowe xorl %eax, %eax /* rax = 0 (unheld adaptive) */ 284*5d9d9091SRichard Lowe lock 285*5d9d9091SRichard Lowe cmpxchgq %rdx, (%rdi) 286*5d9d9091SRichard Lowe jnz mutex_vector_enter 287*5d9d9091SRichard Lowe 288*5d9d9091SRichard Lowe ERRATUM147_PATCH_POINT(mutex_enter) 289*5d9d9091SRichard Lowe 290*5d9d9091SRichard Lowe LOCKSTAT_RET(mutex_enter) 291*5d9d9091SRichard Lowe 292*5d9d9091SRichard Lowe movq %rdi, %rsi 293*5d9d9091SRichard Lowe movl $LS_MUTEX_ENTER_ACQUIRE, %edi 294*5d9d9091SRichard Lowe jmp lockstat_wrapper 295*5d9d9091SRichard Lowe SET_SIZE(mutex_enter) 296*5d9d9091SRichard Lowe 297*5d9d9091SRichard Lowe 298*5d9d9091SRichard Lowe/* 299*5d9d9091SRichard Lowe * expects %rdx=thread, %rsi=lock, %edi=lockstat event 300*5d9d9091SRichard Lowe */ 301*5d9d9091SRichard Lowe ENTRY_NP(lockstat_wrapper) 302*5d9d9091SRichard Lowe incb T_LOCKSTAT(%rdx) /* curthread->t_lockstat++ */ 303*5d9d9091SRichard Lowe leaq lockstat_probemap(%rip), %rax 304*5d9d9091SRichard Lowe movl (%rax, %rdi, DTRACE_IDSIZE), %eax 305*5d9d9091SRichard Lowe testl %eax, %eax /* check for non-zero probe */ 306*5d9d9091SRichard Lowe jz 1f 307*5d9d9091SRichard Lowe pushq %rbp 308*5d9d9091SRichard Lowe movq %rsp, %rbp 309*5d9d9091SRichard Lowe movl %eax, %edi 310*5d9d9091SRichard Lowe movq lockstat_probe, %rax 311*5d9d9091SRichard Lowe INDIRECT_CALL_REG(rax) 312*5d9d9091SRichard Lowe leave /* unwind stack */ 313*5d9d9091SRichard Lowe1: 314*5d9d9091SRichard Lowe movq %gs:CPU_THREAD, %rdx /* reload thread ptr */ 315*5d9d9091SRichard Lowe decb T_LOCKSTAT(%rdx) /* curthread->t_lockstat-- */ 316*5d9d9091SRichard Lowe movl $1, %eax /* return success if tryenter */ 317*5d9d9091SRichard Lowe ret 318*5d9d9091SRichard Lowe SET_SIZE(lockstat_wrapper) 319*5d9d9091SRichard Lowe 320*5d9d9091SRichard Lowe/* 321*5d9d9091SRichard Lowe * expects %rcx=thread, %rdx=arg, %rsi=lock, %edi=lockstat event 322*5d9d9091SRichard Lowe */ 323*5d9d9091SRichard Lowe ENTRY(lockstat_wrapper_arg) 324*5d9d9091SRichard Lowe incb T_LOCKSTAT(%rcx) /* curthread->t_lockstat++ */ 325*5d9d9091SRichard Lowe leaq lockstat_probemap(%rip), %rax 326*5d9d9091SRichard Lowe movl (%rax, %rdi, DTRACE_IDSIZE), %eax 327*5d9d9091SRichard Lowe testl %eax, %eax /* check for non-zero probe */ 328*5d9d9091SRichard Lowe jz 1f 329*5d9d9091SRichard Lowe pushq %rbp 330*5d9d9091SRichard Lowe movq %rsp, %rbp 331*5d9d9091SRichard Lowe movl %eax, %edi 332*5d9d9091SRichard Lowe movq lockstat_probe, %rax 333*5d9d9091SRichard Lowe INDIRECT_CALL_REG(rax) 334*5d9d9091SRichard Lowe leave /* unwind stack */ 335*5d9d9091SRichard Lowe1: 336*5d9d9091SRichard Lowe movq %gs:CPU_THREAD, %rdx /* reload thread ptr */ 337*5d9d9091SRichard Lowe decb T_LOCKSTAT(%rdx) /* curthread->t_lockstat-- */ 338*5d9d9091SRichard Lowe movl $1, %eax /* return success if tryenter */ 339*5d9d9091SRichard Lowe ret 340*5d9d9091SRichard Lowe SET_SIZE(lockstat_wrapper_arg) 341*5d9d9091SRichard Lowe 342*5d9d9091SRichard Lowe 343*5d9d9091SRichard Lowe ENTRY(mutex_tryenter) 344*5d9d9091SRichard Lowe movq %gs:CPU_THREAD, %rdx /* rdx = thread ptr */ 345*5d9d9091SRichard Lowe xorl %eax, %eax /* rax = 0 (unheld adaptive) */ 346*5d9d9091SRichard Lowe lock 347*5d9d9091SRichard Lowe cmpxchgq %rdx, (%rdi) 348*5d9d9091SRichard Lowe jnz mutex_vector_tryenter 349*5d9d9091SRichard Lowe not %eax /* return success (nonzero) */ 350*5d9d9091SRichard Lowe 351*5d9d9091SRichard Lowe ERRATUM147_PATCH_POINT(mutex_tryenter) 352*5d9d9091SRichard Lowe 353*5d9d9091SRichard Lowe LOCKSTAT_RET(mutex_tryenter) 354*5d9d9091SRichard Lowe 355*5d9d9091SRichard Lowe movq %rdi, %rsi 356*5d9d9091SRichard Lowe movl $LS_MUTEX_TRYENTER_ACQUIRE, %edi 357*5d9d9091SRichard Lowe jmp lockstat_wrapper 358*5d9d9091SRichard Lowe SET_SIZE(mutex_tryenter) 359*5d9d9091SRichard Lowe 360*5d9d9091SRichard Lowe ENTRY(mutex_adaptive_tryenter) 361*5d9d9091SRichard Lowe movq %gs:CPU_THREAD, %rdx /* rdx = thread ptr */ 362*5d9d9091SRichard Lowe xorl %eax, %eax /* rax = 0 (unheld adaptive) */ 363*5d9d9091SRichard Lowe lock 364*5d9d9091SRichard Lowe cmpxchgq %rdx, (%rdi) 365*5d9d9091SRichard Lowe jnz 0f 366*5d9d9091SRichard Lowe not %eax /* return success (nonzero) */ 367*5d9d9091SRichard Lowe 368*5d9d9091SRichard Lowe ERRATUM147_PATCH_POINT(mutex_atryenter) 369*5d9d9091SRichard Lowe 370*5d9d9091SRichard Lowe ret 371*5d9d9091SRichard Lowe0: 372*5d9d9091SRichard Lowe xorl %eax, %eax /* return failure */ 373*5d9d9091SRichard Lowe ret 374*5d9d9091SRichard Lowe SET_SIZE(mutex_adaptive_tryenter) 375*5d9d9091SRichard Lowe 376*5d9d9091SRichard Lowe .globl mutex_owner_running_critical_start 377*5d9d9091SRichard Lowe 378*5d9d9091SRichard Lowe ENTRY(mutex_owner_running) 379*5d9d9091SRichard Lowemutex_owner_running_critical_start: 380*5d9d9091SRichard Lowe movq (%rdi), %r11 /* get owner field */ 381*5d9d9091SRichard Lowe andq $MUTEX_THREAD, %r11 /* remove waiters bit */ 382*5d9d9091SRichard Lowe cmpq $0, %r11 /* if free, skip */ 383*5d9d9091SRichard Lowe je 1f /* go return 0 */ 384*5d9d9091SRichard Lowe movq T_CPU(%r11), %r8 /* get owner->t_cpu */ 385*5d9d9091SRichard Lowe movq CPU_THREAD(%r8), %r9 /* get t_cpu->cpu_thread */ 386*5d9d9091SRichard Lowe.mutex_owner_running_critical_end: 387*5d9d9091SRichard Lowe cmpq %r11, %r9 /* owner == running thread? */ 388*5d9d9091SRichard Lowe je 2f /* yes, go return cpu */ 389*5d9d9091SRichard Lowe1: 390*5d9d9091SRichard Lowe xorq %rax, %rax /* return 0 */ 391*5d9d9091SRichard Lowe ret 392*5d9d9091SRichard Lowe2: 393*5d9d9091SRichard Lowe movq %r8, %rax /* return cpu */ 394*5d9d9091SRichard Lowe ret 395*5d9d9091SRichard Lowe SET_SIZE(mutex_owner_running) 396*5d9d9091SRichard Lowe 397*5d9d9091SRichard Lowe .globl mutex_owner_running_critical_size 398*5d9d9091SRichard Lowe .type mutex_owner_running_critical_size, @object 399*5d9d9091SRichard Lowe .align CPTRSIZE 400*5d9d9091SRichard Lowemutex_owner_running_critical_size: 401*5d9d9091SRichard Lowe .quad .mutex_owner_running_critical_end - mutex_owner_running_critical_start 402*5d9d9091SRichard Lowe SET_SIZE(mutex_owner_running_critical_size) 403*5d9d9091SRichard Lowe 404*5d9d9091SRichard Lowe .globl mutex_exit_critical_start 405*5d9d9091SRichard Lowe 406*5d9d9091SRichard Lowe ENTRY(mutex_exit) 407*5d9d9091SRichard Lowemutex_exit_critical_start: /* If interrupted, restart here */ 408*5d9d9091SRichard Lowe movq %gs:CPU_THREAD, %rdx 409*5d9d9091SRichard Lowe cmpq %rdx, (%rdi) 410*5d9d9091SRichard Lowe jne mutex_vector_exit /* wrong type or wrong owner */ 411*5d9d9091SRichard Lowe movq $0, (%rdi) /* clear owner AND lock */ 412*5d9d9091SRichard Lowe.mutex_exit_critical_end: 413*5d9d9091SRichard Lowe LOCKSTAT_RET(mutex_exit) 414*5d9d9091SRichard Lowe 415*5d9d9091SRichard Lowe movq %rdi, %rsi 416*5d9d9091SRichard Lowe movl $LS_MUTEX_EXIT_RELEASE, %edi 417*5d9d9091SRichard Lowe jmp lockstat_wrapper 418*5d9d9091SRichard Lowe SET_SIZE(mutex_exit) 419*5d9d9091SRichard Lowe 420*5d9d9091SRichard Lowe .globl mutex_exit_critical_size 421*5d9d9091SRichard Lowe .type mutex_exit_critical_size, @object 422*5d9d9091SRichard Lowe .align CPTRSIZE 423*5d9d9091SRichard Lowemutex_exit_critical_size: 424*5d9d9091SRichard Lowe .quad .mutex_exit_critical_end - mutex_exit_critical_start 425*5d9d9091SRichard Lowe SET_SIZE(mutex_exit_critical_size) 426*5d9d9091SRichard Lowe 427*5d9d9091SRichard Lowe/* 428*5d9d9091SRichard Lowe * rw_enter() and rw_exit(). 429*5d9d9091SRichard Lowe * 430*5d9d9091SRichard Lowe * These routines handle the simple cases of rw_enter (write-locking an unheld 431*5d9d9091SRichard Lowe * lock or read-locking a lock that's neither write-locked nor write-wanted) 432*5d9d9091SRichard Lowe * and rw_exit (no waiters or not the last reader). If anything complicated 433*5d9d9091SRichard Lowe * is going on we punt to rw_enter_sleep() and rw_exit_wakeup(), respectively. 434*5d9d9091SRichard Lowe */ 435*5d9d9091SRichard Lowe 436*5d9d9091SRichard Lowe ENTRY(rw_enter) 437*5d9d9091SRichard Lowe cmpl $RW_WRITER, %esi 438*5d9d9091SRichard Lowe je .rw_write_enter 439*5d9d9091SRichard Lowe movq (%rdi), %rax /* rax = old rw_wwwh value */ 440*5d9d9091SRichard Lowe testl $RW_WRITE_LOCKED|RW_WRITE_WANTED, %eax 441*5d9d9091SRichard Lowe jnz rw_enter_sleep 442*5d9d9091SRichard Lowe leaq RW_READ_LOCK(%rax), %rdx /* rdx = new rw_wwwh value */ 443*5d9d9091SRichard Lowe lock 444*5d9d9091SRichard Lowe cmpxchgq %rdx, (%rdi) /* try to grab read lock */ 445*5d9d9091SRichard Lowe jnz rw_enter_sleep 446*5d9d9091SRichard Lowe LOCKSTAT_RET(rw_read_enter) 447*5d9d9091SRichard Lowe 448*5d9d9091SRichard Lowe movq %gs:CPU_THREAD, %rcx /* rcx = thread ptr */ 449*5d9d9091SRichard Lowe movq %rdi, %rsi /* rsi = lock ptr */ 450*5d9d9091SRichard Lowe movl $LS_RW_ENTER_ACQUIRE, %edi 451*5d9d9091SRichard Lowe movl $RW_READER, %edx 452*5d9d9091SRichard Lowe jmp lockstat_wrapper_arg 453*5d9d9091SRichard Lowe 454*5d9d9091SRichard Lowe.rw_write_enter: 455*5d9d9091SRichard Lowe movq %gs:CPU_THREAD, %rdx 456*5d9d9091SRichard Lowe orq $RW_WRITE_LOCKED, %rdx /* rdx = write-locked value */ 457*5d9d9091SRichard Lowe xorl %eax, %eax /* rax = unheld value */ 458*5d9d9091SRichard Lowe lock 459*5d9d9091SRichard Lowe cmpxchgq %rdx, (%rdi) /* try to grab write lock */ 460*5d9d9091SRichard Lowe jnz rw_enter_sleep 461*5d9d9091SRichard Lowe 462*5d9d9091SRichard Lowe ERRATUM147_PATCH_POINT(rw_write_enter) 463*5d9d9091SRichard Lowe 464*5d9d9091SRichard Lowe LOCKSTAT_RET(rw_write_enter) 465*5d9d9091SRichard Lowe 466*5d9d9091SRichard Lowe movq %gs:CPU_THREAD, %rcx /* rcx = thread ptr */ 467*5d9d9091SRichard Lowe movq %rdi, %rsi /* rsi = lock ptr */ 468*5d9d9091SRichard Lowe movl $LS_RW_ENTER_ACQUIRE, %edi 469*5d9d9091SRichard Lowe movl $RW_WRITER, %edx 470*5d9d9091SRichard Lowe jmp lockstat_wrapper_arg 471*5d9d9091SRichard Lowe SET_SIZE(rw_enter) 472*5d9d9091SRichard Lowe 473*5d9d9091SRichard Lowe ENTRY(rw_exit) 474*5d9d9091SRichard Lowe movq (%rdi), %rax /* rax = old rw_wwwh value */ 475*5d9d9091SRichard Lowe cmpl $RW_READ_LOCK, %eax /* single-reader, no waiters? */ 476*5d9d9091SRichard Lowe jne .rw_not_single_reader 477*5d9d9091SRichard Lowe xorl %edx, %edx /* rdx = new value (unheld) */ 478*5d9d9091SRichard Lowe.rw_read_exit: 479*5d9d9091SRichard Lowe lock 480*5d9d9091SRichard Lowe cmpxchgq %rdx, (%rdi) /* try to drop read lock */ 481*5d9d9091SRichard Lowe jnz rw_exit_wakeup 482*5d9d9091SRichard Lowe LOCKSTAT_RET(rw_read_exit) 483*5d9d9091SRichard Lowe 484*5d9d9091SRichard Lowe movq %gs:CPU_THREAD, %rcx /* rcx = thread ptr */ 485*5d9d9091SRichard Lowe movq %rdi, %rsi /* rsi = lock ptr */ 486*5d9d9091SRichard Lowe movl $LS_RW_EXIT_RELEASE, %edi 487*5d9d9091SRichard Lowe movl $RW_READER, %edx 488*5d9d9091SRichard Lowe jmp lockstat_wrapper_arg 489*5d9d9091SRichard Lowe 490*5d9d9091SRichard Lowe.rw_not_single_reader: 491*5d9d9091SRichard Lowe testl $RW_WRITE_LOCKED, %eax /* write-locked or write-wanted? */ 492*5d9d9091SRichard Lowe jnz .rw_write_exit 493*5d9d9091SRichard Lowe leaq -RW_READ_LOCK(%rax), %rdx /* rdx = new value */ 494*5d9d9091SRichard Lowe cmpl $RW_READ_LOCK, %edx 495*5d9d9091SRichard Lowe jge .rw_read_exit /* not last reader, safe to drop */ 496*5d9d9091SRichard Lowe jmp rw_exit_wakeup /* last reader with waiters */ 497*5d9d9091SRichard Lowe.rw_write_exit: 498*5d9d9091SRichard Lowe movq %gs:CPU_THREAD, %rax /* rax = thread ptr */ 499*5d9d9091SRichard Lowe xorl %edx, %edx /* rdx = new value (unheld) */ 500*5d9d9091SRichard Lowe orq $RW_WRITE_LOCKED, %rax /* eax = write-locked value */ 501*5d9d9091SRichard Lowe lock 502*5d9d9091SRichard Lowe cmpxchgq %rdx, (%rdi) /* try to drop read lock */ 503*5d9d9091SRichard Lowe jnz rw_exit_wakeup 504*5d9d9091SRichard Lowe LOCKSTAT_RET(rw_write_exit) 505*5d9d9091SRichard Lowe 506*5d9d9091SRichard Lowe movq %gs:CPU_THREAD, %rcx /* rcx = thread ptr */ 507*5d9d9091SRichard Lowe movq %rdi, %rsi /* rsi - lock ptr */ 508*5d9d9091SRichard Lowe movl $LS_RW_EXIT_RELEASE, %edi 509*5d9d9091SRichard Lowe movl $RW_WRITER, %edx 510*5d9d9091SRichard Lowe jmp lockstat_wrapper_arg 511*5d9d9091SRichard Lowe SET_SIZE(rw_exit) 512*5d9d9091SRichard Lowe 513*5d9d9091SRichard Lowe#if defined(OPTERON_ERRATUM_147) 514*5d9d9091SRichard Lowe 515*5d9d9091SRichard Lowe/* 516*5d9d9091SRichard Lowe * Track if erratum 147 workaround has been hotpatched into place. 517*5d9d9091SRichard Lowe */ 518*5d9d9091SRichard Lowe DGDEF3(erratum_147_patched, 4, 4) 519*5d9d9091SRichard Lowe .long 0 520*5d9d9091SRichard Lowe 521*5d9d9091SRichard Lowe#define HOT_MUTEX_PATCH(iaddr, insn_reg) \ 522*5d9d9091SRichard Lowe movq $iaddr, %rdi; \ 523*5d9d9091SRichard Lowe movl %insn_reg, %esi; \ 524*5d9d9091SRichard Lowe movl $4, %edx; \ 525*5d9d9091SRichard Lowe call hot_patch_kernel_text; 526*5d9d9091SRichard Lowe 527*5d9d9091SRichard Lowe 528*5d9d9091SRichard Lowe/* 529*5d9d9091SRichard Lowe * void 530*5d9d9091SRichard Lowe * patch_erratum_147(void) 531*5d9d9091SRichard Lowe * 532*5d9d9091SRichard Lowe * Patch lock operations to work around erratum 147. 533*5d9d9091SRichard Lowe * 534*5d9d9091SRichard Lowe * The workaround is to place a fencing instruction (lfence) between the 535*5d9d9091SRichard Lowe * mutex operation and the subsequent read-modify-write instruction. 536*5d9d9091SRichard Lowe */ 537*5d9d9091SRichard Lowe 538*5d9d9091SRichard Lowe ENTRY_NP(patch_erratum_147) 539*5d9d9091SRichard Lowe pushq %rbp 540*5d9d9091SRichard Lowe movq %rsp, %rbp 541*5d9d9091SRichard Lowe pushq %r12 542*5d9d9091SRichard Lowe 543*5d9d9091SRichard Lowe /* 544*5d9d9091SRichard Lowe * Patch `nop; nop; nop; nop` sequence to `lfence; nop`. Since those 545*5d9d9091SRichard Lowe * patch points have been aligned to a 4-byte boundary, we can be 546*5d9d9091SRichard Lowe * confident that hot_patch_kernel_text() will be able to proceed 547*5d9d9091SRichard Lowe * safely and successfully. 548*5d9d9091SRichard Lowe */ 549*5d9d9091SRichard Lowe movl $0x90e8ae0f, %r12d 550*5d9d9091SRichard Lowe HOT_MUTEX_PATCH(.mutex_enter_147_patch_point, r12d) 551*5d9d9091SRichard Lowe HOT_MUTEX_PATCH(.mutex_tryenter_147_patch_point, r12d) 552*5d9d9091SRichard Lowe HOT_MUTEX_PATCH(.mutex_atryenter_147_patch_point, r12d) 553*5d9d9091SRichard Lowe HOT_MUTEX_PATCH(.rw_write_enter_147_patch_point, r12d) 554*5d9d9091SRichard Lowe 555*5d9d9091SRichard Lowe /* Record that erratum 147 points have been hotpatched */ 556*5d9d9091SRichard Lowe movl $1, erratum_147_patched 557*5d9d9091SRichard Lowe 558*5d9d9091SRichard Lowe popq %r12 559*5d9d9091SRichard Lowe movq %rbp, %rsp 560*5d9d9091SRichard Lowe popq %rbp 561*5d9d9091SRichard Lowe ret 562*5d9d9091SRichard Lowe SET_SIZE(patch_erratum_147) 563*5d9d9091SRichard Lowe 564*5d9d9091SRichard Lowe#endif /* OPTERON_ERRATUM_147 */ 565*5d9d9091SRichard Lowe 566*5d9d9091SRichard Lowe /* 567*5d9d9091SRichard Lowe * void 568*5d9d9091SRichard Lowe * lockstat_hotpatch_site(caddr_t instr_addr, int do_enable) 569*5d9d9091SRichard Lowe */ 570*5d9d9091SRichard Lowe ENTRY(lockstat_hotpatch_site) 571*5d9d9091SRichard Lowe pushq %rbp 572*5d9d9091SRichard Lowe movq %rsp, %rbp 573*5d9d9091SRichard Lowe pushq %rdi 574*5d9d9091SRichard Lowe pushq %rsi 575*5d9d9091SRichard Lowe 576*5d9d9091SRichard Lowe testl %esi, %esi 577*5d9d9091SRichard Lowe jz .do_disable 578*5d9d9091SRichard Lowe 579*5d9d9091SRichard Lowe /* enable the probe (replace ret with nop) */ 580*5d9d9091SRichard Lowe movl $NOP_INSTR, %esi 581*5d9d9091SRichard Lowe movl $1, %edx 582*5d9d9091SRichard Lowe call hot_patch_kernel_text 583*5d9d9091SRichard Lowe leave 584*5d9d9091SRichard Lowe ret 585*5d9d9091SRichard Lowe 586*5d9d9091SRichard Lowe.do_disable: 587*5d9d9091SRichard Lowe /* disable the probe (replace nop with ret) */ 588*5d9d9091SRichard Lowe movl $RET_INSTR, %esi 589*5d9d9091SRichard Lowe movl $1, %edx 590*5d9d9091SRichard Lowe call hot_patch_kernel_text 591*5d9d9091SRichard Lowe leave 592*5d9d9091SRichard Lowe ret 593*5d9d9091SRichard Lowe SET_SIZE(lockstat_hotpatch_site) 594*5d9d9091SRichard Lowe 595*5d9d9091SRichard Lowe#define HOT_PATCH_MATCH(name, probe, reg) \ 596*5d9d9091SRichard Lowe cmpl $probe, %reg; \ 597*5d9d9091SRichard Lowe jne 1f; \ 598*5d9d9091SRichard Lowe leaq lockstat_probemap(%rip), %rax; \ 599*5d9d9091SRichard Lowe movl _MUL(probe, DTRACE_IDSIZE)(%rax), %esi; \ 600*5d9d9091SRichard Lowe movq $.##name##_lockstat_patch_point, %rdi; \ 601*5d9d9091SRichard Lowe call lockstat_hotpatch_site; \ 602*5d9d9091SRichard Lowe 1: 603*5d9d9091SRichard Lowe 604*5d9d9091SRichard Lowe/* 605*5d9d9091SRichard Lowe * void 606*5d9d9091SRichard Lowe * lockstat_hotpatch_probe(int ls_probe) 607*5d9d9091SRichard Lowe * 608*5d9d9091SRichard Lowe * Given a lockstat probe identifier, hotpatch any associated lockstat 609*5d9d9091SRichard Lowe * primitive routine(s) so they fall through into the lockstat_probe() call (if 610*5d9d9091SRichard Lowe * the probe is enabled) or return normally (when the probe is disabled). 611*5d9d9091SRichard Lowe */ 612*5d9d9091SRichard Lowe 613*5d9d9091SRichard Lowe ENTRY(lockstat_hotpatch_probe) 614*5d9d9091SRichard Lowe pushq %rbp 615*5d9d9091SRichard Lowe movq %rsp, %rbp 616*5d9d9091SRichard Lowe pushq %r12 617*5d9d9091SRichard Lowe movl %edi, %r12d 618*5d9d9091SRichard Lowe 619*5d9d9091SRichard Lowe HOT_PATCH_MATCH(mutex_enter, LS_MUTEX_ENTER_ACQUIRE, r12d) 620*5d9d9091SRichard Lowe HOT_PATCH_MATCH(mutex_tryenter, LS_MUTEX_TRYENTER_ACQUIRE, r12d) 621*5d9d9091SRichard Lowe HOT_PATCH_MATCH(mutex_exit, LS_MUTEX_EXIT_RELEASE, r12d) 622*5d9d9091SRichard Lowe 623*5d9d9091SRichard Lowe HOT_PATCH_MATCH(rw_write_enter, LS_RW_ENTER_ACQUIRE, r12d) 624*5d9d9091SRichard Lowe HOT_PATCH_MATCH(rw_read_enter, LS_RW_ENTER_ACQUIRE, r12d) 625*5d9d9091SRichard Lowe HOT_PATCH_MATCH(rw_write_exit, LS_RW_EXIT_RELEASE, r12d) 626*5d9d9091SRichard Lowe HOT_PATCH_MATCH(rw_read_exit, LS_RW_EXIT_RELEASE, r12d) 627*5d9d9091SRichard Lowe 628*5d9d9091SRichard Lowe HOT_PATCH_MATCH(lock_set, LS_LOCK_SET_ACQUIRE, r12d) 629*5d9d9091SRichard Lowe HOT_PATCH_MATCH(lock_try, LS_LOCK_TRY_ACQUIRE, r12d) 630*5d9d9091SRichard Lowe HOT_PATCH_MATCH(lock_clear, LS_LOCK_CLEAR_RELEASE, r12d) 631*5d9d9091SRichard Lowe HOT_PATCH_MATCH(lock_set_spl, LS_LOCK_SET_SPL_ACQUIRE, r12d) 632*5d9d9091SRichard Lowe HOT_PATCH_MATCH(lock_clear_splx, LS_LOCK_CLEAR_SPLX_RELEASE, r12d) 633*5d9d9091SRichard Lowe 634*5d9d9091SRichard Lowe popq %r12 635*5d9d9091SRichard Lowe leave 636*5d9d9091SRichard Lowe ret 637*5d9d9091SRichard Lowe SET_SIZE(lockstat_hotpatch_probe) 638*5d9d9091SRichard Lowe 639*5d9d9091SRichard Lowe ENTRY(membar_enter) 640*5d9d9091SRichard Lowe ALTENTRY(membar_exit) 641*5d9d9091SRichard Lowe ALTENTRY(membar_sync) 642*5d9d9091SRichard Lowe mfence /* lighter weight than lock; xorq $0,(%rsp) */ 643*5d9d9091SRichard Lowe ret 644*5d9d9091SRichard Lowe SET_SIZE(membar_sync) 645*5d9d9091SRichard Lowe SET_SIZE(membar_exit) 646*5d9d9091SRichard Lowe SET_SIZE(membar_enter) 647*5d9d9091SRichard Lowe 648*5d9d9091SRichard Lowe ENTRY(membar_producer) 649*5d9d9091SRichard Lowe sfence 650*5d9d9091SRichard Lowe ret 651*5d9d9091SRichard Lowe SET_SIZE(membar_producer) 652*5d9d9091SRichard Lowe 653*5d9d9091SRichard Lowe ENTRY(membar_consumer) 654*5d9d9091SRichard Lowe lfence 655*5d9d9091SRichard Lowe ret 656*5d9d9091SRichard Lowe SET_SIZE(membar_consumer) 657*5d9d9091SRichard Lowe 658*5d9d9091SRichard Lowe/* 659*5d9d9091SRichard Lowe * thread_onproc() 660*5d9d9091SRichard Lowe * Set thread in onproc state for the specified CPU. 661*5d9d9091SRichard Lowe * Also set the thread lock pointer to the CPU's onproc lock. 662*5d9d9091SRichard Lowe * Since the new lock isn't held, the store ordering is important. 663*5d9d9091SRichard Lowe * If not done in assembler, the compiler could reorder the stores. 664*5d9d9091SRichard Lowe */ 665*5d9d9091SRichard Lowe 666*5d9d9091SRichard Lowe ENTRY(thread_onproc) 667*5d9d9091SRichard Lowe addq $CPU_THREAD_LOCK, %rsi /* pointer to disp_lock while running */ 668*5d9d9091SRichard Lowe movl $ONPROC_THREAD, T_STATE(%rdi) /* set state to TS_ONPROC */ 669*5d9d9091SRichard Lowe movq %rsi, T_LOCKP(%rdi) /* store new lock pointer */ 670*5d9d9091SRichard Lowe ret 671*5d9d9091SRichard Lowe SET_SIZE(thread_onproc) 672*5d9d9091SRichard Lowe 673*5d9d9091SRichard Lowe/* 674*5d9d9091SRichard Lowe * mutex_delay_default(void) 675*5d9d9091SRichard Lowe * Spins for approx a few hundred processor cycles and returns to caller. 676*5d9d9091SRichard Lowe */ 677*5d9d9091SRichard Lowe 678*5d9d9091SRichard Lowe ENTRY(mutex_delay_default) 679*5d9d9091SRichard Lowe movq $92,%r11 680*5d9d9091SRichard Lowe0: decq %r11 681*5d9d9091SRichard Lowe jg 0b 682*5d9d9091SRichard Lowe ret 683*5d9d9091SRichard Lowe SET_SIZE(mutex_delay_default) 684