ARM: gic: consolidate PPI handling
authorMarc Zyngier <marc.zyngier@arm.com>
Wed, 20 Jul 2011 15:24:14 +0000 (16:24 +0100)
committerMarc Zyngier <marc.zyngier@arm.com>
Sun, 23 Oct 2011 12:32:29 +0000 (13:32 +0100)
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>
14 files changed:
arch/arm/common/gic.c
arch/arm/include/asm/entry-macro-multi.S
arch/arm/include/asm/hardirq.h
arch/arm/include/asm/hardware/entry-macro-gic.S
arch/arm/include/asm/localtimer.h
arch/arm/include/asm/smp.h
arch/arm/kernel/irq.c
arch/arm/kernel/smp.c
arch/arm/mach-exynos4/include/mach/entry-macro.S
arch/arm/mach-msm/board-msm8x60.c
arch/arm/mach-msm/include/mach/entry-macro-qgic.S
arch/arm/mach-omap2/include/mach/entry-macro.S
arch/arm/mach-shmobile/entry-intc.S
arch/arm/mach-shmobile/include/mach/entry-macro.S

index 666b278e56d7c6bf4610e05f0afd25de06646944..bbea0168779b8892488179e203c8f3fc2e14b6b4 100644 (file)
 #include <linux/smp.h>
 #include <linux/cpumask.h>
 #include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/percpu.h>
+#include <linux/slab.h>
 
 #include <asm/irq.h>
 #include <asm/mach/irq.h>
 #include <asm/hardware/gic.h>
+#include <asm/localtimer.h>
 
 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);
 }
 
+#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,
        unsigned int irq_start)
 {
@@ -262,6 +292,7 @@ static void __init gic_dist_init(struct gic_chip_data *gic,
        u32 cpumask;
        void __iomem *base = gic->dist_base;
        u32 cpu = 0;
+       u32 nrppis = 0, ppi_base = 0;
 
 #ifdef CONFIG_SMP
        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)
                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.
         */
@@ -317,7 +375,22 @@ static void __init gic_dist_init(struct gic_chip_data *gic,
        /*
         * 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_data(i, gic);
                set_irq_flags(i, IRQF_VALID | IRQF_PROBE);
index 2f1e2098dfe778211e9209ea0285e089020e5745..88d61815f0c03caceaa94af319687b6dbd6913ce 100644 (file)
        movne   r1, sp
        adrne   lr, BSYM(1b)
        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
 9997:
        .endm
index 89ad1805e5797625a2d5df0912253bcd9e2a9f5f..ddf07a92a6c8484029927aa51fa09816ce38c337 100644 (file)
@@ -9,9 +9,6 @@
 
 typedef struct {
        unsigned int __softirq_pending;
-#ifdef CONFIG_LOCAL_TIMERS
-       unsigned int local_timer_irqs;
-#endif
 #ifdef CONFIG_SMP
        unsigned int ipi_irqs[NR_IPI];
 #endif
index c115b82fe80a4ce8807b0de04b9c53d647c9aa12..74ebc803904d7cd9df4b348c895ac3787a27d410 100644 (file)
  * interrupt controller spec.  To wit:
  *
  * Interrupts 0-15 are IPI
- * 16-28 are reserved
- * 29-31 are local.  We allow 30 to be used for the watchdog.
+ * 16-31 are local.  We allow 30 to be used for the watchdog.
  * 32-1020 are global
  * 1021-1022 are reserved
  * 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
  * priority enabled interrupt.  We then just need to check whether it is in the
  * valid range for an IRQ (30-1020 inclusive).
@@ -43,7 +39,7 @@
 
        ldr     \tmp, =1021
        bic     \irqnr, \irqstat, #0x1c00
-       cmp     \irqnr, #29
+       cmp     \irqnr, #15
        cmpcc   \irqnr, \irqnr
        cmpne   \irqnr, \tmp
        cmpcs   \irqnr, \irqnr
        strcc   \irqstat, [\base, #GIC_CPU_EOI]
        cmpcs   \irqnr, \irqnr
        .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
index 3306f281333c36760f36654752943526e7ce9339..5c8acb4c4040c3493d3b6623c50fbaac0928c8d5 100644 (file)
@@ -10,6 +10,8 @@
 #ifndef __ASM_ARM_LOCALTIMER_H
 #define __ASM_ARM_LOCALTIMER_H
 
+#include <linux/interrupt.h>
+
 struct clock_event_device;
 
 /*
@@ -18,14 +20,9 @@ struct clock_event_device;
 void percpu_timer_setup(void);
 
 /*
- * Called from assembly, this is the local timer IRQ handler
- */
-asmlinkage void do_local_timer(struct pt_regs *);
-
-/*
- * Called from C code
+ * Per-cpu timer IRQ handler
  */
-void handle_local_timer(struct pt_regs *);
+irqreturn_t percpu_timer_handler(int irq, void *dev_id);
 
 #ifdef CONFIG_LOCAL_TIMERS
 
index 0a17b62538c2705b0a959f18d67ad4f75aa90990..1e5717afc4ac007e94447cf91ab88bdee9f7f1ad 100644 (file)
@@ -99,9 +99,4 @@ extern void platform_cpu_enable(unsigned int cpu);
 extern void arch_send_call_function_single_ipi(int cpu);
 extern void arch_send_call_function_ipi_mask(const struct cpumask *mask);
 
-/*
- * show local interrupt info
- */
-extern void show_local_irqs(struct seq_file *, int);
-
 #endif /* ifndef __ASM_ARM_SMP_H */
index 53919b230e8ba45bbaa431c408b9a6c354fe3cd7..7cb29261249af0c74157fd362d15827723ee1715 100644 (file)
@@ -58,9 +58,6 @@ int arch_show_interrupts(struct seq_file *p, int prec)
 #endif
 #ifdef CONFIG_SMP
        show_ipi_list(p, prec);
-#endif
-#ifdef CONFIG_LOCAL_TIMERS
-       show_local_irqs(p, prec);
 #endif
        seq_printf(p, "%*s: %10lu\n", prec, "Err", irq_err_count);
        return 0;
index 35417d0fb8abdf5a5a173012597b750f15edae97..917ed2fa4e4c4a909cbf7fc7d2853ed41e25b461 100644 (file)
@@ -457,10 +457,6 @@ u64 smp_irq_stat_cpu(unsigned int cpu)
        for (i = 0; i < NR_IPI; i++)
                sum += __get_irq_stat(cpu, ipi_irqs[i]);
 
-#ifdef CONFIG_LOCAL_TIMERS
-       sum += __get_irq_stat(cpu, local_timer_irqs);
-#endif
-
        return sum;
 }
 
@@ -478,34 +474,16 @@ static void ipi_timer(void)
 }
 
 #ifdef CONFIG_LOCAL_TIMERS
