aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/cpu.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/cpu.c')
-rw-r--r--kernel/cpu.c111
1 files changed, 83 insertions, 28 deletions
diff --git a/kernel/cpu.c b/kernel/cpu.c
index 025f419d16f6..f2ef10460698 100644
--- a/kernel/cpu.c
+++ b/kernel/cpu.c
@@ -9,6 +9,7 @@
9#include <linux/notifier.h> 9#include <linux/notifier.h>
10#include <linux/sched/signal.h> 10#include <linux/sched/signal.h>
11#include <linux/sched/hotplug.h> 11#include <linux/sched/hotplug.h>
12#include <linux/sched/isolation.h>
12#include <linux/sched/task.h> 13#include <linux/sched/task.h>
13#include <linux/sched/smt.h> 14#include <linux/sched/smt.h>
14#include <linux/unistd.h> 15#include <linux/unistd.h>
@@ -564,6 +565,20 @@ static void undo_cpu_up(unsigned int cpu, struct cpuhp_cpu_state *st)
564 cpuhp_invoke_callback(cpu, st->state, false, NULL, NULL); 565 cpuhp_invoke_callback(cpu, st->state, false, NULL, NULL);
565} 566}
566 567
568static inline bool can_rollback_cpu(struct cpuhp_cpu_state *st)
569{
570 if (IS_ENABLED(CONFIG_HOTPLUG_CPU))
571 return true;
572 /*
573 * When CPU hotplug is disabled, then taking the CPU down is not
574 * possible because takedown_cpu() and the architecture and
575 * subsystem specific mechanisms are not available. So the CPU
576 * which would be completely unplugged again needs to stay around
577 * in the current state.
578 */
579 return st->state <= CPUHP_BRINGUP_CPU;
580}
581
567static int cpuhp_up_callbacks(unsigned int cpu, struct cpuhp_cpu_state *st, 582static int cpuhp_up_callbacks(unsigned int cpu, struct cpuhp_cpu_state *st,
568 enum cpuhp_state target) 583 enum cpuhp_state target)
569{ 584{
@@ -574,8 +589,10 @@ static int cpuhp_up_callbacks(unsigned int cpu, struct cpuhp_cpu_state *st,
574 st->state++; 589 st->state++;
575 ret = cpuhp_invoke_callback(cpu, st->state, true, NULL, NULL); 590 ret = cpuhp_invoke_callback(cpu, st->state, true, NULL, NULL);
576 if (ret) { 591 if (ret) {
577 st->target = prev_state; 592 if (can_rollback_cpu(st)) {
578 undo_cpu_up(cpu, st); 593 st->target = prev_state;
594 undo_cpu_up(cpu, st);
595 }
579 break; 596 break;
580 } 597 }
581 } 598 }
@@ -844,6 +861,8 @@ static int take_cpu_down(void *_param)
844 861
845 /* Give up timekeeping duties */ 862 /* Give up timekeeping duties */
846 tick_handover_do_timer(); 863 tick_handover_do_timer();
864 /* Remove CPU from timer broadcasting */
865 tick_offline_cpu(cpu);
847 /* Park the stopper thread */ 866 /* Park the stopper thread */
848 stop_machine_park(cpu); 867 stop_machine_park(cpu);
849 return 0; 868 return 0;
@@ -1183,8 +1202,15 @@ int freeze_secondary_cpus(int primary)
1183 int cpu, error = 0; 1202 int cpu, error = 0;
1184 1203
1185 cpu_maps_update_begin(); 1204 cpu_maps_update_begin();
1186 if (!cpu_online(primary)) 1205 if (primary == -1) {
1187 primary = cpumask_first(cpu_online_mask); 1206 primary = cpumask_first(cpu_online_mask);
1207 if (!housekeeping_cpu(primary, HK_FLAG_TIMER))
1208 primary = housekeeping_any_cpu(HK_FLAG_TIMER);
1209 } else {
1210 if (!cpu_online(primary))
1211 primary = cpumask_first(cpu_online_mask);
1212 }
1213
1188 /* 1214 /*
1189 * We take down all of the non-boot CPUs in one shot to avoid races 1215 * We take down all of the non-boot CPUs in one shot to avoid races
1190 * with the userspace trying to use the CPU hotplug at the same time 1216 * with the userspace trying to use the CPU hotplug at the same time
@@ -2017,19 +2043,6 @@ static const struct attribute_group cpuhp_cpu_root_attr_group = {
2017 2043
2018#ifdef CONFIG_HOTPLUG_SMT 2044#ifdef CONFIG_HOTPLUG_SMT
2019 2045
2020static const char *smt_states[] = {
2021 [CPU_SMT_ENABLED] = "on",
2022 [CPU_SMT_DISABLED] = "off",
2023 [CPU_SMT_FORCE_DISABLED] = "forceoff",
2024 [CPU_SMT_NOT_SUPPORTED] = "notsupported",
2025};
2026
2027static ssize_t
2028show_smt_control(struct device *dev, struct device_attribute *attr, char *buf)
2029{
2030 return snprintf(buf, PAGE_SIZE - 2, "%s\n", smt_states[cpu_smt_control]);
2031}
2032
2033static void cpuhp_offline_cpu_device(unsigned int cpu) 2046static void cpuhp_offline_cpu_device(unsigned int cpu)
2034{ 2047{
2035 struct device *dev = get_cpu_device(cpu); 2048 struct device *dev = get_cpu_device(cpu);
@@ -2100,9 +2113,10 @@ static int cpuhp_smt_enable(void)
2100 return ret; 2113 return ret;
2101} 2114}
2102 2115
2116
2103static ssize_t 2117static ssize_t
2104store_smt_control(struct device *dev, struct device_attribute *attr, 2118__store_smt_control(struct device *dev, struct device_attribute *attr,
2105 const char *buf, size_t count) 2119 const char *buf, size_t count)
2106{ 2120{
2107 int ctrlval, ret; 2121 int ctrlval, ret;
2108 2122
@@ -2140,14 +2154,44 @@ store_smt_control(struct device *dev, struct device_attribute *attr,
2140 unlock_device_hotplug(); 2154 unlock_device_hotplug();
2141 return ret ? ret : count; 2155 return ret ? ret : count;
2142} 2156}
2157
2158#else /* !CONFIG_HOTPLUG_SMT */
2159static ssize_t
2160__store_smt_control(struct device *dev, struct device_attribute *attr,
2161 const char *buf, size_t count)
2162{
2163 return -ENODEV;
2164}
2165#endif /* CONFIG_HOTPLUG_SMT */
2166
2167static const char *smt_states[] = {
2168 [CPU_SMT_ENABLED] = "on",
2169 [CPU_SMT_DISABLED] = "off",
2170 [CPU_SMT_FORCE_DISABLED] = "forceoff",
2171 [CPU_SMT_NOT_SUPPORTED] = "notsupported",
2172 [CPU_SMT_NOT_IMPLEMENTED] = "notimplemented",
2173};
2174
2175static ssize_t
2176show_smt_control(struct device *dev, struct device_attribute *attr, char *buf)
2177{
2178 const char *state = smt_states[cpu_smt_control];
2179
2180 return snprintf(buf, PAGE_SIZE - 2, "%s\n", state);
2181}
2182
2183static ssize_t
2184store_smt_control(struct device *dev, struct device_attribute *attr,
2185 const char *buf, size_t count)
2186{
2187 return __store_smt_control(dev, attr, buf, count);
2188}
2143static DEVICE_ATTR(control, 0644, show_smt_control, store_smt_control); 2189static DEVICE_ATTR(control, 0644, show_smt_control, store_smt_control);
2144 2190
2145static ssize_t 2191static ssize_t
2146show_smt_active(struct device *dev, struct device_attribute *attr, char *buf) 2192show_smt_active(struct device *dev, struct device_attribute *attr, char *buf)
2147{ 2193{
2148 bool active = topology_max_smt_threads() > 1; 2194 return snprintf(buf, PAGE_SIZE - 2, "%d\n", sched_smt_active());
2149
2150 return snprintf(buf, PAGE_SIZE - 2, "%d\n", active);
2151} 2195}
2152static DEVICE_ATTR(active, 0444, show_smt_active, NULL); 2196static DEVICE_ATTR(active, 0444, show_smt_active, NULL);
2153 2197
@@ -2163,21 +2207,17 @@ static const struct attribute_group cpuhp_smt_attr_group = {
2163 NULL 2207 NULL
2164}; 2208};
2165 2209
2166static int __init cpu_smt_state_init(void) 2210static int __init cpu_smt_sysfs_init(void)
2167{ 2211{
2168 return sysfs_create_group(&cpu_subsys.dev_root->kobj, 2212 return sysfs_create_group(&cpu_subsys.dev_root->kobj,
2169 &cpuhp_smt_attr_group); 2213 &cpuhp_smt_attr_group);
2170} 2214}
2171 2215
2172#else
2173static inline int cpu_smt_state_init(void) { return 0; }
2174#endif
2175
2176static int __init cpuhp_sysfs_init(void) 2216static int __init cpuhp_sysfs_init(void)
2177{ 2217{
2178 int cpu, ret; 2218 int cpu, ret;
2179 2219
2180 ret = cpu_smt_state_init(); 2220 ret = cpu_smt_sysfs_init();
2181 if (ret) 2221 if (ret)
2182 return ret; 2222 return ret;
2183 2223
@@ -2198,7 +2238,7 @@ static int __init cpuhp_sysfs_init(void)
2198 return 0; 2238 return 0;
2199} 2239}
2200device_initcall(cpuhp_sysfs_init); 2240device_initcall(cpuhp_sysfs_init);
2201#endif 2241#endif /* CONFIG_SYSFS && CONFIG_HOTPLUG_CPU */
2202 2242
2203/* 2243/*
2204 * cpu_bit_bitmap[] is a special, "compressed" data structure that 2244 * cpu_bit_bitmap[] is a special, "compressed" data structure that
@@ -2288,3 +2328,18 @@ void __init boot_cpu_hotplug_init(void)
2288#endif 2328#endif
2289 this_cpu_write(cpuhp_state.state, CPUHP_ONLINE); 2329 this_cpu_write(cpuhp_state.state, CPUHP_ONLINE);
2290} 2330}
2331
2332enum cpu_mitigations cpu_mitigations __ro_after_init = CPU_MITIGATIONS_AUTO;
2333
2334static int __init mitigations_parse_cmdline(char *arg)
2335{
2336 if (!strcmp(arg, "off"))
2337 cpu_mitigations = CPU_MITIGATIONS_OFF;
2338 else if (!strcmp(arg, "auto"))
2339 cpu_mitigations = CPU_MITIGATIONS_AUTO;
2340 else if (!strcmp(arg, "auto,nosmt"))
2341 cpu_mitigations = CPU_MITIGATIONS_AUTO_NOSMT;
2342
2343 return 0;
2344}
2345early_param("mitigations", mitigations_parse_cmdline);