qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/3] Some SMMUv3 bug fixes
@ 2021-02-18 14:02 Eric Auger
  2021-02-18 14:02 ` [PATCH 1/3] hw/arm/smmu-common: Fix smmu_iotlb_inv_iova when asid is not set Eric Auger
                   ` (2 more replies)
  0 siblings, 3 replies; 4+ messages in thread
From: Eric Auger @ 2021-02-18 14:02 UTC (permalink / raw)
  To: eric.auger.pro, eric.auger, qemu-devel, qemu-arm, peter.maydell
  Cc: jasowang, jiangkunkun, peterx, shameerali.kolothum.thodi

Hi,

This series fixes three issues:

- top SID computation overflow when handling SMMU_CMD_CFGI_ALL
- internal IOTLB handling (changes related to range invalidation)
  - smmu_iotlb_inv_iova with asid = -1
  - non power of 2 invalidation range handling.

Best Regards

Eric

This series can be found at:
https://github.com/eauger/qemu/tree/viommu_fixes_for_6


Eric Auger (3):
  hw/arm/smmu-common: Fix smmu_iotlb_inv_iova when asid is not set
  hw/arm/smmuv3: Enforce invalidation on a power of two range
  hw/arm/smmuv3: Fix SMMU_CMD_CFGI_STE_RANGE handling

 hw/arm/smmu-common.c   | 32 ++++++++++++++----------
 hw/arm/smmu-internal.h |  5 ++++
 hw/arm/smmuv3.c        | 56 ++++++++++++++++++++++++++++--------------
 3 files changed, 62 insertions(+), 31 deletions(-)

-- 
2.26.2



^ permalink raw reply	[flat|nested] 4+ messages in thread

* [PATCH 1/3] hw/arm/smmu-common: Fix smmu_iotlb_inv_iova when asid is not set
  2021-02-18 14:02 [PATCH 0/3] Some SMMUv3 bug fixes Eric Auger
@ 2021-02-18 14:02 ` Eric Auger
  2021-02-18 14:02 ` [PATCH 2/3] hw/arm/smmuv3: Enforce invalidation on a power of two range Eric Auger
  2021-02-18 14:02 ` [PATCH 3/3] hw/arm/smmuv3: Fix SMMU_CMD_CFGI_STE_RANGE handling Eric Auger
  2 siblings, 0 replies; 4+ messages in thread
From: Eric Auger @ 2021-02-18 14:02 UTC (permalink / raw)
  To: eric.auger.pro, eric.auger, qemu-devel, qemu-arm, peter.maydell
  Cc: jasowang, jiangkunkun, peterx, shameerali.kolothum.thodi

If the asid is not set, do not attempt to locate the key directly
as all inserted keys have a valid asid.

Use g_hash_table_foreach_remove instead.

Signed-off-by: Eric Auger <eric.auger@redhat.com>
---
 hw/arm/smmu-common.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/hw/arm/smmu-common.c b/hw/arm/smmu-common.c
index 405d5c5325..e9ca3aebb2 100644
--- a/hw/arm/smmu-common.c
+++ b/hw/arm/smmu-common.c
@@ -151,7 +151,7 @@ inline void
 smmu_iotlb_inv_iova(SMMUState *s, int asid, dma_addr_t iova,
                     uint8_t tg, uint64_t num_pages, uint8_t ttl)
 {
-    if (ttl && (num_pages == 1)) {
+    if (ttl && (num_pages == 1) && (asid >= 0)) {
         SMMUIOTLBKey key = smmu_get_iotlb_key(asid, iova, tg, ttl);
 
         g_hash_table_remove(s->iotlb, &key);
-- 
2.26.2



^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [PATCH 2/3] hw/arm/smmuv3: Enforce invalidation on a power of two range
  2021-02-18 14:02 [PATCH 0/3] Some SMMUv3 bug fixes Eric Auger
  2021-02-18 14:02 ` [PATCH 1/3] hw/arm/smmu-common: Fix smmu_iotlb_inv_iova when asid is not set Eric Auger
@ 2021-02-18 14:02 ` Eric Auger
  2021-02-18 14:02 ` [PATCH 3/3] hw/arm/smmuv3: Fix SMMU_CMD_CFGI_STE_RANGE handling Eric Auger
  2 siblings, 0 replies; 4+ messages in thread
From: Eric Auger @ 2021-02-18 14:02 UTC (permalink / raw)
  To: eric.auger.pro, eric.auger, qemu-devel, qemu-arm, peter.maydell
  Cc: jasowang, jiangkunkun, peterx, shameerali.kolothum.thodi

As of today, the driver can invalide a number of pages that is
not a power of 2. However IOTLB unmap notifications and internal
IOTLB invalidations work with masks leading to erroneous
invalidations.

In case the range is not a power of 2, split invalidations into
power of 2 invalidations.

