[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[xen master] AMD/IOMMU: redo awaiting of command completion



commit b175fc0c1274df34ff8bd89d603c88b014b22f10
Author:     Jan Beulich <jbeulich@xxxxxxxx>
AuthorDate: Tue Jun 29 12:34:37 2021 +0200
Commit:     Jan Beulich <jbeulich@xxxxxxxx>
CommitDate: Tue Jun 29 12:34:37 2021 +0200

    AMD/IOMMU: redo awaiting of command completion
    
    The present abuse of the completion interrupt does not only stand in the
    way of, down the road, using it for its actual purpose, but also
    requires holding the IOMMU lock while waiting for command completion,
    limiting parallelism and keeping interrupts off for non-negligible
    periods of time. Have the IOMMU do an ordinary memory write instead of
    signaling an otherwise disabled interrupt (by just updating a status
    register bit).
    
    Since IOMMU_COMP_WAIT_I_FLAG_SHIFT is now unused and
    IOMMU_COMP_WAIT_[FS]_FLAG_SHIFT already were, drop all three of them
    while at it.
    
    Signed-off-by: Jan Beulich <jbeulich@xxxxxxxx>
    Reviewed-by: Paul Durrant <paul@xxxxxxx>
---
 xen/drivers/passthrough/amd/iommu-defs.h |  3 ---
 xen/drivers/passthrough/amd/iommu_cmd.c  | 30 ++++++++++++++++--------------
 2 files changed, 16 insertions(+), 17 deletions(-)

diff --git a/xen/drivers/passthrough/amd/iommu-defs.h 
b/xen/drivers/passthrough/amd/iommu-defs.h
index 0c97db2a32..774234dfd2 100644
--- a/xen/drivers/passthrough/amd/iommu-defs.h
+++ b/xen/drivers/passthrough/amd/iommu-defs.h
@@ -178,11 +178,8 @@ struct amd_iommu_dte {
 #define IOMMU_COMP_WAIT_DATA_BUFFER_SIZE       8
 #define IOMMU_COMP_WAIT_DATA_BUFFER_ALIGNMENT  8
 #define IOMMU_COMP_WAIT_S_FLAG_MASK            0x00000001
-#define IOMMU_COMP_WAIT_S_FLAG_SHIFT           0
 #define IOMMU_COMP_WAIT_I_FLAG_MASK            0x00000002
-#define IOMMU_COMP_WAIT_I_FLAG_SHIFT           1
 #define IOMMU_COMP_WAIT_F_FLAG_MASK            0x00000004
-#define IOMMU_COMP_WAIT_F_FLAG_SHIFT           2
 #define IOMMU_COMP_WAIT_ADDR_LOW_MASK          0xFFFFFFF8
 #define IOMMU_COMP_WAIT_ADDR_LOW_SHIFT         3
 #define IOMMU_COMP_WAIT_ADDR_HIGH_MASK         0x000FFFFF
diff --git a/xen/drivers/passthrough/amd/iommu_cmd.c 
b/xen/drivers/passthrough/amd/iommu_cmd.c
index 92a688dc9d..e8541276ca 100644
--- a/xen/drivers/passthrough/amd/iommu_cmd.c
+++ b/xen/drivers/passthrough/amd/iommu_cmd.c
@@ -20,6 +20,9 @@
 #include "iommu.h"
 #include "../ats.h"
 
+#define CMD_COMPLETION_INIT 0
+#define CMD_COMPLETION_DONE 1
+
 static void send_iommu_command(struct amd_iommu *iommu,
                                const uint32_t cmd[4])
 {
@@ -49,28 +52,27 @@ static void send_iommu_command(struct amd_iommu *iommu,
 static void flush_command_buffer(struct amd_iommu *iommu,
                                  unsigned int timeout_base)
 {
-    uint32_t cmd[4];
+    static DEFINE_PER_CPU(uint64_t, poll_slot);
+    uint64_t *this_poll_slot = &this_cpu(poll_slot);
+    paddr_t addr = virt_to_maddr(this_poll_slot);
+    /* send a COMPLETION_WAIT command to flush command buffer */
+    uint32_t cmd[4] = {
+        addr | MASK_INSR(IOMMU_CONTROL_ENABLED,
+                         IOMMU_COMP_WAIT_S_FLAG_MASK),
+        (addr >> 32) | MASK_INSR(IOMMU_CMD_COMPLETION_WAIT,
+                                 IOMMU_CMD_OPCODE_MASK),
+        CMD_COMPLETION_DONE
+    };
     s_time_t start, timeout;
     static unsigned int __read_mostly threshold = 1;
 
-    /* RW1C 'ComWaitInt' in status register */
-    writel(IOMMU_STATUS_COMP_WAIT_INT,
-           iommu->mmio_base + IOMMU_STATUS_MMIO_OFFSET);
+    ACCESS_ONCE(*this_poll_slot) = CMD_COMPLETION_INIT;
 
-    /* send an empty COMPLETION_WAIT command to flush command buffer */
-    cmd[3] = cmd[2] = 0;
-    set_field_in_reg_u32(IOMMU_CMD_COMPLETION_WAIT, 0,
-                         IOMMU_CMD_OPCODE_MASK,
-                         IOMMU_CMD_OPCODE_SHIFT, &cmd[1]);
-    set_field_in_reg_u32(IOMMU_CONTROL_ENABLED, 0,
-                         IOMMU_COMP_WAIT_I_FLAG_MASK,
-                         IOMMU_COMP_WAIT_I_FLAG_SHIFT, &cmd[0]);
     send_iommu_command(iommu, cmd);
 
     start = NOW();
     timeout = start + (timeout_base ?: 100) * MILLISECS(threshold);
-    while ( !(readl(iommu->mmio_base + IOMMU_STATUS_MMIO_OFFSET) &
-              IOMMU_STATUS_COMP_WAIT_INT) )
+    while ( ACCESS_ONCE(*this_poll_slot) != CMD_COMPLETION_DONE )
     {
         if ( timeout && NOW() > timeout )
         {
--
generated by git-patchbot for /home/xen/git/xen.git#master



 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.