diff options
author | Soren Brinkmann <soren.brinkmann@xilinx.com> | 2014-09-02 17:19:12 -0400 |
---|---|---|
committer | Michal Simek <michal.simek@xilinx.com> | 2014-09-16 06:55:09 -0400 |
commit | 50c7960a4517d6c93226351cd8c43c86f104c919 (patch) | |
tree | 354342e21f9dfc23fe2d0412f4df7dc3301e928e | |
parent | 18aebf116b494101841f109f07e0d6a0aad9a46e (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.h | 2 | ||||
-rw-r--r-- | arch/arm/mach-zynq/hotplug.c | 2 | ||||
-rw-r--r-- | arch/arm/mach-zynq/platsmp.c | 6 | ||||
-rw-r--r-- | arch/arm/mach-zynq/slcr.c | 43 |
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); | |||
24 | extern void zynq_slcr_system_reset(void); | 24 | extern void zynq_slcr_system_reset(void); |
25 | extern void zynq_slcr_cpu_stop(int cpu); | 25 | extern void zynq_slcr_cpu_stop(int cpu); |
26 | extern void zynq_slcr_cpu_start(int cpu); | 26 | extern void zynq_slcr_cpu_start(int cpu); |
27 | extern bool zynq_slcr_cpu_state_read(int cpu); | ||
28 | extern void zynq_slcr_cpu_state_write(int cpu, bool die); | ||
27 | extern u32 zynq_slcr_get_device_id(void); | 29 | extern 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 | */ |
20 | void zynq_platform_cpu_die(unsigned int cpu) | 20 | void 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 |
128 | static int zynq_cpu_kill(unsigned cpu) | 128 | static 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 | */ | ||
167 | bool 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 | */ | ||
185 | void 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. |