From: Yong-Xuan Wang Date: Mon, 1 Jun 2026 10:26:23 +0000 (-0700) Subject: KVM: RISC-V: SBI FWFT: Add optional init() callback for hardware probing X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=86957e5b4bff60c2f97d79c922e5dfafe0d94151;p=thirdparty%2Flinux.git KVM: RISC-V: SBI FWFT: Add optional init() callback for hardware probing Add an optional init() callback to separate one-time hardware probing from runtime availability checks. For pointer masking, this allows probing supported PMM lengths during initialization while checking ISA extension availability at runtime. Fix try_to_set_pmm() to restore the previous HENVCFG.PMM value after probing, preventing side effects from hardware detection. Add preemption protection to ensure CSR probe sequences complete atomically on the same CPU. Fixes: 6f576fc0aeb9 ("RISC-V: KVM: Add support for SBI_FWFT_POINTER_MASKING_PMLEN") Signed-off-by: Yong-Xuan Wang Reviewed-by: Anup Patel Link: https://lore.kernel.org/r/20260601-kvm-get_reg_list-v2-v5-2-415d08a2813b@sifive.com Signed-off-by: Anup Patel --- diff --git a/arch/riscv/kvm/vcpu_sbi_fwft.c b/arch/riscv/kvm/vcpu_sbi_fwft.c index 5e4aafb0cbf1..aee951f2b8e6 100644 --- a/arch/riscv/kvm/vcpu_sbi_fwft.c +++ b/arch/riscv/kvm/vcpu_sbi_fwft.c @@ -35,6 +35,16 @@ struct kvm_sbi_fwft_feature { */ bool (*supported)(struct kvm_vcpu *vcpu); + /** + * @init: Probe and initialize the feature on the vcpu + * + * This callback is optional. If provided, it will be called during + * vcpu initialization to probe the feature availability and perform + * any necessary initialization. Returns true if the feature is supported + * and initialized successfully, false otherwise. + */ + bool (*init)(struct kvm_vcpu *vcpu); + /** * @reset: Reset the feature value irrespective whether feature is supported or not * @@ -131,19 +141,30 @@ static long kvm_sbi_fwft_get_misaligned_delegation(struct kvm_vcpu *vcpu, static bool try_to_set_pmm(unsigned long value) { + unsigned long prev; + bool ret; + + prev = csr_read_clear(CSR_HENVCFG, ENVCFG_PMM); csr_set(CSR_HENVCFG, value); - return (csr_read_clear(CSR_HENVCFG, ENVCFG_PMM) & ENVCFG_PMM) == value; + ret = (csr_read_clear(CSR_HENVCFG, ENVCFG_PMM) & ENVCFG_PMM) == value; + csr_write(CSR_HENVCFG, prev); + + return ret; } static bool kvm_sbi_fwft_pointer_masking_pmlen_supported(struct kvm_vcpu *vcpu) { - struct kvm_sbi_fwft *fwft = vcpu_to_fwft(vcpu); + return riscv_isa_extension_available(vcpu->arch.isa, SMNPM); +} - if (!riscv_isa_extension_available(vcpu->arch.isa, SMNPM)) - return false; +static bool kvm_sbi_fwft_pointer_masking_pmlen_init(struct kvm_vcpu *vcpu) +{ + struct kvm_sbi_fwft *fwft = vcpu_to_fwft(vcpu); + preempt_disable(); fwft->have_vs_pmlen_7 = try_to_set_pmm(ENVCFG_PMM_PMLEN_7); fwft->have_vs_pmlen_16 = try_to_set_pmm(ENVCFG_PMM_PMLEN_16); + preempt_enable(); return fwft->have_vs_pmlen_7 || fwft->have_vs_pmlen_16; } @@ -231,6 +252,7 @@ static const struct kvm_sbi_fwft_feature features[] = { .first_reg_num = offsetof(struct kvm_riscv_sbi_fwft, pointer_masking.enable) / sizeof(unsigned long), .supported = kvm_sbi_fwft_pointer_masking_pmlen_supported, + .init = kvm_sbi_fwft_pointer_masking_pmlen_init, .reset = kvm_sbi_fwft_reset_pointer_masking_pmlen, .set = kvm_sbi_fwft_set_pointer_masking_pmlen, .get = kvm_sbi_fwft_get_pointer_masking_pmlen, @@ -365,6 +387,9 @@ static int kvm_sbi_ext_fwft_init(struct kvm_vcpu *vcpu) else conf->supported = true; + if (conf->supported && feature->init) + conf->supported = feature->init(vcpu); + conf->enabled = conf->supported; conf->feature = feature; }