162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (C) 2020-2022 Loongson Technology Corporation Limited
462306a36Sopenharmony_ci */
562306a36Sopenharmony_ci#ifndef __ASM_BARRIER_H
662306a36Sopenharmony_ci#define __ASM_BARRIER_H
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci/*
962306a36Sopenharmony_ci * Hint encoding:
1062306a36Sopenharmony_ci *
1162306a36Sopenharmony_ci * Bit4: ordering or completion (0: completion, 1: ordering)
1262306a36Sopenharmony_ci * Bit3: barrier for previous read (0: true, 1: false)
1362306a36Sopenharmony_ci * Bit2: barrier for previous write (0: true, 1: false)
1462306a36Sopenharmony_ci * Bit1: barrier for succeeding read (0: true, 1: false)
1562306a36Sopenharmony_ci * Bit0: barrier for succeeding write (0: true, 1: false)
1662306a36Sopenharmony_ci *
1762306a36Sopenharmony_ci * Hint 0x700: barrier for "read after read" from the same address
1862306a36Sopenharmony_ci */
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci#define DBAR(hint) __asm__ __volatile__("dbar %0 " : : "I"(hint) : "memory")
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ci#define crwrw		0b00000
2362306a36Sopenharmony_ci#define cr_r_		0b00101
2462306a36Sopenharmony_ci#define c_w_w		0b01010
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci#define orwrw		0b10000
2762306a36Sopenharmony_ci#define or_r_		0b10101
2862306a36Sopenharmony_ci#define o_w_w		0b11010
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci#define orw_w		0b10010
3162306a36Sopenharmony_ci#define or_rw		0b10100
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci#define c_sync()	DBAR(crwrw)
3462306a36Sopenharmony_ci#define c_rsync()	DBAR(cr_r_)
3562306a36Sopenharmony_ci#define c_wsync()	DBAR(c_w_w)
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ci#define o_sync()	DBAR(orwrw)
3862306a36Sopenharmony_ci#define o_rsync()	DBAR(or_r_)
3962306a36Sopenharmony_ci#define o_wsync()	DBAR(o_w_w)
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci#define ldacq_mb()	DBAR(or_rw)
4262306a36Sopenharmony_ci#define strel_mb()	DBAR(orw_w)
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci#define mb()		c_sync()
4562306a36Sopenharmony_ci#define rmb()		c_rsync()
4662306a36Sopenharmony_ci#define wmb()		c_wsync()
4762306a36Sopenharmony_ci#define iob()		c_sync()
4862306a36Sopenharmony_ci#define wbflush()	c_sync()
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci#define __smp_mb()	o_sync()
5162306a36Sopenharmony_ci#define __smp_rmb()	o_rsync()
5262306a36Sopenharmony_ci#define __smp_wmb()	o_wsync()
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci#ifdef CONFIG_SMP
5562306a36Sopenharmony_ci#define __WEAK_LLSC_MB		"	dbar 0x700	\n"
5662306a36Sopenharmony_ci#else
5762306a36Sopenharmony_ci#define __WEAK_LLSC_MB		"			\n"
5862306a36Sopenharmony_ci#endif
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci#define __smp_mb__before_atomic()	barrier()
6162306a36Sopenharmony_ci#define __smp_mb__after_atomic()	barrier()
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci/**
6462306a36Sopenharmony_ci * array_index_mask_nospec() - generate a ~0 mask when index < size, 0 otherwise
6562306a36Sopenharmony_ci * @index: array element index
6662306a36Sopenharmony_ci * @size: number of elements in array
6762306a36Sopenharmony_ci *
6862306a36Sopenharmony_ci * Returns:
6962306a36Sopenharmony_ci *     0 - (@index < @size)
7062306a36Sopenharmony_ci */
7162306a36Sopenharmony_ci#define array_index_mask_nospec array_index_mask_nospec
7262306a36Sopenharmony_cistatic inline unsigned long array_index_mask_nospec(unsigned long index,
7362306a36Sopenharmony_ci						    unsigned long size)
7462306a36Sopenharmony_ci{
7562306a36Sopenharmony_ci	unsigned long mask;
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci	__asm__ __volatile__(
7862306a36Sopenharmony_ci		"sltu	%0, %1, %2\n\t"
7962306a36Sopenharmony_ci#if (__SIZEOF_LONG__ == 4)
8062306a36Sopenharmony_ci		"sub.w	%0, $zero, %0\n\t"
8162306a36Sopenharmony_ci#elif (__SIZEOF_LONG__ == 8)
8262306a36Sopenharmony_ci		"sub.d	%0, $zero, %0\n\t"
8362306a36Sopenharmony_ci#endif
8462306a36Sopenharmony_ci		: "=r" (mask)
8562306a36Sopenharmony_ci		: "r" (index), "r" (size)
8662306a36Sopenharmony_ci		:);
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci	return mask;
8962306a36Sopenharmony_ci}
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci#define __smp_load_acquire(p)				\
9262306a36Sopenharmony_ci({							\
9362306a36Sopenharmony_ci	typeof(*p) ___p1 = READ_ONCE(*p);		\
9462306a36Sopenharmony_ci	compiletime_assert_atomic_type(*p);		\
9562306a36Sopenharmony_ci	ldacq_mb();					\
9662306a36Sopenharmony_ci	___p1;						\
9762306a36Sopenharmony_ci})
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci#define __smp_store_release(p, v)			\
10062306a36Sopenharmony_cido {							\
10162306a36Sopenharmony_ci	compiletime_assert_atomic_type(*p);		\
10262306a36Sopenharmony_ci	strel_mb();					\
10362306a36Sopenharmony_ci	WRITE_ONCE(*p, v);				\
10462306a36Sopenharmony_ci} while (0)
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci#define __smp_store_mb(p, v)							\
10762306a36Sopenharmony_cido {										\
10862306a36Sopenharmony_ci	union { typeof(p) __val; char __c[1]; } __u =				\
10962306a36Sopenharmony_ci		{ .__val = (__force typeof(p)) (v) };				\
11062306a36Sopenharmony_ci	unsigned long __tmp;							\
11162306a36Sopenharmony_ci	switch (sizeof(p)) {							\
11262306a36Sopenharmony_ci	case 1:									\
11362306a36Sopenharmony_ci		*(volatile __u8 *)&p = *(__u8 *)__u.__c;			\
11462306a36Sopenharmony_ci		__smp_mb();							\
11562306a36Sopenharmony_ci		break;								\
11662306a36Sopenharmony_ci	case 2:									\
11762306a36Sopenharmony_ci		*(volatile __u16 *)&p = *(__u16 *)__u.__c;			\
11862306a36Sopenharmony_ci		__smp_mb();							\
11962306a36Sopenharmony_ci		break;								\
12062306a36Sopenharmony_ci	case 4:									\
12162306a36Sopenharmony_ci		__asm__ __volatile__(						\
12262306a36Sopenharmony_ci		"amswap_db.w %[tmp], %[val], %[mem]	\n"			\
12362306a36Sopenharmony_ci		: [mem] "+ZB" (*(u32 *)&p), [tmp] "=&r" (__tmp)			\
12462306a36Sopenharmony_ci		: [val] "r" (*(__u32 *)__u.__c)					\
12562306a36Sopenharmony_ci		: );								\
12662306a36Sopenharmony_ci		break;								\
12762306a36Sopenharmony_ci	case 8:									\
12862306a36Sopenharmony_ci		__asm__ __volatile__(						\
12962306a36Sopenharmony_ci		"amswap_db.d %[tmp], %[val], %[mem]	\n"			\
13062306a36Sopenharmony_ci		: [mem] "+ZB" (*(u64 *)&p), [tmp] "=&r" (__tmp)			\
13162306a36Sopenharmony_ci		: [val] "r" (*(__u64 *)__u.__c)					\
13262306a36Sopenharmony_ci		: );								\
13362306a36Sopenharmony_ci		break;								\
13462306a36Sopenharmony_ci	}									\
13562306a36Sopenharmony_ci} while (0)
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci#include <asm-generic/barrier.h>
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci#endif /* __ASM_BARRIER_H */
140