[PATCH 3/3] irqchip/riscv-imsic: Remove global nr_guest_files after KVM AIA per-HART conversion

Guo Ren guoren at kernel.org
Tue Apr 21 20:09:30 PDT 2026


Hi all,

This patch simply removed `nr_guest_files`, which is suboptimal. For
v2, I will keep `nr_guest_files` inside `struct imsic_local_config`
(per-HART) and compute the effective HGEI count in
`kvm_riscv_aia_enable()` as:

min(hgctrl->nr_hgei, lc->nr_guest_files)

This provides a more accurate and robust per-HART configuration.

Here are the updated two patches for your review:

    irqchip/riscv-imsic: Move nr_guest_files to per-HART local config

    With the recent KVM AIA per-HART HGEI conversion, the global
    nr_guest_files is no longer appropriate. Different HARTs in
    heterogeneous SoCs may have different numbers of guest interrupt
    files.

    Move `nr_guest_files` from `struct imsic_global_config` to
    `struct imsic_local_config`, and compute it per-CPU in
    imsic_setup_state() based on the actual MMIO guest file region size.

    Update the related comment to reflect that KVM now uses the
    per-HART value.

    This eliminates the last global assumption about guest files and
    completes the per-HART conversion series for RISC-V AIA/IMSIC.

    Signed-off-by: Guo Ren (Alibaba DAMO Academy) <guoren at kernel.org>

