Skip to content

Commit 292b293

Browse files
author
Marc Zyngier
committed
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 <[email protected]> Cc: David Brown <[email protected]> Cc: Bryan Huntsman <[email protected]> Cc: Tony Lindgren <[email protected]> Cc: Paul Mundt <[email protected]> Cc: Magnus Damm <[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 88b6fc8 commit 292b293

File tree

14 files changed

+88
-178
lines changed

14 files changed

+88
-178
lines changed

arch/arm/common/gic.c

Lines changed: 74 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,14 @@
2828
#include <linux/smp.h>
2929
#include <linux/cpumask.h>
3030
#include <linux/io.h>
31+
#include <linux/interrupt.h>
32+
#include <linux/percpu.h>
33+
#include <linux/slab.h>
3134

3235
#include <asm/irq.h>
3336
#include <asm/mach/irq.h>
3437
#include <asm/hardware/gic.h>
38+
#include <asm/localtimer.h>
3539

3640
static DEFINE_SPINLOCK(irq_controller_lock);
3741

@@ -255,13 +259,40 @@ void __init gic_cascade_irq(unsigned int gic_nr, unsigned int irq)
255259
irq_set_chained_handler(irq, gic_handle_cascade_irq);
256260
}
257261

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+
258288
static void __init gic_dist_init(struct gic_chip_data *gic,
259289
unsigned int irq_start)
260290
{
261291
unsigned int gic_irqs, irq_limit, i;
262292
u32 cpumask;
263293
void __iomem *base = gic->dist_base;
264294
u32 cpu = 0;
295+
u32 nrppis = 0, ppi_base = 0;
265296

266297
#ifdef CONFIG_SMP
267298
cpu = cpu_logical_map(smp_processor_id());
@@ -282,6 +313,33 @@ static void __init gic_dist_init(struct gic_chip_data *gic,
282313
if (gic_irqs > 1020)
283314
gic_irqs = 1020;
284315

316+
/*
317+
* Nobody would be insane enough to use PPIs on a secondary
318+
* GIC, right?
319+
*/
320+
if (gic == &gic_data[0]) {
321+
nrppis = (32 - irq_start) & 31;
322+
323+
/* The GIC only supports up to 16 PPIs. */
324+
if (nrppis > 16)
325+
BUG();
326+
327+
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+
}
338+
}
339+
340+
pr_info("Configuring GIC with %d sources (%d PPIs)\n",
341+
gic_irqs, (gic == &gic_data[0]) ? nrppis : 0);
342+
285343
/*
286344
* Set all global interrupts to be level triggered, active low.
287345
*/
@@ -317,7 +375,22 @@ static void __init gic_dist_init(struct gic_chip_data *gic,
317375
/*
318376
* Setup the Linux IRQ subsystem.
319377
*/
320-
for (i = irq_start; i < irq_limit; i++) {
378+
for (i = 0; i < nrppis; i++) {
379+
int ppi = i + ppi_base;
380+
int err;
381+
382+
irq_set_percpu_devid(ppi);
383+
irq_set_chip_and_handler(ppi, &gic_chip,
384+
handle_percpu_devid_irq);
385+
irq_set_chip_data(ppi, gic);
386+
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);
391+
}
392+
393+
for (i = irq_start + nrppis; i < irq_limit; i++) {
321394
irq_set_chip_and_handler(i, &gic_chip, handle_fasteoi_irq);
322395
irq_set_chip_data(i, gic);
323396
set_irq_flags(i, IRQF_VALID | IRQF_PROBE);

arch/arm/include/asm/entry-macro-multi.S

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,6 @@
2525
movne r1, sp
2626
adrne lr, BSYM(1b)
2727
bne do_IPI
28-
29-
#ifdef CONFIG_LOCAL_TIMERS
30-
test_for_ltirq r0, r2, r6, lr
31-
movne r0, sp
32-
adrne lr, BSYM(1b)
33-
bne do_local_timer
34-
#endif
3528
#endif
3629
9997:
3730
.endm

arch/arm/include/asm/hardirq.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,6 @@
99

1010
typedef struct {
1111
unsigned int __softirq_pending;
12-
#ifdef CONFIG_LOCAL_TIMERS
13-
unsigned int local_timer_irqs;
14-
#endif
1512
#ifdef CONFIG_SMP
1613
unsigned int ipi_irqs[NR_IPI];
1714
#endif

arch/arm/include/asm/hardware/entry-macro-gic.S

Lines changed: 2 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -22,15 +22,11 @@
2222
* interrupt controller spec. To wit:
2323
*
2424
* Interrupts 0-15 are IPI
25-
* 16-28 are reserved
26-
* 29-31 are local. We allow 30 to be used for the watchdog.
25+
* 16-31 are local. We allow 30 to be used for the watchdog.
2726
* 32-1020 are global
2827
* 1021-1022 are reserved
2928
* 1023 is "spurious" (no interrupt)
3029
*
31-
* For now, we ignore all local interrupts so only return an interrupt if it's
32-
* between 30 and 1020. The test_for_ipi routine below will pick up on IPIs.
33-
*
3430
* A simple read from the controller will tell us the number of the highest
3531
* priority enabled interrupt. We then just need to check whether it is in the
3632
* valid range for an IRQ (30-1020 inclusive).
@@ -43,7 +39,7 @@
4339

4440
ldr \tmp, =1021
4541
bic \irqnr, \irqstat, #0x1c00
46-
cmp \irqnr, #29
42+
cmp \irqnr, #15
4743
cmpcc \irqnr, \irqnr
4844
cmpne \irqnr, \tmp
4945
cmpcs \irqnr, \irqnr
@@ -62,14 +58,3 @@
6258
strcc \irqstat, [\base, #GIC_CPU_EOI]
6359
cmpcs \irqnr, \irqnr
6460
.endm
65-
66-
/* As above, this assumes that irqstat and base are preserved.. */
67-
68-
.macro test_for_ltirq, irqnr, irqstat, base, tmp
69-
bic \irqnr, \irqstat, #0x1c00
70-
mov \tmp, #0
71-
cmp \irqnr, #29
72-
moveq \tmp, #1
73-
streq \irqstat, [\base, #GIC_CPU_EOI]
74-
cmp \tmp, #0
75-
.endm

arch/arm/include/asm/localtimer.h

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
#ifndef __ASM_ARM_LOCALTIMER_H
1111
#define __ASM_ARM_LOCALTIMER_H
1212

13+
#include <linux/interrupt.h>
14+
1315
struct clock_event_device;
1416

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

2022
/*
21-
* Called from assembly, this is the local timer IRQ handler
22-
*/
23-
asmlinkage void do_local_timer(struct pt_regs *);
24-
25-
/*
26-
* Called from C code
23+
* Per-cpu timer IRQ handler
2724
*/
28-
void handle_local_timer(struct pt_regs *);
25+
irqreturn_t percpu_timer_handler(int irq, void *dev_id);
2926

3027
#ifdef CONFIG_LOCAL_TIMERS
3128

arch/arm/include/asm/smp.h

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -99,9 +99,4 @@ extern void platform_cpu_enable(unsigned int cpu);
9999
extern void arch_send_call_function_single_ipi(int cpu);
100100
extern void arch_send_call_function_ipi_mask(const struct cpumask *mask);
101101

102-
/*
103-
* show local interrupt info
104-
*/
105-
extern void show_local_irqs(struct seq_file *, int);
106-
107102
#endif /* ifndef __ASM_ARM_SMP_H */

arch/arm/kernel/irq.c

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,9 +58,6 @@ int arch_show_interrupts(struct seq_file *p, int prec)
5858
#endif
5959
#ifdef CONFIG_SMP
6060
show_ipi_list(p, prec);
61-
#endif
62-
#ifdef CONFIG_LOCAL_TIMERS
63-
show_local_irqs(p, prec);
6461
#endif
6562
seq_printf(p, "%*s: %10lu\n", prec, "Err", irq_err_count);
6663
return 0;

arch/arm/kernel/smp.c

Lines changed: 5 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -457,10 +457,6 @@ u64 smp_irq_stat_cpu(unsigned int cpu)
457457
for (i = 0; i < NR_IPI; i++)
458458
sum += __get_irq_stat(cpu, ipi_irqs[i]);
459459

460-
#ifdef CONFIG_LOCAL_TIMERS
461-
sum += __get_irq_stat(cpu, local_timer_irqs);
462-
#endif
463-
464460
return sum;
465461
}
466462

@@ -478,34 +474,16 @@ static void ipi_timer(void)
478474
}
479475

480476
#ifdef CONFIG_LOCAL_TIMERS
481-
asmlinkage void __exception_irq_entry do_local_timer(struct pt_regs *regs)
482-
{
483-
handle_local_timer(regs);
484-
}
485-
486-
void handle_local_timer(struct pt_regs *regs)
477+
irqreturn_t percpu_timer_handler(int irq, void *dev_id)
487478
{
488-
struct pt_regs *old_regs = set_irq_regs(regs);
489-
int cpu = smp_processor_id();
479+
struct clock_event_device *evt = &__get_cpu_var(percpu_clockevent);
490480

491481
if (local_timer_ack()) {
492-
__inc_irq_stat(cpu, local_timer_irqs);
493-
ipi_timer();
482+
evt->event_handler(evt);
483+
return IRQ_HANDLED;
494484
}
495485

496-
set_irq_regs(old_regs);
497-
}
498-
499-
void show_local_irqs(struct seq_file *p, int prec)
500-
{
501-
unsigned int cpu;
502-
503-
seq_printf(p, "%*s: ", prec, "LOC");
504-
505-
for_each_present_cpu(cpu)
506-
seq_printf(p, "%10u ", __get_irq_stat(cpu, local_timer_irqs));
507-
508-
seq_printf(p, " Local timer interrupts\n");
486+
return IRQ_NONE;
509487
}
510488
#endif
511489

arch/arm/mach-exynos4/include/mach/entry-macro.S

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@
5555

5656
bic \irqnr, \irqstat, #0x1c00
5757

58-
cmp \irqnr, #29
58+
cmp \irqnr, #15
5959
cmpcc \irqnr, \irqnr
6060
cmpne \irqnr, \tmp
6161
cmpcs \irqnr, \irqnr
@@ -76,8 +76,3 @@
7676
strcc \irqstat, [\base, #GIC_CPU_EOI]
7777
cmpcs \irqnr, \irqnr
7878
.endm
79-
80-
/* As above, this assumes that irqstat and base are preserved.. */
81-
82-
.macro test_for_ltirq, irqnr, irqstat, base, tmp
83-
.endm

arch/arm/mach-msm/board-msm8x60.c

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,6 @@ static void __init msm8x60_map_io(void)
3636

3737
static void __init msm8x60_init_irq(void)
3838
{
39-
unsigned int i;
40-
4139
gic_init(0, GIC_PPI_START, MSM_QGIC_DIST_BASE,
4240
(void *)MSM_QGIC_CPU_BASE);
4341

@@ -49,15 +47,6 @@ static void __init msm8x60_init_irq(void)
4947
*/
5048
if (!machine_is_msm8x60_sim())
5149
writel(0x0000FFFF, MSM_QGIC_DIST_BASE + GIC_DIST_ENABLE_SET);
52-
53-
/* FIXME: Not installing AVS_SVICINT and AVS_SVICINTSWDONE yet
54-
* as they are configured as level, which does not play nice with
55-
* handle_percpu_irq.
56-
*/
57-
for (i = GIC_PPI_START; i < GIC_SPI_START; i++) {
58-
if (i != AVS_SVICINT && i != AVS_SVICINTSWDONE)
59-
irq_set_handler(i, handle_percpu_irq);
60-
}
6150
}
6251

6352
static void __init msm8x60_init(void)

0 commit comments

Comments
 (0)