Commit 6213f70e authored by Russell King's avatar Russell King
Browse files

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: default avatarRussell King <rmk+kernel@armlinux.org.uk>
parent 70678554
Loading
Loading
Loading
Loading
+0 −1
Original line number Diff line number Diff line
@@ -67,7 +67,6 @@ struct secondary_data {
	void *stack;
};
extern struct secondary_data secondary_data;
extern volatile int pen_release;
extern void secondary_startup(void);
extern void secondary_startup_arm(void);

+0 −6
Original line number Diff line number Diff line
@@ -62,12 +62,6 @@
 */
struct secondary_data secondary_data;

/*
 * control for which core is the next to come out of the secondary
 * boot "holding pen"
 */
volatile int pen_release = -1;

enum ipi_msg_type {
	IPI_WAKEUP,
	IPI_TIMER,
+1 −1
Original line number Diff line number Diff line
@@ -36,4 +36,4 @@ ENDPROC(exynos4_secondary_startup)

	.align 2
1:	.long	.
	.long	pen_release
	.long	exynos_pen_release
+18 −13
Original line number Diff line number Diff line
@@ -28,6 +28,9 @@

extern void exynos4_secondary_startup(void);

/* XXX exynos_pen_release is cargo culted code - DO NOT COPY XXX */
volatile int exynos_pen_release = -1;

#ifdef CONFIG_HOTPLUG_CPU
static inline void cpu_leave_lowpower(u32 core_id)
{
@@ -57,7 +60,7 @@ static inline void platform_do_lowpower(unsigned int cpu, int *spurious)

		wfi();

		if (pen_release == core_id) {
		if (exynos_pen_release == core_id) {
			/*
			 * OK, proper wakeup, we're done
			 */
@@ -228,15 +231,17 @@ void exynos_core_restart(u32 core_id)
}

/*
 * Write pen_release in a way that is guaranteed to be visible to all
 * observers, irrespective of whether they're taking part in coherency
 * XXX CARGO CULTED CODE - DO NOT COPY XXX
 *
 * Write exynos_pen_release in a way that is guaranteed to be visible to
 * all observers, irrespective of whether they're taking part in coherency
 * or not.  This is necessary for the hotplug code to work reliably.
 */
static void write_pen_release(int val)
static void exynos_write_pen_release(int val)
{
	pen_release = val;
	exynos_pen_release = val;
	smp_wmb();
	sync_cache_w(&pen_release);
	sync_cache_w(&exynos_pen_release);
}

static DEFINE_SPINLOCK(boot_lock);
@@ -247,7 +252,7 @@ static void exynos_secondary_init(unsigned int cpu)
	 * let the primary processor know we're out of the
	 * pen, then head off into the C entry point
	 */
	write_pen_release(-1);
	exynos_write_pen_release(-1);

	/*
	 * Synchronise with the boot thread.
@@ -322,12 +327,12 @@ static int exynos_boot_secondary(unsigned int cpu, struct task_struct *idle)
	/*
	 * The secondary processor is waiting to be released from
	 * the holding pen - release it, then wait for it to flag
	 * that it has been released by resetting pen_release.
	 * that it has been released by resetting exynos_pen_release.
	 *
	 * Note that "pen_release" is the hardware CPU core ID, whereas
	 * Note that "exynos_pen_release" is the hardware CPU core ID, whereas
	 * "cpu" is Linux's internal ID.
	 */
	write_pen_release(core_id);
	exynos_write_pen_release(core_id);

	if (!exynos_cpu_power_state(core_id)) {
		exynos_cpu_power_up(core_id);
@@ -376,13 +381,13 @@ static int exynos_boot_secondary(unsigned int cpu, struct task_struct *idle)
		else
			arch_send_wakeup_ipi_mask(cpumask_of(cpu));

		if (pen_release == -1)
		if (exynos_pen_release == -1)
			break;

		udelay(10);
	}

	if (pen_release != -1)
	if (exynos_pen_release != -1)
		ret = -ETIMEDOUT;

	/*
@@ -392,7 +397,7 @@ static int exynos_boot_secondary(unsigned int cpu, struct task_struct *idle)
fail:
	spin_unlock(&boot_lock);

	return pen_release != -1 ? ret : 0;
	return exynos_pen_release != -1 ? ret : 0;
}

static void __init exynos_smp_prepare_cpus(unsigned int max_cpus)
+2 −0
Original line number Diff line number Diff line
@@ -15,6 +15,8 @@
#include <asm/mach/time.h>
#include <asm/exception.h>

extern volatile int prima2_pen_release;

extern const struct smp_operations sirfsoc_smp_ops;
extern void sirfsoc_secondary_startup(void);
extern void sirfsoc_cpu_die(unsigned int cpu);
Loading