On 09/05/2025 02:18, Atish Patra wrote:
On 4/24/25 10:31 AM, Clément Léger wrote:
This SBI extensions enables supervisor mode to control feature that are under M-mode control (For instance, Svadu menvcfg ADUE bit, Ssdbltrp DTE, etc). Add an interface to set local features for a specific cpu mask as well as for the online cpu mask.
Signed-off-by: Clément Léger cleger@rivosinc.com Reviewed-by: Andrew Jones ajones@ventanamicro.com
arch/riscv/include/asm/sbi.h | 17 +++++++++++ arch/riscv/kernel/sbi.c | 57 ++++++++++++++++++++++++++++++++++++ 2 files changed, 74 insertions(+)
diff --git a/arch/riscv/include/asm/sbi.h b/arch/riscv/include/asm/sbi.h index 7ec249fea880..3bbef56bcefc 100644 --- a/arch/riscv/include/asm/sbi.h +++ b/arch/riscv/include/asm/sbi.h @@ -503,6 +503,23 @@ int sbi_remote_hfence_vvma_asid(const struct cpumask *cpu_mask, unsigned long asid); long sbi_probe_extension(int ext); +int sbi_fwft_set(u32 feature, unsigned long value, unsigned long flags); +int sbi_fwft_set_cpumask(const cpumask_t *mask, u32 feature, + unsigned long value, unsigned long flags); +/**
- sbi_fwft_set_online_cpus() - Set a feature on all online cpus
- @feature: The feature to be set
- @value: The feature value to be set
- @flags: FWFT feature set flags
- Return: 0 on success, appropriate linux error code otherwise.
- */
+static inline int sbi_fwft_set_online_cpus(u32 feature, unsigned long value, + unsigned long flags) +{ + return sbi_fwft_set_cpumask(cpu_online_mask, feature, value, flags); +}
/* Check if current SBI specification version is 0.1 or not */ static inline int sbi_spec_is_0_1(void) { diff --git a/arch/riscv/kernel/sbi.c b/arch/riscv/kernel/sbi.c index 1d44c35305a9..d57e4dae7dac 100644 --- a/arch/riscv/kernel/sbi.c +++ b/arch/riscv/kernel/sbi.c @@ -299,6 +299,63 @@ static int __sbi_rfence_v02(int fid, const struct cpumask *cpu_mask, return 0; } +/**
- sbi_fwft_set() - Set a feature on the local hart
- @feature: The feature ID to be set
- @value: The feature value to be set
- @flags: FWFT feature set flags
- Return: 0 on success, appropriate linux error code otherwise.
- */
+int sbi_fwft_set(u32 feature, unsigned long value, unsigned long flags) +{ + return -EOPNOTSUPP; +}
+struct fwft_set_req { + u32 feature; + unsigned long value; + unsigned long flags; + atomic_t error; +};
+static void cpu_sbi_fwft_set(void *arg) +{ + struct fwft_set_req *req = arg; + int ret;
+ ret = sbi_fwft_set(req->feature, req->value, req->flags); + if (ret) + atomic_set(&req->error, ret);
What happens when cpuX executed first reported an error but cpuY executed this function later and report success.
The error will be masked in that case.
We actually only set the bit if an error happened (consider it as a sticky error bit). So if CPUy reports success, it won't clear the bit.
Thanks,
Clément
+}
+/**
- sbi_fwft_set_cpumask() - Set a feature for the specified cpumask
- @mask: CPU mask of cpus that need the feature to be set
- @feature: The feature ID to be set
- @value: The feature value to be set
- @flags: FWFT feature set flags
- Return: 0 on success, appropriate linux error code otherwise.
- */
+int sbi_fwft_set_cpumask(const cpumask_t *mask, u32 feature, + unsigned long value, unsigned long flags) +{ + struct fwft_set_req req = { + .feature = feature, + .value = value, + .flags = flags, + .error = ATOMIC_INIT(0), + };
+ if (feature & SBI_FWFT_GLOBAL_FEATURE_BIT) + return -EINVAL;
+ on_each_cpu_mask(mask, cpu_sbi_fwft_set, &req, 1);
+ return atomic_read(&req.error); +}
/** * sbi_set_timer() - Program the timer for next timer event. * @stime_value: The value after which next timer event should fire.