On Thu, Apr 17, 2025 at 02:19:52PM +0200, Clément Léger wrote:
Now that the kernel can handle misaligned accesses in S-mode, request misaligned access exception delegation from SBI. This uses the FWFT SBI extension defined in SBI version 3.0.
Signed-off-by: Clément Léger cleger@rivosinc.com Reviewed-by: Andrew Jones ajones@ventanamicro.com
arch/riscv/include/asm/cpufeature.h | 3 +- arch/riscv/kernel/traps_misaligned.c | 71 +++++++++++++++++++++- arch/riscv/kernel/unaligned_access_speed.c | 8 ++- 3 files changed, 77 insertions(+), 5 deletions(-)
diff --git a/arch/riscv/include/asm/cpufeature.h b/arch/riscv/include/asm/cpufeature.h index f56b409361fb..dbe5970d4fe6 100644 --- a/arch/riscv/include/asm/cpufeature.h +++ b/arch/riscv/include/asm/cpufeature.h @@ -67,8 +67,9 @@ void __init riscv_user_isa_enable(void); _RISCV_ISA_EXT_DATA(_name, _id, _sub_exts, ARRAY_SIZE(_sub_exts), _validate) bool __init check_unaligned_access_emulated_all_cpus(void); +void unaligned_access_init(void); +int cpu_online_unaligned_access_init(unsigned int cpu); #if defined(CONFIG_RISCV_SCALAR_MISALIGNED) -void check_unaligned_access_emulated(struct work_struct *work __always_unused); void unaligned_emulation_finish(void); bool unaligned_ctl_available(void); DECLARE_PER_CPU(long, misaligned_access_speed); diff --git a/arch/riscv/kernel/traps_misaligned.c b/arch/riscv/kernel/traps_misaligned.c index 97c674d7d34f..058a69c30181 100644 --- a/arch/riscv/kernel/traps_misaligned.c +++ b/arch/riscv/kernel/traps_misaligned.c @@ -16,6 +16,7 @@ #include <asm/entry-common.h> #include <asm/hwprobe.h> #include <asm/cpufeature.h> +#include <asm/sbi.h> #include <asm/vector.h> #define INSN_MATCH_LB 0x3 @@ -629,7 +630,7 @@ bool __init check_vector_unaligned_access_emulated_all_cpus(void) static bool unaligned_ctl __read_mostly; -void check_unaligned_access_emulated(struct work_struct *work __always_unused) +static void check_unaligned_access_emulated(struct work_struct *work __always_unused) { int cpu = smp_processor_id(); long *mas_ptr = per_cpu_ptr(&misaligned_access_speed, cpu); @@ -640,6 +641,13 @@ void check_unaligned_access_emulated(struct work_struct *work __always_unused) __asm__ __volatile__ ( " "REG_L" %[tmp], 1(%[ptr])\n" : [tmp] "=r" (tmp_val) : [ptr] "r" (&tmp_var) : "memory"); +}
+static int cpu_online_check_unaligned_access_emulated(unsigned int cpu) +{
- long *mas_ptr = per_cpu_ptr(&misaligned_access_speed, cpu);
- check_unaligned_access_emulated(NULL);
/* * If unaligned_ctl is already set, this means that we detected that all @@ -648,9 +656,10 @@ void check_unaligned_access_emulated(struct work_struct *work __always_unused) */ if (unlikely(unaligned_ctl && (*mas_ptr != RISCV_HWPROBE_MISALIGNED_SCALAR_EMULATED))) { pr_crit("CPU misaligned accesses non homogeneous (expected all emulated)\n");
while (true)
cpu_relax();
}return -EINVAL;
- return 0;
} bool __init check_unaligned_access_emulated_all_cpus(void) @@ -682,4 +691,60 @@ bool __init check_unaligned_access_emulated_all_cpus(void) { return false; } +static int cpu_online_check_unaligned_access_emulated(unsigned int cpu) +{
- return 0;
+} +#endif
+#ifdef CONFIG_RISCV_SBI
+static bool misaligned_traps_delegated;
+static int cpu_online_sbi_unaligned_setup(unsigned int cpu) +{
- if (sbi_fwft_set(SBI_FWFT_MISALIGNED_EXC_DELEG, 1, 0) &&
misaligned_traps_delegated) {
pr_crit("Misaligned trap delegation non homogeneous (expected delegated)");
return -EINVAL;
- }
- return 0;
+}
+void unaligned_access_init(void)
__init
+{
- int ret;
- ret = sbi_fwft_local_set(SBI_FWFT_MISALIGNED_EXC_DELEG, 1, 0);
- if (ret)
return;
- misaligned_traps_delegated = true;
- pr_info("SBI misaligned access exception delegation ok\n");
- /*
* Note that we don't have to take any specific action here, if
* the delegation is successful, then
* check_unaligned_access_emulated() will verify that indeed the
* platform traps on misaligned accesses.
*/
+} +#else +void unaligned_access_init(void) {}
__init
+static int cpu_online_sbi_unaligned_setup(unsigned int cpu __always_unused) +{
- return 0;
+} #endif
+int cpu_online_unaligned_access_init(unsigned int cpu) +{
- int ret;
- ret = cpu_online_sbi_unaligned_setup(cpu);
- if (ret)
return ret;
- return cpu_online_check_unaligned_access_emulated(cpu);
+} diff --git a/arch/riscv/kernel/unaligned_access_speed.c b/arch/riscv/kernel/unaligned_access_speed.c index 585d2dcf2dab..a64d51a8da47 100644 --- a/arch/riscv/kernel/unaligned_access_speed.c +++ b/arch/riscv/kernel/unaligned_access_speed.c @@ -236,6 +236,11 @@ arch_initcall_sync(lock_and_set_unaligned_access_static_branch); static int riscv_online_cpu(unsigned int cpu) {
- int ret = cpu_online_unaligned_access_init(cpu);
- if (ret)
return ret;
- /* We are already set since the last check */ if (per_cpu(misaligned_access_speed, cpu) != RISCV_HWPROBE_MISALIGNED_SCALAR_UNKNOWN) { goto exit;
@@ -248,7 +253,6 @@ static int riscv_online_cpu(unsigned int cpu) { static struct page *buf;
buf = alloc_pages(GFP_KERNEL, MISALIGNED_BUFFER_ORDER); if (!buf) { pr_warn("Allocation failure, not measuring misaligned performance\n");check_unaligned_access_emulated(NULL);
@@ -439,6 +443,8 @@ static int __init check_unaligned_access_all_cpus(void) { int cpu;
- unaligned_access_init();
- if (unaligned_scalar_speed_param == RISCV_HWPROBE_MISALIGNED_SCALAR_UNKNOWN && !check_unaligned_access_emulated_all_cpus()) { check_unaligned_access_speed_all_cpus();
-- 2.49.0
Thanks, drew