[PATCH 2/3] irqchip/gic-v3: allocate one SGI for MSHV

Anirudh Raybharam
2025-11-25T17:03:10Z

From: Anirudh Rayabharam <anirudh@anirudhrb.com>

From: Anirudh Rayabharam (Microsoft) <anirudh@anirudhrb.com>

Currently SGIs are allocated only for the smp subsystem. The MSHV
(Microsoft Hypervisor aka Hyper-V) code also needs an SGI that can be
programmed into the SYNIC to receive intercepts from the hypervisor. The
hypervisor would then assert this SGI whenever there is a guest
VMEXIT.

Allocate one SGI for MSHV use in addition to the SGIs allocated for
IPIs. When running under MSHV, the full SGI range can be used i.e. no
need to reserve SGIs 8-15 for the secure firmware.

Since this SGI is needed only when running as a parent partition (i.e.
we can create guest partitions), check for it before allocating an SGI.

Signed-off-by: Anirudh Rayabharam (Microsoft) <anirudh@anirudhrb.com>
---
arch/arm64/hyperv/mshyperv.c | 13 +++++++++++++
arch/arm64/include/asm/mshyperv.h | 8 ++++++++
drivers/irqchip/irq-gic-v3.c | 29 ++++++++++++++++++++++++++---
3 files changed, 47 insertions(+), 3 deletions(-)

diff --git a/arch/arm64/hyperv/mshyperv.c b/arch/arm64/hyperv/mshyperv.c
index cc443a5d6c71..99690ae9b53f 100644
--- a/arch/arm64/hyperv/mshyperv.c
+++ b/arch/arm64/hyperv/mshyperv.c
@@ -20,6 +20,8 @@
static bool hyperv_detected;
static bool hyperv_initialized;

+static int mshv_intercept_irq;
+
int hv_get_hypervisor_version(union hv_hypervisor_version_info *info)
{
hv_get_vpreg_128(HV_REGISTER_HYPERVISOR_VERSION,
@@ -137,6 +139,17 @@ static int __init hyperv_init(void)
return 0;
}

+void __init mshv_set_intercept_irq(int irq)
+{
+ mshv_intercept_irq = irq;
+}
+
+int mshv_get_intercept_irq(void)
+{
+ return mshv_intercept_irq;
+}
+EXPORT_SYMBOL_GPL(mshv_get_intercept_irq);
+
early_initcall(hyperv_init);

bool hv_is_hyperv_initialized(void)
diff --git a/arch/arm64/include/asm/mshyperv.h b/arch/arm64/include/asm/mshyperv.h
index 58fde70c2e39..f3f6e82a9cb6 100644
--- a/arch/arm64/include/asm/mshyperv.h
+++ b/arch/arm64/include/asm/mshyperv.h
@@ -55,6 +55,14 @@ static inline u64 hv_get_non_nested_msr(unsigned int reg)

void hyperv_early_init(void);

+#if IS_ENABLED(CONFIG_MSHV_ROOT)
+void mshv_set_intercept_irq(int irq);
+#else
+static inline void mshv_set_intercept_irq(int irq) {}
+#endif
+
+int mshv_get_intercept_irq(void);
+
/* SMCCC hypercall parameters */
#define HV_SMCCC_FUNC_NUMBER 1
#define HV_FUNC_ID ARM_SMCCC_CALL_VAL( \
diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c
index 3de351e66ee8..56013dd0564c 100644
--- a/drivers/irqchip/irq-gic-v3.c
+++ b/drivers/irqchip/irq-gic-v3.c
@@ -35,6 +35,7 @@
#include <asm/exception.h>
#include <asm/smp_plat.h>
#include <asm/virt.h>
+#include <asm/mshyperv.h>

#include "irq-gic-common.h"

@@ -1456,8 +1457,24 @@ static void __init gic_smp_init(void)
.fwnode = gic_data.fwnode,
.param_count = 1,
};
+ /* Register all 8 non-secure SGIs */
+ const int NR_SMP_SGIS = 8;
+ int nr_sgis = NR_SMP_SGIS;
int base_sgi;

+ /*
+ * Allocate one more SGI for use by Hyper-V. This is only needed when
+ * Linux is running in a parent partition. Hyper-V will use this interrupt
+ * to notify the parent partition of intercepts.
+ *
+ * When running on Hyper-V, it is okay to use SGIs 8-15. They're not reserved
+ * for secure firmware.
+ */
+#if IS_ENABLED(CONFIG_HYPERV)
+ if (hv_parent_partition())
+ nr_sgis += 1;
+#endif
+
cpuhp_setup_state_nocalls(CPUHP_BP_PREPARE_DYN,
"irqchip/arm/gicv3:checkrdist",
gic_check_rdist, NULL);
@@ -1466,12 +1483,18 @@ static void __init gic_smp_init(void)
"irqchip/arm/gicv3:starting",
gic_starting_cpu, NULL);

- /* Register all 8 non-secure SGIs */
- base_sgi = irq_domain_alloc_irqs(gic_data.domain, 8, NUMA_NO_NODE, &sgi_fwspec);
+ base_sgi = irq_domain_alloc_irqs(gic_data.domain, nr_sgis, NUMA_NO_NODE, &sgi_fwspec);
if (WARN_ON(base_sgi <= 0))
return;

- set_smp_ipi_range(base_sgi, 8);
+ set_smp_ipi_range(base_sgi, NR_SMP_SGIS);
+
+#if IS_ENABLED(CONFIG_HYPERV)
+ if (hv_parent_partition()) {
+ base_sgi += NR_SMP_SGIS;
+ mshv_set_intercept_irq(base_sgi);
+ }
+#endif
}

static int gic_set_affinity(struct irq_data *d, const struct cpumask *mask_val,
--
2.34.1