Pull arm64 fixes/cleanups from Catalin Marinas: - Avoid taking a mutex in the secondary CPU bring-up path when interrupts are disabled - Ignore perf exclude_hv when the kernel is running in Hyp mode - Remove redundant instruction in cmpxchg * tag 'arm64-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux: arm64/cpufeature: don't use mutex in bringup path arm64: perf: Ignore exclude_hv when kernel is running in HYP arm64: Remove redundant mov from LL/SC cmpxchg
Unified · Split
| @@ -264,7 +264,6 @@ __LL_SC_PREFIX(__cmpxchg_case_##name(volatile void *ptr, \ · 263 unmodified lines | ||
| 264 | 264 | " st" #rel "xr" #sz "\t%w[tmp], %" #w "[new], %[v]\n" \ |
| 265 | 265 | " cbnz %w[tmp], 1b\n" \ |
| 266 | 266 | " " #mb "\n" \ |
| 267 | − " mov %" #w "[oldval], %" #w "[old]\n" \ | |
| 268 | 267 | "2:" \ |
| 269 | 268 | : [tmp] "=&r" (tmp), [oldval] "=&r" (oldval), \ |
| 270 | 269 | [v] "+Q" (*(unsigned long *)ptr) \ |
| @@ -115,6 +115,7 @@ struct arm64_cpu_capabilities { · 114 unmodified lines | ||
| 115 | 115 | |
| 116 | 116 | extern DECLARE_BITMAP(cpu_hwcaps, ARM64_NCAPS); |
| 117 | 117 | extern struct static_key_false cpu_hwcap_keys[ARM64_NCAPS]; |
| 118 | +extern struct static_key_false arm64_const_caps_ready; | |
| 118 | 119 | |
| 119 | 120 | bool this_cpu_has_cap(unsigned int cap); |
| 120 | 121 | |
| @@ -124,7 +125,7 @@ static inline bool cpu_have_feature(unsigned int num) · 3 unmodified lines | ||
| 124 | 125 | } |
| 125 | 126 | |
| 126 | 127 | /* System capability check for constant caps */ |
| 127 | −static inline bool cpus_have_const_cap(int num) | |
| 128 | +static inline bool __cpus_have_const_cap(int num) | |
| 128 | 129 | { |
| 129 | 130 | if (num >= ARM64_NCAPS) |
| 130 | 131 | return false; |
| @@ -138,6 +139,14 @@ static inline bool cpus_have_cap(unsigned int num) · 7 unmodified lines | ||
| 138 | 139 | return test_bit(num, cpu_hwcaps); |
| 139 | 140 | } |
| 140 | 141 | |
| 142 | +static inline bool cpus_have_const_cap(int num) | |
| 143 | +{ | |
| 144 | + if (static_branch_likely(&arm64_const_caps_ready)) | |
| 145 | + return __cpus_have_const_cap(num); | |
| 146 | + else | |
| 147 | + return cpus_have_cap(num); | |
| 148 | +} | |
| 149 | + | |
| 141 | 150 | static inline void cpus_set_cap(unsigned int num) |
| 142 | 151 | { |
| 143 | 152 | if (num >= ARM64_NCAPS) { |
| @@ -145,7 +154,6 @@ static inline void cpus_set_cap(unsigned int num) · 1 unmodified line | ||
| 145 | 154 | num, ARM64_NCAPS); |
| 146 | 155 | } else { |
| 147 | 156 | __set_bit(num, cpu_hwcaps); |
| 148 | − static_branch_enable(&cpu_hwcap_keys[num]); | |
| 149 | 157 | } |
| 150 | 158 | } |
| 151 | 159 | |
| @@ -24,6 +24,7 @@ · 23 unmodified lines | ||
| 24 | 24 | |
| 25 | 25 | #include <linux/types.h> |
| 26 | 26 | #include <linux/kvm_types.h> |
| 27 | +#include <asm/cpufeature.h> | |
| 27 | 28 | #include <asm/kvm.h> |
| 28 | 29 | #include <asm/kvm_asm.h> |
| 29 | 30 | #include <asm/kvm_mmio.h> |
| @@ -355,9 +356,12 @@ static inline void __cpu_init_hyp_mode(phys_addr_t pgd_ptr, · 325 unmodified lines | ||
| 355 | 356 | unsigned long vector_ptr) |
| 356 | 357 | { |
| 357 | 358 | /* |
| 358 | − * Call initialization code, and switch to the full blown | |
| 359 | − * HYP code. | |
| 359 | + * Call initialization code, and switch to the full blown HYP code. | |
| 360 | + * If the cpucaps haven't been finalized yet, something has gone very | |
| 361 | + * wrong, and hyp will crash and burn when it uses any | |
| 362 | + * cpus_have_const_cap() wrapper. | |
| 360 | 363 | */ |
| 364 | + BUG_ON(!static_branch_likely(&arm64_const_caps_ready)); | |
| 361 | 365 | __kvm_call_hyp((void *)pgd_ptr, hyp_stack_ptr, vector_ptr); |
| 362 | 366 | } |
| 363 | 367 | |
| @@ -985,8 +985,16 @@ void update_cpu_capabilities(const struct arm64_cpu_capabilities *caps, · 984 unmodified lines | ||
| 985 | 985 | */ |
| 986 | 986 | void __init enable_cpu_capabilities(const struct arm64_cpu_capabilities *caps) |
| 987 | 987 | { |
| 988 | − for (; caps->matches; caps++) | |
| 989 | − if (caps->enable && cpus_have_cap(caps->capability)) | |
| 988 | + for (; caps->matches; caps++) { | |
| 989 | + unsigned int num = caps->capability; | |
| 990 | + | |
| 991 | + if (!cpus_have_cap(num)) | |
| 992 | + continue; | |
| 993 | + | |
| 994 | + /* Ensure cpus_have_const_cap(num) works */ | |
| 995 | + static_branch_enable(&cpu_hwcap_keys[num]); | |
| 996 | + | |
| 997 | + if (caps->enable) { | |
| 990 | 998 | /* |
| 991 | 999 | * Use stop_machine() as it schedules the work allowing |
| 992 | 1000 | * us to modify PSTATE, instead of on_each_cpu() which |
| @@ -994,6 +1002,8 @@ void __init enable_cpu_capabilities(const struct arm64_cpu_capabilities *caps) · 1 unmodified line | ||
| 994 | 1002 | * we return. |
| 995 | 1003 | */ |
| 996 | 1004 | stop_machine(caps->enable, NULL, cpu_online_mask); |
| 1005 | + } | |
| 1006 | + } | |
| 997 | 1007 | } |
| 998 | 1008 | |
| 999 | 1009 | /* |
| @@ -1096,6 +1106,14 @@ static void __init setup_feature_capabilities(void) · 96 unmodified lines | ||
| 1096 | 1106 | enable_cpu_capabilities(arm64_features); |
| 1097 | 1107 | } |
| 1098 | 1108 | |
| 1109 | +DEFINE_STATIC_KEY_FALSE(arm64_const_caps_ready); | |
| 1110 | +EXPORT_SYMBOL(arm64_const_caps_ready); | |
| 1111 | + | |
| 1112 | +static void __init mark_const_caps_ready(void) | |
| 1113 | +{ | |
| 1114 | + static_branch_enable(&arm64_const_caps_ready); | |
| 1115 | +} | |
| 1116 | + | |
| 1099 | 1117 | /* |
| 1100 | 1118 | * Check if the current CPU has a given feature capability. |
| 1101 | 1119 | * Should be called from non-preemptible context. |
| @@ -1131,6 +1149,7 @@ void __init setup_cpu_features(void) · 29 unmodified lines | ||
| 1131 | 1149 | /* Set the CPU feature capabilies */ |
| 1132 | 1150 | setup_feature_capabilities(); |
| 1133 | 1151 | enable_errata_workarounds(); |
| 1152 | + mark_const_caps_ready(); | |
| 1134 | 1153 | setup_elf_hwcaps(arm64_elf_hwcaps); |
| 1135 | 1154 | |
| 1136 | 1155 | if (system_supports_32bit_el0()) |
| @@ -877,15 +877,24 @@ static int armv8pmu_set_event_filter(struct hw_perf_event *event, · 876 unmodified lines | ||
| 877 | 877 | |
| 878 | 878 | if (attr->exclude_idle) |
| 879 | 879 | return -EPERM; |
| 880 | − if (is_kernel_in_hyp_mode() && | |
| 881 | − attr->exclude_kernel != attr->exclude_hv) | |
| 882 | − return -EINVAL; | |
| 880 | + | |
| 881 | + /* | |
| 882 | + * If we're running in hyp mode, then we *are* the hypervisor. | |
| 883 | + * Therefore we ignore exclude_hv in this configuration, since | |
| 884 | + * there's no hypervisor to sample anyway. This is consistent | |
| 885 | + * with other architectures (x86 and Power). | |
| 886 | + */ | |
| 887 | + if (is_kernel_in_hyp_mode()) { | |
| 888 | + if (!attr->exclude_kernel) | |
| 889 | + config_base |= ARMV8_PMU_INCLUDE_EL2; | |
| 890 | + } else { | |
| 891 | + if (attr->exclude_kernel) | |
| 892 | + config_base |= ARMV8_PMU_EXCLUDE_EL1; | |
| 893 | + if (!attr->exclude_hv) | |
| 894 | + config_base |= ARMV8_PMU_INCLUDE_EL2; | |
| 895 | + } | |
| 883 | 896 | if (attr->exclude_user) |
| 884 | 897 | config_base |= ARMV8_PMU_EXCLUDE_EL0; |
| 885 | − if (!is_kernel_in_hyp_mode() && attr->exclude_kernel) | |
| 886 | − config_base |= ARMV8_PMU_EXCLUDE_EL1; | |
| 887 | − if (!attr->exclude_hv) | |
| 888 | − config_base |= ARMV8_PMU_INCLUDE_EL2; | |
| 889 | 898 | |
| 890 | 899 | /* |
| 891 | 900 | * Install the filter into config_base as this is used to |