Currently, Xvisor is only doing local tlb flush for both host & stage 2
tlb.
Issue remote tlb flush calls via IPIs to all the online cpus. It can
be optimized further by keeping track of relevant cpus using a separate
cpumask.
Signed-off-by: Atish Patra <
atish...@wdc.com>
---
arch/riscv/cpu/generic/cpu_mmu.c | 47 +++++++++++++++++++-----
arch/riscv/cpu/generic/include/cpu_tlb.h | 39 ++++++++++++++++++++
2 files changed, 76 insertions(+), 10 deletions(-)
diff --git a/arch/riscv/cpu/generic/cpu_mmu.c b/arch/riscv/cpu/generic/cpu_mmu.c
index 549e71abfb26..b660097179d2 100644
--- a/arch/riscv/cpu/generic/cpu_mmu.c
+++ b/arch/riscv/cpu/generic/cpu_mmu.c
@@ -70,14 +70,41 @@ static inline void cpu_mmu_sync_pte(cpu_pte_t *pte)
arch_smp_mb();
}
-static inline void cpu_invalid_gpa_guest_tlb(physical_addr_t gpa)
+static inline void cpu_local_va_hyp_tlbflush(virtual_addr_t va)
{
- __hfence_gvma_gpa(gpa);
+ __sfence_vma_va(va);
}
-static inline void cpu_invalid_va_hypervisor_tlb(virtual_addr_t va)
+static void cpu_tlbflush_ipi_handler(void *tinfo, void *a2, void *a3)
{
- __asm__ __volatile__ ("sfence.vma %0" : : "r" (va) : "memory");
+ struct tlbinfo *info = tinfo;
+
+ if (info->type == TLBFLUSH_SFENCE_VMA)
+ __sfence_vma_va(info->addr);
+ else if (info->type == TLBFLUSH_HFENCE_GVMA)
+ __hfence_gvma_gpa(info->addr);
+}
+
+static inline void cpu_remote_gpa_guest_tlbflush(physical_addr_t gpa)
+{
+ struct tlbinfo info;
+
+ info.addr = gpa;
+ info.type = TLBFLUSH_HFENCE_GVMA;
+ vmm_smp_ipi_sync_call(cpu_online_mask, 1000,
+ cpu_tlbflush_ipi_handler,
+ &info, NULL, NULL);
+}
+
+static inline void cpu_remote_va_hyp_tlb_flush(virtual_addr_t va)
+{
+ struct tlbinfo info;
+
+ info.addr = va;
+ info.type = TLBFLUSH_SFENCE_VMA;
+ vmm_smp_ipi_sync_call(cpu_online_mask, 1000,
+ cpu_tlbflush_ipi_handler,
+ &info, NULL, NULL);
}
static struct cpu_pgtbl *cpu_mmu_pgtbl_find(physical_addr_t tbl_pa)
@@ -562,10 +589,10 @@ int cpu_mmu_unmap_page(struct cpu_pgtbl *pgtbl, struct cpu_page *pg)
cpu_mmu_sync_pte(&pte[index]);
if (pgtbl->stage == PGTBL_STAGE2) {
- cpu_invalid_gpa_guest_tlb((pg->ia));
+ cpu_remote_gpa_guest_tlbflush(pg->ia);
start_level = mmuctrl.stage2_start_level;
} else {
- cpu_invalid_va_hypervisor_tlb(((virtual_addr_t)pg->ia));
+ cpu_remote_va_hyp_tlb_flush((virtual_addr_t)pg->ia);
start_level = mmuctrl.stage1_start_level;
}
@@ -647,9 +674,9 @@ int cpu_mmu_map_page(struct cpu_pgtbl *pgtbl, struct cpu_page *pg)
cpu_mmu_sync_pte(&pte[index]);
if (pgtbl->stage == PGTBL_STAGE2) {
- cpu_invalid_gpa_guest_tlb((pg->ia));
+ cpu_remote_gpa_guest_tlbflush(pg->ia);
} else {
- cpu_invalid_va_hypervisor_tlb(((virtual_addr_t)pg->ia));
+ cpu_remote_va_hyp_tlb_flush((virtual_addr_t)pg->ia);
}
pgtbl->pte_cnt++;
@@ -720,7 +747,7 @@ int arch_cpu_aspace_memory_read(virtual_addr_t tmp_va,
*pte |= PHYS_RW_PTE;
cpu_mmu_sync_pte(pte);
- cpu_invalid_va_hypervisor_tlb(tmp_va);
+ cpu_local_va_hyp_tlbflush(tmp_va);
switch (len) {
case 1:
@@ -763,7 +790,7 @@ int arch_cpu_aspace_memory_write(virtual_addr_t tmp_va,
*pte |= PHYS_RW_PTE;
cpu_mmu_sync_pte(pte);
- cpu_invalid_va_hypervisor_tlb(tmp_va);
+ cpu_local_va_hyp_tlbflush(tmp_va);
switch (len) {
case 1:
diff --git a/arch/riscv/cpu/generic/include/cpu_tlb.h b/arch/riscv/cpu/generic/include/cpu_tlb.h
index af150a261ed4..aebadc4775da 100644
--- a/arch/riscv/cpu/generic/include/cpu_tlb.h
+++ b/arch/riscv/cpu/generic/include/cpu_tlb.h
@@ -26,6 +26,19 @@
#include <vmm_types.h>
+#define TLBFLUSH_SFENCE_VMA 1
+#define TLBFLUSH_HFENCE_GVMA 2
+#define TLBFLUSH_HFENCE_BVMA 3
+
+struct tlbinfo {
+ unsigned long addr;
+ u32 type;
+ /* Only valid if type is TLBFLUSH_HFENCE_GVMA */
+ u32 vmid;
+ /* Only valid if type is TLBFLUSH_HFENCE_BVMA or SFENCE_VMA*/
+ u32 asid;
+};
+
/** Invalidate Stage2 TLBs for given VMID and guest physical address */
void __hfence_gvma_vmid_gpa(unsigned long vmid, unsigned long gpa);
@@ -38,4 +51,30 @@ void __hfence_gvma_gpa(unsigned long gpa);
/** Invalidate all possible Stage2 TLBs */
void __hfence_gvma_all(void);
+inline void __sfence_vma_asid_va(unsigned long asid, unsigned long va)
+{
+ __asm__ __volatile__("sfence.vma %0 %1"
+ :
+ : "r"(va),"r"(asid)
+ : "memory");
+}
+
+inline void __sfence_vma_asid(unsigned long asid)
+{
+ __asm__ __volatile__("sfence.vma x0 %1"
+ :
+ : "r"(asid)
+ : "memory");
+
+}
+
+inline void __sfence_vma_all(void)
+{
+ __asm__ __volatile("sfence.vma");
+}
+
+inline void __sfence_vma_va(virtual_addr_t va)
+{
+ __asm__ __volatile__ ("sfence.vma %0" : : "r" (va) : "memory");
+}
#endif
--
2.21.0