[linux-yocto] [PATCH 26/42] ARM: irq: Return error when set_affinity is called from hotplug

Cristian Bercaru cristian.bercaru at windriver.com
Thu Jun 11 01:32:11 PDT 2015


From: Magnus Karlsson <magnus.karlsson at intel.com>

Set_affinity now returns an error when called from the hotplug
path. This will be in place until we implement a way to migrate
interrupts between clusters during a hotplug operation. Note that
set_affinity from user space works as before.

Signed-off-by: Magnus Karlsson <magnus.karlsson at intel.com>
---
 arch/arm/mach-axxia/axxia-gic.c |  135 ++++++++++++++++++++++-----------------
 1 file changed, 77 insertions(+), 58 deletions(-)

diff --git a/arch/arm/mach-axxia/axxia-gic.c b/arch/arm/mach-axxia/axxia-gic.c
index 9d3ac12..a7656a7 100644
--- a/arch/arm/mach-axxia/axxia-gic.c
+++ b/arch/arm/mach-axxia/axxia-gic.c
@@ -497,6 +497,37 @@ static void gic_clr_affinity_remote(void *info)
 	_gic_set_affinity(rpc->d, rpc->mask_val, true);
 }
 
+static bool on_same_cluster(u32 pcpu1, u32 pcpu2)
+{
+	return pcpu1 / CORES_PER_CLUSTER == pcpu2 / CORES_PER_CLUSTER;
+}
+
+static int exec_remote_set_affinity(bool clr_affinity, u32 cpu,
+				    struct irq_data *d,
+				    const struct cpumask *mask_val,
+				    bool force)
+{
+	int ret = IRQ_SET_MASK_OK;
+
+	if (force == false) {
+		gic_rpc_data.d = d;
+		gic_rpc_data.mask_val = mask_val;
+		if (clr_affinity == true) {
+			gic_rpc_data.oldcpu = cpu;
+			gic_rpc_data.func_mask |= CLR_AFFINITY;
+		} else {
+			gic_rpc_data.cpu = cpu;
+			gic_rpc_data.func_mask |= SET_AFFINITY;
+		}
+
+	} else {
+		pr_warn("Set affinity for hotplug not implemented.\n");
+		return -ENOSYS;
+	}
+
+	return ret;
+}
+
 static int gic_set_affinity(struct irq_data *d,
 			    const struct cpumask *mask_val,
 			    bool force)
