summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStafford Horne <shorne@gmail.com>2026-05-22 18:56:03 +0300
committerStafford Horne <shorne@gmail.com>2026-05-23 08:34:35 +0300
commit1be031de802ba486a7605b52eda825f128b026e2 (patch)
tree9dcf379128a6514debb61b757a81b1ceccf929d5
parentcf40e2cee8fe86d54f7eeb38944366d5c23e42dc (diff)
downloadlinux-1be031de802ba486a7605b52eda825f128b026e2.tar.xz
openrisc: Add full instruction cache invalidate functions
Add functions to invalidate all cache lines which we will use for static_key patching. On OpenRISC there is no instruction to invalidate an entire cache so we loop and invalidate cache lines one by one. This is not extremely expensive on OpenRISC as we usually have only a few hundred cache lines. I considered using the invalidate cache page or range functions. However, tracking which ranges need invalidation would have been more expensive than flushing all pages. Cc: stable@vger.kernel.org Signed-off-by: Stafford Horne <shorne@gmail.com>
-rw-r--r--arch/openrisc/include/asm/cacheflush.h4
-rw-r--r--arch/openrisc/kernel/smp.c21
-rw-r--r--arch/openrisc/mm/cache.c16
3 files changed, 41 insertions, 0 deletions
diff --git a/arch/openrisc/include/asm/cacheflush.h b/arch/openrisc/include/asm/cacheflush.h
index cd8f971c0fec..7b8c043a831d 100644
--- a/arch/openrisc/include/asm/cacheflush.h
+++ b/arch/openrisc/include/asm/cacheflush.h
@@ -26,6 +26,7 @@ extern void local_icache_page_inv(struct page *page);
extern void local_dcache_range_flush(unsigned long start, unsigned long end);
extern void local_dcache_range_inv(unsigned long start, unsigned long end);
extern void local_icache_range_inv(unsigned long start, unsigned long end);
+extern void local_icache_all_inv(void);
/*
* Data cache flushing always happen on the local cpu. Instruction cache
@@ -35,10 +36,13 @@ extern void local_icache_range_inv(unsigned long start, unsigned long end);
#ifndef CONFIG_SMP
#define dcache_page_flush(page) local_dcache_page_flush(page)
#define icache_page_inv(page) local_icache_page_inv(page)
+#define icache_all_inv() local_icache_all_inv()
#else /* CONFIG_SMP */
#define dcache_page_flush(page) local_dcache_page_flush(page)
#define icache_page_inv(page) smp_icache_page_inv(page)
+#define icache_all_inv() smp_icache_all_inv()
extern void smp_icache_page_inv(struct page *page);
+extern void smp_icache_all_inv(void);
#endif /* CONFIG_SMP */
/*
diff --git a/arch/openrisc/kernel/smp.c b/arch/openrisc/kernel/smp.c
index 040ca201b692..65599252f3d4 100644
--- a/arch/openrisc/kernel/smp.c
+++ b/arch/openrisc/kernel/smp.c
@@ -346,3 +346,24 @@ void smp_icache_page_inv(struct page *page)
on_each_cpu(ipi_icache_page_inv, page, 1);
}
EXPORT_SYMBOL(smp_icache_page_inv);
+
+static void ipi_icache_all_inv(void *arg)
+{
+ local_icache_all_inv();
+}
+
+void smp_icache_all_inv(void)
+{
+ if (num_online_cpus() < 2) {
+ local_icache_all_inv();
+ return;
+ }
+
+ /*
+ * Ensure stores complete before we request remote icaches
+ * to invalidate.
+ */
+ mb();
+
+ on_each_cpu(ipi_icache_all_inv, NULL, 1);
+}
diff --git a/arch/openrisc/mm/cache.c b/arch/openrisc/mm/cache.c
index f33df46dae4e..2667d90691b5 100644
--- a/arch/openrisc/mm/cache.c
+++ b/arch/openrisc/mm/cache.c
@@ -63,6 +63,22 @@ void local_icache_page_inv(struct page *page)
}
EXPORT_SYMBOL(local_icache_page_inv);
+void local_icache_all_inv(void)
+{
+ if (cpu_cache_is_present(SPR_UPR_ICP)) {
+ unsigned long iccfgr = mfspr(SPR_ICCFGR);
+ unsigned long sets = 1 << ((iccfgr & SPR_ICCFGR_NCS) >> 3);
+ unsigned long block_size = 16 << ((iccfgr & SPR_ICCFGR_CBS) >> 7);
+ unsigned long paddr = 0;
+ unsigned long end = sets * block_size;
+
+ while (paddr < end) {
+ mtspr(SPR_ICBIR, paddr);
+ paddr += block_size;
+ }
+ }
+}
+
void local_dcache_range_flush(unsigned long start, unsigned long end)
{
cache_loop(start, end, SPR_DCBFR, SPR_UPR_DCP);