tlbinvasid cleared each matching JTLB entry via fTLBW(), and these would
hit hex_tlbw()'s flush.  tlbinvasid could trigger several full flushes.

Since the softtlb isn't ASID-tagged, clear all matching valid bits first
and flush once.

The hardware threads share one JTLB but have their own softtlb, so the
flush has to be broadcast to every CPU rather than just the one running
the invalidation.

Reviewed-by: Pierrick Bouvier <[email protected]>
Signed-off-by: Brian Cain <[email protected]>
---
 include/hw/hexagon/hexagon_tlb.h |  2 ++
 target/hexagon/cpu.h             |  8 ++++++++
 target/hexagon/gen_tcg_sys.h     |  3 +++
 target/hexagon/helper.h          |  1 +
 target/hexagon/hex_mmu.h         |  1 +
 hw/hexagon/hexagon_tlb.c         | 18 ++++++++++++++++++
 target/hexagon/hex_mmu.c         | 21 +++++++++++++++++++--
 target/hexagon/op_helper.c       |  6 ++++++
 8 files changed, 58 insertions(+), 2 deletions(-)

diff --git a/include/hw/hexagon/hexagon_tlb.h b/include/hw/hexagon/hexagon_tlb.h
index 56aa0b2beed..355ba3888c0 100644
--- a/include/hw/hexagon/hexagon_tlb.h
+++ b/include/hw/hexagon/hexagon_tlb.h
@@ -30,6 +30,8 @@ uint64_t hexagon_tlb_read(HexagonTLBState *tlb, uint32_t 
index);
 uint64_t hexagon_tlb_write(HexagonTLBState *tlb, uint32_t index,
                            uint64_t value);
 
+uint32_t hexagon_tlb_invalidate_asid(HexagonTLBState *tlb, uint32_t asid);
+
 bool hexagon_tlb_find_match(HexagonTLBState *tlb, uint32_t asid,
                             uint32_t VA, MMUAccessType access_type,
                             hwaddr *PA, int *prot, uint64_t *size,
diff --git a/target/hexagon/cpu.h b/target/hexagon/cpu.h
index ba155d4383c..feb80368238 100644
--- a/target/hexagon/cpu.h
+++ b/target/hexagon/cpu.h
@@ -76,6 +76,14 @@ typedef struct HexagonHVXContextState HexagonHVXContextState;
 #define MMU_GUEST_IDX        1
 #define MMU_KERNEL_IDX       2
 
+/*
+ * TLB entry match is by ASID and global bit, neither of which is encoded in
+ * mmu_idx, so a JTLB change has to be flushed out of every mmu_idx.
+ */
+#define MMU_IDX_ALL          ((1 << MMU_USER_IDX) | \
+                              (1 << MMU_GUEST_IDX) | \
+                              (1 << MMU_KERNEL_IDX))
+
 typedef enum {
     HEX_LOCK_UNLOCKED       = 0,
     HEX_LOCK_WAITING        = 1,
diff --git a/target/hexagon/gen_tcg_sys.h b/target/hexagon/gen_tcg_sys.h
index 2486f9f0d63..a3f07bd47b9 100644
--- a/target/hexagon/gen_tcg_sys.h
+++ b/target/hexagon/gen_tcg_sys.h
@@ -20,6 +20,9 @@
 #define fGEN_TCG_Y4_siad(SHORTCODE) \
     gen_helper_siad(tcg_env, RsV)
 
+#define fGEN_TCG_Y5_tlbasidi(SHORTCODE) \
+    gen_helper_tlbinvasid(tcg_env, RsV)
+
 #define fGEN_TCG_Y2_iassignw(SHORTCODE) \
     gen_helper_iassignw(tcg_env, RsV)
 
diff --git a/target/hexagon/helper.h b/target/hexagon/helper.h
index 1f6f0350fbb..8c49e798093 100644
--- a/target/hexagon/helper.h
+++ b/target/hexagon/helper.h
@@ -148,4 +148,5 @@ DEF_HELPER_2(resume, void, env, i32)
 DEF_HELPER_1(resched, void, env)
 DEF_HELPER_3(modify_ssr, void, env, i32, i32)
 DEF_HELPER_1(pending_interrupt, void, env)
+DEF_HELPER_2(tlbinvasid, void, env, i32)
 #endif
diff --git a/target/hexagon/hex_mmu.h b/target/hexagon/hex_mmu.h
index 2cfcd10949a..0c49404448c 100644
--- a/target/hexagon/hex_mmu.h
+++ b/target/hexagon/hex_mmu.h
@@ -13,6 +13,7 @@
 #include "monitor/hmp.h"
 
 extern void hex_tlbw(CPUHexagonState *env, uint32_t index, uint64_t value);
+extern void hex_tlb_invalidate_asid(CPUHexagonState *env, uint32_t asid);
 extern uint32_t hex_tlb_lookup(CPUHexagonState *env, uint32_t ssr, uint32_t 
VA);
 extern void hex_mmu_on(CPUHexagonState *env);
 extern void hex_mmu_off(CPUHexagonState *env);
diff --git a/hw/hexagon/hexagon_tlb.c b/hw/hexagon/hexagon_tlb.c
index 28601b78a6f..3e72026d62a 100644
--- a/hw/hexagon/hexagon_tlb.c
+++ b/hw/hexagon/hexagon_tlb.c
@@ -321,6 +321,24 @@ uint64_t hexagon_tlb_write(HexagonTLBState *tlb, uint32_t 
index,
     return old;
 }
 
+uint32_t hexagon_tlb_invalidate_asid(HexagonTLBState *tlb, uint32_t asid)
+{
+    uint32_t invalidated = 0;
+
+    for (uint32_t i = 0; i < tlb->num_entries; i++) {
+        uint64_t entry = tlb->entries[i];
+
+        if (!GET_PTE_V(entry) || GET_PTE_G(entry) ||
+            GET_PTE_ASID(entry) != asid) {
+            continue;
+        }
+        tlb->entries[i] = deposit64(entry, 63, 1, 0);
+        invalidated++;
+    }
+
+    return invalidated;
+}
+
 bool hexagon_tlb_find_match(HexagonTLBState *tlb, uint32_t asid,
                             uint32_t VA, MMUAccessType access_type,
                             hwaddr *PA, int *prot, uint64_t *size,
diff --git a/target/hexagon/hex_mmu.c b/target/hexagon/hex_mmu.c
index f93dd3d82d4..2e0e4ab705b 100644
--- a/target/hexagon/hex_mmu.c
+++ b/target/hexagon/hex_mmu.c
@@ -29,6 +29,11 @@ static inline void hex_log_tlbw(uint32_t index, uint64_t 
entry)
                   index, entry);
 }
 