diff --git a/drivers/irqchip/irq-riscv-imsic-state.c
b/drivers/irqchip/irq-riscv-imsic-state.c
index e3ed874d89e7..3d455ef43298 100644
--- a/drivers/irqchip/irq-riscv-imsic-state.c
+++ b/drivers/irqchip/irq-riscv-imsic-state.c
@@ -784,7 +784,7 @@ static int __init imsic_parse_fwnode(struct
fwnode_handle *fwnode,

 int __init imsic_setup_state(struct fwnode_handle *fwnode, void *opaque)
 {
-       u32 i, j, index, nr_parent_irqs, nr_mmios, nr_guest_files,
nr_handlers = 0;
+       u32 i, j, index, nr_parent_irqs, nr_mmios, nr_handlers = 0;
        struct imsic_global_config *global;
        struct imsic_local_config *local;
        void __iomem **mmios_va = NULL;
@@ -878,7 +878,6 @@ int __init imsic_setup_state(struct fwnode_handle
*fwnode, void *opaque)
        }

        /* Configure handlers for target CPUs */
-       global->nr_guest_files = BIT(global->guest_index_bits) - 1;
        for (i = 0; i < nr_parent_irqs; i++) {
                rc = imsic_get_parent_hartid(fwnode, i, &hartid);
                if (rc) {
@@ -920,13 +919,13 @@ 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
+                * KVM uses local->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.
                 */
-               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 =
+                       (resource_size(&mmios[index]) - reloff) /
IMSIC_MMIO_PAGE_SZ - 1;

                nr_handlers++;
        }
diff --git a/include/linux/irqchip/riscv-imsic.h
b/include/linux/irqchip/riscv-imsic.h
index 4b348836de7a..13e8bd7ff4b4 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 core */
+       u32                                     nr_guest_files;
 };

 struct imsic_global_config {
@@ -68,9 +71,6 @@ struct imsic_global_config {
        /* Number of guest interrupt identities */
        u32                                     nr_guest_ids;

-       /* Number of guest interrupt files per core */
-       u32                                     nr_guest_files;
-
        /* Per-CPU IMSIC addresses */
        struct imsic_local_config __percpu      *local;
 };

------------------------
The other one:

    RISC-V: KVM: AIA: Use per-HART IMSIC guest files to compute final HGEI count

    Now that `nr_guest_files` has been moved to `struct imsic_local_config`
    and is computed per-HART, KVM must respect the actual number of guest
    interrupt files available on each HART when setting up HGEI.

    In `kvm_riscv_aia_enable()`:

     - Retrieve the per-CPU IMSIC local config
     - Take `min(hgctrl->nr_hgei, lc->nr_guest_files)` as the final usable
       HGEI count for this HART
     - Use the result to initialize `free_bitmap`

    This ensures correct HGEI allocation on heterogeneous RISC-V SoCs
    where different cores may have different IMSIC guest file counts, and
    completes the per-HART conversion series.

    Signed-off-by: Guo Ren (Alibaba DAMO Academy) <guoren at kernel.org>

diff --git a/arch/riscv/kvm/aia.c b/arch/riscv/kvm/aia.c
index 70ff1d25dd99..a5f4b7fe1dce 100644
--- a/arch/riscv/kvm/aia.c
+++ b/arch/riscv/kvm/aia.c
@@ -534,6 +534,9 @@ static void aia_hgei_exit(void)
 void kvm_riscv_aia_enable(void)
 {
        struct aia_hgei_control *hgctrl;
+       const struct imsic_global_config *gc;
+       const struct imsic_local_config *lc;
+       unsigned int nr_hgei;

        if (!kvm_riscv_aia_available())
                return;
@@ -547,8 +550,13 @@ void kvm_riscv_aia_enable(void)
        if (hgctrl->nr_hgei)
                hgctrl->nr_hgei--;

-       if (hgctrl->nr_hgei) {
-               hgctrl->free_bitmap = BIT(hgctrl->nr_hgei + 1) - 1;
+       gc = imsic_get_global_config();
+       lc = (gc) ? this_cpu_ptr(gc->local) : NULL;
+       if (lc)
+               nr_hgei = min(hgctrl->nr_hgei, lc->nr_guest_files);
+
+       if (nr_hgei) {
+               hgctrl->free_bitmap = BIT(nr_hgei + 1) - 1;
                hgctrl->free_bitmap &= ~BIT(0);
        } else {
                hgctrl->free_bitmap = 0;


On Tue, Apr 21, 2026 at 10:55 PM <guoren at kernel.org> wrote:
>
> From: "Guo Ren (Alibaba DAMO Academy)" <guoren at kernel.org>
>
> With the recent KVM AIA changes, HGEI line management is now fully
> per-CPU (via struct aia_hgei_control::nr_hgei) and the global
> kvm_riscv_aia_nr_hgei has been replaced by a simple enabled flag.
> The IMSIC driver no longer needs to compute and enforce a global
> minimum number of guest interrupt files across all HARTs.
>
> Remove:
>  - `u32 nr_guest_files` from `struct imsic_global_config`
>  - the initial `BIT(global->guest_index_bits) - 1` assignment
>  - the entire per-CPU MMIO-based min() calculation and its comment
>    (which was specifically there to protect old KVM)
>
> The per-HART guest file count is already handled locally in
> `imsic_local_config` during the parent IRQ loop, so this global
> field was redundant.
>
> This completes the cleanup series, eliminates the last global
> assumption about guest files, and improves support for heterogeneous
> (big.LITTLE / multi-vendor) RISC-V platforms.
>
> Signed-off-by: Guo Ren (Alibaba DAMO Academy) <guoren at kernel.org>
> ---
>  drivers/irqchip/irq-riscv-imsic-state.c | 12 +-----------
>  include/linux/irqchip/riscv-imsic.h     |  3 ---
>  2 files changed, 1 insertion(+), 14 deletions(-)
>
> diff --git a/drivers/irqchip/irq-riscv-imsic-state.c b/drivers/irqchip/irq-riscv-imsic-state.c
> index e3ed874d89e7..fef27247a34f 100644
> --- a/drivers/irqchip/irq-riscv-imsic-state.c
> +++ b/drivers/irqchip/irq-riscv-imsic-state.c
> @@ -784,7 +784,7 @@ static int __init imsic_parse_fwnode(struct fwnode_handle *fwnode,
>
>  int __init imsic_setup_state(struct fwnode_handle *fwnode, void *opaque)
>  {
> -       u32 i, j, index, nr_parent_irqs, nr_mmios, nr_guest_files, nr_handlers = 0;
> +       u32 i, j, index, nr_parent_irqs, nr_mmios, nr_handlers = 0;
>         struct imsic_global_config *global;
>         struct imsic_local_config *local;
>         void __iomem **mmios_va = NULL;
> @@ -878,7 +878,6 @@ int __init imsic_setup_state(struct fwnode_handle *fwnode, void *opaque)
>         }
>
>         /* Configure handlers for target CPUs */
> -       global->nr_guest_files = BIT(global->guest_index_bits) - 1;
>         for (i = 0; i < nr_parent_irqs; i++) {
>                 rc = imsic_get_parent_hartid(fwnode, i, &hartid);
>                 if (rc) {
> @@ -919,15 +918,6 @@ int __init imsic_setup_state(struct fwnode_handle *fwnode, void *opaque)
>                 local->msi_pa = mmios[index].start + reloff;
>                 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.
> -                */
> -               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);
> -
>                 nr_handlers++;
>         }
>
> diff --git a/include/linux/irqchip/riscv-imsic.h b/include/linux/irqchip/riscv-imsic.h
> index 4b348836de7a..7f3ff5c5ea53 100644
> --- a/include/linux/irqchip/riscv-imsic.h
> +++ b/include/linux/irqchip/riscv-imsic.h
> @@ -68,9 +68,6 @@ struct imsic_global_config {
>         /* Number of guest interrupt identities */
>         u32                                     nr_guest_ids;
>
> -       /* Number of guest interrupt files per core */
> -       u32                                     nr_guest_files;
> -
>         /* Per-CPU IMSIC addresses */
>         struct imsic_local_config __percpu      *local;
>  };
> --
> 2.40.1
>


--
Best Regards
 Guo Ren



More information about the linux-riscv mailing list