aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHelge Deller <deller@gmx.de>2017-09-21 15:55:01 -0400
committerHelge Deller <deller@gmx.de>2017-11-17 09:27:22 -0500
commitbf7b4c1b3c92f246a535a7c792177041d0442011 (patch)
tree1bd779b15d0c77656f99b79a1e8950910daf43cf
parent05f016d2ca7a4fab99d5d5472168506ddf95e74f (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/Kconfig16
-rw-r--r--arch/parisc/include/asm/topology.h36
-rw-r--r--arch/parisc/kernel/Makefile4
-rw-r--r--arch/parisc/kernel/processor.c13
-rw-r--r--arch/parisc/kernel/setup.c2
-rw-r--r--arch/parisc/kernel/topology.c153
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
292config 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
299config 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
291config IRQSTACKS 307config 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
8struct 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
16extern 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
23void init_cpu_topology(void);
24void store_cpu_topology(unsigned int cpuid);
25const struct cpumask *cpu_coregroup_mask(int cpu);
26
27#else
28
29static inline void init_cpu_topology(void) { }
30static 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
15ifdef CONFIG_FUNCTION_TRACER 14ifdef 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
30obj64-$(CONFIG_AUDIT) += compat_audit.o 29obj64-$(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
32obj-$(CONFIG_64BIT) += perf.o perf_asm.o $(obj64-y) 31obj-$(CONFIG_64BIT) += perf.o perf_asm.o $(obj64-y)
32obj-$(CONFIG_PARISC_CPU_TOPOLOGY) += topology.o
33obj-$(CONFIG_FUNCTION_TRACER) += ftrace.o 33obj-$(CONFIG_FUNCTION_TRACER) += ftrace.o
34obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o 34obj-$(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
25static DEFINE_PER_CPU(struct cpu, cpu_devices); 17#include <asm/topology.h>
26 18
27static int __init topology_init(void) 19 /*
20 * cpu topology table
21 */
22struct cputopo_parisc cpu_topology[NR_CPUS] __read_mostly;
23EXPORT_SYMBOL_GPL(cpu_topology);
24
25const struct cpumask *cpu_coregroup_mask(int cpu)
28{ 26{
29 int num; 27 return &cpu_topology[cpu].core_sibling;
28}
29
30static 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
56static 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 */
63void __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
37subsys_initcall(topology_init); 110static 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 */
123void __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}