+static void hex_tlb_flush_all(CPUState *cs)
+{
+    tlb_flush_by_mmuidx_all_cpus_synced(cs, MMU_IDX_ALL);
+}
+
 void hex_tlbw(CPUHexagonState *env, uint32_t index, uint64_t value)
 {
     uint32_t myidx = fTLB_NONPOW2WRAP(fTLB_IDXMASK(index));
@@ -36,12 +41,24 @@ void hex_tlbw(CPUHexagonState *env, uint32_t index, 
uint64_t value)
     uint64_t old_entry = hexagon_tlb_write(tlb, myidx, value);
     bool old_entry_valid = extract64(old_entry, 63, 1);
     if (old_entry_valid && hexagon_cpu_mmu_enabled(env)) {
-        CPUState *cs = env_cpu(env);
-        tlb_flush_all_cpus_synced(cs);
+        hex_tlb_flush_all(env_cpu(env));
     }
     hex_log_tlbw(myidx, value);
 }
 
+void hex_tlb_invalidate_asid(CPUHexagonState *env, uint32_t asid)
+{
+    HexagonTLBState *tlb = env_archcpu(env)->tlb;
+    uint32_t invalidated = hexagon_tlb_invalidate_asid(tlb, asid);
+
+    qemu_log_mask(CPU_LOG_MMU,
+                  "tlbinvasid: asid 0x%02" PRIx32 ", %" PRIu32 " entries\n",
+                  asid, invalidated);
+    if (invalidated && hexagon_cpu_mmu_enabled(env)) {
+        hex_tlb_flush_all(env_cpu(env));
+    }
+}
+
 void hex_mmu_on(CPUHexagonState *env)
 {
     CPUState *cs = env_cpu(env);
diff --git a/target/hexagon/op_helper.c b/target/hexagon/op_helper.c
index 40891e5ee1a..6076a5f29fd 100644
--- a/target/hexagon/op_helper.c
+++ b/target/hexagon/op_helper.c
@@ -1740,6 +1740,12 @@ void HELPER(siad)(CPUHexagonState *env, uint32_t mask)
     hex_interrupt_update(env);
 }
 
+void HELPER(tlbinvasid)(CPUHexagonState *env, uint32_t RsV)
+{
+    BQL_LOCK_GUARD();
+    hex_tlb_invalidate_asid(env, extract32(RsV, 20, 7));
+}
+
 void HELPER(swi)(CPUHexagonState *env, uint32_t mask)
 {
     BQL_LOCK_GUARD();
-- 
2.34.1

Reply via email to