Blame SOURCES/kvm-hw-arm-smmu-common-Manage-IOTLB-block-entries.patch

c687bc
From 4770f43dab482e4585d3555933a473cf24e796db Mon Sep 17 00:00:00 2001
c687bc
From: eperezma <eperezma@redhat.com>
c687bc
Date: Tue, 12 Jan 2021 14:36:30 -0500
c687bc
Subject: [PATCH 06/17] hw/arm/smmu-common: Manage IOTLB block entries
c687bc
MIME-Version: 1.0
c687bc
Content-Type: text/plain; charset=UTF-8
c687bc
Content-Transfer-Encoding: 8bit
c687bc
c687bc
RH-Author: eperezma <eperezma@redhat.com>
c687bc
Message-id: <20210112143638.374060-6-eperezma@redhat.com>
c687bc
Patchwork-id: 100598
c687bc
O-Subject: [RHEL-8.4.0 qemu-kvm PATCH v2 05/13] hw/arm/smmu-common: Manage IOTLB block entries
c687bc
Bugzilla: 1843852
c687bc
RH-Acked-by: Xiao Wang <jasowang@redhat.com>
c687bc
RH-Acked-by: Peter Xu <peterx@redhat.com>
c687bc
RH-Acked-by: Auger Eric <eric.auger@redhat.com>
c687bc
c687bc
From: Eric Auger <eric.auger@redhat.com>
c687bc
c687bc
At the moment each entry in the IOTLB corresponds to a page sized
c687bc
mapping (4K, 16K or 64K), even if the page belongs to a mapped
c687bc
block. In case of block mapping this unefficiently consumes IOTLB
c687bc
entries.
c687bc
c687bc
Change the value of the entry so that it reflects the actual
c687bc
mapping it belongs to (block or page start address and size).
c687bc
c687bc
Also the level/tg of the entry is encoded in the key. In subsequent
c687bc
patches we will enable range invalidation. This latter is able
c687bc
to provide the level/tg of the entry.
c687bc
c687bc
Encoding the level/tg directly in the key will allow to invalidate
c687bc
using g_hash_table_remove() when num_pages equals to 1.
c687bc
c687bc
Signed-off-by: Eric Auger <eric.auger@redhat.com>
c687bc
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
c687bc
Message-id: 20200728150815.11446-6-eric.auger@redhat.com
c687bc
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
c687bc
(cherry picked from commit 9e54dee71fcfaae69f87b8e1f51485a832266a39)
c687bc
Signed-off-by: Eugenio PĂ©rez <eperezma@redhat.com>
c687bc
Signed-off-by: Danilo C. L. de Paula <ddepaula@redhat.com>
c687bc
---
c687bc
 hw/arm/smmu-common.c         | 67 ++++++++++++++++++++++++++----------
c687bc
 hw/arm/smmu-internal.h       |  7 ++++
c687bc
 hw/arm/smmuv3.c              |  6 ++--
c687bc
 hw/arm/trace-events          |  2 +-
c687bc
 include/hw/arm/smmu-common.h | 10 ++++--
c687bc
 5 files changed, 67 insertions(+), 25 deletions(-)
c687bc
c687bc
diff --git a/hw/arm/smmu-common.c b/hw/arm/smmu-common.c
c687bc
index 06e9e38b007..8007edeaaa2 100644
c687bc
--- a/hw/arm/smmu-common.c
c687bc
+++ b/hw/arm/smmu-common.c
c687bc
@@ -39,7 +39,7 @@ static guint smmu_iotlb_key_hash(gconstpointer v)
c687bc
 
c687bc
     /* Jenkins hash */
c687bc
     a = b = c = JHASH_INITVAL + sizeof(*key);
c687bc
-    a += key->asid;
c687bc
+    a += key->asid + key->level + key->tg;
c687bc
     b += extract64(key->iova, 0, 32);
c687bc
     c += extract64(key->iova, 32, 32);
c687bc
 
c687bc
@@ -51,24 +51,41 @@ static guint smmu_iotlb_key_hash(gconstpointer v)
c687bc
 
c687bc
 static gboolean smmu_iotlb_key_equal(gconstpointer v1, gconstpointer v2)
c687bc
 {
c687bc
-    const SMMUIOTLBKey *k1 = v1;
c687bc
-    const SMMUIOTLBKey *k2 = v2;
c687bc
+    SMMUIOTLBKey *k1 = (SMMUIOTLBKey *)v1, *k2 = (SMMUIOTLBKey *)v2;
c687bc
 
c687bc
-    return (k1->asid == k2->asid) && (k1->iova == k2->iova);
c687bc
+    return (k1->asid == k2->asid) && (k1->iova == k2->iova) &&
c687bc
+           (k1->level == k2->level) && (k1->tg == k2->tg);
c687bc
 }
