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 <cle...@rivosinc.com> > Reviewed-by: Andrew Jones <ajo...@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; > > - check_unaligned_access_emulated(NULL); > buf = alloc_pages(GFP_KERNEL, MISALIGNED_BUFFER_ORDER); > if (!buf) { > pr_warn("Allocation failure, not measuring misaligned > performance\n"); > @@ -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