@@ -1,5 +1,8 @@
menu "CPU errata selection"
+config ERRATA_CMO_FUNC
+ bool
+
config ERRATA_ANDES
bool "Andes AX45MP errata"
depends on !XIP_KERNEL
@@ -14,6 +17,7 @@ config ERRATA_ANDES
config ERRATA_ANDES_CMO
bool "Apply Andes cache management errata"
depends on ERRATA_ANDES && MMU && ARCH_R9A07G043
+ select ERRATA_CMO_FUNC
select RISCV_DMA_NONCOHERENT
default y
help
@@ -62,6 +62,25 @@ void riscv_noncoherent_supported(void);
static inline void riscv_noncoherent_supported(void) {}
#endif
+struct riscv_cache_maint_ops {
+ void (*cmo_patchfunc) (unsigned int cache_size, void *vaddr,
+ size_t size, int dir, int ops);
+};
+
+#ifdef CONFIG_RISCV_DMA_NONCOHERENT
+void riscv_set_cache_maint_ops(struct riscv_cache_maint_ops *ops);
+#else
+static void riscv_set_cache_maint_ops(struct riscv_cache_maint_ops *ops) {}
+#endif
+
+#ifdef CONFIG_ERRATA_CMO_FUNC
+asmlinkage void cmo_patchfunc(unsigned int cache_size, void *vaddr, size_t size,
+ int dir, int ops);
+#else
+__maybe_unused static void cmo_patchfunc(unsigned int cache_size, void *vaddr,
+ size_t size, int dir, int ops) {}
+#endif
+
/*
* Bits in sys_riscv_flush_icache()'s flags argument.
*/
@@ -83,3 +83,24 @@ void riscv_noncoherent_supported(void)
"Non-coherent DMA support enabled without a block size\n");
noncoherent_supported = true;
}
+
+static struct riscv_cache_maint_ops *rv_cache_maint_ops;
+static DEFINE_STATIC_KEY_FALSE(cmo_patchfunc_present);
+
+void riscv_set_cache_maint_ops(struct riscv_cache_maint_ops *ops)
+{
+ rv_cache_maint_ops = ops;
+ static_branch_enable(&cmo_patchfunc_present);
+}
+EXPORT_SYMBOL_GPL(riscv_set_cache_maint_ops);
+
+#ifdef CONFIG_ERRATA_CMO_FUNC
+asmlinkage void cmo_patchfunc(unsigned int cache_size, void *vaddr, size_t size,
+ int dir, int ops)
+{
+ if (!static_branch_unlikely(&cmo_patchfunc_present))
+ return;
+
+ rv_cache_maint_ops->cmo_patchfunc(cache_size, vaddr, size, dir, ops);
+}
+#endif