/* SPDX-License-Identifier: GPL-2.0-only */1/*2* Based on arch/arm/include/asm/barrier.h3*4* Copyright (C) 2012 ARM Ltd.5* Copyright (C) 2013 Regents of the University of California6* Copyright (C) 2017 SiFive7*/89#ifndef _ASM_RISCV_BARRIER_H10#define _ASM_RISCV_BARRIER_H1112#ifndef __ASSEMBLY__13#include <asm/cmpxchg.h>14#include <asm/fence.h>1516/* These barriers need to enforce ordering on both devices or memory. */17#define __mb() RISCV_FENCE(iorw, iorw)18#define __rmb() RISCV_FENCE(ir, ir)19#define __wmb() RISCV_FENCE(ow, ow)2021/* These barriers do not need to enforce ordering on devices, just memory. */22#define __smp_mb() RISCV_FENCE(rw, rw)23#define __smp_rmb() RISCV_FENCE(r, r)24#define __smp_wmb() RISCV_FENCE(w, w)2526/*27* This is a very specific barrier: it's currently only used in two places in28* the kernel, both in the scheduler. See include/linux/spinlock.h for the two29* orderings it guarantees, but the "critical section is RCsc" guarantee30* mandates a barrier on RISC-V. The sequence looks like:31*32* lr.aq lock33* sc lock <= LOCKED34* smp_mb__after_spinlock()35* // critical section36* lr lock37* sc.rl lock <= UNLOCKED38*39* The AQ/RL pair provides a RCpc critical section, but there's not really any40* way we can take advantage of that here because the ordering is only enforced41* on that one lock. Thus, we're just doing a full fence.42*43* Since we allow writeX to be called from preemptive regions we need at least44* an "o" in the predecessor set to ensure device writes are visible before the45* task is marked as available for scheduling on a new hart. While I don't see46* any concrete reason we need a full IO fence, it seems safer to just upgrade47* this in order to avoid any IO crossing a scheduling boundary. In both48* instances the scheduler pairs this with an mb(), so nothing is necessary on49* the new hart.50*/51#define smp_mb__after_spinlock() RISCV_FENCE(iorw, iorw)5253#define __smp_store_release(p, v) \54do { \55compiletime_assert_atomic_type(*p); \56RISCV_FENCE(rw, w); \57WRITE_ONCE(*p, v); \58} while (0)5960#define __smp_load_acquire(p) \61({ \62typeof(*p) ___p1 = READ_ONCE(*p); \63compiletime_assert_atomic_type(*p); \64RISCV_FENCE(r, rw); \65___p1; \66})6768#ifdef CONFIG_RISCV_ISA_ZAWRS69#define smp_cond_load_relaxed(ptr, cond_expr) ({ \70typeof(ptr) __PTR = (ptr); \71__unqual_scalar_typeof(*ptr) VAL; \72for (;;) { \73VAL = READ_ONCE(*__PTR); \74if (cond_expr) \75break; \76__cmpwait_relaxed(ptr, VAL); \77} \78(typeof(*ptr))VAL; \79})80#endif8182#include <asm-generic/barrier.h>8384#endif /* __ASSEMBLY__ */8586#endif /* _ASM_RISCV_BARRIER_H */878889