When looking for a single page entry in the vSMMU internal IOTLB,
let's make sure that if the entry is not found using a
g_hash_table_remove() we iterate over all the entries to find a
potential range that overlaps it.

Signed-off-by: Eric Auger <eric.auger@redhat.com>
---
 hw/arm/smmu-common.c | 30 ++++++++++++++++++------------
 hw/arm/smmuv3.c      | 22 ++++++++++++++++++----
 2 files changed, 36 insertions(+), 16 deletions(-)

diff --git a/hw/arm/smmu-common.c b/hw/arm/smmu-common.c
index e9ca3aebb2..84d2c62c26 100644
--- a/hw/arm/smmu-common.c
+++ b/hw/arm/smmu-common.c
@@ -151,22 +151,28 @@ inline void
 smmu_iotlb_inv_iova(SMMUState *s, int asid, dma_addr_t iova,
                     uint8_t tg, uint64_t num_pages, uint8_t ttl)
 {
+    /* if tg is not set we use 4KB range invalidation */
+    uint8_t granule = tg ? tg * 2 + 10 : 12;
+
     if (ttl && (num_pages == 1) && (asid >= 0)) {
         SMMUIOTLBKey key = smmu_get_iotlb_key(asid, iova, tg, ttl);
 
-        g_hash_table_remove(s->iotlb, &key);
-    } else {
-        /* if tg is not set we use 4KB range invalidation */
-        uint8_t granule = tg ? tg * 2 + 10 : 12;
-
-        SMMUIOTLBPageInvInfo info = {
-            .asid = asid, .iova = iova,
-            .mask = (num_pages * 1 << granule) - 1};
-
-        g_hash_table_foreach_remove(s->iotlb,
-                                    smmu_hash_remove_by_asid_iova,
-                                    &info);
+        if (g_hash_table_remove(s->iotlb, &key)) {
+            return;
+        }
+        /*
+         * if the entry is not found, let's see if it does not
+         * belong to a larger IOTLB entry
+         */
     }
+
+    SMMUIOTLBPageInvInfo info = {
+        .asid = asid, .iova = iova,
+        .mask = (num_pages * 1 << granule) - 1};
+
+    g_hash_table_foreach_remove(s->iotlb,
+                                smmu_hash_remove_by_asid_iova,
+                                &info);
 }
 
 inline void smmu_iotlb_inv_asid(SMMUState *s, uint16_t asid)
diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
index bd1f97000d..0bb8065b16 100644
--- a/hw/arm/smmuv3.c
+++ b/hw/arm/smmuv3.c
@@ -861,7 +861,7 @@ static void smmuv3_s1_range_inval(SMMUState *s, Cmd *cmd)
     uint16_t vmid = CMD_VMID(cmd);
     bool leaf = CMD_LEAF(cmd);
     uint8_t tg = CMD_TG(cmd);
-    hwaddr num_pages = 1;
+    uint64_t num_pages = 1;
     int asid = -1;
 
     if (tg) {
@@ -874,9 +874,23 @@ static void smmuv3_s1_range_inval(SMMUState *s, Cmd *cmd)
     if (type == SMMU_CMD_TLBI_NH_VA) {
         asid = CMD_ASID(cmd);
     }
-    trace_smmuv3_s1_range_inval(vmid, asid, addr, tg, num_pages, ttl, leaf);
-    smmuv3_inv_notifiers_iova(s, asid, addr, tg, num_pages);
-    smmu_iotlb_inv_iova(s, asid, addr, tg, num_pages, ttl);
+
+    /* Split invalidations into ^2 range invalidations */
+    while (num_pages) {
+        uint8_t granule = tg * 2 + 10;
+        uint8_t highest_bit;
+        uint64_t pow2pages;
+
+        highest_bit = 64 - clz64(num_pages) - 1;
+        pow2pages =  BIT_ULL(highest_bit);
+
+        trace_smmuv3_s1_range_inval(vmid, asid, addr, tg, pow2pages, ttl, leaf);
+        smmuv3_inv_notifiers_iova(s, asid, addr, tg, pow2pages);
+        smmu_iotlb_inv_iova(s, asid, addr, tg, pow2pages, ttl);
+
+        num_pages &= ~pow2pages;
+        addr += pow2pages * BIT_ULL(granule);
+    }
 }
 
 static int smmuv3_cmdq_consume(SMMUv3State *s)
-- 
2.26.2



^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [PATCH 3/3] hw/arm/smmuv3: Fix SMMU_CMD_CFGI_STE_RANGE handling
  2021-02-18 14:02 [PATCH 0/3] Some SMMUv3 bug fixes Eric Auger
  2021-02-18 14:02 ` [PATCH 1/3] hw/arm/smmu-common: Fix smmu_iotlb_inv_iova when asid is not set Eric Auger
  2021-02-18 14:02 ` [PATCH 2/3] hw/arm/smmuv3: Enforce invalidation on a power of two range Eric Auger
