Skip to content

Commit 28af690

Browse files
author
Marc Zyngier
committed
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 <[email protected]> Cc: Thomas Gleixner <[email protected]> Acked-by: David Brown <[email protected]> Tested-by: David Brown <[email protected]> Tested-by: Shawn Guo <[email protected]> Signed-off-by: Marc Zyngier <[email protected]>
1 parent 292b293 commit 28af690

File tree

8 files changed

+99
-111
lines changed

8 files changed

+99
-111
lines changed

arch/arm/common/gic.c

Lines changed: 0 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@
3535
#include <asm/irq.h>
3636
#include <asm/mach/irq.h>
3737
#include <asm/hardware/gic.h>
38-
#include <asm/localtimer.h>
3938

4039
static DEFINE_SPINLOCK(irq_controller_lock);
4140

@@ -259,32 +258,6 @@ void __init gic_cascade_irq(unsigned int gic_nr, unsigned int irq)
259258
irq_set_chained_handler(irq, gic_handle_cascade_irq);
260259
}
261260

262-
#ifdef CONFIG_LOCAL_TIMERS
263-
#define gic_ppi_handler percpu_timer_handler
264-
#else
265-
static irqreturn_t gic_ppi_handler(int irq, void *dev_id)
266-
{
267-
return IRQ_NONE;
268-
}
269-
#endif
270-
271-
#define PPI_IRQACT(nr) \
272-
{ \
273-
.handler = gic_ppi_handler, \
274-
.flags = IRQF_PERCPU | IRQF_TIMER, \
275-
.irq = nr, \
276-
.name = "PPI-" # nr, \
277-
}
278-
279-
static struct irqaction ppi_irqaction_template[16] __initdata = {
280-
PPI_IRQACT(0), PPI_IRQACT(1), PPI_IRQACT(2), PPI_IRQACT(3),
281-
PPI_IRQACT(4), PPI_IRQACT(5), PPI_IRQACT(6), PPI_IRQACT(7),
282-
PPI_IRQACT(8), PPI_IRQACT(9), PPI_IRQACT(10), PPI_IRQACT(11),
283-
PPI_IRQACT(12), PPI_IRQACT(13), PPI_IRQACT(14), PPI_IRQACT(15),
284-
};
285-
286-
static struct irqaction *ppi_irqaction;
287-
288261
static void __init gic_dist_init(struct gic_chip_data *gic,
289262
unsigned int irq_start)
290263
{
@@ -325,16 +298,6 @@ static void __init gic_dist_init(struct gic_chip_data *gic,
325298
BUG();
326299

327300
ppi_base = gic->irq_offset + 32 - nrppis;
328-
329-
ppi_irqaction = kmemdup(&ppi_irqaction_template[16 - nrppis],
330-
sizeof(*ppi_irqaction) * nrppis,
331-
GFP_KERNEL);
332-
333-
if (nrppis && !ppi_irqaction) {
334-
pr_err("GIC: Can't allocate PPI memory");
335-
nrppis = 0;
336-
ppi_base = 0;
337-
}
338301
}
339302

340303
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,
377340
*/
378341
for (i = 0; i < nrppis; i++) {
379342
int ppi = i + ppi_base;
380-
int err;
381343

382344
irq_set_percpu_devid(ppi);
383345
irq_set_chip_and_handler(ppi, &gic_chip,
384346
handle_percpu_devid_irq);
385347
irq_set_chip_data(ppi, gic);
386348
set_irq_flags(ppi, IRQF_VALID | IRQF_NOAUTOEN);
387-
388-
err = setup_percpu_irq(ppi, &ppi_irqaction[i]);
389-
if (err)
390-
pr_err("GIC: can't setup PPI%d (%d)\n", ppi, err);
391349
}
392350

393351
for (i = irq_start + nrppis; i < irq_limit; i++) {
@@ -448,16 +406,6 @@ void __cpuinit gic_secondary_init(unsigned int gic_nr)
448406
gic_cpu_init(&gic_data[gic_nr]);
449407
}
450408

451-
void __cpuinit gic_enable_ppi(unsigned int irq)
452-
{
453-
unsigned long flags;
454-
455-
local_irq_save(flags);
456-
irq_set_status_flags(irq, IRQ_NOPROBE);
457-
gic_unmask_irq(irq_get_irq_data(irq));
458-
local_irq_restore(flags);
459-
}
460-
461409
#ifdef CONFIG_SMP
462410
void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
463411
{

arch/arm/include/asm/hardware/gic.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,6 @@ void gic_init(unsigned int, unsigned int, void __iomem *, void __iomem *);
4040
void gic_secondary_init(unsigned int);
4141
void gic_cascade_irq(unsigned int gic_nr, unsigned int irq);
4242
void gic_raise_softirq(const struct cpumask *mask, unsigned int irq);
43-
void gic_enable_ppi(unsigned int);
4443

4544
struct gic_chip_data {
4645
unsigned int irq_offset;

arch/arm/include/asm/localtimer.h

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,26 +19,20 @@ struct clock_event_device;
1919
*/
2020
void percpu_timer_setup(void);
2121

22-
/*
23-
* Per-cpu timer IRQ handler
24-
*/
25-
irqreturn_t percpu_timer_handler(int irq, void *dev_id);
26-
2722
#ifdef CONFIG_LOCAL_TIMERS
2823

2924
#ifdef CONFIG_HAVE_ARM_TWD
3025

3126
#include "smp_twd.h"
3227

33-
#define local_timer_ack() twd_timer_ack()
28+
#define local_timer_stop(c) twd_timer_stop((c))
3429

3530
#else
3631

3732
/*
38-
* Platform provides this to acknowledge a local timer IRQ.
39-
* Returns true if the local timer IRQ is to be processed.
33+
* Stop the local timer
4034
*/
41-
int local_timer_ack(void);
35+
void local_timer_stop(struct clock_event_device *);
4236

4337
#endif
4438

@@ -53,6 +47,10 @@ static inline int local_timer_setup(struct clock_event_device *evt)
5347
{
5448
return -ENXIO;
5549
}
50+
51+
static inline void local_timer_stop(struct clock_event_device *evt)
52+
{
53+
}
5654
#endif
5755

5856
#endif

arch/arm/include/asm/smp_twd.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ struct clock_event_device;
2222

2323
extern void __iomem *twd_base;
2424

25-
int twd_timer_ack(void);
2625
void twd_timer_setup(struct clock_event_device *);
26+
void twd_timer_stop(struct clock_event_device *);
2727

2828
#endif

arch/arm/kernel/smp.c

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -473,20 +473,6 @@ static void ipi_timer(void)
473473
irq_exit();
474474
}
475475

476-
#ifdef CONFIG_LOCAL_TIMERS
477-
irqreturn_t percpu_timer_handler(int irq, void *dev_id)
478-
{
479-
struct clock_event_device *evt = &__get_cpu_var(percpu_clockevent);
480-
481-
if (local_timer_ack()) {
482-
evt->event_handler(evt);
483-
return IRQ_HANDLED;
484-
}
485-
486-
return IRQ_NONE;
487-
}
488-
#endif
489-
490476
#ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST
491477
static void smp_timer_broadcast(const struct cpumask *mask)
492478
{
@@ -537,7 +523,7 @@ static void percpu_timer_stop(void)
537523
unsigned int cpu = smp_processor_id();
538524
struct clock_event_device *evt = &per_cpu(percpu_clockevent, cpu);
539525

540-
evt->set_mode(CLOCK_EVT_MODE_UNUSED, evt);
526+
local_timer_stop(evt);
541527
}
542528
#endif
543529

arch/arm/kernel/smp_twd.c

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,16 @@
1919
#include <linux/io.h>
2020

2121
#include <asm/smp_twd.h>
22+
#include <asm/localtimer.h>
2223
#include <asm/hardware/gic.h>
2324

2425
/* set up by the platform code */
2526
void __iomem *twd_base;
2627

2728
static unsigned long twd_timer_rate;
2829

30+
static struct clock_event_device __percpu **twd_evt;
31+
2932
static void twd_set_mode(enum clock_event_mode mode,
3033
struct clock_event_device *clk)
3134
{
@@ -80,6 +83,12 @@ int twd_timer_ack(void)
8083
return 0;
8184
}
8285

86+
void twd_timer_stop(struct clock_event_device *clk)
87+
{
88+
twd_set_mode(CLOCK_EVT_MODE_UNUSED, clk);
89+
disable_percpu_irq(clk->irq);
90+
}
91+
8392
static void __cpuinit twd_calibrate_rate(void)
8493
{
8594
unsigned long count;
@@ -119,11 +128,43 @@ static void __cpuinit twd_calibrate_rate(void)
119128
}
120129
}
121130

131+
static irqreturn_t twd_handler(int irq, void *dev_id)
132+
{
133+
struct clock_event_device *evt = *(struct clock_event_device **)dev_id;
134+
135+
if (twd_timer_ack()) {
136+
evt->event_handler(evt);
137+
return IRQ_HANDLED;
138+
}
139+
140+
return IRQ_NONE;
141+
}
142+
122143
/*
123144
* Setup the local clock events for a CPU.
124145
*/
125146
void __cpuinit twd_timer_setup(struct clock_event_device *clk)
126147
{
148+
struct clock_event_device **this_cpu_clk;
149+
150+
if (!twd_evt) {
151+
int err;
152+
153+
twd_evt = alloc_percpu(struct clock_event_device *);
154+
if (!twd_evt) {
155+
pr_err("twd: can't allocate memory\n");
156+
return;
157+
}
158+
159+
err = request_percpu_irq(clk->irq, twd_handler,
160+
"twd", twd_evt);
161+
if (err) {
162+
pr_err("twd: can't register interrupt %d (%d)\n",
163+
clk->irq, err);
164+
return;
165+
}
166+
}
167+
127168
twd_calibrate_rate();
128169

129170
clk->name = "local_timer";
@@ -137,8 +178,10 @@ void __cpuinit twd_timer_setup(struct clock_event_device *clk)
137178
clk->max_delta_ns = clockevent_delta2ns(0xffffffff, clk);
138179
clk->min_delta_ns = clockevent_delta2ns(0xf, clk);
139180

181+
this_cpu_clk = __this_cpu_ptr(twd_evt);
182+
*this_cpu_clk = clk;
183+
140184
clockevents_register_device(clk);
141185

142-
/* Make sure our local interrupt controller has this enabled */
143-
gic_enable_ppi(clk->irq);
186+
enable_percpu_irq(clk->irq, 0);
144187
}

arch/arm/mach-exynos4/mct.c

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -380,9 +380,11 @@ static void exynos4_mct_tick_init(struct clock_event_device *evt)
380380

381381
if (cpu == 0) {
382382
mct_tick0_event_irq.dev_id = &mct_tick[cpu];
383+
evt->irq = IRQ_MCT_L0;
383384
setup_irq(IRQ_MCT_L0, &mct_tick0_event_irq);
384385
} else {
385386
mct_tick1_event_irq.dev_id = &mct_tick[cpu];
387+
evt->irq = IRQ_MCT_L1;
386388
setup_irq(IRQ_MCT_L1, &mct_tick1_event_irq);
387389
irq_set_affinity(IRQ_MCT_L1, cpumask_of(1));
388390
}
@@ -394,9 +396,10 @@ void __cpuinit local_timer_setup(struct clock_event_device *evt)
394396
exynos4_mct_tick_init(evt);
395397
}
396398

397-
int local_timer_ack(void)
399+
void local_timer_stop(struct clock_event_device *evt)
398400
{
399-
return 0;
401+
evt->set_mode(CLOCK_EVT_MODE_UNUSED, evt);
402+
disable_irq(evt->irq);
400403
}
401404

402405
#endif /* CONFIG_LOCAL_TIMERS */

0 commit comments

Comments
 (0)