aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/irqchip/irq-gic.c
diff options
context:
space:
mode:
authorMarc Zyngier <marc.zyngier@arm.com>2015-09-13 07:14:31 -0400
committerThomas Gleixner <tglx@linutronix.de>2015-09-15 11:06:29 -0400
commit12e14066f4835f5ee1ca795f0309415b54c067a9 (patch)
tree59c892804e516258e31b57dbad4d21007f033e00 /drivers/irqchip/irq-gic.c
parente4084a16bbe07957811c75dfb7c9bf25c5862ba0 (diff)
irqchip/GIC: Add workaround for aliased GIC400
The GICv2 architecture mandates that the two 4kB GIC regions are contiguous, and on two separate physical pages (so that access to the second page can be trapped by a hypervisor). This doesn't work very well when PAGE_SIZE is 64kB. A relatively common hack^Wway to work around this is to alias each 4kB region over its own 64kB page. Of course in this case, the base address you want to use is not really the begining of the region, but base + 60kB (so that you get a contiguous 8kB region over two distinct pages). Normally, this would be described in DT with a new property, but some HW is already out there, and the firmware makes sure that it will override whatever you put in the GIC node. Duh. And of course, said firmware source code is not available, despite being based on u-boot. The workaround is to detect the case where the CPU interface size is set to 128kB, and verify the aliasing by checking that the ID register for GIC400 (which is the only GIC wired this way so far) is the same at base and base + 0xF000. In this case, we update the GIC base address and let it roll. And if you feel slightly sick by looking at this, rest assured that I do too... Reported-by: Julien Grall <julien.grall@citrix.com> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com> Cc: linux-arm-kernel@lists.infradead.org Cc: Stuart Yoder <stuart.yoder@freescale.com> Cc: Pavel Fedin <p.fedin@samsung.com> Cc: Jason Cooper <jason@lakedaemon.net> Link: http://lkml.kernel.org/r/1442142873-20213-2-git-send-email-marc.zyngier@arm.com Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'drivers/irqchip/irq-gic.c')
-rw-r--r--drivers/irqchip/irq-gic.c44
1 files changed, 39 insertions, 5 deletions
diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index e6b7ed537952..a9470574c031 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -1119,12 +1119,49 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start,
1119#ifdef CONFIG_OF 1119#ifdef CONFIG_OF
1120static int gic_cnt __initdata; 1120static int gic_cnt __initdata;
1121 1121
1122static bool gic_check_eoimode(struct device_node *node, void __iomem **base)
1123{
1124 struct resource cpuif_res;
1125
1126 of_address_to_resource(node, 1, &cpuif_res);
1127
1128 if (!is_hyp_mode_available())
1129 return false;
1130 if (resource_size(&cpuif_res) < SZ_8K)
1131 return false;
1132 if (resource_size(&cpuif_res) == SZ_128K) {
1133 u32 val_low, val_high;
1134
1135 /*
1136 * Verify that we have the first 4kB of a GIC400
1137 * aliased over the first 64kB by checking the
1138 * GICC_IIDR register on both ends.
1139 */
1140 val_low = readl_relaxed(*base + GIC_CPU_IDENT);
1141 val_high = readl_relaxed(*base + GIC_CPU_IDENT + 0xf000);
1142 if ((val_low & 0xffff0fff) != 0x0202043B ||
1143 val_low != val_high)
1144 return false;
1145
1146 /*
1147 * Move the base up by 60kB, so that we have a 8kB
1148 * contiguous region, which allows us to use GICC_DIR
1149 * at its normal offset. Please pass me that bucket.
1150 */
1151 *base += 0xf000;
1152 cpuif_res.start += 0xf000;
1153 pr_warn("GIC: Adjusting CPU interface base to %pa",
1154 &cpuif_res.start);
1155 }
1156
1157 return true;
1158}
1159
1122static int __init 1160static int __init
1123gic_of_init(struct device_node *node, struct device_node *parent) 1161gic_of_init(struct device_node *node, struct device_node *parent)
1124{ 1162{
1125 void __iomem *cpu_base; 1163 void __iomem *cpu_base;
1126 void __iomem *dist_base; 1164 void __iomem *dist_base;
1127 struct resource cpu_res;
1128 u32 percpu_offset; 1165 u32 percpu_offset;
1129 int irq; 1166 int irq;
1130 1167
@@ -1137,14 +1174,11 @@ gic_of_init(struct device_node *node, struct device_node *parent)
1137 cpu_base = of_iomap(node, 1); 1174 cpu_base = of_iomap(node, 1);
1138 WARN(!cpu_base, "unable to map gic cpu registers\n"); 1175 WARN(!cpu_base, "unable to map gic cpu registers\n");
1139 1176
1140 of_address_to_resource(node, 1, &cpu_res);
1141
1142 /* 1177 /*
1143 * Disable split EOI/Deactivate if either HYP is not available 1178 * Disable split EOI/Deactivate if either HYP is not available
1144 * or the CPU interface is too small. 1179 * or the CPU interface is too small.
1145 */ 1180 */
1146 if (gic_cnt == 0 && (!is_hyp_mode_available() || 1181 if (gic_cnt == 0 && !gic_check_eoimode(node, &cpu_base))
1147 resource_size(&cpu_res) < SZ_8K))
1148 static_key_slow_dec(&supports_deactivate); 1182 static_key_slow_dec(&supports_deactivate);
1149 1183
1150 if (of_property_read_u32(node, "cpu-offset", &percpu_offset)) 1184 if (of_property_read_u32(node, "cpu-offset", &percpu_offset))