Преглед изворни кода

lib: sbi: Allow custom local TLB flush function

Currently, we have fixed TLB flush types supported by the
remote TLB library. This approach is not flexible and does
not allow custom local TLB flush function. For example,
after updating PMP entries on a set of HARTs at runtime,
we have to flush TLB on these HARTs as well.

To support custom local TLB flush function, we replace the
"type" field of "struct sbi_tlb_info" with a local TLB flush
function pointer. We also provide definitions of standard TLB
flush operations (such as fence_i, sfence.vma, hfence.vvma,
hfence.gvma, etc).

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Reviewed-by: Atish Patra <atish.patra@wdc.com>
Anup Patel пре 3 година
родитељ
комит
12394a269b
4 измењених фајлова са 44 додато и 64 уклоњено
  1. 11 13
      include/sbi/sbi_tlb.h
  2. 6 3
      lib/sbi/sbi_ecall_legacy.c
  3. 9 7
      lib/sbi/sbi_ecall_replace.c
  4. 18 41
      lib/sbi/sbi_tlb.c

+ 11 - 13
include/sbi/sbi_tlb.h

@@ -22,16 +22,6 @@
 
 #define SBI_TLB_FIFO_NUM_ENTRIES		8
 
-enum sbi_tlb_info_types {
-	SBI_TLB_FLUSH_VMA,
-	SBI_TLB_FLUSH_VMA_ASID,
-	SBI_TLB_FLUSH_GVMA,
-	SBI_TLB_FLUSH_GVMA_VMID,
-	SBI_TLB_FLUSH_VVMA,
-	SBI_TLB_FLUSH_VVMA_ASID,
-	SBI_ITLB_FLUSH
-};
-
 struct sbi_scratch;
 
 struct sbi_tlb_info {
@@ -39,17 +29,25 @@ struct sbi_tlb_info {
 	unsigned long size;
 	unsigned long asid;
 	unsigned long vmid;
-	unsigned long type;
+	void (*local_fn)(struct sbi_tlb_info *tinfo);
 	struct sbi_hartmask smask;
 };
 
-#define SBI_TLB_INFO_INIT(__p, __start, __size, __asid, __vmid, __type, __src) \
+void sbi_tlb_local_hfence_vvma(struct sbi_tlb_info *tinfo);
+void sbi_tlb_local_hfence_gvma(struct sbi_tlb_info *tinfo);
+void sbi_tlb_local_sfence_vma(struct sbi_tlb_info *tinfo);
+void sbi_tlb_local_hfence_vvma_asid(struct sbi_tlb_info *tinfo);
+void sbi_tlb_local_hfence_gvma_vmid(struct sbi_tlb_info *tinfo);
+void sbi_tlb_local_sfence_vma_asid(struct sbi_tlb_info *tinfo);
+void sbi_tlb_local_fence_i(struct sbi_tlb_info *tinfo);
+
+#define SBI_TLB_INFO_INIT(__p, __start, __size, __asid, __vmid, __lfn, __src) \
 do { \
 	(__p)->start = (__start); \
 	(__p)->size = (__size); \
 	(__p)->asid = (__asid); \
 	(__p)->vmid = (__vmid); \
-	(__p)->type = (__type); \
+	(__p)->local_fn = (__lfn); \
 	SBI_HARTMASK_INIT_EXCEPT(&(__p)->smask, (__src)); \
 } while (0)
 

+ 6 - 3
lib/sbi/sbi_ecall_legacy.c

@@ -80,7 +80,8 @@ static int sbi_ecall_legacy_handler(unsigned long extid, unsigned long funcid,
 						&hmask, out_trap);
 		if (ret != SBI_ETRAP) {
 			SBI_TLB_INFO_INIT(&tlb_info, 0, 0, 0, 0,
-					  SBI_ITLB_FLUSH, source_hart);
+					  sbi_tlb_local_fence_i,
+					  source_hart);
 			ret = sbi_tlb_request(hmask, 0, &tlb_info);
 		}
 		break;
@@ -89,7 +90,8 @@ static int sbi_ecall_legacy_handler(unsigned long extid, unsigned long funcid,
 						&hmask, out_trap);
 		if (ret != SBI_ETRAP) {
 			SBI_TLB_INFO_INIT(&tlb_info, regs->a1, regs->a2, 0, 0,
-					  SBI_TLB_FLUSH_VMA, source_hart);
+					  sbi_tlb_local_sfence_vma,
+					  source_hart);
 			ret = sbi_tlb_request(hmask, 0, &tlb_info);
 		}
 		break;
@@ -99,7 +101,8 @@ static int sbi_ecall_legacy_handler(unsigned long extid, unsigned long funcid,
 		if (ret != SBI_ETRAP) {
 			SBI_TLB_INFO_INIT(&tlb_info, regs->a1,
 					  regs->a2, regs->a3, 0,
-					  SBI_TLB_FLUSH_VMA_ASID, source_hart);
+					  sbi_tlb_local_sfence_vma_asid,
+					  source_hart);
 			ret = sbi_tlb_request(hmask, 0, &tlb_info);
 		}
 		break;

