* [PATCH v5 0/2] RISC-V: KVM: Convert HGEI management to fully per-HART
@ 2026-05-25 9:49 Anup Patel
2026-05-25 9:49 ` [PATCH v5 1/2] irqchip/riscv-imsic: Add nr_guest_files in per-HART local config Anup Patel
` (3 more replies)
0 siblings, 4 replies; 6+ messages in thread
From: Anup Patel @ 2026-05-25 9:49 UTC (permalink / raw)
To: Paolo Bonzini, Atish Patra, Thomas Gleixner
Cc: Palmer Dabbelt, Paul Walmsley, Anup Patel, Andrew Jones,
kvm-riscv, kvm, linux-riscv, linux-kernel,
Guo Ren (Alibaba DAMO Academy)
From: "Guo Ren (Alibaba DAMO Academy)" <guoren@kernel.org>
This short series converts RISC-V KVM AIA's Hypervisor Guest External
Interrupt (HGEI) line management from a global "one-size-fits-all"
model to a fully per-HART (per-CPU) model. It also performs the
corresponding changes in the IMSIC irqchip driver.
The motivation is to properly support heterogeneous RISC-V SoCs
(big.LITTLE, multi-vendor core mixes) where different HARTs may
expose different numbers of guest interrupt files / HGEIE bits.
After this series, HGEI allocation, freeing, and interrupt delivery
are completely per-HART and there are no remaining global assumptions
about number of guest interrupt files.
Changelog:
V5:
- Avoid re-initializing hgctrl->lock in kvm_riscv_aia_enable()
- Setup free_bitmap only once in kvm_riscv_aia_enable()
- Make kvm_riscv_aia_nr_hgei so that it can be concurrently
updated from kvm_riscv_aia_enable()
V4:
- Don't modify kvm_riscv_aia_nr_hgei in kvm_riscv_aia_enable()
since we use kvm_riscv_aia_nr_hgei mostly for HGEI enable/disable
checks.
- Use GENMASK_ULL() instead of `BIT(hgctrl->nr_hgei + 1) - 1`
- Always setup SGEI interrupt irrespective of kvm_riscv_aia_nr_hgei
V3:
- Move PATCH3 as first patch and kept the nr_guest_files in
global config as the number of guest files across all CPUs
- Droped original PATCH2 and squashed original PATCH4 into
original PATCH1 which is now PATCH2.
- Addressed comments in original PATCH1.
V2:
- Add per-HART IMSIC guest files to compute final HGEI count.
- Add min(local->nr_guest_files, nr_guest_files);
V1:
- https://lore.kernel.org/kvm-riscv/20260421145451.1597930-1-guoren@kernel.org/
Guo Ren (Alibaba DAMO Academy) (2):
irqchip/riscv-imsic: Add nr_guest_files in per-HART local config
RISC-V: KVM: AIA: Make HGEI number management fully per-CPU
arch/riscv/include/asm/kvm_aia.h | 2 +-
arch/riscv/kvm/aia.c | 88 +++++++++++++++----------
arch/riscv/kvm/aia_device.c | 4 +-
arch/riscv/kvm/main.c | 8 +--
drivers/irqchip/irq-riscv-imsic-state.c | 9 ++-
include/linux/irqchip/riscv-imsic.h | 5 +-
6 files changed, 68 insertions(+), 48 deletions(-)
--
2.43.0
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply [flat|nested] 6+ messages in thread* [PATCH v5 1/2] irqchip/riscv-imsic: Add nr_guest_files in per-HART local config 2026-05-25 9:49 [PATCH v5 0/2] RISC-V: KVM: Convert HGEI management to fully per-HART Anup Patel @ 2026-05-25 9:49 ` Anup Patel 2026-05-25 9:49 ` [PATCH v5 2/2] RISC-V: KVM: AIA: Make HGEI number management fully per-CPU Anup Patel ` (2 subsequent siblings) 3 siblings, 0 replies; 6+ messages in thread From: Anup Patel @ 2026-05-25 9:49 UTC (permalink / raw) To: Paolo Bonzini, Atish Patra, Thomas Gleixner Cc: Palmer Dabbelt, Paul Walmsley, Anup Patel, Andrew Jones, kvm-riscv, kvm, linux-riscv, linux-kernel, Guo Ren (Alibaba DAMO Academy), Anup Patel From: "Guo Ren (Alibaba DAMO Academy)" <guoren@kernel.org> Add nr_guest_files in per-HART local config to represent the number of guest files available on a particular HART whereas the nr_guest_files in the global config represents the number of guest files available across all HARTs. This allows KVM RISC-V to use nr_guest_files from per-HART local config for asymmetric big.Little systems. Signed-off-by: Guo Ren (Alibaba DAMO Academy) <guoren@kernel.org> Acked-by: Thomas Gleixner <tglx@kernel.org> Signed-off-by: Anup Patel <anup.patel@oss.qualcomm.com> --- drivers/irqchip/irq-riscv-imsic-state.c | 9 ++++----- include/linux/irqchip/riscv-imsic.h | 5 ++++- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/drivers/irqchip/irq-riscv-imsic-state.c b/drivers/irqchip/irq-riscv-imsic-state.c index e3ed874d89e7..b8d1bbbf42f7 100644 --- a/drivers/irqchip/irq-riscv-imsic-state.c +++ b/drivers/irqchip/irq-riscv-imsic-state.c @@ -920,13 +920,12 @@ int __init imsic_setup_state(struct fwnode_handle *fwnode, void *opaque) local->msi_va = mmios_va[index] + reloff; /* - * KVM uses global->nr_guest_files to determine the available guest - * interrupt files on each CPU. Take the minimum number of guest - * interrupt files across all CPUs to avoid KVM incorrectly allocating - * an unexisted or unmapped guest interrupt file on some CPUs. + * KVM uses both local->nr_guest_files and global->nr_guest_files + * to determine the available guest interrupt files on each CPU. */ nr_guest_files = (resource_size(&mmios[index]) - reloff) / IMSIC_MMIO_PAGE_SZ - 1; - global->nr_guest_files = min(global->nr_guest_files, nr_guest_files); + local->nr_guest_files = min((BIT(global->guest_index_bits) - 1), nr_guest_files); + global->nr_guest_files = min(global->nr_guest_files, local->nr_guest_files); nr_handlers++; } diff --git a/include/linux/irqchip/riscv-imsic.h b/include/linux/irqchip/riscv-imsic.h index 4b348836de7a..61af3a5bea09 100644 --- a/include/linux/irqchip/riscv-imsic.h +++ b/include/linux/irqchip/riscv-imsic.h @@ -40,6 +40,9 @@ struct imsic_local_config { phys_addr_t msi_pa; void __iomem *msi_va; + + /* Number of guest interrupt files per-HART */ + u32 nr_guest_files; }; struct imsic_global_config { @@ -68,7 +71,7 @@ struct imsic_global_config { /* Number of guest interrupt identities */ u32 nr_guest_ids; - /* Number of guest interrupt files per core */ + /* Number of guest interrupt files across all HARTs */ u32 nr_guest_files; /* Per-CPU IMSIC addresses */ -- 2.43.0 _______________________________________________ linux-riscv mailing list linux-riscv@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-riscv ^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH v5 2/2] RISC-V: KVM: AIA: Make HGEI number management fully per-CPU 2026-05-25 9:49 [PATCH v5 0/2] RISC-V: KVM: Convert HGEI management to fully per-HART Anup Patel 2026-05-25 9:49 ` [PATCH v5 1/2] irqchip/riscv-imsic: Add nr_guest_files in per-HART local config Anup Patel @ 2026-05-25 9:49 ` Anup Patel 2026-05-26 1:12 ` Guo Ren 2026-05-31 15:10 ` [PATCH v5 0/2] RISC-V: KVM: Convert HGEI management to fully per-HART Anup Patel 2026-06-26 8:21 ` patchwork-bot+linux-riscv 3 siblings, 1 reply; 6+ messages in thread From: Anup Patel @ 2026-05-25 9:49 UTC (permalink / raw) To: Paolo Bonzini, Atish Patra, Thomas Gleixner Cc: Palmer Dabbelt, Paul Walmsley, Anup Patel, Andrew Jones, kvm-riscv, kvm, linux-riscv, linux-kernel, Guo Ren (Alibaba DAMO Academy), Anup Patel From: "Guo Ren (Alibaba DAMO Academy)" <guoren@kernel.org> Previously, the number of Hypervisor Guest External Interrupt (HGEI) lines was stored in a single global variable `kvm_riscv_aia_nr_hgei` and assumed to be the same for all HARTs. This assumption does not hold on heterogeneous RISC-V SoCs where different cores may expose different HGEIE CSR widths. Introduce `nr_hgei` field into the per-CPU `struct aia_hgei_control` and probe the actual supported HGEI count for the current HART in `kvm_riscv_aia_enable()` using the standard RISC-V CSR probe technique: csr_write(CSR_HGEIE, -1UL); nr = fls_long(csr_read(CSR_HGEIE)); if (nr) nr--; All HGEI allocation, free and disable paths (`kvm_riscv_aia_free_hgei()`, `kvm_riscv_aia_disable()`, etc.) now use the per-CPU value instead of the global one. The global `kvm_riscv_aia_nr_hgei` now represents the minimum number of HGEI lines across HARTs and can be used to check whether HGEI support is available or not. This makes KVM AIA robust on big.LITTLE-style asymmetric platforms. Signed-off-by: Guo Ren (Alibaba DAMO Academy) <guoren@kernel.org> Signed-off-by: Anup Patel <anup.patel@oss.qualcomm.com> --- arch/riscv/include/asm/kvm_aia.h | 2 +- arch/riscv/kvm/aia.c | 88 +++++++++++++++++++------------- arch/riscv/kvm/aia_device.c | 4 +- arch/riscv/kvm/main.c | 8 +-- 4 files changed, 60 insertions(+), 42 deletions(-) diff --git a/arch/riscv/include/asm/kvm_aia.h b/arch/riscv/include/asm/kvm_aia.h index b04ecdd1a860..c67ec5ac0a14 100644 --- a/arch/riscv/include/asm/kvm_aia.h +++ b/arch/riscv/include/asm/kvm_aia.h @@ -79,7 +79,7 @@ struct kvm_vcpu_aia { #define irqchip_in_kernel(k) ((k)->arch.aia.in_kernel) -extern unsigned int kvm_riscv_aia_nr_hgei; +extern atomic_t kvm_riscv_aia_nr_hgei; extern unsigned int kvm_riscv_aia_max_ids; DECLARE_STATIC_KEY_FALSE(kvm_riscv_aia_available); #define kvm_riscv_aia_available() \ diff --git a/arch/riscv/kvm/aia.c b/arch/riscv/kvm/aia.c index 5ec503288555..bafb009c5ce5 100644 --- a/arch/riscv/kvm/aia.c +++ b/arch/riscv/kvm/aia.c @@ -21,13 +21,15 @@ struct aia_hgei_control { raw_spinlock_t lock; + bool free_bitmap_initialized; unsigned long free_bitmap; struct kvm_vcpu *owners[BITS_PER_LONG]; + unsigned int nr_hgei; }; static DEFINE_PER_CPU(struct aia_hgei_control, aia_hgei); static int hgei_parent_irq; -unsigned int kvm_riscv_aia_nr_hgei; +atomic_t kvm_riscv_aia_nr_hgei; unsigned int kvm_riscv_aia_max_ids; DEFINE_STATIC_KEY_FALSE(kvm_riscv_aia_available); @@ -452,7 +454,7 @@ void kvm_riscv_aia_free_hgei(int cpu, int hgei) raw_spin_lock_irqsave(&hgctrl->lock, flags); - if (hgei > 0 && hgei <= kvm_riscv_aia_nr_hgei) { + if (hgei > 0 && hgei <= hgctrl->nr_hgei) { if (!(hgctrl->free_bitmap & BIT(hgei))) { hgctrl->free_bitmap |= BIT(hgei); hgctrl->owners[hgei] = NULL; @@ -486,26 +488,18 @@ static irqreturn_t hgei_interrupt(int irq, void *dev_id) static int aia_hgei_init(void) { - int cpu, rc; - struct irq_domain *domain; struct aia_hgei_control *hgctrl; + struct irq_domain *domain; + int cpu, rc; /* Initialize per-CPU guest external interrupt line management */ for_each_possible_cpu(cpu) { hgctrl = per_cpu_ptr(&aia_hgei, cpu); raw_spin_lock_init(&hgctrl->lock); - if (kvm_riscv_aia_nr_hgei) { - hgctrl->free_bitmap = - BIT(kvm_riscv_aia_nr_hgei + 1) - 1; - hgctrl->free_bitmap &= ~BIT(0); - } else - hgctrl->free_bitmap = 0; + hgctrl->free_bitmap_initialized = false; + hgctrl->free_bitmap = 0; } - /* Skip SGEI interrupt setup for zero guest external interrupts */ - if (!kvm_riscv_aia_nr_hgei) - goto skip_sgei_interrupt; - /* Find INTC irq domain */ domain = irq_find_matching_fwnode(riscv_get_intc_hwnode(), DOMAIN_BUS_ANY); @@ -529,25 +523,60 @@ static int aia_hgei_init(void) return rc; } -skip_sgei_interrupt: return 0; } static void aia_hgei_exit(void) { - /* Do nothing for zero guest external interrupts */ - if (!kvm_riscv_aia_nr_hgei) - return; - /* Free per-CPU SGEI interrupt */ free_percpu_irq(hgei_parent_irq, &aia_hgei); } void kvm_riscv_aia_enable(void) { + const struct imsic_global_config *gc; + const struct imsic_local_config *lc; + struct aia_hgei_control *hgctrl; + unsigned long flags; + int aia_nr_hgei; + if (!kvm_riscv_aia_available()) return; + gc = imsic_get_global_config(); + lc = (gc) ? this_cpu_ptr(gc->local) : NULL; + hgctrl = this_cpu_ptr(&aia_hgei); + + /* Figure-out number of bits in HGEIE */ + csr_write(CSR_HGEIE, -1UL); + hgctrl->nr_hgei = fls_long(csr_read(CSR_HGEIE)); + csr_write(CSR_HGEIE, 0); + if (hgctrl->nr_hgei) + hgctrl->nr_hgei--; + + /* + * Number of usable per-HART HGEI lines should be minimum of + * per-HART IMSIC guest files and number of bits in HGEIE. + */ + if (lc) + hgctrl->nr_hgei = min((ulong)hgctrl->nr_hgei, lc->nr_guest_files); + else + hgctrl->nr_hgei = 0; + + /* Update the number of IMSIC guest files across all HARTs */ + aia_nr_hgei = atomic_read(&kvm_riscv_aia_nr_hgei); + do { + if (aia_nr_hgei <= hgctrl->nr_hgei) + break; + } while (!atomic_try_cmpxchg(&kvm_riscv_aia_nr_hgei, &aia_nr_hgei, hgctrl->nr_hgei)); + + raw_spin_lock_irqsave(&hgctrl->lock, flags); + if (!hgctrl->free_bitmap_initialized) { + hgctrl->free_bitmap = (hgctrl->nr_hgei) ? GENMASK_ULL(hgctrl->nr_hgei, 1) : 0; + hgctrl->free_bitmap_initialized = true; + } + raw_spin_unlock_irqrestore(&hgctrl->lock, flags); + csr_write(CSR_HVICTL, aia_hvictl_value(false)); csr_write(CSR_HVIPRIO1, 0x0); csr_write(CSR_HVIPRIO2, 0x0); @@ -588,7 +617,7 @@ void kvm_riscv_aia_disable(void) raw_spin_lock_irqsave(&hgctrl->lock, flags); - for (i = 0; i <= kvm_riscv_aia_nr_hgei; i++) { + for (i = 0; i <= hgctrl->nr_hgei; i++) { vcpu = hgctrl->owners[i]; if (!vcpu) continue; @@ -628,26 +657,15 @@ int kvm_riscv_aia_init(void) return -ENODEV; gc = imsic_get_global_config(); - /* Figure-out number of bits in HGEIE */ - csr_write(CSR_HGEIE, -1UL); - kvm_riscv_aia_nr_hgei = fls_long(csr_read(CSR_HGEIE)); - csr_write(CSR_HGEIE, 0); - if (kvm_riscv_aia_nr_hgei) - kvm_riscv_aia_nr_hgei--; - - /* - * Number of usable HGEI lines should be minimum of per-HART - * IMSIC guest files and number of bits in HGEIE - */ + /* Set initial value of IMSIC guest files across all HARTs */ if (gc) - kvm_riscv_aia_nr_hgei = min((ulong)kvm_riscv_aia_nr_hgei, - gc->nr_guest_files); + atomic_set(&kvm_riscv_aia_nr_hgei, gc->nr_guest_files); else - kvm_riscv_aia_nr_hgei = 0; + atomic_set(&kvm_riscv_aia_nr_hgei, 0); /* Find number of guest MSI IDs */ kvm_riscv_aia_max_ids = IMSIC_MAX_ID; - if (gc && kvm_riscv_aia_nr_hgei) + if (gc) kvm_riscv_aia_max_ids = gc->nr_guest_ids + 1; /* Initialize guest external interrupt line management */ diff --git a/arch/riscv/kvm/aia_device.c b/arch/riscv/kvm/aia_device.c index 3d1e81e2a36b..be83c2d5fc30 100644 --- a/arch/riscv/kvm/aia_device.c +++ b/arch/riscv/kvm/aia_device.c @@ -71,7 +71,7 @@ static int aia_config(struct kvm *kvm, unsigned long type, * external interrupts (i.e. non-zero * VS-level IMSIC pages). */ - if (!kvm_riscv_aia_nr_hgei) + if (!atomic_read(&kvm_riscv_aia_nr_hgei)) return -EINVAL; break; default: @@ -628,7 +628,7 @@ void kvm_riscv_aia_init_vm(struct kvm *kvm) */ /* Initialize default values in AIA global context */ - aia->mode = (kvm_riscv_aia_nr_hgei) ? + aia->mode = (atomic_read(&kvm_riscv_aia_nr_hgei)) ? KVM_DEV_RISCV_AIA_MODE_AUTO : KVM_DEV_RISCV_AIA_MODE_EMUL; aia->nr_ids = kvm_riscv_aia_max_ids - 1; aia->nr_sources = 0; diff --git a/arch/riscv/kvm/main.c b/arch/riscv/kvm/main.c index cb8a65273c1f..0924c75100a2 100644 --- a/arch/riscv/kvm/main.c +++ b/arch/riscv/kvm/main.c @@ -168,10 +168,6 @@ static int __init riscv_kvm_init(void) kvm_info("VMID %ld bits available\n", kvm_riscv_gstage_vmid_bits()); - if (kvm_riscv_aia_available()) - kvm_info("AIA available with %d guest external interrupts\n", - kvm_riscv_aia_nr_hgei); - kvm_riscv_setup_vendor_features(); kvm_register_perf_callbacks(); @@ -182,6 +178,10 @@ static int __init riscv_kvm_init(void) return rc; } + if (kvm_riscv_aia_available()) + kvm_info("AIA available with %d guest external interrupts\n", + atomic_read(&kvm_riscv_aia_nr_hgei)); + return 0; } module_init(riscv_kvm_init); -- 2.43.0 _______________________________________________ linux-riscv mailing list linux-riscv@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-riscv ^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [PATCH v5 2/2] RISC-V: KVM: AIA: Make HGEI number management fully per-CPU 2026-05-25 9:49 ` [PATCH v5 2/2] RISC-V: KVM: AIA: Make HGEI number management fully per-CPU Anup Patel @ 2026-05-26 1:12 ` Guo Ren 0 siblings, 0 replies; 6+ messages in thread From: Guo Ren @ 2026-05-26 1:12 UTC (permalink / raw) To: Anup Patel Cc: Paolo Bonzini, Atish Patra, Thomas Gleixner, Palmer Dabbelt, Paul Walmsley, Anup Patel, Andrew Jones, kvm-riscv, kvm, linux-riscv, linux-kernel On Mon, May 25, 2026 at 5:49 PM Anup Patel <anup.patel@oss.qualcomm.com> wrote: > > From: "Guo Ren (Alibaba DAMO Academy)" <guoren@kernel.org> > > Previously, the number of Hypervisor Guest External Interrupt (HGEI) > lines was stored in a single global variable `kvm_riscv_aia_nr_hgei` > and assumed to be the same for all HARTs. This assumption does not > hold on heterogeneous RISC-V SoCs where different cores may expose > different HGEIE CSR widths. > > Introduce `nr_hgei` field into the per-CPU `struct aia_hgei_control` > and probe the actual supported HGEI count for the current HART in > `kvm_riscv_aia_enable()` using the standard RISC-V CSR probe technique: > > csr_write(CSR_HGEIE, -1UL); > nr = fls_long(csr_read(CSR_HGEIE)); > if (nr) > nr--; > > All HGEI allocation, free and disable paths (`kvm_riscv_aia_free_hgei()`, > `kvm_riscv_aia_disable()`, etc.) now use the per-CPU value instead of > the global one. > > The global `kvm_riscv_aia_nr_hgei` now represents the minimum number > of HGEI lines across HARTs and can be used to check whether HGEI > support is available or not. > > This makes KVM AIA robust on big.LITTLE-style asymmetric platforms. > > Signed-off-by: Guo Ren (Alibaba DAMO Academy) <guoren@kernel.org> > Signed-off-by: Anup Patel <anup.patel@oss.qualcomm.com> > --- > arch/riscv/include/asm/kvm_aia.h | 2 +- > arch/riscv/kvm/aia.c | 88 +++++++++++++++++++------------- > arch/riscv/kvm/aia_device.c | 4 +- > arch/riscv/kvm/main.c | 8 +-- > 4 files changed, 60 insertions(+), 42 deletions(-) > > diff --git a/arch/riscv/include/asm/kvm_aia.h b/arch/riscv/include/asm/kvm_aia.h > index b04ecdd1a860..c67ec5ac0a14 100644 > --- a/arch/riscv/include/asm/kvm_aia.h > +++ b/arch/riscv/include/asm/kvm_aia.h > @@ -79,7 +79,7 @@ struct kvm_vcpu_aia { > > #define irqchip_in_kernel(k) ((k)->arch.aia.in_kernel) > > -extern unsigned int kvm_riscv_aia_nr_hgei; > +extern atomic_t kvm_riscv_aia_nr_hgei; > extern unsigned int kvm_riscv_aia_max_ids; > DECLARE_STATIC_KEY_FALSE(kvm_riscv_aia_available); > #define kvm_riscv_aia_available() \ > diff --git a/arch/riscv/kvm/aia.c b/arch/riscv/kvm/aia.c > index 5ec503288555..bafb009c5ce5 100644 > --- a/arch/riscv/kvm/aia.c > +++ b/arch/riscv/kvm/aia.c > @@ -21,13 +21,15 @@ > > struct aia_hgei_control { > raw_spinlock_t lock; > + bool free_bitmap_initialized; > unsigned long free_bitmap; > struct kvm_vcpu *owners[BITS_PER_LONG]; > + unsigned int nr_hgei; > }; > static DEFINE_PER_CPU(struct aia_hgei_control, aia_hgei); > static int hgei_parent_irq; > > -unsigned int kvm_riscv_aia_nr_hgei; > +atomic_t kvm_riscv_aia_nr_hgei; > unsigned int kvm_riscv_aia_max_ids; > DEFINE_STATIC_KEY_FALSE(kvm_riscv_aia_available); > > @@ -452,7 +454,7 @@ void kvm_riscv_aia_free_hgei(int cpu, int hgei) > > raw_spin_lock_irqsave(&hgctrl->lock, flags); > > - if (hgei > 0 && hgei <= kvm_riscv_aia_nr_hgei) { > + if (hgei > 0 && hgei <= hgctrl->nr_hgei) { > if (!(hgctrl->free_bitmap & BIT(hgei))) { > hgctrl->free_bitmap |= BIT(hgei); > hgctrl->owners[hgei] = NULL; > @@ -486,26 +488,18 @@ static irqreturn_t hgei_interrupt(int irq, void *dev_id) > > static int aia_hgei_init(void) > { > - int cpu, rc; > - struct irq_domain *domain; > struct aia_hgei_control *hgctrl; > + struct irq_domain *domain; > + int cpu, rc; > > /* Initialize per-CPU guest external interrupt line management */ > for_each_possible_cpu(cpu) { > hgctrl = per_cpu_ptr(&aia_hgei, cpu); > raw_spin_lock_init(&hgctrl->lock); > - if (kvm_riscv_aia_nr_hgei) { > - hgctrl->free_bitmap = > - BIT(kvm_riscv_aia_nr_hgei + 1) - 1; > - hgctrl->free_bitmap &= ~BIT(0); > - } else > - hgctrl->free_bitmap = 0; > + hgctrl->free_bitmap_initialized = false; > + hgctrl->free_bitmap = 0; > } > > - /* Skip SGEI interrupt setup for zero guest external interrupts */ > - if (!kvm_riscv_aia_nr_hgei) > - goto skip_sgei_interrupt; > - > /* Find INTC irq domain */ > domain = irq_find_matching_fwnode(riscv_get_intc_hwnode(), > DOMAIN_BUS_ANY); > @@ -529,25 +523,60 @@ static int aia_hgei_init(void) > return rc; > } > > -skip_sgei_interrupt: > return 0; > } > > static void aia_hgei_exit(void) > { > - /* Do nothing for zero guest external interrupts */ > - if (!kvm_riscv_aia_nr_hgei) > - return; > - > /* Free per-CPU SGEI interrupt */ > free_percpu_irq(hgei_parent_irq, &aia_hgei); > } > > void kvm_riscv_aia_enable(void) > { > + const struct imsic_global_config *gc; > + const struct imsic_local_config *lc; > + struct aia_hgei_control *hgctrl; > + unsigned long flags; > + int aia_nr_hgei; > + > if (!kvm_riscv_aia_available()) > return; > > + gc = imsic_get_global_config(); > + lc = (gc) ? this_cpu_ptr(gc->local) : NULL; > + hgctrl = this_cpu_ptr(&aia_hgei); > + > + /* Figure-out number of bits in HGEIE */ > + csr_write(CSR_HGEIE, -1UL); > + hgctrl->nr_hgei = fls_long(csr_read(CSR_HGEIE)); > + csr_write(CSR_HGEIE, 0); > + if (hgctrl->nr_hgei) > + hgctrl->nr_hgei--; > + > + /* > + * Number of usable per-HART HGEI lines should be minimum of > + * per-HART IMSIC guest files and number of bits in HGEIE. > + */ > + if (lc) > + hgctrl->nr_hgei = min((ulong)hgctrl->nr_hgei, lc->nr_guest_files); Great! You correct that. > + else > + hgctrl->nr_hgei = 0; > + > + /* Update the number of IMSIC guest files across all HARTs */ > + aia_nr_hgei = atomic_read(&kvm_riscv_aia_nr_hgei); > + do { > + if (aia_nr_hgei <= hgctrl->nr_hgei) > + break; > + } while (!atomic_try_cmpxchg(&kvm_riscv_aia_nr_hgei, &aia_nr_hgei, hgctrl->nr_hgei)); > + > + raw_spin_lock_irqsave(&hgctrl->lock, flags); > + if (!hgctrl->free_bitmap_initialized) { > + hgctrl->free_bitmap = (hgctrl->nr_hgei) ? GENMASK_ULL(hgctrl->nr_hgei, 1) : 0; > + hgctrl->free_bitmap_initialized = true; > + } > + raw_spin_unlock_irqrestore(&hgctrl->lock, flags); > + > csr_write(CSR_HVICTL, aia_hvictl_value(false)); > csr_write(CSR_HVIPRIO1, 0x0); > csr_write(CSR_HVIPRIO2, 0x0); > @@ -588,7 +617,7 @@ void kvm_riscv_aia_disable(void) > > raw_spin_lock_irqsave(&hgctrl->lock, flags); > > - for (i = 0; i <= kvm_riscv_aia_nr_hgei; i++) { > + for (i = 0; i <= hgctrl->nr_hgei; i++) { > vcpu = hgctrl->owners[i]; > if (!vcpu) > continue; > @@ -628,26 +657,15 @@ int kvm_riscv_aia_init(void) > return -ENODEV; > gc = imsic_get_global_config(); > > - /* Figure-out number of bits in HGEIE */ > - csr_write(CSR_HGEIE, -1UL); > - kvm_riscv_aia_nr_hgei = fls_long(csr_read(CSR_HGEIE)); > - csr_write(CSR_HGEIE, 0); > - if (kvm_riscv_aia_nr_hgei) > - kvm_riscv_aia_nr_hgei--; > - > - /* > - * Number of usable HGEI lines should be minimum of per-HART > - * IMSIC guest files and number of bits in HGEIE > - */ > + /* Set initial value of IMSIC guest files across all HARTs */ > if (gc) > - kvm_riscv_aia_nr_hgei = min((ulong)kvm_riscv_aia_nr_hgei, > - gc->nr_guest_files); > + atomic_set(&kvm_riscv_aia_nr_hgei, gc->nr_guest_files); > else > - kvm_riscv_aia_nr_hgei = 0; > + atomic_set(&kvm_riscv_aia_nr_hgei, 0); > > /* Find number of guest MSI IDs */ > kvm_riscv_aia_max_ids = IMSIC_MAX_ID; > - if (gc && kvm_riscv_aia_nr_hgei) > + if (gc) > kvm_riscv_aia_max_ids = gc->nr_guest_ids + 1; > > /* Initialize guest external interrupt line management */ > diff --git a/arch/riscv/kvm/aia_device.c b/arch/riscv/kvm/aia_device.c > index 3d1e81e2a36b..be83c2d5fc30 100644 > --- a/arch/riscv/kvm/aia_device.c > +++ b/arch/riscv/kvm/aia_device.c > @@ -71,7 +71,7 @@ static int aia_config(struct kvm *kvm, unsigned long type, > * external interrupts (i.e. non-zero > * VS-level IMSIC pages). > */ > - if (!kvm_riscv_aia_nr_hgei) > + if (!atomic_read(&kvm_riscv_aia_nr_hgei)) > return -EINVAL; > break; > default: > @@ -628,7 +628,7 @@ void kvm_riscv_aia_init_vm(struct kvm *kvm) > */ > > /* Initialize default values in AIA global context */ > - aia->mode = (kvm_riscv_aia_nr_hgei) ? > + aia->mode = (atomic_read(&kvm_riscv_aia_nr_hgei)) ? > KVM_DEV_RISCV_AIA_MODE_AUTO : KVM_DEV_RISCV_AIA_MODE_EMUL; > aia->nr_ids = kvm_riscv_aia_max_ids - 1; > aia->nr_sources = 0; > diff --git a/arch/riscv/kvm/main.c b/arch/riscv/kvm/main.c > index cb8a65273c1f..0924c75100a2 100644 > --- a/arch/riscv/kvm/main.c > +++ b/arch/riscv/kvm/main.c > @@ -168,10 +168,6 @@ static int __init riscv_kvm_init(void) > > kvm_info("VMID %ld bits available\n", kvm_riscv_gstage_vmid_bits()); > > - if (kvm_riscv_aia_available()) > - kvm_info("AIA available with %d guest external interrupts\n", > - kvm_riscv_aia_nr_hgei); > - > kvm_riscv_setup_vendor_features(); > > kvm_register_perf_callbacks(); > @@ -182,6 +178,10 @@ static int __init riscv_kvm_init(void) > return rc; > } > > + if (kvm_riscv_aia_available()) > + kvm_info("AIA available with %d guest external interrupts\n", > + atomic_read(&kvm_riscv_aia_nr_hgei)); > + > return 0; > } > module_init(riscv_kvm_init); > -- > 2.43.0 > -- Best Regards Guo Ren _______________________________________________ linux-riscv mailing list linux-riscv@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-riscv ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH v5 0/2] RISC-V: KVM: Convert HGEI management to fully per-HART 2026-05-25 9:49 [PATCH v5 0/2] RISC-V: KVM: Convert HGEI management to fully per-HART Anup Patel 2026-05-25 9:49 ` [PATCH v5 1/2] irqchip/riscv-imsic: Add nr_guest_files in per-HART local config Anup Patel 2026-05-25 9:49 ` [PATCH v5 2/2] RISC-V: KVM: AIA: Make HGEI number management fully per-CPU Anup Patel @ 2026-05-31 15:10 ` Anup Patel 2026-06-26 8:21 ` patchwork-bot+linux-riscv 3 siblings, 0 replies; 6+ messages in thread From: Anup Patel @ 2026-05-31 15:10 UTC (permalink / raw) To: Anup Patel Cc: Paolo Bonzini, Atish Patra, Thomas Gleixner, Palmer Dabbelt, Paul Walmsley, Andrew Jones, kvm-riscv, kvm, linux-riscv, linux-kernel, Guo Ren (Alibaba DAMO Academy) On Mon, May 25, 2026 at 3:19 PM Anup Patel <anup.patel@oss.qualcomm.com> wrote: > > From: "Guo Ren (Alibaba DAMO Academy)" <guoren@kernel.org> > > This short series converts RISC-V KVM AIA's Hypervisor Guest External > Interrupt (HGEI) line management from a global "one-size-fits-all" > model to a fully per-HART (per-CPU) model. It also performs the > corresponding changes in the IMSIC irqchip driver. > > The motivation is to properly support heterogeneous RISC-V SoCs > (big.LITTLE, multi-vendor core mixes) where different HARTs may > expose different numbers of guest interrupt files / HGEIE bits. > > After this series, HGEI allocation, freeing, and interrupt delivery > are completely per-HART and there are no remaining global assumptions > about number of guest interrupt files. > > Changelog: > V5: > - Avoid re-initializing hgctrl->lock in kvm_riscv_aia_enable() > - Setup free_bitmap only once in kvm_riscv_aia_enable() > - Make kvm_riscv_aia_nr_hgei so that it can be concurrently > updated from kvm_riscv_aia_enable() > > V4: > - Don't modify kvm_riscv_aia_nr_hgei in kvm_riscv_aia_enable() > since we use kvm_riscv_aia_nr_hgei mostly for HGEI enable/disable > checks. > - Use GENMASK_ULL() instead of `BIT(hgctrl->nr_hgei + 1) - 1` > - Always setup SGEI interrupt irrespective of kvm_riscv_aia_nr_hgei > > V3: > - Move PATCH3 as first patch and kept the nr_guest_files in > global config as the number of guest files across all CPUs > - Droped original PATCH2 and squashed original PATCH4 into > original PATCH1 which is now PATCH2. > - Addressed comments in original PATCH1. > > V2: > - Add per-HART IMSIC guest files to compute final HGEI count. > - Add min(local->nr_guest_files, nr_guest_files); > > V1: > - https://lore.kernel.org/kvm-riscv/20260421145451.1597930-1-guoren@kernel.org/ > > Guo Ren (Alibaba DAMO Academy) (2): > irqchip/riscv-imsic: Add nr_guest_files in per-HART local config > RISC-V: KVM: AIA: Make HGEI number management fully per-CPU > > arch/riscv/include/asm/kvm_aia.h | 2 +- > arch/riscv/kvm/aia.c | 88 +++++++++++++++---------- > arch/riscv/kvm/aia_device.c | 4 +- > arch/riscv/kvm/main.c | 8 +-- > drivers/irqchip/irq-riscv-imsic-state.c | 9 ++- > include/linux/irqchip/riscv-imsic.h | 5 +- > 6 files changed, 68 insertions(+), 48 deletions(-) > > -- > 2.43.0 > Queued this series for Linux-7.2 Thanks, Anup _______________________________________________ linux-riscv mailing list linux-riscv@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-riscv ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH v5 0/2] RISC-V: KVM: Convert HGEI management to fully per-HART 2026-05-25 9:49 [PATCH v5 0/2] RISC-V: KVM: Convert HGEI management to fully per-HART Anup Patel ` (2 preceding siblings ...) 2026-05-31 15:10 ` [PATCH v5 0/2] RISC-V: KVM: Convert HGEI management to fully per-HART Anup Patel @ 2026-06-26 8:21 ` patchwork-bot+linux-riscv 3 siblings, 0 replies; 6+ messages in thread From: patchwork-bot+linux-riscv @ 2026-06-26 8:21 UTC (permalink / raw) To: Anup Patel Cc: linux-riscv, pbonzini, atish.patra, tglx, palmer, pjw, anup, andrew.jones, kvm-riscv, kvm, linux-kernel, guoren Hello: This series was applied to riscv/linux.git (fixes) by Anup Patel <anup@brainfault.org>: On Mon, 25 May 2026 15:19:43 +0530 you wrote: > From: "Guo Ren (Alibaba DAMO Academy)" <guoren@kernel.org> > > This short series converts RISC-V KVM AIA's Hypervisor Guest External > Interrupt (HGEI) line management from a global "one-size-fits-all" > model to a fully per-HART (per-CPU) model. It also performs the > corresponding changes in the IMSIC irqchip driver. > > [...] Here is the summary with links: - [v5,1/2] irqchip/riscv-imsic: Add nr_guest_files in per-HART local config https://git.kernel.org/riscv/c/59ebc16276c5 - [v5,2/2] RISC-V: KVM: AIA: Make HGEI number management fully per-CPU (no matching commit) You are awesome, thank you! -- Deet-doot-dot, I am a bot. https://korg.docs.kernel.org/patchwork/pwbot.html _______________________________________________ linux-riscv mailing list linux-riscv@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-riscv ^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2026-06-26 8:21 UTC | newest] Thread overview: 6+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-05-25 9:49 [PATCH v5 0/2] RISC-V: KVM: Convert HGEI management to fully per-HART Anup Patel 2026-05-25 9:49 ` [PATCH v5 1/2] irqchip/riscv-imsic: Add nr_guest_files in per-HART local config Anup Patel 2026-05-25 9:49 ` [PATCH v5 2/2] RISC-V: KVM: AIA: Make HGEI number management fully per-CPU Anup Patel 2026-05-26 1:12 ` Guo Ren 2026-05-31 15:10 ` [PATCH v5 0/2] RISC-V: KVM: Convert HGEI management to fully per-HART Anup Patel 2026-06-26 8:21 ` patchwork-bot+linux-riscv
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox