1// See LICENSE for license details. 2 3#ifndef _RISCV_ATOMIC_H 4#define _RISCV_ATOMIC_H 5 6#include "config.h" 7#include "encoding.h" 8 9// Currently, interrupts are always disabled in M-mode. 10#define disable_irqsave() (0) 11#define enable_irqrestore(flags) ((void) (flags)) 12 13typedef struct { int lock; } spinlock_t; 14#define SPINLOCK_INIT {0} 15 16#define mb() asm volatile ("fence" ::: "memory") 17#define atomic_set(ptr, val) (*(volatile typeof(*(ptr)) *)(ptr) = val) 18#define atomic_read(ptr) (*(volatile typeof(*(ptr)) *)(ptr)) 19 20#ifdef __riscv_atomic 21# define atomic_add(ptr, inc) __sync_fetch_and_add(ptr, inc) 22# define atomic_or(ptr, inc) __sync_fetch_and_or(ptr, inc) 23# define atomic_swap(ptr, swp) __sync_lock_test_and_set(ptr, swp) 24# define atomic_cas(ptr, cmp, swp) __sync_val_compare_and_swap(ptr, cmp, swp) 25#else 26# define atomic_binop(ptr, inc, op) ({ \ 27 long flags = disable_irqsave(); \ 28 typeof(*(ptr)) res = atomic_read(ptr); \ 29 atomic_set(ptr, op); \ 30 enable_irqrestore(flags); \ 31 res; }) 32# define atomic_add(ptr, inc) atomic_binop(ptr, inc, res + (inc)) 33# define atomic_or(ptr, inc) atomic_binop(ptr, inc, res | (inc)) 34# define atomic_swap(ptr, inc) atomic_binop(ptr, inc, (inc)) 35# define atomic_cas(ptr, cmp, swp) ({ \ 36 long flags = disable_irqsave(); \ 37 typeof(*(ptr)) res = *(volatile typeof(*(ptr)) *)(ptr); \ 38 if (res == (cmp)) *(volatile typeof(ptr))(ptr) = (swp); \ 39 enable_irqrestore(flags); \ 40 res; }) 41#endif 42 43static inline int spinlock_trylock(spinlock_t* lock) 44{ 45 int res = atomic_swap(&lock->lock, -1); 46 mb(); 47 return res; 48} 49 50static inline void spinlock_lock(spinlock_t* lock) 51{ 52 do 53 { 54 while (atomic_read(&lock->lock)) 55 ; 56 } while (spinlock_trylock(lock)); 57} 58 59static inline void spinlock_unlock(spinlock_t* lock) 60{ 61 mb(); 62 atomic_set(&lock->lock,0); 63} 64 65static inline long spinlock_lock_irqsave(spinlock_t* lock) 66{ 67 long flags = disable_irqsave(); 68 spinlock_lock(lock); 69 return flags; 70} 71 72static inline void spinlock_unlock_irqrestore(spinlock_t* lock, long flags) 73{ 74 spinlock_unlock(lock); 75 enable_irqrestore(flags); 76} 77 78#endif 79