Linux-ARM-Kernel Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2] arm64: errata: Handle Apple WFI State Loss
@ 2026-06-15 12:21 Yureka Lilian
  2026-06-15 12:59 ` Nick Chan
  2026-06-15 15:02 ` Will Deacon
  0 siblings, 2 replies; 4+ messages in thread
From: Yureka Lilian @ 2026-06-15 12:21 UTC (permalink / raw)
  To: Catalin Marinas, Will Deacon
  Cc: linux-arm-kernel, linux-kernel, asahi, Sasha Finkelstein,
	Yureka Lilian

Apple Silicon CPUs can lose register state in WFI, leading to crashes
in the idle loop early in the boot process.
This applies to any previous Apple Silicon CPUs too, but is worked
around by configuring the WFI mode in SYS_IMP_APL_CYC_OVRD sysreg
during m1n1's chickens setup.
This workaround no longer exists since M4.

Add a workaround capability for replacing wfi and wfit with nop, and
an erratum to enable it on the affected CPUs if the workaround using the
sysreg is not already applied. Leave the decision whether the sysreg
workaround can be used up to the earlier parts of the boot chain which
already configure the Apple Silicon chicken bits.

This alternative has to be applied in early boot, since otherwise some
cores might enter the idle loop before apply_alternatives_all() is run.

Reviewed-by: Sasha Finkelstein <k@chaosmail.tech>
Signed-off-by: Yureka Lilian <yureka@cyberchaos.dev>
---
Changes since v1:
Restricted the erratum to EL2 only, since in EL1 we'd expect the
hypervisor to trap WFI and handle the erratum.

Tested on M4 and M4 Pro (which now sometimes nondeterministically
crash later during boot).
Successfully booted on M3 Max with the SYS_IMP_APL_CYC_OVRD
workaround disabled in the bootloader, as well as A18 Pro (which,
like M4 / M4 Pro, doesn't have SYS_IMP_APL_CYC_OVRD).

There is probably a better place for the SYS_IMP_APL_CYC_OVRD
defines, which I currently put in the middle of cpu_errata.c, but I
wouldn't know where.
---
 arch/arm64/Kconfig               | 12 ++++++++++++
 arch/arm64/include/asm/barrier.h | 19 ++++++++++++++++---
 arch/arm64/kernel/cpu_errata.c   | 21 +++++++++++++++++++++
 arch/arm64/tools/cpucaps         |  1 +
 4 files changed, 50 insertions(+), 3 deletions(-)

diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index b3afe0688919..8c8ff069856f 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -453,6 +453,18 @@ config AMPERE_ERRATUM_AC04_CPU_23
 
 	  If unsure, say Y.
 
+config APPLE_ERRATUM_WFI_STATE
+	bool "Apple Silicon: WFI loses state"
+	default y
+	help
+	  This option adds an alternative code sequence to work around some
+	  Apple Silicon CPUs losing register state during wfi and wfit
+	  instructions.
+
+	  As a workaround, the wfi and wfit instructions are replaced with nop
+	  operations via the alternative framework if an affected CPU is
+	  detected.
+
 config ARM64_WORKAROUND_CLEAN_CACHE
 	bool
 
diff --git a/arch/arm64/include/asm/barrier.h b/arch/arm64/include/asm/barrier.h
index 9495c4441a46..f72eddc7c434 100644
--- a/arch/arm64/include/asm/barrier.h
+++ b/arch/arm64/include/asm/barrier.h
@@ -20,9 +20,22 @@
 #define wfe()		asm volatile("wfe" : : : "memory")
 #define wfet(val)	asm volatile("msr s0_3_c1_c0_0, %0"	\
 				     : : "r" (val) : "memory")
