SGI interrupts are a convenient way for trusted firmware to target a specific set of CPUs. Update the ARM GIC code to allow the translation and mapping of SGI interrupts. Since the kernel already uses SGIs for various inter-processor interrupt activities, we specifically make sure that we do not let users of the IRQ API to even try to map those. Internal IPIs remain dispatched through handle_IPI() while public SGIs get promoted to a normal interrupt flow management. Signed-off-by: Florian Fainelli <f.fainelli@xxxxxxxxx> --- drivers/irqchip/irq-gic.c | 41 +++++++++++++++++++++++++++------------ 1 file changed, 29 insertions(+), 12 deletions(-) diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c index 30ab623343d3..dcfdbaacdd64 100644 --- a/drivers/irqchip/irq-gic.c +++ b/drivers/irqchip/irq-gic.c @@ -385,7 +385,10 @@ static void __exception_irq_entry gic_handle_irq(struct pt_regs *regs) * Pairs with the write barrier in gic_raise_softirq */ smp_rmb(); - handle_IPI(irqnr, regs); + if (irqnr < NR_IPI) + handle_IPI(irqnr, regs); + else + handle_domain_irq(gic->domain, irqnr, regs); #endif continue; } @@ -1005,20 +1008,34 @@ static int gic_irq_domain_translate(struct irq_domain *d, if (fwspec->param_count < 3) return -EINVAL; - /* Get the interrupt number and add 16 to skip over SGIs */ - *hwirq = fwspec->param[1] + 16; - - /* - * For SPIs, we need to add 16 more to get the GIC irq - * ID number - */ - if (!fwspec->param[0]) + *hwirq = fwspec->param[1]; + switch (fwspec->param[0]) { + case 0: + /* + * For SPIs, we need to add 16 more to get the GIC irq + * ID number + */ + *hwirq += 16; + /* fall through */ + case 1: + /* Add 16 to skip over SGIs */ *hwirq += 16; + *type = fwspec->param[2] & IRQ_TYPE_SENSE_MASK; - *type = fwspec->param[2] & IRQ_TYPE_SENSE_MASK; + /* Make it clear that broken DTs are... broken */ + WARN_ON(*type == IRQ_TYPE_NONE); + break; + case 2: + /* Refuse to map internal IPIs */ + if (*hwirq < NR_IPI) + return -EPERM; + + *type = IRQ_TYPE_NONE; + break; + default: + break; + } - /* Make it clear that broken DTs are... broken */ - WARN_ON(*type == IRQ_TYPE_NONE); return 0; } -- 2.17.1