1 /*
2  * SPDX-License-Identifier: GPL-2.0-or-later
3  * Load/store for 128-bit atomic operations, generic version.
4  *
5  * Copyright (C) 2018, 2023 Linaro, Ltd.
6  *
7  * See docs/devel/atomics.rst for discussion about the guarantees each
8  * atomic primitive is meant to provide.
9  */
10 
11 #ifndef HOST_ATOMIC128_LDST_H
12 #define HOST_ATOMIC128_LDST_H
13 
14 #if defined(CONFIG_ATOMIC128)
15 # define HAVE_ATOMIC128_RO 1
16 # define HAVE_ATOMIC128_RW 1
17 
18 static inline Int128 ATTRIBUTE_ATOMIC128_OPT
19 atomic16_read_ro(const Int128 *ptr)
20 {
21     const __int128_t *ptr_align = __builtin_assume_aligned(ptr, 16);
22     Int128Alias r;
23 
24     r.i = qatomic_read__nocheck(ptr_align);
25     return r.s;
26 }
27 
28 static inline Int128 ATTRIBUTE_ATOMIC128_OPT
29 atomic16_read_rw(Int128 *ptr)
30 {
31     return atomic16_read_ro(ptr);
32 }
33 
34 static inline void ATTRIBUTE_ATOMIC128_OPT
35 atomic16_set(Int128 *ptr, Int128 val)
36 {
37     __int128_t *ptr_align = __builtin_assume_aligned(ptr, 16);
38     Int128Alias v;
39 
40     v.s = val;
41     qatomic_set__nocheck(ptr_align, v.i);
42 }
43 
44 #elif defined(CONFIG_CMPXCHG128)
45 # define HAVE_ATOMIC128_RO 0
46 # define HAVE_ATOMIC128_RW 1
47 
48 Int128 QEMU_ERROR("unsupported atomic") atomic16_read_ro(const Int128 *ptr);
49 
50 static inline Int128 ATTRIBUTE_ATOMIC128_OPT
51 atomic16_read_rw(Int128 *ptr)
52 {
53     /* Maybe replace 0 with 0, returning the old value.  */
54     Int128 z = int128_make64(0);
55     return atomic16_cmpxchg(ptr, z, z);
56 }
57 
58 static inline void ATTRIBUTE_ATOMIC128_OPT
59 atomic16_set(Int128 *ptr, Int128 val)
60 {
61     Int128Aligned *ptr_align = __builtin_assume_aligned(ptr, 16);
62     __int128_t old;
63     Int128Alias new;
64 
65     new.s = val;
66     do {
67         old = *ptr_align;
68     } while (!__sync_bool_compare_and_swap_16(ptr_align, old, new.i));
69 }
70 
71 #else
72 # define HAVE_ATOMIC128_RO 0
73 # define HAVE_ATOMIC128_RW 0
74 
75 /* Fallback definitions that must be optimized away, or error.  */
76 Int128 QEMU_ERROR("unsupported atomic") atomic16_read_ro(const Int128 *ptr);
77 Int128 QEMU_ERROR("unsupported atomic") atomic16_read_rw(Int128 *ptr);
78 void QEMU_ERROR("unsupported atomic") atomic16_set(Int128 *ptr, Int128 val);
79 #endif
80 
81 #endif /* HOST_ATOMIC128_LDST_H */
82