1*4882a593Smuzhiyun /* SPDX-License-Identifier: GPL-2.0-only */
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Based on arch/arm/include/asm/barrier.h
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Copyright (C) 2012 ARM Ltd.
6*4882a593Smuzhiyun */
7*4882a593Smuzhiyun #ifndef __ASM_BARRIER_H
8*4882a593Smuzhiyun #define __ASM_BARRIER_H
9*4882a593Smuzhiyun
10*4882a593Smuzhiyun #ifndef __ASSEMBLY__
11*4882a593Smuzhiyun
12*4882a593Smuzhiyun #include <linux/kasan-checks.h>
13*4882a593Smuzhiyun
14*4882a593Smuzhiyun #define __nops(n) ".rept " #n "\nnop\n.endr\n"
15*4882a593Smuzhiyun #define nops(n) asm volatile(__nops(n))
16*4882a593Smuzhiyun
17*4882a593Smuzhiyun #define sev() asm volatile("sev" : : : "memory")
18*4882a593Smuzhiyun #define wfe() asm volatile("wfe" : : : "memory")
19*4882a593Smuzhiyun #define wfi() asm volatile("wfi" : : : "memory")
20*4882a593Smuzhiyun
21*4882a593Smuzhiyun #define isb() asm volatile("isb" : : : "memory")
22*4882a593Smuzhiyun #define dmb(opt) asm volatile("dmb " #opt : : : "memory")
23*4882a593Smuzhiyun #define dsb(opt) asm volatile("dsb " #opt : : : "memory")
24*4882a593Smuzhiyun
25*4882a593Smuzhiyun #define psb_csync() asm volatile("hint #17" : : : "memory")
26*4882a593Smuzhiyun #define __tsb_csync() asm volatile("hint #18" : : : "memory")
27*4882a593Smuzhiyun #define csdb() asm volatile("hint #20" : : : "memory")
28*4882a593Smuzhiyun
29*4882a593Smuzhiyun #define spec_bar() asm volatile(ALTERNATIVE("dsb nsh\nisb\n", \
30*4882a593Smuzhiyun SB_BARRIER_INSN"nop\n", \
31*4882a593Smuzhiyun ARM64_HAS_SB))
32*4882a593Smuzhiyun
33*4882a593Smuzhiyun #ifdef CONFIG_ARM64_PSEUDO_NMI
34*4882a593Smuzhiyun #define pmr_sync() \
35*4882a593Smuzhiyun do { \
36*4882a593Smuzhiyun extern struct static_key_false gic_pmr_sync; \
37*4882a593Smuzhiyun \
38*4882a593Smuzhiyun if (static_branch_unlikely(&gic_pmr_sync)) \
39*4882a593Smuzhiyun dsb(sy); \
40*4882a593Smuzhiyun } while(0)
41*4882a593Smuzhiyun #else
42*4882a593Smuzhiyun #define pmr_sync() do {} while (0)
43*4882a593Smuzhiyun #endif
44*4882a593Smuzhiyun
45*4882a593Smuzhiyun #define mb() dsb(sy)
46*4882a593Smuzhiyun #define rmb() dsb(ld)
47*4882a593Smuzhiyun #define wmb() dsb(st)
48*4882a593Smuzhiyun
49*4882a593Smuzhiyun #define dma_mb() dmb(osh)
50*4882a593Smuzhiyun #define dma_rmb() dmb(oshld)
51*4882a593Smuzhiyun #define dma_wmb() dmb(oshst)
52*4882a593Smuzhiyun
53*4882a593Smuzhiyun
54*4882a593Smuzhiyun #define tsb_csync() \
55*4882a593Smuzhiyun do { \
56*4882a593Smuzhiyun /* \
57*4882a593Smuzhiyun * CPUs affected by Arm Erratum 2054223 or 2067961 needs \
58*4882a593Smuzhiyun * another TSB to ensure the trace is flushed. The barriers \
59*4882a593Smuzhiyun * don't have to be strictly back to back, as long as the \
60*4882a593Smuzhiyun * CPU is in trace prohibited state. \
61*4882a593Smuzhiyun */ \
62*4882a593Smuzhiyun if (cpus_have_final_cap(ARM64_WORKAROUND_TSB_FLUSH_FAILURE)) \
63*4882a593Smuzhiyun __tsb_csync(); \
64*4882a593Smuzhiyun __tsb_csync(); \
65*4882a593Smuzhiyun } while (0)
66*4882a593Smuzhiyun
67*4882a593Smuzhiyun /*
68*4882a593Smuzhiyun * Generate a mask for array_index__nospec() that is ~0UL when 0 <= idx < sz
69*4882a593Smuzhiyun * and 0 otherwise.
70*4882a593Smuzhiyun */
71*4882a593Smuzhiyun #define array_index_mask_nospec array_index_mask_nospec
array_index_mask_nospec(unsigned long idx,unsigned long sz)72*4882a593Smuzhiyun static inline unsigned long array_index_mask_nospec(unsigned long idx,
73*4882a593Smuzhiyun unsigned long sz)
74*4882a593Smuzhiyun {
75*4882a593Smuzhiyun unsigned long mask;
76*4882a593Smuzhiyun
77*4882a593Smuzhiyun asm volatile(
78*4882a593Smuzhiyun " cmp %1, %2\n"
79*4882a593Smuzhiyun " sbc %0, xzr, xzr\n"
80*4882a593Smuzhiyun : "=r" (mask)
81*4882a593Smuzhiyun : "r" (idx), "Ir" (sz)
82*4882a593Smuzhiyun : "cc");
83*4882a593Smuzhiyun
84*4882a593Smuzhiyun csdb();
85*4882a593Smuzhiyun return mask;
86*4882a593Smuzhiyun }
87*4882a593Smuzhiyun
88*4882a593Smuzhiyun /*
89*4882a593Smuzhiyun * Ensure that reads of the counter are treated the same as memory reads
90*4882a593Smuzhiyun * for the purposes of ordering by subsequent memory barriers.
91*4882a593Smuzhiyun *
92*4882a593Smuzhiyun * This insanity brought to you by speculative system register reads,
93*4882a593Smuzhiyun * out-of-order memory accesses, sequence locks and Thomas Gleixner.
94*4882a593Smuzhiyun *
95*4882a593Smuzhiyun * http://lists.infradead.org/pipermail/linux-arm-kernel/2019-February/631195.html
96*4882a593Smuzhiyun */
97*4882a593Smuzhiyun #define arch_counter_enforce_ordering(val) do { \
98*4882a593Smuzhiyun u64 tmp, _val = (val); \
99*4882a593Smuzhiyun \
100*4882a593Smuzhiyun asm volatile( \
101*4882a593Smuzhiyun " eor %0, %1, %1\n" \
102*4882a593Smuzhiyun " add %0, sp, %0\n" \
103*4882a593Smuzhiyun " ldr xzr, [%0]" \
104*4882a593Smuzhiyun : "=r" (tmp) : "r" (_val)); \
105*4882a593Smuzhiyun } while (0)
106*4882a593Smuzhiyun
107*4882a593Smuzhiyun #define __smp_mb() dmb(ish)
108*4882a593Smuzhiyun #define __smp_rmb() dmb(ishld)
109*4882a593Smuzhiyun #define __smp_wmb() dmb(ishst)
110*4882a593Smuzhiyun
111*4882a593Smuzhiyun #define __smp_store_release(p, v) \
112*4882a593Smuzhiyun do { \
113*4882a593Smuzhiyun typeof(p) __p = (p); \
114*4882a593Smuzhiyun union { __unqual_scalar_typeof(*p) __val; char __c[1]; } __u = \
115*4882a593Smuzhiyun { .__val = (__force __unqual_scalar_typeof(*p)) (v) }; \
116*4882a593Smuzhiyun compiletime_assert_atomic_type(*p); \
117*4882a593Smuzhiyun kasan_check_write(__p, sizeof(*p)); \
118*4882a593Smuzhiyun switch (sizeof(*p)) { \
119*4882a593Smuzhiyun case 1: \
120*4882a593Smuzhiyun asm volatile ("stlrb %w1, %0" \
121*4882a593Smuzhiyun : "=Q" (*__p) \
122*4882a593Smuzhiyun : "r" (*(__u8 *)__u.__c) \
123*4882a593Smuzhiyun : "memory"); \
124*4882a593Smuzhiyun break; \
125*4882a593Smuzhiyun case 2: \
126*4882a593Smuzhiyun asm volatile ("stlrh %w1, %0" \
127*4882a593Smuzhiyun : "=Q" (*__p) \
128*4882a593Smuzhiyun : "r" (*(__u16 *)__u.__c) \
129*4882a593Smuzhiyun : "memory"); \
130*4882a593Smuzhiyun break; \
131*4882a593Smuzhiyun case 4: \
132*4882a593Smuzhiyun asm volatile ("stlr %w1, %0" \
133*4882a593Smuzhiyun : "=Q" (*__p) \
134*4882a593Smuzhiyun : "r" (*(__u32 *)__u.__c) \
135*4882a593Smuzhiyun : "memory"); \
136*4882a593Smuzhiyun break; \
137*4882a593Smuzhiyun case 8: \
138*4882a593Smuzhiyun asm volatile ("stlr %1, %0" \
139*4882a593Smuzhiyun : "=Q" (*__p) \
140*4882a593Smuzhiyun : "r" (*(__u64 *)__u.__c) \
141*4882a593Smuzhiyun : "memory"); \
142*4882a593Smuzhiyun break; \
143*4882a593Smuzhiyun } \
144*4882a593Smuzhiyun } while (0)
145*4882a593Smuzhiyun
146*4882a593Smuzhiyun #define __smp_load_acquire(p) \
147*4882a593Smuzhiyun ({ \
148*4882a593Smuzhiyun union { __unqual_scalar_typeof(*p) __val; char __c[1]; } __u; \
149*4882a593Smuzhiyun typeof(p) __p = (p); \
150*4882a593Smuzhiyun compiletime_assert_atomic_type(*p); \
151*4882a593Smuzhiyun kasan_check_read(__p, sizeof(*p)); \
152*4882a593Smuzhiyun switch (sizeof(*p)) { \
153*4882a593Smuzhiyun case 1: \
154*4882a593Smuzhiyun asm volatile ("ldarb %w0, %1" \
155*4882a593Smuzhiyun : "=r" (*(__u8 *)__u.__c) \
156*4882a593Smuzhiyun : "Q" (*__p) : "memory"); \
157*4882a593Smuzhiyun break; \
158*4882a593Smuzhiyun case 2: \
159*4882a593Smuzhiyun asm volatile ("ldarh %w0, %1" \
160*4882a593Smuzhiyun : "=r" (*(__u16 *)__u.__c) \
161*4882a593Smuzhiyun : "Q" (*__p) : "memory"); \
162*4882a593Smuzhiyun break; \
163*4882a593Smuzhiyun case 4: \
164*4882a593Smuzhiyun asm volatile ("ldar %w0, %1" \
165*4882a593Smuzhiyun : "=r" (*(__u32 *)__u.__c) \
166*4882a593Smuzhiyun : "Q" (*__p) : "memory"); \
167*4882a593Smuzhiyun break; \
168*4882a593Smuzhiyun case 8: \
169*4882a593Smuzhiyun asm volatile ("ldar %0, %1" \
170*4882a593Smuzhiyun : "=r" (*(__u64 *)__u.__c) \
171*4882a593Smuzhiyun : "Q" (*__p) : "memory"); \
172*4882a593Smuzhiyun break; \
173*4882a593Smuzhiyun } \
174*4882a593Smuzhiyun (typeof(*p))__u.__val; \
175*4882a593Smuzhiyun })
176*4882a593Smuzhiyun
177*4882a593Smuzhiyun #define smp_cond_load_relaxed(ptr, cond_expr) \
178*4882a593Smuzhiyun ({ \
179*4882a593Smuzhiyun typeof(ptr) __PTR = (ptr); \
180*4882a593Smuzhiyun __unqual_scalar_typeof(*ptr) VAL; \
181*4882a593Smuzhiyun for (;;) { \
182*4882a593Smuzhiyun VAL = READ_ONCE(*__PTR); \
183*4882a593Smuzhiyun if (cond_expr) \
184*4882a593Smuzhiyun break; \
185*4882a593Smuzhiyun __cmpwait_relaxed(__PTR, VAL); \
186*4882a593Smuzhiyun } \
187*4882a593Smuzhiyun (typeof(*ptr))VAL; \
188*4882a593Smuzhiyun })
189*4882a593Smuzhiyun
190*4882a593Smuzhiyun #define smp_cond_load_acquire(ptr, cond_expr) \
191*4882a593Smuzhiyun ({ \
192*4882a593Smuzhiyun typeof(ptr) __PTR = (ptr); \
193*4882a593Smuzhiyun __unqual_scalar_typeof(*ptr) VAL; \
194*4882a593Smuzhiyun for (;;) { \
195*4882a593Smuzhiyun VAL = smp_load_acquire(__PTR); \
196*4882a593Smuzhiyun if (cond_expr) \
197*4882a593Smuzhiyun break; \
198*4882a593Smuzhiyun __cmpwait_relaxed(__PTR, VAL); \
199*4882a593Smuzhiyun } \
200*4882a593Smuzhiyun (typeof(*ptr))VAL; \
201*4882a593Smuzhiyun })
202*4882a593Smuzhiyun
203*4882a593Smuzhiyun #include <asm-generic/barrier.h>
204*4882a593Smuzhiyun
205*4882a593Smuzhiyun #endif /* __ASSEMBLY__ */
206*4882a593Smuzhiyun
207*4882a593Smuzhiyun #endif /* __ASM_BARRIER_H */
208