-#define wfi()		asm volatile("wfi" : : : "memory")
-#define wfit(val)	asm volatile("msr s0_3_c1_c0_1, %0"	\
-				     : : "r" (val) : "memory")
+#define wfi()							\
+	do {							\
+		asm volatile(					\
+		ALTERNATIVE("wfi",				\
+			    "nop",				\
+			    ARM64_WORKAROUND_WFI_STATE)		\
+		: : : "memory");				\
+	} while (0)
+#define wfit(val)						\
+	do {							\
+		asm volatile(					\
+		ALTERNATIVE("msr s0_3_c1_c0_1, %0",		\
+			    "nop",				\
+			    ARM64_WORKAROUND_WFI_STATE)		\
+		: : "r" (val) : "memory");			\
+	} while (0)
 
 #define isb()		asm volatile("isb" : : : "memory")
 #define dmb(opt)	asm volatile("dmb " #opt : : : "memory")
diff --git a/arch/arm64/kernel/cpu_errata.c b/arch/arm64/kernel/cpu_errata.c
index 1995e1198648..8c9a194eddc4 100644
--- a/arch/arm64/kernel/cpu_errata.c
+++ b/arch/arm64/kernel/cpu_errata.c
@@ -309,6 +309,19 @@ static void cpu_enable_impdef_pmuv3_traps(const struct arm64_cpu_capabilities *_
 	sysreg_clear_set_s(SYS_HACR_EL2, 0, BIT(56));
 }
 
+#ifdef CONFIG_APPLE_ERRATUM_WFI_STATE
+static bool has_apple_erratum_wfi_state(const struct arm64_cpu_capabilities *entry, int scope)
+{
+#define SYS_IMP_APL_CYC_OVRD   sys_reg(3, 5, 15, 5, 0)
+#define CYC_OVRD_WFI_MODE_MASK GENMASK(26, 24)
+	if (read_cpuid_implementor() != ARM_CPU_IMP_APPLE)
+		return false;
+	if ((read_sysreg(CurrentEL) >> 2) != 2)
+		return false;
+	return FIELD_GET(CYC_OVRD_WFI_MODE_MASK, read_sysreg_s(SYS_IMP_APL_CYC_OVRD)) != 2;
+}
+#endif
+
 #ifdef CONFIG_ARM64_WORKAROUND_REPEAT_TLBI
 static const struct arm64_cpu_capabilities arm64_repeat_tlbi_list[] = {
 #ifdef CONFIG_QCOM_FALKOR_ERRATUM_1009
@@ -1009,6 +1022,14 @@ const struct arm64_cpu_capabilities arm64_errata[] = {
 		.matches = has_impdef_pmuv3,
 		.cpu_enable = cpu_enable_impdef_pmuv3_traps,
 	},
+#ifdef CONFIG_APPLE_ERRATUM_WFI_STATE
+	{
+		.desc = "Apple WFI loses state",
+		.capability = ARM64_WORKAROUND_WFI_STATE,
+		.type = ARM64_CPUCAP_SCOPE_BOOT_CPU | ARM64_CPUCAP_OPTIONAL_FOR_LATE_CPU,
+		.matches = has_apple_erratum_wfi_state,
+	},
+#endif
 	{
 	}
 };
diff --git a/arch/arm64/tools/cpucaps b/arch/arm64/tools/cpucaps
index 9b85a84f6fd4..bbf8c15d79b0 100644
--- a/arch/arm64/tools/cpucaps
+++ b/arch/arm64/tools/cpucaps
@@ -128,3 +128,4 @@ WORKAROUND_REPEAT_TLBI
 WORKAROUND_SPECULATIVE_AT
 WORKAROUND_SPECULATIVE_SSBS
 WORKAROUND_SPECULATIVE_UNPRIV_LOAD
+WORKAROUND_WFI_STATE

---
base-commit: c425609d6ac4012c8bbf01ec2e10e801b1923a7b
change-id: 20260614-wfi-erratum-7a9f305f601f

Best regards,
--  
Yureka Lilian <yureka@cyberchaos.dev>



^ permalink raw reply related	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2026-06-15 15:28 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-06-15 12:21 [PATCH v2] arm64: errata: Handle Apple WFI State Loss Yureka Lilian
2026-06-15 12:59 ` Nick Chan
2026-06-15 15:02 ` Will Deacon
2026-06-15 15:27   ` Sven Peter

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox