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:
Marc Zyngier
2011-07-20 16:24:14 +01:00
parent 88b6fc8c57
commit 292b293cee
14 changed files with 88 additions and 178 deletions

View File

@@ -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);