riscv: sbi: add FWFT extension interface

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>
Reviewed-by: Atish Patra <atishp@rivosinc.com>
Link: https://lore.kernel.org/r/20250523101932.1594077-5-cleger@rivosinc.com
Signed-off-by: Palmer Dabbelt <palmer@dabbelt.com>
This commit is contained in:
Clément Léger 2025-05-23 12:19:21 +02:00 committed by Palmer Dabbelt
parent 99cf5b7c73
commit 6d6d0641dc
No known key found for this signature in database
GPG Key ID: 2E1319F35FBB1889
2 changed files with 74 additions and 0 deletions

View File

@ -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)
{

View File

@ -299,6 +299,63 @@ static int __sbi_rfence_v02(int fid, const struct cpumask *cpu_mask,
return 0;
}
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);
}
/**
* 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;
}
/**
* 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.