mirror of
https://github.com/torvalds/linux.git
synced 2026-06-03 20:14:06 +02:00
riscv: misaligned: request misaligned exception from SBI
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> Link: https://lore.kernel.org/r/20250523101932.1594077-7-cleger@rivosinc.com Signed-off-by: Palmer Dabbelt <palmer@dabbelt.com>
This commit is contained in:
parent
c4a50db1e1
commit
cf5a8abc65
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -646,7 +647,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);
|
||||
|
|
@ -657,6 +658,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
|
||||
|
|
@ -665,9 +673,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)
|
||||
|
|
@ -699,4 +708,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 __init unaligned_access_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = sbi_fwft_set_online_cpus(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 __init unaligned_access_init(void) {}
|
||||
|
||||
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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
pr_info("scalar unaligned access speed set to '%s' (%lu) by command line\n",
|
||||
speed_str[unaligned_scalar_speed_param], unaligned_scalar_speed_param);
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user