#include <sys/param.h>
#include <sys/systm.h>
#include <sys/witness.h>
#include <sys/_lock.h>
#include <machine/atomic.h>
#include <machine/intr.h>
#include <machine/psl.h>
#include <machine/cpu.h>
#include <ddb/db_output.h>
static __inline int
__cpu_cas(struct __mp_lock *mpl, volatile unsigned long *addr,
unsigned long old, unsigned long new)
{
volatile int *lock = (int *)(((vaddr_t)mpl->mpl_lock + 0xf) & ~0xf);
volatile register_t old_lock = 0;
int ret = 1;
asm volatile (
"ldcws 0(%2), %0"
: "=&r" (old_lock), "+m" (lock)
: "r" (lock)
);
if (old_lock == MPL_UNLOCKED) {
if (*addr == old) {
*addr = new;
asm("sync" ::: "memory");
ret = 0;
}
*lock = MPL_UNLOCKED;
}
return ret;
}
void
___mp_lock_init(struct __mp_lock *lock)
{
lock->mpl_lock[0] = MPL_UNLOCKED;
lock->mpl_lock[1] = MPL_UNLOCKED;
lock->mpl_lock[2] = MPL_UNLOCKED;
lock->mpl_lock[3] = MPL_UNLOCKED;
lock->mpl_cpu = NULL;
lock->mpl_count = 0;
}
#if defined(MP_LOCKDEBUG)
#ifndef DDB
#error "MP_LOCKDEBUG requires DDB"
#endif
#endif
static __inline void
__mp_lock_spin(struct __mp_lock *mpl)
{
#ifndef MP_LOCKDEBUG
while (mpl->mpl_count != 0)
CPU_BUSY_CYCLE();
#else
long nticks = __mp_lock_spinout;
while (mpl->mpl_count != 0) {
CPU_BUSY_CYCLE();
if (--nticks <= 0) {
db_printf("__mp_lock(%p): lock spun out", mpl);
db_enter();
nticks = __mp_lock_spinout;
}
}
#endif
}
void
__mp_lock(struct __mp_lock *mpl)
{
int s;
#ifdef WITNESS
if (!__mp_lock_held(mpl, curcpu()))
WITNESS_CHECKORDER(&mpl->mpl_lock_obj,
LOP_EXCLUSIVE | LOP_NEWORDER, NULL);
#endif
while (1) {
s = hppa_intr_disable();
if (__cpu_cas(mpl, &mpl->mpl_count, 0, 1) == 0) {
__asm volatile("sync" ::: "memory");
mpl->mpl_cpu = curcpu();
}
if (mpl->mpl_cpu == curcpu()) {
mpl->mpl_count++;
hppa_intr_enable(s);
break;
}
hppa_intr_enable(s);
__mp_lock_spin(mpl);
}
WITNESS_LOCK(&mpl->mpl_lock_obj, LOP_EXCLUSIVE);
}
void
__mp_unlock(struct __mp_lock *mpl)
{
int s;
#ifdef MP_LOCKDEBUG
if (mpl->mpl_cpu != curcpu()) {
db_printf("__mp_unlock(%p): lock not held - %p != %p\n",
mpl, mpl->mpl_cpu, curcpu());
db_enter();
}
#endif
WITNESS_UNLOCK(&mpl->mpl_lock_obj, LOP_EXCLUSIVE);
s = hppa_intr_disable();
if (--mpl->mpl_count == 1) {
mpl->mpl_cpu = NULL;
__asm volatile("sync" ::: "memory");
mpl->mpl_count = 0;
}
hppa_intr_enable(s);
}
int
__mp_release_all(struct __mp_lock *mpl)
{
int rv = mpl->mpl_count - 1;
int s;
#ifdef WITNESS
int i;
#endif
#ifdef MP_LOCKDEBUG
if (mpl->mpl_cpu != curcpu()) {
db_printf("__mp_release_all(%p): lock not held - %p != %p\n",
mpl, mpl->mpl_cpu, curcpu());
db_enter();
}
#endif
#ifdef WITNESS
for (i = 0; i < rv; i++)
WITNESS_UNLOCK(&mpl->mpl_lock_obj, LOP_EXCLUSIVE);
#endif
s = hppa_intr_disable();
mpl->mpl_cpu = NULL;
__asm volatile("sync" ::: "memory");
mpl->mpl_count = 0;
hppa_intr_enable(s);
return (rv);
}
void
__mp_acquire_count(struct __mp_lock *mpl, int count)
{
while (count--)
__mp_lock(mpl);
}
int
__mp_lock_held(struct __mp_lock *mpl, struct cpu_info *ci)
{
return mpl->mpl_cpu == ci;
}