UPSTREAM: irqchip/gic-v3: Refactor gic_of_init() for GICv3 driver
authorTomasz Nowicki <tn@semihalf.com>
Tue, 19 Jan 2016 13:11:14 +0000 (14:11 +0100)
committerHuang, Tao <huangtao@rock-chips.com>
Fri, 1 Jul 2016 06:20:47 +0000 (14:20 +0800)
Isolate hardware abstraction (FDT) code to gic_of_init().
Rest of the logic goes to gic_init_bases() and expects well
defined data to initialize GIC properly. The same solution
is used for GICv2 driver.

This is needed for ACPI initialization later.

Change-Id: I61fcbd96ecd2dc8130cdd2d6ce79841eb184e87b
Acked-by: Marc Zyngier <marc.zyngier@arm.com>
Signed-off-by: Tomasz Nowicki <tomasz.nowicki@linaro.org>
Signed-off-by: Hanjun Guo <hanjun.guo@linaro.org>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
Signed-off-by: Caesar Wang <wxt@rock-chips.com>
(cherry picked from commit db57d7460ea74de2204ddc303520753f256ea67d)

drivers/irqchip/irq-gic-v3.c

index d7be6ddc34f685a47dad313274f209b59dff6bf5..31205c7d03e34d2c2de05784740e662259b3107c 100644 (file)
@@ -811,59 +811,16 @@ static void gicv3_enable_quirks(void)
 #endif
 }
 
-static int __init gic_of_init(struct device_node *node, struct device_node *parent)
+static int __init gic_init_bases(void __iomem *dist_base,
+                                struct redist_region *rdist_regs,
+                                u32 nr_redist_regions,
+                                u64 redist_stride,
+                                struct fwnode_handle *handle)
 {
-       void __iomem *dist_base;
-       struct redist_region *rdist_regs;
-       u64 redist_stride;
-       u32 nr_redist_regions;
+       struct device_node *node;
        u32 typer;
-       u32 reg;
        int gic_irqs;
        int err;
-       int i;
-
-       dist_base = of_iomap(node, 0);
-       if (!dist_base) {
-               pr_err("%s: unable to map gic dist registers\n",
-                       node->full_name);
-               return -ENXIO;
-       }
-
-       reg = readl_relaxed(dist_base + GICD_PIDR2) & GIC_PIDR2_ARCH_MASK;
-       if (reg != GIC_PIDR2_ARCH_GICv3 && reg != GIC_PIDR2_ARCH_GICv4) {
-               pr_err("%s: no distributor detected, giving up\n",
-                       node->full_name);
-               err = -ENODEV;
-               goto out_unmap_dist;
-       }
-
-       if (of_property_read_u32(node, "#redistributor-regions", &nr_redist_regions))
-               nr_redist_regions = 1;
-
-       rdist_regs = kzalloc(sizeof(*rdist_regs) * nr_redist_regions, GFP_KERNEL);
-       if (!rdist_regs) {
-               err = -ENOMEM;
-               goto out_unmap_dist;
-       }
-
-       for (i = 0; i < nr_redist_regions; i++) {
-               struct resource res;
-               int ret;
-
-               ret = of_address_to_resource(node, 1 + i, &res);
-               rdist_regs[i].redist_base = of_iomap(node, 1 + i);
-               if (ret || !rdist_regs[i].redist_base) {
-                       pr_err("%s: couldn't map region %d\n",
-                              node->full_name, i);
-                       err = -ENODEV;
-                       goto out_unmap_rdist;
-               }
-               rdist_regs[i].phys_base = res.start;
-       }
-
-       if (of_property_read_u64(node, "redistributor-stride", &redist_stride))
-               redist_stride = 0;
 
        if (!is_hyp_mode_available())
                static_key_slow_dec(&supports_deactivate);
@@ -889,8 +846,8 @@ static int __init gic_of_init(struct device_node *node, struct device_node *pare
                gic_irqs = 1020;
        gic_data.irq_nr = gic_irqs;
 
-       gic_data.domain = irq_domain_add_tree(node, &gic_irq_domain_ops,
-                                             &gic_data);
+       gic_data.domain = irq_domain_create_tree(handle, &gic_irq_domain_ops,
+                                                &gic_data);
        gic_data.rdists.rdist = alloc_percpu(typeof(*gic_data.rdists.rdist));
 
        if (WARN_ON(!gic_data.domain) || WARN_ON(!gic_data.rdists.rdist)) {
@@ -900,7 +857,9 @@ static int __init gic_of_init(struct device_node *node, struct device_node *pare
 
        set_handle_irq(gic_handle_irq);
 
-       if (IS_ENABLED(CONFIG_ARM_GIC_V3_ITS) && gic_dist_supports_lpis())
+       node = to_of_node(handle);
+       if (IS_ENABLED(CONFIG_ARM_GIC_V3_ITS) && gic_dist_supports_lpis() &&
+           node) /* Temp hack to prevent ITS init for ACPI */
                its_init(node, &gic_data.rdists, gic_data.domain);
 
        gic_smp_init();
@@ -914,6 +873,73 @@ out_free:
        if (gic_data.domain)
                irq_domain_remove(gic_data.domain);
        free_percpu(gic_data.rdists.rdist);
+       return err;
+}
+
+static int __init gic_validate_dist_version(void __iomem *dist_base)
+{
+       u32 reg = readl_relaxed(dist_base + GICD_PIDR2) & GIC_PIDR2_ARCH_MASK;
+
+       if (reg != GIC_PIDR2_ARCH_GICv3 && reg != GIC_PIDR2_ARCH_GICv4)
+               return -ENODEV;
+
+       return 0;
+}
+
+static int __init gic_of_init(struct device_node *node, struct device_node *parent)
+{
+       void __iomem *dist_base;
+       struct redist_region *rdist_regs;
+       u64 redist_stride;
+       u32 nr_redist_regions;
+       int err, i;
+
+       dist_base = of_iomap(node, 0);
+       if (!dist_base) {
+               pr_err("%s: unable to map gic dist registers\n",
+                       node->full_name);
+               return -ENXIO;
+       }
+
+       err = gic_validate_dist_version(dist_base);
+       if (err) {
+               pr_err("%s: no distributor detected, giving up\n",
+                       node->full_name);
+               goto out_unmap_dist;
+       }
+
+       if (of_property_read_u32(node, "#redistributor-regions", &nr_redist_regions))
+               nr_redist_regions = 1;
+
+       rdist_regs = kzalloc(sizeof(*rdist_regs) * nr_redist_regions, GFP_KERNEL);
+       if (!rdist_regs) {
+               err = -ENOMEM;
+               goto out_unmap_dist;
+       }
+
+       for (i = 0; i < nr_redist_regions; i++) {
+               struct resource res;
+               int ret;
+
+               ret = of_address_to_resource(node, 1 + i, &res);
+               rdist_regs[i].redist_base = of_iomap(node, 1 + i);
+               if (ret || !rdist_regs[i].redist_base) {
+                       pr_err("%s: couldn't map region %d\n",
+                              node->full_name, i);
+                       err = -ENODEV;
+                       goto out_unmap_rdist;
+               }
+               rdist_regs[i].phys_base = res.start;
+       }
+
+       if (of_property_read_u64(node, "redistributor-stride", &redist_stride))
+               redist_stride = 0;
+
+       err = gic_init_bases(dist_base, rdist_regs, nr_redist_regions,
+                            redist_stride, &node->fwnode);
+       if (!err)
+               return 0;
+
 out_unmap_rdist:
        for (i = 0; i < nr_redist_regions; i++)
                if (rdist_regs[i].redist_base)