#include "opt_cputype.h"
#include "opt_lockdebug.h"
#include <sys/errno.h>
#include <machine/asm.h>
RCSID("$NetBSD: lock_stubs_llsc.S,v 1.18 2023/12/05 17:38:40 andvar Exp $")
#include "assym.h"
#if defined(MIPS3)
.set mips3
#endif
#if defined(MIPS32)
.set mips32
#endif
#if defined(MIPS64)
.set mips64
#endif
.set noreorder
.set noat
STATIC_LEAF(llsc_atomic_cas_ulong)
LLSCSYNC
1:
LONG_LL t0, (a0)
bne t0, a1, 2f
move t1, a2
LONG_SC t1, (a0)
beqz t1, 1b
nop
SYNC_ACQ
j ra
move v0, a1
2:
j ra
move v0, t0
END(llsc_atomic_cas_ulong)
STATIC_LEAF(llsc_atomic_cas_uint)
LLSCSYNC
1:
INT_LL t0, (a0)
bne t0, a1, 2f
move t1, a2
INT_SC t1, (a0)
beqz t1, 1b
nop
SYNC_ACQ
j ra
move v0, a1
2:
j ra
move v0, t0
END(llsc_atomic_cas_uint)
STATIC_LEAF(llsc_ucas_32)
.set at
PTR_LA v0, _C_LABEL(llsc_ucaserr)
.set noat
PTR_L v1, L_PCB(MIPS_CURLWP)
PTR_S v0, PCB_ONFAULT(v1)
bltz a0, _C_LABEL(llsc_ucaserr)
nop
move v0, zero
SYNC_REL
LLSCSYNC
1: ll t0, 0(a0)
bne t0, a1, 2f
move t1, a2
sc t1, 0(a0)
beqz t1, 1b
nop
SYNC_ACQ
2: PTR_S zero, PCB_ONFAULT(v1)
j ra
sw t0, 0(a3)
END(llsc_ucas_32)
#ifdef _LP64
STATIC_LEAF(llsc_ucas_64)
.set at
PTR_LA v0, _C_LABEL(llsc_ucaserr)
.set noat
PTR_L v1, L_PCB(MIPS_CURLWP)
PTR_S v0, PCB_ONFAULT(v1)
bltz a0, _C_LABEL(llsc_ucaserr)
nop
move v0, zero
SYNC_REL
LLSCSYNC
1: lld t0, 0(a0)
bne t0, a1, 2f
move t1, a2
scd t1, 0(a0)
beqz t1, 1b
nop
SYNC_ACQ
2: PTR_S zero, PCB_ONFAULT(v1)
j ra
sd t0, 0(a3)
END(llsc_ucas_64)
#endif
STATIC_LEAF_NOPROFILE(llsc_ucaserr)
PTR_S zero, PCB_ONFAULT(v1) # reset fault handler
j ra
li v0, EFAULT # return EFAULT on error
END(llsc_ucaserr)
#ifndef LOCKDEBUG
STATIC_LEAF(llsc_mutex_enter)
LLSCSYNC
PTR_LL t0, MTX_OWNER(a0)
1:
bnez t0, 2f
move t2, MIPS_CURLWP
PTR_SC t2, MTX_OWNER(a0)
beqz t2, 1b
PTR_LL t0, MTX_OWNER(a0)
j ra
BDSYNC_ACQ
2:
j _C_LABEL(mutex_vector_enter)
nop
END(llsc_mutex_enter)
STATIC_LEAF(llsc_mutex_exit)
SYNC_REL
LLSCSYNC
PTR_LL t0, MTX_OWNER(a0)
1:
bne t0, MIPS_CURLWP, 2f
move t2, zero
PTR_SC t2, MTX_OWNER(a0)
beqz t2, 1b
PTR_LL t0, MTX_OWNER(a0)
j ra
BDSYNC_PLUNGER
2:
j _C_LABEL(mutex_vector_exit)
nop
END(llsc_mutex_exit)
STATIC_NESTED(llsc_mutex_spin_enter, CALLFRAME_SIZ, ra)
move t0, a0
PTR_L t2, L_CPU(MIPS_CURLWP)
INT_L a0, MTX_IPL(t0)
#ifdef PARANOIA
INT_L ta1, CPU_INFO_CPL(t2)
#endif
move t3, ra # need to save ra
jal _C_LABEL(splraise)
nop
move ra, t3 # move ra back
#ifdef PARANOIA
10: bne ta1, v0, 10b # loop forever if v0 != ta1
nop
#endif
1:
INT_L ta2, CPU_INFO_MTX_COUNT(t2)
INT_ADDU ta3, ta2, -1
INT_S ta3, CPU_INFO_MTX_COUNT(t2)
bltz ta2, 2f
nop
INT_S v0, CPU_INFO_MTX_OLDSPL(t2)
2:
#ifdef PARANOIA
INT_L ta1, CPU_INFO_MTX_OLDSPL(t2)
INT_L ta2, CPU_INFO_CPL(t2) # get updated CPL
sltu v0, ta2, ta0 # v0 = cpl < mtx_ipl
sltu v1, ta2, ta1 # v1 = cpl < oldspl
sll v0, 1
or v0, v1
12: bnez v0, 12b # loop forever if any are true
nop
#endif
LLSCSYNC
INT_LL t3, MTX_LOCK(t0)
3:
bnez t3, 4f
li t1, 1
INT_SC t1, MTX_LOCK(t0)
beqz t1, 3b
INT_LL t3, MTX_LOCK(t0)
j ra
BDSYNC_ACQ
4:
j _C_LABEL(mutex_spin_retry)
move a0, t0
END(llsc_mutex_spin_enter)
LEAF(llsc_mutex_spin_exit)
SYNC_REL
PTR_L t2, L_CPU(MIPS_CURLWP)
#if defined(DIAGNOSTIC)
INT_L t0, MTX_LOCK(a0)
beqz t0, 2f
nop
#endif
INT_S zero, MTX_LOCK(a0)
#ifdef PARANOIA
INT_L a2, MTX_IPL(a0)
#endif
INT_L a0, CPU_INFO_MTX_OLDSPL(t2)
INT_L t0, CPU_INFO_MTX_COUNT(t2)
INT_ADDU t0, t0, 1
INT_S t0, CPU_INFO_MTX_COUNT(t2)
INT_L a1, CPU_INFO_CPL(t2)
#ifdef PARANOIA
sltu v0, a1, a2 # v0 = cpl < mtx_ipl
sltu v1, a1, a0 # v1 = cpl < oldspl
sll v0, 1
or v0, v1
12: bnez v0, 12b # loop forever if either is true
nop
#endif
beq a0, a1, 1f # if oldspl == cpl
nop # no reason to drop ipl
bltz t0, 1f # there are still holders
nop # so don't drop IPL
#ifdef PARANOIA
sltiu v0, a0, IPL_HIGH+1
13: beqz v0, 13b # loop forever if ipl > IPL_HIGH
nop
#endif
j _C_LABEL(splx)
BDSYNC_PLUNGER
1:
j ra
BDSYNC_PLUNGER
#if defined(DIAGNOSTIC)
2:
j _C_LABEL(mutex_vector_exit)
nop
#endif
END(llsc_mutex_spin_exit)
#endif
.rdata
EXPORT_OBJECT(mips_llsc_locore_atomicvec)
PTR_WORD llsc_atomic_cas_uint
PTR_WORD llsc_atomic_cas_ulong
PTR_WORD llsc_ucas_32
#ifdef _LP64
PTR_WORD llsc_ucas_64
#else
PTR_WORD 0
#endif
#ifdef LOCKDEBUG
PTR_WORD mutex_vector_enter
PTR_WORD mutex_vector_exit
PTR_WORD mutex_vector_enter
PTR_WORD mutex_vector_exit
#else
PTR_WORD llsc_mutex_enter
PTR_WORD llsc_mutex_exit
PTR_WORD llsc_mutex_spin_enter
PTR_WORD llsc_mutex_spin_exit
#endif