162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (C) 1999 Cort Dougan <cort@cs.nmt.edu>
462306a36Sopenharmony_ci */
562306a36Sopenharmony_ci#ifndef _ASM_POWERPC_BARRIER_H
662306a36Sopenharmony_ci#define _ASM_POWERPC_BARRIER_H
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include <asm/asm-const.h>
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#ifndef __ASSEMBLY__
1162306a36Sopenharmony_ci#include <asm/ppc-opcode.h>
1262306a36Sopenharmony_ci#endif
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci/*
1562306a36Sopenharmony_ci * Memory barrier.
1662306a36Sopenharmony_ci * The sync instruction guarantees that all memory accesses initiated
1762306a36Sopenharmony_ci * by this processor have been performed (with respect to all other
1862306a36Sopenharmony_ci * mechanisms that access memory).  The eieio instruction is a barrier
1962306a36Sopenharmony_ci * providing an ordering (separately) for (a) cacheable stores and (b)
2062306a36Sopenharmony_ci * loads and stores to non-cacheable memory (e.g. I/O devices).
2162306a36Sopenharmony_ci *
2262306a36Sopenharmony_ci * mb() prevents loads and stores being reordered across this point.
2362306a36Sopenharmony_ci * rmb() prevents loads being reordered across this point.
2462306a36Sopenharmony_ci * wmb() prevents stores being reordered across this point.
2562306a36Sopenharmony_ci *
2662306a36Sopenharmony_ci * *mb() variants without smp_ prefix must order all types of memory
2762306a36Sopenharmony_ci * operations with one another. sync is the only instruction sufficient
2862306a36Sopenharmony_ci * to do this.
2962306a36Sopenharmony_ci *
3062306a36Sopenharmony_ci * For the smp_ barriers, ordering is for cacheable memory operations
3162306a36Sopenharmony_ci * only. We have to use the sync instruction for smp_mb(), since lwsync
3262306a36Sopenharmony_ci * doesn't order loads with respect to previous stores.  Lwsync can be
3362306a36Sopenharmony_ci * used for smp_rmb() and smp_wmb().
3462306a36Sopenharmony_ci *
3562306a36Sopenharmony_ci * However, on CPUs that don't support lwsync, lwsync actually maps to a
3662306a36Sopenharmony_ci * heavy-weight sync, so smp_wmb() can be a lighter-weight eieio.
3762306a36Sopenharmony_ci */
3862306a36Sopenharmony_ci#define __mb()   __asm__ __volatile__ ("sync" : : : "memory")
3962306a36Sopenharmony_ci#define __rmb()  __asm__ __volatile__ ("sync" : : : "memory")
4062306a36Sopenharmony_ci#define __wmb()  __asm__ __volatile__ ("sync" : : : "memory")
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci/* The sub-arch has lwsync */
4362306a36Sopenharmony_ci#if defined(CONFIG_PPC64) || defined(CONFIG_PPC_E500MC)
4462306a36Sopenharmony_ci#    define SMPWMB      LWSYNC
4562306a36Sopenharmony_ci#elif defined(CONFIG_BOOKE)
4662306a36Sopenharmony_ci#    define SMPWMB      mbar
4762306a36Sopenharmony_ci#else
4862306a36Sopenharmony_ci#    define SMPWMB      eieio
4962306a36Sopenharmony_ci#endif
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci/* clang defines this macro for a builtin, which will not work with runtime patching */
5262306a36Sopenharmony_ci#undef __lwsync
5362306a36Sopenharmony_ci#define __lwsync()	__asm__ __volatile__ (stringify_in_c(LWSYNC) : : :"memory")
5462306a36Sopenharmony_ci#define __dma_rmb()	__lwsync()
5562306a36Sopenharmony_ci#define __dma_wmb()	__asm__ __volatile__ (stringify_in_c(SMPWMB) : : :"memory")
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci#define __smp_lwsync()	__lwsync()
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci#define __smp_mb()	__mb()
6062306a36Sopenharmony_ci#define __smp_rmb()	__lwsync()
6162306a36Sopenharmony_ci#define __smp_wmb()	__asm__ __volatile__ (stringify_in_c(SMPWMB) : : :"memory")
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci/*
6462306a36Sopenharmony_ci * This is a barrier which prevents following instructions from being
6562306a36Sopenharmony_ci * started until the value of the argument x is known.  For example, if
6662306a36Sopenharmony_ci * x is a variable loaded from memory, this prevents following
6762306a36Sopenharmony_ci * instructions from being executed until the load has been performed.
6862306a36Sopenharmony_ci */
6962306a36Sopenharmony_ci#define data_barrier(x)	\
7062306a36Sopenharmony_ci	asm volatile("twi 0,%0,0; isync" : : "r" (x) : "memory");
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci#define __smp_store_release(p, v)						\
7362306a36Sopenharmony_cido {									\
7462306a36Sopenharmony_ci	compiletime_assert_atomic_type(*p);				\
7562306a36Sopenharmony_ci	__smp_lwsync();							\
7662306a36Sopenharmony_ci	WRITE_ONCE(*p, v);						\
7762306a36Sopenharmony_ci} while (0)
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci#define __smp_load_acquire(p)						\
8062306a36Sopenharmony_ci({									\
8162306a36Sopenharmony_ci	typeof(*p) ___p1 = READ_ONCE(*p);				\
8262306a36Sopenharmony_ci	compiletime_assert_atomic_type(*p);				\
8362306a36Sopenharmony_ci	__smp_lwsync();							\
8462306a36Sopenharmony_ci	___p1;								\
8562306a36Sopenharmony_ci})
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci#ifdef CONFIG_PPC_BOOK3S_64
8862306a36Sopenharmony_ci#define NOSPEC_BARRIER_SLOT   nop
8962306a36Sopenharmony_ci#elif defined(CONFIG_PPC_E500)
9062306a36Sopenharmony_ci#define NOSPEC_BARRIER_SLOT   nop; nop
9162306a36Sopenharmony_ci#endif
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci#ifdef CONFIG_PPC_BARRIER_NOSPEC
9462306a36Sopenharmony_ci/*
9562306a36Sopenharmony_ci * Prevent execution of subsequent instructions until preceding branches have
9662306a36Sopenharmony_ci * been fully resolved and are no longer executing speculatively.
9762306a36Sopenharmony_ci */
9862306a36Sopenharmony_ci#define barrier_nospec_asm NOSPEC_BARRIER_FIXUP_SECTION; NOSPEC_BARRIER_SLOT
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci// This also acts as a compiler barrier due to the memory clobber.
10162306a36Sopenharmony_ci#define barrier_nospec() asm (stringify_in_c(barrier_nospec_asm) ::: "memory")
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci#else /* !CONFIG_PPC_BARRIER_NOSPEC */
10462306a36Sopenharmony_ci#define barrier_nospec_asm
10562306a36Sopenharmony_ci#define barrier_nospec()
10662306a36Sopenharmony_ci#endif /* CONFIG_PPC_BARRIER_NOSPEC */
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci/*
10962306a36Sopenharmony_ci * pmem_wmb() ensures that all stores for which the modification
11062306a36Sopenharmony_ci * are written to persistent storage by preceding dcbfps/dcbstps
11162306a36Sopenharmony_ci * instructions have updated persistent storage before any data
11262306a36Sopenharmony_ci * access or data transfer caused by subsequent instructions is
11362306a36Sopenharmony_ci * initiated.
11462306a36Sopenharmony_ci */
11562306a36Sopenharmony_ci#define pmem_wmb() __asm__ __volatile__(PPC_PHWSYNC ::: "memory")
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci#include <asm-generic/barrier.h>
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci#endif /* _ASM_POWERPC_BARRIER_H */
120