Re: [PATCH v5 2/6] iommu/amd: Introduce helper function to update 256-bit DTE

From: Uros Bizjak
Date: Mon Oct 07 2024 - 10:42:46 EST




On 7. 10. 24 06:13, Suravee Suthikulpanit wrote:

+
/****************************************************************************
*
* Helper functions
*
****************************************************************************/
+static void write_dte_upper128(struct dev_table_entry *ptr, struct dev_table_entry *new)
+{
+ struct dev_table_entry old = {};
+
+ do {
+ old.data128[1] = ptr->data128[1];
+ new->data[2] &= ~DTE_DATA2_INTR_MASK;
+ new->data[2] |= old.data[2] & (DTE_DATA2_INTR_MASK | DTE_DATA2_RESV_MASK);
+ } while (!try_cmpxchg128(&ptr->data128[1], &old.data128[1], new->data128[1]));

Please note that try_cmpxchg inherently updates &old.data128[1] above on failure. There is no need to update value again in the loop.

Please also note that the value from ptr->data128[1] should be read using READ_ONCE() to prevent compiler from merging, refetching or reordering the read. Currently, there is no READ_ONCE() implemented for __int128, so something like the attached patch should be used.

Based on the above, the loop should be rewritten as:

old.data128[1] = READ_ONCE(ptr->data128[1]);
do {
new->data[2] &= ~DTE_DATA2_INTR_MASK;
new->data[2] |= old.data[2] & (DTE_DATA2_INTR_MASK | DTE_DATA2_RESV_MASK);
} while (!try_cmpxchg128(&ptr->data128[1], &old.data128[1], new->data128[1]));

+}
+
+static void write_dte_lower128(struct dev_table_entry *ptr, struct dev_table_entry *new)
+{
+ struct dev_table_entry old = {};
+
+ /*
+ * Need to preserve DTE[96:106], which can be set by information in IVRS table.
+ * See set_dev_entry_from_acpi().
+ */
+ new->data[1] |= ptr->data[1] & DTE_FLAG_MASK;
+
+ do {
+ old.data128[0] = ptr->data128[0];
+ } while (!try_cmpxchg128(&ptr->data128[0], &old.data128[0], new->data128[0]));

And this one as:

old.data128[0] = READ_ONCE(ptr->data128[0]);
do {
} while (!try_cmpxchg128(&ptr->data128[0], &old.data128[0], new->data128[0]));

Best regards,
Uros.diff --git a/include/asm-generic/rwonce.h b/include/asm-generic/rwonce.h
index 8d0a6280e982..8bf942ad5ef3 100644
--- a/include/asm-generic/rwonce.h
+++ b/include/asm-generic/rwonce.h
@@ -33,7 +33,7 @@
* (e.g. a virtual address) and a strong prevailing wind.
*/
#define compiletime_assert_rwonce_type(t) \
- compiletime_assert(__native_word(t) || sizeof(t) == sizeof(long long), \
+ compiletime_assert(__native_word(t) || sizeof(t) == sizeof(__dword_type), \
"Unsupported access size for {READ,WRITE}_ONCE().")

/*
diff --git a/include/linux/compiler_types.h b/include/linux/compiler_types.h
index 94b8fedfb077..8615e91f48fd 100644
--- a/include/linux/compiler_types.h
+++ b/include/linux/compiler_types.h
@@ -469,6 +469,12 @@ struct ftrace_likely_data {
unsigned type: (unsigned type)0, \
signed type: (signed type)0

+#ifdef __SIZEOF_INT128__
+#define __dword_type __int128
+#else
+#define __dword_type long long
+#endif
+
#define __unqual_scalar_typeof(x) typeof( \
_Generic((x), \
char: (char)0, \
@@ -476,7 +482,7 @@ struct ftrace_likely_data {
__scalar_type_to_expr_cases(short), \
__scalar_type_to_expr_cases(int), \
__scalar_type_to_expr_cases(long), \
- __scalar_type_to_expr_cases(long long), \
+ __scalar_type_to_expr_cases(__dword_type), \
default: (x)))

/* Is this type a native word size -- useful for atomic operations */