+/**
+ * store_atom_insert_al16:
+ * @p: host address
+ * @val: shifted value to store
+ * @msk: mask for value to store
+ *
+ * Atomically store @val to @p masked by @msk.
+ */
+static void store_atom_insert_al16(Int128 *ps, Int128Alias val, Int128Alias
msk)
+{
+#if defined(CONFIG_ATOMIC128)
+ __uint128_t *pu, old, new;
+
+ /* With CONFIG_ATOMIC128, we can avoid the memory barriers. */
+ pu = __builtin_assume_aligned(ps, 16);
+ old = *pu;
+ do {
+ new = (old & ~msk.u) | val.u;
+ } while (!__atomic_compare_exchange_n(pu, &old, new, true,
+ __ATOMIC_RELAXED, __ATOMIC_RELAXED));
+#elif defined(CONFIG_CMPXCHG128)
+ __uint128_t *pu, old, new;
+
+ /*
+ * Without CONFIG_ATOMIC128, __atomic_compare_exchange_n will always
+ * defer to libatomic, so we must use __sync_val_compare_and_swap_16
+ * and accept the sequential consistency that comes with it.
+ */
+ pu = __builtin_assume_aligned(ps, 16);
+ do {
+ old = *pu;
+ new = (old & ~msk.u) | val.u;
+ } while (!__sync_bool_compare_and_swap_16(pu, old, new));