summaryrefslogtreecommitdiffstats
path: root/drivers/irqchip
diff options
context:
space:
mode:
authorPaul Burton <paul.burton@imgtec.com>2017-04-20 10:07:34 +0100
committerThomas Gleixner <tglx@linutronix.de>2017-04-20 16:07:02 +0200
commitf8dcd9e81797ae24acc44c84f0eb3b9e6cee9791 (patch)
tree89df0c729832d39902784dc5bc8e4ddfd0930259 /drivers/irqchip
parent7a258ff04f9d5fe549fed6d03931a0236587047e (diff)
downloadlinux-f8dcd9e81797ae24acc44c84f0eb3b9e6cee9791.tar.bz2
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>
Diffstat (limited to 'drivers/irqchip')
-rw-r--r--drivers/irqchip/irq-mips-gic.c12
1 files changed, 7 insertions, 5 deletions
diff --git a/drivers/irqchip/irq-mips-gic.c b/drivers/irqchip/irq-mips-gic.c
index cd20df12d63d..db058e10df00 100644
--- a/drivers/irqchip/irq-mips-gic.c
+++ b/drivers/irqchip/irq-mips-gic.c
@@ -55,6 +55,7 @@ static unsigned int gic_cpu_pin;
static unsigned int timer_cpu_pin;
static struct irq_chip gic_level_irq_controller, gic_edge_irq_controller;
DECLARE_BITMAP(ipi_resrv, GIC_MAX_INTRS);
+DECLARE_BITMAP(ipi_available, GIC_MAX_INTRS);
static void __gic_irq_dispatch(void);
@@ -746,17 +747,17 @@ static int gic_irq_domain_alloc(struct irq_domain *d, unsigned int virq,
return gic_setup_dev_chip(d, virq, spec->hwirq);
} else {
- base_hwirq = find_first_bit(ipi_resrv, gic_shared_intrs);
+ base_hwirq = find_first_bit(ipi_available, gic_shared_intrs);
if (base_hwirq == gic_shared_intrs) {
return -ENOMEM;
}
/* check that we have enough space */
for (i = base_hwirq; i < nr_irqs; i++) {
- if (!test_bit(i, ipi_resrv))
+ if (!test_bit(i, ipi_available))
return -EBUSY;
}
- bitmap_clear(ipi_resrv, base_hwirq, nr_irqs);
+ bitmap_clear(ipi_available, base_hwirq, nr_irqs);
/* map the hwirq for each cpu consecutively */
i = 0;
@@ -787,7 +788,7 @@ static int gic_irq_domain_alloc(struct irq_domain *d, unsigned int virq,
return 0;
error:
- bitmap_set(ipi_resrv, base_hwirq, nr_irqs);
+ bitmap_set(ipi_available, base_hwirq, nr_irqs);
return ret;
}
@@ -802,7 +803,7 @@ void gic_irq_domain_free(struct irq_domain *d, unsigned int virq,
return;
base_hwirq = GIC_HWIRQ_TO_SHARED(irqd_to_hwirq(data));
- bitmap_set(ipi_resrv, base_hwirq, nr_irqs);
+ bitmap_set(ipi_available, base_hwirq, nr_irqs);
}
int gic_irq_domain_match(struct irq_domain *d, struct device_node *node,
@@ -1098,6 +1099,7 @@ static void __init __gic_init(unsigned long gic_base_addr,
2 * gic_vpes);
}
+ bitmap_copy(ipi_available, ipi_resrv, GIC_MAX_INTRS);
gic_basic_init();
gic_map_interrupts(node);
}