c687bc
 
c687bc
-SMMUIOTLBKey smmu_get_iotlb_key(uint16_t asid, uint64_t iova)
c687bc
+SMMUIOTLBKey smmu_get_iotlb_key(uint16_t asid, uint64_t iova,
c687bc
+                                uint8_t tg, uint8_t level)
c687bc
 {
c687bc
-    SMMUIOTLBKey key = {.asid = asid, .iova = iova};
c687bc
+    SMMUIOTLBKey key = {.asid = asid, .iova = iova, .tg = tg, .level = level};
c687bc
 
c687bc
     return key;
c687bc
 }
c687bc
 
c687bc
 SMMUTLBEntry *smmu_iotlb_lookup(SMMUState *bs, SMMUTransCfg *cfg,
c687bc
-                                hwaddr iova)
c687bc
+                                SMMUTransTableInfo *tt, hwaddr iova)
c687bc
 {
c687bc
-    SMMUIOTLBKey key = smmu_get_iotlb_key(cfg->asid, iova);
c687bc
-    SMMUTLBEntry *entry = g_hash_table_lookup(bs->iotlb, &key);
c687bc
+    uint8_t tg = (tt->granule_sz - 10) / 2;
c687bc
+    uint8_t inputsize = 64 - tt->tsz;
c687bc
+    uint8_t stride = tt->granule_sz - 3;
c687bc
+    uint8_t level = 4 - (inputsize - 4) / stride;
c687bc
+    SMMUTLBEntry *entry = NULL;
c687bc
+
c687bc
+    while (level <= 3) {
c687bc
+        uint64_t subpage_size = 1ULL << level_shift(level, tt->granule_sz);
c687bc
+        uint64_t mask = subpage_size - 1;
c687bc
+        SMMUIOTLBKey key;
c687bc
+
c687bc
+        key = smmu_get_iotlb_key(cfg->asid, iova & ~mask, tg, level);
c687bc
+        entry = g_hash_table_lookup(bs->iotlb, &key);
c687bc
+        if (entry) {
c687bc
+            break;
c687bc
+        }
c687bc
+        level++;
c687bc
+    }
c687bc
 
c687bc
     if (entry) {
c687bc
         cfg->iotlb_hits++;
c687bc
@@ -89,13 +106,14 @@ SMMUTLBEntry *smmu_iotlb_lookup(SMMUState *bs, SMMUTransCfg *cfg,
c687bc
 void smmu_iotlb_insert(SMMUState *bs, SMMUTransCfg *cfg, SMMUTLBEntry *new)
c687bc
 {
c687bc
     SMMUIOTLBKey *key = g_new0(SMMUIOTLBKey, 1);
c687bc
+    uint8_t tg = (new->granule - 10) / 2;
c687bc
 
c687bc
     if (g_hash_table_size(bs->iotlb) >= SMMU_IOTLB_MAX_SIZE) {
c687bc
         smmu_iotlb_inv_all(bs);
c687bc
     }
c687bc
 
c687bc
-    *key = smmu_get_iotlb_key(cfg->asid, new->entry.iova);
c687bc
-    trace_smmu_iotlb_insert(cfg->asid, new->entry.iova);
c687bc
+    *key = smmu_get_iotlb_key(cfg->asid, new->entry.iova, tg, new->level);
c687bc
+    trace_smmu_iotlb_insert(cfg->asid, new->entry.iova, tg, new->level);
c687bc
     g_hash_table_insert(bs->iotlb, key, new);
c687bc
 }
c687bc
 
c687bc
@@ -114,12 +132,26 @@ static gboolean smmu_hash_remove_by_asid(gpointer key, gpointer value,
c687bc
     return SMMU_IOTLB_ASID(*iotlb_key) == asid;
c687bc
 }
c687bc
 
c687bc
-inline void smmu_iotlb_inv_iova(SMMUState *s, uint16_t asid, dma_addr_t iova)
c687bc
+static gboolean smmu_hash_remove_by_asid_iova(gpointer key, gpointer value,
c687bc
+                                              gpointer user_data)
c687bc
 {
c687bc
-    SMMUIOTLBKey key = smmu_get_iotlb_key(asid, iova);
c687bc
+    SMMUTLBEntry *iter = (SMMUTLBEntry *)value;
c687bc
+    IOMMUTLBEntry *entry = &iter->entry;
c687bc
+    SMMUIOTLBPageInvInfo *info = (SMMUIOTLBPageInvInfo *)user_data;
c687bc
+    SMMUIOTLBKey iotlb_key = *(SMMUIOTLBKey *)key;
c687bc
+
c687bc
+    if (info->asid >= 0 && info->asid != SMMU_IOTLB_ASID(iotlb_key)) {
c687bc
+        return false;
c687bc
+    }
c687bc
+    return (info->iova & ~entry->addr_mask) == entry->iova;
c687bc
+}
c687bc
+
c687bc
+inline void smmu_iotlb_inv_iova(SMMUState *s, int asid, dma_addr_t iova)
c687bc
+{
c687bc
+    SMMUIOTLBPageInvInfo info = {.asid = asid, .iova = iova};
c687bc
 
c687bc
     trace_smmu_iotlb_inv_iova(asid, iova);
c687bc
-    g_hash_table_remove(s->iotlb, &key);
c687bc
+    g_hash_table_foreach_remove(s->iotlb, smmu_hash_remove_by_asid_iova, &info;;
c687bc
 }
c687bc
 
c687bc
 inline void smmu_iotlb_inv_asid(SMMUState *s, uint16_t asid)
c687bc
@@ -247,9 +279,6 @@ static int smmu_ptw_64(SMMUTransCfg *cfg,
c687bc
     baseaddr = extract64(tt->ttb, 0, 48);
c687bc
     baseaddr &= ~indexmask;
c687bc
 
c687bc
-    tlbe->entry.iova = iova;
c687bc
-    tlbe->entry.addr_mask = (1 << granule_sz) - 1;
c687bc
-
c687bc
     while (level <= 3) {
c687bc
         uint64_t subpage_size = 1ULL << level_shift(level, granule_sz);
c687bc
         uint64_t mask = subpage_size - 1;
c687bc
@@ -299,7 +328,9 @@ static int smmu_ptw_64(SMMUTransCfg *cfg,
c687bc
             goto error;
c687bc
         }
c687bc
 
c687bc
-        tlbe->entry.translated_addr = gpa + (iova & mask);
c687bc
+        tlbe->entry.translated_addr = gpa;
c687bc
+        tlbe->entry.iova = iova & ~mask;
c687bc
+        tlbe->entry.addr_mask = mask;
c687bc
         tlbe->entry.perm = PTE_AP_TO_PERM(ap);
c687bc
         tlbe->level = level;
c687bc
         tlbe->granule = granule_sz;
c687bc
diff --git a/hw/arm/smmu-internal.h b/hw/arm/smmu-internal.h
c687bc
index 3104f768cd2..55147f29be4 100644
c687bc
--- a/hw/arm/smmu-internal.h
c687bc
+++ b/hw/arm/smmu-internal.h
c687bc
@@ -97,4 +97,11 @@ uint64_t iova_level_offset(uint64_t iova, int inputsize,
c687bc
 }
c687bc
 
c687bc
 #define SMMU_IOTLB_ASID(key) ((key).asid)
c687bc
+
c687bc
+typedef struct SMMUIOTLBPageInvInfo {
c687bc
+    int asid;
c687bc
+    uint64_t iova;
c687bc
+    uint64_t mask;
c687bc
+} SMMUIOTLBPageInvInfo;
c687bc
+
c687bc
 #endif
c687bc
diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
c687bc
index ad8212779d3..067c9480a03 100644
c687bc
--- a/hw/arm/smmuv3.c
c687bc
+++ b/hw/arm/smmuv3.c
c687bc
@@ -662,7 +662,7 @@ static IOMMUTLBEntry smmuv3_translate(IOMMUMemoryRegion *mr, hwaddr addr,
c687bc
     page_mask = (1ULL << (tt->granule_sz)) - 1;
c687bc
     aligned_addr = addr & ~page_mask;
c687bc
 
c687bc
-    cached_entry = smmu_iotlb_lookup(bs, cfg, aligned_addr);
c687bc
+    cached_entry = smmu_iotlb_lookup(bs, cfg, tt, aligned_addr);
c687bc
     if (cached_entry) {
c687bc
         if ((flag & IOMMU_WO) && !(cached_entry->entry.perm & IOMMU_WO)) {
c687bc
             status = SMMU_TRANS_ERROR;
c687bc
@@ -732,7 +732,7 @@ epilogue:
c687bc
     case SMMU_TRANS_SUCCESS:
c687bc
         entry.perm = flag;
c687bc
         entry.translated_addr = cached_entry->entry.translated_addr +
c687bc
-                                    (addr & page_mask);
c687bc
+                                    (addr & cached_entry->entry.addr_mask);
c687bc
         entry.addr_mask = cached_entry->entry.addr_mask;
c687bc
         trace_smmuv3_translate_success(mr->parent_obj.name, sid, addr,
c687bc
                                        entry.translated_addr, entry.perm);
c687bc
@@ -960,7 +960,7 @@ static int smmuv3_cmdq_consume(SMMUv3State *s)
c687bc
 
c687bc
             trace_smmuv3_cmdq_tlbi_nh_vaa(vmid, addr);
c687bc
             smmuv3_inv_notifiers_iova(bs, -1, addr);
c687bc
-            smmu_iotlb_inv_all(bs);
c687bc
+            smmu_iotlb_inv_iova(bs, -1, addr);
c687bc
             break;
c687bc
         }
c687bc
         case SMMU_CMD_TLBI_NH_VA:
c687bc
diff --git a/hw/arm/trace-events b/hw/arm/trace-events
c687bc
index b808a1bfc19..f74d3e920f1 100644
c687bc
--- a/hw/arm/trace-events
c687bc
+++ b/hw/arm/trace-events
c687bc
@@ -16,7 +16,7 @@ smmu_iotlb_inv_iova(uint16_t asid, uint64_t addr) "IOTLB invalidate asid=%d addr
c687bc
 smmu_inv_notifiers_mr(const char *name) "iommu mr=%s"
c687bc
 smmu_iotlb_lookup_hit(uint16_t asid, uint64_t addr, uint32_t hit, uint32_t miss, uint32_t p) "IOTLB cache HIT asid=%d addr=0x%"PRIx64" hit=%d miss=%d hit rate=%d"
c687bc
 smmu_iotlb_lookup_miss(uint16_t asid, uint64_t addr, uint32_t hit, uint32_t miss, uint32_t p) "IOTLB cache MISS asid=%d addr=0x%"PRIx64" hit=%d miss=%d hit rate=%d"
c687bc
-smmu_iotlb_insert(uint16_t asid, uint64_t addr) "IOTLB ++ asid=%d addr=0x%"PRIx64
c687bc
+smmu_iotlb_insert(uint16_t asid, uint64_t addr, uint8_t tg, uint8_t level) "IOTLB ++ asid=%d addr=0x%"PRIx64" tg=%d level=%d"
c687bc
 
c687bc
 # smmuv3.c
c687bc
 smmuv3_read_mmio(uint64_t addr, uint64_t val, unsigned size, uint32_t r) "addr: 0x%"PRIx64" val:0x%"PRIx64" size: 0x%x(%d)"
c687bc
diff --git a/include/hw/arm/smmu-common.h b/include/hw/arm/smmu-common.h
c687bc
index 277923bdc0a..bbf3abc41fd 100644
c687bc
--- a/include/hw/arm/smmu-common.h
c687bc
+++ b/include/hw/arm/smmu-common.h
c687bc
@@ -97,6 +97,8 @@ typedef struct SMMUPciBus {
c687bc
 typedef struct SMMUIOTLBKey {
c687bc
     uint64_t iova;
c687bc
     uint16_t asid;
c687bc
+    uint8_t tg;
c687bc
+    uint8_t level;
c687bc
 } SMMUIOTLBKey;
c687bc
 
c687bc
 typedef struct SMMUState {
c687bc
@@ -159,12 +161,14 @@ IOMMUMemoryRegion *smmu_iommu_mr(SMMUState *s, uint32_t sid);
c687bc
 
c687bc
 #define SMMU_IOTLB_MAX_SIZE 256
c687bc
 
c687bc
-SMMUTLBEntry *smmu_iotlb_lookup(SMMUState *bs, SMMUTransCfg *cfg, hwaddr iova);
c687bc
+SMMUTLBEntry *smmu_iotlb_lookup(SMMUState *bs, SMMUTransCfg *cfg,
c687bc
+                                SMMUTransTableInfo *tt, hwaddr iova);
c687bc
 void smmu_iotlb_insert(SMMUState *bs, SMMUTransCfg *cfg, SMMUTLBEntry *entry);
c687bc
-SMMUIOTLBKey smmu_get_iotlb_key(uint16_t asid, uint64_t iova);
c687bc
+SMMUIOTLBKey smmu_get_iotlb_key(uint16_t asid, uint64_t iova,
c687bc
+                                uint8_t tg, uint8_t level);
c687bc
 void smmu_iotlb_inv_all(SMMUState *s);
c687bc
 void smmu_iotlb_inv_asid(SMMUState *s, uint16_t asid);
c687bc
-void smmu_iotlb_inv_iova(SMMUState *s, uint16_t asid, dma_addr_t iova);
c687bc
+void smmu_iotlb_inv_iova(SMMUState *s, int asid, dma_addr_t iova);
c687bc
 
c687bc
 /* Unmap the range of all the notifiers registered to any IOMMU mr */
c687bc
 void smmu_inv_notifiers_all(SMMUState *s);
c687bc
-- 
c687bc
2.27.0
c687bc