@ 2021-02-18 14:02 ` Eric Auger
  2 siblings, 0 replies; 4+ messages in thread
From: Eric Auger @ 2021-02-18 14:02 UTC (permalink / raw)
  To: eric.auger.pro, eric.auger, qemu-devel, qemu-arm, peter.maydell
  Cc: jasowang, jiangkunkun, peterx, shameerali.kolothum.thodi

If the whole SID range (32b) is invalidated (SMMU_CMD_CFGI_ALL),
@end overflows and we fail to handle the command properly.

Once this gets fixed, the current code really is awkward in the
sense it loops over the whole range instead of removing the
currently cached configs through a hash table lookup.

Fix both the overflow and the lookup.

Signed-off-by: Eric Auger <eric.auger@redhat.com>
---
 hw/arm/smmu-internal.h |  5 +++++
 hw/arm/smmuv3.c        | 34 ++++++++++++++++++++--------------
 2 files changed, 25 insertions(+), 14 deletions(-)

diff --git a/hw/arm/smmu-internal.h b/hw/arm/smmu-internal.h
index 55147f29be..2d75b31953 100644
--- a/hw/arm/smmu-internal.h
+++ b/hw/arm/smmu-internal.h
@@ -104,4 +104,9 @@ typedef struct SMMUIOTLBPageInvInfo {
     uint64_t mask;
 } SMMUIOTLBPageInvInfo;
 
+typedef struct SMMUSIDRange {
+    uint32_t start;
+    uint32_t end;
+} SMMUSIDRange;
+
 #endif
diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
index 0bb8065b16..032cc3b300 100644
--- a/hw/arm/smmuv3.c
+++ b/hw/arm/smmuv3.c
@@ -32,6 +32,7 @@
 
 #include "hw/arm/smmuv3.h"
 #include "smmuv3-internal.h"
+#include "smmu-internal.h"
 
 /**
  * smmuv3_trigger_irq - pulse @irq if enabled and update
@@ -893,6 +894,20 @@ static void smmuv3_s1_range_inval(SMMUState *s, Cmd *cmd)
     }
 }
 
+static gboolean
+smmuv3_invalidate_ste(gpointer key, gpointer value, gpointer user_data)
+{
+    SMMUDevice *sdev = (SMMUDevice *)key;
+    uint32_t sid = smmu_get_sid(sdev);
+    SMMUSIDRange *sid_range = (SMMUSIDRange *)user_data;
+
+    if (sid < sid_range->start || sid > sid_range->end) {
+        return false;
+    }
+    trace_smmuv3_config_cache_inv(sid);
+    return true;
+}
+
 static int smmuv3_cmdq_consume(SMMUv3State *s)
 {
     SMMUState *bs = ARM_SMMU(s);
@@ -963,27 +978,18 @@ static int smmuv3_cmdq_consume(SMMUv3State *s)
         }
         case SMMU_CMD_CFGI_STE_RANGE: /* same as SMMU_CMD_CFGI_ALL */
         {
-            uint32_t start = CMD_SID(&cmd), end, i;
+            uint32_t start = CMD_SID(&cmd);
             uint8_t range = CMD_STE_RANGE(&cmd);
+            uint64_t end = start + (1ULL << (range + 1)) - 1;
+            SMMUSIDRange sid_range = {start, end};
 
             if (CMD_SSEC(&cmd)) {
                 cmd_error = SMMU_CERROR_ILL;
                 break;
             }
-
-            end = start + (1 << (range + 1)) - 1;
             trace_smmuv3_cmdq_cfgi_ste_range(start, end);
-
-            for (i = start; i <= end; i++) {
-                IOMMUMemoryRegion *mr = smmu_iommu_mr(bs, i);
-                SMMUDevice *sdev;
-
-                if (!mr) {
-                    continue;
-                }
-                sdev = container_of(mr, SMMUDevice, iommu);
-                smmuv3_flush_config(sdev);
-            }
+            g_hash_table_foreach_remove(bs->configs, smmuv3_invalidate_ste,
+                                        &sid_range);
             break;
         }
         case SMMU_CMD_CFGI_CD:
-- 
2.26.2



^ permalink raw reply related	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2021-02-18 14:09 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2021-02-18 14:02 [PATCH 0/3] Some SMMUv3 bug fixes Eric Auger
2021-02-18 14:02 ` [PATCH 1/3] hw/arm/smmu-common: Fix smmu_iotlb_inv_iova when asid is not set Eric Auger
2021-02-18 14:02 ` [PATCH 2/3] hw/arm/smmuv3: Enforce invalidation on a power of two range Eric Auger
2021-02-18 14:02 ` [PATCH 3/3] hw/arm/smmuv3: Fix SMMU_CMD_CFGI_STE_RANGE handling Eric Auger

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).