]>
Commit | Line | Data |
---|---|---|
1981af9d SL |
1 | From 98b38d2cd82d185a179365f284a493a848628893 Mon Sep 17 00:00:00 2001 |
2 | From: Max Filippov <jcmvbkbc@gmail.com> | |
3 | Date: Fri, 21 Dec 2018 08:26:20 -0800 | |
4 | Subject: xtensa: SMP: fix secondary CPU initialization | |
5 | ||
6 | [ Upstream commit 32a7726c4f4aadfabdb82440d84f88a5a2c8fe13 ] | |
7 | ||
8 | - add missing memory barriers to the secondary CPU synchronization spin | |
9 | loops; add comment to the matching memory barrier in the boot_secondary | |
10 | and __cpu_die functions; | |
11 | - use READ_ONCE/WRITE_ONCE to access cpu_start_id/cpu_start_ccount | |
12 | instead of reading/writing them directly; | |
13 | - re-initialize cpu_running every time before starting secondary CPU to | |
14 | flush possible previous CPU startup results. | |
15 | ||
16 | Signed-off-by: Max Filippov <jcmvbkbc@gmail.com> | |
17 | Signed-off-by: Sasha Levin <sashal@kernel.org> | |
18 | --- | |
19 | arch/xtensa/kernel/head.S | 5 ++++- | |
20 | arch/xtensa/kernel/smp.c | 34 +++++++++++++++++++++------------- | |
21 | 2 files changed, 25 insertions(+), 14 deletions(-) | |
22 | ||
23 | diff --git a/arch/xtensa/kernel/head.S b/arch/xtensa/kernel/head.S | |
24 | index c7b3bedbfffe..e3823b4f9d08 100644 | |
25 | --- a/arch/xtensa/kernel/head.S | |
26 | +++ b/arch/xtensa/kernel/head.S | |
27 | @@ -286,12 +286,13 @@ should_never_return: | |
28 | ||
29 | movi a2, cpu_start_ccount | |
30 | 1: | |
31 | + memw | |
32 | l32i a3, a2, 0 | |
33 | beqi a3, 0, 1b | |
34 | movi a3, 0 | |
35 | s32i a3, a2, 0 | |
36 | - memw | |
37 | 1: | |
38 | + memw | |
39 | l32i a3, a2, 0 | |
40 | beqi a3, 0, 1b | |
41 | wsr a3, ccount | |
42 | @@ -328,11 +329,13 @@ ENTRY(cpu_restart) | |
43 | rsr a0, prid | |
44 | neg a2, a0 | |
45 | movi a3, cpu_start_id | |
46 | + memw | |
47 | s32i a2, a3, 0 | |
48 | #if XCHAL_DCACHE_IS_WRITEBACK | |
49 | dhwbi a3, 0 | |
50 | #endif | |
51 | 1: | |
52 | + memw | |
53 | l32i a2, a3, 0 | |
54 | dhi a3, 0 | |
55 | bne a2, a0, 1b | |
56 | diff --git a/arch/xtensa/kernel/smp.c b/arch/xtensa/kernel/smp.c | |
57 | index 4d02e38514f5..545144d1431d 100644 | |
58 | --- a/arch/xtensa/kernel/smp.c | |
59 | +++ b/arch/xtensa/kernel/smp.c | |
60 | @@ -192,9 +192,11 @@ static int boot_secondary(unsigned int cpu, struct task_struct *ts) | |
61 | int i; | |
62 | ||
63 | #ifdef CONFIG_HOTPLUG_CPU | |
64 | - cpu_start_id = cpu; | |
65 | - system_flush_invalidate_dcache_range( | |
66 | - (unsigned long)&cpu_start_id, sizeof(cpu_start_id)); | |
67 | + WRITE_ONCE(cpu_start_id, cpu); | |
68 | + /* Pairs with the third memw in the cpu_restart */ | |
69 | + mb(); | |
70 | + system_flush_invalidate_dcache_range((unsigned long)&cpu_start_id, | |
71 | + sizeof(cpu_start_id)); | |
72 | #endif | |
73 | smp_call_function_single(0, mx_cpu_start, (void *)cpu, 1); | |
74 | ||
75 | @@ -203,18 +205,21 @@ static int boot_secondary(unsigned int cpu, struct task_struct *ts) | |
76 | ccount = get_ccount(); | |
77 | while (!ccount); | |
78 | ||
79 | - cpu_start_ccount = ccount; | |
80 | + WRITE_ONCE(cpu_start_ccount, ccount); | |
81 | ||
82 | - while (time_before(jiffies, timeout)) { | |
83 | + do { | |
84 | + /* | |
85 | + * Pairs with the first two memws in the | |
86 | + * .Lboot_secondary. | |
87 | + */ | |
88 | mb(); | |
89 | - if (!cpu_start_ccount) | |
90 | - break; | |
91 | - } | |
92 | + ccount = READ_ONCE(cpu_start_ccount); | |
93 | + } while (ccount && time_before(jiffies, timeout)); | |
94 | ||
95 | - if (cpu_start_ccount) { | |
96 | + if (ccount) { | |
97 | smp_call_function_single(0, mx_cpu_stop, | |
98 | - (void *)cpu, 1); | |
99 | - cpu_start_ccount = 0; | |
100 | + (void *)cpu, 1); | |
101 | + WRITE_ONCE(cpu_start_ccount, 0); | |
102 | return -EIO; | |
103 | } | |
104 | } | |
105 | @@ -234,6 +239,7 @@ int __cpu_up(unsigned int cpu, struct task_struct *idle) | |
106 | pr_debug("%s: Calling wakeup_secondary(cpu:%d, idle:%p, sp: %08lx)\n", | |
107 | __func__, cpu, idle, start_info.stack); | |
108 | ||
109 | + init_completion(&cpu_running); | |
110 | ret = boot_secondary(cpu, idle); | |
111 | if (ret == 0) { | |
112 | wait_for_completion_timeout(&cpu_running, | |
113 | @@ -295,8 +301,10 @@ void __cpu_die(unsigned int cpu) | |
114 | unsigned long timeout = jiffies + msecs_to_jiffies(1000); | |
115 | while (time_before(jiffies, timeout)) { | |
116 | system_invalidate_dcache_range((unsigned long)&cpu_start_id, | |
117 | - sizeof(cpu_start_id)); | |
118 | - if (cpu_start_id == -cpu) { | |
119 | + sizeof(cpu_start_id)); | |
120 | + /* Pairs with the second memw in the cpu_restart */ | |
121 | + mb(); | |
122 | + if (READ_ONCE(cpu_start_id) == -cpu) { | |
123 | platform_cpu_kill(cpu); | |
124 | return; | |
125 | } | |
126 | -- | |
127 | 2.19.1 | |
128 |