-asmlinkage void __exception_irq_entry do_local_timer(struct pt_regs *regs)
-{
-       handle_local_timer(regs);
-}
-
-void handle_local_timer(struct pt_regs *regs)
+irqreturn_t percpu_timer_handler(int irq, void *dev_id)
 {
-       struct pt_regs *old_regs = set_irq_regs(regs);
-       int cpu = smp_processor_id();
+       struct clock_event_device *evt = &__get_cpu_var(percpu_clockevent);
 
        if (local_timer_ack()) {
-               __inc_irq_stat(cpu, local_timer_irqs);
-               ipi_timer();
+               evt->event_handler(evt);
+               return IRQ_HANDLED;
        }
 
-       set_irq_regs(old_regs);
-}
-
-void show_local_irqs(struct seq_file *p, int prec)
-{
-       unsigned int cpu;
-
-       seq_printf(p, "%*s: ", prec, "LOC");
-
-       for_each_present_cpu(cpu)
-               seq_printf(p, "%10u ", __get_irq_stat(cpu, local_timer_irqs));
-
-       seq_printf(p, " Local timer interrupts\n");
+       return IRQ_NONE;
 }
 #endif
 
index d7a1e281ce7a98f437b65da2f33328b1629b5458..006a4f4c65c62fa21cf3d67a1e99cc39197efa2e 100644 (file)
@@ -55,7 +55,7 @@
 
                bic     \irqnr, \irqstat, #0x1c00
 
-               cmp     \irqnr, #29
+               cmp     \irqnr, #15
                cmpcc   \irqnr, \irqnr
                cmpne   \irqnr, \tmp
                cmpcs   \irqnr, \irqnr
