lib: Support stage1 and stage2 tlb flushing

The hypervisor specification support hfence calls which can be used
issue tlb flush requests at both level of address translation. Currently,
these requests are issued only via SBI which are defined in v0.2.

Signed-off-by: Atish Patra <atish.patra@wdc.com>
Reviewed-by: Anup Patel <anup.patel@wdc.com>
This commit is contained in:
Atish Patra 2019-11-24 23:33:49 -08:00 committed by Anup Patel
parent 9407202532
commit 331ff6a162
2 changed files with 102 additions and 5 deletions

View file

@ -24,7 +24,10 @@
enum sbi_tlb_info_types {
SBI_TLB_FLUSH_VMA,
SBI_TLB_FLUSH_VMA_ASID,
SBI_TLB_FLUSH_VMA_VMID,
SBI_TLB_FLUSH_GVMA,
SBI_TLB_FLUSH_GVMA_VMID,
SBI_TLB_FLUSH_VVMA,
SBI_TLB_FLUSH_VVMA_ASID,
SBI_ITLB_FLUSH
};

View file

@ -16,6 +16,7 @@
#include <sbi/sbi_hart.h>
#include <sbi/sbi_scratch.h>
#include <sbi/sbi_tlb.h>
#include <sbi/sbi_hfence.h>
#include <sbi/sbi_string.h>
#include <sbi/sbi_console.h>
#include <sbi/sbi_platform.h>
@ -30,6 +31,38 @@ static void sbi_tlb_flush_all(void)
__asm__ __volatile("sfence.vma");
}
static void sbi_tlb_fifo_hfence_vvma(struct sbi_tlb_info *tinfo)
{
unsigned long start = tinfo->start;
unsigned long size = tinfo->size;
unsigned long i;
if ((start == 0 && size == 0) || (size == SBI_TLB_FLUSH_ALL)) {
__sbi_hfence_vvma_all();
return;
}
for (i = 0; i < size; i += PAGE_SIZE) {
__sbi_hfence_vvma_va(start+i);
}
}
static void sbi_tlb_fifo_hfence_gvma(struct sbi_tlb_info *tinfo)
{
unsigned long start = tinfo->start;
unsigned long size = tinfo->size;
unsigned long i;
if ((start == 0 && size == 0) || (size == SBI_TLB_FLUSH_ALL)) {
__sbi_hfence_gvma_all();
return;
}
for (i = 0; i < size; i += PAGE_SIZE) {
__sbi_hfence_gvma_gpa(start+i);
}
}
static void sbi_tlb_fifo_sfence_vma(struct sbi_tlb_info *tinfo)
{
unsigned long start = tinfo->start;
@ -49,6 +82,50 @@ static void sbi_tlb_fifo_sfence_vma(struct sbi_tlb_info *tinfo)
}
}
static void sbi_tlb_fifo_hfence_vvma_asid(struct sbi_tlb_info *tinfo)
{
unsigned long start = tinfo->start;
unsigned long size = tinfo->size;
unsigned long asid = tinfo->asid;
unsigned long i;
if (start == 0 && size == 0) {
__sbi_hfence_vvma_all();
return;
}
if (size == SBI_TLB_FLUSH_ALL) {
__sbi_hfence_vvma_asid(asid);
return;
}
for (i = 0; i < size; i += PAGE_SIZE) {
__sbi_hfence_vvma_asid_va(asid, start + i);
}
}
static void sbi_tlb_fifo_hfence_gvma_vmid(struct sbi_tlb_info *tinfo)
{
unsigned long start = tinfo->start;
unsigned long size = tinfo->size;
unsigned long vmid = tinfo->asid;
unsigned long i;
if (start == 0 && size == 0) {
__sbi_hfence_gvma_all();
return;
}
if (size == SBI_TLB_FLUSH_ALL) {
__sbi_hfence_gvma_vmid(vmid);
return;
}
for (i = 0; i < size; i += PAGE_SIZE) {
__sbi_hfence_gvma_vmid_gpa(vmid, start+i);
}
}
static void sbi_tlb_fifo_sfence_vma_asid(struct sbi_tlb_info *tinfo)
{
unsigned long start = tinfo->start;
@ -80,15 +157,32 @@ static void sbi_tlb_fifo_sfence_vma_asid(struct sbi_tlb_info *tinfo)
static void sbi_tlb_local_flush(struct sbi_tlb_info *tinfo)
{
if (tinfo->type == SBI_TLB_FLUSH_VMA) {
switch (tinfo->type) {
case SBI_TLB_FLUSH_VMA:
sbi_tlb_fifo_sfence_vma(tinfo);
} else if (tinfo->type == SBI_TLB_FLUSH_VMA_ASID) {
break;
case SBI_TLB_FLUSH_VMA_ASID:
sbi_tlb_fifo_sfence_vma_asid(tinfo);
} else if (tinfo->type == SBI_ITLB_FLUSH)
break;
case SBI_TLB_FLUSH_GVMA:
sbi_tlb_fifo_hfence_gvma(tinfo);
break;
case SBI_TLB_FLUSH_GVMA_VMID:
sbi_tlb_fifo_hfence_gvma_vmid(tinfo);
break;
case SBI_TLB_FLUSH_VVMA:
sbi_tlb_fifo_hfence_vvma(tinfo);
break;
case SBI_TLB_FLUSH_VVMA_ASID:
sbi_tlb_fifo_hfence_vvma_asid(tinfo);
break;
case SBI_ITLB_FLUSH:
__asm__ __volatile("fence.i");
else
break;
default:
sbi_printf("Invalid tlb flush request type [%lu]\n",
tinfo->type);
}
return;
}