18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (C) 2020 Google LLC.
48c2ecf20Sopenharmony_ci */
58c2ecf20Sopenharmony_ci#ifndef __ASM_RWONCE_H
68c2ecf20Sopenharmony_ci#define __ASM_RWONCE_H
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci#if defined(CONFIG_LTO) && !defined(__ASSEMBLY__)
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#include <linux/compiler_types.h>
118c2ecf20Sopenharmony_ci#include <asm/alternative-macros.h>
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_ci#ifndef BUILD_VDSO
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ci#ifdef CONFIG_AS_HAS_LDAPR
168c2ecf20Sopenharmony_ci#define __LOAD_RCPC(sfx, regs...)					\
178c2ecf20Sopenharmony_ci	ALTERNATIVE(							\
188c2ecf20Sopenharmony_ci		"ldar"	#sfx "\t" #regs,				\
198c2ecf20Sopenharmony_ci		".arch_extension rcpc\n"				\
208c2ecf20Sopenharmony_ci		"ldapr"	#sfx "\t" #regs,				\
218c2ecf20Sopenharmony_ci	ARM64_HAS_LDAPR)
228c2ecf20Sopenharmony_ci#else
238c2ecf20Sopenharmony_ci#define __LOAD_RCPC(sfx, regs...)	"ldar" #sfx "\t" #regs
248c2ecf20Sopenharmony_ci#endif /* CONFIG_AS_HAS_LDAPR */
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci/*
278c2ecf20Sopenharmony_ci * When building with LTO, there is an increased risk of the compiler
288c2ecf20Sopenharmony_ci * converting an address dependency headed by a READ_ONCE() invocation
298c2ecf20Sopenharmony_ci * into a control dependency and consequently allowing for harmful
308c2ecf20Sopenharmony_ci * reordering by the CPU.
318c2ecf20Sopenharmony_ci *
328c2ecf20Sopenharmony_ci * Ensure that such transformations are harmless by overriding the generic
338c2ecf20Sopenharmony_ci * READ_ONCE() definition with one that provides RCpc acquire semantics
348c2ecf20Sopenharmony_ci * when building with LTO.
358c2ecf20Sopenharmony_ci */
368c2ecf20Sopenharmony_ci#define __READ_ONCE(x)							\
378c2ecf20Sopenharmony_ci({									\
388c2ecf20Sopenharmony_ci	typeof(&(x)) __x = &(x);					\
398c2ecf20Sopenharmony_ci	int atomic = 1;							\
408c2ecf20Sopenharmony_ci	union { __unqual_scalar_typeof(*__x) __val; char __c[1]; } __u;	\
418c2ecf20Sopenharmony_ci	switch (sizeof(x)) {						\
428c2ecf20Sopenharmony_ci	case 1:								\
438c2ecf20Sopenharmony_ci		asm volatile(__LOAD_RCPC(b, %w0, %1)			\
448c2ecf20Sopenharmony_ci			: "=r" (*(__u8 *)__u.__c)			\
458c2ecf20Sopenharmony_ci			: "Q" (*__x) : "memory");			\
468c2ecf20Sopenharmony_ci		break;							\
478c2ecf20Sopenharmony_ci	case 2:								\
488c2ecf20Sopenharmony_ci		asm volatile(__LOAD_RCPC(h, %w0, %1)			\
498c2ecf20Sopenharmony_ci			: "=r" (*(__u16 *)__u.__c)			\
508c2ecf20Sopenharmony_ci			: "Q" (*__x) : "memory");			\
518c2ecf20Sopenharmony_ci		break;							\
528c2ecf20Sopenharmony_ci	case 4:								\
538c2ecf20Sopenharmony_ci		asm volatile(__LOAD_RCPC(, %w0, %1)			\
548c2ecf20Sopenharmony_ci			: "=r" (*(__u32 *)__u.__c)			\
558c2ecf20Sopenharmony_ci			: "Q" (*__x) : "memory");			\
568c2ecf20Sopenharmony_ci		break;							\
578c2ecf20Sopenharmony_ci	case 8:								\
588c2ecf20Sopenharmony_ci		asm volatile(__LOAD_RCPC(, %0, %1)			\
598c2ecf20Sopenharmony_ci			: "=r" (*(__u64 *)__u.__c)			\
608c2ecf20Sopenharmony_ci			: "Q" (*__x) : "memory");			\
618c2ecf20Sopenharmony_ci		break;							\
628c2ecf20Sopenharmony_ci	default:							\
638c2ecf20Sopenharmony_ci		atomic = 0;						\
648c2ecf20Sopenharmony_ci	}								\
658c2ecf20Sopenharmony_ci	atomic ? (typeof(*__x))__u.__val : (*(volatile typeof(__x))__x);\
668c2ecf20Sopenharmony_ci})
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ci#endif	/* !BUILD_VDSO */
698c2ecf20Sopenharmony_ci#endif	/* CONFIG_LTO && !__ASSEMBLY__ */
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_ci#include <asm-generic/rwonce.h>
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci#endif	/* __ASM_RWONCE_H */
74