aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRussell King <rmk+kernel@armlinux.org.uk>2018-12-13 09:02:48 -0500
committerRussell King <rmk+kernel@armlinux.org.uk>2019-02-01 17:05:23 -0500
commit6213f70e7c10fd4a01b65bad3826648fc78df8a8 (patch)
treec1296d53776c9668057f570485285754c2424ab5
parent70678554c4c40f2cf8de5e7cd53fdd2c73387e51 (diff)
ARM: smp: remove arch-provided "pen_release"
Consolidating the "pen_release" stuff amongst the various SoC implementations gives credence to having a CPU holding pen for secondary CPUs. However, this is far from the truth. Many SoC implementations cargo-cult copied various bits of the pen release implementation from the initial Realview/Versatile Express implementation without understanding what it was or why it existed. The reason it existed is because these are _development_ platforms, and some board firmware is unable to individually control the startup of secondary CPUs. Moreover, they do not have a way to power down or reset secondary CPUs for hot-unplug. Hence, the pen_release implementation was designed for ARM Ltd's development platforms to provide a working implementation, even though it is very far from what is required. It was decided a while back to reduce the duplication by consolidating the "pen_release" variable, but this only made the situation worse - we have ended up with several implementations that read this variable but do not write it - again, showing the cargo-cult mentality at work, lack of proper review of new code, and in some cases a lack of testing. While it would be preferable to remove pen_release entirely from the kernel, this is not possible without help from the SoC maintainers, which seems to be lacking. However, I want to remove pen_release from arch code to remove the credence that having it gives. This patch removes pen_release from the arch code entirely, adding private per-SoC definitions for it instead, and explicitly stating that write_pen_release() is cargo-cult copied and should not be copied any further. Rename write_pen_release() in a similar fashion as well. Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
-rw-r--r--arch/arm/include/asm/smp.h1
-rw-r--r--arch/arm/kernel/smp.c6
-rw-r--r--arch/arm/mach-exynos/headsmp.S2
-rw-r--r--arch/arm/mach-exynos/platsmp.c31
-rw-r--r--arch/arm/mach-prima2/common.h2
-rw-r--r--arch/arm/mach-prima2/headsmp.S2
-rw-r--r--arch/arm/mach-prima2/hotplug.c3
-rw-r--r--arch/arm/mach-prima2/platsmp.c17
-rw-r--r--arch/arm/mach-spear/generic.h2
-rw-r--r--arch/arm/mach-spear/headsmp.S2
-rw-r--r--arch/arm/mach-spear/hotplug.c4
-rw-r--r--arch/arm/mach-spear/platsmp.c27
12 files changed, 56 insertions, 43 deletions
diff --git a/arch/arm/include/asm/smp.h b/arch/arm/include/asm/smp.h
index 709a55989cb0..451ae684aaf4 100644
--- a/arch/arm/include/asm/smp.h
+++ b/arch/arm/include/asm/smp.h
@@ -67,7 +67,6 @@ struct secondary_data {
67 void *stack; 67 void *stack;
68}; 68};
69extern struct secondary_data secondary_data; 69extern struct secondary_data secondary_data;
70extern volatile int pen_release;
71extern void secondary_startup(void); 70extern void secondary_startup(void);
72extern void secondary_startup_arm(void); 71extern void secondary_startup_arm(void);
73 72
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index 3bf82232b1be..051b0e8e7d30 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -62,12 +62,6 @@
62 */ 62 */
63struct secondary_data secondary_data; 63struct secondary_data secondary_data;
64 64
65/*
66 * control for which core is the next to come out of the secondary
67 * boot "holding pen"
68 */
69volatile int pen_release = -1;
70
71enum ipi_msg_type { 65enum ipi_msg_type {
72 IPI_WAKEUP, 66 IPI_WAKEUP,
73 IPI_TIMER, 67 IPI_TIMER,
diff --git a/arch/arm/mach-exynos/headsmp.S b/arch/arm/mach-exynos/headsmp.S
index 005695c9bf40..0ac2cb9a7355 100644
--- a/arch/arm/mach-exynos/headsmp.S
+++ b/arch/arm/mach-exynos/headsmp.S
@@ -36,4 +36,4 @@ ENDPROC(exynos4_secondary_startup)
36 36
37 .align 2 37 .align 2
381: .long . 381: .long .
39 .long pen_release 39 .long exynos_pen_release
diff --git a/arch/arm/mach-exynos/platsmp.c b/arch/arm/mach-exynos/platsmp.c
index c39ffd2e2fe6..3795412c0189 100644
--- a/arch/arm/mach-exynos/platsmp.c
+++ b/arch/arm/mach-exynos/platsmp.c
@@ -28,6 +28,9 @@
28 28
29extern void exynos4_secondary_startup(void); 29extern void exynos4_secondary_startup(void);
30 30
31/* XXX exynos_pen_release is cargo culted code - DO NOT COPY XXX */
32volatile int exynos_pen_release = -1;
33
31#ifdef CONFIG_HOTPLUG_CPU 34#ifdef CONFIG_HOTPLUG_CPU
32static inline void cpu_leave_lowpower(u32 core_id) 35static inline void cpu_leave_lowpower(u32 core_id)
33{ 36{
@@ -57,7 +60,7 @@ static inline void platform_do_lowpower(unsigned int cpu, int *spurious)
57 60
58 wfi(); 61 wfi();
59 62
60 if (pen_release == core_id) { 63 if (exynos_pen_release == core_id) {
61 /* 64 /*
62 * OK, proper wakeup, we're done 65 * OK, proper wakeup, we're done
63 */ 66 */
@@ -228,15 +231,17 @@ void exynos_core_restart(u32 core_id)
228} 231}
229 232
230/* 233/*
231 * Write pen_release in a way that is guaranteed to be visible to all 234 * XXX CARGO CULTED CODE - DO NOT COPY XXX
232 * observers, irrespective of whether they're taking part in coherency 235 *
236 * Write exynos_pen_release in a way that is guaranteed to be visible to
237 * all observers, irrespective of whether they're taking part in coherency
233 * or not. This is necessary for the hotplug code to work reliably. 238 * or not. This is necessary for the hotplug code to work reliably.
234 */ 239 */
235static void write_pen_release(int val) 240static void exynos_write_pen_release(int val)
236{ 241{
237 pen_release = val; 242 exynos_pen_release = val;
238 smp_wmb(); 243 smp_wmb();
239 sync_cache_w(&pen_release); 244 sync_cache_w(&exynos_pen_release);
240} 245}
241 246
242static DEFINE_SPINLOCK(boot_lock); 247static DEFINE_SPINLOCK(boot_lock);
@@ -247,7 +252,7 @@ static void exynos_secondary_init(unsigned int cpu)
247 * let the primary processor know we're out of the 252 * let the primary processor know we're out of the
248 * pen, then head off into the C entry point 253 * pen, then head off into the C entry point
249 */ 254 */
250 write_pen_release(-1); 255 exynos_write_pen_release(-1);
251 256
252 /* 257 /*
253 * Synchronise with the boot thread. 258 * Synchronise with the boot thread.
@@ -322,12 +327,12 @@ static int exynos_boot_secondary(unsigned int cpu, struct task_struct *idle)
322 /* 327 /*
323 * The secondary processor is waiting to be released from 328 * The secondary processor is waiting to be released from
324 * the holding pen - release it, then wait for it to flag 329 * the holding pen - release it, then wait for it to flag
325 * that it has been released by resetting pen_release. 330 * that it has been released by resetting exynos_pen_release.
326 * 331 *
327 * Note that "pen_release" is the hardware CPU core ID, whereas 332 * Note that "exynos_pen_release" is the hardware CPU core ID, whereas
328 * "cpu" is Linux's internal ID. 333 * "cpu" is Linux's internal ID.
329 */ 334 */
330 write_pen_release(core_id); 335 exynos_write_pen_release(core_id);
331 336
332 if (!exynos_cpu_power_state(core_id)) { 337 if (!exynos_cpu_power_state(core_id)) {
333 exynos_cpu_power_up(core_id); 338 exynos_cpu_power_up(core_id);
@@ -376,13 +381,13 @@ static int exynos_boot_secondary(unsigned int cpu, struct task_struct *idle)
376 else 381 else
377 arch_send_wakeup_ipi_mask(cpumask_of(cpu)); 382 arch_send_wakeup_ipi_mask(cpumask_of(cpu));
378 383
379 if (pen_release == -1) 384 if (exynos_pen_release == -1)
380 break; 385 break;
381 386
382 udelay(10); 387 udelay(10);
383 } 388 }
384 389
385 if (pen_release != -1) 390 if (exynos_pen_release != -1)
386 ret = -ETIMEDOUT; 391 ret = -ETIMEDOUT;
387 392
388 /* 393 /*
@@ -392,7 +397,7 @@ static int exynos_boot_secondary(unsigned int cpu, struct task_struct *idle)
392fail: 397fail:
393 spin_unlock(&boot_lock); 398 spin_unlock(&boot_lock);
394 399
395 return pen_release != -1 ? ret : 0; 400 return exynos_pen_release != -1 ? ret : 0;
396} 401}
397 402
398static void __init exynos_smp_prepare_cpus(unsigned int max_cpus) 403static void __init exynos_smp_prepare_cpus(unsigned int max_cpus)
diff --git a/arch/arm/mach-prima2/common.h b/arch/arm/mach-prima2/common.h
index 6d77b622d168..457eb7b18160 100644
--- a/arch/arm/mach-prima2/common.h
+++ b/arch/arm/mach-prima2/common.h
@@ -15,6 +15,8 @@
15#include <asm/mach/time.h> 15#include <asm/mach/time.h>
16#include <asm/exception.h> 16#include <asm/exception.h>
17 17
18extern volatile int prima2_pen_release;
19
18extern const struct smp_operations sirfsoc_smp_ops; 20extern const struct smp_operations sirfsoc_smp_ops;
19extern void sirfsoc_secondary_startup(void); 21extern void sirfsoc_secondary_startup(void);
20extern void sirfsoc_cpu_die(unsigned int cpu); 22extern void sirfsoc_cpu_die(unsigned int cpu);
diff --git a/arch/arm/mach-prima2/headsmp.S b/arch/arm/mach-prima2/headsmp.S
index 209d9fc5c16c..6cf4fc60347b 100644
--- a/arch/arm/mach-prima2/headsmp.S
+++ b/arch/arm/mach-prima2/headsmp.S
@@ -34,4 +34,4 @@ ENDPROC(sirfsoc_secondary_startup)
34 34
35 .align 35 .align
361: .long . 361: .long .
37 .long pen_release 37 .long prima2_pen_release
diff --git a/arch/arm/mach-prima2/hotplug.c b/arch/arm/mach-prima2/hotplug.c
index a728c78b996f..b6cf1527e330 100644
--- a/arch/arm/mach-prima2/hotplug.c
+++ b/arch/arm/mach-prima2/hotplug.c
@@ -11,6 +11,7 @@
11#include <linux/smp.h> 11#include <linux/smp.h>
12 12
13#include <asm/smp_plat.h> 13#include <asm/smp_plat.h>
14#include "common.h"
14 15
15static inline void platform_do_lowpower(unsigned int cpu) 16static inline void platform_do_lowpower(unsigned int cpu)
16{ 17{
@@ -18,7 +19,7 @@ static inline void platform_do_lowpower(unsigned int cpu)
18 for (;;) { 19 for (;;) {
19 __asm__ __volatile__("dsb\n\t" "wfi\n\t" 20 __asm__ __volatile__("dsb\n\t" "wfi\n\t"
20 : : : "memory"); 21 : : : "memory");
21 if (pen_release == cpu_logical_map(cpu)) { 22 if (prima2_pen_release == cpu_logical_map(cpu)) {
22 /* 23 /*
23 * OK, proper wakeup, we're done 24 * OK, proper wakeup, we're done
24 */ 25 */
diff --git a/arch/arm/mach-prima2/platsmp.c b/arch/arm/mach-prima2/platsmp.c
index 75ef5d4be554..d1f8b5168083 100644
--- a/arch/arm/mach-prima2/platsmp.c
+++ b/arch/arm/mach-prima2/platsmp.c
@@ -24,13 +24,16 @@ static void __iomem *clk_base;
24 24
25static DEFINE_SPINLOCK(boot_lock); 25static DEFINE_SPINLOCK(boot_lock);
26 26
27/* XXX prima2_pen_release is cargo culted code - DO NOT COPY XXX */
28volatile int prima2_pen_release = -1;
29
27static void sirfsoc_secondary_init(unsigned int cpu) 30static void sirfsoc_secondary_init(unsigned int cpu)
28{ 31{
29 /* 32 /*
30 * let the primary processor know we're out of the 33 * let the primary processor know we're out of the
31 * pen, then head off into the C entry point 34 * pen, then head off into the C entry point
32 */ 35 */
33 pen_release = -1; 36 prima2_pen_release = -1;
34 smp_wmb(); 37 smp_wmb();
35 38
36 /* 39 /*
@@ -80,13 +83,13 @@ static int sirfsoc_boot_secondary(unsigned int cpu, struct task_struct *idle)
80 /* 83 /*
81 * The secondary processor is waiting to be released from 84 * The secondary processor is waiting to be released from
82 * the holding pen - release it, then wait for it to flag 85 * the holding pen - release it, then wait for it to flag
83 * that it has been released by resetting pen_release. 86 * that it has been released by resetting prima2_pen_release.
84 * 87 *
85 * Note that "pen_release" is the hardware CPU ID, whereas 88 * Note that "prima2_pen_release" is the hardware CPU ID, whereas
86 * "cpu" is Linux's internal ID. 89 * "cpu" is Linux's internal ID.
87 */ 90 */
88 pen_release = cpu_logical_map(cpu); 91 prima2_pen_release = cpu_logical_map(cpu);
89 sync_cache_w(&pen_release); 92 sync_cache_w(&prima2_pen_release);
90 93
91 /* 94 /*
92 * Send the secondary CPU SEV, thereby causing the boot monitor to read 95 * Send the secondary CPU SEV, thereby causing the boot monitor to read
@@ -97,7 +100,7 @@ static int sirfsoc_boot_secondary(unsigned int cpu, struct task_struct *idle)
97 timeout = jiffies + (1 * HZ); 100 timeout = jiffies + (1 * HZ);
98 while (time_before(jiffies, timeout)) { 101 while (time_before(jiffies, timeout)) {
99 smp_rmb(); 102 smp_rmb();
100 if (pen_release == -1) 103 if (prima2_pen_release == -1)
101 break; 104 break;
102 105
103 udelay(10); 106 udelay(10);
@@ -109,7 +112,7 @@ static int sirfsoc_boot_secondary(unsigned int cpu, struct task_struct *idle)
109 */ 112 */
110 spin_unlock(&boot_lock); 113 spin_unlock(&boot_lock);
111 114
112 return pen_release != -1 ? -ENOSYS : 0; 115 return prima2_pen_release != -1 ? -ENOSYS : 0;
113} 116}
114 117
115const struct smp_operations sirfsoc_smp_ops __initconst = { 118const struct smp_operations sirfsoc_smp_ops __initconst = {
diff --git a/arch/arm/mach-spear/generic.h b/arch/arm/mach-spear/generic.h
index 909b97c0b237..25b4c5e66e39 100644
--- a/arch/arm/mach-spear/generic.h
+++ b/arch/arm/mach-spear/generic.h
@@ -20,6 +20,8 @@
20 20
21#include <asm/mach/time.h> 21#include <asm/mach/time.h>
22 22
23extern volatile int spear_pen_release;
24
23extern void spear13xx_timer_init(void); 25extern void spear13xx_timer_init(void);
24extern void spear3xx_timer_init(void); 26extern void spear3xx_timer_init(void);
25extern struct pl022_ssp_controller pl022_plat_data; 27extern struct pl022_ssp_controller pl022_plat_data;
diff --git a/arch/arm/mach-spear/headsmp.S b/arch/arm/mach-spear/headsmp.S
index c52192dc3d9f..6e250b6c0aa2 100644
--- a/arch/arm/mach-spear/headsmp.S
+++ b/arch/arm/mach-spear/headsmp.S
@@ -43,5 +43,5 @@ pen: ldr r7, [r6]
43 43
44 .align 44 .align
451: .long . 451: .long .
46 .long pen_release 46 .long spear_pen_release
47ENDPROC(spear13xx_secondary_startup) 47ENDPROC(spear13xx_secondary_startup)
diff --git a/arch/arm/mach-spear/hotplug.c b/arch/arm/mach-spear/hotplug.c
index 12edd1cf8a12..0dd84f609627 100644
--- a/arch/arm/mach-spear/hotplug.c
+++ b/arch/arm/mach-spear/hotplug.c
@@ -16,6 +16,8 @@
16#include <asm/cp15.h> 16#include <asm/cp15.h>
17#include <asm/smp_plat.h> 17#include <asm/smp_plat.h>
18 18
19#include "generic.h"
20
19static inline void cpu_enter_lowpower(void) 21static inline void cpu_enter_lowpower(void)
20{ 22{
21 unsigned int v; 23 unsigned int v;
@@ -57,7 +59,7 @@ static inline void spear13xx_do_lowpower(unsigned int cpu, int *spurious)
57 for (;;) { 59 for (;;) {
58 wfi(); 60 wfi();
59 61
60 if (pen_release == cpu) { 62 if (spear_pen_release == cpu) {
61 /* 63 /*
62 * OK, proper wakeup, we're done 64 * OK, proper wakeup, we're done
63 */ 65 */
diff --git a/arch/arm/mach-spear/platsmp.c b/arch/arm/mach-spear/platsmp.c
index 39038a03836a..b1ff4bb86f6d 100644
--- a/arch/arm/mach-spear/platsmp.c
+++ b/arch/arm/mach-spear/platsmp.c
@@ -20,16 +20,21 @@
20#include <mach/spear.h> 20#include <mach/spear.h>
21#include "generic.h" 21#include "generic.h"
22 22
23/* XXX spear_pen_release is cargo culted code - DO NOT COPY XXX */
24volatile int spear_pen_release = -1;
25
23/* 26/*
24 * Write pen_release in a way that is guaranteed to be visible to all 27 * XXX CARGO CULTED CODE - DO NOT COPY XXX
25 * observers, irrespective of whether they're taking part in coherency 28 *
29 * Write spear_pen_release in a way that is guaranteed to be visible to
30 * all observers, irrespective of whether they're taking part in coherency
26 * or not. This is necessary for the hotplug code to work reliably. 31 * or not. This is necessary for the hotplug code to work reliably.
27 */ 32 */
28static void write_pen_release(int val) 33static void spear_write_pen_release(int val)
29{ 34{
30 pen_release = val; 35 spear_pen_release = val;
31 smp_wmb(); 36 smp_wmb();
32 sync_cache_w(&pen_release); 37 sync_cache_w(&spear_pen_release);
33} 38}
34 39
35static DEFINE_SPINLOCK(boot_lock); 40static DEFINE_SPINLOCK(boot_lock);
@@ -42,7 +47,7 @@ static void spear13xx_secondary_init(unsigned int cpu)
42 * let the primary processor know we're out of the 47 * let the primary processor know we're out of the
43 * pen, then head off into the C entry point 48 * pen, then head off into the C entry point
44 */ 49 */
45 write_pen_release(-1); 50 spear_write_pen_release(-1);
46 51
47 /* 52 /*
48 * Synchronise with the boot thread. 53 * Synchronise with the boot thread.
@@ -64,17 +69,17 @@ static int spear13xx_boot_secondary(unsigned int cpu, struct task_struct *idle)
64 /* 69 /*
65 * The secondary processor is waiting to be released from 70 * The secondary processor is waiting to be released from
66 * the holding pen - release it, then wait for it to flag 71 * the holding pen - release it, then wait for it to flag
67 * that it has been released by resetting pen_release. 72 * that it has been released by resetting spear_pen_release.
68 * 73 *
69 * Note that "pen_release" is the hardware CPU ID, whereas 74 * Note that "spear_pen_release" is the hardware CPU ID, whereas
70 * "cpu" is Linux's internal ID. 75 * "cpu" is Linux's internal ID.
71 */ 76 */
72 write_pen_release(cpu); 77 spear_write_pen_release(cpu);
73 78
74 timeout = jiffies + (1 * HZ); 79 timeout = jiffies + (1 * HZ);
75 while (time_before(jiffies, timeout)) { 80 while (time_before(jiffies, timeout)) {
76 smp_rmb(); 81 smp_rmb();
77 if (pen_release == -1) 82 if (spear_pen_release == -1)
78 break; 83 break;
79 84
80 udelay(10); 85 udelay(10);
@@ -86,7 +91,7 @@ static int spear13xx_boot_secondary(unsigned int cpu, struct task_struct *idle)
86 */ 91 */
87 spin_unlock(&boot_lock); 92 spin_unlock(&boot_lock);
88 93
89 return pen_release != -1 ? -ENOSYS : 0; 94 return spear_pen_release != -1 ? -ENOSYS : 0;
90} 95}
91 96
92/* 97/*