diff options
| author | Rany Hany | 2026-03-30 13:37:03 +0000 |
|---|---|---|
| committer | Hauke Mehrtens | 2026-04-12 20:12:15 +0000 |
| commit | fdeb6d6a9ffa568455ebdcc8eaac7667a50c47b6 (patch) | |
| tree | aae21258cd2a516a4cd9a44c81543b8e0723a01c | |
| parent | d7fe2c756255c37d5d27df1fb849a5cbbb4302d7 (diff) | |
| download | openwrt-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>
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(¤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 */ |