@@ -76,8 +76,3 @@
                strcc   \irqstat, [\base, #GIC_CPU_EOI]
                cmpcs   \irqnr, \irqnr
                .endm
-
-               /* As above, this assumes that irqstat and base are preserved.. */
-
-               .macro test_for_ltirq, irqnr, irqstat, base, tmp
-               .endm
index 1163b6fd05d2ceb71ae21b5b3bef550a65ba3ca6..d70a2f64361399d576e8b2f53a18c6f997734354 100644 (file)
@@ -36,8 +36,6 @@ static void __init msm8x60_map_io(void)
 
 static void __init msm8x60_init_irq(void)
 {
-       unsigned int i;
-
        gic_init(0, GIC_PPI_START, MSM_QGIC_DIST_BASE,
                 (void *)MSM_QGIC_CPU_BASE);
 
@@ -49,15 +47,6 @@ static void __init msm8x60_init_irq(void)
         */
        if (!machine_is_msm8x60_sim())
                writel(0x0000FFFF, MSM_QGIC_DIST_BASE + GIC_DIST_ENABLE_SET);
-
-       /* FIXME: Not installing AVS_SVICINT and AVS_SVICINTSWDONE yet
-        * as they are configured as level, which does not play nice with
-        * handle_percpu_irq.
-        */
-       for (i = GIC_PPI_START; i < GIC_SPI_START; i++) {
-               if (i != AVS_SVICINT && i != AVS_SVICINTSWDONE)
-                       irq_set_handler(i, handle_percpu_irq);
-       }
 }
 
 static void __init msm8x60_init(void)
index 12467157afb99f905ac10c8c559af06a37b6e0f7..717076f3ca73586a1c9482f8fba0b7031c7ad18f 100644 (file)
@@ -8,81 +8,10 @@
  * warranty of any kind, whether express or implied.
  */
 
-#include <mach/hardware.h>
-#include <asm/hardware/gic.h>
+#include <asm/hardware/entry-macro-gic.S>
 
        .macro  disable_fiq
        .endm
 
-       .macro  get_irqnr_preamble, base, tmp
-       ldr     \base, =gic_cpu_base_addr
-       ldr     \base, [\base]
-       .endm
-
        .macro  arch_ret_to_user, tmp1, tmp2
        .endm
-
-       /*
-        * The interrupt numbering scheme is defined in the
-        * interrupt controller spec.  To wit:
-        *
-        * Migrated the code from ARM MP port to be more consistent
-        * with interrupt processing , the following still holds true
-        * however, all interrupts are treated the same regardless of
-        * if they are local IPI or PPI
-        *
-        * Interrupts 0-15 are IPI
-        * 16-31 are PPI
-        *   (16-18 are the timers)
-        * 32-1020 are global
-        * 1021-1022 are reserved
-        * 1023 is "spurious" (no interrupt)
-        *
-        * 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 valid range for an IRQ (0-1020 inclusive).
-        *
-        * Base ARM code assumes that the local (private) peripheral interrupts
-        * are not valid, we treat them differently, in that the privates are
-        * handled like normal shared interrupts with the exception that only
-        * one processor can register the interrupt and the handler must be
-        * the same for all processors.
-        */
-
-       .macro  get_irqnr_and_base, irqnr, irqstat, base, tmp
-
-       ldr  \irqstat, [\base, #GIC_CPU_INTACK] /* bits 12-10 =srcCPU,
-                                                  9-0 =int # */
-
-       bic     \irqnr, \irqstat, #0x1c00       @mask src
-       cmp     \irqnr, #15
-       ldr             \tmp, =1021
-       cmpcc   \irqnr, \irqnr
-       cmpne   \irqnr, \tmp
-       cmpcs   \irqnr, \irqnr
-
-       .endm
-
-       /* We assume that irqstat (the raw value of the IRQ acknowledge
-        * register) is preserved from the macro above.
-        * If there is an IPI, we immediately signal end of interrupt on the
-        * controller, since this requires the original irqstat value which
-        * we won't easily be able to recreate later.
-        */
-       .macro test_for_ipi, irqnr, irqstat, base, tmp
-    bic \irqnr, \irqstat, #0x1c00
-    cmp \irqnr, #16
-    strcc   \irqstat, [\base, #GIC_CPU_EOI]
-    cmpcs   \irqnr, \irqnr
-       .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, #16
-    moveq   \tmp, #1
-    streq   \irqstat, [\base, #GIC_CPU_EOI]
-    cmp \tmp, #0
-       .endm
index ceb8b7e593d7f162285d043c0106944b311fbff5..feb90a10945af23348d59e7a88a413b98ce18b4a 100644 (file)
@@ -78,7 +78,7 @@
 4401:          ldr     \irqstat, [\base, #GIC_CPU_INTACK]
                ldr     \tmp, =1021
                bic     \irqnr, \irqstat, #0x1c00
-               cmp     \irqnr, #29
+               cmp     \irqnr, #15
                cmpcc   \irqnr, \irqnr
                cmpne   \irqnr, \tmp
                cmpcs   \irqnr, \irqnr
                it      cs
                cmpcs   \irqnr, \irqnr
                .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
-               itt     eq
-               moveq   \tmp, #1
-               streq   \irqstat, [\base, #GIC_CPU_EOI]
-               cmp     \tmp, #0
-               .endm
 #endif /* CONFIG_SMP */
 
 #else  /* MULTI_OMAP2 */
index cac0a7ae2084a06b27c3c5cec85aeee4871171bb..1a1c00ca39a2527b56c7a7103cc66f890483c98a 100644 (file)
@@ -51,7 +51,4 @@
        .macro  test_for_ipi, irqnr, irqstat, base, tmp
        .endm
 
-       .macro  test_for_ltirq, irqnr, irqstat, base, tmp
-       .endm
-
        arch_irq_handler shmobile_handle_irq_intc
index d791f10eeac7ee4e26f1a072e7769d3e0a149b22..8d4a416d42859f87a3a4d4bef1209e3b15588145 100644 (file)
@@ -27,8 +27,5 @@
        .macro  test_for_ipi, irqnr, irqstat, base, tmp
        .endm
 
-       .macro  test_for_ltirq, irqnr, irqstat, base, tmp
-       .endm
-
        .macro  arch_ret_to_user, tmp1, tmp2
        .endm