162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-only */ 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Based on arch/arm/include/asm/barrier.h 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2012 ARM Ltd. 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci#ifndef __ASM_BARRIER_H 862306a36Sopenharmony_ci#define __ASM_BARRIER_H 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#ifndef __ASSEMBLY__ 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#include <linux/kasan-checks.h> 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#include <asm/alternative-macros.h> 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci#define __nops(n) ".rept " #n "\nnop\n.endr\n" 1762306a36Sopenharmony_ci#define nops(n) asm volatile(__nops(n)) 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci#define sev() asm volatile("sev" : : : "memory") 2062306a36Sopenharmony_ci#define wfe() asm volatile("wfe" : : : "memory") 2162306a36Sopenharmony_ci#define wfet(val) asm volatile("msr s0_3_c1_c0_0, %0" \ 2262306a36Sopenharmony_ci : : "r" (val) : "memory") 2362306a36Sopenharmony_ci#define wfi() asm volatile("wfi" : : : "memory") 2462306a36Sopenharmony_ci#define wfit(val) asm volatile("msr s0_3_c1_c0_1, %0" \ 2562306a36Sopenharmony_ci : : "r" (val) : "memory") 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci#define isb() asm volatile("isb" : : : "memory") 2862306a36Sopenharmony_ci#define dmb(opt) asm volatile("dmb " #opt : : : "memory") 2962306a36Sopenharmony_ci#define dsb(opt) asm volatile("dsb " #opt : : : "memory") 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci#define psb_csync() asm volatile("hint #17" : : : "memory") 3262306a36Sopenharmony_ci#define __tsb_csync() asm volatile("hint #18" : : : "memory") 3362306a36Sopenharmony_ci#define csdb() asm volatile("hint #20" : : : "memory") 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci/* 3662306a36Sopenharmony_ci * Data Gathering Hint: 3762306a36Sopenharmony_ci * This instruction prevents merging memory accesses with Normal-NC or 3862306a36Sopenharmony_ci * Device-GRE attributes before the hint instruction with any memory accesses 3962306a36Sopenharmony_ci * appearing after the hint instruction. 4062306a36Sopenharmony_ci */ 4162306a36Sopenharmony_ci#define dgh() asm volatile("hint #6" : : : "memory") 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci#ifdef CONFIG_ARM64_PSEUDO_NMI 4462306a36Sopenharmony_ci#define pmr_sync() \ 4562306a36Sopenharmony_ci do { \ 4662306a36Sopenharmony_ci asm volatile( \ 4762306a36Sopenharmony_ci ALTERNATIVE_CB("dsb sy", \ 4862306a36Sopenharmony_ci ARM64_HAS_GIC_PRIO_RELAXED_SYNC, \ 4962306a36Sopenharmony_ci alt_cb_patch_nops) \ 5062306a36Sopenharmony_ci ); \ 5162306a36Sopenharmony_ci } while(0) 5262306a36Sopenharmony_ci#else 5362306a36Sopenharmony_ci#define pmr_sync() do {} while (0) 5462306a36Sopenharmony_ci#endif 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci#define __mb() dsb(sy) 5762306a36Sopenharmony_ci#define __rmb() dsb(ld) 5862306a36Sopenharmony_ci#define __wmb() dsb(st) 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci#define __dma_mb() dmb(osh) 6162306a36Sopenharmony_ci#define __dma_rmb() dmb(oshld) 6262306a36Sopenharmony_ci#define __dma_wmb() dmb(oshst) 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci#define io_stop_wc() dgh() 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci#define tsb_csync() \ 6762306a36Sopenharmony_ci do { \ 6862306a36Sopenharmony_ci /* \ 6962306a36Sopenharmony_ci * CPUs affected by Arm Erratum 2054223 or 2067961 needs \ 7062306a36Sopenharmony_ci * another TSB to ensure the trace is flushed. The barriers \ 7162306a36Sopenharmony_ci * don't have to be strictly back to back, as long as the \ 7262306a36Sopenharmony_ci * CPU is in trace prohibited state. \ 7362306a36Sopenharmony_ci */ \ 7462306a36Sopenharmony_ci if (cpus_have_final_cap(ARM64_WORKAROUND_TSB_FLUSH_FAILURE)) \ 7562306a36Sopenharmony_ci __tsb_csync(); \ 7662306a36Sopenharmony_ci __tsb_csync(); \ 7762306a36Sopenharmony_ci } while (0) 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci/* 8062306a36Sopenharmony_ci * Generate a mask for array_index__nospec() that is ~0UL when 0 <= idx < sz 8162306a36Sopenharmony_ci * and 0 otherwise. 8262306a36Sopenharmony_ci */ 8362306a36Sopenharmony_ci#define array_index_mask_nospec array_index_mask_nospec 8462306a36Sopenharmony_cistatic inline unsigned long array_index_mask_nospec(unsigned long idx, 8562306a36Sopenharmony_ci unsigned long sz) 8662306a36Sopenharmony_ci{ 8762306a36Sopenharmony_ci unsigned long mask; 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci asm volatile( 9062306a36Sopenharmony_ci " cmp %1, %2\n" 9162306a36Sopenharmony_ci " sbc %0, xzr, xzr\n" 9262306a36Sopenharmony_ci : "=r" (mask) 9362306a36Sopenharmony_ci : "r" (idx), "Ir" (sz) 9462306a36Sopenharmony_ci : "cc"); 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci csdb(); 9762306a36Sopenharmony_ci return mask; 9862306a36Sopenharmony_ci} 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci/* 10162306a36Sopenharmony_ci * Ensure that reads of the counter are treated the same as memory reads 10262306a36Sopenharmony_ci * for the purposes of ordering by subsequent memory barriers. 10362306a36Sopenharmony_ci * 10462306a36Sopenharmony_ci * This insanity brought to you by speculative system register reads, 10562306a36Sopenharmony_ci * out-of-order memory accesses, sequence locks and Thomas Gleixner. 10662306a36Sopenharmony_ci * 10762306a36Sopenharmony_ci * https://lore.kernel.org/r/alpine.DEB.2.21.1902081950260.1662@nanos.tec.linutronix.de/ 10862306a36Sopenharmony_ci */ 10962306a36Sopenharmony_ci#define arch_counter_enforce_ordering(val) do { \ 11062306a36Sopenharmony_ci u64 tmp, _val = (val); \ 11162306a36Sopenharmony_ci \ 11262306a36Sopenharmony_ci asm volatile( \ 11362306a36Sopenharmony_ci " eor %0, %1, %1\n" \ 11462306a36Sopenharmony_ci " add %0, sp, %0\n" \ 11562306a36Sopenharmony_ci " ldr xzr, [%0]" \ 11662306a36Sopenharmony_ci : "=r" (tmp) : "r" (_val)); \ 11762306a36Sopenharmony_ci} while (0) 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci#define __smp_mb() dmb(ish) 12062306a36Sopenharmony_ci#define __smp_rmb() dmb(ishld) 12162306a36Sopenharmony_ci#define __smp_wmb() dmb(ishst) 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci#define __smp_store_release(p, v) \ 12462306a36Sopenharmony_cido { \ 12562306a36Sopenharmony_ci typeof(p) __p = (p); \ 12662306a36Sopenharmony_ci union { __unqual_scalar_typeof(*p) __val; char __c[1]; } __u = \ 12762306a36Sopenharmony_ci { .__val = (__force __unqual_scalar_typeof(*p)) (v) }; \ 12862306a36Sopenharmony_ci compiletime_assert_atomic_type(*p); \ 12962306a36Sopenharmony_ci kasan_check_write(__p, sizeof(*p)); \ 13062306a36Sopenharmony_ci switch (sizeof(*p)) { \ 13162306a36Sopenharmony_ci case 1: \ 13262306a36Sopenharmony_ci asm volatile ("stlrb %w1, %0" \ 13362306a36Sopenharmony_ci : "=Q" (*__p) \ 13462306a36Sopenharmony_ci : "rZ" (*(__u8 *)__u.__c) \ 13562306a36Sopenharmony_ci : "memory"); \ 13662306a36Sopenharmony_ci break; \ 13762306a36Sopenharmony_ci case 2: \ 13862306a36Sopenharmony_ci asm volatile ("stlrh %w1, %0" \ 13962306a36Sopenharmony_ci : "=Q" (*__p) \ 14062306a36Sopenharmony_ci : "rZ" (*(__u16 *)__u.__c) \ 14162306a36Sopenharmony_ci : "memory"); \ 14262306a36Sopenharmony_ci break; \ 14362306a36Sopenharmony_ci case 4: \ 14462306a36Sopenharmony_ci asm volatile ("stlr %w1, %0" \ 14562306a36Sopenharmony_ci : "=Q" (*__p) \ 14662306a36Sopenharmony_ci : "rZ" (*(__u32 *)__u.__c) \ 14762306a36Sopenharmony_ci : "memory"); \ 14862306a36Sopenharmony_ci break; \ 14962306a36Sopenharmony_ci case 8: \ 15062306a36Sopenharmony_ci asm volatile ("stlr %x1, %0" \ 15162306a36Sopenharmony_ci : "=Q" (*__p) \ 15262306a36Sopenharmony_ci : "rZ" (*(__u64 *)__u.__c) \ 15362306a36Sopenharmony_ci : "memory"); \ 15462306a36Sopenharmony_ci break; \ 15562306a36Sopenharmony_ci } \ 15662306a36Sopenharmony_ci} while (0) 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci#define __smp_load_acquire(p) \ 15962306a36Sopenharmony_ci({ \ 16062306a36Sopenharmony_ci union { __unqual_scalar_typeof(*p) __val; char __c[1]; } __u; \ 16162306a36Sopenharmony_ci typeof(p) __p = (p); \ 16262306a36Sopenharmony_ci compiletime_assert_atomic_type(*p); \ 16362306a36Sopenharmony_ci kasan_check_read(__p, sizeof(*p)); \ 16462306a36Sopenharmony_ci switch (sizeof(*p)) { \ 16562306a36Sopenharmony_ci case 1: \ 16662306a36Sopenharmony_ci asm volatile ("ldarb %w0, %1" \ 16762306a36Sopenharmony_ci : "=r" (*(__u8 *)__u.__c) \ 16862306a36Sopenharmony_ci : "Q" (*__p) : "memory"); \ 16962306a36Sopenharmony_ci break; \ 17062306a36Sopenharmony_ci case 2: \ 17162306a36Sopenharmony_ci asm volatile ("ldarh %w0, %1" \ 17262306a36Sopenharmony_ci : "=r" (*(__u16 *)__u.__c) \ 17362306a36Sopenharmony_ci : "Q" (*__p) : "memory"); \ 17462306a36Sopenharmony_ci break; \ 17562306a36Sopenharmony_ci case 4: \ 17662306a36Sopenharmony_ci asm volatile ("ldar %w0, %1" \ 17762306a36Sopenharmony_ci : "=r" (*(__u32 *)__u.__c) \ 17862306a36Sopenharmony_ci : "Q" (*__p) : "memory"); \ 17962306a36Sopenharmony_ci break; \ 18062306a36Sopenharmony_ci case 8: \ 18162306a36Sopenharmony_ci asm volatile ("ldar %0, %1" \ 18262306a36Sopenharmony_ci : "=r" (*(__u64 *)__u.__c) \ 18362306a36Sopenharmony_ci : "Q" (*__p) : "memory"); \ 18462306a36Sopenharmony_ci break; \ 18562306a36Sopenharmony_ci } \ 18662306a36Sopenharmony_ci (typeof(*p))__u.__val; \ 18762306a36Sopenharmony_ci}) 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci#define smp_cond_load_relaxed(ptr, cond_expr) \ 19062306a36Sopenharmony_ci({ \ 19162306a36Sopenharmony_ci typeof(ptr) __PTR = (ptr); \ 19262306a36Sopenharmony_ci __unqual_scalar_typeof(*ptr) VAL; \ 19362306a36Sopenharmony_ci for (;;) { \ 19462306a36Sopenharmony_ci VAL = READ_ONCE(*__PTR); \ 19562306a36Sopenharmony_ci if (cond_expr) \ 19662306a36Sopenharmony_ci break; \ 19762306a36Sopenharmony_ci __cmpwait_relaxed(__PTR, VAL); \ 19862306a36Sopenharmony_ci } \ 19962306a36Sopenharmony_ci (typeof(*ptr))VAL; \ 20062306a36Sopenharmony_ci}) 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci#define smp_cond_load_acquire(ptr, cond_expr) \ 20362306a36Sopenharmony_ci({ \ 20462306a36Sopenharmony_ci typeof(ptr) __PTR = (ptr); \ 20562306a36Sopenharmony_ci __unqual_scalar_typeof(*ptr) VAL; \ 20662306a36Sopenharmony_ci for (;;) { \ 20762306a36Sopenharmony_ci VAL = smp_load_acquire(__PTR); \ 20862306a36Sopenharmony_ci if (cond_expr) \ 20962306a36Sopenharmony_ci break; \ 21062306a36Sopenharmony_ci __cmpwait_relaxed(__PTR, VAL); \ 21162306a36Sopenharmony_ci } \ 21262306a36Sopenharmony_ci (typeof(*ptr))VAL; \ 21362306a36Sopenharmony_ci}) 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci#include <asm-generic/barrier.h> 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci#endif /* __ASSEMBLY__ */ 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci#endif /* __ASM_BARRIER_H */ 220