From: Dengcheng Zhu <dzhu@wavecomp.com>
To: pburton@wavecomp.com, ralf@linux-mips.org
Cc: linux-mips@linux-mips.org, Dengcheng Zhu <dzhu@wavecomp.com>
Subject: [PATCH v2 1/6] MIPS: Make play_dead() work for kexec
Date: Wed, 11 Jul 2018 18:27:43 -0700 [thread overview]
Message-ID: <1531358868-10101-2-git-send-email-dzhu@wavecomp.com> (raw)
In-Reply-To: <1531358868-10101-1-git-send-email-dzhu@wavecomp.com>
Extract play_dead() from CONFIG_HOTPLUG_CPU and share with CONFIG_KEXEC.
Also, add one parameter to it to avoid doing unnecessary things in the case
of kexec.
This is needed to correctly support SMP new kernel in kexec. Before doing
this, all non-crashing CPUs are waiting for the reboot signal
(kexec_ready_to_reboot) to jump to kexec_start_address in kexec_smp_wait(),
which creates some problems like incorrect CPU topology upon booting from
new UP kernel, sluggish performance in MT environment during and after
reboot, new SMP kernel not able to bring up secondary CPU etc.
It would make sense to let the new (SMP) kernel manage all CPUs, instead of
crashing CPU booting from reboot_code_buffer whereas others jumping to
kexec_start_address. To do this, play_dead() is well suitable for preparing
a boot environment for the new kernel.
Signed-off-by: Dengcheng Zhu <dzhu@wavecomp.com>
---
arch/mips/cavium-octeon/smp.c | 35 ++++++++-------
arch/mips/include/asm/smp.h | 4 +-
arch/mips/kernel/process.c | 2 +-
arch/mips/kernel/smp-bmips.c | 11 +++--
arch/mips/kernel/smp-cps.c | 59 ++++++++++++++----------
arch/mips/loongson64/loongson-3/smp.c | 85 ++++++++++++++++++-----------------
6 files changed, 112 insertions(+), 84 deletions(-)
diff --git a/arch/mips/cavium-octeon/smp.c b/arch/mips/cavium-octeon/smp.c
index 75e7c86..31150a8 100644
--- a/arch/mips/cavium-octeon/smp.c
+++ b/arch/mips/cavium-octeon/smp.c
@@ -280,11 +280,30 @@ static void octeon_smp_finish(void)
local_irq_enable();
}
-#ifdef CONFIG_HOTPLUG_CPU
+#if defined(CONFIG_HOTPLUG_CPU) || defined(CONFIG_KEXEC)
/* State of each CPU. */
DEFINE_PER_CPU(int, cpu_state);
+void play_dead(bool kexec)
+{
+ int cpu = cpu_number_map(cvmx_get_core_num());
+
+ if (!kexec)
+ idle_task_exit();
+ octeon_processor_boot = 0xff;
+ per_cpu(cpu_state, cpu) = CPU_DEAD;
+
+ mb();
+
+ while (1) /* core will be reset here */
+ ;
+}
+
+#endif /* CONFIG_HOTPLUG_CPU || CONFIG_KEXEC */
+
+#ifdef CONFIG_HOTPLUG_CPU
+
static int octeon_cpu_disable(void)
{
unsigned int cpu = smp_processor_id();
@@ -343,20 +362,6 @@ static void octeon_cpu_die(unsigned int cpu)
cvmx_write_csr(CVMX_CIU_PP_RST, 0);
}
-void play_dead(void)
-{
- int cpu = cpu_number_map(cvmx_get_core_num());
-
- idle_task_exit();
- octeon_processor_boot = 0xff;
- per_cpu(cpu_state, cpu) = CPU_DEAD;
-
- mb();
-
- while (1) /* core will be reset here */
- ;
-}
-
static void start_after_reset(void)
{
kernel_entry(0, 0, 0); /* set a2 = 0 for secondary core */
diff --git a/arch/mips/include/asm/smp.h b/arch/mips/include/asm/smp.h
index 88ebd83..3176053 100644
--- a/arch/mips/include/asm/smp.h
+++ b/arch/mips/include/asm/smp.h
@@ -77,8 +77,10 @@ static inline void __cpu_die(unsigned int cpu)
mp_ops->cpu_die(cpu);
}
+#endif
-extern void play_dead(void);
+#if defined(CONFIG_HOTPLUG_CPU) || defined(CONFIG_KEXEC)
+extern void play_dead(bool kexec);
#endif
/*
diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c
index 8d85046..1aa24bb 100644
--- a/arch/mips/kernel/process.c
+++ b/arch/mips/kernel/process.c
@@ -53,7 +53,7 @@
#ifdef CONFIG_HOTPLUG_CPU
void arch_cpu_idle_dead(void)
{
- play_dead();
+ play_dead(false);
}
#endif
diff --git a/arch/mips/kernel/smp-bmips.c b/arch/mips/kernel/smp-bmips.c
index 159e83a..e1c11bd 100644
--- a/arch/mips/kernel/smp-bmips.c
+++ b/arch/mips/kernel/smp-bmips.c
@@ -381,9 +381,14 @@ static void bmips_cpu_die(unsigned int cpu)
{
}
-void __ref play_dead(void)
+#endif /* CONFIG_HOTPLUG_CPU */
+
+#if defined(CONFIG_HOTPLUG_CPU) || defined(CONFIG_KEXEC)
+
+void __ref play_dead(bool kexec)
{
- idle_task_exit();
+ if (!kexec)
+ idle_task_exit();
/* flush data cache */
_dma_cache_wback_inv(0, ~0);
@@ -409,7 +414,7 @@ void __ref play_dead(void)
: : : "memory");
}
-#endif /* CONFIG_HOTPLUG_CPU */
+#endif /* CONFIG_HOTPLUG_CPU || CONFIG_KEXEC */
const struct plat_smp_ops bmips43xx_smp_ops = {
.smp_setup = bmips_smp_setup,
diff --git a/arch/mips/kernel/smp-cps.c b/arch/mips/kernel/smp-cps.c
index 03f1026..4615702 100644
--- a/arch/mips/kernel/smp-cps.c
+++ b/arch/mips/kernel/smp-cps.c
@@ -398,27 +398,7 @@ static void cps_smp_finish(void)
local_irq_enable();
}
-#ifdef CONFIG_HOTPLUG_CPU
-
-static int cps_cpu_disable(void)
-{
- unsigned cpu = smp_processor_id();
- struct core_boot_config *core_cfg;
-
- if (!cpu)
- return -EBUSY;
-
- if (!cps_pm_support_state(CPS_PM_POWER_GATED))
- return -EINVAL;
-
- core_cfg = &mips_cps_core_bootcfg[cpu_core(¤t_cpu_data)];
- atomic_sub(1 << cpu_vpe_id(¤t_cpu_data), &core_cfg->vpe_mask);
- smp_mb__after_atomic();
- set_cpu_online(cpu, false);
- calculate_cpu_foreign_map();
-
- return 0;
-}
+#if defined(CONFIG_HOTPLUG_CPU) || defined(CONFIG_KEXEC)
static unsigned cpu_death_sibling;
static enum {
@@ -426,12 +406,18 @@ static enum {
CPU_DEATH_POWER,
} cpu_death;
-void play_dead(void)
+void play_dead(bool kexec)
{
unsigned int cpu, core, vpe_id;
local_irq_disable();
- idle_task_exit();
+ /*
+ * Don't bother dealing with idle task's mm as we are executing the
+ * new kernel.
+ */
+ if (!kexec)
+ idle_task_exit();
+
cpu = smp_processor_id();
core = cpu_core(&cpu_data[cpu]);
cpu_death = CPU_DEATH_POWER;
@@ -454,7 +440,8 @@ void play_dead(void)
}
/* This CPU has chosen its way out */
- (void)cpu_report_death();
+ if (!kexec)
+ (void)cpu_report_death();
if (cpu_death == CPU_DEATH_HALT) {
vpe_id = cpu_vpe_id(&cpu_data[cpu]);
@@ -480,6 +467,30 @@ void play_dead(void)
panic("Failed to offline CPU %u", cpu);
}
+#endif /* CONFIG_HOTPLUG_CPU || CONFIG_KEXEC */
+
+#ifdef CONFIG_HOTPLUG_CPU
+
+static int cps_cpu_disable(void)
+{
+ unsigned cpu = smp_processor_id();
+ struct core_boot_config *core_cfg;
+
+ if (!cpu)
+ return -EBUSY;
+
+ if (!cps_pm_support_state(CPS_PM_POWER_GATED))
+ return -EINVAL;
+
+ core_cfg = &mips_cps_core_bootcfg[cpu_core(¤t_cpu_data)];
+ atomic_sub(1 << cpu_vpe_id(¤t_cpu_data), &core_cfg->vpe_mask);
+ smp_mb__after_atomic();
+ set_cpu_online(cpu, false);
+ calculate_cpu_foreign_map();
+
+ return 0;
+}
+
static void wait_for_sibling_halt(void *ptr_cpu)
{
unsigned cpu = (unsigned long)ptr_cpu;
diff --git a/arch/mips/loongson64/loongson-3/smp.c b/arch/mips/loongson64/loongson-3/smp.c
index 8501109..d426ce2 100644
--- a/arch/mips/loongson64/loongson-3/smp.c
+++ b/arch/mips/loongson64/loongson-3/smp.c
@@ -455,6 +455,47 @@ static void loongson3_cpu_die(unsigned int cpu)
mb();
}
+static int loongson3_disable_clock(unsigned int cpu)
+{
+ uint64_t core_id = cpu_core(&cpu_data[cpu]);
+ uint64_t package_id = cpu_data[cpu].package;
+
+ if ((read_c0_prid() & PRID_REV_MASK) == PRID_REV_LOONGSON3A_R1) {
+ LOONGSON_CHIPCFG(package_id) &= ~(1 << (12 + core_id));
+ } else {
+ if (!(loongson_sysconf.workarounds & WORKAROUND_CPUHOTPLUG))
+ LOONGSON_FREQCTRL(package_id) &= ~(1 << (core_id * 4 + 3));
+ }
+ return 0;
+}
+
+static int loongson3_enable_clock(unsigned int cpu)
+{
+ uint64_t core_id = cpu_core(&cpu_data[cpu]);
+ uint64_t package_id = cpu_data[cpu].package;
+
+ if ((read_c0_prid() & PRID_REV_MASK) == PRID_REV_LOONGSON3A_R1) {
+ LOONGSON_CHIPCFG(package_id) |= 1 << (12 + core_id);
+ } else {
+ if (!(loongson_sysconf.workarounds & WORKAROUND_CPUHOTPLUG))
+ LOONGSON_FREQCTRL(package_id) |= 1 << (core_id * 4 + 3);
+ }
+ return 0;
+}
+
+static int register_loongson3_notifier(void)
+{
+ return cpuhp_setup_state_nocalls(CPUHP_MIPS_SOC_PREPARE,
+ "mips/loongson:prepare",
+ loongson3_enable_clock,
+ loongson3_disable_clock);
+}
+early_initcall(register_loongson3_notifier);
+
+#endif /* CONFIG_HOTPLUG_CPU */
+
+#if defined(CONFIG_HOTPLUG_CPU) || defined(CONFIG_KEXEC)
+
/* To shutdown a core in Loongson 3, the target core should go to CKSEG1 and
* flush all L1 entries at first. Then, another core (usually Core 0) can
* safely disable the clock of the target core. loongson3_play_dead() is
@@ -668,13 +709,14 @@ static void loongson3b_play_dead(int *state_addr)
: "a1");
}
-void play_dead(void)
+void play_dead(bool kexec)
{
int *state_addr;
unsigned int cpu = smp_processor_id();
void (*play_dead_at_ckseg1)(int *);
- idle_task_exit();
+ if (!kexec)
+ idle_task_exit();
switch (read_c0_prid() & PRID_REV_MASK) {
case PRID_REV_LOONGSON3A_R1:
default:
@@ -697,44 +739,7 @@ void play_dead(void)
play_dead_at_ckseg1(state_addr);
}
-static int loongson3_disable_clock(unsigned int cpu)
-{
- uint64_t core_id = cpu_core(&cpu_data[cpu]);
- uint64_t package_id = cpu_data[cpu].package;
-
- if ((read_c0_prid() & PRID_REV_MASK) == PRID_REV_LOONGSON3A_R1) {
- LOONGSON_CHIPCFG(package_id) &= ~(1 << (12 + core_id));
- } else {
- if (!(loongson_sysconf.workarounds & WORKAROUND_CPUHOTPLUG))
- LOONGSON_FREQCTRL(package_id) &= ~(1 << (core_id * 4 + 3));
- }
- return 0;
-}
-
-static int loongson3_enable_clock(unsigned int cpu)
-{
- uint64_t core_id = cpu_core(&cpu_data[cpu]);
- uint64_t package_id = cpu_data[cpu].package;
-
- if ((read_c0_prid() & PRID_REV_MASK) == PRID_REV_LOONGSON3A_R1) {
- LOONGSON_CHIPCFG(package_id) |= 1 << (12 + core_id);
- } else {
- if (!(loongson_sysconf.workarounds & WORKAROUND_CPUHOTPLUG))
- LOONGSON_FREQCTRL(package_id) |= 1 << (core_id * 4 + 3);
- }
- return 0;
-}
-
-static int register_loongson3_notifier(void)
-{
- return cpuhp_setup_state_nocalls(CPUHP_MIPS_SOC_PREPARE,
- "mips/loongson:prepare",
- loongson3_enable_clock,
- loongson3_disable_clock);
-}
-early_initcall(register_loongson3_notifier);
-
-#endif
+#endif /* CONFIG_HOTPLUG_CPU || CONFIG_KEXEC */
const struct plat_smp_ops loongson3_smp_ops = {
.send_ipi_single = loongson3_send_ipi_single,
--
2.7.4
next prev parent reply other threads:[~2018-07-12 1:29 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2018-07-12 1:27 [PATCH v2 0/6] MIPS: kexec/kdump: Fix smp reboot and other issues Dengcheng Zhu
2018-07-12 1:27 ` Dengcheng Zhu [this message]
2018-08-30 23:20 ` [PATCH v2 1/6] MIPS: Make play_dead() work for kexec Paul Burton
2018-08-31 16:58 ` Dengcheng Zhu
2018-07-12 1:27 ` [PATCH v2 2/6] MIPS: kexec: Let the new kernel handle all CPUs Dengcheng Zhu
2018-07-12 1:27 ` [PATCH v2 3/6] MIPS: kexec: Deprecate (relocated_)kexec_smp_wait Dengcheng Zhu
2018-07-12 1:27 ` [PATCH v2 4/6] MIPS: kexec: Do not flush system wide caches in machine_kexec() Dengcheng Zhu
2018-07-12 1:27 ` [PATCH v2 5/6] MIPS: kexec: Relax memory restriction Dengcheng Zhu
2018-07-12 1:27 ` [PATCH v2 6/6] MIPS: kexec: Use prepare method from generic platform as default option Dengcheng Zhu
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1531358868-10101-2-git-send-email-dzhu@wavecomp.com \
--to=dzhu@wavecomp.com \
--cc=linux-mips@linux-mips.org \
--cc=pburton@wavecomp.com \
--cc=ralf@linux-mips.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.