diff options
-rw-r--r-- | include/sbi/riscv_asm.h | 5 | ||||
-rw-r--r-- | include/sbi/sbi_ipi.h | 15 | ||||
-rw-r--r-- | include/sbi/sbi_scratch.h | 10 | ||||
-rw-r--r-- | lib/sbi_ecall.c | 17 | ||||
-rw-r--r-- | lib/sbi_ipi.c | 71 | ||||
-rw-r--r-- | lib/sbi_system.c | 2 |
6 files changed, 105 insertions, 15 deletions
diff --git a/include/sbi/riscv_asm.h b/include/sbi/riscv_asm.h index a88c086..9648629 100644 --- a/include/sbi/riscv_asm.h +++ b/include/sbi/riscv_asm.h @@ -26,6 +26,11 @@ #error "Unexpected __riscv_xlen" #endif +#define PAGE_SHIFT (12) +#define PAGE_SIZE (_AC(1, UL) << PAGE_SHIFT) +#define PAGE_MASK (~(PAGE_SIZE - 1)) +#define SBI_TLB_FLUSH_ALL ((unsigned long)-1) + #define REG_L __REG_SEL(ld, lw) #define REG_S __REG_SEL(sd, sw) #define SZREG __REG_SEL(8, 4) diff --git a/include/sbi/sbi_ipi.h b/include/sbi/sbi_ipi.h index 708dd8c..1aafe35 100644 --- a/include/sbi/sbi_ipi.h +++ b/include/sbi/sbi_ipi.h @@ -15,12 +15,23 @@ #define SBI_IPI_EVENT_SOFT 0x1 #define SBI_IPI_EVENT_FENCE_I 0x2 #define SBI_IPI_EVENT_SFENCE_VMA 0x4 -#define SBI_IPI_EVENT_HALT 0x8 +#define SBI_IPI_EVENT_SFENCE_VMA_ASID 0x8 +#define SBI_IPI_EVENT_HALT 0x10 struct sbi_scratch; +struct sbi_ipi_data { + unsigned long ipi_type; +}; + +struct sbi_tlb_info { + unsigned long start; + unsigned long size; + unsigned long asid; +}; + int sbi_ipi_send_many(struct sbi_scratch *scratch, - ulong *pmask, u32 event); + ulong *pmask, u32 event, void *data); void sbi_ipi_clear_smode(struct sbi_scratch *scratch); diff --git a/include/sbi/sbi_scratch.h b/include/sbi/sbi_scratch.h index 70ab384..1534893 100644 --- a/include/sbi/sbi_scratch.h +++ b/include/sbi/sbi_scratch.h @@ -35,16 +35,14 @@ /** Offset of ipi_type in sbi_ipi_data */ #define SBI_IPI_DATA_IPI_TYPE_OFFSET (15 * __SIZEOF_POINTER__) +#define SBI_SCRATCH_TLB_INFO_OFFSET (16 * __SIZEOF_POINTER__) /** Maximum size of sbi_scratch and sbi_ipi_data */ #define SBI_SCRATCH_SIZE (32 * __SIZEOF_POINTER__) #ifndef __ASSEMBLY__ #include <sbi/sbi_types.h> - -struct sbi_ipi_data { - unsigned long ipi_type; -}; +#include <sbi/sbi_ipi.h> /** Representation of per-HART scratch space */ struct sbi_scratch { @@ -80,6 +78,10 @@ struct sbi_scratch { #define sbi_ipi_data_ptr(scratch) \ ((struct sbi_ipi_data *)(void*)scratch + SBI_IPI_DATA_IPI_TYPE_OFFSET) +/** Get pointer to tlb flush info from sbi_scratch */ +#define sbi_tlb_info_ptr(scratch) \ +((struct sbi_tlb_info *)(void*)scratch + SBI_SCRATCH_TLB_INFO_OFFSET) + #endif #endif diff --git a/lib/sbi_ecall.c b/lib/sbi_ecall.c index 42123ba..6312469 100644 --- a/lib/sbi_ecall.c +++ b/lib/sbi_ecall.c @@ -34,6 +34,7 @@ int sbi_ecall_handler(u32 hartid, ulong mcause, struct sbi_scratch *scratch) { int ret = SBI_ENOTSUPP; + struct sbi_tlb_info tlb_info; switch (regs->a7) { case SBI_ECALL_SET_TIMER: @@ -59,16 +60,26 @@ int sbi_ecall_handler(u32 hartid, ulong mcause, break; case SBI_ECALL_SEND_IPI: ret = sbi_ipi_send_many(scratch, (ulong *)regs->a0, - SBI_IPI_EVENT_SOFT); + SBI_IPI_EVENT_SOFT, NULL); break; case SBI_ECALL_REMOTE_FENCE_I: ret = sbi_ipi_send_many(scratch, (ulong *)regs->a0, - SBI_IPI_EVENT_FENCE_I); + SBI_IPI_EVENT_FENCE_I, NULL); break; case SBI_ECALL_REMOTE_SFENCE_VMA: + tlb_info.start = (unsigned long)regs->a1; + tlb_info.size = (unsigned long)regs->a2; + + ret = sbi_ipi_send_many(scratch, (ulong *)regs->a0, + SBI_IPI_EVENT_SFENCE_VMA, &tlb_info); + break; case SBI_ECALL_REMOTE_SFENCE_VMA_ASID: + tlb_info.start = (unsigned long)regs->a1; + tlb_info.size = (unsigned long)regs->a2; + tlb_info.asid = (unsigned long)regs->a3; + ret = sbi_ipi_send_many(scratch, (ulong *)regs->a0, - SBI_IPI_EVENT_SFENCE_VMA); + SBI_IPI_EVENT_SFENCE_VMA_ASID, &tlb_info); break; case SBI_ECALL_SHUTDOWN: sbi_system_shutdown(scratch, 0); diff --git a/lib/sbi_ipi.c b/lib/sbi_ipi.c index e0f2a19..468db9a 100644 --- a/lib/sbi_ipi.c +++ b/lib/sbi_ipi.c @@ -19,10 +19,13 @@ #include <sbi/sbi_timer.h> #include <sbi/sbi_unpriv.h> -static int sbi_ipi_send(struct sbi_scratch *scratch, u32 hartid, u32 event) +static int sbi_ipi_send(struct sbi_scratch *scratch, u32 hartid, + u32 event, void *data) { struct sbi_scratch *remote_scratch = NULL; const struct sbi_platform *plat = sbi_platform_ptr(scratch); + struct sbi_tlb_info *tlb_info = data; + struct sbi_tlb_info *ipi_tlb_data; if (sbi_platform_hart_disabled(plat, hartid)) return -1; @@ -31,6 +34,13 @@ static int sbi_ipi_send(struct sbi_scratch *scratch, u32 hartid, u32 event) * trigger the interrupt */ remote_scratch = sbi_hart_id_to_scratch(scratch, hartid); + if (event == SBI_IPI_EVENT_SFENCE_VMA || + event == SBI_IPI_EVENT_SFENCE_VMA_ASID) { + ipi_tlb_data = sbi_tlb_info_ptr(remote_scratch); + ipi_tlb_data->start = tlb_info->start; + ipi_tlb_data->size = tlb_info->size; + ipi_tlb_data->asid = tlb_info->asid; + } atomic_raw_set_bit(event, &sbi_ipi_data_ptr(remote_scratch)->ipi_type); mb(); sbi_platform_ipi_send(plat, hartid); @@ -41,7 +51,7 @@ static int sbi_ipi_send(struct sbi_scratch *scratch, u32 hartid, u32 event) } int sbi_ipi_send_many(struct sbi_scratch *scratch, - ulong *pmask, u32 event) + ulong *pmask, u32 event, void *data) { ulong i, m; ulong mask = sbi_hart_available_mask(); @@ -53,13 +63,13 @@ int sbi_ipi_send_many(struct sbi_scratch *scratch, /* send IPIs to every other hart on the set */ for (i = 0, m = mask; m; i++, m >>= 1) if ((m & 1UL) && (i != hartid)) - sbi_ipi_send(scratch, i, event); + sbi_ipi_send(scratch, i, event, data); /* If the current hart is on the set, send an IPI * to it as well */ if (mask & (1UL << hartid)) - sbi_ipi_send(scratch, hartid, event); + sbi_ipi_send(scratch, hartid, event, data); return 0; @@ -70,6 +80,51 @@ void sbi_ipi_clear_smode(struct sbi_scratch *scratch) csr_clear(CSR_MIP, MIP_SSIP); } +static void sbi_ipi_tlb_flush_all(unsigned long asid) +{ + __asm__ __volatile__ ("sfence.vma x0, %0" + : : "r" (asid) + : "memory"); +} + +static void sbi_ipi_sfence_vma(struct sbi_tlb_info *tinfo) +{ + unsigned long start = tinfo->start; + unsigned long size = tinfo->size; + unsigned long i; + + if (start == 0 && size == 0) + sbi_ipi_tlb_flush_all(0); + + for (i = 0; i < size; i += PAGE_SIZE) { + __asm__ __volatile__ ("sfence.vma %0" + : : "r" (start + i) + : "memory"); + } +} + +static void sbi_ipi_sfence_vma_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_ipi_tlb_flush_all(0); + /* Flush entire MM context */ + if (size == SBI_TLB_FLUSH_ALL) { + sbi_ipi_tlb_flush_all(asid); + return; + } + + for (i = 0; i < size; i += PAGE_SIZE) { + __asm__ __volatile__ ("sfence.vma %0, %1" + : : "r" (start + i), "r" (asid) + : "memory"); + } +} + void sbi_ipi_process(struct sbi_scratch *scratch) { const struct sbi_platform *plat = sbi_platform_ptr(scratch); @@ -91,7 +146,10 @@ void sbi_ipi_process(struct sbi_scratch *scratch) __asm__ __volatile("fence.i"); break; case SBI_IPI_EVENT_SFENCE_VMA: - __asm__ __volatile("sfence.vma"); + sbi_ipi_sfence_vma(sbi_tlb_info_ptr(scratch)); + break; + case SBI_IPI_EVENT_SFENCE_VMA_ASID: + sbi_ipi_sfence_vma_asid(sbi_tlb_info_ptr(scratch)); break; case SBI_IPI_EVENT_HALT: sbi_hart_hang(); @@ -104,6 +162,9 @@ void sbi_ipi_process(struct sbi_scratch *scratch) int sbi_ipi_init(struct sbi_scratch *scratch, bool cold_boot) { sbi_ipi_data_ptr(scratch)->ipi_type = 0x00; + sbi_tlb_info_ptr(scratch)->start = 0x00; + sbi_tlb_info_ptr(scratch)->size = 0x00; + sbi_tlb_info_ptr(scratch)->asid = 0x00; /* Enable software interrupts */ csr_set(CSR_MIE, MIP_MSIP); diff --git a/lib/sbi_system.c b/lib/sbi_system.c index f23d046..b373828 100644 --- a/lib/sbi_system.c +++ b/lib/sbi_system.c @@ -41,7 +41,7 @@ void __attribute__((noreturn)) sbi_system_shutdown(struct sbi_scratch *scratch, /* If that fails (or is not implemented) send an IPI on every * hart to hang and then hang the current hart */ - sbi_ipi_send_many(scratch, NULL, SBI_IPI_EVENT_HALT); + sbi_ipi_send_many(scratch, NULL, SBI_IPI_EVENT_HALT, NULL); sbi_hart_hang(); } |