Blame view
drivers/base/cpu.c
14.9 KB
989d42e85
|
1 |
// SPDX-License-Identifier: GPL-2.0 |
1da177e4c
|
2 |
/* |
8a25a2fd1
|
3 |
* CPU subsystem support |
1da177e4c
|
4 |
*/ |
024f78462
|
5 |
#include <linux/kernel.h> |
1da177e4c
|
6 7 |
#include <linux/module.h> #include <linux/init.h> |
f6a570333
|
8 |
#include <linux/sched.h> |
1da177e4c
|
9 10 11 |
#include <linux/cpu.h> #include <linux/topology.h> #include <linux/device.h> |
76b67ed9d
|
12 |
#include <linux/node.h> |
5a0e3ad6a
|
13 |
#include <linux/gfp.h> |
fad12ac8c
|
14 |
#include <linux/slab.h> |
9f13a1fd4
|
15 |
#include <linux/percpu.h> |
ac212b698
|
16 |
#include <linux/acpi.h> |
f86e4718f
|
17 |
#include <linux/of.h> |
67bad2fdb
|
18 |
#include <linux/cpufeature.h> |
6570a9a1c
|
19 |
#include <linux/tick.h> |
37efa4b41
|
20 |
#include <linux/pm_qos.h> |
edb938217
|
21 |
#include <linux/sched/isolation.h> |
1da177e4c
|
22 |
|
a1bdc7aad
|
23 |
#include "base.h" |
1da177e4c
|
24 |
|
8a25a2fd1
|
25 |
static DEFINE_PER_CPU(struct device *, cpu_sys_devices); |
ad74557a4
|
26 |
|
ac212b698
|
27 28 29 30 31 32 33 34 |
static int cpu_subsys_match(struct device *dev, struct device_driver *drv) { /* ACPI style match is the only one that may succeed. */ if (acpi_driver_match_device(dev, drv)) return 1; return 0; } |
1da177e4c
|
35 |
#ifdef CONFIG_HOTPLUG_CPU |
346404682
|
36 37 38 39 40 41 42 43 |
static void change_cpu_under_node(struct cpu *cpu, unsigned int from_nid, unsigned int to_nid) { int cpuid = cpu->dev.id; unregister_cpu_under_node(cpuid, from_nid); register_cpu_under_node(cpuid, to_nid); cpu->node_id = to_nid; } |
eda5867b6
|
44 |
static int cpu_subsys_online(struct device *dev) |
1da177e4c
|
45 |
{ |
8a25a2fd1
|
46 |
struct cpu *cpu = container_of(dev, struct cpu, dev); |
0902a9044
|
47 48 |
int cpuid = dev->id; int from_nid, to_nid; |
6dedcca61
|
49 |
int ret; |
1da177e4c
|
50 |
|
0902a9044
|
51 |
from_nid = cpu_to_node(cpuid); |
c7991b0b7
|
52 |
if (from_nid == NUMA_NO_NODE) |
6dedcca61
|
53 |
return -ENODEV; |
c7991b0b7
|
54 |
|
33c3736ec
|
55 |
ret = cpu_device_up(dev); |
0902a9044
|
56 57 58 59 60 61 62 |
/* * When hot adding memory to memoryless node and enabling a cpu * on the node, node number of the cpu may internally change. */ to_nid = cpu_to_node(cpuid); if (from_nid != to_nid) change_cpu_under_node(cpu, from_nid, to_nid); |
1da177e4c
|
63 |
|
0902a9044
|
64 |
return ret; |
1da177e4c
|
65 |
} |
0902a9044
|
66 |
static int cpu_subsys_offline(struct device *dev) |
1da177e4c
|
67 |
{ |
33c3736ec
|
68 |
return cpu_device_down(dev); |
1da177e4c
|
69 |
} |
1c4e2d70a
|
70 |
|
76b67ed9d
|
71 |
void unregister_cpu(struct cpu *cpu) |
1da177e4c
|
72 |
{ |
8a25a2fd1
|
73 |
int logical_cpu = cpu->dev.id; |
1da177e4c
|
74 |
|
76b67ed9d
|
75 |
unregister_cpu_under_node(logical_cpu, cpu_to_node(logical_cpu)); |
8a25a2fd1
|
76 |
device_unregister(&cpu->dev); |
e37d05dad
|
77 |
per_cpu(cpu_sys_devices, logical_cpu) = NULL; |
1da177e4c
|
78 79 |
return; } |
12633e803
|
80 81 |
#ifdef CONFIG_ARCH_CPU_PROBE_RELEASE |
8a25a2fd1
|
82 83 |
static ssize_t cpu_probe_store(struct device *dev, struct device_attribute *attr, |
67fc233f4
|
84 |
const char *buf, |
12633e803
|
85 86 |
size_t count) { |
574b851e9
|
87 88 89 90 91 92 93 94 95 96 97 |
ssize_t cnt; int ret; ret = lock_device_hotplug_sysfs(); if (ret) return ret; cnt = arch_cpu_probe(buf, count); unlock_device_hotplug(); return cnt; |
12633e803
|
98 |
} |
8a25a2fd1
|
99 100 |
static ssize_t cpu_release_store(struct device *dev, struct device_attribute *attr, |
67fc233f4
|
101 |
const char *buf, |
12633e803
|
102 103 |
size_t count) { |
574b851e9
|
104 105 106 107 108 109 110 111 112 113 114 |
ssize_t cnt; int ret; ret = lock_device_hotplug_sysfs(); if (ret) return ret; cnt = arch_cpu_release(buf, count); unlock_device_hotplug(); return cnt; |
12633e803
|
115 |
} |
8a25a2fd1
|
116 117 |
static DEVICE_ATTR(probe, S_IWUSR, NULL, cpu_probe_store); static DEVICE_ATTR(release, S_IWUSR, NULL, cpu_release_store); |
12633e803
|
118 |
#endif /* CONFIG_ARCH_CPU_PROBE_RELEASE */ |
1da177e4c
|
119 |
#endif /* CONFIG_HOTPLUG_CPU */ |
0902a9044
|
120 121 122 |
struct bus_type cpu_subsys = { .name = "cpu", .dev_name = "cpu", |
ac212b698
|
123 |
.match = cpu_subsys_match, |
0902a9044
|
124 125 126 127 128 129 |
#ifdef CONFIG_HOTPLUG_CPU .online = cpu_subsys_online, .offline = cpu_subsys_offline, #endif }; EXPORT_SYMBOL_GPL(cpu_subsys); |
51be5606d
|
130 131 |
#ifdef CONFIG_KEXEC #include <linux/kexec.h> |
948b3edba
|
132 133 |
static ssize_t crash_notes_show(struct device *dev, struct device_attribute *attr, |
4a0b2b4db
|
134 |
char *buf) |
51be5606d
|
135 |
{ |
8a25a2fd1
|
136 |
struct cpu *cpu = container_of(dev, struct cpu, dev); |
51be5606d
|
137 138 |
unsigned long long addr; int cpunum; |
8a25a2fd1
|
139 |
cpunum = cpu->dev.id; |
51be5606d
|
140 141 142 143 144 145 146 |
/* * Might be reading other cpu's data based on which cpu read thread * has been scheduled. But cpu data (memory) is allocated once during * boot up and this data does not change there after. Hence this * operation should be safe. No locking required. */ |
3b034b0d0
|
147 |
addr = per_cpu_ptr_to_phys(per_cpu_ptr(crash_notes, cpunum)); |
948b3edba
|
148 149 150 |
return sysfs_emit(buf, "%llx ", addr); |
51be5606d
|
151 |
} |
948b3edba
|
152 |
static DEVICE_ATTR_ADMIN_RO(crash_notes); |
eca4549f5
|
153 |
|
948b3edba
|
154 |
static ssize_t crash_notes_size_show(struct device *dev, |
eca4549f5
|
155 156 157 |
struct device_attribute *attr, char *buf) { |
948b3edba
|
158 159 |
return sysfs_emit(buf, "%zu ", sizeof(note_buf_t)); |
eca4549f5
|
160 |
} |
948b3edba
|
161 |
static DEVICE_ATTR_ADMIN_RO(crash_notes_size); |
c055da9fb
|
162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 |
static struct attribute *crash_note_cpu_attrs[] = { &dev_attr_crash_notes.attr, &dev_attr_crash_notes_size.attr, NULL }; static struct attribute_group crash_note_cpu_attr_group = { .attrs = crash_note_cpu_attrs, }; #endif static const struct attribute_group *common_cpu_attr_groups[] = { #ifdef CONFIG_KEXEC &crash_note_cpu_attr_group, |
51be5606d
|
177 |
#endif |
c055da9fb
|
178 179 |
NULL }; |
51be5606d
|
180 |
|
1c4e2d70a
|
181 182 183 184 |
static const struct attribute_group *hotplugable_cpu_attr_groups[] = { #ifdef CONFIG_KEXEC &crash_note_cpu_attr_group, #endif |
1c4e2d70a
|
185 186 |
NULL }; |
1da177e4c
|
187 |
/* |
9d1fe3236
|
188 189 |
* Print cpu online, possible, present, and system maps */ |
265d2e2e3
|
190 191 |
struct cpu_attr { |
8a25a2fd1
|
192 |
struct device_attribute attr; |
848e23915
|
193 |
const struct cpumask *const map; |
265d2e2e3
|
194 |
}; |
8a25a2fd1
|
195 196 |
static ssize_t show_cpus_attr(struct device *dev, struct device_attribute *attr, |
265d2e2e3
|
197 |
char *buf) |
9d1fe3236
|
198 |
{ |
265d2e2e3
|
199 |
struct cpu_attr *ca = container_of(attr, struct cpu_attr, attr); |
9d1fe3236
|
200 |
|
848e23915
|
201 |
return cpumap_print_to_pagebuf(true, buf, ca->map); |
9d1fe3236
|
202 |
} |
8a25a2fd1
|
203 204 |
#define _CPU_ATTR(name, map) \ { __ATTR(name, 0444, show_cpus_attr, NULL), map } |
9d1fe3236
|
205 |
|
8a25a2fd1
|
206 |
/* Keep in sync with cpu_subsys_attrs */ |
265d2e2e3
|
207 |
static struct cpu_attr cpu_attrs[] = { |
848e23915
|
208 209 210 |
_CPU_ATTR(online, &__cpu_online_mask), _CPU_ATTR(possible, &__cpu_possible_mask), _CPU_ATTR(present, &__cpu_present_mask), |
265d2e2e3
|
211 |
}; |
9d1fe3236
|
212 |
|
e057d7aea
|
213 214 215 |
/* * Print values for NR_CPUS and offlined cpus */ |
8a25a2fd1
|
216 217 |
static ssize_t print_cpus_kernel_max(struct device *dev, struct device_attribute *attr, char *buf) |
e057d7aea
|
218 |
{ |
aa838896d
|
219 220 |
return sysfs_emit(buf, "%d ", NR_CPUS - 1); |
e057d7aea
|
221 |
} |
8a25a2fd1
|
222 |
static DEVICE_ATTR(kernel_max, 0444, print_cpus_kernel_max, NULL); |
e057d7aea
|
223 224 225 |
/* arch-optional setting to enable display of offline cpus >= nr_cpu_ids */ unsigned int total_cpus; |
8a25a2fd1
|
226 227 |
static ssize_t print_cpus_offline(struct device *dev, struct device_attribute *attr, char *buf) |
e057d7aea
|
228 |
{ |
948b3edba
|
229 |
int len = 0; |
e057d7aea
|
230 231 232 233 234 |
cpumask_var_t offline; /* display offline cpus < nr_cpu_ids */ if (!alloc_cpumask_var(&offline, GFP_KERNEL)) return -ENOMEM; |
cdc6e3d39
|
235 |
cpumask_andnot(offline, cpu_possible_mask, cpu_online_mask); |
948b3edba
|
236 |
len += sysfs_emit_at(buf, len, "%*pbl", cpumask_pr_args(offline)); |
e057d7aea
|
237 238 239 240 |
free_cpumask_var(offline); /* display offline cpus >= nr_cpu_ids */ if (total_cpus && nr_cpu_ids < total_cpus) { |
948b3edba
|
241 |
len += sysfs_emit_at(buf, len, ","); |
e057d7aea
|
242 243 |
if (nr_cpu_ids == total_cpus-1) |
948b3edba
|
244 |
len += sysfs_emit_at(buf, len, "%u", nr_cpu_ids); |
e057d7aea
|
245 |
else |
948b3edba
|
246 247 |
len += sysfs_emit_at(buf, len, "%u-%d", nr_cpu_ids, total_cpus - 1); |
e057d7aea
|
248 |
} |
948b3edba
|
249 250 251 252 |
len += sysfs_emit_at(buf, len, " "); return len; |
e057d7aea
|
253 |
} |
8a25a2fd1
|
254 |
static DEVICE_ATTR(offline, 0444, print_cpus_offline, NULL); |
e057d7aea
|
255 |
|
59f30abe9
|
256 257 258 |
static ssize_t print_cpus_isolated(struct device *dev, struct device_attribute *attr, char *buf) { |
948b3edba
|
259 |
int len; |
edb938217
|
260 |
cpumask_var_t isolated; |
59f30abe9
|
261 |
|
edb938217
|
262 263 264 265 266 |
if (!alloc_cpumask_var(&isolated, GFP_KERNEL)) return -ENOMEM; cpumask_andnot(isolated, cpu_possible_mask, housekeeping_cpumask(HK_FLAG_DOMAIN)); |
948b3edba
|
267 268 |
len = sysfs_emit(buf, "%*pbl ", cpumask_pr_args(isolated)); |
edb938217
|
269 270 |
free_cpumask_var(isolated); |
59f30abe9
|
271 |
|
948b3edba
|
272 |
return len; |
59f30abe9
|
273 274 |
} static DEVICE_ATTR(isolated, 0444, print_cpus_isolated, NULL); |
6570a9a1c
|
275 276 |
#ifdef CONFIG_NO_HZ_FULL static ssize_t print_cpus_nohz_full(struct device *dev, |
948b3edba
|
277 |
struct device_attribute *attr, char *buf) |
6570a9a1c
|
278 |
{ |
aa838896d
|
279 280 |
return sysfs_emit(buf, "%*pbl ", cpumask_pr_args(tick_nohz_full_mask)); |
6570a9a1c
|
281 282 283 |
} static DEVICE_ATTR(nohz_full, 0444, print_cpus_nohz_full, NULL); #endif |
2885e25c4
|
284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 |
static void cpu_device_release(struct device *dev) { /* * This is an empty function to prevent the driver core from spitting a * warning at us. Yes, I know this is directly opposite of what the * documentation for the driver core and kobjects say, and the author * of this code has already been publically ridiculed for doing * something as foolish as this. However, at this point in time, it is * the only way to handle the issue of statically allocated cpu * devices. The different architectures will have their cpu device * code reworked to properly handle this in the near future, so this * function will then be changed to correctly free up the memory held * by the cpu device. * * Never copy this way of doing things, or you too will be made fun of |
30a4840a4
|
299 |
* on the linux-kernel list, you have been warned. |
2885e25c4
|
300 301 |
*/ } |
67bad2fdb
|
302 303 304 305 306 |
#ifdef CONFIG_GENERIC_CPU_AUTOPROBE static ssize_t print_cpu_modalias(struct device *dev, struct device_attribute *attr, char *buf) { |
948b3edba
|
307 |
int len = 0; |
67bad2fdb
|
308 |
u32 i; |
948b3edba
|
309 310 311 |
len += sysfs_emit_at(buf, len, "cpu:type:" CPU_FEATURE_TYPEFMT ":feature:", CPU_FEATURE_TYPEVAL); |
67bad2fdb
|
312 313 314 |
for (i = 0; i < MAX_CPU_FEATURES; i++) if (cpu_have_feature(i)) { |
948b3edba
|
315 316 |
if (len + sizeof(",XXXX ") >= PAGE_SIZE) { |
67bad2fdb
|
317 318 319 320 |
WARN(1, "CPU features overflow page "); break; } |
948b3edba
|
321 |
len += sysfs_emit_at(buf, len, ",%04X", i); |
67bad2fdb
|
322 |
} |
948b3edba
|
323 324 325 |
len += sysfs_emit_at(buf, len, " "); return len; |
67bad2fdb
|
326 |
} |
67bad2fdb
|
327 328 329 330 331 332 333 334 335 336 337 338 |
static int cpu_uevent(struct device *dev, struct kobj_uevent_env *env) { char *buf = kzalloc(PAGE_SIZE, GFP_KERNEL); if (buf) { print_cpu_modalias(NULL, NULL, buf); add_uevent_var(env, "MODALIAS=%s", buf); kfree(buf); } return 0; } #endif |
9d1fe3236
|
339 |
/* |
405ae7d38
|
340 |
* register_cpu - Setup a sysfs device for a CPU. |
72486f1f8
|
341 342 |
* @cpu - cpu->hotpluggable field set to 1 will generate a control file in * sysfs for this CPU. |
1da177e4c
|
343 344 345 346 |
* @num - CPU number to use when creating the device. * * Initialize and register the CPU device. */ |
a83048ebd
|
347 |
int register_cpu(struct cpu *cpu, int num) |
1da177e4c
|
348 349 |
{ int error; |
76b67ed9d
|
350 |
|
8a25a2fd1
|
351 |
cpu->node_id = cpu_to_node(num); |
29bb5d4fd
|
352 |
memset(&cpu->dev, 0x00, sizeof(struct device)); |
8a25a2fd1
|
353 354 |
cpu->dev.id = num; cpu->dev.bus = &cpu_subsys; |
2885e25c4
|
355 |
cpu->dev.release = cpu_device_release; |
0902a9044
|
356 |
cpu->dev.offline_disabled = !cpu->hotpluggable; |
1001b4d4a
|
357 |
cpu->dev.offline = !cpu_online(num); |
f86e4718f
|
358 |
cpu->dev.of_node = of_get_cpu_node(num, NULL); |
2b9c1f032
|
359 |
#ifdef CONFIG_GENERIC_CPU_AUTOPROBE |
67bad2fdb
|
360 |
cpu->dev.bus->uevent = cpu_uevent; |
fad12ac8c
|
361 |
#endif |
c055da9fb
|
362 |
cpu->dev.groups = common_cpu_attr_groups; |
1c4e2d70a
|
363 364 |
if (cpu->hotpluggable) cpu->dev.groups = hotplugable_cpu_attr_groups; |
8a25a2fd1
|
365 |
error = device_register(&cpu->dev); |
3aaba245d
|
366 367 |
if (error) { put_device(&cpu->dev); |
59fffa340
|
368 |
return error; |
3aaba245d
|
369 |
} |
51be5606d
|
370 |
|
59fffa340
|
371 372 |
per_cpu(cpu_sys_devices, num) = &cpu->dev; register_cpu_under_node(num, cpu_to_node(num)); |
0759e80b8
|
373 374 |
dev_pm_qos_expose_latency_limit(&cpu->dev, PM_QOS_RESUME_LATENCY_NO_CONSTRAINT); |
59fffa340
|
375 376 |
return 0; |
1da177e4c
|
377 |
} |
8a25a2fd1
|
378 |
struct device *get_cpu_device(unsigned cpu) |
ad74557a4
|
379 |
{ |
e37d05dad
|
380 381 |
if (cpu < nr_cpu_ids && cpu_possible(cpu)) return per_cpu(cpu_sys_devices, cpu); |
ad74557a4
|
382 383 384 |
else return NULL; } |
8a25a2fd1
|
385 |
EXPORT_SYMBOL_GPL(get_cpu_device); |
3d52943b3
|
386 387 388 389 |
static void device_create_release(struct device *dev) { kfree(dev); } |
fa548d79d
|
390 |
__printf(4, 0) |
3d52943b3
|
391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 |
static struct device * __cpu_device_create(struct device *parent, void *drvdata, const struct attribute_group **groups, const char *fmt, va_list args) { struct device *dev = NULL; int retval = -ENODEV; dev = kzalloc(sizeof(*dev), GFP_KERNEL); if (!dev) { retval = -ENOMEM; goto error; } device_initialize(dev); dev->parent = parent; dev->groups = groups; dev->release = device_create_release; |
85945c28b
|
409 |
device_set_pm_not_required(dev); |
3d52943b3
|
410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 |
dev_set_drvdata(dev, drvdata); retval = kobject_set_name_vargs(&dev->kobj, fmt, args); if (retval) goto error; retval = device_add(dev); if (retval) goto error; return dev; error: put_device(dev); return ERR_PTR(retval); } struct device *cpu_device_create(struct device *parent, void *drvdata, const struct attribute_group **groups, const char *fmt, ...) { va_list vargs; struct device *dev; va_start(vargs, fmt); dev = __cpu_device_create(parent, drvdata, groups, fmt, vargs); va_end(vargs); return dev; } EXPORT_SYMBOL_GPL(cpu_device_create); |
2b9c1f032
|
440 |
#ifdef CONFIG_GENERIC_CPU_AUTOPROBE |
67bad2fdb
|
441 |
static DEVICE_ATTR(modalias, 0444, print_cpu_modalias, NULL); |
fad12ac8c
|
442 |
#endif |
8a25a2fd1
|
443 444 445 446 447 448 449 450 451 452 |
static struct attribute *cpu_root_attrs[] = { #ifdef CONFIG_ARCH_CPU_PROBE_RELEASE &dev_attr_probe.attr, &dev_attr_release.attr, #endif &cpu_attrs[0].attr.attr, &cpu_attrs[1].attr.attr, &cpu_attrs[2].attr.attr, &dev_attr_kernel_max.attr, &dev_attr_offline.attr, |
59f30abe9
|
453 |
&dev_attr_isolated.attr, |
6570a9a1c
|
454 455 456 |
#ifdef CONFIG_NO_HZ_FULL &dev_attr_nohz_full.attr, #endif |
2b9c1f032
|
457 |
#ifdef CONFIG_GENERIC_CPU_AUTOPROBE |
fad12ac8c
|
458 459 |
&dev_attr_modalias.attr, #endif |
8a25a2fd1
|
460 461 462 463 464 465 466 467 468 469 470 |
NULL }; static struct attribute_group cpu_root_attr_group = { .attrs = cpu_root_attrs, }; static const struct attribute_group *cpu_root_attr_groups[] = { &cpu_root_attr_group, NULL, }; |
1da177e4c
|
471 |
|
2987557f5
|
472 473 |
bool cpu_is_hotpluggable(unsigned cpu) { |
7affca353
|
474 475 |
struct device *dev = get_cpu_device(cpu); return dev && container_of(dev, struct cpu, dev)->hotpluggable; |
2987557f5
|
476 477 |
} EXPORT_SYMBOL_GPL(cpu_is_hotpluggable); |
9f13a1fd4
|
478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 |
#ifdef CONFIG_GENERIC_CPU_DEVICES static DEFINE_PER_CPU(struct cpu, cpu_devices); #endif static void __init cpu_dev_register_generic(void) { #ifdef CONFIG_GENERIC_CPU_DEVICES int i; for_each_possible_cpu(i) { if (register_cpu(&per_cpu(cpu_devices, i), i)) panic("Failed to register CPU device"); } #endif } |
87590ce6e
|
493 494 495 496 497 |
#ifdef CONFIG_GENERIC_CPU_VULNERABILITIES ssize_t __weak cpu_show_meltdown(struct device *dev, struct device_attribute *attr, char *buf) { |
aa838896d
|
498 499 |
return sysfs_emit(buf, "Not affected "); |
87590ce6e
|
500 501 502 503 504 |
} ssize_t __weak cpu_show_spectre_v1(struct device *dev, struct device_attribute *attr, char *buf) { |
aa838896d
|
505 506 |
return sysfs_emit(buf, "Not affected "); |
87590ce6e
|
507 508 509 510 511 |
} ssize_t __weak cpu_show_spectre_v2(struct device *dev, struct device_attribute *attr, char *buf) { |
aa838896d
|
512 513 |
return sysfs_emit(buf, "Not affected "); |
87590ce6e
|
514 |
} |
c456442cd
|
515 516 517 |
ssize_t __weak cpu_show_spec_store_bypass(struct device *dev, struct device_attribute *attr, char *buf) { |
aa838896d
|
518 519 |
return sysfs_emit(buf, "Not affected "); |
c456442cd
|
520 |
} |
17dbca119
|
521 522 523 |
ssize_t __weak cpu_show_l1tf(struct device *dev, struct device_attribute *attr, char *buf) { |
aa838896d
|
524 525 |
return sysfs_emit(buf, "Not affected "); |
17dbca119
|
526 |
} |
8a4b06d39
|
527 528 529 |
ssize_t __weak cpu_show_mds(struct device *dev, struct device_attribute *attr, char *buf) { |
aa838896d
|
530 531 |
return sysfs_emit(buf, "Not affected "); |
8a4b06d39
|
532 |
} |
6608b45ac
|
533 534 535 536 |
ssize_t __weak cpu_show_tsx_async_abort(struct device *dev, struct device_attribute *attr, char *buf) { |
aa838896d
|
537 538 |
return sysfs_emit(buf, "Not affected "); |
6608b45ac
|
539 |
} |
db4d30fbb
|
540 |
ssize_t __weak cpu_show_itlb_multihit(struct device *dev, |
948b3edba
|
541 |
struct device_attribute *attr, char *buf) |
db4d30fbb
|
542 |
{ |
aa838896d
|
543 544 |
return sysfs_emit(buf, "Not affected "); |
db4d30fbb
|
545 |
} |
7e5b3c267
|
546 547 548 |
ssize_t __weak cpu_show_srbds(struct device *dev, struct device_attribute *attr, char *buf) { |
aa838896d
|
549 550 |
return sysfs_emit(buf, "Not affected "); |
7e5b3c267
|
551 |
} |
87590ce6e
|
552 553 554 |
static DEVICE_ATTR(meltdown, 0444, cpu_show_meltdown, NULL); static DEVICE_ATTR(spectre_v1, 0444, cpu_show_spectre_v1, NULL); static DEVICE_ATTR(spectre_v2, 0444, cpu_show_spectre_v2, NULL); |
c456442cd
|
555 |
static DEVICE_ATTR(spec_store_bypass, 0444, cpu_show_spec_store_bypass, NULL); |
17dbca119
|
556 |
static DEVICE_ATTR(l1tf, 0444, cpu_show_l1tf, NULL); |
8a4b06d39
|
557 |
static DEVICE_ATTR(mds, 0444, cpu_show_mds, NULL); |
6608b45ac
|
558 |
static DEVICE_ATTR(tsx_async_abort, 0444, cpu_show_tsx_async_abort, NULL); |
db4d30fbb
|
559 |
static DEVICE_ATTR(itlb_multihit, 0444, cpu_show_itlb_multihit, NULL); |
7e5b3c267
|
560 |
static DEVICE_ATTR(srbds, 0444, cpu_show_srbds, NULL); |
87590ce6e
|
561 562 563 564 565 |
static struct attribute *cpu_root_vulnerabilities_attrs[] = { &dev_attr_meltdown.attr, &dev_attr_spectre_v1.attr, &dev_attr_spectre_v2.attr, |
c456442cd
|
566 |
&dev_attr_spec_store_bypass.attr, |
17dbca119
|
567 |
&dev_attr_l1tf.attr, |
8a4b06d39
|
568 |
&dev_attr_mds.attr, |
6608b45ac
|
569 |
&dev_attr_tsx_async_abort.attr, |
db4d30fbb
|
570 |
&dev_attr_itlb_multihit.attr, |
7e5b3c267
|
571 |
&dev_attr_srbds.attr, |
87590ce6e
|
572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 |
NULL }; static const struct attribute_group cpu_root_vulnerabilities_group = { .name = "vulnerabilities", .attrs = cpu_root_vulnerabilities_attrs, }; static void __init cpu_register_vulnerabilities(void) { if (sysfs_create_group(&cpu_subsys.dev_root->kobj, &cpu_root_vulnerabilities_group)) pr_err("Unable to register CPU vulnerabilities "); } #else static inline void cpu_register_vulnerabilities(void) { } #endif |
024f78462
|
591 |
void __init cpu_dev_init(void) |
1da177e4c
|
592 |
{ |
024f78462
|
593 594 |
if (subsys_system_register(&cpu_subsys, cpu_root_attr_groups)) panic("Failed to register CPU subsystem"); |
8a25a2fd1
|
595 |
|
9f13a1fd4
|
596 |
cpu_dev_register_generic(); |
87590ce6e
|
597 |
cpu_register_vulnerabilities(); |
1da177e4c
|
598 |
} |