mirror of
https://github.com/linux-msm/laptops-kernel.git
synced 2026-08-13 14:19:53 -07: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:
@@ -67,8 +67,9 @@ void __init riscv_user_isa_enable(void);
|
|||||||
_RISCV_ISA_EXT_DATA(_name, _id, _sub_exts, ARRAY_SIZE(_sub_exts), _validate)
|
_RISCV_ISA_EXT_DATA(_name, _id, _sub_exts, ARRAY_SIZE(_sub_exts), _validate)
|
||||||
|
|
||||||
bool __init check_unaligned_access_emulated_all_cpus(void);
|
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)
|
#if defined(CONFIG_RISCV_SCALAR_MISALIGNED)
|
||||||
void check_unaligned_access_emulated(struct work_struct *work __always_unused);
|
|
||||||
void unaligned_emulation_finish(void);
|
void unaligned_emulation_finish(void);
|
||||||
bool unaligned_ctl_available(void);
|
bool unaligned_ctl_available(void);
|
||||||
DECLARE_PER_CPU(long, misaligned_access_speed);
|
DECLARE_PER_CPU(long, misaligned_access_speed);
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
#include <asm/entry-common.h>
|
#include <asm/entry-common.h>
|
||||||
#include <asm/hwprobe.h>
|
#include <asm/hwprobe.h>
|
||||||
#include <asm/cpufeature.h>
|
#include <asm/cpufeature.h>
|
||||||
|
#include <asm/sbi.h>
|
||||||
#include <asm/vector.h>
|
#include <asm/vector.h>
|
||||||
|
|
||||||
#define INSN_MATCH_LB 0x3
|
#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;
|
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();
|
int cpu = smp_processor_id();
|
||||||
long *mas_ptr = per_cpu_ptr(&misaligned_access_speed, cpu);
|
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__ (
|
__asm__ __volatile__ (
|
||||||
" "REG_L" %[tmp], 1(%[ptr])\n"
|
" "REG_L" %[tmp], 1(%[ptr])\n"
|
||||||
: [tmp] "=r" (tmp_val) : [ptr] "r" (&tmp_var) : "memory");
|
: [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
|
* 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))) {
|
if (unlikely(unaligned_ctl && (*mas_ptr != RISCV_HWPROBE_MISALIGNED_SCALAR_EMULATED))) {
|
||||||
pr_crit("CPU misaligned accesses non homogeneous (expected all emulated)\n");
|
pr_crit("CPU misaligned accesses non homogeneous (expected all emulated)\n");
|
||||||
while (true)
|
return -EINVAL;
|
||||||
cpu_relax();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool __init check_unaligned_access_emulated_all_cpus(void)
|
bool __init check_unaligned_access_emulated_all_cpus(void)
|
||||||
@@ -699,4 +708,60 @@ bool __init check_unaligned_access_emulated_all_cpus(void)
|
|||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
static int cpu_online_check_unaligned_access_emulated(unsigned int cpu)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
#endif
|
#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)
|
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 */
|
/* We are already set since the last check */
|
||||||
if (per_cpu(misaligned_access_speed, cpu) != RISCV_HWPROBE_MISALIGNED_SCALAR_UNKNOWN) {
|
if (per_cpu(misaligned_access_speed, cpu) != RISCV_HWPROBE_MISALIGNED_SCALAR_UNKNOWN) {
|
||||||
goto exit;
|
goto exit;
|
||||||
@@ -248,7 +253,6 @@ static int riscv_online_cpu(unsigned int cpu)
|
|||||||
{
|
{
|
||||||
static struct page *buf;
|
static struct page *buf;
|
||||||
|
|
||||||
check_unaligned_access_emulated(NULL);
|
|
||||||
buf = alloc_pages(GFP_KERNEL, MISALIGNED_BUFFER_ORDER);
|
buf = alloc_pages(GFP_KERNEL, MISALIGNED_BUFFER_ORDER);
|
||||||
if (!buf) {
|
if (!buf) {
|
||||||
pr_warn("Allocation failure, not measuring misaligned performance\n");
|
pr_warn("Allocation failure, not measuring misaligned performance\n");
|
||||||
@@ -439,6 +443,8 @@ static int __init check_unaligned_access_all_cpus(void)
|
|||||||
{
|
{
|
||||||
int cpu;
|
int cpu;
|
||||||
|
|
||||||
|
unaligned_access_init();
|
||||||
|
|
||||||
if (unaligned_scalar_speed_param != RISCV_HWPROBE_MISALIGNED_SCALAR_UNKNOWN) {
|
if (unaligned_scalar_speed_param != RISCV_HWPROBE_MISALIGNED_SCALAR_UNKNOWN) {
|
||||||
pr_info("scalar unaligned access speed set to '%s' (%lu) by command line\n",
|
pr_info("scalar unaligned access speed set to '%s' (%lu) by command line\n",
|
||||||
speed_str[unaligned_scalar_speed_param], unaligned_scalar_speed_param);
|
speed_str[unaligned_scalar_speed_param], unaligned_scalar_speed_param);
|
||||||
|
|||||||
Reference in New Issue
Block a user