diff options
author | Suzuki K Poulose <suzuki.poulose@arm.com> | 2016-11-08 08:56:20 -0500 |
---|---|---|
committer | Catalin Marinas <catalin.marinas@arm.com> | 2016-11-16 12:50:51 -0500 |
commit | a4023f682739439b434165b54af7cb3676a4766e (patch) | |
tree | ef2638d37291c56d972f20b69c59a6dee9292c18 | |
parent | c02433dd6de32f042cf3ffe476746b1115b8c096 (diff) |
arm64: Add hypervisor safe helper for checking constant capabilities
The hypervisor may not have full access to the kernel data structures
and hence cannot safely use cpus_have_cap() helper for checking the
system capability. Add a safe helper for hypervisors to check a constant
system capability, which *doesn't* fall back to checking the bitmap
maintained by the kernel. With this, make the cpus_have_cap() only
check the bitmask and force constant cap checks to use the new API
for quicker checks.
Cc: Robert Ritcher <rritcher@cavium.com>
Cc: Tirumalesh Chalamarla <tchalamarla@cavium.com>
Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
Reviewed-by: Will Deacon <will.deacon@arm.com>
Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
-rw-r--r-- | arch/arm64/include/asm/cpufeature.h | 19 | ||||
-rw-r--r-- | arch/arm64/kernel/cpufeature.c | 2 | ||||
-rw-r--r-- | arch/arm64/kernel/process.c | 2 | ||||
-rw-r--r-- | drivers/irqchip/irq-gic-v3.c | 13 |
4 files changed, 15 insertions, 21 deletions
diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h index a27c3245ba21..8b63adb148e7 100644 --- a/arch/arm64/include/asm/cpufeature.h +++ b/arch/arm64/include/asm/cpufeature.h | |||
@@ -9,8 +9,6 @@ | |||
9 | #ifndef __ASM_CPUFEATURE_H | 9 | #ifndef __ASM_CPUFEATURE_H |
10 | #define __ASM_CPUFEATURE_H | 10 | #define __ASM_CPUFEATURE_H |
11 | 11 | ||
12 | #include <linux/jump_label.h> | ||
13 | |||
14 | #include <asm/hwcap.h> | 12 | #include <asm/hwcap.h> |
15 | #include <asm/sysreg.h> | 13 | #include <asm/sysreg.h> |
16 | 14 | ||
@@ -45,6 +43,8 @@ | |||
45 | 43 | ||
46 | #ifndef __ASSEMBLY__ | 44 | #ifndef __ASSEMBLY__ |
47 | 45 | ||
46 | #include <linux/bug.h> | ||
47 | #include <linux/jump_label.h> | ||
48 | #include <linux/kernel.h> | 48 | #include <linux/kernel.h> |
49 | 49 | ||
50 | /* CPU feature register tracking */ | 50 | /* CPU feature register tracking */ |
@@ -122,14 +122,19 @@ static inline bool cpu_have_feature(unsigned int num) | |||
122 | return elf_hwcap & (1UL << num); | 122 | return elf_hwcap & (1UL << num); |
123 | } | 123 | } |
124 | 124 | ||
125 | /* System capability check for constant caps */ | ||
126 | static inline bool cpus_have_const_cap(int num) | ||
127 | { | ||
128 | if (num >= ARM64_NCAPS) | ||
129 | return false; | ||
130 | return static_branch_unlikely(&cpu_hwcap_keys[num]); | ||
131 | } | ||
132 | |||
125 | static inline bool cpus_have_cap(unsigned int num) | 133 | static inline bool cpus_have_cap(unsigned int num) |
126 | { | 134 | { |
127 | if (num >= ARM64_NCAPS) | 135 | if (num >= ARM64_NCAPS) |
128 | return false; | 136 | return false; |
129 | if (__builtin_constant_p(num)) | 137 | return test_bit(num, cpu_hwcaps); |
130 | return static_branch_unlikely(&cpu_hwcap_keys[num]); | ||
131 | else | ||
132 | return test_bit(num, cpu_hwcaps); | ||
133 | } | 138 | } |
134 | 139 | ||
135 | static inline void cpus_set_cap(unsigned int num) | 140 | static inline void cpus_set_cap(unsigned int num) |
@@ -218,7 +223,7 @@ static inline bool cpu_supports_mixed_endian_el0(void) | |||
218 | 223 | ||
219 | static inline bool system_supports_32bit_el0(void) | 224 | static inline bool system_supports_32bit_el0(void) |
220 | { | 225 | { |
221 | return cpus_have_cap(ARM64_HAS_32BIT_EL0); | 226 | return cpus_have_const_cap(ARM64_HAS_32BIT_EL0); |
222 | } | 227 | } |
223 | 228 | ||
224 | static inline bool system_supports_mixed_endian_el0(void) | 229 | static inline bool system_supports_mixed_endian_el0(void) |
diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c index c02504ea304b..fc2bd1926607 100644 --- a/arch/arm64/kernel/cpufeature.c +++ b/arch/arm64/kernel/cpufeature.c | |||
@@ -1102,5 +1102,5 @@ void __init setup_cpu_features(void) | |||
1102 | static bool __maybe_unused | 1102 | static bool __maybe_unused |
1103 | cpufeature_pan_not_uao(const struct arm64_cpu_capabilities *entry, int __unused) | 1103 | cpufeature_pan_not_uao(const struct arm64_cpu_capabilities *entry, int __unused) |
1104 | { | 1104 | { |
1105 | return (cpus_have_cap(ARM64_HAS_PAN) && !cpus_have_cap(ARM64_HAS_UAO)); | 1105 | return (cpus_have_const_cap(ARM64_HAS_PAN) && !cpus_have_const_cap(ARM64_HAS_UAO)); |
1106 | } | 1106 | } |
diff --git a/arch/arm64/kernel/process.c b/arch/arm64/kernel/process.c index a98b743631c5..a3a2816ba73a 100644 --- a/arch/arm64/kernel/process.c +++ b/arch/arm64/kernel/process.c | |||
@@ -283,7 +283,7 @@ int copy_thread(unsigned long clone_flags, unsigned long stack_start, | |||
283 | memset(childregs, 0, sizeof(struct pt_regs)); | 283 | memset(childregs, 0, sizeof(struct pt_regs)); |
284 | childregs->pstate = PSR_MODE_EL1h; | 284 | childregs->pstate = PSR_MODE_EL1h; |
285 | if (IS_ENABLED(CONFIG_ARM64_UAO) && | 285 | if (IS_ENABLED(CONFIG_ARM64_UAO) && |
286 | cpus_have_cap(ARM64_HAS_UAO)) | 286 | cpus_have_const_cap(ARM64_HAS_UAO)) |
287 | childregs->pstate |= PSR_UAO_BIT; | 287 | childregs->pstate |= PSR_UAO_BIT; |
288 | p->thread.cpu_context.x19 = stack_start; | 288 | p->thread.cpu_context.x19 = stack_start; |
289 | p->thread.cpu_context.x20 = stk_sz; | 289 | p->thread.cpu_context.x20 = stk_sz; |
diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c index 19d642eae096..26e1d7fafb1e 100644 --- a/drivers/irqchip/irq-gic-v3.c +++ b/drivers/irqchip/irq-gic-v3.c | |||
@@ -120,11 +120,10 @@ static void gic_redist_wait_for_rwp(void) | |||
120 | } | 120 | } |
121 | 121 | ||
122 | #ifdef CONFIG_ARM64 | 122 | #ifdef CONFIG_ARM64 |
123 | static DEFINE_STATIC_KEY_FALSE(is_cavium_thunderx); | ||
124 | 123 | ||
125 | static u64 __maybe_unused gic_read_iar(void) | 124 | static u64 __maybe_unused gic_read_iar(void) |
126 | { | 125 | { |
127 | if (static_branch_unlikely(&is_cavium_thunderx)) | 126 | if (cpus_have_const_cap(ARM64_WORKAROUND_CAVIUM_23154)) |
128 | return gic_read_iar_cavium_thunderx(); | 127 | return gic_read_iar_cavium_thunderx(); |
129 | else | 128 | else |
130 | return gic_read_iar_common(); | 129 | return gic_read_iar_common(); |
@@ -905,14 +904,6 @@ static const struct irq_domain_ops partition_domain_ops = { | |||
905 | .select = gic_irq_domain_select, | 904 | .select = gic_irq_domain_select, |
906 | }; | 905 | }; |
907 | 906 | ||
908 | static void gicv3_enable_quirks(void) | ||
909 | { | ||
910 | #ifdef CONFIG_ARM64 | ||
911 | if (cpus_have_cap(ARM64_WORKAROUND_CAVIUM_23154)) | ||
912 | static_branch_enable(&is_cavium_thunderx); | ||
913 | #endif | ||
914 | } | ||
915 | |||
916 | static int __init gic_init_bases(void __iomem *dist_base, | 907 | static int __init gic_init_bases(void __iomem *dist_base, |
917 | struct redist_region *rdist_regs, | 908 | struct redist_region *rdist_regs, |
918 | u32 nr_redist_regions, | 909 | u32 nr_redist_regions, |
@@ -935,8 +926,6 @@ static int __init gic_init_bases(void __iomem *dist_base, | |||
935 | gic_data.nr_redist_regions = nr_redist_regions; | 926 | gic_data.nr_redist_regions = nr_redist_regions; |
936 | gic_data.redist_stride = redist_stride; | 927 | gic_data.redist_stride = redist_stride; |
937 | 928 | ||
938 | gicv3_enable_quirks(); | ||
939 | |||
940 | /* | 929 | /* |
941 | * Find out how many interrupts are supported. | 930 | * Find out how many interrupts are supported. |
942 | * The GIC only supports up to 1020 interrupt sources (SGI+PPI+SPI) | 931 | * The GIC only supports up to 1020 interrupt sources (SGI+PPI+SPI) |