diff options
Diffstat (limited to 'arch/s390/kernel/topology.c')
-rw-r--r-- | arch/s390/kernel/topology.c | 148 |
1 files changed, 135 insertions, 13 deletions
diff --git a/arch/s390/kernel/topology.c b/arch/s390/kernel/topology.c index bb47c92476f0..ed0bdd220e1a 100644 --- a/arch/s390/kernel/topology.c +++ b/arch/s390/kernel/topology.c | |||
@@ -8,6 +8,8 @@ | |||
8 | 8 | ||
9 | #include <linux/workqueue.h> | 9 | #include <linux/workqueue.h> |
10 | #include <linux/bootmem.h> | 10 | #include <linux/bootmem.h> |
11 | #include <linux/uaccess.h> | ||
12 | #include <linux/sysctl.h> | ||
11 | #include <linux/cpuset.h> | 13 | #include <linux/cpuset.h> |
12 | #include <linux/device.h> | 14 | #include <linux/device.h> |
13 | #include <linux/export.h> | 15 | #include <linux/export.h> |
@@ -29,12 +31,20 @@ | |||
29 | #define PTF_VERTICAL (1UL) | 31 | #define PTF_VERTICAL (1UL) |
30 | #define PTF_CHECK (2UL) | 32 | #define PTF_CHECK (2UL) |
31 | 33 | ||
34 | enum { | ||
35 | TOPOLOGY_MODE_HW, | ||
36 | TOPOLOGY_MODE_SINGLE, | ||
37 | TOPOLOGY_MODE_PACKAGE, | ||
38 | TOPOLOGY_MODE_UNINITIALIZED | ||
39 | }; | ||
40 | |||
32 | struct mask_info { | 41 | struct mask_info { |
33 | struct mask_info *next; | 42 | struct mask_info *next; |
34 | unsigned char id; | 43 | unsigned char id; |
35 | cpumask_t mask; | 44 | cpumask_t mask; |
36 | }; | 45 | }; |
37 | 46 | ||
47 | static int topology_mode = TOPOLOGY_MODE_UNINITIALIZED; | ||
38 | static void set_topology_timer(void); | 48 | static void set_topology_timer(void); |
39 | static void topology_work_fn(struct work_struct *work); | 49 | static void topology_work_fn(struct work_struct *work); |
40 | static struct sysinfo_15_1_x *tl_info; | 50 | static struct sysinfo_15_1_x *tl_info; |
@@ -59,11 +69,26 @@ static cpumask_t cpu_group_map(struct mask_info *info, unsigned int cpu) | |||
59 | cpumask_t mask; | 69 | cpumask_t mask; |
60 | 70 | ||
61 | cpumask_copy(&mask, cpumask_of(cpu)); | 71 | cpumask_copy(&mask, cpumask_of(cpu)); |
62 | if (!MACHINE_HAS_TOPOLOGY) | 72 | switch (topology_mode) { |
63 | return mask; | 73 | case TOPOLOGY_MODE_HW: |
64 | for (; info; info = info->next) { | 74 | while (info) { |
65 | if (cpumask_test_cpu(cpu, &info->mask)) | 75 | if (cpumask_test_cpu(cpu, &info->mask)) { |
66 | return info->mask; | 76 | mask = info->mask; |
77 | break; | ||
78 | } | ||
79 | info = info->next; | ||
80 | } | ||
81 | if (cpumask_empty(&mask)) | ||
82 | cpumask_copy(&mask, cpumask_of(cpu)); | ||
83 | break; | ||
84 | case TOPOLOGY_MODE_PACKAGE: | ||
85 | cpumask_copy(&mask, cpu_present_mask); | ||
86 | break; | ||
87 | default: | ||
88 | /* fallthrough */ | ||
89 | case TOPOLOGY_MODE_SINGLE: | ||
90 | cpumask_copy(&mask, cpumask_of(cpu)); | ||
91 | break; | ||
67 | } | 92 | } |
68 | return mask; | 93 | return mask; |
69 | } | 94 | } |
@@ -74,7 +99,7 @@ static cpumask_t cpu_thread_map(unsigned int cpu) | |||
74 | int i; | 99 | int i; |
75 | 100 | ||
76 | cpumask_copy(&mask, cpumask_of(cpu)); | 101 | cpumask_copy(&mask, cpumask_of(cpu)); |
77 | if (!MACHINE_HAS_TOPOLOGY) | 102 | if (topology_mode != TOPOLOGY_MODE_HW) |
78 | return mask; | 103 | return mask; |
79 | cpu -= cpu % (smp_cpu_mtid + 1); | 104 | cpu -= cpu % (smp_cpu_mtid + 1); |
80 | for (i = 0; i <= smp_cpu_mtid; i++) | 105 | for (i = 0; i <= smp_cpu_mtid; i++) |
@@ -184,10 +209,8 @@ static void topology_update_polarization_simple(void) | |||
184 | { | 209 | { |
185 | int cpu; | 210 | int cpu; |
186 | 211 | ||
187 | mutex_lock(&smp_cpu_state_mutex); | ||
188 | for_each_possible_cpu(cpu) | 212 | for_each_possible_cpu(cpu) |
189 | smp_cpu_set_polarization(cpu, POLARIZATION_HRZ); | 213 | smp_cpu_set_polarization(cpu, POLARIZATION_HRZ); |
190 | mutex_unlock(&smp_cpu_state_mutex); | ||
191 | } | 214 | } |
192 | 215 | ||
193 | static int ptf(unsigned long fc) | 216 | static int ptf(unsigned long fc) |
@@ -223,7 +246,7 @@ int topology_set_cpu_management(int fc) | |||
223 | static void update_cpu_masks(void) | 246 | static void update_cpu_masks(void) |
224 | { | 247 | { |
225 | struct cpu_topology_s390 *topo; | 248 | struct cpu_topology_s390 *topo; |
226 | int cpu; | 249 | int cpu, id; |
227 | 250 | ||
228 | for_each_possible_cpu(cpu) { | 251 | for_each_possible_cpu(cpu) { |
229 | topo = &cpu_topology[cpu]; | 252 | topo = &cpu_topology[cpu]; |
@@ -231,12 +254,13 @@ static void update_cpu_masks(void) | |||
231 | topo->core_mask = cpu_group_map(&socket_info, cpu); | 254 | topo->core_mask = cpu_group_map(&socket_info, cpu); |
232 | topo->book_mask = cpu_group_map(&book_info, cpu); | 255 | topo->book_mask = cpu_group_map(&book_info, cpu); |
233 | topo->drawer_mask = cpu_group_map(&drawer_info, cpu); | 256 | topo->drawer_mask = cpu_group_map(&drawer_info, cpu); |
234 | if (!MACHINE_HAS_TOPOLOGY) { | 257 | if (topology_mode != TOPOLOGY_MODE_HW) { |
258 | id = topology_mode == TOPOLOGY_MODE_PACKAGE ? 0 : cpu; | ||
235 | topo->thread_id = cpu; | 259 | topo->thread_id = cpu; |
236 | topo->core_id = cpu; | 260 | topo->core_id = cpu; |
237 | topo->socket_id = cpu; | 261 | topo->socket_id = id; |
238 | topo->book_id = cpu; | 262 | topo->book_id = id; |
239 | topo->drawer_id = cpu; | 263 | topo->drawer_id = id; |
240 | if (cpu_present(cpu)) | 264 | if (cpu_present(cpu)) |
241 | cpumask_set_cpu(cpu, &cpus_with_topology); | 265 | cpumask_set_cpu(cpu, &cpus_with_topology); |
242 | } | 266 | } |
@@ -254,6 +278,7 @@ static int __arch_update_cpu_topology(void) | |||
254 | struct sysinfo_15_1_x *info = tl_info; | 278 | struct sysinfo_15_1_x *info = tl_info; |
255 | int rc = 0; | 279 | int rc = 0; |
256 | 280 | ||
281 | mutex_lock(&smp_cpu_state_mutex); | ||
257 | cpumask_clear(&cpus_with_topology); | 282 | cpumask_clear(&cpus_with_topology); |
258 | if (MACHINE_HAS_TOPOLOGY) { | 283 | if (MACHINE_HAS_TOPOLOGY) { |
259 | rc = 1; | 284 | rc = 1; |
@@ -263,6 +288,7 @@ static int __arch_update_cpu_topology(void) | |||
263 | update_cpu_masks(); | 288 | update_cpu_masks(); |
264 | if (!MACHINE_HAS_TOPOLOGY) | 289 | if (!MACHINE_HAS_TOPOLOGY) |
265 | topology_update_polarization_simple(); | 290 | topology_update_polarization_simple(); |
291 | mutex_unlock(&smp_cpu_state_mutex); | ||
266 | return rc; | 292 | return rc; |
267 | } | 293 | } |
268 | 294 | ||
@@ -289,6 +315,11 @@ void topology_schedule_update(void) | |||
289 | schedule_work(&topology_work); | 315 | schedule_work(&topology_work); |
290 | } | 316 | } |
291 | 317 | ||
318 | static void topology_flush_work(void) | ||
319 | { | ||
320 | flush_work(&topology_work); | ||
321 | } | ||
322 | |||
292 | static void topology_timer_fn(unsigned long ignored) | 323 | static void topology_timer_fn(unsigned long ignored) |
293 | { | 324 | { |
294 | if (ptf(PTF_CHECK)) | 325 | if (ptf(PTF_CHECK)) |
@@ -459,6 +490,12 @@ void __init topology_init_early(void) | |||
459 | struct sysinfo_15_1_x *info; | 490 | struct sysinfo_15_1_x *info; |
460 | 491 | ||
461 | set_sched_topology(s390_topology); | 492 | set_sched_topology(s390_topology); |
493 | if (topology_mode == TOPOLOGY_MODE_UNINITIALIZED) { | ||
494 | if (MACHINE_HAS_TOPOLOGY) | ||
495 | topology_mode = TOPOLOGY_MODE_HW; | ||
496 | else | ||
497 | topology_mode = TOPOLOGY_MODE_SINGLE; | ||
498 | } | ||
462 | if (!MACHINE_HAS_TOPOLOGY) | 499 | if (!MACHINE_HAS_TOPOLOGY) |
463 | goto out; | 500 | goto out; |
464 | tl_info = memblock_virt_alloc(PAGE_SIZE, PAGE_SIZE); | 501 | tl_info = memblock_virt_alloc(PAGE_SIZE, PAGE_SIZE); |
@@ -474,12 +511,97 @@ out: | |||
474 | __arch_update_cpu_topology(); | 511 | __arch_update_cpu_topology(); |
475 | } | 512 | } |
476 | 513 | ||
514 | static inline int topology_get_mode(int enabled) | ||
515 | { | ||
516 | if (!enabled) | ||
517 | return TOPOLOGY_MODE_SINGLE; | ||
518 | return MACHINE_HAS_TOPOLOGY ? TOPOLOGY_MODE_HW : TOPOLOGY_MODE_PACKAGE; | ||
519 | } | ||
520 | |||
521 | static inline int topology_is_enabled(void) | ||
522 | { | ||
523 | return topology_mode != TOPOLOGY_MODE_SINGLE; | ||
524 | } | ||
525 | |||
526 | static int __init topology_setup(char *str) | ||
527 | { | ||
528 | bool enabled; | ||
529 | int rc; | ||
530 | |||
531 | rc = kstrtobool(str, &enabled); | ||
532 | if (rc) | ||
533 | return rc; | ||
534 | topology_mode = topology_get_mode(enabled); | ||
535 | return 0; | ||
536 | } | ||
537 | early_param("topology", topology_setup); | ||
538 | |||
539 | static int topology_ctl_handler(struct ctl_table *ctl, int write, | ||
540 | void __user *buffer, size_t *lenp, loff_t *ppos) | ||
541 | { | ||
542 | unsigned int len; | ||
543 | int new_mode; | ||
544 | char buf[2]; | ||
545 | |||
546 | if (!*lenp || *ppos) { | ||
547 | *lenp = 0; | ||
548 | return 0; | ||
549 | } | ||
550 | if (!write) { | ||
551 | strncpy(buf, topology_is_enabled() ? "1\n" : "0\n", | ||
552 | ARRAY_SIZE(buf)); | ||
553 | len = strnlen(buf, ARRAY_SIZE(buf)); | ||
554 | if (len > *lenp) | ||
555 | len = *lenp; | ||
556 | if (copy_to_user(buffer, buf, len)) | ||
557 | return -EFAULT; | ||
558 | goto out; | ||
559 | } | ||
560 | len = *lenp; | ||
561 | if (copy_from_user(buf, buffer, len > sizeof(buf) ? sizeof(buf) : len)) | ||
562 | return -EFAULT; | ||
563 | if (buf[0] != '0' && buf[0] != '1') | ||
564 | return -EINVAL; | ||
565 | mutex_lock(&smp_cpu_state_mutex); | ||
566 | new_mode = topology_get_mode(buf[0] == '1'); | ||
567 | if (topology_mode != new_mode) { | ||
568 | topology_mode = new_mode; | ||
569 | topology_schedule_update(); | ||
570 | } | ||
571 | mutex_unlock(&smp_cpu_state_mutex); | ||
572 | topology_flush_work(); | ||
573 | out: | ||
574 | *lenp = len; | ||
575 | *ppos += len; | ||
576 | return 0; | ||
577 | } | ||
578 | |||
579 | static struct ctl_table topology_ctl_table[] = { | ||
580 | { | ||
581 | .procname = "topology", | ||
582 | .mode = 0644, | ||
583 | .proc_handler = topology_ctl_handler, | ||
584 | }, | ||
585 | { }, | ||
586 | }; | ||
587 | |||
588 | static struct ctl_table topology_dir_table[] = { | ||
589 | { | ||
590 | .procname = "s390", | ||
591 | .maxlen = 0, | ||
592 | .mode = 0555, | ||
593 | .child = topology_ctl_table, | ||
594 | }, | ||
595 | { }, | ||
596 | }; | ||
597 | |||
477 | static int __init topology_init(void) | 598 | static int __init topology_init(void) |
478 | { | 599 | { |
479 | if (MACHINE_HAS_TOPOLOGY) | 600 | if (MACHINE_HAS_TOPOLOGY) |
480 | set_topology_timer(); | 601 | set_topology_timer(); |
481 | else | 602 | else |
482 | topology_update_polarization_simple(); | 603 | topology_update_polarization_simple(); |
604 | register_sysctl_table(topology_dir_table); | ||
483 | return device_create_file(cpu_subsys.dev_root, &dev_attr_dispatching); | 605 | return device_create_file(cpu_subsys.dev_root, &dev_attr_dispatching); |
484 | } | 606 | } |
485 | device_initcall(topology_init); | 607 | device_initcall(topology_init); |