Re: [PATCH v5 2/2] RISC-V: KVM: AIA: Make HGEI number management fully per-CPU

Guo Ren <[email protected]>
Newsgroups org.infradead.lists.kvm-riscv,org.infradead.lists.linux-riscv,org.kernel.vger.kvm,org.kernel.vger.linux-kernel
Message-ID <CAJF2gTST9S5ojmvqvGZ7AekTKyN5JQJQZbW=Ruyg40ZRZmBtNQ@mail.gmail.com>
On Mon, May 25, 2026 at 5:49 PM Anup Patel <[email protected]> wrote:
>
> From: "Guo Ren (Alibaba DAMO Academy)" <[email protected]>
>
> 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) <[email protected]>
> Signed-off-by: Anup Patel <[email protected]>
> ---
>  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

-- 
kvm-riscv mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/kvm-riscv
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.