]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
irqchip/gic-v5: Introduce minimal irq_set_type() for PPIs
authorSascha Bischoff <Sascha.Bischoff@arm.com>
Thu, 19 Mar 2026 15:57:30 +0000 (15:57 +0000)
committerMarc Zyngier <maz@kernel.org>
Thu, 19 Mar 2026 18:21:28 +0000 (18:21 +0000)
GICv5 does not support configuring the handling mode or trigger mode
of PPIs at runtime - these choices are made at implementation time,
and most of the architected PPIs have an architected handling mode (as
reported in the ICH_PPI_HMRn_EL1 registers). As chip->set_irq_type()
is optional, this has not been implemented for GICv5 PPIs as it served
no real purpose.

However, although the set_irq_type() function is marked as optional,
the lack of it breaks attempts to create a domain hierarchy on top of
GICv5's PPI domain. This is due to __irq_set_trigger() calling
chip->set_irq_type(), which returns -ENOSYS if the parent domain
doesn't implement the set_irq_type() call.

In order to make things work, this change introduces a set_irq_type()
call for GICv5 PPIs. This performs a basic sanity check (that the
hardware's handling mode (Level/Edge) matches what is being set as the
type, and does nothing else.

This is sufficient to get hierarchical domains working for GICv5 PPIs
(such as the one KVM introduces for the arch timer). It has the side
benefit (or drawback) that it will catch cases where the firmware
description doesn't match what the hardware reports.

Signed-off-by: Sascha Bischoff <sascha.bischoff@arm.com>
Link: https://patch.msgid.link/20260319154937.3619520-31-sascha.bischoff@arm.com
Signed-off-by: Marc Zyngier <maz@kernel.org>
drivers/irqchip/irq-gic-v5.c

index 405a5eee847b6a4a460bc071260c39d1f38e450c..6b0903be8ebfd3a05460410e813807623876c6d3 100644 (file)
@@ -511,6 +511,23 @@ static bool gicv5_ppi_irq_is_level(irq_hw_number_t hwirq)
        return !!(read_ppi_sysreg_s(hwirq, PPI_HM) & bit);
 }
 
+static int gicv5_ppi_irq_set_type(struct irq_data *d, unsigned int type)
+{
+       /*
+        * GICv5's PPIs do not have a configurable trigger or handling
+        * mode. Check that the attempt to set a type matches what the
+        * hardware reports in the HMR, and error on a mismatch.
+        */
+
+       if (type & IRQ_TYPE_EDGE_BOTH && gicv5_ppi_irq_is_level(d->hwirq))
+               return -EINVAL;
+
+       if (type & IRQ_TYPE_LEVEL_MASK && !gicv5_ppi_irq_is_level(d->hwirq))
+               return -EINVAL;
+
+       return 0;
+}
+
 static int gicv5_ppi_irq_set_vcpu_affinity(struct irq_data *d, void *vcpu)
 {
        if (vcpu)
@@ -526,6 +543,7 @@ static const struct irq_chip gicv5_ppi_irq_chip = {
        .irq_mask               = gicv5_ppi_irq_mask,
        .irq_unmask             = gicv5_ppi_irq_unmask,
        .irq_eoi                = gicv5_ppi_irq_eoi,
+       .irq_set_type           = gicv5_ppi_irq_set_type,
        .irq_get_irqchip_state  = gicv5_ppi_irq_get_irqchip_state,
        .irq_set_irqchip_state  = gicv5_ppi_irq_set_irqchip_state,
        .irq_set_vcpu_affinity  = gicv5_ppi_irq_set_vcpu_affinity,