Merge branch 'irq-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git...
[linux-2.6-block.git] / drivers / irqchip / irq-gic.c
index 7cf13828644278611ac593a9d73333a59300cff5..1de20e14a721111737bdab39c575ab7a45ddc63b 100644 (file)
@@ -55,7 +55,7 @@
 
 static void gic_check_cpu_features(void)
 {
-       WARN_TAINT_ONCE(cpus_have_cap(ARM64_HAS_SYSREG_GIC_CPUIF),
+       WARN_TAINT_ONCE(this_cpu_has_cap(ARM64_HAS_SYSREG_GIC_CPUIF),
                        TAINT_CPU_OUT_OF_SPEC,
                        "GICv3 system registers enabled, broken firmware!\n");
 }
@@ -72,6 +72,9 @@ struct gic_chip_data {
        struct irq_chip chip;
        union gic_base dist_base;
        union gic_base cpu_base;
+       void __iomem *raw_dist_base;
+       void __iomem *raw_cpu_base;
+       u32 percpu_offset;
 #ifdef CONFIG_CPU_PM
        u32 saved_spi_enable[DIV_ROUND_UP(1020, 32)];
        u32 saved_spi_active[DIV_ROUND_UP(1020, 32)];
@@ -486,6 +489,7 @@ static int gic_cpu_init(struct gic_chip_data *gic)
                if (WARN_ON(cpu >= NR_GIC_CPU_IF))
                        return -EINVAL;
 
+               gic_check_cpu_features();
                cpu_mask = gic_get_cpumask(gic);
                gic_cpu_map[cpu] = cpu_mask;
 
@@ -529,34 +533,35 @@ int gic_cpu_if_down(unsigned int gic_nr)
  * this function, no interrupts will be delivered by the GIC, and another
  * platform-specific wakeup source must be enabled.
  */
-static void gic_dist_save(unsigned int gic_nr)
+static void gic_dist_save(struct gic_chip_data *gic)
 {
        unsigned int gic_irqs;
        void __iomem *dist_base;
        int i;
 
-       BUG_ON(gic_nr >= CONFIG_ARM_GIC_MAX_NR);
+       if (WARN_ON(!gic))
+               return;
 
-       gic_irqs = gic_data[gic_nr].gic_irqs;
-       dist_base = gic_data_dist_base(&gic_data[gic_nr]);
+       gic_irqs = gic->gic_irqs;
+       dist_base = gic_data_dist_base(gic);
 
        if (!dist_base)
                return;
 
        for (i = 0; i < DIV_ROUND_UP(gic_irqs, 16); i++)
-               gic_data[gic_nr].saved_spi_conf[i] =
+               gic->saved_spi_conf[i] =
                        readl_relaxed(dist_base + GIC_DIST_CONFIG + i * 4);
 
        for (i = 0; i < DIV_ROUND_UP(gic_irqs, 4); i++)
-               gic_data[gic_nr].saved_spi_target[i] =
+               gic->saved_spi_target[i] =
                        readl_relaxed(dist_base + GIC_DIST_TARGET + i * 4);
 
        for (i = 0; i < DIV_ROUND_UP(gic_irqs, 32); i++)
-               gic_data[gic_nr].saved_spi_enable[i] =
+               gic->saved_spi_enable[i] =
                        readl_relaxed(dist_base + GIC_DIST_ENABLE_SET + i * 4);
 
        for (i = 0; i < DIV_ROUND_UP(gic_irqs, 32); i++)
-               gic_data[gic_nr].saved_spi_active[i] =
+               gic->saved_spi_active[i] =
                        readl_relaxed(dist_base + GIC_DIST_ACTIVE_SET + i * 4);
 }
 
@@ -567,16 +572,17 @@ static void gic_dist_save(unsigned int gic_nr)
  * handled normally, but any edge interrupts that occured will not be seen by
  * the GIC and need to be handled by the platform-specific wakeup source.
  */
-static void gic_dist_restore(unsigned int gic_nr)
+static void gic_dist_restore(struct gic_chip_data *gic)
 {
        unsigned int gic_irqs;
        unsigned int i;
        void __iomem *dist_base;
 
-       BUG_ON(gic_nr >= CONFIG_ARM_GIC_MAX_NR);
+       if (WARN_ON(!gic))
+               return;
 
-       gic_irqs = gic_data[gic_nr].gic_irqs;
-       dist_base = gic_data_dist_base(&gic_data[gic_nr]);
+       gic_irqs = gic->gic_irqs;
+       dist_base = gic_data_dist_base(gic);
 
        if (!dist_base)
                return;
@@ -584,7 +590,7 @@ static void gic_dist_restore(unsigned int gic_nr)
        writel_relaxed(GICD_DISABLE, dist_base + GIC_DIST_CTRL);
 
        for (i = 0; i < DIV_ROUND_UP(gic_irqs, 16); i++)
-               writel_relaxed(gic_data[gic_nr].saved_spi_conf[i],
+               writel_relaxed(gic->saved_spi_conf[i],
                        dist_base + GIC_DIST_CONFIG + i * 4);
 
        for (i = 0; i < DIV_ROUND_UP(gic_irqs, 4); i++)
@@ -592,85 +598,87 @@ static void gic_dist_restore(unsigned int gic_nr)
                        dist_base + GIC_DIST_PRI + i * 4);
 
        for (i = 0; i < DIV_ROUND_UP(gic_irqs, 4); i++)
-               writel_relaxed(gic_data[gic_nr].saved_spi_target[i],
+               writel_relaxed(gic->saved_spi_target[i],
                        dist_base + GIC_DIST_TARGET + i * 4);
 
        for (i = 0; i < DIV_ROUND_UP(gic_irqs, 32); i++) {
                writel_relaxed(GICD_INT_EN_CLR_X32,
                        dist_base + GIC_DIST_ENABLE_CLEAR + i * 4);
-               writel_relaxed(gic_data[gic_nr].saved_spi_enable[i],
+               writel_relaxed(gic->saved_spi_enable[i],
                        dist_base + GIC_DIST_ENABLE_SET + i * 4);
        }
 
        for (i = 0; i < DIV_ROUND_UP(gic_irqs, 32); i++) {
                writel_relaxed(GICD_INT_EN_CLR_X32,
                        dist_base + GIC_DIST_ACTIVE_CLEAR + i * 4);
-               writel_relaxed(gic_data[gic_nr].saved_spi_active[i],
+               writel_relaxed(gic->saved_spi_active[i],
                        dist_base + GIC_DIST_ACTIVE_SET + i * 4);
        }
 
        writel_relaxed(GICD_ENABLE, dist_base + GIC_DIST_CTRL);
 }
 
-static void gic_cpu_save(unsigned int gic_nr)
+static void gic_cpu_save(struct gic_chip_data *gic)
 {
        int i;
        u32 *ptr;
        void __iomem *dist_base;
        void __iomem *cpu_base;
 
-       BUG_ON(gic_nr >= CONFIG_ARM_GIC_MAX_NR);
+       if (WARN_ON(!gic))
+               return;
 
-       dist_base = gic_data_dist_base(&gic_data[gic_nr]);
-       cpu_base = gic_data_cpu_base(&gic_data[gic_nr]);
+       dist_base = gic_data_dist_base(gic);
+       cpu_base = gic_data_cpu_base(gic);
 
        if (!dist_base || !cpu_base)
                return;
 
-       ptr = raw_cpu_ptr(gic_data[gic_nr].saved_ppi_enable);
+       ptr = raw_cpu_ptr(gic->saved_ppi_enable);
        for (i = 0; i < DIV_ROUND_UP(32, 32); i++)
                ptr[i] = readl_relaxed(dist_base + GIC_DIST_ENABLE_SET + i * 4);
 
-       ptr = raw_cpu_ptr(gic_data[gic_nr].saved_ppi_active);
+       ptr = raw_cpu_ptr(gic->saved_ppi_active);
        for (i = 0; i < DIV_ROUND_UP(32, 32); i++)
                ptr[i] = readl_relaxed(dist_base + GIC_DIST_ACTIVE_SET + i * 4);
 
-       ptr = raw_cpu_ptr(gic_data[gic_nr].saved_ppi_conf);
+       ptr = raw_cpu_ptr(gic->saved_ppi_conf);
        for (i = 0; i < DIV_ROUND_UP(32, 16); i++)
                ptr[i] = readl_relaxed(dist_base + GIC_DIST_CONFIG + i * 4);
 
 }
 
-static void gic_cpu_restore(unsigned int gic_nr)
+static void gic_cpu_restore(struct gic_chip_data *gic)
 {
        int i;
        u32 *ptr;
        void __iomem *dist_base;
        void __iomem *cpu_base;
 
-       BUG_ON(gic_nr >= CONFIG_ARM_GIC_MAX_NR);
+       if (WARN_ON(!gic))
+               return;
 
-       dist_base = gic_data_dist_base(&gic_data[gic_nr]);
-       cpu_base = gic_data_cpu_base(&gic_data[gic_nr]);
+       dist_base = gic_data_dist_base(gic);
+       cpu_base = gic_data_cpu_base(gic);
 
        if (!dist_base || !cpu_base)
                return;
 
-       ptr = raw_cpu_ptr(gic_data[gic_nr].saved_ppi_enable);
+       ptr = raw_cpu_ptr(gic->saved_ppi_enable);
        for (i = 0; i < DIV_ROUND_UP(32, 32); i++) {
                writel_relaxed(GICD_INT_EN_CLR_X32,
                               dist_base + GIC_DIST_ENABLE_CLEAR + i * 4);
                writel_relaxed(ptr[i], dist_base + GIC_DIST_ENABLE_SET + i * 4);
        }
 
-       ptr = raw_cpu_ptr(gic_data[gic_nr].saved_ppi_active);
+       ptr = raw_cpu_ptr(gic->saved_ppi_active);
        for (i = 0; i < DIV_ROUND_UP(32, 32); i++) {
                writel_relaxed(GICD_INT_EN_CLR_X32,
                               dist_base + GIC_DIST_ACTIVE_CLEAR + i * 4);
                writel_relaxed(ptr[i], dist_base + GIC_DIST_ACTIVE_SET + i * 4);
        }
 
-       ptr = raw_cpu_ptr(gic_data[gic_nr].saved_ppi_conf);
+       ptr = raw_cpu_ptr(gic->saved_ppi_conf);
        for (i = 0; i < DIV_ROUND_UP(32, 16); i++)
                writel_relaxed(ptr[i], dist_base + GIC_DIST_CONFIG + i * 4);
 
@@ -679,7 +687,7 @@ static void gic_cpu_restore(unsigned int gic_nr)
                                        dist_base + GIC_DIST_PRI + i * 4);
 
        writel_relaxed(GICC_INT_PRI_THRESHOLD, cpu_base + GIC_CPU_PRIMASK);
-       gic_cpu_if_up(&gic_data[gic_nr]);
+       gic_cpu_if_up(gic);
 }
 
 static int gic_notifier(struct notifier_block *self, unsigned long cmd,        void *v)
@@ -694,18 +702,18 @@ static int gic_notifier(struct notifier_block *self, unsigned long cmd,   void *v)
 #endif
                switch (cmd) {
                case CPU_PM_ENTER:
-                       gic_cpu_save(i);
+                       gic_cpu_save(&gic_data[i]);
                        break;
                case CPU_PM_ENTER_FAILED:
                case CPU_PM_EXIT:
-                       gic_cpu_restore(i);
+                       gic_cpu_restore(&gic_data[i]);
                        break;
                case CPU_CLUSTER_PM_ENTER:
-                       gic_dist_save(i);
+                       gic_dist_save(&gic_data[i]);
                        break;
                case CPU_CLUSTER_PM_ENTER_FAILED:
                case CPU_CLUSTER_PM_EXIT:
-                       gic_dist_restore(i);
+                       gic_dist_restore(&gic_data[i]);
                        break;
                }
        }
@@ -1022,38 +1030,34 @@ static const struct irq_domain_ops gic_irq_domain_ops = {
        .unmap = gic_irq_domain_unmap,
 };
 
-static int __init __gic_init_bases(unsigned int gic_nr, int irq_start,
-                          void __iomem *dist_base, void __iomem *cpu_base,
-                          u32 percpu_offset, struct fwnode_handle *handle)
+static int __init __gic_init_bases(struct gic_chip_data *gic, int irq_start,
+                                  struct fwnode_handle *handle)
 {
        irq_hw_number_t hwirq_base;
-       struct gic_chip_data *gic;
        int gic_irqs, irq_base, i, ret;
 
-       BUG_ON(gic_nr >= CONFIG_ARM_GIC_MAX_NR);
-
-       gic_check_cpu_features();
-
-       gic = &gic_data[gic_nr];
+       if (WARN_ON(!gic || gic->domain))
+               return -EINVAL;
 
        /* Initialize irq_chip */
        gic->chip = gic_chip;
 
-       if (static_key_true(&supports_deactivate) && gic_nr == 0) {
+       if (static_key_true(&supports_deactivate) && gic == &gic_data[0]) {
                gic->chip.irq_mask = gic_eoimode1_mask_irq;
                gic->chip.irq_eoi = gic_eoimode1_eoi_irq;
                gic->chip.irq_set_vcpu_affinity = gic_irq_set_vcpu_affinity;
                gic->chip.name = kasprintf(GFP_KERNEL, "GICv2");
        } else {
-               gic->chip.name = kasprintf(GFP_KERNEL, "GIC-%d", gic_nr);
+               gic->chip.name = kasprintf(GFP_KERNEL, "GIC-%d",
+                                          (int)(gic - &gic_data[0]));
        }
 
 #ifdef CONFIG_SMP
-       if (gic_nr == 0)
+       if (gic == &gic_data[0])
                gic->chip.irq_set_affinity = gic_set_affinity;
 #endif
 
-       if (IS_ENABLED(CONFIG_GIC_NON_BANKED) && percpu_offset) {
+       if (IS_ENABLED(CONFIG_GIC_NON_BANKED) && gic->percpu_offset) {
                /* Frankein-GIC without banked registers... */
                unsigned int cpu;
 
@@ -1068,19 +1072,21 @@ static int __init __gic_init_bases(unsigned int gic_nr, int irq_start,
                for_each_possible_cpu(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;
+                       unsigned long offset = gic->percpu_offset * core_id;
+                       *per_cpu_ptr(gic->dist_base.percpu_base, cpu) =
+                               gic->raw_dist_base + offset;
+                       *per_cpu_ptr(gic->cpu_base.percpu_base, cpu) =
+                               gic->raw_cpu_base + offset;
                }
 
                gic_set_base_accessor(gic, gic_get_percpu_base);
        } else {
                /* Normal, sane GIC... */
-               WARN(percpu_offset,
+               WARN(gic->percpu_offset,
                     "GIC_NON_BANKED not enabled, ignoring %08x offset!",
-                    percpu_offset);
-               gic->dist_base.common_base = dist_base;
-               gic->cpu_base.common_base = cpu_base;
+                    gic->percpu_offset);
+               gic->dist_base.common_base = gic->raw_dist_base;
+               gic->cpu_base.common_base = gic->raw_cpu_base;
                gic_set_base_accessor(gic, gic_get_common_base);
        }
 
@@ -1103,7 +1109,7 @@ static int __init __gic_init_bases(unsigned int gic_nr, int irq_start,
                 * For primary GICs, skip over SGIs.
                 * For secondary GICs, skip over PPIs, too.
                 */
-               if (gic_nr == 0 && (irq_start & 31) > 0) {
+               if (gic == &gic_data[0] && (irq_start & 31) > 0) {
                        hwirq_base = 16;
                        if (irq_start != -1)
                                irq_start = (irq_start & ~31) + 16;
@@ -1130,7 +1136,7 @@ static int __init __gic_init_bases(unsigned int gic_nr, int irq_start,
                goto error;
        }
 
-       if (gic_nr == 0) {
+       if (gic == &gic_data[0]) {
                /*
                 * Initialize the CPU interface map to all CPUs.
                 * It will be refined as each CPU probes its ID.
@@ -1159,7 +1165,7 @@ static int __init __gic_init_bases(unsigned int gic_nr, int irq_start,
        return 0;
 
 error:
-       if (IS_ENABLED(CONFIG_GIC_NON_BANKED) && percpu_offset) {
+       if (IS_ENABLED(CONFIG_GIC_NON_BANKED) && gic->percpu_offset) {
                free_percpu(gic->dist_base.percpu_base);
                free_percpu(gic->cpu_base.percpu_base);
        }
@@ -1172,12 +1178,33 @@ error:
 void __init gic_init(unsigned int gic_nr, int irq_start,
                     void __iomem *dist_base, void __iomem *cpu_base)
 {
+       struct gic_chip_data *gic;
+
+       if (WARN_ON(gic_nr >= CONFIG_ARM_GIC_MAX_NR))
+               return;
+
        /*
         * Non-DT/ACPI systems won't run a hypervisor, so let's not
         * bother with these...
         */
        static_key_slow_dec(&supports_deactivate);
-       __gic_init_bases(gic_nr, irq_start, dist_base, cpu_base, 0, NULL);
+
+       gic = &gic_data[gic_nr];
+       gic->raw_dist_base = dist_base;
+       gic->raw_cpu_base = cpu_base;
+
+       __gic_init_bases(gic, irq_start, NULL);
+}
+
+static void gic_teardown(struct gic_chip_data *gic)
+{
+       if (WARN_ON(!gic))
+               return;
+
+       if (gic->raw_dist_base)
+               iounmap(gic->raw_dist_base);
+       if (gic->raw_cpu_base)
+               iounmap(gic->raw_cpu_base);
 }
 
 #ifdef CONFIG_OF
@@ -1221,42 +1248,58 @@ static bool gic_check_eoimode(struct device_node *node, void __iomem **base)
        return true;
 }
 
+static int gic_of_setup(struct gic_chip_data *gic, struct device_node *node)
+{
+       if (!gic || !node)
+               return -EINVAL;
+
+       gic->raw_dist_base = of_iomap(node, 0);
+       if (WARN(!gic->raw_dist_base, "unable to map gic dist registers\n"))
+               goto error;
+
+       gic->raw_cpu_base = of_iomap(node, 1);
+       if (WARN(!gic->raw_cpu_base, "unable to map gic cpu registers\n"))
+               goto error;
+
+       if (of_property_read_u32(node, "cpu-offset", &gic->percpu_offset))
+               gic->percpu_offset = 0;
+
+       return 0;
+
+error:
+       gic_teardown(gic);
+
+       return -ENOMEM;
+}
+
 int __init
 gic_of_init(struct device_node *node, struct device_node *parent)
 {
-       void __iomem *cpu_base;
-       void __iomem *dist_base;
-       u32 percpu_offset;
+       struct gic_chip_data *gic;
        int irq, ret;
 
        if (WARN_ON(!node))
                return -ENODEV;
 
-       dist_base = of_iomap(node, 0);
-       if (WARN(!dist_base, "unable to map gic dist registers\n"))
-               return -ENOMEM;
+       if (WARN_ON(gic_cnt >= CONFIG_ARM_GIC_MAX_NR))
+               return -EINVAL;
 
-       cpu_base = of_iomap(node, 1);
-       if (WARN(!cpu_base, "unable to map gic cpu registers\n")) {
-               iounmap(dist_base);
-               return -ENOMEM;
-       }
+       gic = &gic_data[gic_cnt];
+
+       ret = gic_of_setup(gic, node);
+       if (ret)
+               return ret;
 
        /*
         * Disable split EOI/Deactivate if either HYP is not available
         * or the CPU interface is too small.
         */
-       if (gic_cnt == 0 && !gic_check_eoimode(node, &cpu_base))
+       if (gic_cnt == 0 && !gic_check_eoimode(node, &gic->raw_cpu_base))
                static_key_slow_dec(&supports_deactivate);
 
-       if (of_property_read_u32(node, "cpu-offset", &percpu_offset))
-               percpu_offset = 0;
-
-       ret = __gic_init_bases(gic_cnt, -1, dist_base, cpu_base, percpu_offset,
-                        &node->fwnode);
+       ret = __gic_init_bases(gic, -1, &node->fwnode);
        if (ret) {
-               iounmap(dist_base);
-               iounmap(cpu_base);
+               gic_teardown(gic);
                return ret;
        }
 
@@ -1346,8 +1389,8 @@ static int __init gic_v2_acpi_init(struct acpi_subtable_header *header,
                                   const unsigned long end)
 {
        struct acpi_madt_generic_distributor *dist;
-       void __iomem *cpu_base, *dist_base;
        struct fwnode_handle *domain_handle;
+       struct gic_chip_data *gic = &gic_data[0];
        int count, ret;
 
        /* Collect CPU base addresses */
@@ -1358,17 +1401,18 @@ static int __init gic_v2_acpi_init(struct acpi_subtable_header *header,
                return -EINVAL;
        }
 
-       cpu_base = ioremap(cpu_phy_base, ACPI_GIC_CPU_IF_MEM_SIZE);
-       if (!cpu_base) {
+       gic->raw_cpu_base = ioremap(cpu_phy_base, ACPI_GIC_CPU_IF_MEM_SIZE);
+       if (!gic->raw_cpu_base) {
                pr_err("Unable to map GICC registers\n");
                return -ENOMEM;
        }
 
        dist = (struct acpi_madt_generic_distributor *)header;
-       dist_base = ioremap(dist->base_address, ACPI_GICV2_DIST_MEM_SIZE);
-       if (!dist_base) {
+       gic->raw_dist_base = ioremap(dist->base_address,
+                                    ACPI_GICV2_DIST_MEM_SIZE);
+       if (!gic->raw_dist_base) {
                pr_err("Unable to map GICD registers\n");
-               iounmap(cpu_base);
+               gic_teardown(gic);
                return -ENOMEM;
        }
 
@@ -1383,20 +1427,18 @@ static int __init gic_v2_acpi_init(struct acpi_subtable_header *header,
        /*
         * Initialize GIC instance zero (no multi-GIC support).
         */
-       domain_handle = irq_domain_alloc_fwnode(dist_base);
+       domain_handle = irq_domain_alloc_fwnode(gic->raw_dist_base);
        if (!domain_handle) {
                pr_err("Unable to allocate domain handle\n");
-               iounmap(cpu_base);
-               iounmap(dist_base);
+               gic_teardown(gic);
                return -ENOMEM;
        }
 
-       ret = __gic_init_bases(0, -1, dist_base, cpu_base, 0, domain_handle);
+       ret = __gic_init_bases(gic, -1, domain_handle);
        if (ret) {
                pr_err("Failed to initialise GIC\n");
                irq_domain_free_fwnode(domain_handle);
-               iounmap(cpu_base);
-               iounmap(dist_base);
+               gic_teardown(gic);
                return ret;
        }