aboutsummaryrefslogtreecommitdiff
path: root/example/ipfragreass/odp_ipfragreass_atomics_arm.h
blob: e75ae5887266b41ce133b96f6f3ffe79f6b72408 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
/* Copyright (c) 2017, Linaro Limited
 * All rights reserved.
 *
 * SPDX-License-Identifier:     BSD-3-Clause
 */

#ifndef ODP_FRAGREASS_PP_ATOMICS_ARM_H_
#define ODP_FRAGREASS_PP_ATOMICS_ARM_H_

#include <example_debug.h>

#if __SIZEOF_POINTER__ == 8 && defined(__aarch64__)
static inline __int128 lld(__int128 *var, int mo)
{
	__int128 old;
	uint64_t lo, hi;

	if (mo == __ATOMIC_ACQUIRE)
		__asm__ volatile("ldaxp %0, %1, [%2]" : "=&r" (lo), "=&r" (hi)
				 : "r" (var) : "memory");
	else /* mo == __ATOMIC_RELAXED */
		__asm__ volatile("ldxp %0, %1, [%2]" : "=&r" (lo), "=&r" (hi)
				 : "r" (var) : );
	old = hi;
	old <<= 64;
	old |= lo;

	return old;

}

static inline uint32_t scd(__int128 *var, __int128 neu, int mo)
{
	uint32_t ret;
	uint64_t lo = neu, hi = neu >> 64;

	if (mo == __ATOMIC_RELEASE)
		__asm__ volatile("stlxp %w0, %1, %2, [%3]" : "=&r" (ret)
				 : "r" (lo), "r" (hi), "r" (var) : "memory");
	else /* mo == __ATOMIC_RELAXED */
		__asm__ volatile("stxp %w0, %1, %2, [%3]" : "=&r" (ret)
				 : "r" (lo), "r" (hi), "r" (var) : "memory");
	return ret;
}

static inline bool atomic_strong_cas_dblptr(__int128 *var, __int128 *exp,
					    __int128 neu, int mo_success,
					    int mo_failure EXAMPLE_UNUSED)
{
	register __int128 old;
	register __int128 expected = *exp;
	int ll_mo, sc_mo;

	ll_mo = (mo_success != __ATOMIC_RELAXED &&
		 mo_success != __ATOMIC_RELEASE) ? __ATOMIC_ACQUIRE
						 : __ATOMIC_RELAXED;
	sc_mo = (mo_success == __ATOMIC_RELEASE ||
		 mo_success == __ATOMIC_ACQ_REL ||
		 mo_success == __ATOMIC_SEQ_CST) ? __ATOMIC_RELEASE
						 : __ATOMIC_RELAXED;

	/*
	 * To prevent spurious failures and ensure atomicity, we must write some
	 * value back -- whether it's the value we wanted to write, or the value
	 * that is currently there. Repeat until we perform a successful write.
	 */
	do {
		old = lld(var, ll_mo);
	} while (scd(var, old == expected ? neu : old, sc_mo));

	*exp = old;
	return (old == expected);
}
#elif __SIZEOF_POINTER__ == 4 && defined(__ARM_ARCH) && __ARM_ARCH == 7
static inline uint64_t lld(uint64_t *var, int mo)
{
	uint64_t old;

	__asm__ volatile("ldrexd %0, %H0, [%1]" : "=&r" (old) : "r" (var) : );
	if (mo == __ATOMIC_ACQUIRE)
		__asm__ volatile("dmb ish" ::: "memory");
	return old;
}

static inline uint32_t scd(uint64_t *var, uint64_t neu, int mo)
{
	uint32_t ret;

	if (mo == __ATOMIC_RELEASE)
		__asm__ volatile("dmb ish" ::: "memory");
	__asm__ volatile("strexd %0, %1, %H1, [%2]" : "=&r" (ret)
			 : "r" (neu), "r" (var) : );
	return ret;
}

static inline bool atomic_strong_cas_dblptr(uint64_t *var, uint64_t *exp,
					    uint64_t neu, int mo_success,
					    int mo_failure EXAMPLE_UNUSED)
{
	register uint64_t old;
	register uint64_t expected = *exp;
	int ll_mo, sc_mo;

	ll_mo = (mo_success != __ATOMIC_RELAXED &&
		 mo_success != __ATOMIC_RELEASE) ? __ATOMIC_ACQUIRE
						 : __ATOMIC_RELAXED;
	sc_mo = (mo_success == __ATOMIC_RELEASE ||
		 mo_success == __ATOMIC_ACQ_REL ||
		 mo_success == __ATOMIC_SEQ_CST) ? __ATOMIC_RELEASE
						 : __ATOMIC_RELAXED;

	/*
	 * To prevent spurious failures and ensure atomicity, we must write some
	 * value back -- whether it's the value we wanted to write, or the value
	 * that is currently there. Repeat until we perform a successful write.
	 */
	do {
		old = lld(var, ll_mo);
	} while (scd(var, old == expected ? neu : old, sc_mo));

	*exp = old;
	return (old == expected);
}
#else
#include "odp_ipfragreass_atomics.h"
#endif
#endif