thebeanogamer / rpms / qemu-kvm

Forked from rpms/qemu-kvm 5 months ago
Clone

Blame SOURCES/kvm-hw-arm-smmuv3-Get-prepared-for-range-invalidation.patch

a19a21
From 3f027ac56449e51a61e76c18b97fd341d302dc80 Mon Sep 17 00:00:00 2001
a19a21
From: eperezma <eperezma@redhat.com>
a19a21
Date: Tue, 12 Jan 2021 14:36:32 -0500
a19a21
Subject: [PATCH 08/17] hw/arm/smmuv3: Get prepared for range invalidation
a19a21
MIME-Version: 1.0
a19a21
Content-Type: text/plain; charset=UTF-8
a19a21
Content-Transfer-Encoding: 8bit
a19a21
a19a21
RH-Author: eperezma <eperezma@redhat.com>
a19a21
Message-id: <20210112143638.374060-8-eperezma@redhat.com>
a19a21
Patchwork-id: 100600
a19a21
O-Subject: [RHEL-8.4.0 qemu-kvm PATCH v2 07/13] hw/arm/smmuv3: Get prepared for range invalidation
a19a21
Bugzilla: 1843852
a19a21
RH-Acked-by: Xiao Wang <jasowang@redhat.com>
a19a21
RH-Acked-by: Peter Xu <peterx@redhat.com>
a19a21
RH-Acked-by: Auger Eric <eric.auger@redhat.com>
a19a21
a19a21
From: Eric Auger <eric.auger@redhat.com>
a19a21
a19a21
Enhance the smmu_iotlb_inv_iova() helper with range invalidation.
a19a21
This uses the new fields passed in the NH_VA and NH_VAA commands:
a19a21
the size of the range, the level and the granule.
a19a21
a19a21
As NH_VA and NH_VAA both use those fields, their decoding and
a19a21
handling is factorized in a new smmuv3_s1_range_inval() helper.
a19a21
a19a21
Signed-off-by: Eric Auger <eric.auger@redhat.com>
a19a21
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
a19a21
Message-id: 20200728150815.11446-8-eric.auger@redhat.com
a19a21
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
a19a21
(cherry picked from commit d52915616c059ed273caa2d496b58e5d215c5962)
a19a21
Signed-off-by: Eugenio PĂ©rez <eperezma@redhat.com>
a19a21
Signed-off-by: Danilo C. L. de Paula <ddepaula@redhat.com>
a19a21
---
a19a21
 hw/arm/smmu-common.c         | 25 +++++++++++---
a19a21
 hw/arm/smmuv3-internal.h     |  4 +++
a19a21
 hw/arm/smmuv3.c              | 64 +++++++++++++++++++++++-------------
a19a21
 hw/arm/trace-events          |  4 +--
a19a21
 include/hw/arm/smmu-common.h |  3 +-
a19a21
 5 files changed, 69 insertions(+), 31 deletions(-)
a19a21
a19a21
diff --git a/hw/arm/smmu-common.c b/hw/arm/smmu-common.c
a19a21
index 8007edeaaa2..9780404f002 100644
a19a21
--- a/hw/arm/smmu-common.c
a19a21
+++ b/hw/arm/smmu-common.c
a19a21
@@ -143,15 +143,30 @@ static gboolean smmu_hash_remove_by_asid_iova(gpointer key, gpointer value,
a19a21
     if (info->asid >= 0 && info->asid != SMMU_IOTLB_ASID(iotlb_key)) {
a19a21
         return false;
a19a21
     }
a19a21
-    return (info->iova & ~entry->addr_mask) == entry->iova;
a19a21
+    return ((info->iova & ~entry->addr_mask) == entry->iova) ||
a19a21
+           ((entry->iova & ~info->mask) == info->iova);
a19a21
 }
a19a21
 
