diff options
| -rw-r--r-- | arch/xtensa/kernel/head.S | 5 | ||||
| -rw-r--r-- | arch/xtensa/kernel/smp.c | 34 |
2 files changed, 25 insertions, 14 deletions
diff --git a/arch/xtensa/kernel/head.S b/arch/xtensa/kernel/head.S index da08e75100ab..7f009719304e 100644 --- a/arch/xtensa/kernel/head.S +++ b/arch/xtensa/kernel/head.S | |||
| @@ -276,12 +276,13 @@ should_never_return: | |||
| 276 | 276 | ||
| 277 | movi a2, cpu_start_ccount | 277 | movi a2, cpu_start_ccount |
| 278 | 1: | 278 | 1: |
| 279 | memw | ||
| 279 | l32i a3, a2, 0 | 280 | l32i a3, a2, 0 |
| 280 | beqi a3, 0, 1b | 281 | beqi a3, 0, 1b |
| 281 | movi a3, 0 | 282 | movi a3, 0 |
| 282 | s32i a3, a2, 0 | 283 | s32i a3, a2, 0 |
| 283 | memw | ||
| 284 | 1: | 284 | 1: |
| 285 | memw | ||
| 285 | l32i a3, a2, 0 | 286 | l32i a3, a2, 0 |
| 286 | beqi a3, 0, 1b | 287 | beqi a3, 0, 1b |
| 287 | wsr a3, ccount | 288 | wsr a3, ccount |
| @@ -317,11 +318,13 @@ ENTRY(cpu_restart) | |||
| 317 | rsr a0, prid | 318 | rsr a0, prid |
| 318 | neg a2, a0 | 319 | neg a2, a0 |
| 319 | movi a3, cpu_start_id | 320 | movi a3, cpu_start_id |
| 321 | memw | ||
| 320 | s32i a2, a3, 0 | 322 | s32i a2, a3, 0 |
| 321 | #if XCHAL_DCACHE_IS_WRITEBACK | 323 | #if XCHAL_DCACHE_IS_WRITEBACK |
| 322 | dhwbi a3, 0 | 324 | dhwbi a3, 0 |
| 323 | #endif | 325 | #endif |
| 324 | 1: | 326 | 1: |
| 327 | memw | ||
| 325 | l32i a2, a3, 0 | 328 | l32i a2, a3, 0 |
| 326 | dhi a3, 0 | 329 | dhi a3, 0 |
| 327 | bne a2, a0, 1b | 330 | bne a2, a0, 1b |
diff --git a/arch/xtensa/kernel/smp.c b/arch/xtensa/kernel/smp.c index 932d64689bac..c9fc2c4f71b3 100644 --- a/arch/xtensa/kernel/smp.c +++ b/arch/xtensa/kernel/smp.c | |||
| @@ -195,9 +195,11 @@ static int boot_secondary(unsigned int cpu, struct task_struct *ts) | |||
| 195 | int i; | 195 | int i; |
| 196 | 196 | ||
| 197 | #ifdef CONFIG_HOTPLUG_CPU | 197 | #ifdef CONFIG_HOTPLUG_CPU |
| 198 | cpu_start_id = cpu; | 198 | WRITE_ONCE(cpu_start_id, cpu); |
| 199 | system_flush_invalidate_dcache_range( | 199 | /* Pairs with the third memw in the cpu_restart */ |
| 200 | (unsigned long)&cpu_start_id, sizeof(cpu_start_id)); | 200 | mb(); |
| 201 | system_flush_invalidate_dcache_range((unsigned long)&cpu_start_id, | ||
| 202 | sizeof(cpu_start_id)); | ||
| 201 | #endif | 203 | #endif |
| 202 | smp_call_function_single(0, mx_cpu_start, (void *)cpu, 1); | 204 | smp_call_function_single(0, mx_cpu_start, (void *)cpu, 1); |
| 203 | 205 | ||
| @@ -206,18 +208,21 @@ static int boot_secondary(unsigned int cpu, struct task_struct *ts) | |||
| 206 | ccount = get_ccount(); | 208 | ccount = get_ccount(); |
| 207 | while (!ccount); | 209 | while (!ccount); |
| 208 | 210 | ||
| 209 | cpu_start_ccount = ccount; | 211 | WRITE_ONCE(cpu_start_ccount, ccount); |
| 210 | 212 | ||
| 211 | while (time_before(jiffies, timeout)) { | 213 | do { |
| 214 | /* | ||
| 215 | * Pairs with the first two memws in the | ||
| 216 | * .Lboot_secondary. | ||
| 217 | */ | ||
| 212 | mb(); | 218 | mb(); |
| 213 | if (!cpu_start_ccount) | 219 | ccount = READ_ONCE(cpu_start_ccount); |
| 214 | break; | 220 | } while (ccount && time_before(jiffies, timeout)); |
| 215 | } | ||
| 216 | 221 | ||
| 217 | if (cpu_start_ccount) { | 222 | if (ccount) { |
| 218 | smp_call_function_single(0, mx_cpu_stop, | 223 | smp_call_function_single(0, mx_cpu_stop, |
| 219 | (void *)cpu, 1); | 224 | (void *)cpu, 1); |
| 220 | cpu_start_ccount = 0; | 225 | WRITE_ONCE(cpu_start_ccount, 0); |
| 221 | return -EIO; | 226 | return -EIO; |
| 222 | } | 227 | } |
| 223 | } | 228 | } |
| @@ -237,6 +242,7 @@ int __cpu_up(unsigned int cpu, struct task_struct *idle) | |||
| 237 | pr_debug("%s: Calling wakeup_secondary(cpu:%d, idle:%p, sp: %08lx)\n", | 242 | pr_debug("%s: Calling wakeup_secondary(cpu:%d, idle:%p, sp: %08lx)\n", |
| 238 | __func__, cpu, idle, start_info.stack); | 243 | __func__, cpu, idle, start_info.stack); |
| 239 | 244 | ||
| 245 | init_completion(&cpu_running); | ||
| 240 | ret = boot_secondary(cpu, idle); | 246 | ret = boot_secondary(cpu, idle); |
| 241 | if (ret == 0) { | 247 | if (ret == 0) { |
| 242 | wait_for_completion_timeout(&cpu_running, | 248 | wait_for_completion_timeout(&cpu_running, |
| @@ -298,8 +304,10 @@ void __cpu_die(unsigned int cpu) | |||
| 298 | unsigned long timeout = jiffies + msecs_to_jiffies(1000); | 304 | unsigned long timeout = jiffies + msecs_to_jiffies(1000); |
| 299 | while (time_before(jiffies, timeout)) { | 305 | while (time_before(jiffies, timeout)) { |
| 300 | system_invalidate_dcache_range((unsigned long)&cpu_start_id, | 306 | system_invalidate_dcache_range((unsigned long)&cpu_start_id, |
| 301 | sizeof(cpu_start_id)); | 307 | sizeof(cpu_start_id)); |
| 302 | if (cpu_start_id == -cpu) { | 308 | /* Pairs with the second memw in the cpu_restart */ |
| 309 | mb(); | ||
| 310 | if (READ_ONCE(cpu_start_id) == -cpu) { | ||
| 303 | platform_cpu_kill(cpu); | 311 | platform_cpu_kill(cpu); |
| 304 | return; | 312 | return; |
| 305 | } | 313 | } |
