summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRany Hany2026-03-30 13:37:03 +0000
committerHauke Mehrtens2026-04-12 20:12:15 +0000
commitfdeb6d6a9ffa568455ebdcc8eaac7667a50c47b6 (patch)
treeaae21258cd2a516a4cd9a44c81543b8e0723a01c
parentd7fe2c756255c37d5d27df1fb849a5cbbb4302d7 (diff)
downloadopenwrt-fdeb6d6a9ffa568455ebdcc8eaac7667a50c47b6.tar.gz
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 3166710fc96c6926a71eea1d72ac1d15cc00172e) Link: https://github.com/openwrt/openwrt/pull/22673 Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
-rw-r--r--target/linux/ramips/patches-6.12/932-MIPS-Stop-secondary-CPUs-before-platform-restart-hal.patch67
-rw-r--r--target/linux/ramips/patches-6.12/933-MIPS-SMP-Wait-for-secondary-CPUs-to-stop-in-smp_send.patch36
-rw-r--r--target/linux/ramips/patches-6.12/934-MIPS-SMP-Properly-stop-secondary-CPUs-for-restart.patch104
3 files changed, 207 insertions, 0 deletions
diff --git a/target/linux/ramips/patches-6.12/932-MIPS-Stop-secondary-CPUs-before-platform-restart-hal.patch b/target/linux/ramips/patches-6.12/932-MIPS-Stop-secondary-CPUs-before-platform-restart-hal.patch
new file mode 100644
index 0000000000..144c95bd25
--- /dev/null
+++ b/target/linux/ramips/patches-6.12/932-MIPS-Stop-secondary-CPUs-before-platform-restart-hal.patch
@@ -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();
+ }
diff --git a/target/linux/ramips/patches-6.12/933-MIPS-SMP-Wait-for-secondary-CPUs-to-stop-in-smp_send.patch b/target/linux/ramips/patches-6.12/933-MIPS-SMP-Wait-for-secondary-CPUs-to-stop-in-smp_send.patch
new file mode 100644
index 0000000000..74adbbefe9
--- /dev/null
+++ b/target/linux/ramips/patches-6.12/933-MIPS-SMP-Wait-for-secondary-CPUs-to-stop-in-smp_send.patch
@@ -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)
diff --git a/target/linux/ramips/patches-6.12/934-MIPS-SMP-Properly-stop-secondary-CPUs-for-restart.patch b/target/linux/ramips/patches-6.12/934-MIPS-SMP-Properly-stop-secondary-CPUs-for-restart.patch
new file mode 100644
index 0000000000..2587592139
--- /dev/null
+++ b/target/linux/ramips/patches-6.12/934-MIPS-SMP-Properly-stop-secondary-CPUs-for-restart.patch
@@ -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(&current_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 */