[PATCH] platform: Allow platforms to customize TLB operations

Xiang W <[email protected]>
Newsgroups org.infradead.lists.opensbi
Message-ID <[email protected]>
Some T-Head based processors, for example the Sophgo SG2044, have a
JTLB errata that requires special handling of certain TLB maintenance
instructions (sfence.vma).

Enable the JTLB workaround for affected boards.

Signed-off-by: Xiang W <[email protected]>
Signed-off-by: Han Gao <[email protected]>
---
 include/sbi/sbi_platform.h                   | 162 +++++++++++++++++++
 lib/sbi/sbi_tlb.c                            |  28 ++++
 platform/generic/include/thead/c9xx_errata.h |   1 +
 platform/generic/thead/thead-generic.c       |  26 ++-
 4 files changed, 216 insertions(+), 1 deletion(-)

diff --git a/include/sbi/sbi_platform.h b/include/sbi/sbi_platform.h
index fe382b56..911b37bf 100644
--- a/include/sbi/sbi_platform.h
+++ b/include/sbi/sbi_platform.h
@@ -56,6 +56,7 @@ struct sbi_domain_memregion;
 struct sbi_ecall_return;
 struct sbi_trap_regs;
 struct sbi_hart_features;
+struct sbi_tlb_info;
 union sbi_ldst_data;
 
 /** Possible feature flags of a platform */
