summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLorenzo Pieralisi <lorenzo.pieralisi@arm.com>2011-11-17 17:20:36 +0000
committerJon Medhurst <tixy@linaro.org>2012-07-17 09:57:56 +0100
commit184c91540802cff92019a9cbb88afcb3c785983f (patch)
tree68ec8dc36462c0e5527307e86f674235ec70436a
parentc7ba32ea421c5e6f33f8c30c2c5fe83e4f03de48 (diff)
downloadvexpress-a9-184c91540802cff92019a9cbb88afcb3c785983f.tar.gz
ARM: gic: add cpuif topology description
In order to set up a proper logical to per-cpu interrupt controller IF mapping, the GIC interrupt controller device tree bindings must be enhanced to define the CPU IF id for all present CPUs. GIC CPU IF ids are needed to send interprocessor IPIs and to set affinity levels. Since the way CPU IF ids are wired depends on the specific system design, they cannot be extrapolated or probed in HW by the boot CPU, so a binding to define them is needed to set-up the system properly. This patch adds a logical map of per-cpu interrupt controller identifiers. The newly introduced per-cpu IF map has to be initialized by the GIC driver so that interprocessor interrupts and affinity levels can be set accordingly in an SMP system, with a proper 1:1 relation between per-cpu IF ids and logical cpu indexes. This patch adds a function that parses the device tree properties and initializes the cpu interfaces ids properly according to the latest GIC device tree bindings. If CONFIG_OF is not enabled, per-cpu CPU IF mappings are defined as cpu_logical_map(), leaving the current functionality unchanged. The GIC device tree bindings documentation is updated by the patch accordingly. Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com> Conflicts: arch/arm/common/gic.c
-rw-r--r--Documentation/devicetree/bindings/arm/gic.txt70
-rw-r--r--arch/arm/common/gic.c94
2 files changed, 160 insertions, 4 deletions
diff --git a/Documentation/devicetree/bindings/arm/gic.txt b/Documentation/devicetree/bindings/arm/gic.txt
index 62eb8df1e08..7c507bf99e7 100644
--- a/Documentation/devicetree/bindings/arm/gic.txt
+++ b/Documentation/devicetree/bindings/arm/gic.txt
@@ -88,3 +88,73 @@ Example:
<0x2c006000 0x2000>;
interrupts = <1 9 0xf04>;
};
+
+* ARM Generic Interrupt Controller CPU Interfaces
+
+ARM GIC device tree nodes contain subnodes representing its CPU interfaces.
+
+The main properties required by CPU interface nodes are:
+
+- compatible : "arm,gic-cpuif"
+- cpuif-id : specifies the CPU IF HW identifier
+- cpu : a phandle to the respective CPU node
+
+Example:
+
+ cpus {
+ #size-cells = <0>;
+ #address-cells = <1>;
+
+ CPU0: cpu@0x0 {
+ device_type = "cpu";
+ reg = <0x0>;
+ };
+
+ CPU1: cpu@0x1 {
+ device_type = "cpu";
+ reg = <0x1>;
+ };
+
+ CPU2: cpu@0x100 {
+ device_type = "cpu";
+ reg = <0x100>;
+ };
+
+ CPU3: cpu@0x101 {
+ device_type = "cpu";
+ reg = <0x101>;
+ };
+ };
+
+ intc: interrupt-controller@fff11000 {
+ compatible = "arm,cortex-a9-gic";
+ #interrupt-cells = <3>;
+ #address-cells = <1>;
+ interrupt-controller;
+ reg = <0xfff11000 0x1000>,
+ <0xfff10100 0x100>;
+
+ gic-cpuif@0x0 {
+ compatible = "arm,gic-cpuif";
+ cpuif-id = <0x0>;
+ cpu = <&CPU0>;
+ };
+
+ gic-cpuif@0x1 {
+ compatible = "arm,gic-cpuif";
+ cpuif-id = <0x1>;
+ cpu = <&CPU1>;
+ };
+
+ gic-cpuif@0x2 {
+ compatible = "arm,gic-cpuif";
+ cpuif-id = <0x2>;
+ cpu = <&CPU2>;
+ };
+
+ gic-cpuif@0x3 {
+ compatible = "arm,gic-cpuif";
+ cpuif-id = <0x3>;
+ cpu = <&CPU3>;
+ };
+ };
diff --git a/arch/arm/common/gic.c b/arch/arm/common/gic.c
index aa526998418..5ff990a765f 100644
--- a/arch/arm/common/gic.c
+++ b/arch/arm/common/gic.c
@@ -137,6 +137,83 @@ static inline unsigned int gic_irq(struct irq_data *d)
return d->hwirq;
}
+#ifdef CONFIG_OF
+static u32 gic_cpuif_logical_map[NR_CPUS];
+#define cpuif_logical_map(cpu) gic_cpuif_logical_map[cpu]
+
+/*
+ * Create a mapping of GIC CPU IF numbers to logical cpus through the device
+ * tree. GIC CPU IF are linked to the respective cpu nodes through the "cpu"
+ * phandle.
+ */
+static void __init gic_init_if_maps(struct gic_chip_data *gic)
+{
+ struct device_node *ncpu, *gic_cpuif;
+ struct irq_domain *domain = gic->domain;
+ int i;
+
+ if (WARN_ON(!domain || !domain->of_node))
+ return;
+
+ for_each_child_of_node(domain->of_node, gic_cpuif) {
+ const u32 *cpuif_hwid, *mpidr;
+ int len;
+
+ if (!of_device_is_compatible(gic_cpuif, "arm,gic-cpuif"))
+ continue;
+
+ pr_debug(" * %s...\n", gic_cpuif->full_name);
+
+ ncpu = of_parse_phandle(gic_cpuif, "cpu", 0);
+
+ if (!ncpu) {
+ pr_err(" * %s missing cpu phandle\n",
+ gic_cpuif->full_name);
+ continue;
+ }
+
+ mpidr = of_get_property(ncpu, "reg", &len);
+
+ if (!mpidr || len != 4) {
+ pr_err(" * %s missing reg property\n",
+ ncpu->full_name);
+ continue;
+ }
+
+ cpuif_hwid = of_get_property(gic_cpuif, "cpuif-id", &len);
+
+ if (!cpuif_hwid || len != 4) {
+ pr_err(" * %s missing cpuif-id property\n",
+ gic_cpuif->full_name);
+ continue;
+ }
+
+ /*
+ * Do the logical enumeration once in arm_dt_init_cpu_maps and
+ * use it again here to avoid logical numbering mix-ups between
+ * cpu and interrupt controller ids
+ */
+
+ i = get_logical_index(be32_to_cpup(mpidr));
+
+ if (i < 0) {
+ pr_err(" * %s mpidr mismatch\n",
+ ncpu->full_name);
+ continue;
+ }
+
+ if (!i)
+ printk(KERN_INFO "Booting Linux on GIC CPU IF 0x%x\n",
+ be32_to_cpup(cpuif_hwid));
+
+ cpuif_logical_map(i) = be32_to_cpup(cpuif_hwid);
+ }
+}
+#else
+static inline void gic_init_if_maps(struct gic_chip_data *gic) {}
+#define cpuif_logical_map(cpu) cpu_logical_map(cpu)
+#endif
+
/*
* Routines to acknowledge, disable and enable interrupts
*/
@@ -242,7 +319,7 @@ static int gic_set_affinity(struct irq_data *d, const struct cpumask *mask_val,
return -EINVAL;
mask = 0xff << shift;
- bit = 1 << (cpu_logical_map(cpu) + shift);
+ bit = 1 << (cpuif_logical_map(cpu) + shift);
raw_spin_lock(&irq_controller_lock);
val = readl_relaxed(reg) & ~mask;
@@ -349,7 +426,7 @@ static void __init gic_dist_init(struct gic_chip_data *gic)
u32 cpumask;
unsigned int gic_irqs = gic->gic_irqs;
void __iomem *base = gic_data_dist_base(gic);
- u32 cpu = cpu_logical_map(smp_processor_id());
+ u32 cpu = cpuif_logical_map(smp_processor_id());
cpumask = 1 << cpu;
cpumask |= cpumask << 8;
@@ -651,6 +728,7 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start,
BUG_ON(gic_nr >= MAX_GIC_NR);
gic = &gic_data[gic_nr];
+
#ifdef CONFIG_GIC_NON_BANKED
if (percpu_offset) { /* Frankein-GIC without banked registers... */
unsigned int cpu;
@@ -665,7 +743,8 @@ 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);
+ unsigned long offset =
+ percpu_offset * cpuif_logical_map(cpu);
*per_cpu_ptr(gic->dist_base.percpu_base, cpu) = dist_base + offset;
*per_cpu_ptr(gic->cpu_base.percpu_base, cpu) = cpu_base + offset;
}
@@ -716,6 +795,13 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start,
if (WARN_ON(!gic->domain))
return;
+ /*
+ * create the logical/physical mapping just for the
+ * primary GIC
+ */
+ if (gic_nr == 0)
+ gic_init_if_maps(gic);
+
gic_chip.flags |= gic_arch_extn.flags;
gic_dist_init(gic);
gic_cpu_init(gic);
@@ -737,7 +823,7 @@ void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
/* Convert our logical CPU mask into a physical one. */
for_each_cpu(cpu, mask)
- map |= 1 << cpu_logical_map(cpu);
+ map |= 1 << cpuif_logical_map(cpu);
/*
* Ensure that stores to Normal memory are visible to the