[linux-yocto] [PATCH 8/9] arch/arm/mach-axxia: adding atomicity to per_cpu data manipulation

Daniel Dragomir daniel.dragomir at windriver.com
Thu Mar 9 08:22:29 PST 2017


From: Marek Bykowski <marek.bykowski at gmail.com>

Also, remove the loop in the IPI handler all together

INFO: rcu_sched self-detected stall on CPU

6x IPIs (of kernel armv7) are multiplexed on a single GIC/IPI2.
The race shows up in reading and subsequently modifying the IPI
of a core that services the IPI. See illustration below: core0 and
core1 are to execute an IRQ routine on a core4. They need to mux
the IPI using a per_cpu msg variable of a core4 destined. Core0
sets the msg and raises IPI to core4. Core4 demuxes the msg from core0
and services the IPI. Core4 before leaving the interrupt handler
checks for any interrupt pending. It sees there is one from core1.
However the core1 while setting the IPI of itself set along the IPI
already handled. It results in core0 never gets its IPI acked and hence
waits infinitely.

core0:           core1:            core4:
read info->msg
set bit X
send_IPI
                 read info->msg
                                   xchg info->msg with 0 (bit X set)
                 set bit Y (X set) do something
                 send_IPI reg.     process bit X
                                   check for info->msg (Y and X set)
                                   loop for Y and X (X set again!!!)

Signed-off-by: Matija Glavinic Pecotic <matija.glavinic-pecotic.ext at nokia.com>
Signed-off-by: Marek Bykowski <marek.bykowski at gmail.com>
---
 arch/arm/mach-axxia/axxia-gic.c | 32 +++++++++++++++-----------------
 1 file changed, 15 insertions(+), 17 deletions(-)

diff --git a/arch/arm/mach-axxia/axxia-gic.c b/arch/arm/mach-axxia/axxia-gic.c
index e086277..2a072f4 100644
--- a/arch/arm/mach-axxia/axxia-gic.c
+++ b/arch/arm/mach-axxia/axxia-gic.c
@@ -85,7 +85,7 @@ enum axxia_mux_msg_type {
 };
 
 struct axxia_mux_msg {
-	u32 msg;
+	unsigned long msg;
 };
 
 static DEFINE_PER_CPU_SHARED_ALIGNED(struct axxia_mux_msg, ipi_mux_msg);
@@ -98,7 +98,7 @@ static void muxed_ipi_message_pass(const struct cpumask *mask,
 
 	for_each_cpu(cpu, mask) {
 		info = &per_cpu(ipi_mux_msg, cpu_logical_map(cpu));
-		info->msg |= 1 << ipi_num;
+		set_bit(ipi_num, &info->msg);
 	}
 }
 
@@ -108,21 +108,19 @@ static void axxia_ipi_demux(struct pt_regs *regs)
 	struct axxia_mux_msg *info = this_cpu_ptr(&ipi_mux_msg);
 	u32 all;
 
-	do {
-		all = xchg(&info->msg, 0);
-		if (all & (1 << MUX_MSG_CALL_FUNC))
-			handle_IPI(3, regs); /* 3 = ARM IPI_CALL_FUNC */
-		if (all & (1 << MUX_MSG_CALL_FUNC_SINGLE))
-			handle_IPI(4, regs); /* 4 = ARM IPI_CALL_FUNC_SINGLE */
-		if (all & (1 << MUX_MSG_CPU_STOP))
-			handle_IPI(5, regs); /* 5 = ARM IPI_CPU_STOP */
-		if (all & (1 << MUX_MSG_IRQ_WORK))
-			handle_IPI(6, regs); /* 6 = ARM IPI_IRQ_WORK */
-		if (all & (1 << MUX_MSG_COMPLETION))
-			handle_IPI(7, regs); /* 7 = ARM IPI_COMPLETION */
-		if (all & (1 << MUX_MSG_CPU_WAKEUP))
-			handle_IPI(0, regs); /* 0 = ARM IPI_WAKEUP */
-	} while (info->msg);
+	all = xchg(&info->msg, 0);
+	if (all & (1 << MUX_MSG_CALL_FUNC))
+		handle_IPI(3, regs); /* 3 = ARM IPI_CALL_FUNC */
+	if (all & (1 << MUX_MSG_CALL_FUNC_SINGLE))
+		handle_IPI(4, regs); /* 4 = ARM IPI_CALL_FUNC_SINGLE */
+	if (all & (1 << MUX_MSG_CPU_STOP))
+		handle_IPI(5, regs); /* 5 = ARM IPI_CPU_STOP */
+	if (all & (1 << MUX_MSG_IRQ_WORK))
+		handle_IPI(6, regs); /* 6 = ARM IPI_IRQ_WORK */
+	if (all & (1 << MUX_MSG_COMPLETION))
+		handle_IPI(7, regs); /* 7 = ARM IPI_COMPLETION */
+	if (all & (1 << MUX_MSG_CPU_WAKEUP))
+		handle_IPI(0, regs); /* 0 = ARM IPI_WAKEUP */
 }
 #endif
 
-- 
2.7.4



More information about the linux-yocto mailing list