aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSoren Brinkmann <soren.brinkmann@xilinx.com>2014-09-02 17:19:12 -0400
committerMichal Simek <michal.simek@xilinx.com>2014-09-16 06:55:09 -0400
commit50c7960a4517d6c93226351cd8c43c86f104c919 (patch)
tree354342e21f9dfc23fe2d0412f4df7dc3301e928e
parent18aebf116b494101841f109f07e0d6a0aad9a46e (diff)
ARM: zynq: Synchronise zynq_cpu_die/kill
Avoid races and add synchronisation between the arch specific kill and die routines. The same synchronisation issue was fixed on IMX platform by this commit: "ARM: imx: fix sync issue between imx_cpu_die and imx_cpu_kill" (sha1: 2f3edfd7e27ad4206acbc2ae99c9df5f46353024) Signed-off-by: Soren Brinkmann <soren.brinkmann@xilinx.com> Signed-off-by: Michal Simek <michal.simek@xilinx.com>
-rw-r--r--arch/arm/mach-zynq/common.h2
-rw-r--r--arch/arm/mach-zynq/hotplug.c2
-rw-r--r--arch/arm/mach-zynq/platsmp.c6
-rw-r--r--arch/arm/mach-zynq/slcr.c43
4 files changed, 52 insertions, 1 deletions
diff --git a/arch/arm/mach-zynq/common.h b/arch/arm/mach-zynq/common.h
index 0edbb6997b1c..24d6340d3fb6 100644
--- a/arch/arm/mach-zynq/common.h
+++ b/arch/arm/mach-zynq/common.h
@@ -24,6 +24,8 @@ extern int zynq_early_slcr_init(void);
24extern void zynq_slcr_system_reset(void); 24extern void zynq_slcr_system_reset(void);
25extern void zynq_slcr_cpu_stop(int cpu); 25extern void zynq_slcr_cpu_stop(int cpu);
26extern void zynq_slcr_cpu_start(int cpu); 26extern void zynq_slcr_cpu_start(int cpu);
27extern bool zynq_slcr_cpu_state_read(int cpu);
28extern void zynq_slcr_cpu_state_write(int cpu, bool die);
27extern u32 zynq_slcr_get_device_id(void); 29extern u32 zynq_slcr_get_device_id(void);
28 30
29#ifdef CONFIG_SMP 31#ifdef CONFIG_SMP
diff --git a/arch/arm/mach-zynq/hotplug.c b/arch/arm/mach-zynq/hotplug.c
index 366f46c91365..fe44a05677e2 100644
--- a/arch/arm/mach-zynq/hotplug.c
+++ b/arch/arm/mach-zynq/hotplug.c
@@ -19,6 +19,8 @@
19 */ 19 */
20void zynq_platform_cpu_die(unsigned int cpu) 20void zynq_platform_cpu_die(unsigned int cpu)
21{ 21{
22 zynq_slcr_cpu_state_write(cpu, true);
23
22 /* 24 /*
23 * there is no power-control hardware on this platform, so all 25 * there is no power-control hardware on this platform, so all
24 * we can do is put the core into WFI; this is safe as the calling 26 * we can do is put the core into WFI; this is safe as the calling
diff --git a/arch/arm/mach-zynq/platsmp.c b/arch/arm/mach-zynq/platsmp.c
index 6c7843108c7f..06415eeba7e6 100644
--- a/arch/arm/mach-zynq/platsmp.c
+++ b/arch/arm/mach-zynq/platsmp.c
@@ -127,6 +127,12 @@ static void zynq_secondary_init(unsigned int cpu)
127#ifdef CONFIG_HOTPLUG_CPU 127#ifdef CONFIG_HOTPLUG_CPU
128static int zynq_cpu_kill(unsigned cpu) 128static int zynq_cpu_kill(unsigned cpu)
129{ 129{
130 unsigned long timeout = jiffies + msecs_to_jiffies(50);
131
132 while (zynq_slcr_cpu_state_read(cpu))
133 if (time_after(jiffies, timeout))
134 return 0;
135
130 zynq_slcr_cpu_stop(cpu); 136 zynq_slcr_cpu_stop(cpu);
131 return 1; 137 return 1;
132} 138}
diff --git a/arch/arm/mach-zynq/slcr.c b/arch/arm/mach-zynq/slcr.c
index c43a2d16e223..d4cb50cf97c0 100644
--- a/arch/arm/mach-zynq/slcr.c
+++ b/arch/arm/mach-zynq/slcr.c
@@ -138,6 +138,8 @@ void zynq_slcr_cpu_start(int cpu)
138 zynq_slcr_write(reg, SLCR_A9_CPU_RST_CTRL_OFFSET); 138 zynq_slcr_write(reg, SLCR_A9_CPU_RST_CTRL_OFFSET);
139 reg &= ~(SLCR_A9_CPU_CLKSTOP << cpu); 139 reg &= ~(SLCR_A9_CPU_CLKSTOP << cpu);
140 zynq_slcr_write(reg, SLCR_A9_CPU_RST_CTRL_OFFSET); 140 zynq_slcr_write(reg, SLCR_A9_CPU_RST_CTRL_OFFSET);
141
142 zynq_slcr_cpu_state_write(cpu, false);
141} 143}
142 144
143/** 145/**
@@ -154,8 +156,47 @@ void zynq_slcr_cpu_stop(int cpu)
154} 156}
155 157
156/** 158/**
157 * zynq_slcr_init - Regular slcr driver init 159 * zynq_slcr_cpu_state - Read/write cpu state
160 * @cpu: cpu number
158 * 161 *
162 * SLCR_REBOOT_STATUS save upper 2 bits (31/30 cpu states for cpu0 and cpu1)
163 * 0 means cpu is running, 1 cpu is going to die.
164 *
165 * Return: true if cpu is running, false if cpu is going to die
166 */
167bool zynq_slcr_cpu_state_read(int cpu)
168{
169 u32 state;
170
171 state = readl(zynq_slcr_base + SLCR_REBOOT_STATUS_OFFSET);
172 state &= 1 << (31 - cpu);
173
174 return !state;
175}
176
177/**
178 * zynq_slcr_cpu_state - Read/write cpu state
179 * @cpu: cpu number
180 * @die: cpu state - true if cpu is going to die
181 *
182 * SLCR_REBOOT_STATUS save upper 2 bits (31/30 cpu states for cpu0 and cpu1)
183 * 0 means cpu is running, 1 cpu is going to die.
184 */
185void zynq_slcr_cpu_state_write(int cpu, bool die)
186{
187 u32 state, mask;
188
189 state = readl(zynq_slcr_base + SLCR_REBOOT_STATUS_OFFSET);
190 mask = 1 << (31 - cpu);
191 if (die)
192 state |= mask;
193 else
194 state &= ~mask;
195 writel(state, zynq_slcr_base + SLCR_REBOOT_STATUS_OFFSET);
196}
197
198/**
199 * zynq_slcr_init - Regular slcr driver init
159 * Return: 0 on success, negative errno otherwise. 200 * Return: 0 on success, negative errno otherwise.
160 * 201 *
161 * Called early during boot from platform code to remap SLCR area. 202 * Called early during boot from platform code to remap SLCR area.