+ 9 - 7
lib/sbi/sbi_ecall_replace.c

@@ -62,41 +62,43 @@ static int sbi_ecall_rfence_handler(unsigned long extid, unsigned long funcid,
 	switch (funcid) {
 	case SBI_EXT_RFENCE_REMOTE_FENCE_I:
 		SBI_TLB_INFO_INIT(&tlb_info, 0, 0, 0, 0,
-				  SBI_ITLB_FLUSH, source_hart);
+				  sbi_tlb_local_fence_i, source_hart);
 		ret = sbi_tlb_request(regs->a0, regs->a1, &tlb_info);
 		break;
 	case SBI_EXT_RFENCE_REMOTE_HFENCE_GVMA:
 		SBI_TLB_INFO_INIT(&tlb_info, regs->a2, regs->a3, 0, 0,
-				  SBI_TLB_FLUSH_GVMA, source_hart);
+				  sbi_tlb_local_hfence_gvma, source_hart);
 		ret = sbi_tlb_request(regs->a0, regs->a1, &tlb_info);
 		break;
 	case SBI_EXT_RFENCE_REMOTE_HFENCE_GVMA_VMID:
 		SBI_TLB_INFO_INIT(&tlb_info, regs->a2, regs->a3, 0, regs->a4,
-				  SBI_TLB_FLUSH_GVMA_VMID, source_hart);
+				  sbi_tlb_local_hfence_gvma_vmid,
+				  source_hart);
 		ret = sbi_tlb_request(regs->a0, regs->a1, &tlb_info);
 		break;
 	case SBI_EXT_RFENCE_REMOTE_HFENCE_VVMA:
 		vmid = (csr_read(CSR_HGATP) & HGATP_VMID_MASK);
 		vmid = vmid >> HGATP_VMID_SHIFT;
 		SBI_TLB_INFO_INIT(&tlb_info, regs->a2, regs->a3, 0, vmid,
-				  SBI_TLB_FLUSH_VVMA, source_hart);
+				  sbi_tlb_local_hfence_vvma, source_hart);
 		ret = sbi_tlb_request(regs->a0, regs->a1, &tlb_info);
 		break;
 	case SBI_EXT_RFENCE_REMOTE_HFENCE_VVMA_ASID:
 		vmid = (csr_read(CSR_HGATP) & HGATP_VMID_MASK);
 		vmid = vmid >> HGATP_VMID_SHIFT;
 		SBI_TLB_INFO_INIT(&tlb_info, regs->a2, regs->a3, regs->a4,
-				  vmid, SBI_TLB_FLUSH_VVMA_ASID, source_hart);
+				  vmid, sbi_tlb_local_hfence_vvma_asid,
+				  source_hart);
 		ret = sbi_tlb_request(regs->a0, regs->a1, &tlb_info);
 		break;
 	case SBI_EXT_RFENCE_REMOTE_SFENCE_VMA:
 		SBI_TLB_INFO_INIT(&tlb_info, regs->a2, regs->a3, 0, 0,
-				  SBI_TLB_FLUSH_VMA, source_hart);
+				  sbi_tlb_local_sfence_vma, source_hart);
 		ret = sbi_tlb_request(regs->a0, regs->a1, &tlb_info);
 		break;
 	case SBI_EXT_RFENCE_REMOTE_SFENCE_VMA_ASID:
 		SBI_TLB_INFO_INIT(&tlb_info, regs->a2, regs->a3, regs->a4, 0,
-				  SBI_TLB_FLUSH_VMA_ASID, source_hart);
+				  sbi_tlb_local_sfence_vma_asid, source_hart);
 		ret = sbi_tlb_request(regs->a0, regs->a1, &tlb_info);
 		break;
 	default:

+ 18 - 41
lib/sbi/sbi_tlb.c

@@ -32,7 +32,7 @@ static void sbi_tlb_flush_all(void)
 	__asm__ __volatile("sfence.vma");
 }
 
-static void sbi_tlb_hfence_vvma(struct sbi_tlb_info *tinfo)
+void sbi_tlb_local_hfence_vvma(struct sbi_tlb_info *tinfo)
 {
 	unsigned long start = tinfo->start;
 	unsigned long size  = tinfo->size;
@@ -55,7 +55,7 @@ done:
 	csr_write(CSR_HGATP, hgatp);
 }
 
-static void sbi_tlb_hfence_gvma(struct sbi_tlb_info *tinfo)
+void sbi_tlb_local_hfence_gvma(struct sbi_tlb_info *tinfo)
 {
 	unsigned long start = tinfo->start;
 	unsigned long size  = tinfo->size;
@@ -71,7 +71,7 @@ static void sbi_tlb_hfence_gvma(struct sbi_tlb_info *tinfo)
 	}
 }
 
-static void sbi_tlb_sfence_vma(struct sbi_tlb_info *tinfo)
+void sbi_tlb_local_sfence_vma(struct sbi_tlb_info *tinfo)
 {
 	unsigned long start = tinfo->start;
 	unsigned long size  = tinfo->size;
@@ -90,7 +90,7 @@ static void sbi_tlb_sfence_vma(struct sbi_tlb_info *tinfo)
 	}
 }
 