@@ -125,6 +126,27 @@ struct sbi_platform_operations {
 	/** Get tlb fifo num entries*/
 	u32 (*get_tlb_num_entries)(void);
 
+	/** Platform hook for custom fence.i */
+	void (*local_fence_i)(struct sbi_tlb_info *tinfo);
+
+	/** Platform hook for custom supervisor-mode TLB flush */
+	void (*local_sfence_vma)(struct sbi_tlb_info *tinfo);
+
+	/** Platform hook for custom supervisor-mode TLB flush with ASID */
+	void (*local_sfence_vma_asid)(struct sbi_tlb_info *tinfo);
+
+	/** Platform hook for custom G-stage TLB flush for a specific VMID */
+	void (*local_hfence_gvma_vmid)(struct sbi_tlb_info *tinfo);
+
+	/** Platform hook for custom G-stage TLB flush */
+	void (*local_hfence_gvma)(struct sbi_tlb_info *tinfo);
+
+	/** Platform hook for custom VS-stage TLB flush with ASID */
+	void (*local_hfence_vvma_asid)(struct sbi_tlb_info *tinfo);
+
+	/** Platform hook for custom VS-stage TLB flush */
+	void (*local_hfence_vvma)(struct sbi_tlb_info *tinfo);
+
 	/** Initialize platform timer during cold boot */
 	int (*timer_init)(void);
 
@@ -313,6 +335,146 @@ static inline u32 sbi_platform_tlb_fifo_num_entries(const struct sbi_platform *p
 	return sbi_hart_count();
 }
 
+/**
+ * Platform hook for custom fence.i
+ *
+ * @param plat pointer to struct sbi_platform
+ * @paeam tinfo pointer to struct sbi_tlb_info
+ *
+ * @return 0 indicates that the platform supports the operation and the
+ * operation was successful; otherwise, a normal operation needs to be performed.
+ */
+static inline u32 sbi_platform_local_fence_i(
+					const struct sbi_platform *plat,
+					struct sbi_tlb_info *tinfo)
+{
+	if (plat && sbi_platform_ops(plat)->local_fence_i) {
+		sbi_platform_ops(plat)->local_fence_i(tinfo);
+		return 0;
+	}
+	return SBI_ENOTSUPP;
+}
+
+/**
+ * Platform hook for custom supervisor-mode TLB flush
+ *
+ * @param plat pointer to struct sbi_platform
+ * @paeam tinfo pointer to struct sbi_tlb_info
+ *
+ * @return 0 indicates that the platform supports the operation and the
+ * operation was successful; otherwise, a normal operation needs to be performed.
+ */
+static inline u32 sbi_platform_local_sfence_vma(
+					const struct sbi_platform *plat,
+					struct sbi_tlb_info *tinfo)
+{
+	if (plat && sbi_platform_ops(plat)->local_sfence_vma) {
+		sbi_platform_ops(plat)->local_sfence_vma(tinfo);
+		return 0;
+	}
+	return SBI_ENOTSUPP;
+}
+
+/**
+ * Platform hook for custom supervisor-mode TLB flush with ASID
+ *
+ * @param plat pointer to struct sbi_platform
+ * @paeam tinfo pointer to struct sbi_tlb_info
+ *
+ * @return 0 indicates that the platform supports the operation and the
+ * operation was successful; otherwise, a normal operation needs to be performed.
+ */
+static inline u32 sbi_platform_local_sfence_vma_asid(
+					const struct sbi_platform *plat,
+					struct sbi_tlb_info *tinfo)
+{
+	if (plat && sbi_platform_ops(plat)->local_sfence_vma_asid) {
+		sbi_platform_ops(plat)->local_sfence_vma_asid(tinfo);
+		return 0;
+	}
+	return SBI_ENOTSUPP;
+}
+
+/**
+ * Platform hook for custom G-stage TLB flush for a specific VMID
+ *
+ * @param plat pointer to struct sbi_platform
+ * @paeam tinfo pointer to struct sbi_tlb_info
+ *
+ * @return 0 indicates that the platform supports the operation and the
+ * operation was successful; otherwise, a normal operation needs to be performed.
+ */
+static inline u32 sbi_platform_local_hfence_gvma_vmid(
+					const struct sbi_platform *plat,
+					struct sbi_tlb_info *tinfo)
+{
+	if (plat && sbi_platform_ops(plat)->local_hfence_gvma_vmid) {
+		sbi_platform_ops(plat)->local_hfence_gvma_vmid(tinfo);
+		return 0;
+	}
+	return SBI_ENOTSUPP;
+}
+
+/**
+ * Platform hook for custom G-stage TLB flush
+ *
+ * @param plat pointer to struct sbi_platform
+ * @paeam tinfo pointer to struct sbi_tlb_info
+ *
+ * @return 0 indicates that the platform supports the operation and the
+ * operation was successful; otherwise, a normal operation needs to be performed.
+ */
+static inline u32 sbi_platform_local_hfence_gvma(
+					const struct sbi_platform *plat,
+					struct sbi_tlb_info *tinfo)
+{
+	if (plat && sbi_platform_ops(plat)->local_hfence_gvma) {
+		sbi_platform_ops(plat)->local_hfence_gvma(tinfo);
+		return 0;
+	}
+	return SBI_ENOTSUPP;
+}
+
+/**
+ * Platform hook for custom VS-stage TLB flush with ASID
+ *
+ * @param plat pointer to struct sbi_platform
+ * @paeam tinfo pointer to struct sbi_tlb_info
+ *
+ * @return 0 indicates that the platform supports the operation and the
+ * operation was successful; otherwise, a normal operation needs to be performed.
+ */
+static inline u32 sbi_platform_local_hfence_vvma_asid(
+					const struct sbi_platform *plat,
+					struct sbi_tlb_info *tinfo)
+{
+	if (plat && sbi_platform_ops(plat)->local_hfence_vvma_asid) {
+		sbi_platform_ops(plat)->local_hfence_vvma_asid(tinfo);
+		return 0;
+	}
+	return SBI_ENOTSUPP;
+}
+
+/**
+ * Platform hook for custom VS-stage TLB flush
+ *
+ * @param plat pointer to struct sbi_platform
+ * @paeam tinfo pointer to struct sbi_tlb_info
+ *
+ * @return 0 indicates that the platform supports the operation and the
+ * operation was successful; otherwise, a normal operation needs to be performed.
+ */
+static inline u32 sbi_platform_local_hfence_vvma(
+					const struct sbi_platform *plat,
+					struct sbi_tlb_info *tinfo)
+{
+	if (plat && sbi_platform_ops(plat)->local_hfence_vvma) {
+		sbi_platform_ops(plat)->local_hfence_vvma(tinfo);
+		return 0;
+	}
+	return SBI_ENOTSUPP;
+}
+
 /**
  * Get total number of HARTs supported by the platform
  *
diff --git a/lib/sbi/sbi_tlb.c b/lib/sbi/sbi_tlb.c
index ada60c32..69b8fb48 100644
--- a/lib/sbi/sbi_tlb.c
+++ b/lib/sbi/sbi_tlb.c
@@ -46,6 +46,10 @@ static void sbi_tlb_local_hfence_vvma(struct sbi_tlb_info *tinfo)
 	hgatp = csr_swap(CSR_HGATP,
 			 (vmid << HGATP_VMID_SHIFT) & HGATP_VMID_MASK);
 
+	if (sbi_platform_local_hfence_gvma(
+			sbi_platform_thishart_ptr(), tinfo) == SBI_OK)
+		gito done;
+
 	if ((start == 0 && size == 0) || (size == SBI_TLB_FLUSH_ALL)) {
 		__sbi_hfence_vvma_all();
 		goto done;
@@ -67,6 +71,10 @@ static void sbi_tlb_local_hfence_gvma(struct sbi_tlb_info *tinfo)
 
 	sbi_pmu_ctr_incr_fw(SBI_PMU_FW_HFENCE_GVMA_RCVD);
 
+	if (sbi_platform_local_hfence_gvma(
+			sbi_platform_thishart_ptr(), tinfo) == SBI_OK)
+		return;
+
 	if ((start == 0 && size == 0) || (size == SBI_TLB_FLUSH_ALL)) {
 		__sbi_hfence_gvma_all();
 		return;
@@ -85,6 +93,10 @@ static void sbi_tlb_local_sfence_vma(struct sbi_tlb_info *tinfo)
 
 	sbi_pmu_ctr_incr_fw(SBI_PMU_FW_SFENCE_VMA_RCVD);
 
+	if (sbi_platform_local_sfence_vma(
+			sbi_platform_thishart_ptr(), tinfo) == SBI_OK)
+		return;
+
 	if ((start == 0 && size == 0) || (size == SBI_TLB_FLUSH_ALL)) {
 		__sbi_sfence_vma_all();
 		return;
@@ -111,6 +123,10 @@ static void sbi_tlb_local_hfence_vvma_asid(struct sbi_tlb_info *tinfo)
 	hgatp = csr_swap(CSR_HGATP,
 			 (vmid << HGATP_VMID_SHIFT) & HGATP_VMID_MASK);
 
+	if (sbi_platform_local_hfence_vvma_asid(
+			sbi_platform_thishart_ptr(), tinfo) == SBI_OK)
+		goto done;
+
 	if ((start == 0 && size == 0) || (size == SBI_TLB_FLUSH_ALL)) {
 		__sbi_hfence_vvma_asid(asid);
 		goto done;
@@ -133,6 +149,10 @@ static void sbi_tlb_local_hfence_gvma_vmid(struct sbi_tlb_info *tinfo)
 
 	sbi_pmu_ctr_incr_fw(SBI_PMU_FW_HFENCE_GVMA_VMID_RCVD);
 
+	if (sbi_platform_local_hfence_gvma_vmid(
+			sbi_platform_thishart_ptr(), tinfo) == SBI_OK)
+		return;
+
 	if ((start == 0 && size == 0) || (size == SBI_TLB_FLUSH_ALL)) {
 		__sbi_hfence_gvma_vmid(vmid);
 		return;
@@ -152,6 +172,10 @@ static void sbi_tlb_local_sfence_vma_asid(struct sbi_tlb_info *tinfo)
 
 	sbi_pmu_ctr_incr_fw(SBI_PMU_FW_SFENCE_VMA_ASID_RCVD);
 
+	if (sbi_platform_local_sfence_vma_asid(
+			sbi_platform_thishart_ptr(), tinfo) == SBI_OK)
+		return;
+
 	/* Flush entire MM context for a given ASID */
 	if ((start == 0 && size == 0) || (size == SBI_TLB_FLUSH_ALL)) {
 		__asm__ __volatile__("sfence.vma x0, %0"
@@ -173,6 +197,10 @@ static void sbi_tlb_local_fence_i(struct sbi_tlb_info *tinfo)
 {
 	sbi_pmu_ctr_incr_fw(SBI_PMU_FW_FENCE_I_RECVD);
 
+	if (sbi_platform_local_fence_i(
+			sbi_platform_thishart_ptr(), tinfo) == SBI_OK)
+		return;
+
 	__asm__ __volatile("fence.i");
 }
 
diff --git a/platform/generic/include/thead/c9xx_errata.h b/platform/generic/include/thead/c9xx_errata.h
index 40c1587b..7a419e41 100644
--- a/platform/generic/include/thead/c9xx_errata.h
+++ b/platform/generic/include/thead/c9xx_errata.h
@@ -8,6 +8,7 @@
  */
 #define THEAD_QUIRK_ERRATA_TLB_FLUSH		BIT(0)
 #define THEAD_QUIRK_ERRATA_THEAD_PMU		BIT(1)
+#define THEAD_QUIRK_ERRATA_JTLB			BIT(2)
 
 void thead_register_tlb_flush_trap_handler(void);
 
diff --git a/platform/generic/thead/thead-generic.c b/platform/generic/thead/thead-generic.c
index ddb4f0bf..86793ab1 100644
--- a/platform/generic/thead/thead-generic.c
+++ b/platform/generic/thead/thead-generic.c
@@ -13,6 +13,7 @@
 #include <sbi/sbi_platform.h>
 #include <sbi/sbi_scratch.h>
 #include <sbi/sbi_string.h>
+#include <sbi/sbi_tlb.h>
 #include <sbi_utils/fdt/fdt_helper.h>
 
 struct thead_generic_quirks {
@@ -39,6 +40,20 @@ static int thead_pmu_extensions_init(struct sbi_hart_features *hfeatures)
 	return 0;
 }
 
+static void thead_jtlb_local_sfence_vma(struct sbi_tlb_info *tinfo)
+{
+	__asm__ __volatile__("sfence.vma");
+}
+
+static void thead_jtlb_local_sfence_vvma_asid(struct sbi_tlb_info *tinfo)
+{
+	/* Flush entire MM context for a given ASID */
+	__asm__ __volatile__("sfence.vma x0, %0"
+			     :
+			     : "r"(tinfo->asid)
+			     : "memory");
+}
+
 static int thead_generic_platform_init(const void *fdt, int nodeoff,
 				       const struct fdt_match *match)
 {
@@ -49,6 +64,11 @@ static int thead_generic_platform_init(const void *fdt, int nodeoff,
 	if (quirks->errata & THEAD_QUIRK_ERRATA_THEAD_PMU)
 		generic_platform_ops.extensions_init = thead_pmu_extensions_init;
 
+	if (quirks->errata &THEAD_QUIRK_ERRATA_JTLB) {
+		generic_platform_ops.local_sfence_vma = thead_jtlb_local_sfence_vma;
+		generic_platform_ops.local_sfence_vma_asid = thead_jtlb_local_sfence_vvma_asid;
+	}
+
 	return 0;
 }
 
@@ -60,13 +80,17 @@ static const struct thead_generic_quirks thead_pmu_quirks = {
 	.errata = THEAD_QUIRK_ERRATA_THEAD_PMU,
 };
 
+static const struct thead_generic_quirks thead_pmu_jtlb_quirks = {
+	.errata = THEAD_QUIRK_ERRATA_THEAD_PMU | THEAD_QUIRK_ERRATA_JTLB,
+};
+
 static const struct fdt_match thead_generic_match[] = {
 	{ .compatible = "canaan,kendryte-k230", .data = &thead_pmu_quirks },
 	{ .compatible = "sophgo,cv1800b", .data = &thead_pmu_quirks },
 	{ .compatible = "sophgo,cv1812h", .data = &thead_pmu_quirks },
 	{ .compatible = "sophgo,sg2000", .data = &thead_pmu_quirks },
 	{ .compatible = "sophgo,sg2002", .data = &thead_pmu_quirks },
-	{ .compatible = "sophgo,sg2044", .data = &thead_pmu_quirks },
+	{ .compatible = "sophgo,sg2044", .data = &thead_pmu_jtlb_quirks },
 	{ .compatible = "thead,th1520", .data = &thead_th1520_quirks },
 	{ },
 };
-- 
2.47.3


-- 
opensbi mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/opensbi
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.