ramips: mt7621: fix reset hang
These patches stop secondary CPUs before restart and wait for them
to go offline, fixing the mt7621 reboot deadlock without needing to
disable CONFIG_LIST_HARDENED.
Signed-off-by: Rany Hany <rany_hany@riseup.net>
Link: https://github.com/openwrt/openwrt/pull/22724
(cherry picked from commit 3166710fc9)
Link: https://github.com/openwrt/openwrt/pull/22673
Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
This commit is contained in:
parent
d7fe2c7562
commit
fdeb6d6a9f
@ -0,0 +1,67 @@
|
||||
From 641e36faf86bcd9b6dc2cd4a6d6e3fc604ee6397 Mon Sep 17 00:00:00 2001
|
||||
From: Rany Hany <rany_hany@riseup.net>
|
||||
Date: Tue, 31 Mar 2026 17:46:35 +0300
|
||||
Subject: [PATCH 1/3] MIPS: Stop secondary CPUs before platform
|
||||
restart/halt/poweroff
|
||||
|
||||
smp_send_stop() was placed after the platform restart, halt, and
|
||||
power-off callbacks. These callbacks never return, so smp_send_stop()
|
||||
was dead code and secondary CPUs were never stopped before the system
|
||||
reset. Move smp_send_stop() before the callbacks.
|
||||
|
||||
Signed-off-by: Rany Hany <rany_hany@riseup.net>
|
||||
---
|
||||
arch/mips/kernel/reset.c | 19 +++++++++++--------
|
||||
1 file changed, 11 insertions(+), 8 deletions(-)
|
||||
|
||||
--- a/arch/mips/kernel/reset.c
|
||||
+++ b/arch/mips/kernel/reset.c
|
||||
@@ -87,13 +87,14 @@ static void machine_hang(void)
|
||||
|
||||
void machine_restart(char *command)
|
||||
{
|
||||
- if (_machine_restart)
|
||||
- _machine_restart(command);
|
||||
-
|
||||
#ifdef CONFIG_SMP
|
||||
preempt_disable();
|
||||
smp_send_stop();
|
||||
#endif
|
||||
+
|
||||
+ if (_machine_restart)
|
||||
+ _machine_restart(command);
|
||||
+
|
||||
do_kernel_restart(command);
|
||||
mdelay(1000);
|
||||
pr_emerg("Reboot failed -- System halted\n");
|
||||
@@ -102,23 +103,25 @@ void machine_restart(char *command)
|
||||
|
||||
void machine_halt(void)
|
||||
{
|
||||
- if (_machine_halt)
|
||||
- _machine_halt();
|
||||
-
|
||||
#ifdef CONFIG_SMP
|
||||
preempt_disable();
|
||||
smp_send_stop();
|
||||
#endif
|
||||
+
|
||||
+ if (_machine_halt)
|
||||
+ _machine_halt();
|
||||
+
|
||||
machine_hang();
|
||||
}
|
||||
|
||||
void machine_power_off(void)
|
||||
{
|
||||
- do_kernel_power_off();
|
||||
-
|
||||
#ifdef CONFIG_SMP
|
||||
preempt_disable();
|
||||
smp_send_stop();
|
||||
#endif
|
||||
+
|
||||
+ do_kernel_power_off();
|
||||
+
|
||||
machine_hang();
|
||||
}
|
||||
@ -0,0 +1,36 @@
|
||||
From 251cd7607a3dcc578b249d2a685db99d7da73975 Mon Sep 17 00:00:00 2001
|
||||
From: Rany Hany <rany_hany@riseup.net>
|
||||
Date: Tue, 31 Mar 2026 18:07:36 +0300
|
||||
Subject: [PATCH 2/3] MIPS: SMP: Wait for secondary CPUs to stop in
|
||||
smp_send_stop()
|
||||
|
||||
smp_send_stop() returns immediately without waiting.
|
||||
|
||||
Wait up to one second for secondary CPUs to mark themselves offline
|
||||
before returning, similar to what ARM and ARM64 already do.
|
||||
|
||||
Signed-off-by: Rany Hany <rany_hany@riseup.net>
|
||||
---
|
||||
arch/mips/kernel/smp.c | 10 ++++++++++
|
||||
1 file changed, 10 insertions(+)
|
||||
|
||||
--- a/arch/mips/kernel/smp.c
|
||||
+++ b/arch/mips/kernel/smp.c
|
||||
@@ -416,7 +416,17 @@ static void stop_this_cpu(void *dummy)
|
||||
|
||||
void smp_send_stop(void)
|
||||
{
|
||||
+ unsigned long timeout;
|
||||
+
|
||||
smp_call_function(stop_this_cpu, NULL, 0);
|
||||
+
|
||||
+ /* Wait up to 1s for other CPUs to stop */
|
||||
+ timeout = USEC_PER_SEC;
|
||||
+ while (num_online_cpus() > 1 && timeout--)
|
||||
+ udelay(1);
|
||||
+
|
||||
+ if (num_online_cpus() > 1)
|
||||
+ pr_warn("SMP: failed to stop secondary CPUs\n");
|
||||
}
|
||||
|
||||
void __init smp_cpus_done(unsigned int max_cpus)
|
||||
@ -0,0 +1,104 @@
|
||||
From de332bdaf33c09be03c05c0681beae1276ccbcc2 Mon Sep 17 00:00:00 2001
|
||||
From: Rany Hany <rany_hany@riseup.net>
|
||||
Date: Tue, 31 Mar 2026 20:29:53 +0300
|
||||
Subject: [PATCH 3/3] MIPS: SMP: Properly stop secondary CPUs for restart
|
||||
|
||||
MT7621 deadlocks in the platform restart callback unless the other
|
||||
CPUs are stopped by taking other cores out of coherence and clocking
|
||||
them off, while halting sibling TCs on the restarting core.
|
||||
|
||||
This fixes restart deadlocks on MT7621, although the exact reason
|
||||
why this is required is still unclear.
|
||||
|
||||
Signed-off-by: Rany Hany <rany_hany@riseup.net>
|
||||
---
|
||||
arch/mips/kernel/smp.c | 54 +++++++++++++++++++++++++++++++++++++++++-
|
||||
1 file changed, 53 insertions(+), 1 deletion(-)
|
||||
|
||||
--- a/arch/mips/kernel/smp.c
|
||||
+++ b/arch/mips/kernel/smp.c
|
||||
@@ -32,6 +32,7 @@
|
||||
#include <asm/processor.h>
|
||||
#include <asm/idle.h>
|
||||
#include <asm/r4k-timer.h>
|
||||
+#include <asm/r4kcache.h>
|
||||
#include <asm/mips-cps.h>
|
||||
#include <asm/mmu_context.h>
|
||||
#include <asm/time.h>
|
||||
@@ -402,6 +403,8 @@ asmlinkage void start_secondary(void)
|
||||
cpu_startup_entry(CPUHP_AP_ONLINE_IDLE);
|
||||
}
|
||||
|
||||
+static atomic_t core_stop_count[NR_CPUS];
|
||||
+
|
||||
static void stop_this_cpu(void *dummy)
|
||||
{
|
||||
/*
|
||||
@@ -411,13 +414,66 @@ static void stop_this_cpu(void *dummy)
|
||||
set_cpu_online(smp_processor_id(), false);
|
||||
calculate_cpu_foreign_map();
|
||||
local_irq_disable();
|
||||
- while (1);
|
||||
+
|
||||
+ if (mips_cm_present() && r4k_blast_dcache) {
|
||||
+ unsigned int core = cpu_core(¤t_cpu_data);
|
||||
+
|
||||
+ if (atomic_dec_and_test(&core_stop_count[core])) {
|
||||
+ /* Flush data cache */
|
||||
+ r4k_blast_dcache();
|
||||
+ __sync();
|
||||
+
|
||||
+ if (mips_cm_revision() < CM_REV_CM3) {
|
||||
+ /* Restrict coherence to own core first */
|
||||
+ write_gcr_cl_coherence(1 << core);
|
||||
+ read_gcr_cl_coherence();
|
||||
+ __sync();
|
||||
+ }
|
||||
+
|
||||
+ /* Disable coherence */
|
||||
+ write_gcr_cl_coherence(0);
|
||||
+ read_gcr_cl_coherence();
|
||||
+
|
||||
+ /* Gate the core clock */
|
||||
+ if (mips_cpc_present())
|
||||
+ write_cpc_cl_cmd(CPC_Cx_CMD_CLOCKOFF);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (cpu_has_mipsmt) {
|
||||
+ /* The last active VPE on the core will gate the core clock
|
||||
+ * and all other remaining VPEs will halt this TC instead.
|
||||
+ *
|
||||
+ * Note that on systems without CPC, this will be the
|
||||
+ * only way to shutdown the CPU.
|
||||
+ */
|
||||
+ write_c0_tchalt(TCHALT_H);
|
||||
+ instruction_hazard();
|
||||
+ }
|
||||
+
|
||||
+ while (1)
|
||||
+ cpu_relax();
|
||||
}
|
||||
|
||||
void smp_send_stop(void)
|
||||
{
|
||||
+ static unsigned long stop_in_progress;
|
||||
unsigned long timeout;
|
||||
|
||||
+ if (test_and_set_bit(0, &stop_in_progress))
|
||||
+ return;
|
||||
+
|
||||
+ if (mips_cm_present()) {
|
||||
+ unsigned int cpu;
|
||||
+
|
||||
+ for_each_online_cpu(cpu) {
|
||||
+ unsigned int core;
|
||||
+
|
||||
+ core = cpu_core(&cpu_data[cpu]);
|
||||
+ atomic_inc(&core_stop_count[core]);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
smp_call_function(stop_this_cpu, NULL, 0);
|
||||
|
||||
/* Wait up to 1s for other CPUs to stop */
|
||||
Loading…
Reference in New Issue
Block a user