18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-only */
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Based on arch/arm/include/asm/barrier.h
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (C) 2012 ARM Ltd.
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci#ifndef __ASM_BARRIER_H
88c2ecf20Sopenharmony_ci#define __ASM_BARRIER_H
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#ifndef __ASSEMBLY__
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ci#include <linux/kasan-checks.h>
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci#define __nops(n)	".rept	" #n "\nnop\n.endr\n"
158c2ecf20Sopenharmony_ci#define nops(n)		asm volatile(__nops(n))
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci#define sev()		asm volatile("sev" : : : "memory")
188c2ecf20Sopenharmony_ci#define wfe()		asm volatile("wfe" : : : "memory")
198c2ecf20Sopenharmony_ci#define wfi()		asm volatile("wfi" : : : "memory")
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ci#define isb()		asm volatile("isb" : : : "memory")
228c2ecf20Sopenharmony_ci#define dmb(opt)	asm volatile("dmb " #opt : : : "memory")
238c2ecf20Sopenharmony_ci#define dsb(opt)	asm volatile("dsb " #opt : : : "memory")
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci#define psb_csync()	asm volatile("hint #17" : : : "memory")
268c2ecf20Sopenharmony_ci#define csdb()		asm volatile("hint #20" : : : "memory")
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ci#define spec_bar()	asm volatile(ALTERNATIVE("dsb nsh\nisb\n",		\
298c2ecf20Sopenharmony_ci						 SB_BARRIER_INSN"nop\n",	\
308c2ecf20Sopenharmony_ci						 ARM64_HAS_SB))
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci#ifdef CONFIG_ARM64_PSEUDO_NMI
338c2ecf20Sopenharmony_ci#define pmr_sync()						\
348c2ecf20Sopenharmony_ci	do {							\
358c2ecf20Sopenharmony_ci		extern struct static_key_false gic_pmr_sync;	\
368c2ecf20Sopenharmony_ci								\
378c2ecf20Sopenharmony_ci		if (static_branch_unlikely(&gic_pmr_sync))	\
388c2ecf20Sopenharmony_ci			dsb(sy);				\
398c2ecf20Sopenharmony_ci	} while(0)
408c2ecf20Sopenharmony_ci#else
418c2ecf20Sopenharmony_ci#define pmr_sync()	do {} while (0)
428c2ecf20Sopenharmony_ci#endif
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ci#define mb()		dsb(sy)
458c2ecf20Sopenharmony_ci#define rmb()		dsb(ld)
468c2ecf20Sopenharmony_ci#define wmb()		dsb(st)
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ci#define dma_mb()	dmb(osh)
498c2ecf20Sopenharmony_ci#define dma_rmb()	dmb(oshld)
508c2ecf20Sopenharmony_ci#define dma_wmb()	dmb(oshst)
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci/*
538c2ecf20Sopenharmony_ci * Generate a mask for array_index__nospec() that is ~0UL when 0 <= idx < sz
548c2ecf20Sopenharmony_ci * and 0 otherwise.
558c2ecf20Sopenharmony_ci */
568c2ecf20Sopenharmony_ci#define array_index_mask_nospec array_index_mask_nospec
578c2ecf20Sopenharmony_cistatic inline unsigned long array_index_mask_nospec(unsigned long idx,
588c2ecf20Sopenharmony_ci						    unsigned long sz)
598c2ecf20Sopenharmony_ci{
608c2ecf20Sopenharmony_ci	unsigned long mask;
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci	asm volatile(
638c2ecf20Sopenharmony_ci	"	cmp	%1, %2\n"
648c2ecf20Sopenharmony_ci	"	sbc	%0, xzr, xzr\n"
658c2ecf20Sopenharmony_ci	: "=r" (mask)
668c2ecf20Sopenharmony_ci	: "r" (idx), "Ir" (sz)
678c2ecf20Sopenharmony_ci	: "cc");
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci	csdb();
708c2ecf20Sopenharmony_ci	return mask;
718c2ecf20Sopenharmony_ci}
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci/*
748c2ecf20Sopenharmony_ci * Ensure that reads of the counter are treated the same as memory reads
758c2ecf20Sopenharmony_ci * for the purposes of ordering by subsequent memory barriers.
768c2ecf20Sopenharmony_ci *
778c2ecf20Sopenharmony_ci * This insanity brought to you by speculative system register reads,
788c2ecf20Sopenharmony_ci * out-of-order memory accesses, sequence locks and Thomas Gleixner.
798c2ecf20Sopenharmony_ci *
808c2ecf20Sopenharmony_ci * http://lists.infradead.org/pipermail/linux-arm-kernel/2019-February/631195.html
818c2ecf20Sopenharmony_ci */
828c2ecf20Sopenharmony_ci#define arch_counter_enforce_ordering(val) do {				\
838c2ecf20Sopenharmony_ci	u64 tmp, _val = (val);						\
848c2ecf20Sopenharmony_ci									\
858c2ecf20Sopenharmony_ci	asm volatile(							\
868c2ecf20Sopenharmony_ci	"	eor	%0, %1, %1\n"					\
878c2ecf20Sopenharmony_ci	"	add	%0, sp, %0\n"					\
888c2ecf20Sopenharmony_ci	"	ldr	xzr, [%0]"					\
898c2ecf20Sopenharmony_ci	: "=r" (tmp) : "r" (_val));					\
908c2ecf20Sopenharmony_ci} while (0)
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ci#define __smp_mb()	dmb(ish)
938c2ecf20Sopenharmony_ci#define __smp_rmb()	dmb(ishld)
948c2ecf20Sopenharmony_ci#define __smp_wmb()	dmb(ishst)
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_ci#define __smp_store_release(p, v)					\
978c2ecf20Sopenharmony_cido {									\
988c2ecf20Sopenharmony_ci	typeof(p) __p = (p);						\
998c2ecf20Sopenharmony_ci	union { __unqual_scalar_typeof(*p) __val; char __c[1]; } __u =	\
1008c2ecf20Sopenharmony_ci		{ .__val = (__force __unqual_scalar_typeof(*p)) (v) };	\
1018c2ecf20Sopenharmony_ci	compiletime_assert_atomic_type(*p);				\
1028c2ecf20Sopenharmony_ci	kasan_check_write(__p, sizeof(*p));				\
1038c2ecf20Sopenharmony_ci	switch (sizeof(*p)) {						\
1048c2ecf20Sopenharmony_ci	case 1:								\
1058c2ecf20Sopenharmony_ci		asm volatile ("stlrb %w1, %0"				\
1068c2ecf20Sopenharmony_ci				: "=Q" (*__p)				\
1078c2ecf20Sopenharmony_ci				: "r" (*(__u8 *)__u.__c)		\
1088c2ecf20Sopenharmony_ci				: "memory");				\
1098c2ecf20Sopenharmony_ci		break;							\
1108c2ecf20Sopenharmony_ci	case 2:								\
1118c2ecf20Sopenharmony_ci		asm volatile ("stlrh %w1, %0"				\
1128c2ecf20Sopenharmony_ci				: "=Q" (*__p)				\
1138c2ecf20Sopenharmony_ci				: "r" (*(__u16 *)__u.__c)		\
1148c2ecf20Sopenharmony_ci				: "memory");				\
1158c2ecf20Sopenharmony_ci		break;							\
1168c2ecf20Sopenharmony_ci	case 4:								\
1178c2ecf20Sopenharmony_ci		asm volatile ("stlr %w1, %0"				\
1188c2ecf20Sopenharmony_ci				: "=Q" (*__p)				\
1198c2ecf20Sopenharmony_ci				: "r" (*(__u32 *)__u.__c)		\
1208c2ecf20Sopenharmony_ci				: "memory");				\
1218c2ecf20Sopenharmony_ci		break;							\
1228c2ecf20Sopenharmony_ci	case 8:								\
1238c2ecf20Sopenharmony_ci		asm volatile ("stlr %1, %0"				\
1248c2ecf20Sopenharmony_ci				: "=Q" (*__p)				\
1258c2ecf20Sopenharmony_ci				: "r" (*(__u64 *)__u.__c)		\
1268c2ecf20Sopenharmony_ci				: "memory");				\
1278c2ecf20Sopenharmony_ci		break;							\
1288c2ecf20Sopenharmony_ci	}								\
1298c2ecf20Sopenharmony_ci} while (0)
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ci#define __smp_load_acquire(p)						\
1328c2ecf20Sopenharmony_ci({									\
1338c2ecf20Sopenharmony_ci	union { __unqual_scalar_typeof(*p) __val; char __c[1]; } __u;	\
1348c2ecf20Sopenharmony_ci	typeof(p) __p = (p);						\
1358c2ecf20Sopenharmony_ci	compiletime_assert_atomic_type(*p);				\
1368c2ecf20Sopenharmony_ci	kasan_check_read(__p, sizeof(*p));				\
1378c2ecf20Sopenharmony_ci	switch (sizeof(*p)) {						\
1388c2ecf20Sopenharmony_ci	case 1:								\
1398c2ecf20Sopenharmony_ci		asm volatile ("ldarb %w0, %1"				\
1408c2ecf20Sopenharmony_ci			: "=r" (*(__u8 *)__u.__c)			\
1418c2ecf20Sopenharmony_ci			: "Q" (*__p) : "memory");			\
1428c2ecf20Sopenharmony_ci		break;							\
1438c2ecf20Sopenharmony_ci	case 2:								\
1448c2ecf20Sopenharmony_ci		asm volatile ("ldarh %w0, %1"				\
1458c2ecf20Sopenharmony_ci			: "=r" (*(__u16 *)__u.__c)			\
1468c2ecf20Sopenharmony_ci			: "Q" (*__p) : "memory");			\
1478c2ecf20Sopenharmony_ci		break;							\
1488c2ecf20Sopenharmony_ci	case 4:								\
1498c2ecf20Sopenharmony_ci		asm volatile ("ldar %w0, %1"				\
1508c2ecf20Sopenharmony_ci			: "=r" (*(__u32 *)__u.__c)			\
1518c2ecf20Sopenharmony_ci			: "Q" (*__p) : "memory");			\
1528c2ecf20Sopenharmony_ci		break;							\
1538c2ecf20Sopenharmony_ci	case 8:								\
1548c2ecf20Sopenharmony_ci		asm volatile ("ldar %0, %1"				\
1558c2ecf20Sopenharmony_ci			: "=r" (*(__u64 *)__u.__c)			\
1568c2ecf20Sopenharmony_ci			: "Q" (*__p) : "memory");			\
1578c2ecf20Sopenharmony_ci		break;							\
1588c2ecf20Sopenharmony_ci	}								\
1598c2ecf20Sopenharmony_ci	(typeof(*p))__u.__val;						\
1608c2ecf20Sopenharmony_ci})
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_ci#define smp_cond_load_relaxed(ptr, cond_expr)				\
1638c2ecf20Sopenharmony_ci({									\
1648c2ecf20Sopenharmony_ci	typeof(ptr) __PTR = (ptr);					\
1658c2ecf20Sopenharmony_ci	__unqual_scalar_typeof(*ptr) VAL;				\
1668c2ecf20Sopenharmony_ci	for (;;) {							\
1678c2ecf20Sopenharmony_ci		VAL = READ_ONCE(*__PTR);				\
1688c2ecf20Sopenharmony_ci		if (cond_expr)						\
1698c2ecf20Sopenharmony_ci			break;						\
1708c2ecf20Sopenharmony_ci		__cmpwait_relaxed(__PTR, VAL);				\
1718c2ecf20Sopenharmony_ci	}								\
1728c2ecf20Sopenharmony_ci	(typeof(*ptr))VAL;						\
1738c2ecf20Sopenharmony_ci})
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_ci#define smp_cond_load_acquire(ptr, cond_expr)				\
1768c2ecf20Sopenharmony_ci({									\
1778c2ecf20Sopenharmony_ci	typeof(ptr) __PTR = (ptr);					\
1788c2ecf20Sopenharmony_ci	__unqual_scalar_typeof(*ptr) VAL;				\
1798c2ecf20Sopenharmony_ci	for (;;) {							\
1808c2ecf20Sopenharmony_ci		VAL = smp_load_acquire(__PTR);				\
1818c2ecf20Sopenharmony_ci		if (cond_expr)						\
1828c2ecf20Sopenharmony_ci			break;						\
1838c2ecf20Sopenharmony_ci		__cmpwait_relaxed(__PTR, VAL);				\
1848c2ecf20Sopenharmony_ci	}								\
1858c2ecf20Sopenharmony_ci	(typeof(*ptr))VAL;						\
1868c2ecf20Sopenharmony_ci})
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_ci#include <asm-generic/barrier.h>
1898c2ecf20Sopenharmony_ci
1908c2ecf20Sopenharmony_ci#endif	/* __ASSEMBLY__ */
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_ci#endif	/* __ASM_BARRIER_H */
193