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

From: Suthikulpanit, Suravee
Date: Fri Oct 11 2024 - 06:23:07 EST


On 10/7/2024 9:42 PM, Uros Bizjak wrote:


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.

Thanks for pointing this out. I will introduce the attached patch separately in this series on your behalf as author/sign-off, and review the current code to properly use the READ_ONCE().

Thanks,
Suravee

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.