ARM: gic: consolidate PPI handling
PPI handling is a bit of an odd beast. It uses its own low level handling code and is hardwired to the local timers (hence lacking a registration interface). Instead, switch the low handling to the normal SPI handling code. PPIs are handled by the handle_percpu_devid_irq flow. This also allows the removal of some duplicated code. Cc: Kukjin Kim <kgene.kim@samsung.com> Cc: David Brown <davidb@codeaurora.org> Cc: Bryan Huntsman <bryanh@codeaurora.org> Cc: Tony Lindgren <tony@atomide.com> Cc: Paul Mundt <lethal@linux-sh.org> Cc: Magnus Damm <magnus.damm@gmail.com> Cc: Thomas Gleixner <tglx@linutronix.de> Acked-by: David Brown <davidb@codeaurora.org> Tested-by: David Brown <davidb@codeaurora.org> Tested-by: Shawn Guo <shawn.guo@linaro.org> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
This commit is contained in:
@@ -28,10 +28,14 @@
|
||||
#include <linux/smp.h>
|
||||
#include <linux/cpumask.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/percpu.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include <asm/irq.h>
|
||||
#include <asm/mach/irq.h>
|
||||
#include <asm/hardware/gic.h>
|
||||
#include <asm/localtimer.h>
|
||||
|
||||
static DEFINE_SPINLOCK(irq_controller_lock);
|
||||
|
||||
@@ -255,6 +259,32 @@ void __init gic_cascade_irq(unsigned int gic_nr, unsigned int irq)
|
||||
irq_set_chained_handler(irq, gic_handle_cascade_irq);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_LOCAL_TIMERS
|
||||
#define gic_ppi_handler percpu_timer_handler
|
||||
#else
|
||||
static irqreturn_t gic_ppi_handler(int irq, void *dev_id)
|
||||
{
|
||||
return IRQ_NONE;
|
||||
}
|
||||
#endif
|
||||
|
||||
#define PPI_IRQACT(nr) \
|
||||
{ \
|
||||
.handler = gic_ppi_handler, \
|
||||
.flags = IRQF_PERCPU | IRQF_TIMER, \
|
||||
.irq = nr, \
|
||||
.name = "PPI-" # nr, \
|
||||
}
|
||||
|
||||
static struct irqaction ppi_irqaction_template[16] __initdata = {
|
||||
PPI_IRQACT(0), PPI_IRQACT(1), PPI_IRQACT(2), PPI_IRQACT(3),
|
||||
PPI_IRQACT(4), PPI_IRQACT(5), PPI_IRQACT(6), PPI_IRQACT(7),
|
||||
PPI_IRQACT(8), PPI_IRQACT(9), PPI_IRQACT(10), PPI_IRQACT(11),
|
||||
PPI_IRQACT(12), PPI_IRQACT(13), PPI_IRQACT(14), PPI_IRQACT(15),
|
||||
};
|
||||
|
||||
static struct irqaction *ppi_irqaction;
|
||||
|
||||
static void __init gic_dist_init(struct gic_chip_data *gic,
|
||||
unsigned int irq_start)
|
||||
{
|
||||
@@ -262,6 +292,7 @@ static void __init gic_dist_init(struct gic_chip_data *gic,
|
||||
u32 cpumask;
|
||||
void __iomem *base = gic->dist_base;
|
||||
u32 cpu = 0;
|
||||
u32 nrppis = 0, ppi_base = 0;
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
cpu = cpu_logical_map(smp_processor_id());
|
||||
@@ -282,6 +313,33 @@ static void __init gic_dist_init(struct gic_chip_data *gic,
|
||||
if (gic_irqs > 1020)
|
||||
gic_irqs = 1020;
|
||||
|
||||
/*
|
||||
* Nobody would be insane enough to use PPIs on a secondary
|
||||
* GIC, right?
|
||||
*/
|
||||
if (gic == &gic_data[0]) {
|
||||
nrppis = (32 - irq_start) & 31;
|
||||
|
||||
/* The GIC only supports up to 16 PPIs. */
|
||||
if (nrppis > 16)
|
||||
BUG();
|
||||
|
||||
ppi_base = gic->irq_offset + 32 - nrppis;
|
||||
|
||||
ppi_irqaction = kmemdup(&ppi_irqaction_template[16 - nrppis],
|
||||
sizeof(*ppi_irqaction) * nrppis,
|
||||
GFP_KERNEL);
|
||||
|
||||
if (nrppis && !ppi_irqaction) {
|
||||
pr_err("GIC: Can't allocate PPI memory");
|
||||
nrppis = 0;
|
||||
ppi_base = 0;
|
||||
}
|
||||
}
|
||||
|
||||
pr_info("Configuring GIC with %d sources (%d PPIs)\n",
|
||||
gic_irqs, (gic == &gic_data[0]) ? nrppis : 0);
|
||||
|
||||
/*
|
||||
* Set all global interrupts to be level triggered, active low.
|
||||
*/
|
||||
@@ -317,7 +375,22 @@ static void __init gic_dist_init(struct gic_chip_data *gic,
|
||||
/*
|
||||
* Setup the Linux IRQ subsystem.
|
||||
*/
|
||||
for (i = irq_start; i < irq_limit; i++) {
|
||||
for (i = 0; i < nrppis; i++) {
|
||||
int ppi = i + ppi_base;
|
||||
int err;
|
||||
|
||||
irq_set_percpu_devid(ppi);
|
||||
irq_set_chip_and_handler(ppi, &gic_chip,
|
||||
handle_percpu_devid_irq);
|
||||
irq_set_chip_data(ppi, gic);
|
||||
set_irq_flags(ppi, IRQF_VALID | IRQF_NOAUTOEN);
|
||||
|
||||
err = setup_percpu_irq(ppi, &ppi_irqaction[i]);
|
||||
if (err)
|
||||
pr_err("GIC: can't setup PPI%d (%d)\n", ppi, err);
|
||||
}
|
||||
|
||||
for (i = irq_start + nrppis; i < irq_limit; i++) {
|
||||
irq_set_chip_and_handler(i, &gic_chip, handle_fasteoi_irq);
|
||||
irq_set_chip_data(i, gic);
|
||||
set_irq_flags(i, IRQF_VALID | IRQF_PROBE);
|
||||
|
Reference in New Issue
Block a user