Merge branch 'ppi-irq-core-for-rmk' of git://github.com/mzyngier/arm-platforms into...
[deliverable/linux.git] / arch / arm / common / gic.c
index 734db99eaee768bb060ac684fd6cff19d33b1472..016c1aeb847c5c5aa2cfd092ced53e2c8e017c39 100644 (file)
@@ -29,6 +29,9 @@
 #include <linux/cpu_pm.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>
@@ -181,7 +184,7 @@ static int gic_set_affinity(struct irq_data *d, const struct cpumask *mask_val,
                return -EINVAL;
 
        mask = 0xff << shift;
-       bit = 1 << (cpu + shift);
+       bit = 1 << (cpu_logical_map(cpu) + shift);
 
        spin_lock(&irq_controller_lock);
        val = readl_relaxed(reg) & ~mask;
@@ -260,9 +263,16 @@ static void __init gic_dist_init(struct gic_chip_data *gic,
        unsigned int irq_start)
 {
        unsigned int gic_irqs, irq_limit, i;
+       u32 cpumask;
        void __iomem *base = gic->dist_base;
-       u32 cpumask = 1 << smp_processor_id();
+       u32 cpu = 0;
+       u32 nrppis = 0, ppi_base = 0;
 
+#ifdef CONFIG_SMP
+       cpu = cpu_logical_map(smp_processor_id());
+#endif
+
+       cpumask = 1 << cpu;
        cpumask |= cpumask << 8;
        cpumask |= cpumask << 16;
 
@@ -279,6 +289,23 @@ static void __init gic_dist_init(struct gic_chip_data *gic,
 
        gic->gic_irqs = gic_irqs;
 
+       /*
+        * 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;
+       }
+
+       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.
         */
@@ -314,7 +341,17 @@ 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;
+
+               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);
+       }
+
+       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);
@@ -557,20 +594,15 @@ void __cpuinit gic_secondary_init(unsigned int 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
 void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
 {
-       unsigned long map = *cpus_addr(*mask);
+       int cpu;
+       unsigned long map = 0;
+
+       /* Convert our logical CPU mask into a physical one. */
+       for_each_cpu(cpu, mask)
+               map |= 1 << cpu_logical_map(cpu);
 
        /*
         * Ensure that stores to Normal memory are visible to the
This page took 0.042083 seconds and 5 git commands to generate.