-static void sbi_tlb_hfence_vvma_asid(struct sbi_tlb_info *tinfo)
+void sbi_tlb_local_hfence_vvma_asid(struct sbi_tlb_info *tinfo)
 {
 	unsigned long start = tinfo->start;
 	unsigned long size  = tinfo->size;
@@ -119,7 +119,7 @@ done:
 	csr_write(CSR_HGATP, hgatp);
 }
 
-static void sbi_tlb_hfence_gvma_vmid(struct sbi_tlb_info *tinfo)
+void sbi_tlb_local_hfence_gvma_vmid(struct sbi_tlb_info *tinfo)
 {
 	unsigned long start = tinfo->start;
 	unsigned long size  = tinfo->size;
@@ -141,7 +141,7 @@ static void sbi_tlb_hfence_gvma_vmid(struct sbi_tlb_info *tinfo)
 	}
 }
 
-static void sbi_tlb_sfence_vma_asid(struct sbi_tlb_info *tinfo)
+void sbi_tlb_local_sfence_vma_asid(struct sbi_tlb_info *tinfo)
 {
 	unsigned long start = tinfo->start;
 	unsigned long size  = tinfo->size;
@@ -170,35 +170,9 @@ static void sbi_tlb_sfence_vma_asid(struct sbi_tlb_info *tinfo)
 	}
 }
 
-static void sbi_tlb_local_flush(struct sbi_tlb_info *tinfo)
+void sbi_tlb_local_fence_i(struct sbi_tlb_info *tinfo)
 {
-	switch (tinfo->type) {
-	case SBI_TLB_FLUSH_VMA:
-		sbi_tlb_sfence_vma(tinfo);
-		break;
-	case SBI_TLB_FLUSH_VMA_ASID:
-		sbi_tlb_sfence_vma_asid(tinfo);
-		break;
-	case SBI_TLB_FLUSH_GVMA:
-		sbi_tlb_hfence_gvma(tinfo);
-		break;
-	case SBI_TLB_FLUSH_GVMA_VMID:
-		sbi_tlb_hfence_gvma_vmid(tinfo);
-		break;
-	case SBI_TLB_FLUSH_VVMA:
-		sbi_tlb_hfence_vvma(tinfo);
-		break;
-	case SBI_TLB_FLUSH_VVMA_ASID:
-		sbi_tlb_hfence_vvma_asid(tinfo);
-		break;
-	case SBI_ITLB_FLUSH:
-		__asm__ __volatile("fence.i");
-		break;
-	default:
-		sbi_printf("Invalid tlb flush request type [%lu]\n",
-			   tinfo->type);
-	}
-	return;
+	__asm__ __volatile("fence.i");
 }
 
 static void sbi_tlb_entry_process(struct sbi_tlb_info *tinfo)
@@ -207,7 +181,7 @@ static void sbi_tlb_entry_process(struct sbi_tlb_info *tinfo)
 	struct sbi_scratch *rscratch = NULL;
 	unsigned long *rtlb_sync = NULL;
 
-	sbi_tlb_local_flush(tinfo);
+	tinfo->local_fn(tinfo);
 
 	sbi_hartmask_for_each_hart(rhartid, &tinfo->smask) {
 		rscratch = sbi_hartid_to_scratch(rhartid);
@@ -316,13 +290,13 @@ static int sbi_tlb_update_cb(void *in, void *data)
 	curr = (struct sbi_tlb_info *)data;
 	next = (struct sbi_tlb_info *)in;
 
-	if (next->type == SBI_TLB_FLUSH_VMA_ASID &&
-	    curr->type == SBI_TLB_FLUSH_VMA_ASID) {
+	if (next->local_fn == sbi_tlb_local_sfence_vma_asid &&
+	    curr->local_fn == sbi_tlb_local_sfence_vma_asid) {
 		if (next->asid == curr->asid)
 			ret = __sbi_tlb_range_check(curr, next);
-	} else if (next->type == SBI_TLB_FLUSH_VMA &&
-		   curr->type == SBI_TLB_FLUSH_VMA) {
-			ret = __sbi_tlb_range_check(curr, next);
+	} else if (next->local_fn == sbi_tlb_local_sfence_vma &&
+		   curr->local_fn == sbi_tlb_local_sfence_vma) {
+		ret = __sbi_tlb_range_check(curr, next);
 	}
 
 	return ret;
@@ -352,7 +326,7 @@ static int sbi_tlb_update(struct sbi_scratch *scratch,
 	 * then just do a local flush and return;
 	 */
 	if (remote_hartid == curr_hartid) {
-		sbi_tlb_local_flush(tinfo);
+		tinfo->local_fn(tinfo);
 		return -1;
 	}
 
@@ -391,6 +365,9 @@ static u32 tlb_event = SBI_IPI_EVENT_MAX;
 
 int sbi_tlb_request(ulong hmask, ulong hbase, struct sbi_tlb_info *tinfo)
 {
+	if (!tinfo->local_fn)
+		return SBI_EINVAL;
+
 	return sbi_ipi_send_many(hmask, hbase, tlb_event, tinfo);
 }