Index: sys/mips/include/atomic.h =================================================================== --- sys/mips/include/atomic.h +++ sys/mips/include/atomic.h @@ -36,6 +36,17 @@ #error this file needs sys/cdefs.h as a prerequisite #endif +#if defined(__mips_o32) && defined(_KERNEL) +#ifdef SMP +#error MIPS O32 SMP is no longer supported. +#endif + +#define _MIPS32_64BIT_ATOMICS +#endif + +#ifdef _MIPS32_64BIT_ATOMICS +#include +#endif #include /* @@ -52,6 +63,16 @@ #define __MIPS_PLATFORM_SYNC_NOPS "" #endif +#ifdef _MIPS32_64BIT_ATOMICS +#define __with_interrupts_disabled(expr) \ + do { \ + register_t s; \ + s = intr_disable(); \ + (expr); \ + intr_restore(s); \ + } while(0) +#endif + static __inline void mips_sync(void) { @@ -284,7 +305,88 @@ return result; } -#endif +#elif defined(_MIPS32_64BIT_ATOMICS) +static __inline void +atomic_set_64(volatile uint64_t *address, uint64_t setmask) +{ + __with_interrupts_disabled(*address |= setmask); +} + +static __inline void +atomic_clear_64(volatile uint64_t *address, uint64_t clearmask) +{ + __with_interrupts_disabled(*address &= ~clearmask); +} + +static __inline uint64_t +atomic_load_64(volatile uint64_t *p) +{ + uint64_t value; + + __with_interrupts_disabled(value = *p); + + return (value); +} + +static __inline void +atomic_store_64(volatile uint64_t *p, uint64_t value) +{ + __with_interrupts_disabled(*p = value); +} + +static __inline void +atomic_add_64(volatile u_int64_t *p, u_int64_t val) +{ + __with_interrupts_disabled(*p += val); +} + +static __inline void +atomic_subtract_64(volatile u_int64_t *p, u_int64_t val) +{ + __with_interrupts_disabled(*p -= val); +} + +static __inline uint64_t +atomic_swap_64(volatile uint64_t *p, uint64_t v) +{ + uint64_t value; + + __with_interrupts_disabled( + { + value = *p; + *p = v; + }); + return (value); +} + +static __inline uint64_t +atomic_readandclear_64(__volatile uint64_t *addr) +{ + uint64_t result; + + __with_interrupts_disabled( + { + result = *addr; + *addr = 0; + }); + + return (result); +} + +static __inline uint64_t +atomic_readandset_64(__volatile uint64_t *addr, uint64_t value) +{ + uint64_t result; + + __with_interrupts_disabled( + { + result = *addr; + *addr = value; + }); + + return (result); +} +#endif /* defined(__mips_n64) || defined(__mips_n32) */ #define ATOMIC_ACQ_REL(NAME, WIDTH) \ static __inline void \ @@ -314,7 +416,7 @@ ATOMIC_ACQ_REL(clear, 32) ATOMIC_ACQ_REL(add, 32) ATOMIC_ACQ_REL(subtract, 32) -#if defined(__mips_n64) || defined(__mips_n32) +#if defined(__mips_n64) || defined(__mips_n32) || defined(_MIPS32_64BIT_ATOMICS) ATOMIC_ACQ_REL(set, 64) ATOMIC_ACQ_REL(clear, 64) ATOMIC_ACQ_REL(add, 64) @@ -460,18 +562,6 @@ return (atomic_fcmpset_##WIDTH(p, cmpval, newval)); \ } -/* - * Atomically compare the value stored at *p with cmpval and if the - * two values are equal, update the value of *p with newval. Returns - * zero if the compare failed, nonzero otherwise. - */ -ATOMIC_CMPSET_ACQ_REL(8); -ATOMIC_CMPSET_ACQ_REL(16); -ATOMIC_CMPSET_ACQ_REL(32); -ATOMIC_FCMPSET_ACQ_REL(8); -ATOMIC_FCMPSET_ACQ_REL(16); -ATOMIC_FCMPSET_ACQ_REL(32); - /* * Atomically add the value of v to the integer pointed to by p and return * the previous value of *p. @@ -543,14 +633,6 @@ return ret; } -/* - * Atomically compare the value stored at *p with cmpval and if the - * two values are equal, update the value of *p with newval. Returns - * zero if the compare failed, nonzero otherwise. - */ -ATOMIC_CMPSET_ACQ_REL(64); -ATOMIC_FCMPSET_ACQ_REL(64); - /* * Atomically add the value of v to the integer pointed to by p and return * the previous value of *p. @@ -570,6 +652,70 @@ : "r" (v), "m" (*p)); return (value); } +#elif defined(_MIPS32_64BIT_ATOMICS) +static __inline int +atomic_cmpset_64(__volatile uint64_t *p, uint64_t cmpval, uint64_t newval) +{ + int ret; + + __with_interrupts_disabled( + { + if (*p == cmpval) { + *p = newval; + ret = 1; + } else { + ret = 0; + } + }); + return (ret); +} + +static __inline int +atomic_fcmpset_64(__volatile uint64_t *p, uint64_t *cmpval, uint64_t newval) +{ + int ret; + + __with_interrupts_disabled( + { + if (*p == *cmpval) { + *p = newval; + ret = 1; + } else { + *cmpval = *p; + ret = 0; + } + }); + return (ret); +} + +static __inline uint64_t +atomic_fetchadd_64(volatile uint64_t *p, uint64_t v) +{ + uint64_t value; + + __with_interrupts_disabled( + { + value = *p; + *p += v; + }); + return (value); +} +#endif + +/* + * Atomically compare the value stored at *p with cmpval and if the + * two values are equal, update the value of *p with newval. Returns + * zero if the compare failed, nonzero otherwise. + */ +ATOMIC_CMPSET_ACQ_REL(8); +ATOMIC_CMPSET_ACQ_REL(16); +ATOMIC_CMPSET_ACQ_REL(32); +ATOMIC_FCMPSET_ACQ_REL(8); +ATOMIC_FCMPSET_ACQ_REL(16); +ATOMIC_FCMPSET_ACQ_REL(32); +#if defined(__mips_n64) || defined(__mips_n32) || defined(_MIPS32_64BIT_ATOMICS) +ATOMIC_CMPSET_ACQ_REL(64); +ATOMIC_FCMPSET_ACQ_REL(64); #endif static __inline void @@ -844,4 +990,7 @@ #include +#undef __with_interrupts_disabled +#undef _MIPS32_64BIT_ATOMICS + #endif /* ! _MACHINE_ATOMIC_H_ */