gem5: Add support for gem5's extended GIC mode

gem5's GIC model contains a gem5-specific extension that enables
support for up to 255 CPUs. When enabled, the GIC interprets registers
where a CPU bitmask would normally be present as a CPU ID.

This extensions need to be enabled by setting the OF compatible string
to "gem5,gic".

Kudos to Matt Evans for the original version of this patch.

Change-Id: I1a8776f1adcbfcd97813573050a8595176de6a7e
Signed-off-by: Andreas Sandberg <andreas.sandberg@arm.com>
Reviewed-by: Stephan Diestelhorst <stephan.diestelhorst@arm.com>
Reviewed-by: Curtis Dunham <curtis.dunham@arm.com>
[Ported to 4.4]
Signed-off-by: Andreas Sandberg <andreas.sandberg@arm.com>
[gabor.dozsa@arm.com: Ported to 4.9 and merged initialization fixup from 4.4.]
Signed-off-by: Andreas Sandberg <andreas.sandberg@arm.com>
diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index 651d726..2b06254 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -89,6 +89,8 @@
 #ifdef CONFIG_GIC_NON_BANKED
 	void __iomem *(*get_base)(union gic_base *);
 #endif
+       bool probe_gem5_extensions;
+       bool gem5_extensions;
 };
 
 #ifdef CONFIG_BL_SWITCHER
@@ -117,8 +119,12 @@
  * The GIC mapping of CPU interfaces does not necessarily match
  * the logical CPU numbering.  Let's use a mapping as returned
  * by the GIC itself.
+ *
+ * The CPU map normally contains a bitmask that maps interrupts to
+ * CPUs. When gem5 extensions have been enabled, it represents an 8
+ * bit CPU ID instead.
  */
-#define NR_GIC_CPU_IF 8
+#define NR_GIC_CPU_IF 256
 static u8 gic_cpu_map[NR_GIC_CPU_IF] __read_mostly;
 
 static struct static_key supports_deactivate = STATIC_KEY_INIT_TRUE;
@@ -439,16 +445,24 @@
 	void __iomem *base = gic_data_dist_base(gic);
 	u32 mask, i;
 
-	for (i = mask = 0; i < 32; i += 4) {
-		mask = readl_relaxed(base + GIC_DIST_TARGET + i);
-		mask |= mask >> 16;
-		mask |= mask >> 8;
-		if (mask)
-			break;
-	}
+	if (!gic->gem5_extensions) {
+		for (i = mask = 0; i < 32; i += 4) {
+			mask = readl_relaxed(base + GIC_DIST_TARGET + i);
+			mask |= mask >> 16;
+			mask |= mask >> 8;
+			if (mask)
+				break;
+		}
 
-	if (!mask && num_possible_cpus() > 1)
-		pr_crit("GIC CPU mask not found - kernel will fail to boot.\n");
+		if (!mask && num_possible_cpus() > 1)
+			pr_crit("GIC CPU mask not found - kernel will fail "
+				"to boot.\n");
+	} else {
+		/* This isn't a mask, it's an actual CPU number.  It always
+		 * exists in TARGETR0.
+		 */
+		mask = readl_relaxed(base + GIC_DIST_TARGET);
+	}
 
 	return mask;
 }
@@ -522,9 +536,11 @@
 		 * Clear our mask from the other map entries in case they're
 		 * still undefined.
 		 */
-		for (i = 0; i < NR_GIC_CPU_IF; i++)
-			if (i != cpu)
-				gic_cpu_map[i] &= ~cpu_mask;
+		if (!gic->gem5_extensions) {
+			for (i = 0; i < NR_GIC_CPU_IF; i++)
+				if (i != cpu)
+					gic_cpu_map[i] &= ~cpu_mask;
+		}
 	}
 
 	gic_cpu_config(dist_base, NULL);
@@ -787,6 +803,16 @@
 #endif
 
 #ifdef CONFIG_SMP
+static int gic_cpu_map_initialized(const struct cpumask *mask)
+{
+	int cpu;
+	for_each_cpu(cpu, mask) {
+		if (gic_cpu_map[cpu] == 0xff)
+			return 0;
+	}
+	return 1;
+}
+
 static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
 {
 	int cpu;
@@ -800,20 +826,36 @@
 	}
 
 	gic_lock_irqsave(flags);
+	if (gic_data[0].gem5_extensions) {
+		dmb(ishst);
+		if (!gic_cpu_map_initialized(mask)) {
+			/* We don't know the CPU mapping yet, so send
+			 * a broadcast */
+			writel_relaxed(0x1 << 24 | irq,
+				       gic_data_dist_base(&gic_data[0]) + GIC_DIST_SOFTINT);
+		} else {
+			/* We can only send one IPI at once, so have
+			 * to loop in here. */
+			for_each_cpu(cpu, mask) {
+				int dest = gic_cpu_map[cpu];
+				writel_relaxed(dest << 16 | irq,
+					       gic_data_dist_base(&gic_data[0]) + GIC_DIST_SOFTINT);
+			}
+		}
+		dmb(ishst);
+	} else {
+		/* Convert our logical CPU mask into a physical one. */
+		for_each_cpu(cpu, mask)
+			map |= gic_cpu_map[cpu];
+		/*
+		* Ensure that stores to Normal memory are visible to the
+		* other CPUs before they observe us issuing the IPI.
+		*/
+		dmb(ishst);
 
-	/* Convert our logical CPU mask into a physical one. */
-	for_each_cpu(cpu, mask)
-		map |= gic_cpu_map[cpu];
-
-	/*
-	 * Ensure that stores to Normal memory are visible to the
-	 * other CPUs before they observe us issuing the IPI.
-	 */
-	dmb(ishst);
-
-	/* this always happens on GIC0 */
-	writel_relaxed(map << 16 | irq, gic_data_dist_base(&gic_data[0]) + GIC_DIST_SOFTINT);
-
+		/* this always happens on GIC0 */
+		writel_relaxed(map << 16 | irq, gic_data_dist_base(&gic_data[0]) + GIC_DIST_SOFTINT);
+	}
 	gic_unlock_irqrestore(flags);
 }
 #endif
@@ -1112,6 +1154,19 @@
 		gic_set_base_accessor(gic, gic_get_common_base);
 	}
 
+	gic->gem5_extensions = false;
+	if (gic->probe_gem5_extensions) {
+#ifndef CONFIG_BL_SWITCHER
+		if (readl_relaxed(gic_data_dist_base(gic) + GIC_DIST_CTR) & 0x100) {
+			pr_info("GIC: Detected gem5 extensions\n");
+			writel_relaxed(0x200, gic_data_dist_base(gic) + GIC_DIST_CTR);
+			gic->gem5_extensions = true;
+		}
+#else
+		WARN(1, "gem5 GIC extensions aren't supported when using the bL switcher.\n");
+#endif
+	}
+
 	/*
 	 * Find out how many interrupts are supported.
 	 * The GIC only supports up to 1020 interrupt sources.
@@ -1395,6 +1450,9 @@
 	if (gic_cnt == 0 && !gic_check_eoimode(node, &gic->raw_cpu_base))
 		static_key_slow_dec(&supports_deactivate);
 
+	gic->probe_gem5_extensions =
+		node && of_device_is_compatible(node, "gem5,gic");
+
 	ret = __gic_init_bases(gic, -1, &node->fwnode);
 	if (ret) {
 		gic_teardown(gic);
@@ -1417,6 +1475,7 @@
 	gic_cnt++;
 	return 0;
 }
+IRQCHIP_DECLARE(gem5_gic, "gem5,gic", gic_of_init);
 IRQCHIP_DECLARE(gic_400, "arm,gic-400", gic_of_init);
 IRQCHIP_DECLARE(arm11mp_gic, "arm,arm11mp-gic", gic_of_init);
 IRQCHIP_DECLARE(arm1176jzf_dc_gic, "arm,arm1176jzf-devchip-gic", gic_of_init);