On Mon, Mar 10, 2025 at 04:12:09PM +0100, 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).
Signed-off-by: Clément Léger cleger@rivosinc.com
arch/riscv/include/asm/sbi.h | 5 ++ arch/riscv/kernel/sbi.c | 97 ++++++++++++++++++++++++++++++++++++ 2 files changed, 102 insertions(+)
diff --git a/arch/riscv/include/asm/sbi.h b/arch/riscv/include/asm/sbi.h index bb077d0c912f..fc87c609c11a 100644 --- a/arch/riscv/include/asm/sbi.h +++ b/arch/riscv/include/asm/sbi.h @@ -503,6 +503,11 @@ int sbi_remote_hfence_vvma_asid(const struct cpumask *cpu_mask, unsigned long asid); long sbi_probe_extension(int ext); +int sbi_fwft_all_cpus_set(u32 feature, unsigned long value, unsigned long flags,
bool revert_on_failure);
+int sbi_fwft_get(u32 feature, unsigned long *value); +int sbi_fwft_set(u32 feature, unsigned long value, unsigned long 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 1989b8cade1b..256910db1307 100644 --- a/arch/riscv/kernel/sbi.c +++ b/arch/riscv/kernel/sbi.c @@ -299,6 +299,103 @@ static int __sbi_rfence_v02(int fid, const struct cpumask *cpu_mask, return 0; } +int sbi_fwft_get(u32 feature, unsigned long *value) +{
- return -EOPNOTSUPP;
+}
+/**
- sbi_fwft_set() - Set a feature on all online cpus
copy+paste of description from sbi_fwft_all_cpus_set(). This function only sets the feature on the calling hart.
- @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.
- */
+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;
- cpumask_t mask;
+};
+static void cpu_sbi_fwft_set(void *arg) +{
- struct fwft_set_req *req = arg;
- if (sbi_fwft_set(req->feature, req->value, req->flags))
cpumask_clear_cpu(smp_processor_id(), &req->mask);
+}
+static int sbi_fwft_feature_local_set(u32 feature, unsigned long value,
unsigned long flags,
bool revert_on_fail)
+{
- int ret;
- unsigned long prev_value;
- cpumask_t tmp;
- struct fwft_set_req req = {
.feature = feature,
.value = value,
.flags = flags,
- };
- cpumask_copy(&req.mask, cpu_online_mask);
- /* We can not revert if features are locked */
- if (revert_on_fail && flags & SBI_FWFT_SET_FLAG_LOCK)
Should use () around the flags &. I thought checkpatch complained about that?
return -EINVAL;
- /* Reset value is the same for all cpus, read it once. */
How do we know we're reading the reset value? sbi_fwft_all_cpus_set() may be called multiple times on the same feature. And harts may have had sbi_fwft_set() called on them independently. I think we should drop the whole prev_value optimization.
- ret = sbi_fwft_get(feature, &prev_value);
- if (ret)
return ret;
- /* Feature might already be set to the value we want */
- if (prev_value == value)
return 0;
- on_each_cpu_mask(&req.mask, cpu_sbi_fwft_set, &req, 1);
- if (cpumask_equal(&req.mask, cpu_online_mask))
return 0;
- pr_err("Failed to set feature %x for all online cpus, reverting\n",
feature);
nit: I'd let the above line stick out. We have 100 chars.
- req.value = prev_value;
- cpumask_copy(&tmp, &req.mask);
- on_each_cpu_mask(&req.mask, cpu_sbi_fwft_set, &req, 1);
- if (cpumask_equal(&req.mask, &tmp))
return 0;
I'm not sure we want the revert_on_fail support either. What happens when the revert fails and we return -EINVAL below? Also returning zero when revert succeeds means the caller won't know if we successfully set what we wanted or just successfully reverted.
- return -EINVAL;
+}
+/**
- sbi_fwft_all_cpus_set() - 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
- @revert_on_fail: true if feature value should be restored to it's orignal
its original
value on failure.
Line 'value' up under 'true'
- Return: 0 on success, appropriate linux error code otherwise.
- */
+int sbi_fwft_all_cpus_set(u32 feature, unsigned long value, unsigned long flags,
bool revert_on_fail)
+{
- if (feature & SBI_FWFT_GLOBAL_FEATURE_BIT)
return sbi_fwft_set(feature, value, flags);
- return sbi_fwft_feature_local_set(feature, value, flags,
revert_on_fail);
+}
/**
- sbi_set_timer() - Program the timer for next timer event.
- @stime_value: The value after which next timer event should fire.
-- 2.47.2
Thanks, drew