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

Commit 28af690a authored by Marc Zyngier's avatar Marc Zyngier
Browse files

ARM: gic, local timers: use the request_percpu_irq() interface



This patch remove the hardcoded link between local timers and PPIs,
and convert the PPI users (TWD, MCT and MSM timers) to the new
*_percpu_irq interface. Also some collateral cleanup
(local_timer_ack() is gone, and the interrupt handler is strictly
private to each driver).

PPIs are now useable for more than just the local timers.

Additional testing by David Brown (msm8250 and msm8660) and
Shawn Guo (imx6q).

Cc: David Brown <davidb@codeaurora.org>
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 292b293c
Loading
Loading
Loading
Loading
+0 −52
Original line number Original line Diff line number Diff line
@@ -35,7 +35,6 @@
#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);


@@ -259,32 +258,6 @@ 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)
{
{
@@ -325,16 +298,6 @@ static void __init gic_dist_init(struct gic_chip_data *gic,
			BUG();
			BUG();


		ppi_base = gic->irq_offset + 32 - nrppis;
		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",
	pr_info("Configuring GIC with %d sources (%d PPIs)\n",
@@ -377,17 +340,12 @@ static void __init gic_dist_init(struct gic_chip_data *gic,
	 */
	 */
	for (i = 0; i < nrppis; i++) {
	for (i = 0; i < nrppis; i++) {
		int ppi = i + ppi_base;
		int ppi = i + ppi_base;
		int err;


		irq_set_percpu_devid(ppi);
		irq_set_percpu_devid(ppi);
		irq_set_chip_and_handler(ppi, &gic_chip,
		irq_set_chip_and_handler(ppi, &gic_chip,
					 handle_percpu_devid_irq);
					 handle_percpu_devid_irq);
		irq_set_chip_data(ppi, gic);
		irq_set_chip_data(ppi, gic);
		set_irq_flags(ppi, IRQF_VALID | IRQF_NOAUTOEN);
		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++) {
	for (i = irq_start + nrppis; i < irq_limit; i++) {
@@ -448,16 +406,6 @@ void __cpuinit gic_secondary_init(unsigned int gic_nr)
	gic_cpu_init(&gic_data[gic_nr]);
	gic_cpu_init(&gic_data[gic_nr]);
}
}


void __cpuinit gic_enable_ppi(unsigned int irq)
{
	unsigned long flags;

	local_irq_save(flags);
	irq_set_status_flags(irq, IRQ_NOPROBE);
	gic_unmask_irq(irq_get_irq_data(irq));
	local_irq_restore(flags);
}

#ifdef CONFIG_SMP
#ifdef CONFIG_SMP
void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
{
{
+0 −1
Original line number Original line Diff line number Diff line
@@ -40,7 +40,6 @@ void gic_init(unsigned int, unsigned int, void __iomem *, void __iomem *);
void gic_secondary_init(unsigned int);
void gic_secondary_init(unsigned int);
void gic_cascade_irq(unsigned int gic_nr, unsigned int irq);
void gic_cascade_irq(unsigned int gic_nr, unsigned int irq);
void gic_raise_softirq(const struct cpumask *mask, unsigned int irq);
void gic_raise_softirq(const struct cpumask *mask, unsigned int irq);
void gic_enable_ppi(unsigned int);


struct gic_chip_data {
struct gic_chip_data {
	unsigned int irq_offset;
	unsigned int irq_offset;
+7 −9
Original line number Original line Diff line number Diff line
@@ -19,26 +19,20 @@ struct clock_event_device;
 */
 */
void percpu_timer_setup(void);
void percpu_timer_setup(void);


/*
 * Per-cpu timer IRQ handler
 */
irqreturn_t percpu_timer_handler(int irq, void *dev_id);

#ifdef CONFIG_LOCAL_TIMERS
#ifdef CONFIG_LOCAL_TIMERS


#ifdef CONFIG_HAVE_ARM_TWD
#ifdef CONFIG_HAVE_ARM_TWD


#include "smp_twd.h"
#include "smp_twd.h"


#define local_timer_ack()	twd_timer_ack()
#define local_timer_stop(c)	twd_timer_stop((c))


#else
#else


/*
/*
 * Platform provides this to acknowledge a local timer IRQ.
 * Stop the local timer
 * Returns true if the local timer IRQ is to be processed.
 */
 */
int local_timer_ack(void);
void local_timer_stop(struct clock_event_device *);


#endif
#endif


@@ -53,6 +47,10 @@ static inline int local_timer_setup(struct clock_event_device *evt)
{
{
	return -ENXIO;
	return -ENXIO;
}
}

static inline void local_timer_stop(struct clock_event_device *evt)
{
}
#endif
#endif


#endif
#endif
+1 −1
Original line number Original line Diff line number Diff line
@@ -22,7 +22,7 @@ struct clock_event_device;


extern void __iomem *twd_base;
extern void __iomem *twd_base;


int twd_timer_ack(void);
void twd_timer_setup(struct clock_event_device *);
void twd_timer_setup(struct clock_event_device *);
void twd_timer_stop(struct clock_event_device *);


#endif
#endif
+1 −15
Original line number Original line Diff line number Diff line
@@ -473,20 +473,6 @@ static void ipi_timer(void)
	irq_exit();
	irq_exit();
}
}


#ifdef CONFIG_LOCAL_TIMERS
irqreturn_t percpu_timer_handler(int irq, void *dev_id)
{
	struct clock_event_device *evt = &__get_cpu_var(percpu_clockevent);

	if (local_timer_ack()) {
		evt->event_handler(evt);
		return IRQ_HANDLED;
	}

	return IRQ_NONE;
}
#endif

#ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST
#ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST
static void smp_timer_broadcast(const struct cpumask *mask)
static void smp_timer_broadcast(const struct cpumask *mask)
{
{
@@ -537,7 +523,7 @@ static void percpu_timer_stop(void)
	unsigned int cpu = smp_processor_id();
	unsigned int cpu = smp_processor_id();
	struct clock_event_device *evt = &per_cpu(percpu_clockevent, cpu);
	struct clock_event_device *evt = &per_cpu(percpu_clockevent, cpu);


	evt->set_mode(CLOCK_EVT_MODE_UNUSED, evt);
	local_timer_stop(evt);
}
}
#endif
#endif


Loading