Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

irqchip/mips-gic: Separate IPI reservation & usage tracking

Since commit 2af70a962070 ("irqchip/mips-gic: Add a IPI hierarchy
domain") introduced the GIC IPI IRQ domain we have tracked both
reservation of interrupts & their use with a single bitmap - ipi_resrv.
If an interrupt is reserved for use as an IPI but not actually in use
then the appropriate bit is set in ipi_resrv. If an interrupt is either
not reserved for use as an IPI or has been allocated as one then the
appropriate bit is clear in ipi_resrv.

Unfortunately this means that checking whether a bit is set in ipi_resrv
to prevent IPI interrupts being allocated for use with a device is
broken, because if the interrupt has been allocated as an IPI first then
its bit will be clear.

Fix this by separating the tracking of IPI reservation & usage,
introducing a separate ipi_available bitmap for the latter. This means
that ipi_resrv will now always have bits set corresponding to all
interrupts reserved for use as IPIs, whether or not they have been
allocated yet, and therefore that checking it when allocating device
interrupts works as expected.

Fixes: 2af70a962070 ("irqchip/mips-gic: Add a IPI hierarchy domain")
Signed-off-by: Paul Burton <paul.burton@imgtec.com>
Signed-off-by: Matt Redfearn <matt.redfearn@imgtec.com>
Cc: linux-mips@linux-mips.org
Cc: Jason Cooper <jason@lakedaemon.net>
Cc: Marc Zyngier <marc.zyngier@arm.com>
Cc: Ralf Baechle <ralf@linux-mips.org>
Link: http://lkml.kernel.org/r/1492679256-14513-2-git-send-email-matt.redfearn@imgtec.com
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>

authored by

Paul Burton and committed by
Thomas Gleixner
f8dcd9e8 7a258ff0

+7 -5
+7 -5
drivers/irqchip/irq-mips-gic.c
··· 55 55 static unsigned int timer_cpu_pin; 56 56 static struct irq_chip gic_level_irq_controller, gic_edge_irq_controller; 57 57 DECLARE_BITMAP(ipi_resrv, GIC_MAX_INTRS); 58 + DECLARE_BITMAP(ipi_available, GIC_MAX_INTRS); 58 59 59 60 static void __gic_irq_dispatch(void); 60 61 ··· 747 746 748 747 return gic_setup_dev_chip(d, virq, spec->hwirq); 749 748 } else { 750 - base_hwirq = find_first_bit(ipi_resrv, gic_shared_intrs); 749 + base_hwirq = find_first_bit(ipi_available, gic_shared_intrs); 751 750 if (base_hwirq == gic_shared_intrs) { 752 751 return -ENOMEM; 753 752 } 754 753 755 754 /* check that we have enough space */ 756 755 for (i = base_hwirq; i < nr_irqs; i++) { 757 - if (!test_bit(i, ipi_resrv)) 756 + if (!test_bit(i, ipi_available)) 758 757 return -EBUSY; 759 758 } 760 - bitmap_clear(ipi_resrv, base_hwirq, nr_irqs); 759 + bitmap_clear(ipi_available, base_hwirq, nr_irqs); 761 760 762 761 /* map the hwirq for each cpu consecutively */ 763 762 i = 0; ··· 788 787 789 788 return 0; 790 789 error: 791 - bitmap_set(ipi_resrv, base_hwirq, nr_irqs); 790 + bitmap_set(ipi_available, base_hwirq, nr_irqs); 792 791 return ret; 793 792 } 794 793 ··· 803 802 return; 804 803 805 804 base_hwirq = GIC_HWIRQ_TO_SHARED(irqd_to_hwirq(data)); 806 - bitmap_set(ipi_resrv, base_hwirq, nr_irqs); 805 + bitmap_set(ipi_available, base_hwirq, nr_irqs); 807 806 } 808 807 809 808 int gic_irq_domain_match(struct irq_domain *d, struct device_node *node, ··· 1099 1098 2 * gic_vpes); 1100 1099 } 1101 1100 1101 + bitmap_copy(ipi_available, ipi_resrv, GIC_MAX_INTRS); 1102 1102 gic_basic_init(); 1103 1103 gic_map_interrupts(node); 1104 1104 }