Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 292b293c authored by Marc Zyngier's avatar Marc Zyngier
Browse files

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: default avatarDavid Brown <davidb@codeaurora.org>
Tested-by: default avatarDavid Brown <davidb@codeaurora.org>
Tested-by: default avatarShawn Guo <shawn.guo@linaro.org>
Signed-off-by: default avatarMarc Zyngier <marc.zyngier@arm.com>
parent 88b6fc8c
Loading
Loading
Loading
Loading
+74 −1
Original line number Original line Diff line number Diff line
@@ -28,10 +28,14 @@
#include <linux/smp.h>
#include <linux/smp.h>
#include <linux/cpumask.h>
#include <linux/cpumask.h>
#include <linux/io.h>
#include <linux/io.h>
#include <linux/interrupt.h>
#include <linux/percpu.h>
#include <linux/slab.h>


#include <asm/irq.h>
#include <asm/irq.h>
#include <asm/mach/irq.h>
#include <asm/mach/irq.h>
#include <asm/hardware/gic.h>
#include <asm/hardware/gic.h>
#include <asm/localtimer.h>


static DEFINE_SPINLOCK(irq_controller_lock);
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);
	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,
static void __init gic_dist_init(struct gic_chip_data *gic,
	unsigned int irq_start)
	unsigned int irq_start)
{
{
@@ -262,6 +292,7 @@ static void __init gic_dist_init(struct gic_chip_data *gic,
	u32 cpumask;
	u32 cpumask;
	void __iomem *base = gic->dist_base;
	void __iomem *base = gic->dist_base;
	u32 cpu = 0;
	u32 cpu = 0;
	u32 nrppis = 0, ppi_base = 0;


#ifdef CONFIG_SMP
#ifdef CONFIG_SMP
	cpu = cpu_logical_map(smp_processor_id());
	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)
	if (gic_irqs > 1020)
		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.
	 * 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.
	 * 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_and_handler(i, &gic_chip, handle_fasteoi_irq);
		irq_set_chip_data(i, gic);
		irq_set_chip_data(i, gic);
		set_irq_flags(i, IRQF_VALID | IRQF_PROBE);
		set_irq_flags(i, IRQF_VALID | IRQF_PROBE);
+0 −7
Original line number Original line Diff line number Diff line
@@ -25,13 +25,6 @@
	movne	r1, sp
	movne	r1, sp
	adrne	lr, BSYM(1b)
	adrne	lr, BSYM(1b)
	bne	do_IPI
	bne	do_IPI

#ifdef CONFIG_LOCAL_TIMERS
	test_for_ltirq r0, r2, r6, lr
	movne	r0, sp
	adrne	lr, BSYM(1b)
	bne	do_local_timer
#endif
#endif
#endif
9997:
9997:
	.endm
	.endm
+0 −3
Original line number Original line Diff line number Diff line
@@ -9,9 +9,6 @@


typedef struct {
typedef struct {
	unsigned int __softirq_pending;
	unsigned int __softirq_pending;
#ifdef CONFIG_LOCAL_TIMERS
	unsigned int local_timer_irqs;
#endif
#ifdef CONFIG_SMP
#ifdef CONFIG_SMP
	unsigned int ipi_irqs[NR_IPI];
	unsigned int ipi_irqs[NR_IPI];
#endif
#endif
+2 −17
Original line number Original line Diff line number Diff line
@@ -22,15 +22,11 @@
 * interrupt controller spec.  To wit:
 * interrupt controller spec.  To wit:
 *
 *
 * Interrupts 0-15 are IPI
 * Interrupts 0-15 are IPI
 * 16-28 are reserved
 * 16-31 are local.  We allow 30 to be used for the watchdog.
 * 29-31 are local.  We allow 30 to be used for the watchdog.
 * 32-1020 are global
 * 32-1020 are global
 * 1021-1022 are reserved
 * 1021-1022 are reserved
 * 1023 is "spurious" (no interrupt)
 * 1023 is "spurious" (no interrupt)
 *
 *
 * For now, we ignore all local interrupts so only return an interrupt if it's
 * between 30 and 1020.  The test_for_ipi routine below will pick up on IPIs.
 *
 * A simple read from the controller will tell us the number of the highest
 * A simple read from the controller will tell us the number of the highest
 * priority enabled interrupt.  We then just need to check whether it is in the
 * priority enabled interrupt.  We then just need to check whether it is in the
 * valid range for an IRQ (30-1020 inclusive).
 * valid range for an IRQ (30-1020 inclusive).
@@ -43,7 +39,7 @@


	ldr	\tmp, =1021
	ldr	\tmp, =1021
	bic     \irqnr, \irqstat, #0x1c00
	bic     \irqnr, \irqstat, #0x1c00
	cmp     \irqnr, #29
	cmp     \irqnr, #15
	cmpcc	\irqnr, \irqnr
	cmpcc	\irqnr, \irqnr
	cmpne	\irqnr, \tmp
	cmpne	\irqnr, \tmp
	cmpcs	\irqnr, \irqnr
	cmpcs	\irqnr, \irqnr
@@ -62,14 +58,3 @@
	strcc	\irqstat, [\base, #GIC_CPU_EOI]
	strcc	\irqstat, [\base, #GIC_CPU_EOI]
	cmpcs	\irqnr, \irqnr
	cmpcs	\irqnr, \irqnr
	.endm
	.endm

/* As above, this assumes that irqstat and base are preserved.. */

	.macro test_for_ltirq, irqnr, irqstat, base, tmp
	bic	\irqnr, \irqstat, #0x1c00
	mov 	\tmp, #0
	cmp	\irqnr, #29
	moveq	\tmp, #1
	streq	\irqstat, [\base, #GIC_CPU_EOI]
	cmp	\tmp, #0
	.endm
+4 −7
Original line number Original line Diff line number Diff line
@@ -10,6 +10,8 @@
#ifndef __ASM_ARM_LOCALTIMER_H
#ifndef __ASM_ARM_LOCALTIMER_H
#define __ASM_ARM_LOCALTIMER_H
#define __ASM_ARM_LOCALTIMER_H


#include <linux/interrupt.h>

struct clock_event_device;
struct clock_event_device;


/*
/*
@@ -18,14 +20,9 @@ struct clock_event_device;
void percpu_timer_setup(void);
void percpu_timer_setup(void);


/*
/*
 * Called from assembly, this is the local timer IRQ handler
 * Per-cpu timer IRQ handler
 */
asmlinkage void do_local_timer(struct pt_regs *);

/*
 * Called from C code
 */
 */
void handle_local_timer(struct pt_regs *);
irqreturn_t percpu_timer_handler(int irq, void *dev_id);


#ifdef CONFIG_LOCAL_TIMERS
#ifdef CONFIG_LOCAL_TIMERS


Loading