diff options
author | Helge Deller <deller@gmx.de> | 2017-09-21 15:55:01 -0400 |
---|---|---|
committer | Helge Deller <deller@gmx.de> | 2017-11-17 09:27:22 -0500 |
commit | bf7b4c1b3c92f246a535a7c792177041d0442011 (patch) | |
tree | 1bd779b15d0c77656f99b79a1e8950910daf43cf | |
parent | 05f016d2ca7a4fab99d5d5472168506ddf95e74f (diff) |
parisc: Add CPU topology support
Add topology support, including multi-core scheduler support on
PA8800/PA8900 CPUs and enhanced output in /proc/cpuinfo, e.g.
lscpu now reports on a single-socket, dual-core machine:
Architecture: parisc64
CPU(s): 2
On-line CPU(s) list: 0,1
Thread(s) per core: 1
Core(s) per socket: 2
Socket(s): 1
CPU family: PA-RISC 2.0
Model name: PA8800 (Mako)
Signed-off-by: Helge Deller <deller@gmx.de>
-rw-r--r-- | arch/parisc/Kconfig | 16 | ||||
-rw-r--r-- | arch/parisc/include/asm/topology.h | 36 | ||||
-rw-r--r-- | arch/parisc/kernel/Makefile | 4 | ||||
-rw-r--r-- | arch/parisc/kernel/processor.c | 13 | ||||
-rw-r--r-- | arch/parisc/kernel/setup.c | 2 | ||||
-rw-r--r-- | arch/parisc/kernel/topology.c | 153 |
6 files changed, 198 insertions, 26 deletions
diff --git a/arch/parisc/Kconfig b/arch/parisc/Kconfig index 1fd3eb5b66c6..7171c21bb0af 100644 --- a/arch/parisc/Kconfig +++ b/arch/parisc/Kconfig | |||
@@ -32,6 +32,7 @@ config PARISC | |||
32 | select GENERIC_PCI_IOMAP | 32 | select GENERIC_PCI_IOMAP |
33 | select ARCH_HAVE_NMI_SAFE_CMPXCHG | 33 | select ARCH_HAVE_NMI_SAFE_CMPXCHG |
34 | select GENERIC_SMP_IDLE_THREAD | 34 | select GENERIC_SMP_IDLE_THREAD |
35 | select GENERIC_CPU_DEVICES | ||
35 | select GENERIC_STRNCPY_FROM_USER | 36 | select GENERIC_STRNCPY_FROM_USER |
36 | select SYSCTL_ARCH_UNALIGN_ALLOW | 37 | select SYSCTL_ARCH_UNALIGN_ALLOW |
37 | select SYSCTL_EXCEPTION_TRACE | 38 | select SYSCTL_EXCEPTION_TRACE |
@@ -288,6 +289,21 @@ config SMP | |||
288 | 289 | ||
289 | If you don't know what to do here, say N. | 290 | If you don't know what to do here, say N. |
290 | 291 | ||
292 | config PARISC_CPU_TOPOLOGY | ||
293 | bool "Support cpu topology definition" | ||
294 | depends on SMP | ||
295 | default y | ||
296 | help | ||
297 | Support PARISC cpu topology definition. | ||
298 | |||
299 | config SCHED_MC | ||
300 | bool "Multi-core scheduler support" | ||
301 | depends on PARISC_CPU_TOPOLOGY && PA8X00 | ||
302 | help | ||
303 | Multi-core scheduler support improves the CPU scheduler's decision | ||
304 | making when dealing with multi-core CPU chips at a cost of slightly | ||
305 | increased overhead in some places. If unsure say N here. | ||
306 | |||
291 | config IRQSTACKS | 307 | config IRQSTACKS |
292 | bool "Use separate kernel stacks when processing interrupts" | 308 | bool "Use separate kernel stacks when processing interrupts" |
293 | default y | 309 | default y |
diff --git a/arch/parisc/include/asm/topology.h b/arch/parisc/include/asm/topology.h new file mode 100644 index 000000000000..6f0750c74e47 --- /dev/null +++ b/arch/parisc/include/asm/topology.h | |||
@@ -0,0 +1,36 @@ | |||
1 | #ifndef _ASM_PARISC_TOPOLOGY_H | ||
2 | #define _ASM_PARISC_TOPOLOGY_H | ||
3 | |||
4 | #ifdef CONFIG_PARISC_CPU_TOPOLOGY | ||
5 | |||
6 | #include <linux/cpumask.h> | ||
7 | |||
8 | struct cputopo_parisc { | ||
9 | int thread_id; | ||
10 | int core_id; | ||
11 | int socket_id; | ||
12 | cpumask_t thread_sibling; | ||
13 | cpumask_t core_sibling; | ||
14 | }; | ||
15 | |||
16 | extern struct cputopo_parisc cpu_topology[NR_CPUS]; | ||
17 | |||
18 | #define topology_physical_package_id(cpu) (cpu_topology[cpu].socket_id) | ||
19 | #define topology_core_id(cpu) (cpu_topology[cpu].core_id) | ||
20 | #define topology_core_cpumask(cpu) (&cpu_topology[cpu].core_sibling) | ||
21 | #define topology_sibling_cpumask(cpu) (&cpu_topology[cpu].thread_sibling) | ||
22 | |||
23 | void init_cpu_topology(void); | ||
24 | void store_cpu_topology(unsigned int cpuid); | ||
25 | const struct cpumask *cpu_coregroup_mask(int cpu); | ||
26 | |||
27 | #else | ||
28 | |||
29 | static inline void init_cpu_topology(void) { } | ||
30 | static inline void store_cpu_topology(unsigned int cpuid) { } | ||
31 | |||
32 | #endif | ||
33 | |||
34 | #include <asm-generic/topology.h> | ||
35 | |||
36 | #endif /* _ASM_ARM_TOPOLOGY_H */ | ||
diff --git a/arch/parisc/kernel/Makefile b/arch/parisc/kernel/Makefile index 649dc3eda448..eafd06ab59ef 100644 --- a/arch/parisc/kernel/Makefile +++ b/arch/parisc/kernel/Makefile | |||
@@ -9,8 +9,7 @@ obj-y := cache.o pacache.o setup.o pdt.o traps.o time.o irq.o \ | |||
9 | pa7300lc.o syscall.o entry.o sys_parisc.o firmware.o \ | 9 | pa7300lc.o syscall.o entry.o sys_parisc.o firmware.o \ |
10 | ptrace.o hardware.o inventory.o drivers.o \ | 10 | ptrace.o hardware.o inventory.o drivers.o \ |
11 | signal.o hpmc.o real2.o parisc_ksyms.o unaligned.o \ | 11 | signal.o hpmc.o real2.o parisc_ksyms.o unaligned.o \ |
12 | process.o processor.o pdc_cons.o pdc_chassis.o unwind.o \ | 12 | process.o processor.o pdc_cons.o pdc_chassis.o unwind.o |
13 | topology.o | ||
14 | 13 | ||
15 | ifdef CONFIG_FUNCTION_TRACER | 14 | ifdef CONFIG_FUNCTION_TRACER |
16 | # Do not profile debug and lowlevel utilities | 15 | # Do not profile debug and lowlevel utilities |
@@ -30,5 +29,6 @@ obj-$(CONFIG_AUDIT) += audit.o | |||
30 | obj64-$(CONFIG_AUDIT) += compat_audit.o | 29 | obj64-$(CONFIG_AUDIT) += compat_audit.o |
31 | # only supported for PCX-W/U in 64-bit mode at the moment | 30 | # only supported for PCX-W/U in 64-bit mode at the moment |
32 | obj-$(CONFIG_64BIT) += perf.o perf_asm.o $(obj64-y) | 31 | obj-$(CONFIG_64BIT) += perf.o perf_asm.o $(obj64-y) |
32 | obj-$(CONFIG_PARISC_CPU_TOPOLOGY) += topology.o | ||
33 | obj-$(CONFIG_FUNCTION_TRACER) += ftrace.o | 33 | obj-$(CONFIG_FUNCTION_TRACER) += ftrace.o |
34 | obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o | 34 | obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o |
diff --git a/arch/parisc/kernel/processor.c b/arch/parisc/kernel/processor.c index e120d63c1b28..45cc65902fce 100644 --- a/arch/parisc/kernel/processor.c +++ b/arch/parisc/kernel/processor.c | |||
@@ -184,6 +184,9 @@ static int __init processor_probe(struct parisc_device *dev) | |||
184 | p->txn_addr = txn_addr; /* save CPU IRQ address */ | 184 | p->txn_addr = txn_addr; /* save CPU IRQ address */ |
185 | p->cpu_num = cpu_info.cpu_num; | 185 | p->cpu_num = cpu_info.cpu_num; |
186 | p->cpu_loc = cpu_info.cpu_loc; | 186 | p->cpu_loc = cpu_info.cpu_loc; |
187 | |||
188 | store_cpu_topology(cpuid); | ||
189 | |||
187 | #ifdef CONFIG_SMP | 190 | #ifdef CONFIG_SMP |
188 | /* | 191 | /* |
189 | ** FIXME: review if any other initialization is clobbered | 192 | ** FIXME: review if any other initialization is clobbered |
@@ -325,6 +328,8 @@ int __init init_per_cpu(int cpunum) | |||
325 | set_firmware_width(); | 328 | set_firmware_width(); |
326 | ret = pdc_coproc_cfg(&coproc_cfg); | 329 | ret = pdc_coproc_cfg(&coproc_cfg); |
327 | 330 | ||
331 | store_cpu_topology(cpunum); | ||
332 | |||
328 | if(ret >= 0 && coproc_cfg.ccr_functional) { | 333 | if(ret >= 0 && coproc_cfg.ccr_functional) { |
329 | mtctl(coproc_cfg.ccr_functional, 10); /* 10 == Coprocessor Control Reg */ | 334 | mtctl(coproc_cfg.ccr_functional, 10); /* 10 == Coprocessor Control Reg */ |
330 | 335 | ||
@@ -388,6 +393,14 @@ show_cpuinfo (struct seq_file *m, void *v) | |||
388 | boot_cpu_data.cpu_hz / 1000000, | 393 | boot_cpu_data.cpu_hz / 1000000, |
389 | boot_cpu_data.cpu_hz % 1000000 ); | 394 | boot_cpu_data.cpu_hz % 1000000 ); |
390 | 395 | ||
396 | #ifdef CONFIG_PARISC_CPU_TOPOLOGY | ||
397 | seq_printf(m, "physical id\t: %d\n", | ||
398 | topology_physical_package_id(cpu)); | ||
399 | seq_printf(m, "siblings\t: %d\n", | ||
400 | cpumask_weight(topology_core_cpumask(cpu))); | ||
401 | seq_printf(m, "core id\t\t: %d\n", topology_core_id(cpu)); | ||
402 | #endif | ||
403 | |||
391 | seq_printf(m, "capabilities\t:"); | 404 | seq_printf(m, "capabilities\t:"); |
392 | if (boot_cpu_data.pdc.capabilities & PDC_MODEL_OS32) | 405 | if (boot_cpu_data.pdc.capabilities & PDC_MODEL_OS32) |
393 | seq_puts(m, " os32"); | 406 | seq_puts(m, " os32"); |
diff --git a/arch/parisc/kernel/setup.c b/arch/parisc/kernel/setup.c index f7d0c3b33d70..0e9675f857a5 100644 --- a/arch/parisc/kernel/setup.c +++ b/arch/parisc/kernel/setup.c | |||
@@ -408,6 +408,8 @@ void __init start_parisc(void) | |||
408 | 408 | ||
409 | cpunum = smp_processor_id(); | 409 | cpunum = smp_processor_id(); |
410 | 410 | ||
411 | init_cpu_topology(); | ||
412 | |||
411 | set_firmware_width_unlocked(); | 413 | set_firmware_width_unlocked(); |
412 | 414 | ||
413 | ret = pdc_coproc_cfg_unlocked(&coproc_cfg); | 415 | ret = pdc_coproc_cfg_unlocked(&coproc_cfg); |
diff --git a/arch/parisc/kernel/topology.c b/arch/parisc/kernel/topology.c index f5159381fdd6..0a10e4ddc528 100644 --- a/arch/parisc/kernel/topology.c +++ b/arch/parisc/kernel/topology.c | |||
@@ -1,37 +1,142 @@ | |||
1 | /* | 1 | /* |
2 | * arch/parisc/kernel/topology.c - Populate sysfs with topology information | 2 | * arch/parisc/kernel/topology.c |
3 | * | 3 | * |
4 | * This program is free software; you can redistribute it and/or modify | 4 | * Copyright (C) 2017 Helge Deller <deller@gmx.de> |
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation; either version 2 of the License, or | ||
7 | * (at your option) any later version. | ||
8 | * | 5 | * |
9 | * This program is distributed in the hope that it will be useful, but | 6 | * based on arch/arm/kernel/topology.c |
10 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or | ||
12 | * NON INFRINGEMENT. See the GNU General Public License for more | ||
13 | * details. | ||
14 | * | 7 | * |
15 | * You should have received a copy of the GNU General Public License | 8 | * This file is subject to the terms and conditions of the GNU General Public |
16 | * along with this program; if not, write to the Free Software | 9 | * License. See the file "COPYING" in the main directory of this archive |
17 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | 10 | * for more details. |
18 | */ | 11 | */ |
19 | 12 | ||
20 | #include <linux/init.h> | 13 | #include <linux/percpu.h> |
21 | #include <linux/smp.h> | 14 | #include <linux/sched.h> |
22 | #include <linux/cpu.h> | 15 | #include <linux/sched/topology.h> |
23 | #include <linux/cache.h> | ||
24 | 16 | ||
25 | static DEFINE_PER_CPU(struct cpu, cpu_devices); | 17 | #include <asm/topology.h> |
26 | 18 | ||
27 | static int __init topology_init(void) | 19 | /* |
20 | * cpu topology table | ||
21 | */ | ||
22 | struct cputopo_parisc cpu_topology[NR_CPUS] __read_mostly; | ||
23 | EXPORT_SYMBOL_GPL(cpu_topology); | ||
24 | |||
25 | const struct cpumask *cpu_coregroup_mask(int cpu) | ||
28 | { | 26 | { |
29 | int num; | 27 | return &cpu_topology[cpu].core_sibling; |
28 | } | ||
29 | |||
30 | static void update_siblings_masks(unsigned int cpuid) | ||
31 | { | ||
32 | struct cputopo_parisc *cpu_topo, *cpuid_topo = &cpu_topology[cpuid]; | ||
33 | int cpu; | ||
34 | |||
35 | /* update core and thread sibling masks */ | ||
36 | for_each_possible_cpu(cpu) { | ||
37 | cpu_topo = &cpu_topology[cpu]; | ||
38 | |||
39 | if (cpuid_topo->socket_id != cpu_topo->socket_id) | ||
40 | continue; | ||
41 | |||
42 | cpumask_set_cpu(cpuid, &cpu_topo->core_sibling); | ||
43 | if (cpu != cpuid) | ||
44 | cpumask_set_cpu(cpu, &cpuid_topo->core_sibling); | ||
45 | |||
46 | if (cpuid_topo->core_id != cpu_topo->core_id) | ||
47 | continue; | ||
48 | |||
49 | cpumask_set_cpu(cpuid, &cpu_topo->thread_sibling); | ||
50 | if (cpu != cpuid) | ||
51 | cpumask_set_cpu(cpu, &cpuid_topo->thread_sibling); | ||
52 | } | ||
53 | smp_wmb(); | ||
54 | } | ||
55 | |||
56 | static int dualcores_found __initdata; | ||
57 | |||
58 | /* | ||
59 | * store_cpu_topology is called at boot when only one cpu is running | ||
60 | * and with the mutex cpu_hotplug.lock locked, when several cpus have booted, | ||
61 | * which prevents simultaneous write access to cpu_topology array | ||
62 | */ | ||
63 | void __init store_cpu_topology(unsigned int cpuid) | ||
64 | { | ||
65 | struct cputopo_parisc *cpuid_topo = &cpu_topology[cpuid]; | ||
66 | struct cpuinfo_parisc *p; | ||
67 | int max_socket = -1; | ||
68 | unsigned long cpu; | ||
69 | |||
70 | /* If the cpu topology has been already set, just return */ | ||
71 | if (cpuid_topo->core_id != -1) | ||
72 | return; | ||
30 | 73 | ||
31 | for_each_present_cpu(num) { | 74 | /* create cpu topology mapping */ |
32 | register_cpu(&per_cpu(cpu_devices, num), num); | 75 | cpuid_topo->thread_id = -1; |
76 | cpuid_topo->core_id = 0; | ||
77 | |||
78 | p = &per_cpu(cpu_data, cpuid); | ||
79 | for_each_online_cpu(cpu) { | ||
80 | const struct cpuinfo_parisc *cpuinfo = &per_cpu(cpu_data, cpu); | ||
81 | |||
82 | if (cpu == cpuid) /* ignore current cpu */ | ||
83 | continue; | ||
84 | |||
85 | if (cpuinfo->cpu_loc == p->cpu_loc) { | ||
86 | cpuid_topo->core_id = cpu_topology[cpu].core_id; | ||
87 | if (p->cpu_loc) { | ||
88 | cpuid_topo->core_id++; | ||
89 | cpuid_topo->socket_id = cpu_topology[cpu].socket_id; | ||
90 | dualcores_found = 1; | ||
91 | continue; | ||
92 | } | ||
93 | } | ||
94 | |||
95 | if (cpuid_topo->socket_id == -1) | ||
96 | max_socket = max(max_socket, cpu_topology[cpu].socket_id); | ||
33 | } | 97 | } |
34 | return 0; | 98 | |
99 | if (cpuid_topo->socket_id == -1) | ||
100 | cpuid_topo->socket_id = max_socket + 1; | ||
101 | |||
102 | update_siblings_masks(cpuid); | ||
103 | |||
104 | pr_info("CPU%u: thread %d, cpu %d, socket %d\n", | ||
105 | cpuid, cpu_topology[cpuid].thread_id, | ||
106 | cpu_topology[cpuid].core_id, | ||
107 | cpu_topology[cpuid].socket_id); | ||
35 | } | 108 | } |
36 | 109 | ||
37 | subsys_initcall(topology_init); | 110 | static struct sched_domain_topology_level parisc_mc_topology[] = { |
111 | #ifdef CONFIG_SCHED_MC | ||
112 | { cpu_coregroup_mask, cpu_core_flags, SD_INIT_NAME(MC) }, | ||
113 | #endif | ||
114 | |||
115 | { cpu_cpu_mask, SD_INIT_NAME(DIE) }, | ||
116 | { NULL, }, | ||
117 | }; | ||
118 | |||
119 | /* | ||
120 | * init_cpu_topology is called at boot when only one cpu is running | ||
121 | * which prevent simultaneous write access to cpu_topology array | ||
122 | */ | ||
123 | void __init init_cpu_topology(void) | ||
124 | { | ||
125 | unsigned int cpu; | ||
126 | |||
127 | /* init core mask and capacity */ | ||
128 | for_each_possible_cpu(cpu) { | ||
129 | struct cputopo_parisc *cpu_topo = &(cpu_topology[cpu]); | ||
130 | |||
131 | cpu_topo->thread_id = -1; | ||
132 | cpu_topo->core_id = -1; | ||
133 | cpu_topo->socket_id = -1; | ||
134 | cpumask_clear(&cpu_topo->core_sibling); | ||
135 | cpumask_clear(&cpu_topo->thread_sibling); | ||
136 | } | ||
137 | smp_wmb(); | ||
138 | |||
139 | /* Set scheduler topology descriptor */ | ||
140 | if (dualcores_found) | ||
141 | set_sched_topology(parisc_mc_topology); | ||
142 | } | ||