a19a21
-inline void smmu_iotlb_inv_iova(SMMUState *s, int asid, dma_addr_t iova)
a19a21
+inline void
a19a21
+smmu_iotlb_inv_iova(SMMUState *s, int asid, dma_addr_t iova,
a19a21
+                    uint8_t tg, uint64_t num_pages, uint8_t ttl)
a19a21
 {
a19a21
-    SMMUIOTLBPageInvInfo info = {.asid = asid, .iova = iova};
a19a21
+    if (ttl && (num_pages == 1)) {
a19a21
+        SMMUIOTLBKey key = smmu_get_iotlb_key(asid, iova, tg, ttl);
a19a21
 
a19a21
-    trace_smmu_iotlb_inv_iova(asid, iova);
a19a21
-    g_hash_table_foreach_remove(s->iotlb, smmu_hash_remove_by_asid_iova, &info;;
a19a21
+        g_hash_table_remove(s->iotlb, &key);
a19a21
+    } else {
a19a21
+        /* if tg is not set we use 4KB range invalidation */
a19a21
+        uint8_t granule = tg ? tg * 2 + 10 : 12;
a19a21
+
a19a21
+        SMMUIOTLBPageInvInfo info = {
a19a21
+            .asid = asid, .iova = iova,
a19a21
+            .mask = (num_pages * 1 << granule) - 1};
a19a21
+
a19a21
+        g_hash_table_foreach_remove(s->iotlb,
a19a21
+                                    smmu_hash_remove_by_asid_iova,
a19a21
+                                    &info;;
a19a21
+    }
a19a21
 }
a19a21
 
a19a21
 inline void smmu_iotlb_inv_asid(SMMUState *s, uint16_t asid)
a19a21
diff --git a/hw/arm/smmuv3-internal.h b/hw/arm/smmuv3-internal.h
a19a21
index d190181ef1b..a4ec2c591cd 100644
a19a21
--- a/hw/arm/smmuv3-internal.h
a19a21
+++ b/hw/arm/smmuv3-internal.h
a19a21
@@ -298,6 +298,8 @@ enum { /* Command completion notification */
a19a21
 };
a19a21
 
a19a21
 #define CMD_TYPE(x)         extract32((x)->word[0], 0 , 8)
a19a21
+#define CMD_NUM(x)          extract32((x)->word[0], 12 , 5)
a19a21
+#define CMD_SCALE(x)        extract32((x)->word[0], 20 , 5)
a19a21
 #define CMD_SSEC(x)         extract32((x)->word[0], 10, 1)
a19a21
 #define CMD_SSV(x)          extract32((x)->word[0], 11, 1)
a19a21
 #define CMD_RESUME_AC(x)    extract32((x)->word[0], 12, 1)
a19a21
@@ -310,6 +312,8 @@ enum { /* Command completion notification */
a19a21
 #define CMD_RESUME_STAG(x)  extract32((x)->word[2], 0 , 16)
a19a21
 #define CMD_RESP(x)         extract32((x)->word[2], 11, 2)
a19a21
 #define CMD_LEAF(x)         extract32((x)->word[2], 0 , 1)
a19a21
+#define CMD_TTL(x)          extract32((x)->word[2], 8 , 2)
a19a21
+#define CMD_TG(x)           extract32((x)->word[2], 10, 2)
a19a21
 #define CMD_STE_RANGE(x)    extract32((x)->word[2], 0 , 5)
a19a21
 #define CMD_ADDR(x) ({                                        \
a19a21
             uint64_t high = (uint64_t)(x)->word[3];           \
a19a21
diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
a19a21
index ae2b769f891..f4d5d9d8222 100644
a19a21
--- a/hw/arm/smmuv3.c
a19a21
+++ b/hw/arm/smmuv3.c
a19a21
@@ -773,42 +773,49 @@ epilogue:
a19a21
  * @n: notifier to be called
a19a21
  * @asid: address space ID or negative value if we don't care
a19a21
  * @iova: iova
a19a21
+ * @tg: translation granule (if communicated through range invalidation)
a19a21
+ * @num_pages: number of @granule sized pages (if tg != 0), otherwise 1
a19a21
  */
a19a21
 static void smmuv3_notify_iova(IOMMUMemoryRegion *mr,
a19a21
                                IOMMUNotifier *n,
a19a21
-                               int asid,
a19a21
-                               dma_addr_t iova)
a19a21
+                               int asid, dma_addr_t iova,
a19a21
+                               uint8_t tg, uint64_t num_pages)
a19a21
 {
a19a21
     SMMUDevice *sdev = container_of(mr, SMMUDevice, iommu);
a19a21
-    SMMUEventInfo event = {.inval_ste_allowed = true};
a19a21
-    SMMUTransTableInfo *tt;
a19a21
-    SMMUTransCfg *cfg;
a19a21
     IOMMUTLBEntry entry;
a19a21
+    uint8_t granule = tg;
a19a21
 
a19a21
-    cfg = smmuv3_get_config(sdev, &event);
a19a21
-    if (!cfg) {
a19a21
-        return;
a19a21
-    }
a19a21
+    if (!tg) {
a19a21
+        SMMUEventInfo event = {.inval_ste_allowed = true};
a19a21
+        SMMUTransCfg *cfg = smmuv3_get_config(sdev, &event);
a19a21
+        SMMUTransTableInfo *tt;
a19a21
 
a19a21
-    if (asid >= 0 && cfg->asid != asid) {
a19a21
-        return;
a19a21
-    }
a19a21
+        if (!cfg) {
a19a21
+            return;
a19a21
+        }
a19a21
 
a19a21
-    tt = select_tt(cfg, iova);
a19a21
-    if (!tt) {
a19a21
-        return;
a19a21
+        if (asid >= 0 && cfg->asid != asid) {
a19a21
+            return;
a19a21
+        }
a19a21
+
a19a21
+        tt = select_tt(cfg, iova);
a19a21
+        if (!tt) {
a19a21
+            return;
a19a21
+        }
a19a21
+        granule = tt->granule_sz;
a19a21
     }
a19a21
 
a19a21
     entry.target_as = &address_space_memory;
a19a21
     entry.iova = iova;
a19a21
-    entry.addr_mask = (1 << tt->granule_sz) - 1;
a19a21
+    entry.addr_mask = num_pages * (1 << granule) - 1;
a19a21
     entry.perm = IOMMU_NONE;
a19a21
 
a19a21
     memory_region_notify_one(n, &entry);
a19a21
 }
a19a21
 
a19a21
-/* invalidate an asid/iova tuple in all mr's */
a19a21
-static void smmuv3_inv_notifiers_iova(SMMUState *s, int asid, dma_addr_t iova)
a19a21
+/* invalidate an asid/iova range tuple in all mr's */
a19a21
+static void smmuv3_inv_notifiers_iova(SMMUState *s, int asid, dma_addr_t iova,
a19a21
+                                      uint8_t tg, uint64_t num_pages)
a19a21
 {
a19a21
     SMMUDevice *sdev;
a19a21
 
a19a21
@@ -816,28 +823,39 @@ static void smmuv3_inv_notifiers_iova(SMMUState *s, int asid, dma_addr_t iova)
a19a21
         IOMMUMemoryRegion *mr = &sdev->iommu;
a19a21
         IOMMUNotifier *n;
a19a21
 
a19a21
-        trace_smmuv3_inv_notifiers_iova(mr->parent_obj.name, asid, iova);
a19a21
+        trace_smmuv3_inv_notifiers_iova(mr->parent_obj.name, asid, iova,
a19a21
+                                        tg, num_pages);
a19a21
 
a19a21
         IOMMU_NOTIFIER_FOREACH(n, mr) {
a19a21
-            smmuv3_notify_iova(mr, n, asid, iova);
a19a21
+            smmuv3_notify_iova(mr, n, asid, iova, tg, num_pages);
a19a21
         }
a19a21
     }
a19a21
 }
a19a21
 
a19a21
 static void smmuv3_s1_range_inval(SMMUState *s, Cmd *cmd)
a19a21
 {
a19a21
+    uint8_t scale = 0, num = 0, ttl = 0;
a19a21
     dma_addr_t addr = CMD_ADDR(cmd);
a19a21
     uint8_t type = CMD_TYPE(cmd);
a19a21
     uint16_t vmid = CMD_VMID(cmd);
a19a21
     bool leaf = CMD_LEAF(cmd);
a19a21
+    uint8_t tg = CMD_TG(cmd);
a19a21
+    hwaddr num_pages = 1;
a19a21
     int asid = -1;
a19a21
 
a19a21
+    if (tg) {
a19a21
+        scale = CMD_SCALE(cmd);
a19a21
+        num = CMD_NUM(cmd);
a19a21
+        ttl = CMD_TTL(cmd);
a19a21
+        num_pages = (num + 1) * (1 << (scale));
a19a21
+    }
a19a21
+
a19a21
     if (type == SMMU_CMD_TLBI_NH_VA) {
a19a21
         asid = CMD_ASID(cmd);
a19a21
     }
a19a21
-    trace_smmuv3_s1_range_inval(vmid, asid, addr, leaf);
a19a21
-    smmuv3_inv_notifiers_iova(s, asid, addr);
a19a21
-    smmu_iotlb_inv_iova(s, asid, addr);
a19a21
+    trace_smmuv3_s1_range_inval(vmid, asid, addr, tg, num_pages, ttl, leaf);
a19a21
+    smmuv3_inv_notifiers_iova(s, asid, addr, tg, num_pages);
a19a21
+    smmu_iotlb_inv_iova(s, asid, addr, tg, num_pages, ttl);
a19a21
 }
a19a21
 
a19a21
 static int smmuv3_cmdq_consume(SMMUv3State *s)
a19a21
diff --git a/hw/arm/trace-events b/hw/arm/trace-events
a19a21
index c219fe9e828..3d905e0f7d0 100644
a19a21
--- a/hw/arm/trace-events
a19a21
+++ b/hw/arm/trace-events
a19a21
@@ -45,11 +45,11 @@ smmuv3_cmdq_cfgi_ste_range(int start, int end) "start=0x%d - end=0x%d"
a19a21
 smmuv3_cmdq_cfgi_cd(uint32_t sid) "streamid = %d"
a19a21
 smmuv3_config_cache_hit(uint32_t sid, uint32_t hits, uint32_t misses, uint32_t perc) "Config cache HIT for sid %d (hits=%d, misses=%d, hit rate=%d)"
a19a21
 smmuv3_config_cache_miss(uint32_t sid, uint32_t hits, uint32_t misses, uint32_t perc) "Config cache MISS for sid %d (hits=%d, misses=%d, hit rate=%d)"
a19a21
-smmuv3_s1_range_inval(int vmid, int asid, uint64_t addr, bool leaf) "vmid =%d asid =%d addr=0x%"PRIx64" leaf=%d"
a19a21
+smmuv3_s1_range_inval(int vmid, int asid, uint64_t addr, uint8_t tg, uint64_t num_pages, uint8_t ttl, bool leaf) "vmid =%d asid =%d addr=0x%"PRIx64" tg=%d num_pages=0x%"PRIx64" ttl=%d leaf=%d"
a19a21
 smmuv3_cmdq_tlbi_nh(void) ""
a19a21
 smmuv3_cmdq_tlbi_nh_asid(uint16_t asid) "asid=%d"
a19a21
 smmuv3_config_cache_inv(uint32_t sid) "Config cache INV for sid %d"
a19a21
 smmuv3_notify_flag_add(const char *iommu) "ADD SMMUNotifier node for iommu mr=%s"
a19a21
 smmuv3_notify_flag_del(const char *iommu) "DEL SMMUNotifier node for iommu mr=%s"
a19a21
-smmuv3_inv_notifiers_iova(const char *name, uint16_t asid, uint64_t iova) "iommu mr=%s asid=%d iova=0x%"PRIx64
a19a21
+smmuv3_inv_notifiers_iova(const char *name, uint16_t asid, uint64_t iova, uint8_t tg, uint64_t num_pages) "iommu mr=%s asid=%d iova=0x%"PRIx64" tg=%d num_pages=0x%"PRIx64
a19a21
 
a19a21
diff --git a/include/hw/arm/smmu-common.h b/include/hw/arm/smmu-common.h
a19a21
index bbf3abc41fd..13489a1ac0d 100644
a19a21
--- a/include/hw/arm/smmu-common.h
a19a21
+++ b/include/hw/arm/smmu-common.h
a19a21
@@ -168,7 +168,8 @@ SMMUIOTLBKey smmu_get_iotlb_key(uint16_t asid, uint64_t iova,
a19a21
                                 uint8_t tg, uint8_t level);
a19a21
 void smmu_iotlb_inv_all(SMMUState *s);
a19a21
 void smmu_iotlb_inv_asid(SMMUState *s, uint16_t asid);
a19a21
-void smmu_iotlb_inv_iova(SMMUState *s, int asid, dma_addr_t iova);
a19a21
+void smmu_iotlb_inv_iova(SMMUState *s, int asid, dma_addr_t iova,
a19a21
+                         uint8_t tg, uint64_t num_pages, uint8_t ttl);
a19a21
 
a19a21
 /* Unmap the range of all the notifiers registered to any IOMMU mr */
a19a21
 void smmu_inv_notifiers_all(SMMUState *s);
a19a21
-- 
a19a21
2.27.0
a19a21