mirror of
https://github.com/torvalds/linux.git
synced 2024-11-17 01:22:07 +00:00
116c81f427
Systems with differing CPU i-cache/d-cache line sizes can cause problems with the cache management by software when the execution is migrated from one to another. Usually, the application reads the cache size on a CPU and then uses that length to perform cache operations. However, if it gets migrated to another CPU with a smaller cache line size, things could go completely wrong. To prevent such cases, always use the smallest cache line size among the CPUs. The kernel CPU feature infrastructure already keeps track of the safe value for all CPUID registers including CTR. This patch works around the problem by : For kernel, dynamically patch the kernel to read the cache size from the system wide copy of CTR_EL0. For applications, trap read accesses to CTR_EL0 (by clearing the SCTLR.UCT) and emulate the mrs instruction to return the system wide safe value of CTR_EL0. For faster access (i.e, avoiding to lookup the system wide value of CTR_EL0 via read_system_reg), we keep track of the pointer to table entry for CTR_EL0 in the CPU feature infrastructure. Cc: Mark Rutland <mark.rutland@arm.com> Cc: Andre Przywara <andre.przywara@arm.com> Cc: Will Deacon <will.deacon@arm.com> Cc: Catalin Marinas <catalin.marinas@arm.com> Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com> Signed-off-by: Will Deacon <will.deacon@arm.com>
165 lines
4.5 KiB
C
165 lines
4.5 KiB
C
/*
|
|
* Contains CPU specific errata definitions
|
|
*
|
|
* Copyright (C) 2014 ARM Ltd.
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License version 2 as
|
|
* published by the Free Software Foundation.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include <linux/types.h>
|
|
#include <asm/cpu.h>
|
|
#include <asm/cputype.h>
|
|
#include <asm/cpufeature.h>
|
|
|
|
static bool __maybe_unused
|
|
is_affected_midr_range(const struct arm64_cpu_capabilities *entry, int scope)
|
|
{
|
|
WARN_ON(scope != SCOPE_LOCAL_CPU || preemptible());
|
|
return MIDR_IS_CPU_MODEL_RANGE(read_cpuid_id(), entry->midr_model,
|
|
entry->midr_range_min,
|
|
entry->midr_range_max);
|
|
}
|
|
|
|
static bool
|
|
has_mismatched_cache_line_size(const struct arm64_cpu_capabilities *entry,
|
|
int scope)
|
|
{
|
|
WARN_ON(scope != SCOPE_LOCAL_CPU || preemptible());
|
|
return (read_cpuid_cachetype() & arm64_ftr_reg_ctrel0.strict_mask) !=
|
|
(arm64_ftr_reg_ctrel0.sys_val & arm64_ftr_reg_ctrel0.strict_mask);
|
|
}
|
|
|
|
static void cpu_enable_trap_ctr_access(void *__unused)
|
|
{
|
|
/* Clear SCTLR_EL1.UCT */
|
|
config_sctlr_el1(SCTLR_EL1_UCT, 0);
|
|
}
|
|
|
|
#define MIDR_RANGE(model, min, max) \
|
|
.def_scope = SCOPE_LOCAL_CPU, \
|
|
.matches = is_affected_midr_range, \
|
|
.midr_model = model, \
|
|
.midr_range_min = min, \
|
|
.midr_range_max = max
|
|
|
|
const struct arm64_cpu_capabilities arm64_errata[] = {
|
|
#if defined(CONFIG_ARM64_ERRATUM_826319) || \
|
|
defined(CONFIG_ARM64_ERRATUM_827319) || \
|
|
defined(CONFIG_ARM64_ERRATUM_824069)
|
|
{
|
|
/* Cortex-A53 r0p[012] */
|
|
.desc = "ARM errata 826319, 827319, 824069",
|
|
.capability = ARM64_WORKAROUND_CLEAN_CACHE,
|
|
MIDR_RANGE(MIDR_CORTEX_A53, 0x00, 0x02),
|
|
.enable = cpu_enable_cache_maint_trap,
|
|
},
|
|
#endif
|
|
#ifdef CONFIG_ARM64_ERRATUM_819472
|
|
{
|
|
/* Cortex-A53 r0p[01] */
|
|
.desc = "ARM errata 819472",
|
|
.capability = ARM64_WORKAROUND_CLEAN_CACHE,
|
|
MIDR_RANGE(MIDR_CORTEX_A53, 0x00, 0x01),
|
|
.enable = cpu_enable_cache_maint_trap,
|
|
},
|
|
#endif
|
|
#ifdef CONFIG_ARM64_ERRATUM_832075
|
|
{
|
|
/* Cortex-A57 r0p0 - r1p2 */
|
|
.desc = "ARM erratum 832075",
|
|
.capability = ARM64_WORKAROUND_DEVICE_LOAD_ACQUIRE,
|
|
MIDR_RANGE(MIDR_CORTEX_A57, 0x00,
|
|
(1 << MIDR_VARIANT_SHIFT) | 2),
|
|
},
|
|
#endif
|
|
#ifdef CONFIG_ARM64_ERRATUM_834220
|
|
{
|
|
/* Cortex-A57 r0p0 - r1p2 */
|
|
.desc = "ARM erratum 834220",
|
|
.capability = ARM64_WORKAROUND_834220,
|
|
MIDR_RANGE(MIDR_CORTEX_A57, 0x00,
|
|
(1 << MIDR_VARIANT_SHIFT) | 2),
|
|
},
|
|
#endif
|
|
#ifdef CONFIG_ARM64_ERRATUM_845719
|
|
{
|
|
/* Cortex-A53 r0p[01234] */
|
|
.desc = "ARM erratum 845719",
|
|
.capability = ARM64_WORKAROUND_845719,
|
|
MIDR_RANGE(MIDR_CORTEX_A53, 0x00, 0x04),
|
|
},
|
|
#endif
|
|
#ifdef CONFIG_CAVIUM_ERRATUM_23154
|
|
{
|
|
/* Cavium ThunderX, pass 1.x */
|
|
.desc = "Cavium erratum 23154",
|
|
.capability = ARM64_WORKAROUND_CAVIUM_23154,
|
|
MIDR_RANGE(MIDR_THUNDERX, 0x00, 0x01),
|
|
},
|
|
#endif
|
|
#ifdef CONFIG_CAVIUM_ERRATUM_27456
|
|
{
|
|
/* Cavium ThunderX, T88 pass 1.x - 2.1 */
|
|
.desc = "Cavium erratum 27456",
|
|
.capability = ARM64_WORKAROUND_CAVIUM_27456,
|
|
MIDR_RANGE(MIDR_THUNDERX, 0x00,
|
|
(1 << MIDR_VARIANT_SHIFT) | 1),
|
|
},
|
|
{
|
|
/* Cavium ThunderX, T81 pass 1.0 */
|
|
.desc = "Cavium erratum 27456",
|
|
.capability = ARM64_WORKAROUND_CAVIUM_27456,
|
|
MIDR_RANGE(MIDR_THUNDERX_81XX, 0x00, 0x00),
|
|
},
|
|
#endif
|
|
{
|
|
.desc = "Mismatched cache line size",
|
|
.capability = ARM64_MISMATCHED_CACHE_LINE_SIZE,
|
|
.matches = has_mismatched_cache_line_size,
|
|
.def_scope = SCOPE_LOCAL_CPU,
|
|
.enable = cpu_enable_trap_ctr_access,
|
|
},
|
|
{
|
|
}
|
|
};
|
|
|
|
/*
|
|
* The CPU Errata work arounds are detected and applied at boot time
|
|
* and the related information is freed soon after. If the new CPU requires
|
|
* an errata not detected at boot, fail this CPU.
|
|
*/
|
|
void verify_local_cpu_errata_workarounds(void)
|
|
{
|
|
const struct arm64_cpu_capabilities *caps = arm64_errata;
|
|
|
|
for (; caps->matches; caps++)
|
|
if (!cpus_have_cap(caps->capability) &&
|
|
caps->matches(caps, SCOPE_LOCAL_CPU)) {
|
|
pr_crit("CPU%d: Requires work around for %s, not detected"
|
|
" at boot time\n",
|
|
smp_processor_id(),
|
|
caps->desc ? : "an erratum");
|
|
cpu_die_early();
|
|
}
|
|
}
|
|
|
|
void update_cpu_errata_workarounds(void)
|
|
{
|
|
update_cpu_capabilities(arm64_errata, "enabling workaround for");
|
|
}
|
|
|
|
void __init enable_errata_workarounds(void)
|
|
{
|
|
enable_cpu_capabilities(arm64_errata);
|
|
}
|