@@ -97,9 +97,6 @@ static int gic_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
const struct gic_clk_data *data;
struct gic_chip_data *gic;
- void __iomem *dist_base;
- void __iomem *cpu_base;
- u32 percpu_offset;
int ret, irq;
data = of_device_get_match_data(&pdev->dev);
@@ -108,16 +105,10 @@ static int gic_probe(struct platform_device *pdev)
return -ENODEV;
}
- gic = devm_kzalloc(dev, sizeof(*gic), GFP_KERNEL);
- if (!gic)
- return -ENOMEM;
-
ret = gic_get_clocks(dev, data);
if (ret)
return ret;
- platform_set_drvdata(pdev, gic);
-
pm_runtime_enable(dev);
ret = pm_runtime_get_sync(dev);
@@ -131,21 +122,16 @@ static int gic_probe(struct platform_device *pdev)
goto rpm_put;
}
- ret = gic_of_setup(dev->of_node, &dist_base, &cpu_base, &percpu_offset);
+ ret = gic_of_setup(dev->of_node, dev, &gic);
if (ret)
goto irq_dispose;
- ret = gic_init_bases(gic, -1, dist_base, cpu_base,
- percpu_offset, &dev->of_node->fwnode,
+ ret = gic_init_bases(gic, -1, gic, &dev->of_node->fwnode,
dev->of_node->name);
if (ret)
goto gic_unmap;
- gic_dist_init(gic);
- gic_cpu_init(gic);
- gic_pm_init(gic);
-
- gic->chip.parent_device = dev;
+ platform_set_drvdata(pdev, gic);
irq_set_chained_handler_and_data(irq, gic_handle_cascade_irq, gic);
@@ -156,8 +142,7 @@ static int gic_probe(struct platform_device *pdev)
return 0;
gic_unmap:
- iounmap(dist_base);
- iounmap(cpu_base);
+ gic_of_teardown(gic);
irq_dispose:
irq_dispose_mapping(irq);
rpm_put:
@@ -51,6 +51,34 @@
#include "irq-gic.h"
#include "irq-gic-common.h"
+union gic_base {
+ void __iomem *common_base;
+ void __percpu * __iomem *percpu_base;
+};
+
+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;
+#if defined(CONFIG_CPU_PM) || defined(ARM_GIC_PM)
+ u32 saved_spi_enable[DIV_ROUND_UP(1020, 32)];
+ u32 saved_spi_active[DIV_ROUND_UP(1020, 32)];
+ u32 saved_spi_conf[DIV_ROUND_UP(1020, 16)];
+ u32 saved_spi_target[DIV_ROUND_UP(1020, 4)];
+ u32 __percpu *saved_ppi_enable;
+ u32 __percpu *saved_ppi_active;
+ u32 __percpu *saved_ppi_conf;
+#endif
+ struct irq_domain *domain;
+ unsigned int gic_irqs;
+#ifdef CONFIG_GIC_NON_BANKED
+ void __iomem *(*get_base)(union gic_base *);
+#endif
+};
+
#ifdef CONFIG_ARM64
#include <asm/cpufeature.h>
@@ -420,7 +448,7 @@ static void gic_cpu_if_up(struct gic_chip_data *gic)
}
-void gic_dist_init(struct gic_chip_data *gic)
+static void gic_dist_init(struct gic_chip_data *gic)
{
unsigned int i;
u32 cpumask;
@@ -443,7 +471,7 @@ void gic_dist_init(struct gic_chip_data *gic)
writel_relaxed(GICD_ENABLE, base + GIC_DIST_CTRL);
}
-void gic_cpu_init(struct gic_chip_data *gic)
+static void gic_cpu_init(struct gic_chip_data *gic)
{
void __iomem *dist_base = gic_data_dist_base(gic);
void __iomem *base = gic_data_cpu_base(gic);
@@ -693,7 +721,7 @@ static struct notifier_block gic_notifier_block = {
.notifier_call = gic_notifier,
};
-void gic_pm_init(struct gic_chip_data *gic)
+static void gic_pm_init(struct gic_chip_data *gic)
{
gic->saved_ppi_enable = __alloc_percpu(DIV_ROUND_UP(32, 32) * 4,
sizeof(u32));
@@ -711,7 +739,7 @@ void gic_pm_init(struct gic_chip_data *gic)
cpu_pm_register_notifier(&gic_notifier_block);
}
#else
-void gic_pm_init(struct gic_chip_data *gic)
+static void gic_pm_init(struct gic_chip_data *gic)
{
}
#endif
@@ -986,9 +1014,7 @@ static const struct irq_domain_ops gic_irq_domain_ops = {
};
int gic_init_bases(struct gic_chip_data *gic, int irq_start,
- void __iomem *dist_base, void __iomem *cpu_base,
- u32 percpu_offset, struct fwnode_handle *handle,
- const char *name)
+ struct fwnode_handle *handle, const char *name)
{
irq_hw_number_t hwirq_base;
int gic_irqs, irq_base, ret;
@@ -1013,7 +1039,7 @@ int gic_init_bases(struct gic_chip_data *gic, int irq_start,
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;
@@ -1028,19 +1054,19 @@ int gic_init_bases(struct gic_chip_data *gic, 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);
}
@@ -1090,10 +1116,14 @@ int gic_init_bases(struct gic_chip_data *gic, int irq_start,
goto error;
}
+ gic_dist_init(gic);
+ gic_cpu_init(gic);
+ gic_pm_init(gic);
+
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);
}
@@ -1101,37 +1131,24 @@ error:
return ret;
}
-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)
{
- struct gic_chip_data *gic;
char *name;
- int i, ret;
-
- if (WARN_ON(gic_nr >= CONFIG_ARM_GIC_MAX_NR))
- return -EINVAL;
-
- gic = &gic_data[gic_nr];
+ int ret;
- if (static_key_true(&supports_deactivate) && gic_nr == 0)
+ if (static_key_true(&supports_deactivate) && gic == &gic_data[0])
name = kasprintf(GFP_KERNEL, "GICv2");
else
- name = kasprintf(GFP_KERNEL, "GIC-%d", gic_nr);
+ name = kasprintf(GFP_KERNEL, "GIC-%d", (int)(gic - &gic_data[0]));
- ret = gic_init_bases(gic, irq_start, dist_base, cpu_base, percpu_offset,
- handle, name);
- if (ret) {
- kfree(name);
- return ret;
- }
-
- 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.
* This is only necessary for the primary GIC.
*/
+ int i;
for (i = 0; i < NR_GIC_CPU_IF; i++)
gic_cpu_map[i] = 0xff;
#ifdef CONFIG_SMP
@@ -1144,22 +1161,26 @@ static int __init __gic_init_bases(unsigned int gic_nr, int irq_start,
pr_info("GIC: Using split EOI/Deactivate mode\n");
}
- gic_dist_init(gic);
- gic_cpu_init(gic);
- gic_pm_init(gic);
+ ret = gic_init_bases(gic, irq_start, handle, name);
+ if (ret)
+ kfree(name);
- return 0;
+ return ret;
}
void __init gic_init(unsigned int gic_nr, int irq_start,
void __iomem *dist_base, void __iomem *cpu_base)
{
+ struct gic_chip_data *gic = &gic_data[gic_nr];
+
/*
* 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->raw_dist_base = dist_base;
+ gic->raw_cpu_base = cpu_base;
+ __gic_init_bases(gic, irq_start, NULL);
}
#ifdef CONFIG_OF
@@ -1203,34 +1224,52 @@ static bool gic_check_eoimode(struct device_node *node, void __iomem **base)
return true;
}
-int gic_of_setup(struct device_node *node, void __iomem **dist_base,
- void __iomem **cpu_base, u32 *percpu_offset)
+void gic_of_teardown(struct gic_chip_data *gic)
{
- if (!node || !dist_base || !cpu_base || !percpu_offset)
- return -EINVAL;
+ if (gic->raw_dist_base)
+ iounmap(gic->raw_dist_base);
+ if (gic->raw_cpu_base)
+ iounmap(gic->raw_cpu_base);
+}
- *dist_base = of_iomap(node, 0);
- if (WARN(!*dist_base, "unable to map gic dist registers\n"))
- return -ENOMEM;
+int gic_of_setup(struct device_node *node, struct device *dev,
+ struct gic_chip_data **gicp)
+{
+ struct gic_chip_data *gic;
- *cpu_base = of_iomap(node, 1);
- if (WARN(!*cpu_base, "unable to map gic cpu registers\n")) {
- iounmap(*dist_base);
- return -ENOMEM;
+ if (!node || !gicp)
+ return -EINVAL;
+
+ if (dev) {
+ *gicp = devm_kzalloc(dev, sizeof(*gic), GFP_KERNEL);
+ if (!*gicp)
+ return -ENOMEM;
}
- if (of_property_read_u32(node, "cpu-offset", percpu_offset))
- *percpu_offset = 0;
+ gic = *gicp;
+
+ gic->raw_dist_base = of_iomap(node, 0);
+ if (WARN(!gic->raw_dist_base, "unable to map gic dist registers\n"))
+ goto err;
+
+ gic->raw_cpu_base = of_iomap(node, 1);
+ if (WARN(!gic->raw_cpu_base, "unable to map gic cpu registers\n"))
+ goto err;
+
+ if (of_property_read_u32(node, "cpu-offset", &gic->percpu_offset))
+ gic->percpu_offset = 0;
+ gic->chip.parent_device = dev;
return 0;
+err:
+ gic_of_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))
@@ -1245,7 +1284,8 @@ gic_of_init(struct device_node *node, struct device_node *parent)
of_property_read_bool(node, "power-domains"))
return 0;
- ret = gic_of_setup(node, &dist_base, &cpu_base, &percpu_offset);
+ gic = &gic_data[gic_cnt];
+ ret = gic_of_setup(node, NULL, &gic);
if (ret)
return ret;
@@ -1253,14 +1293,13 @@ gic_of_init(struct device_node *node, struct device_node *parent)
* 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);
- 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);
+ iounmap(gic->raw_dist_base);
+ iounmap(gic->raw_cpu_base);
return ret;
}
@@ -1395,7 +1434,9 @@ static int __init gic_v2_acpi_init(struct acpi_subtable_header *header,
return -ENOMEM;
}
- ret = __gic_init_bases(0, -1, dist_base, cpu_base, 0, domain_handle);
+ gic_data[0].raw_dist_base = dist_base;
+ gic_data[0].raw_cpu_base = cpu_base;
+ ret = __gic_init_bases(&gic_data[0], -1, domain_handle);
if (ret) {
pr_err("Failed to initialise GIC\n");
irq_domain_free_fwnode(domain_handle);
@@ -17,46 +17,18 @@
#ifndef _IRQ_GIC_H
#define _IRQ_GIC_H
-union gic_base {
- void __iomem *common_base;
- void __percpu * __iomem *percpu_base;
-};
+struct gic_chip_data;
-struct gic_chip_data {
- struct irq_chip chip;
- union gic_base dist_base;
- union gic_base cpu_base;
-#if defined(CONFIG_CPU_PM) || defined(ARM_GIC_PM)
- u32 saved_spi_enable[DIV_ROUND_UP(1020, 32)];
- u32 saved_spi_active[DIV_ROUND_UP(1020, 32)];
- u32 saved_spi_conf[DIV_ROUND_UP(1020, 16)];
- u32 saved_spi_target[DIV_ROUND_UP(1020, 4)];
- u32 __percpu *saved_ppi_enable;
- u32 __percpu *saved_ppi_active;
- u32 __percpu *saved_ppi_conf;
-#endif
- struct irq_domain *domain;
- unsigned int gic_irqs;
-#ifdef CONFIG_GIC_NON_BANKED
- void __iomem *(*get_base)(union gic_base *);
-#endif
-};
-
-void gic_cpu_init(struct gic_chip_data *gic);
void gic_cpu_save(struct gic_chip_data *gic);
void gic_cpu_restore(struct gic_chip_data *gic);
-void gic_dist_init(struct gic_chip_data *gic);
void gic_dist_save(struct gic_chip_data *gic);
void gic_dist_restore(struct gic_chip_data *gic);
-void gic_pm_init(struct gic_chip_data *gic);
-
-int gic_of_setup(struct device_node *node, void __iomem **dist_base,
- void __iomem **cpu_base, u32 *percpu_offset);
+int gic_of_setup(struct device_node *node, struct device *dev,
+ struct gic_chip_data **gic);
+void gic_of_teardown(struct gic_chip_data *gic);
int gic_init_bases(struct gic_chip_data *gic, int irq_start,
- void __iomem *dist_base, void __iomem *cpu_base,
- u32 percpu_offset, struct fwnode_handle *handle,
- const char *name);
+ struct fwnode_handle *handle, const char *name);
void gic_handle_cascade_irq(struct irq_desc *desc);