summaryrefslogtreecommitdiff
path: root/arch/arm64
diff options
context:
space:
mode:
authorWill Deacon <will@kernel.org>2026-08-14 10:16:08 +0000
committerWill Deacon <will@kernel.org>2026-08-14 10:16:08 +0000
commitba3349fc55d2f5de1751a03bd8ccff21b58e8953 (patch)
tree81c366f5f3b527c6c5b6aef2f0896b16495f7bba /arch/arm64
parentdc61684f5c7c809e47a1b2a2d7c2148d1cb22fff (diff)
parentd97afae6f16a4f8ac7d50af0070816270b5380c1 (diff)
Merge branch 'for-next/errata' into for-next/core
* for-next/errata: arch: arm64: add early_param idle=<wfi|yield|nop> arm64: proton-pack: Restore the nospectre_bhb command-line option arm64: errata: work around NVIDIA Olympus device store/load ordering arm64: Clarify ARM64_WORKAROUND_REPEAT_TLBI semantics
Diffstat (limited to 'arch/arm64')
-rw-r--r--arch/arm64/Kconfig56
-rw-r--r--arch/arm64/include/asm/cpucaps.h4
-rw-r--r--arch/arm64/include/asm/io.h16
-rw-r--r--arch/arm64/include/asm/tlbflush.h2
-rw-r--r--arch/arm64/kernel/cpu_errata.c14
-rw-r--r--arch/arm64/kernel/idle.c32
-rw-r--r--arch/arm64/kernel/proton-pack.c9
-rw-r--r--arch/arm64/tools/cpucaps3
8 files changed, 116 insertions, 20 deletions
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index fc57d90d92c1..9deea38ddb73 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -701,12 +701,34 @@ config ARM64_ERRATUM_1530923
If unsure, say Y.
-config ARM64_WORKAROUND_REPEAT_TLBI
+config ARM64_WORKAROUND_REPEAT_TLBI_SYNC
bool
+ # This workaround is (only) suitable for TLB invalidation errata where
+ # all of the following conditions are true:
+ #
+ # - The effects of the errata are only a loss of ordering/completion
+ # for explicit memory accesses when the TLBI is completed with a DSB.
+ # The removal of TLB entries is not affected.
+ #
+ # Note that architecturally, S2-only invalidation does not remove
+ # combined S1+S2 entries, and does not complete accesses translated
+ # via those S1+S2 entries. Consequently, where this condition holds,
+ # the errata do not affect S2-only invalidation.
+ #
+ # - The errata only affect broadcast TLB invalidation operations (e.g.
+ # TLBI VMALLE1IS), and do not affect local TLB invalidation
+ # operations (e.g. TLBI VMALLE1).
+ #
+ # - After any number of affected TLBI operations are completed with a
+ # DSB, the errata can be mitigated by executing a single arbitrary
+ # broadcast TLBI (which targets an arbitrary translation regime),
+ # followed by a DSB.
+ #
+ # For more rationale, see commit a8f78680ee6bf795.
config ARM64_ERRATUM_2441007
bool "Cortex-A55: Completion of affected memory accesses might not be guaranteed by completion of a TLBI (rare)"
- select ARM64_WORKAROUND_REPEAT_TLBI
+ select ARM64_WORKAROUND_REPEAT_TLBI_SYNC
help
This option adds a workaround for ARM Cortex-A55 erratum #2441007.
@@ -722,7 +744,7 @@ config ARM64_ERRATUM_2441007
config ARM64_ERRATUM_1286807
bool "Cortex-A76: Modification of the translation table for a virtual address might lead to read-after-read ordering violation (rare)"
- select ARM64_WORKAROUND_REPEAT_TLBI
+ select ARM64_WORKAROUND_REPEAT_TLBI_SYNC
help
This option adds a workaround for ARM Cortex-A76 erratum 1286807.
@@ -944,7 +966,7 @@ config ARM64_ERRATUM_2224489
config ARM64_ERRATUM_2441009
bool "Cortex-A510: Completion of affected memory accesses might not be guaranteed by completion of a TLBI (rare)"
- select ARM64_WORKAROUND_REPEAT_TLBI
+ select ARM64_WORKAROUND_REPEAT_TLBI_SYNC
help
This option adds a workaround for ARM Cortex-A510 erratum #2441009.
@@ -1156,7 +1178,7 @@ config ARM64_ERRATUM_4193714
config ARM64_ERRATUM_4118414
bool "Various: Completion of affected memory accesses might not be guaranteed by completion of a TLBI"
default y
- select ARM64_WORKAROUND_REPEAT_TLBI
+ select ARM64_WORKAROUND_REPEAT_TLBI_SYNC
help
This option adds a workaround for the following errata:
@@ -1340,7 +1362,7 @@ config QCOM_FALKOR_ERRATUM_1003
config QCOM_FALKOR_ERRATUM_1009
bool "Falkor E1009: Prematurely complete a DSB after a TLBI"
default y
- select ARM64_WORKAROUND_REPEAT_TLBI
+ select ARM64_WORKAROUND_REPEAT_TLBI_SYNC
help
On Falkor v1, the CPU may prematurely complete a DSB following a
TLBI xxIS invalidate maintenance operation. Repeat the TLBI operation
@@ -1382,6 +1404,28 @@ config NVIDIA_CARMEL_CNP_ERRATUM
If unsure, say Y.
+config NVIDIA_OLYMPUS_1027_ERRATUM
+ bool "NVIDIA Olympus: device store/load ordering erratum"
+ default y
+ help
+ This option adds an alternative code sequence to work around an
+ NVIDIA Olympus core erratum where a Device-nGnR* store can be
+ observed by a peripheral after a younger Device-nGnR* load to the
+ same peripheral. This breaks the program order that drivers rely
+ on for MMIO and can leave a device in an incorrect state.
+
+ The workaround inserts a DMB OSH immediately before raw MMIO loads.
+ The erratum cannot occur when a DMB that orders loads appears
+ between the store and load, preventing the younger load from being
+ observed before the older store.
+
+ The alternatives framework patches in DMB OSH only when an affected
+ CPU is detected. Other CPUs execute a NOP in its place. Disabling
+ this option leaves the original MMIO read instruction stream
+ unchanged.
+
+ If unsure, say Y.
+
config ROCKCHIP_ERRATUM_3568002
bool "Rockchip 3568002: GIC600 can not access physical addresses higher than 4GB"
default y
diff --git a/arch/arm64/include/asm/cpucaps.h b/arch/arm64/include/asm/cpucaps.h
index 25c61cda901c..76350b38f0d7 100644
--- a/arch/arm64/include/asm/cpucaps.h
+++ b/arch/arm64/include/asm/cpucaps.h
@@ -60,8 +60,8 @@ cpucap_is_possible(const unsigned int cap)
return IS_ENABLED(CONFIG_CAVIUM_ERRATUM_23154);
case ARM64_WORKAROUND_DISABLE_CNP:
return IS_ENABLED(CONFIG_ARM64_WORKAROUND_DISABLE_CNP);
- case ARM64_WORKAROUND_REPEAT_TLBI:
- return IS_ENABLED(CONFIG_ARM64_WORKAROUND_REPEAT_TLBI);
+ case ARM64_WORKAROUND_REPEAT_TLBI_SYNC:
+ return IS_ENABLED(CONFIG_ARM64_WORKAROUND_REPEAT_TLBI_SYNC);
case ARM64_WORKAROUND_SPECULATIVE_SSBS:
return IS_ENABLED(CONFIG_ARM64_ERRATUM_3194386);
case ARM64_WORKAROUND_4193714:
diff --git a/arch/arm64/include/asm/io.h b/arch/arm64/include/asm/io.h
index 21c8e400107c..49a7002661a9 100644
--- a/arch/arm64/include/asm/io.h
+++ b/arch/arm64/include/asm/io.h
@@ -54,7 +54,9 @@ static __always_inline void __raw_writeq(u64 val, volatile void __iomem *addr)
static __always_inline u8 __raw_readb(const volatile void __iomem *addr)
{
u8 val;
- asm volatile(ALTERNATIVE("ldrb %w0, [%1]",
+ asm volatile(ALTERNATIVE("nop", "dmb osh",
+ ARM64_WORKAROUND_NVIDIA_OLYMPUS_1027)
+ ALTERNATIVE("ldrb %w0, [%1]",
"ldarb %w0, [%1]",
ARM64_WORKAROUND_DEVICE_LOAD_ACQUIRE)
: "=r" (val) : "r" (addr));
@@ -66,7 +68,9 @@ static __always_inline u16 __raw_readw(const volatile void __iomem *addr)
{
u16 val;
- asm volatile(ALTERNATIVE("ldrh %w0, [%1]",
+ asm volatile(ALTERNATIVE("nop", "dmb osh",
+ ARM64_WORKAROUND_NVIDIA_OLYMPUS_1027)
+ ALTERNATIVE("ldrh %w0, [%1]",
"ldarh %w0, [%1]",
ARM64_WORKAROUND_DEVICE_LOAD_ACQUIRE)
: "=r" (val) : "r" (addr));
@@ -77,7 +81,9 @@ static __always_inline u16 __raw_readw(const volatile void __iomem *addr)
static __always_inline u32 __raw_readl(const volatile void __iomem *addr)
{
u32 val;
- asm volatile(ALTERNATIVE("ldr %w0, [%1]",
+ asm volatile(ALTERNATIVE("nop", "dmb osh",
+ ARM64_WORKAROUND_NVIDIA_OLYMPUS_1027)
+ ALTERNATIVE("ldr %w0, [%1]",
"ldar %w0, [%1]",
ARM64_WORKAROUND_DEVICE_LOAD_ACQUIRE)
: "=r" (val) : "r" (addr));
@@ -88,7 +94,9 @@ static __always_inline u32 __raw_readl(const volatile void __iomem *addr)
static __always_inline u64 __raw_readq(const volatile void __iomem *addr)
{
u64 val;
- asm volatile(ALTERNATIVE("ldr %0, [%1]",
+ asm volatile(ALTERNATIVE("nop", "dmb osh",
+ ARM64_WORKAROUND_NVIDIA_OLYMPUS_1027)
+ ALTERNATIVE("ldr %0, [%1]",
"ldar %0, [%1]",
ARM64_WORKAROUND_DEVICE_LOAD_ACQUIRE)
: "=r" (val) : "r" (addr));
diff --git a/arch/arm64/include/asm/tlbflush.h b/arch/arm64/include/asm/tlbflush.h
index e0e84332f51b..14a78ac0f800 100644
--- a/arch/arm64/include/asm/tlbflush.h
+++ b/arch/arm64/include/asm/tlbflush.h
@@ -236,7 +236,7 @@ static inline void __tlbi_level(tlbi_op op, u64 addr, u32 level)
#define __repeat_tlbi_sync(op, arg...) \
do { \
- if (!alternative_has_cap_unlikely(ARM64_WORKAROUND_REPEAT_TLBI)) \
+ if (!alternative_has_cap_unlikely(ARM64_WORKAROUND_REPEAT_TLBI_SYNC)) \
break; \
__tlbi(op, ##arg); \
dsb(ish); \
diff --git a/arch/arm64/kernel/cpu_errata.c b/arch/arm64/kernel/cpu_errata.c
index 1995e1198648..b5ba9c455aef 100644
--- a/arch/arm64/kernel/cpu_errata.c
+++ b/arch/arm64/kernel/cpu_errata.c
@@ -309,7 +309,7 @@ static void cpu_enable_impdef_pmuv3_traps(const struct arm64_cpu_capabilities *_
sysreg_clear_set_s(SYS_HACR_EL2, 0, BIT(56));
}
-#ifdef CONFIG_ARM64_WORKAROUND_REPEAT_TLBI
+#ifdef CONFIG_ARM64_WORKAROUND_REPEAT_TLBI_SYNC
static const struct arm64_cpu_capabilities arm64_repeat_tlbi_list[] = {
#ifdef CONFIG_QCOM_FALKOR_ERRATUM_1009
{
@@ -733,10 +733,10 @@ const struct arm64_cpu_capabilities arm64_errata[] = {
.match_list = qcom_erratum_1003_list,
},
#endif
-#ifdef CONFIG_ARM64_WORKAROUND_REPEAT_TLBI
+#ifdef CONFIG_ARM64_WORKAROUND_REPEAT_TLBI_SYNC
{
.desc = "Broken broadcast TLBI completion",
- .capability = ARM64_WORKAROUND_REPEAT_TLBI,
+ .capability = ARM64_WORKAROUND_REPEAT_TLBI_SYNC,
.type = ARM64_CPUCAP_LOCAL_CPU_ERRATUM,
.matches = cpucap_multi_entry_cap_matches,
.match_list = arm64_repeat_tlbi_list,
@@ -850,6 +850,14 @@ const struct arm64_cpu_capabilities arm64_errata[] = {
ERRATA_MIDR_RANGE_LIST(cnp_erratum_cpus),
},
#endif
+#ifdef CONFIG_NVIDIA_OLYMPUS_1027_ERRATUM
+ {
+ /* NVIDIA Olympus core */
+ .desc = "NVIDIA Olympus device store/load ordering erratum",
+ .capability = ARM64_WORKAROUND_NVIDIA_OLYMPUS_1027,
+ ERRATA_MIDR_ALL_VERSIONS(MIDR_NVIDIA_OLYMPUS),
+ },
+#endif
#ifdef CONFIG_ARM64_WORKAROUND_TRBE_OVERWRITE_FILL_MODE
{
/*
diff --git a/arch/arm64/kernel/idle.c b/arch/arm64/kernel/idle.c
index 05cfb347ec26..42c5543f9589 100644
--- a/arch/arm64/kernel/idle.c
+++ b/arch/arm64/kernel/idle.c
@@ -11,6 +11,29 @@
#include <asm/cpufeature.h>
#include <asm/sysreg.h>
+enum {
+ ARM64_IDLE_WFI,
+ ARM64_IDLE_YIELD,
+ ARM64_IDLE_NOP,
+} idle = ARM64_IDLE_WFI;
+
+static int __init setup_idle(char *arg)
+{
+ if (!arg)
+ return -1;
+ else if (!strcmp(arg, "wfi"))
+ idle = ARM64_IDLE_WFI;
+ else if (!strcmp(arg, "yield"))
+ idle = ARM64_IDLE_YIELD;
+ else if (!strcmp(arg, "nop"))
+ idle = ARM64_IDLE_NOP;
+ else
+ return -1;
+
+ return 0;
+}
+early_param("idle", setup_idle);
+
/*
* cpu_do_idle()
*
@@ -26,8 +49,13 @@ void __cpuidle cpu_do_idle(void)
arm_cpuidle_save_irq_context(&context);
- dsb(sy);
- wfi();
+ if (likely(idle == ARM64_IDLE_WFI)) {
+ dsb(sy);
+ wfi();
+ } else if (idle == ARM64_IDLE_YIELD) {
+ dsb(sy);
+ asm volatile("yield" ::: "memory");
+ }
arm_cpuidle_restore_irq_context(&context);
}
diff --git a/arch/arm64/kernel/proton-pack.c b/arch/arm64/kernel/proton-pack.c
index 7bb6553fec08..3bcf86154d95 100644
--- a/arch/arm64/kernel/proton-pack.c
+++ b/arch/arm64/kernel/proton-pack.c
@@ -1023,6 +1023,11 @@ static int __init parse_spectre_bhb_param(char *str)
}
early_param("nospectre_bhb", parse_spectre_bhb_param);
+static bool spectre_bhb_mitigations_off(void)
+{
+ return __nospectre_bhb || cpu_mitigations_off();
+}
+
void spectre_bhb_enable_mitigation(const struct arm64_cpu_capabilities *entry)
{
bp_hardening_cb_t cpu_cb;
@@ -1036,6 +1041,8 @@ void spectre_bhb_enable_mitigation(const struct arm64_cpu_capabilities *entry)
/* No point mitigating Spectre-BHB alone. */
} else if (!IS_ENABLED(CONFIG_MITIGATE_SPECTRE_BRANCH_HISTORY)) {
/* Do nothing */
+ } else if (spectre_bhb_mitigations_off()) {
+ /* Mitigation disabled on the command line */
} else if (supports_ecbhb(SCOPE_LOCAL_CPU)) {
state = SPECTRE_MITIGATED;
set_bit(BHB_HW, &system_bhb_mitigations);
@@ -1201,6 +1208,6 @@ void spectre_print_disabled_mitigations(void)
if (spectre_v4_mitigations_off())
pr_info("spectre-v4 %s", spectre_disabled_suffix);
- if (__nospectre_bhb || cpu_mitigations_off())
+ if (spectre_bhb_mitigations_off())
pr_info("spectre-bhb %s", spectre_disabled_suffix);
}
diff --git a/arch/arm64/tools/cpucaps b/arch/arm64/tools/cpucaps
index 0b94837ac238..0ee42b0cc8d3 100644
--- a/arch/arm64/tools/cpucaps
+++ b/arch/arm64/tools/cpucaps
@@ -121,10 +121,11 @@ WORKAROUND_CAVIUM_TX2_219_TVM
WORKAROUND_CLEAN_CACHE
WORKAROUND_DEVICE_LOAD_ACQUIRE
WORKAROUND_DISABLE_CNP
+WORKAROUND_NVIDIA_OLYMPUS_1027
WORKAROUND_PMUV3_IMPDEF_TRAPS
WORKAROUND_QCOM_FALKOR_E1003
WORKAROUND_QCOM_ORYON_CNTVOFF
-WORKAROUND_REPEAT_TLBI
+WORKAROUND_REPEAT_TLBI_SYNC
WORKAROUND_SPECULATIVE_AT
WORKAROUND_SPECULATIVE_SSBS
WORKAROUND_SPECULATIVE_UNPRIV_LOAD