@@ -504,6 +535,7 @@ static int gic_set_affinity(struct irq_data *d,
 	unsigned int cpu = cpumask_any_and(mask_val, cpu_online_mask);
 	u32 pcpu = cpu_logical_map(smp_processor_id());
 	unsigned int irqid = gic_irq(d);
+	int ret = IRQ_SET_MASK_OK;
 
 	BUG_ON(!irqs_disabled());
 
@@ -529,14 +561,14 @@ static int gic_set_affinity(struct irq_data *d,
 	 * cluster as the cpu we're currently running on, set the IRQ
 	 * affinity directly. Otherwise, use the RPC mechanism.
 	 */
-	if ((cpu_logical_map(cpu) / CORES_PER_CLUSTER) ==
-		(pcpu / CORES_PER_CLUSTER)) {
+	if (on_same_cluster(cpu_logical_map(cpu), pcpu))
 		_gic_set_affinity(d, mask_val, false);
-	} else {
-		gic_rpc_data.func_mask |= SET_AFFINITY;
-		gic_rpc_data.cpu = cpu;
-		gic_rpc_data.d = d;
-		gic_rpc_data.mask_val = mask_val;
+	else{
+		ret = exec_remote_set_affinity(false, cpu, d, mask_val,
+					       force);
+
+		if (ret != IRQ_SET_MASK_OK)
+			return ret;
 	}
 
 	/*
@@ -544,21 +576,28 @@ static int gic_set_affinity(struct irq_data *d,
 	 * different than the prior cluster, clear the IRQ affinity
 	 * on the old cluster.
 	 */
-	if ((irqid != IRQ_PMU) && ((cpu_logical_map(cpu) / CORES_PER_CLUSTER) !=
-		(irq_cpuid[irqid] / CORES_PER_CLUSTER))) {
+	if (!on_same_cluster(cpu_logical_map(cpu), irq_cpuid[irqid]) &&
+	    (irqid != IRQ_PMU)) {
 		/*
 		 * If old cpu assignment falls within the same cluster as
 		 * the cpu we're currently running on, clear the IRQ affinity
 		 * directly. Otherwise, use RPC mechanism.
 		 */
-		if ((irq_cpuid[irqid] / CORES_PER_CLUSTER) ==
-			(pcpu / CORES_PER_CLUSTER)) {
+		if (on_same_cluster(irq_cpuid[irqid], pcpu))
 			_gic_set_affinity(d, mask_val, true);
-		} else {
-			gic_rpc_data.func_mask |= CLR_AFFINITY;
-			gic_rpc_data.oldcpu = irq_cpuid[irqid];
-			gic_rpc_data.d = d;
-			gic_rpc_data.mask_val = mask_val;
+		else
+			ret = exec_remote_set_affinity(true,
+				      get_logical_index(irq_cpuid[irqid]), d,
+				      mask_val, force);
+		if (ret != IRQ_SET_MASK_OK) {
+			/* Need to back out the set operation */
+			if (on_same_cluster(cpu_logical_map(cpu), pcpu))
+				_gic_set_affinity(d, mask_val, true);
+			else
+				exec_remote_set_affinity(true, cpu, d,
+							 mask_val, force);
+
+			return ret;
 		}
 	}
 
@@ -1085,6 +1124,7 @@ static void __cpuinit gic_dist_init(struct gic_chip_data *gic)
 	cpumask |= cpumask << 16;
 
 	writel_relaxed(0, base + GIC_DIST_CTRL);
+
 	/*
 	 * Set all global interrupts to be level triggered, active low.
 	 */
@@ -1106,8 +1146,6 @@ static void __cpuinit gic_dist_init(struct gic_chip_data *gic)
 	for (i = 32; i < gic_irqs; i += 4)
 		writel_relaxed(0xa0a0a0a0, base + GIC_DIST_PRI + i * 4 / 4);
 
-
-	/*################################# TARGET ####################################*/
 	/*
 	 * Disable all interrupts.  Leave the PPI and SGIs alone
 	 * as these enables are banked registers.
@@ -1119,26 +1157,26 @@ static void __cpuinit gic_dist_init(struct gic_chip_data *gic)
 	/*
 	 * Set Axxia IPI interrupts for all CPUs in this cluster.
 	 */
+
 	for (i = IPI0_CPU0; i < MAX_AXM_IPI_NUM; i++) {
 		cpumask_8 = 1 << ((i - IPI0_CPU0) % 4);
 		writeb_relaxed(cpumask_8, base + GIC_DIST_TARGET + i);
-	}
-
-	/*
-	 * Set the PMU IRQ to the first cpu in this cluster.
-	 */
-	writeb_relaxed(0x01, base + GIC_DIST_TARGET + IRQ_PMU);
+		}
 
-	/*
-	 * Set Axxia IPI interrupts to be edge triggered.
-	 */
+		/*
+		 * Set the PMU IRQ to the first cpu in this cluster.
+		 */
+		writeb_relaxed(0x01, base + GIC_DIST_TARGET + IRQ_PMU);
 
-	for (i = IPI0_CPU0; i < MAX_AXM_IPI_NUM; i++) {
-		confmask = 0x2 << ((i % 16) * 2);
-		confoff = (i / 16) * 4;
-		val = readl_relaxed(base + GIC_DIST_CONFIG + confoff);
-		val |= confmask;
-		writel_relaxed(val, base + GIC_DIST_CONFIG + confoff);
+		/*
+		 * Set Axxia IPI interrupts to be edge triggered.
+		 */
+		for (i = IPI0_CPU0; i < MAX_AXM_IPI_NUM; i++) {
+			confmask = 0x2 << ((i % 16) * 2);
+			confoff = (i / 16) * 4;
+			val = readl_relaxed(base + GIC_DIST_CONFIG + confoff);
+			val |= confmask;
+			writel_relaxed(val, base + GIC_DIST_CONFIG + confoff);
 	}
 
 	/*
@@ -1151,7 +1189,7 @@ static void __cpuinit gic_dist_init(struct gic_chip_data *gic)
 		enablemask = 1 << (i % 32);
 		enableoff = (i / 32) * 4;
 		writel_relaxed(enablemask,
-				base + GIC_DIST_ENABLE_SET + enableoff);
+			       base + GIC_DIST_ENABLE_SET + enableoff);
 	}
 
 	/*
@@ -1164,7 +1202,7 @@ static void __cpuinit gic_dist_init(struct gic_chip_data *gic)
 	writel_relaxed(1, base + GIC_DIST_CTRL);
 }
 
-static void  gic_cpu_init(struct gic_chip_data *gic)
+static void __cpuinit gic_cpu_init(struct gic_chip_data *gic)
 {
 
 	void __iomem *dist_base = gic_data_dist_base(gic);
@@ -1178,34 +1216,14 @@ static void  gic_cpu_init(struct gic_chip_data *gic)
 	 */
 	writel_relaxed(0xffffffff, dist_base + GIC_DIST_ENABLE_CLEAR);
 
-#ifdef CONFIG_HOTPLUG_CPU
-	if (!cluster_power_up[cluster]) {
-#endif
-		writel_relaxed(0, dist_base + GIC_DIST_CTRL);
-		for (i = IPI0_CPU0; i < MAX_AXM_IPI_NUM; i++) {
-			cpumask_8 = 1 << ((i - IPI0_CPU0) % 4);
-			enablemask = 1 << (i % 32);
-			enableoff = (i / 32) * 4;
-			ccpu = (cluster * 4) + ((i - IPI0_CPU0) % CORES_PER_CLUSTER);
-			if (ccpu == cpu) {
-				writeb_relaxed(cpumask_8, dist_base + GIC_DIST_TARGET + i);
-				writel_relaxed(enablemask, dist_base + GIC_DIST_ENABLE_SET + enableoff);
-			}
-		}
-		writel_relaxed(1, dist_base + GIC_DIST_CTRL);
-#ifdef CONFIG_HOTPLUG_CPU
-	}
-#endif
-
 	/*
-	 * Set priority on PPI and SGI interrupts
-	 */
+	* Set priority on PPI and SGI interrupts
+	*/
 	for (i = 0; i < 32; i += 4)
 		writel_relaxed(0xa0a0a0a0,
 				dist_base + GIC_DIST_PRI + i * 4 / 4);
 
 	writel_relaxed(0xf0, base + GIC_CPU_PRIMASK);
-
 	writel_relaxed(1, base + GIC_CPU_CTRL);
 
 }
@@ -1416,13 +1434,14 @@ void __cpuinit axxia_gic_secondary_init(void)
 	gic_dist_init(gic);
 	gic_cpu_init(&gic_data);
 }
-#endif
 
 void __cpuinit axxia_hotplug_gic_secondary_init(void)
 {
 	gic_cpu_init(&gic_data);
 }
 
+#endif
+
 #ifdef CONFIG_OF
 
 int __init axxia_gic_of_init(struct device_node *node,
-- 
1.7.9.5



More information about the linux-yocto mailing list