Merge branch 'irq-final-for-linus-v2' of git://git.kernel.org/pub/scm/linux/kernel...
[pandora-kernel.git] / arch / arm / common / gic.c
index 2243772..f70ec7d 100644 (file)
@@ -44,6 +44,19 @@ struct gic_chip_data {
        void __iomem *cpu_base;
 };
 
+/*
+ * Supported arch specific GIC irq extension.
+ * Default make them NULL.
+ */
+struct irq_chip gic_arch_extn = {
+       .irq_ack        = NULL,
+       .irq_mask       = NULL,
+       .irq_unmask     = NULL,
+       .irq_retrigger  = NULL,
+       .irq_set_type   = NULL,
+       .irq_set_wake   = NULL,
+};
+
 #ifndef MAX_GIC_NR
 #define MAX_GIC_NR     1
 #endif
@@ -74,6 +87,8 @@ static inline unsigned int gic_irq(struct irq_data *d)
 static void gic_ack_irq(struct irq_data *d)
 {
        spin_lock(&irq_controller_lock);
+       if (gic_arch_extn.irq_ack)
+               gic_arch_extn.irq_ack(d);
        writel(gic_irq(d), gic_cpu_base(d) + GIC_CPU_EOI);
        spin_unlock(&irq_controller_lock);
 }
@@ -84,6 +99,8 @@ static void gic_mask_irq(struct irq_data *d)
 
        spin_lock(&irq_controller_lock);
        writel(mask, gic_dist_base(d) + GIC_DIST_ENABLE_CLEAR + (gic_irq(d) / 32) * 4);
+       if (gic_arch_extn.irq_mask)
+               gic_arch_extn.irq_mask(d);
        spin_unlock(&irq_controller_lock);
 }
 
@@ -92,6 +109,8 @@ static void gic_unmask_irq(struct irq_data *d)
        u32 mask = 1 << (d->irq % 32);
 
        spin_lock(&irq_controller_lock);
+       if (gic_arch_extn.irq_unmask)
+               gic_arch_extn.irq_unmask(d);
        writel(mask, gic_dist_base(d) + GIC_DIST_ENABLE_SET + (gic_irq(d) / 32) * 4);
        spin_unlock(&irq_controller_lock);
 }
@@ -116,6 +135,9 @@ static int gic_set_type(struct irq_data *d, unsigned int type)
 
        spin_lock(&irq_controller_lock);
 
+       if (gic_arch_extn.irq_set_type)
+               gic_arch_extn.irq_set_type(d, type);
+
        val = readl(base + GIC_DIST_CONFIG + confoff);
        if (type == IRQ_TYPE_LEVEL_HIGH)
                val &= ~confmask;
@@ -141,36 +163,58 @@ static int gic_set_type(struct irq_data *d, unsigned int type)
        return 0;
 }
 
+static int gic_retrigger(struct irq_data *d)
+{
+       if (gic_arch_extn.irq_retrigger)
+               return gic_arch_extn.irq_retrigger(d);
+
+       return -ENXIO;
+}
+
 #ifdef CONFIG_SMP
-static int
-gic_set_cpu(struct irq_data *d, const struct cpumask *mask_val, bool force)
+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 = (d->irq % 4) * 8;
        unsigned int cpu = cpumask_first(mask_val);
-       u32 val;
-       struct irq_desc *desc;
+       u32 val, mask, bit;
 
-       spin_lock(&irq_controller_lock);
-       desc = irq_to_desc(d->irq);
-       if (desc == NULL) {
-               spin_unlock(&irq_controller_lock);
+       if (cpu >= 8)
                return -EINVAL;
-       }
+
+       mask = 0xff << shift;
+       bit = 1 << (cpu + shift);
+
+       spin_lock(&irq_controller_lock);
        d->node = cpu;
-       val = readl(reg) & ~(0xff << shift);
-       val |= 1 << (cpu + shift);
-       writel(val, reg);
+       val = readl(reg) & ~mask;
+       writel(val | bit, reg);
        spin_unlock(&irq_controller_lock);
 
        return 0;
 }
 #endif
 
+#ifdef CONFIG_PM
+static int gic_set_wake(struct irq_data *d, unsigned int on)
+{
+       int ret = -ENXIO;
+
+       if (gic_arch_extn.irq_set_wake)
+               ret = gic_arch_extn.irq_set_wake(d, on);
+
+       return ret;
+}
+
+#else
+#define gic_set_wake   NULL
+#endif
+
 static void gic_handle_cascade_irq(unsigned int irq, struct irq_desc *desc)
 {
-       struct gic_chip_data *chip_data = get_irq_data(irq);
-       struct irq_chip *chip = get_irq_chip(irq);
+       struct gic_chip_data *chip_data = irq_get_handler_data(irq);
+       struct irq_chip *chip = irq_get_chip(irq);
        unsigned int cascade_irq, gic_irq;
        unsigned long status;
 
@@ -202,18 +246,20 @@ static struct irq_chip gic_chip = {
        .irq_mask               = gic_mask_irq,
        .irq_unmask             = gic_unmask_irq,
        .irq_set_type           = gic_set_type,
+       .irq_retrigger          = gic_retrigger,
 #ifdef CONFIG_SMP
-       .irq_set_affinity       = gic_set_cpu,
+       .irq_set_affinity       = gic_set_affinity,
 #endif
+       .irq_set_wake           = gic_set_wake,
 };
 
 void __init gic_cascade_irq(unsigned int gic_nr, unsigned int irq)
 {
        if (gic_nr >= MAX_GIC_NR)
                BUG();
-       if (set_irq_data(irq, &gic_data[gic_nr]) != 0)
+       if (irq_set_handler_data(irq, &gic_data[gic_nr]) != 0)
                BUG();
-       set_irq_chained_handler(irq, gic_handle_cascade_irq);
+       irq_set_chained_handler(irq, gic_handle_cascade_irq);
 }
 
 static void __init gic_dist_init(struct gic_chip_data *gic,
@@ -273,9 +319,8 @@ static void __init gic_dist_init(struct gic_chip_data *gic,
         * Setup the Linux IRQ subsystem.
         */
        for (i = irq_start; i < irq_limit; i++) {
-               set_irq_chip(i, &gic_chip);
-               set_irq_chip_data(i, gic);
-               set_irq_handler(i, handle_level_irq);
+               irq_set_chip_and_handler(i, &gic_chip, handle_level_irq);
+               irq_set_chip_data(i, gic);
                set_irq_flags(i, IRQF_VALID | IRQF_PROBE);
        }
 
@@ -336,7 +381,7 @@ void __cpuinit gic_enable_ppi(unsigned int irq)
        unsigned long flags;
 
        local_irq_save(flags);
-       irq_to_desc(irq)->status |= IRQ_NOPROBE;
+       irq_set_status_flags(irq, IRQ_NOPROBE);
        gic_unmask_irq(irq_get_irq_data(irq));
        local_irq_restore(flags);
 }