2026-01-29 22:25:33 +08:00

93 lines
1.7 KiB
C

/* SPDX-License-Identifier: GPL-2.0 */
#ifndef __BTLOCK_H__
#define __BTLOCK_H__
#include <linux/delay.h>
#include <asm/timex.h>
union btlock {
char b[2];
unsigned int u;
};
/*
*wait delay us if lock failed.
*lock fail if another one get lock or both try get lock.
*c must compile b with byte access.
*/
static inline int btlock_lock(volatile union btlock *p, int n, unsigned char delay)
{
union btlock t, t1;
unsigned long flags;
unsigned long c0 = get_cycles(), c1;
if (n > 1)
return -1;
delay |= 0x80;
t1.u = 0;
t1.b[n] = delay;
while (1) {
local_irq_save(flags);
p->b[n] = delay;
t.u = p->u;
if (t.u == t1.u) {
wmb(); /* flush write out immediately */
local_irq_restore(flags);
return 0;
}
p->b[n] = 0;
t.u = p->u;
wmb(); /* flush write out immediately */
local_irq_restore(flags);
c1 = get_cycles();
if (c1 - c0 > *mscycles * 1000)
return -1;
ndelay(((t.b[1 - n] & 0x7f) + (c1 & 1)) * 100);
}
return 0;
}
static inline int btlock_trylock(volatile union btlock *p, int n, unsigned char delay)
{
union btlock t, t1;
unsigned long flags;
if (n > 1)
return -1;
delay |= 0x80;
t1.u = 0;
t1.b[n] = delay;
local_irq_save(flags);
p->b[n] = delay;
t.u = p->u;
if (t.u == t1.u) {
wmb(); /* flush write out immediately */
local_irq_restore(flags);
return 0;
}
p->b[n] = 0;
t.u = p->u;
wmb(); /* flush write out immediately */
local_irq_restore(flags);
ndelay(((t.b[1 - n] & 0x7f) + (get_cycles() & 1)) * 100);
return -1;
}
static inline int btlock_unlock(volatile union btlock *p, int n)
{
p->b[n] = 0;
wmb(); /* flush write out immediately */
return p->u;
}
static inline int btlock_islocked(volatile union btlock *p, int n)
{
union btlock t;
t.u = p->u;
return t.b[n] && !t.b[1 - n];
}
#endif