Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/trivial
[sfrench/cifs-2.6.git] / drivers / irqchip / irq-gic.c
index 3b7650fccdc07a35bba8639dfe4800d257016380..4b959e606fe8d64494af44f9f8f66f6f069c22d3 100644 (file)
 #include <linux/irqchip/chained_irq.h>
 #include <linux/irqchip/arm-gic.h>
 
+#include <asm/cputype.h>
 #include <asm/irq.h>
 #include <asm/exception.h>
 #include <asm/smp_plat.h>
 
+#include "irq-gic-common.h"
 #include "irqchip.h"
 
 union gic_base {
@@ -186,12 +188,6 @@ static int gic_set_type(struct irq_data *d, unsigned int type)
 {
        void __iomem *base = gic_dist_base(d);
        unsigned int gicirq = gic_irq(d);
-       u32 enablemask = 1 << (gicirq % 32);
-       u32 enableoff = (gicirq / 32) * 4;
-       u32 confmask = 0x2 << ((gicirq % 16) * 2);
-       u32 confoff = (gicirq / 16) * 4;
-       bool enabled = false;
-       u32 val;
 
        /* Interrupt configuration for SGIs can't be changed */
        if (gicirq < 16)
@@ -205,25 +201,7 @@ static int gic_set_type(struct irq_data *d, unsigned int type)
        if (gic_arch_extn.irq_set_type)
                gic_arch_extn.irq_set_type(d, type);
 
-       val = readl_relaxed(base + GIC_DIST_CONFIG + confoff);
-       if (type == IRQ_TYPE_LEVEL_HIGH)
-               val &= ~confmask;
-       else if (type == IRQ_TYPE_EDGE_RISING)
-               val |= confmask;
-
-       /*
-        * As recommended by the spec, disable the interrupt before changing
-        * the configuration
-        */
-       if (readl_relaxed(base + GIC_DIST_ENABLE_SET + enableoff) & enablemask) {
-               writel_relaxed(enablemask, base + GIC_DIST_ENABLE_CLEAR + enableoff);
-               enabled = true;
-       }
-
-       writel_relaxed(val, base + GIC_DIST_CONFIG + confoff);
-
-       if (enabled)
-               writel_relaxed(enablemask, base + GIC_DIST_ENABLE_SET + enableoff);
+       gic_configure_irq(gicirq, type, base, NULL);
 
        raw_spin_unlock(&irq_controller_lock);
 
@@ -244,10 +222,14 @@ static int gic_set_affinity(struct irq_data *d, const struct cpumask *mask_val,
                            bool force)
 {
        void __iomem *reg = gic_dist_base(d) + GIC_DIST_TARGET + (gic_irq(d) & ~3);
-       unsigned int shift = (gic_irq(d) % 4) * 8;
-       unsigned int cpu = cpumask_any_and(mask_val, cpu_online_mask);
+       unsigned int cpu, shift = (gic_irq(d) % 4) * 8;
        u32 val, mask, bit;
 
+       if (!force)
+               cpu = cpumask_any_and(mask_val, cpu_online_mask);
+       else
+               cpu = cpumask_first(mask_val);
+
        if (cpu >= NR_GIC_CPU_IF || cpu >= nr_cpu_ids)
                return -EINVAL;
 
@@ -285,7 +267,7 @@ static void __exception_irq_entry gic_handle_irq(struct pt_regs *regs)
 
        do {
                irqstat = readl_relaxed(cpu_base + GIC_CPU_INTACK);
-               irqnr = irqstat & ~0x1c00;
+               irqnr = irqstat & GICC_IAR_INT_ID_MASK;
 
                if (likely(irqnr > 15 && irqnr < 1021)) {
                        irqnr = irq_find_mapping(gic->domain, irqnr);
@@ -380,12 +362,6 @@ static void __init gic_dist_init(struct gic_chip_data *gic)
 
        writel_relaxed(0, base + GIC_DIST_CTRL);
 
-       /*
-        * Set all global interrupts to be level triggered, active low.
-        */
-       for (i = 32; i < gic_irqs; i += 16)
-               writel_relaxed(0, base + GIC_DIST_CONFIG + i * 4 / 16);
-
        /*
         * Set all global interrupts to this CPU only.
         */
@@ -395,18 +371,7 @@ static void __init gic_dist_init(struct gic_chip_data *gic)
        for (i = 32; i < gic_irqs; i += 4)
                writel_relaxed(cpumask, base + GIC_DIST_TARGET + i * 4 / 4);
 
-       /*
-        * Set priority on all global interrupts.
-        */
-       for (i = 32; i < gic_irqs; i += 4)
-               writel_relaxed(0xa0a0a0a0, base + GIC_DIST_PRI + i * 4 / 4);
-
-       /*
-        * Disable all interrupts.  Leave the PPI and SGIs alone
-        * as these enables are banked registers.
-        */
-       for (i = 32; i < gic_irqs; i += 32)
-               writel_relaxed(0xffffffff, base + GIC_DIST_ENABLE_CLEAR + i * 4 / 32);
+       gic_dist_config(base, gic_irqs, NULL);
 
        writel_relaxed(1, base + GIC_DIST_CTRL);
 }
@@ -433,18 +398,7 @@ static void gic_cpu_init(struct gic_chip_data *gic)
                if (i != cpu)
                        gic_cpu_map[i] &= ~cpu_mask;
 
-       /*
-        * Deal with the banked PPI and SGI interrupts - disable all
-        * PPI interrupts, ensure all SGI interrupts are enabled.
-        */
-       writel_relaxed(0xffff0000, dist_base + GIC_DIST_ENABLE_CLEAR);
-       writel_relaxed(0x0000ffff, dist_base + GIC_DIST_ENABLE_SET);
-
-       /*
-        * Set priority on PPI and SGI interrupts
-        */
-       for (i = 0; i < 32; i += 4)
-               writel_relaxed(0xa0a0a0a0, dist_base + GIC_DIST_PRI + i * 4 / 4);
+       gic_cpu_config(dist_base, NULL);
 
        writel_relaxed(0xf0, base + GIC_CPU_PRIMASK);
        writel_relaxed(1, base + GIC_CPU_CTRL);
@@ -659,9 +613,9 @@ static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
 
        /*
         * Ensure that stores to Normal memory are visible to the
-        * other CPUs before issuing the IPI.
+        * other CPUs before they observe us issuing the IPI.
         */
-       dsb();
+       dmb(ishst);
 
        /* this always happens on GIC0 */
        writel_relaxed(map << 16 | irq, gic_data_dist_base(&gic_data[0]) + GIC_DIST_SOFTINT);
@@ -822,16 +776,25 @@ static int gic_irq_domain_map(struct irq_domain *d, unsigned int irq,
                irq_set_chip_and_handler(irq, &gic_chip,
                                         handle_fasteoi_irq);
                set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
+
+               gic_routable_irq_domain_ops->map(d, irq, hw);
        }
        irq_set_chip_data(irq, d->host_data);
        return 0;
 }
 
+static void gic_irq_domain_unmap(struct irq_domain *d, unsigned int irq)
+{
+       gic_routable_irq_domain_ops->unmap(d, irq);
+}
+
 static int gic_irq_domain_xlate(struct irq_domain *d,
                                struct device_node *controller,
                                const u32 *intspec, unsigned int intsize,
                                unsigned long *out_hwirq, unsigned int *out_type)
 {
+       unsigned long ret = 0;
+
        if (d->of_node != controller)
                return -EINVAL;
        if (intsize < 3)
@@ -841,11 +804,20 @@ static int gic_irq_domain_xlate(struct irq_domain *d,
        *out_hwirq = intspec[1] + 16;
 
        /* For SPIs, we need to add 16 more to get the GIC irq ID number */
-       if (!intspec[0])
-               *out_hwirq += 16;
+       if (!intspec[0]) {
+               ret = gic_routable_irq_domain_ops->xlate(d, controller,
+                                                        intspec,
+                                                        intsize,
+                                                        out_hwirq,
+                                                        out_type);
+
+               if (IS_ERR_VALUE(ret))
+                       return ret;
+       }
 
        *out_type = intspec[2] & IRQ_TYPE_SENSE_MASK;
-       return 0;
+
+       return ret;
 }
 
 #ifdef CONFIG_SMP
@@ -869,9 +841,41 @@ static struct notifier_block gic_cpu_notifier = {
 
 static const struct irq_domain_ops gic_irq_domain_ops = {
        .map = gic_irq_domain_map,
+       .unmap = gic_irq_domain_unmap,
        .xlate = gic_irq_domain_xlate,
 };
 
+/* Default functions for routable irq domain */
+static int gic_routable_irq_domain_map(struct irq_domain *d, unsigned int irq,
+                             irq_hw_number_t hw)
+{
+       return 0;
+}
+
+static void gic_routable_irq_domain_unmap(struct irq_domain *d,
+                                         unsigned int irq)
+{
+}
+
+static int gic_routable_irq_domain_xlate(struct irq_domain *d,
+                               struct device_node *controller,
+                               const u32 *intspec, unsigned int intsize,
+                               unsigned long *out_hwirq,
+                               unsigned int *out_type)
+{
+       *out_hwirq += 16;
+       return 0;
+}
+
+const struct irq_domain_ops gic_default_routable_irq_domain_ops = {
+       .map = gic_routable_irq_domain_map,
+       .unmap = gic_routable_irq_domain_unmap,
+       .xlate = gic_routable_irq_domain_xlate,
+};
+
+const struct irq_domain_ops *gic_routable_irq_domain_ops =
+                                       &gic_default_routable_irq_domain_ops;
+
 void __init gic_init_bases(unsigned int gic_nr, int irq_start,
                           void __iomem *dist_base, void __iomem *cpu_base,
                           u32 percpu_offset, struct device_node *node)
@@ -879,6 +883,7 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start,
        irq_hw_number_t hwirq_base;
        struct gic_chip_data *gic;
        int gic_irqs, irq_base, i;
+       int nr_routable_irqs;
 
        BUG_ON(gic_nr >= MAX_GIC_NR);
 
@@ -897,7 +902,9 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start,
                }
 
                for_each_possible_cpu(cpu) {
-                       unsigned long offset = percpu_offset * cpu_logical_map(cpu);
+                       u32 mpidr = cpu_logical_map(cpu);
+                       u32 core_id = MPIDR_AFFINITY_LEVEL(mpidr, 0);
+                       unsigned long offset = percpu_offset * core_id;
                        *per_cpu_ptr(gic->dist_base.percpu_base, cpu) = dist_base + offset;
                        *per_cpu_ptr(gic->cpu_base.percpu_base, cpu) = cpu_base + offset;
                }
@@ -944,14 +951,25 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start,
        gic->gic_irqs = gic_irqs;
 
        gic_irqs -= hwirq_base; /* calculate # of irqs to allocate */
-       irq_base = irq_alloc_descs(irq_start, 16, gic_irqs, numa_node_id());
-       if (IS_ERR_VALUE(irq_base)) {
-               WARN(1, "Cannot allocate irq_descs @ IRQ%d, assuming pre-allocated\n",
-                    irq_start);
-               irq_base = irq_start;
+
+       if (of_property_read_u32(node, "arm,routable-irqs",
+                                &nr_routable_irqs)) {
+               irq_base = irq_alloc_descs(irq_start, 16, gic_irqs,
+                                          numa_node_id());
+               if (IS_ERR_VALUE(irq_base)) {
+                       WARN(1, "Cannot allocate irq_descs @ IRQ%d, assuming pre-allocated\n",
+                            irq_start);
+                       irq_base = irq_start;
+               }
+
+               gic->domain = irq_domain_add_legacy(node, gic_irqs, irq_base,
+                                       hwirq_base, &gic_irq_domain_ops, gic);
+       } else {
+               gic->domain = irq_domain_add_linear(node, nr_routable_irqs,
+                                                   &gic_irq_domain_ops,
+                                                   gic);
        }
-       gic->domain = irq_domain_add_legacy(node, gic_irqs, irq_base,
-                                   hwirq_base, &gic_irq_domain_ops, gic);
+
        if (WARN_ON(!gic->domain))
                return;
 
@@ -1003,8 +1021,10 @@ gic_of_init(struct device_node *node, struct device_node *parent)
        gic_cnt++;
        return 0;
 }
+IRQCHIP_DECLARE(gic_400, "arm,gic-400", gic_of_init);
 IRQCHIP_DECLARE(cortex_a15_gic, "arm,cortex-a15-gic", gic_of_init);
 IRQCHIP_DECLARE(cortex_a9_gic, "arm,cortex-a9-gic", gic_of_init);
+IRQCHIP_DECLARE(cortex_a7_gic, "arm,cortex-a7-gic", gic_of_init);
 IRQCHIP_DECLARE(msm_8660_qgic, "qcom,msm-8660-qgic", gic_of_init);
 IRQCHIP_DECLARE(msm_qgic2, "qcom,msm-qgic2", gic_of_init);