The callback used inside sbi_remote_fence_i is set at sbi probe time
to the needed variant. Before that it is a NULL pointer.
flush_icache_all is from its name a pretty generic functionality
so probably shoudln't get a "only call after boot-step X" limit.
To prevent running into a null pointer dereference, add a default
__sbi_rfence_none returning an error code and adapt flush_icache_all
to check for an error from the remote fence to then fall back to a
simple local_icache_flush(), as that could really only happen if
called before other cpu cores are brought up.
Signed-off-by: Heiko Stuebner <heiko@...>
arch/riscv/kernel/sbi.c | 10 +++++++++-
arch/riscv/mm/cacheflush.c | 15 ++++++++++++---
2 files changed, 21 insertions(+), 4 deletions(-)
@@ -14,11 +14,19 @@
unsigned long sbi_spec_version __ro_after_init = SBI_SPEC_VERSION_DEFAULT;
EXPORT_SYMBOL(sbi_spec_version);
+static int __sbi_rfence_none(int fid, const struct cpumask *cpu_mask,
+ unsigned long start, unsigned long size,
+ unsigned long arg4, unsigned long arg5)
+{
+ return -EOPNOTSUPP;
+}
+
static void (*__sbi_set_timer)(uint64_t stime) __ro_after_init;
static int (*__sbi_send_ipi)(const struct cpumask *cpu_mask) __ro_after_init;
static int (*__sbi_rfence)(int fid, const struct cpumask *cpu_mask,
unsigned long start, unsigned long size,
- unsigned long arg4, unsigned long arg5) __ro_after_init;
+ unsigned long arg4, unsigned long arg5)
+ __ro_after_init = __sbi_rfence_none;
struct sbiret sbi_ecall(int ext, int fid, unsigned long arg0,
unsigned long arg1, unsigned long arg2,
@@ -18,10 +18,19 @@ void flush_icache_all(void)
{
local_flush_icache_all();
- if (IS_ENABLED(CONFIG_RISCV_SBI))
- sbi_remote_fence_i(NULL);
- else
+ if (IS_ENABLED(CONFIG_RISCV_SBI)) {
+ int ret = sbi_remote_fence_i(NULL);
+
+ /*
+ * Only fails when sbi-init hasn't run yet, so the kernel
+ * also is before SMP init, so flushing the local cpu
+ * is enough.
+ */
+ if (ret)
+ local_flush_icache_all();
+ } else {
on_each_cpu(ipi_remote_fence_i, NULL, 1);
+ }
}
EXPORT_SYMBOL(flush_icache_all);