Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

+88 -178
+74 -1
arch/arm/common/gic.c
··· 28 28 #include <linux/smp.h> 29 29 #include <linux/cpumask.h> 30 30 #include <linux/io.h> 31 + #include <linux/interrupt.h> 32 + #include <linux/percpu.h> 33 + #include <linux/slab.h> 31 34 32 35 #include <asm/irq.h> 33 36 #include <asm/mach/irq.h> 34 37 #include <asm/hardware/gic.h> 38 + #include <asm/localtimer.h> 35 39 36 40 static DEFINE_SPINLOCK(irq_controller_lock); 37 41 ··· 259 255 irq_set_chained_handler(irq, gic_handle_cascade_irq); 260 256 } 261 257 258 + #ifdef CONFIG_LOCAL_TIMERS 259 + #define gic_ppi_handler percpu_timer_handler 260 + #else 261 + static irqreturn_t gic_ppi_handler(int irq, void *dev_id) 262 + { 263 + return IRQ_NONE; 264 + } 265 + #endif 266 + 267 + #define PPI_IRQACT(nr) \ 268 + { \ 269 + .handler = gic_ppi_handler, \ 270 + .flags = IRQF_PERCPU | IRQF_TIMER, \ 271 + .irq = nr, \ 272 + .name = "PPI-" # nr, \ 273 + } 274 + 275 + static struct irqaction ppi_irqaction_template[16] __initdata = { 276 + PPI_IRQACT(0), PPI_IRQACT(1), PPI_IRQACT(2), PPI_IRQACT(3), 277 + PPI_IRQACT(4), PPI_IRQACT(5), PPI_IRQACT(6), PPI_IRQACT(7), 278 + PPI_IRQACT(8), PPI_IRQACT(9), PPI_IRQACT(10), PPI_IRQACT(11), 279 + PPI_IRQACT(12), PPI_IRQACT(13), PPI_IRQACT(14), PPI_IRQACT(15), 280 + }; 281 + 282 + static struct irqaction *ppi_irqaction; 283 + 262 284 static void __init gic_dist_init(struct gic_chip_data *gic, 263 285 unsigned int irq_start) 264 286 { ··· 292 262 u32 cpumask; 293 263 void __iomem *base = gic->dist_base; 294 264 u32 cpu = 0; 265 + u32 nrppis = 0, ppi_base = 0; 295 266 296 267 #ifdef CONFIG_SMP 297 268 cpu = cpu_logical_map(smp_processor_id()); ··· 312 281 gic_irqs = (gic_irqs + 1) * 32; 313 282 if (gic_irqs > 1020) 314 283 gic_irqs = 1020; 284 + 285 + /* 286 + * Nobody would be insane enough to use PPIs on a secondary 287 + * GIC, right? 288 + */ 289 + if (gic == &gic_data[0]) { 290 + nrppis = (32 - irq_start) & 31; 291 + 292 + /* The GIC only supports up to 16 PPIs. */ 293 + if (nrppis > 16) 294 + BUG(); 295 + 296 + ppi_base = gic->irq_offset + 32 - nrppis; 297 + 298 + ppi_irqaction = kmemdup(&ppi_irqaction_template[16 - nrppis], 299 + sizeof(*ppi_irqaction) * nrppis, 300 + GFP_KERNEL); 301 + 302 + if (nrppis && !ppi_irqaction) { 303 + pr_err("GIC: Can't allocate PPI memory"); 304 + nrppis = 0; 305 + ppi_base = 0; 306 + } 307 + } 308 + 309 + pr_info("Configuring GIC with %d sources (%d PPIs)\n", 310 + gic_irqs, (gic == &gic_data[0]) ? nrppis : 0); 315 311 316 312 /* 317 313 * Set all global interrupts to be level triggered, active low. ··· 375 317 /* 376 318 * Setup the Linux IRQ subsystem. 377 319 */ 378 - for (i = irq_start; i < irq_limit; i++) { 320 + for (i = 0; i < nrppis; i++) { 321 + int ppi = i + ppi_base; 322 + int err; 323 + 324 + irq_set_percpu_devid(ppi); 325 + irq_set_chip_and_handler(ppi, &gic_chip, 326 + handle_percpu_devid_irq); 327 + irq_set_chip_data(ppi, gic); 328 + set_irq_flags(ppi, IRQF_VALID | IRQF_NOAUTOEN); 329 + 330 + err = setup_percpu_irq(ppi, &ppi_irqaction[i]); 331 + if (err) 332 + pr_err("GIC: can't setup PPI%d (%d)\n", ppi, err); 333 + } 334 + 335 + for (i = irq_start + nrppis; i < irq_limit; i++) { 379 336 irq_set_chip_and_handler(i, &gic_chip, handle_fasteoi_irq); 380 337 irq_set_chip_data(i, gic); 381 338 set_irq_flags(i, IRQF_VALID | IRQF_PROBE);
-7
arch/arm/include/asm/entry-macro-multi.S
··· 25 25 movne r1, sp 26 26 adrne lr, BSYM(1b) 27 27 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 35 28 #endif 36 29 9997: 37 30 .endm
-3
arch/arm/include/asm/hardirq.h
··· 9 9 10 10 typedef struct { 11 11 unsigned int __softirq_pending; 12 - #ifdef CONFIG_LOCAL_TIMERS 13 - unsigned int local_timer_irqs; 14 - #endif 15 12 #ifdef CONFIG_SMP 16 13 unsigned int ipi_irqs[NR_IPI]; 17 14 #endif
+2 -17
arch/arm/include/asm/hardware/entry-macro-gic.S
··· 22 22 * interrupt controller spec. To wit: 23 23 * 24 24 * 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. 27 26 * 32-1020 are global 28 27 * 1021-1022 are reserved 29 28 * 1023 is "spurious" (no interrupt) 30 - * 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 29 * 34 30 * A simple read from the controller will tell us the number of the highest 35 31 * priority enabled interrupt. We then just need to check whether it is in the ··· 39 43 40 44 ldr \tmp, =1021 41 45 bic \irqnr, \irqstat, #0x1c00 42 - cmp \irqnr, #29 46 + cmp \irqnr, #15 43 47 cmpcc \irqnr, \irqnr 44 48 cmpne \irqnr, \tmp 45 49 cmpcs \irqnr, \irqnr ··· 57 61 cmp \irqnr, #16 58 62 strcc \irqstat, [\base, #GIC_CPU_EOI] 59 63 cmpcs \irqnr, \irqnr 60 - .endm 61 - 62 - /* As above, this assumes that irqstat and base are preserved.. */ 63 - 64 - .macro test_for_ltirq, irqnr, irqstat, base, tmp 65 - bic \irqnr, \irqstat, #0x1c00 66 - mov \tmp, #0 67 - cmp \irqnr, #29 68 - moveq \tmp, #1 69 - streq \irqstat, [\base, #GIC_CPU_EOI] 70 - cmp \tmp, #0 71 64 .endm
+4 -7
arch/arm/include/asm/localtimer.h
··· 10 10 #ifndef __ASM_ARM_LOCALTIMER_H 11 11 #define __ASM_ARM_LOCALTIMER_H 12 12 13 + #include <linux/interrupt.h> 14 + 13 15 struct clock_event_device; 14 16 15 17 /* ··· 20 18 void percpu_timer_setup(void); 21 19 22 20 /* 23 - * Called from assembly, this is the local timer IRQ handler 21 + * Per-cpu timer IRQ handler 24 22 */ 25 - asmlinkage void do_local_timer(struct pt_regs *); 26 - 27 - /* 28 - * Called from C code 29 - */ 30 - void handle_local_timer(struct pt_regs *); 23 + irqreturn_t percpu_timer_handler(int irq, void *dev_id); 31 24 32 25 #ifdef CONFIG_LOCAL_TIMERS 33 26
-5
arch/arm/include/asm/smp.h
··· 99 99 extern void arch_send_call_function_single_ipi(int cpu); 100 100 extern void arch_send_call_function_ipi_mask(const struct cpumask *mask); 101 101 102 - /* 103 - * show local interrupt info 104 - */ 105 - extern void show_local_irqs(struct seq_file *, int); 106 - 107 102 #endif /* ifndef __ASM_ARM_SMP_H */
-3
arch/arm/kernel/irq.c
··· 59 59 #ifdef CONFIG_SMP 60 60 show_ipi_list(p, prec); 61 61 #endif 62 - #ifdef CONFIG_LOCAL_TIMERS 63 - show_local_irqs(p, prec); 64 - #endif 65 62 seq_printf(p, "%*s: %10lu\n", prec, "Err", irq_err_count); 66 63 return 0; 67 64 }
+5 -27
arch/arm/kernel/smp.c
··· 457 457 for (i = 0; i < NR_IPI; i++) 458 458 sum += __get_irq_stat(cpu, ipi_irqs[i]); 459 459 460 - #ifdef CONFIG_LOCAL_TIMERS 461 - sum += __get_irq_stat(cpu, local_timer_irqs); 462 - #endif 463 - 464 460 return sum; 465 461 } 466 462 ··· 474 478 } 475 479 476 480 #ifdef CONFIG_LOCAL_TIMERS 477 - asmlinkage void __exception_irq_entry do_local_timer(struct pt_regs *regs) 481 + irqreturn_t percpu_timer_handler(int irq, void *dev_id) 478 482 { 479 - handle_local_timer(regs); 480 - } 481 - 482 - void handle_local_timer(struct pt_regs *regs) 483 - { 484 - struct pt_regs *old_regs = set_irq_regs(regs); 485 - int cpu = smp_processor_id(); 483 + struct clock_event_device *evt = &__get_cpu_var(percpu_clockevent); 486 484 487 485 if (local_timer_ack()) { 488 - __inc_irq_stat(cpu, local_timer_irqs); 489 - ipi_timer(); 486 + evt->event_handler(evt); 487 + return IRQ_HANDLED; 490 488 } 491 489 492 - set_irq_regs(old_regs); 493 - } 494 - 495 - void show_local_irqs(struct seq_file *p, int prec) 496 - { 497 - unsigned int cpu; 498 - 499 - seq_printf(p, "%*s: ", prec, "LOC"); 500 - 501 - for_each_present_cpu(cpu) 502 - seq_printf(p, "%10u ", __get_irq_stat(cpu, local_timer_irqs)); 503 - 504 - seq_printf(p, " Local timer interrupts\n"); 490 + return IRQ_NONE; 505 491 } 506 492 #endif 507 493
+1 -6
arch/arm/mach-exynos4/include/mach/entry-macro.S
··· 55 55 56 56 bic \irqnr, \irqstat, #0x1c00 57 57 58 - cmp \irqnr, #29 58 + cmp \irqnr, #15 59 59 cmpcc \irqnr, \irqnr 60 60 cmpne \irqnr, \tmp 61 61 cmpcs \irqnr, \irqnr ··· 75 75 cmp \irqnr, #16 76 76 strcc \irqstat, [\base, #GIC_CPU_EOI] 77 77 cmpcs \irqnr, \irqnr 78 - .endm 79 - 80 - /* As above, this assumes that irqstat and base are preserved.. */ 81 - 82 - .macro test_for_ltirq, irqnr, irqstat, base, tmp 83 78 .endm
-11
arch/arm/mach-msm/board-msm8x60.c
··· 36 36 37 37 static void __init msm8x60_init_irq(void) 38 38 { 39 - unsigned int i; 40 - 41 39 gic_init(0, GIC_PPI_START, MSM_QGIC_DIST_BASE, 42 40 (void *)MSM_QGIC_CPU_BASE); 43 41 ··· 47 49 */ 48 50 if (!machine_is_msm8x60_sim()) 49 51 writel(0x0000FFFF, MSM_QGIC_DIST_BASE + GIC_DIST_ENABLE_SET); 50 - 51 - /* FIXME: Not installing AVS_SVICINT and AVS_SVICINTSWDONE yet 52 - * as they are configured as level, which does not play nice with 53 - * handle_percpu_irq. 54 - */ 55 - for (i = GIC_PPI_START; i < GIC_SPI_START; i++) { 56 - if (i != AVS_SVICINT && i != AVS_SVICINTSWDONE) 57 - irq_set_handler(i, handle_percpu_irq); 58 - } 59 52 } 60 53 61 54 static void __init msm8x60_init(void)
+1 -72
arch/arm/mach-msm/include/mach/entry-macro-qgic.S
··· 8 8 * warranty of any kind, whether express or implied. 9 9 */ 10 10 11 - #include <mach/hardware.h> 12 - #include <asm/hardware/gic.h> 11 + #include <asm/hardware/entry-macro-gic.S> 13 12 14 13 .macro disable_fiq 15 14 .endm 16 15 17 - .macro get_irqnr_preamble, base, tmp 18 - ldr \base, =gic_cpu_base_addr 19 - ldr \base, [\base] 20 - .endm 21 - 22 16 .macro arch_ret_to_user, tmp1, tmp2 23 - .endm 24 - 25 - /* 26 - * The interrupt numbering scheme is defined in the 27 - * interrupt controller spec. To wit: 28 - * 29 - * Migrated the code from ARM MP port to be more consistent 30 - * with interrupt processing , the following still holds true 31 - * however, all interrupts are treated the same regardless of 32 - * if they are local IPI or PPI 33 - * 34 - * Interrupts 0-15 are IPI 35 - * 16-31 are PPI 36 - * (16-18 are the timers) 37 - * 32-1020 are global 38 - * 1021-1022 are reserved 39 - * 1023 is "spurious" (no interrupt) 40 - * 41 - * A simple read from the controller will tell us the number of the 42 - * highest priority enabled interrupt. We then just need to check 43 - * whether it is in the valid range for an IRQ (0-1020 inclusive). 44 - * 45 - * Base ARM code assumes that the local (private) peripheral interrupts 46 - * are not valid, we treat them differently, in that the privates are 47 - * handled like normal shared interrupts with the exception that only 48 - * one processor can register the interrupt and the handler must be 49 - * the same for all processors. 50 - */ 51 - 52 - .macro get_irqnr_and_base, irqnr, irqstat, base, tmp 53 - 54 - ldr \irqstat, [\base, #GIC_CPU_INTACK] /* bits 12-10 =srcCPU, 55 - 9-0 =int # */ 56 - 57 - bic \irqnr, \irqstat, #0x1c00 @mask src 58 - cmp \irqnr, #15 59 - ldr \tmp, =1021 60 - cmpcc \irqnr, \irqnr 61 - cmpne \irqnr, \tmp 62 - cmpcs \irqnr, \irqnr 63 - 64 - .endm 65 - 66 - /* We assume that irqstat (the raw value of the IRQ acknowledge 67 - * register) is preserved from the macro above. 68 - * If there is an IPI, we immediately signal end of interrupt on the 69 - * controller, since this requires the original irqstat value which 70 - * we won't easily be able to recreate later. 71 - */ 72 - .macro test_for_ipi, irqnr, irqstat, base, tmp 73 - bic \irqnr, \irqstat, #0x1c00 74 - cmp \irqnr, #16 75 - strcc \irqstat, [\base, #GIC_CPU_EOI] 76 - cmpcs \irqnr, \irqnr 77 - .endm 78 - 79 - /* As above, this assumes that irqstat and base are preserved.. */ 80 - 81 - .macro test_for_ltirq, irqnr, irqstat, base, tmp 82 - bic \irqnr, \irqstat, #0x1c00 83 - mov \tmp, #0 84 - cmp \irqnr, #16 85 - moveq \tmp, #1 86 - streq \irqstat, [\base, #GIC_CPU_EOI] 87 - cmp \tmp, #0 88 17 .endm
+1 -13
arch/arm/mach-omap2/include/mach/entry-macro.S
··· 78 78 4401: ldr \irqstat, [\base, #GIC_CPU_INTACK] 79 79 ldr \tmp, =1021 80 80 bic \irqnr, \irqstat, #0x1c00 81 - cmp \irqnr, #29 81 + cmp \irqnr, #15 82 82 cmpcc \irqnr, \irqnr 83 83 cmpne \irqnr, \tmp 84 84 cmpcs \irqnr, \irqnr ··· 100 100 strcc \irqstat, [\base, #GIC_CPU_EOI] 101 101 it cs 102 102 cmpcs \irqnr, \irqnr 103 - .endm 104 - 105 - /* As above, this assumes that irqstat and base are preserved */ 106 - 107 - .macro test_for_ltirq, irqnr, irqstat, base, tmp 108 - bic \irqnr, \irqstat, #0x1c00 109 - mov \tmp, #0 110 - cmp \irqnr, #29 111 - itt eq 112 - moveq \tmp, #1 113 - streq \irqstat, [\base, #GIC_CPU_EOI] 114 - cmp \tmp, #0 115 103 .endm 116 104 #endif /* CONFIG_SMP */ 117 105
-3
arch/arm/mach-shmobile/entry-intc.S
··· 51 51 .macro test_for_ipi, irqnr, irqstat, base, tmp 52 52 .endm 53 53 54 - .macro test_for_ltirq, irqnr, irqstat, base, tmp 55 - .endm 56 - 57 54 arch_irq_handler shmobile_handle_irq_intc
-3
arch/arm/mach-shmobile/include/mach/entry-macro.S
··· 27 27 .macro test_for_ipi, irqnr, irqstat, base, tmp 28 28 .endm 29 29 30 - .macro test_for_ltirq, irqnr, irqstat, base, tmp 31 - .endm 32 - 33 30 .macro arch_ret_to_user, tmp1, tmp2 34 31 .endm