2014-03-04 01:10:04 +00:00
|
|
|
/*
|
|
|
|
* Copyright (C) 2014 Linaro Ltd. <ard.biesheuvel@linaro.org>
|
|
|
|
*
|
|
|
|
* 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.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef __ASM_CPUFEATURE_H
|
|
|
|
#define __ASM_CPUFEATURE_H
|
|
|
|
|
2016-09-05 17:25:48 +00:00
|
|
|
#include <linux/jump_label.h>
|
|
|
|
|
2014-03-04 01:10:04 +00:00
|
|
|
#include <asm/hwcap.h>
|
2015-10-19 13:24:42 +00:00
|
|
|
#include <asm/sysreg.h>
|
2014-03-04 01:10:04 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* In the arm64 world (as in the ARM world), elf_hwcap is used both internally
|
|
|
|
* in the kernel and for user space to keep track of which optional features
|
|
|
|
* are supported by the current system. So let's map feature 'x' to HWCAP_x.
|
|
|
|
* Note that HWCAP_x constants are bit fields so we need to take the log.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#define MAX_CPU_FEATURES (8 * sizeof(elf_hwcap))
|
|
|
|
#define cpu_feature(x) ilog2(HWCAP_ ## x)
|
|
|
|
|
2014-11-14 15:54:11 +00:00
|
|
|
#define ARM64_WORKAROUND_CLEAN_CACHE 0
|
|
|
|
#define ARM64_WORKAROUND_DEVICE_LOAD_ACQUIRE 1
|
2015-03-23 19:07:02 +00:00
|
|
|
#define ARM64_WORKAROUND_845719 2
|
2015-06-12 11:06:36 +00:00
|
|
|
#define ARM64_HAS_SYSREG_GIC_CPUIF 3
|
2015-07-22 18:05:54 +00:00
|
|
|
#define ARM64_HAS_PAN 4
|
2015-07-27 13:11:55 +00:00
|
|
|
#define ARM64_HAS_LSE_ATOMICS 5
|
2015-09-21 20:58:35 +00:00
|
|
|
#define ARM64_WORKAROUND_CAVIUM_23154 6
|
2015-11-16 10:28:18 +00:00
|
|
|
#define ARM64_WORKAROUND_834220 7
|
2016-02-02 12:46:24 +00:00
|
|
|
#define ARM64_HAS_NO_HW_PREFETCH 8
|
2016-02-05 14:58:48 +00:00
|
|
|
#define ARM64_HAS_UAO 9
|
2016-02-05 14:58:50 +00:00
|
|
|
#define ARM64_ALT_PAN_NOT_UAO 10
|
2015-01-29 11:24:05 +00:00
|
|
|
#define ARM64_HAS_VIRT_HOST_EXTN 11
|
2016-02-25 01:44:57 +00:00
|
|
|
#define ARM64_WORKAROUND_CAVIUM_27456 12
|
2016-04-18 09:28:36 +00:00
|
|
|
#define ARM64_HAS_32BIT_EL0 13
|
2016-06-30 17:40:38 +00:00
|
|
|
#define ARM64_HYP_OFFSET_LOW 14
|
2014-11-14 15:54:10 +00:00
|
|
|
|
2016-06-30 17:40:38 +00:00
|
|
|
#define ARM64_NCAPS 15
|
2014-11-14 15:54:10 +00:00
|
|
|
|
|
|
|
#ifndef __ASSEMBLY__
|
2014-11-14 15:54:07 +00:00
|
|
|
|
2015-04-30 17:55:50 +00:00
|
|
|
#include <linux/kernel.h>
|
|
|
|
|
2015-10-19 13:24:45 +00:00
|
|
|
/* CPU feature register tracking */
|
|
|
|
enum ftr_type {
|
|
|
|
FTR_EXACT, /* Use a predefined safe value */
|
|
|
|
FTR_LOWER_SAFE, /* Smaller value is safe */
|
|
|
|
FTR_HIGHER_SAFE,/* Bigger value is safe */
|
|
|
|
};
|
|
|
|
|
|
|
|
#define FTR_STRICT true /* SANITY check strict matching required */
|
|
|
|
#define FTR_NONSTRICT false /* SANITY check ignored */
|
|
|
|
|
2015-11-18 17:08:57 +00:00
|
|
|
#define FTR_SIGNED true /* Value should be treated as signed */
|
|
|
|
#define FTR_UNSIGNED false /* Value should be treated as unsigned */
|
|
|
|
|
2015-10-19 13:24:45 +00:00
|
|
|
struct arm64_ftr_bits {
|
2015-11-18 17:08:57 +00:00
|
|
|
bool sign; /* Value is signed ? */
|
|
|
|
bool strict; /* CPU Sanity check: strict matching required ? */
|
2015-10-19 13:24:45 +00:00
|
|
|
enum ftr_type type;
|
|
|
|
u8 shift;
|
|
|
|
u8 width;
|
2016-09-09 13:07:08 +00:00
|
|
|
s64 safe_val; /* safe value for FTR_EXACT features */
|
2015-10-19 13:24:45 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
* @arm64_ftr_reg - Feature register
|
|
|
|
* @strict_mask Bits which should match across all CPUs for sanity.
|
|
|
|
* @sys_val Safe value across the CPUs (system view)
|
|
|
|
*/
|
|
|
|
struct arm64_ftr_reg {
|
2016-08-31 10:31:08 +00:00
|
|
|
const char *name;
|
|
|
|
u64 strict_mask;
|
|
|
|
u64 sys_val;
|
|
|
|
const struct arm64_ftr_bits *ftr_bits;
|
2015-10-19 13:24:45 +00:00
|
|
|
};
|
|
|
|
|
2016-08-31 10:31:10 +00:00
|
|
|
extern struct arm64_ftr_reg arm64_ftr_reg_ctrel0;
|
|
|
|
|
2016-04-22 11:25:31 +00:00
|
|
|
/* scope of capability check */
|
|
|
|
enum {
|
|
|
|
SCOPE_SYSTEM,
|
|
|
|
SCOPE_LOCAL_CPU,
|
|
|
|
};
|
|
|
|
|
2015-03-27 13:09:23 +00:00
|
|
|
struct arm64_cpu_capabilities {
|
|
|
|
const char *desc;
|
|
|
|
u16 capability;
|
2016-04-22 11:25:31 +00:00
|
|
|
int def_scope; /* default scope */
|
|
|
|
bool (*matches)(const struct arm64_cpu_capabilities *caps, int scope);
|
arm64: Delay cpu feature capability checks
At the moment we run through the arm64_features capability list for
each CPU and set the capability if one of the CPU supports it. This
could be problematic in a heterogeneous system with differing capabilities.
Delay the CPU feature checks until all the enabled CPUs are up(i.e,
smp_cpus_done(), so that we can make better decisions based on the
overall system capability. Once we decide and advertise the capabilities
the alternatives can be applied. From this state, we cannot roll back
a feature to disabled based on the values from a new hotplugged CPU,
due to the runtime patching and other reasons. So, for all new CPUs,
we need to make sure that they have the established system capabilities.
Failing which, we bring the CPU down, preventing it from turning online.
Once the capabilities are decided, any new CPU booting up goes through
verification to ensure that it has all the enabled capabilities and also
invokes the respective enable() method on the CPU.
The CPU errata checks are not delayed and is still executed per-CPU
to detect the respective capabilities. If we ever come across a non-errata
capability that needs to be checked on each-CPU, we could introduce them via
a new capability table(or introduce a flag), which can be processed per CPU.
The next patch will make the feature checks use the system wide
safe value of a feature register.
NOTE: The enable() methods associated with the capability is scheduled
on all the CPUs (which is the only use case at the moment). If we need
a different type of 'enable()' which only needs to be run once on any CPU,
we should be able to handle that when needed.
Signed-off-by: Suzuki K. Poulose <suzuki.poulose@arm.com>
Tested-by: Dave Martin <Dave.Martin@arm.com>
[catalin.marinas@arm.com: static variable and coding style fixes]
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
2015-10-19 13:24:50 +00:00
|
|
|
void (*enable)(void *); /* Called on all active CPUs */
|
2015-03-27 13:09:23 +00:00
|
|
|
union {
|
|
|
|
struct { /* To be used for erratum handling only */
|
|
|
|
u32 midr_model;
|
|
|
|
u32 midr_range_min, midr_range_max;
|
|
|
|
};
|
2015-06-12 11:06:36 +00:00
|
|
|
|
|
|
|
struct { /* Feature register checking */
|
2015-10-19 13:24:51 +00:00
|
|
|
u32 sys_reg;
|
2016-01-26 10:58:15 +00:00
|
|
|
u8 field_pos;
|
|
|
|
u8 min_field_value;
|
|
|
|
u8 hwcap_type;
|
|
|
|
bool sign;
|
2015-10-19 13:24:52 +00:00
|
|
|
unsigned long hwcap;
|
2015-06-12 11:06:36 +00:00
|
|
|
};
|
2015-03-27 13:09:23 +00:00
|
|
|
};
|
|
|
|
};
|
|
|
|
|
arm64: Provide a namespace to NCAPS
Building arm64.allmodconfig leads to the following warning:
usb/gadget/function/f_ncm.c:203:0: warning: "NCAPS" redefined
#define NCAPS (USB_CDC_NCM_NCAP_ETH_FILTER | USB_CDC_NCM_NCAP_CRC_MODE)
^
In file included from /home/build/work/batch/arch/arm64/include/asm/io.h:32:0,
from /home/build/work/batch/include/linux/clocksource.h:19,
from /home/build/work/batch/include/clocksource/arm_arch_timer.h:19,
from /home/build/work/batch/arch/arm64/include/asm/arch_timer.h:27,
from /home/build/work/batch/arch/arm64/include/asm/timex.h:19,
from /home/build/work/batch/include/linux/timex.h:65,
from /home/build/work/batch/include/linux/sched.h:19,
from /home/build/work/batch/arch/arm64/include/asm/compat.h:25,
from /home/build/work/batch/arch/arm64/include/asm/stat.h:23,
from /home/build/work/batch/include/linux/stat.h:5,
from /home/build/work/batch/include/linux/module.h:10,
from /home/build/work/batch/drivers/usb/gadget/function/f_ncm.c:19:
arch/arm64/include/asm/cpufeature.h:27:0: note: this is the location of the previous definition
#define NCAPS 2
So add a ARM64 prefix to avoid such problem.
Reported-by: Olof's autobuilder <build@lixom.net>
Signed-off-by: Fabio Estevam <fabio.estevam@freescale.com>
Signed-off-by: Will Deacon <will.deacon@arm.com>
2014-12-04 01:17:01 +00:00
|
|
|
extern DECLARE_BITMAP(cpu_hwcaps, ARM64_NCAPS);
|
2016-09-05 17:25:48 +00:00
|
|
|
extern struct static_key_false cpu_hwcap_keys[ARM64_NCAPS];
|
2014-11-14 15:54:07 +00:00
|
|
|
|
2016-04-22 11:25:32 +00:00
|
|
|
bool this_cpu_has_cap(unsigned int cap);
|
|
|
|
|
2014-03-04 01:10:04 +00:00
|
|
|
static inline bool cpu_have_feature(unsigned int num)
|
|
|
|
{
|
|
|
|
return elf_hwcap & (1UL << num);
|
|
|
|
}
|
|
|
|
|
2014-11-14 15:54:07 +00:00
|
|
|
static inline bool cpus_have_cap(unsigned int num)
|
|
|
|
{
|
arm64: Provide a namespace to NCAPS
Building arm64.allmodconfig leads to the following warning:
usb/gadget/function/f_ncm.c:203:0: warning: "NCAPS" redefined
#define NCAPS (USB_CDC_NCM_NCAP_ETH_FILTER | USB_CDC_NCM_NCAP_CRC_MODE)
^
In file included from /home/build/work/batch/arch/arm64/include/asm/io.h:32:0,
from /home/build/work/batch/include/linux/clocksource.h:19,
from /home/build/work/batch/include/clocksource/arm_arch_timer.h:19,
from /home/build/work/batch/arch/arm64/include/asm/arch_timer.h:27,
from /home/build/work/batch/arch/arm64/include/asm/timex.h:19,
from /home/build/work/batch/include/linux/timex.h:65,
from /home/build/work/batch/include/linux/sched.h:19,
from /home/build/work/batch/arch/arm64/include/asm/compat.h:25,
from /home/build/work/batch/arch/arm64/include/asm/stat.h:23,
from /home/build/work/batch/include/linux/stat.h:5,
from /home/build/work/batch/include/linux/module.h:10,
from /home/build/work/batch/drivers/usb/gadget/function/f_ncm.c:19:
arch/arm64/include/asm/cpufeature.h:27:0: note: this is the location of the previous definition
#define NCAPS 2
So add a ARM64 prefix to avoid such problem.
Reported-by: Olof's autobuilder <build@lixom.net>
Signed-off-by: Fabio Estevam <fabio.estevam@freescale.com>
Signed-off-by: Will Deacon <will.deacon@arm.com>
2014-12-04 01:17:01 +00:00
|
|
|
if (num >= ARM64_NCAPS)
|
2014-11-14 15:54:07 +00:00
|
|
|
return false;
|
2016-09-05 17:25:48 +00:00
|
|
|
if (__builtin_constant_p(num))
|
|
|
|
return static_branch_unlikely(&cpu_hwcap_keys[num]);
|
|
|
|
else
|
|
|
|
return test_bit(num, cpu_hwcaps);
|
2014-11-14 15:54:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static inline void cpus_set_cap(unsigned int num)
|
|
|
|
{
|
2016-09-05 17:25:48 +00:00
|
|
|
if (num >= ARM64_NCAPS) {
|
2014-11-14 15:54:07 +00:00
|
|
|
pr_warn("Attempt to set an illegal CPU capability (%d >= %d)\n",
|
arm64: Provide a namespace to NCAPS
Building arm64.allmodconfig leads to the following warning:
usb/gadget/function/f_ncm.c:203:0: warning: "NCAPS" redefined
#define NCAPS (USB_CDC_NCM_NCAP_ETH_FILTER | USB_CDC_NCM_NCAP_CRC_MODE)
^
In file included from /home/build/work/batch/arch/arm64/include/asm/io.h:32:0,
from /home/build/work/batch/include/linux/clocksource.h:19,
from /home/build/work/batch/include/clocksource/arm_arch_timer.h:19,
from /home/build/work/batch/arch/arm64/include/asm/arch_timer.h:27,
from /home/build/work/batch/arch/arm64/include/asm/timex.h:19,
from /home/build/work/batch/include/linux/timex.h:65,
from /home/build/work/batch/include/linux/sched.h:19,
from /home/build/work/batch/arch/arm64/include/asm/compat.h:25,
from /home/build/work/batch/arch/arm64/include/asm/stat.h:23,
from /home/build/work/batch/include/linux/stat.h:5,
from /home/build/work/batch/include/linux/module.h:10,
from /home/build/work/batch/drivers/usb/gadget/function/f_ncm.c:19:
arch/arm64/include/asm/cpufeature.h:27:0: note: this is the location of the previous definition
#define NCAPS 2
So add a ARM64 prefix to avoid such problem.
Reported-by: Olof's autobuilder <build@lixom.net>
Signed-off-by: Fabio Estevam <fabio.estevam@freescale.com>
Signed-off-by: Will Deacon <will.deacon@arm.com>
2014-12-04 01:17:01 +00:00
|
|
|
num, ARM64_NCAPS);
|
2016-09-05 17:25:48 +00:00
|
|
|
} else {
|
2014-11-14 15:54:07 +00:00
|
|
|
__set_bit(num, cpu_hwcaps);
|
2016-09-05 17:25:48 +00:00
|
|
|
static_branch_enable(&cpu_hwcap_keys[num]);
|
|
|
|
}
|
2014-11-14 15:54:07 +00:00
|
|
|
}
|
|
|
|
|
2015-10-19 13:24:44 +00:00
|
|
|
static inline int __attribute_const__
|
2016-01-26 10:58:16 +00:00
|
|
|
cpuid_feature_extract_signed_field_width(u64 features, int field, int width)
|
2015-07-21 12:23:26 +00:00
|
|
|
{
|
2015-10-19 13:24:44 +00:00
|
|
|
return (s64)(features << (64 - width - field)) >> (64 - width);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline int __attribute_const__
|
2016-01-26 10:58:16 +00:00
|
|
|
cpuid_feature_extract_signed_field(u64 features, int field)
|
2015-10-19 13:24:44 +00:00
|
|
|
{
|
2016-01-26 10:58:16 +00:00
|
|
|
return cpuid_feature_extract_signed_field_width(features, field, 4);
|
2015-07-21 12:23:26 +00:00
|
|
|
}
|
|
|
|
|
2015-11-18 17:08:56 +00:00
|
|
|
static inline unsigned int __attribute_const__
|
|
|
|
cpuid_feature_extract_unsigned_field_width(u64 features, int field, int width)
|
|
|
|
{
|
|
|
|
return (u64)(features << (64 - width - field)) >> (64 - width);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline unsigned int __attribute_const__
|
|
|
|
cpuid_feature_extract_unsigned_field(u64 features, int field)
|
|
|
|
{
|
|
|
|
return cpuid_feature_extract_unsigned_field_width(features, field, 4);
|
|
|
|
}
|
|
|
|
|
2016-08-31 10:31:08 +00:00
|
|
|
static inline u64 arm64_ftr_mask(const struct arm64_ftr_bits *ftrp)
|
2015-10-19 13:24:45 +00:00
|
|
|
{
|
|
|
|
return (u64)GENMASK(ftrp->shift + ftrp->width - 1, ftrp->shift);
|
|
|
|
}
|
|
|
|
|
2016-01-26 10:58:16 +00:00
|
|
|
static inline int __attribute_const__
|
|
|
|
cpuid_feature_extract_field(u64 features, int field, bool sign)
|
|
|
|
{
|
|
|
|
return (sign) ?
|
|
|
|
cpuid_feature_extract_signed_field(features, field) :
|
|
|
|
cpuid_feature_extract_unsigned_field(features, field);
|
|
|
|
}
|
|
|
|
|
2016-08-31 10:31:08 +00:00
|
|
|
static inline s64 arm64_ftr_value(const struct arm64_ftr_bits *ftrp, u64 val)
|
2015-10-19 13:24:45 +00:00
|
|
|
{
|
2016-01-26 10:58:16 +00:00
|
|
|
return (s64)cpuid_feature_extract_field(val, ftrp->shift, ftrp->sign);
|
2015-10-19 13:24:45 +00:00
|
|
|
}
|
|
|
|
|
2015-10-19 13:24:42 +00:00
|
|
|
static inline bool id_aa64mmfr0_mixed_endian_el0(u64 mmfr0)
|
2015-07-21 12:23:26 +00:00
|
|
|
{
|
2016-01-26 10:58:16 +00:00
|
|
|
return cpuid_feature_extract_unsigned_field(mmfr0, ID_AA64MMFR0_BIGENDEL_SHIFT) == 0x1 ||
|
|
|
|
cpuid_feature_extract_unsigned_field(mmfr0, ID_AA64MMFR0_BIGENDEL0_SHIFT) == 0x1;
|
2015-07-21 12:23:26 +00:00
|
|
|
}
|
|
|
|
|
2016-04-18 09:28:34 +00:00
|
|
|
static inline bool id_aa64pfr0_32bit_el0(u64 pfr0)
|
|
|
|
{
|
|
|
|
u32 val = cpuid_feature_extract_unsigned_field(pfr0, ID_AA64PFR0_EL0_SHIFT);
|
|
|
|
|
|
|
|
return val == ID_AA64PFR0_EL0_32BIT_64BIT;
|
|
|
|
}
|
|
|
|
|
2015-10-19 13:24:39 +00:00
|
|
|
void __init setup_cpu_features(void);
|
2015-07-21 12:23:26 +00:00
|
|
|
|
2015-10-19 13:24:49 +00:00
|
|
|
void update_cpu_capabilities(const struct arm64_cpu_capabilities *caps,
|
2015-03-27 13:09:23 +00:00
|
|
|
const char *info);
|
2016-06-28 17:07:30 +00:00
|
|
|
void enable_cpu_capabilities(const struct arm64_cpu_capabilities *caps);
|
2016-09-09 13:07:10 +00:00
|
|
|
void check_local_cpu_capabilities(void);
|
|
|
|
|
2016-09-09 13:07:09 +00:00
|
|
|
void update_cpu_errata_workarounds(void);
|
2016-06-28 17:07:30 +00:00
|
|
|
void __init enable_errata_workarounds(void);
|
2016-09-09 13:07:09 +00:00
|
|
|
void verify_local_cpu_errata_workarounds(void);
|
2014-11-14 15:54:09 +00:00
|
|
|
|
2015-10-19 13:24:47 +00:00
|
|
|
u64 read_system_reg(u32 id);
|
|
|
|
|
2015-10-19 13:24:48 +00:00
|
|
|
static inline bool cpu_supports_mixed_endian_el0(void)
|
|
|
|
{
|
|
|
|
return id_aa64mmfr0_mixed_endian_el0(read_cpuid(ID_AA64MMFR0_EL1));
|
|
|
|
}
|
|
|
|
|
2016-04-18 09:28:36 +00:00
|
|
|
static inline bool system_supports_32bit_el0(void)
|
|
|
|
{
|
|
|
|
return cpus_have_cap(ARM64_HAS_32BIT_EL0);
|
|
|
|
}
|
|
|
|
|
2015-10-19 13:24:48 +00:00
|
|
|
static inline bool system_supports_mixed_endian_el0(void)
|
|
|
|
{
|
|
|
|
return id_aa64mmfr0_mixed_endian_el0(read_system_reg(SYS_ID_AA64MMFR0_EL1));
|
|
|
|
}
|
2014-11-14 15:54:09 +00:00
|
|
|
|
2014-11-14 15:54:10 +00:00
|
|
|
#endif /* __ASSEMBLY__ */
|
|
|
|
|
2014-03-04 01:10:04 +00:00
|
|
|
#endif
|