Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

+200 -28
+16
arch/parisc/Kconfig
··· 32 32 select GENERIC_PCI_IOMAP 33 33 select ARCH_HAVE_NMI_SAFE_CMPXCHG 34 34 select GENERIC_SMP_IDLE_THREAD 35 + select GENERIC_CPU_DEVICES 35 36 select GENERIC_STRNCPY_FROM_USER 36 37 select SYSCTL_ARCH_UNALIGN_ALLOW 37 38 select SYSCTL_EXCEPTION_TRACE ··· 288 287 available at <http://www.tldp.org/docs.html#howto>. 289 288 290 289 If you don't know what to do here, say N. 290 + 291 + config PARISC_CPU_TOPOLOGY 292 + bool "Support cpu topology definition" 293 + depends on SMP 294 + default y 295 + help 296 + Support PARISC cpu topology definition. 297 + 298 + config SCHED_MC 299 + bool "Multi-core scheduler support" 300 + depends on PARISC_CPU_TOPOLOGY && PA8X00 301 + help 302 + Multi-core scheduler support improves the CPU scheduler's decision 303 + making when dealing with multi-core CPU chips at a cost of slightly 304 + increased overhead in some places. If unsure say N here. 291 305 292 306 config IRQSTACKS 293 307 bool "Use separate kernel stacks when processing interrupts"
+36
arch/parisc/include/asm/topology.h
··· 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 */
+2 -2
arch/parisc/kernel/Makefile
··· 9 9 pa7300lc.o syscall.o entry.o sys_parisc.o firmware.o \ 10 10 ptrace.o hardware.o inventory.o drivers.o \ 11 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 \ 13 - topology.o 12 + process.o processor.o pdc_cons.o pdc_chassis.o unwind.o 14 13 15 14 ifdef CONFIG_FUNCTION_TRACER 16 15 # Do not profile debug and lowlevel utilities ··· 29 30 obj64-$(CONFIG_AUDIT) += compat_audit.o 30 31 # only supported for PCX-W/U in 64-bit mode at the moment 31 32 obj-$(CONFIG_64BIT) += perf.o perf_asm.o $(obj64-y) 33 + obj-$(CONFIG_PARISC_CPU_TOPOLOGY) += topology.o 32 34 obj-$(CONFIG_FUNCTION_TRACER) += ftrace.o 33 35 obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o
+13
arch/parisc/kernel/processor.c
··· 184 184 p->txn_addr = txn_addr; /* save CPU IRQ address */ 185 185 p->cpu_num = cpu_info.cpu_num; 186 186 p->cpu_loc = cpu_info.cpu_loc; 187 + 188 + store_cpu_topology(cpuid); 189 + 187 190 #ifdef CONFIG_SMP 188 191 /* 189 192 ** FIXME: review if any other initialization is clobbered ··· 328 325 set_firmware_width(); 329 326 ret = pdc_coproc_cfg(&coproc_cfg); 330 327 328 + store_cpu_topology(cpunum); 329 + 331 330 if(ret >= 0 && coproc_cfg.ccr_functional) { 332 331 mtctl(coproc_cfg.ccr_functional, 10); /* 10 == Coprocessor Control Reg */ 333 332 ··· 392 387 seq_printf(m, "cpu MHz\t\t: %d.%06d\n", 393 388 boot_cpu_data.cpu_hz / 1000000, 394 389 boot_cpu_data.cpu_hz % 1000000 ); 390 + 391 + #ifdef CONFIG_PARISC_CPU_TOPOLOGY 392 + seq_printf(m, "physical id\t: %d\n", 393 + topology_physical_package_id(cpu)); 394 + seq_printf(m, "siblings\t: %d\n", 395 + cpumask_weight(topology_core_cpumask(cpu))); 396 + seq_printf(m, "core id\t\t: %d\n", topology_core_id(cpu)); 397 + #endif 395 398 396 399 seq_printf(m, "capabilities\t:"); 397 400 if (boot_cpu_data.pdc.capabilities & PDC_MODEL_OS32)
+2
arch/parisc/kernel/setup.c
··· 408 408 409 409 cpunum = smp_processor_id(); 410 410 411 + init_cpu_topology(); 412 + 411 413 set_firmware_width_unlocked(); 412 414 413 415 ret = pdc_coproc_cfg_unlocked(&coproc_cfg);
+131 -26
arch/parisc/kernel/topology.c
··· 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 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. 4 + * Copyright (C) 2017 Helge Deller <deller@gmx.de> 8 5 * 9 - * This program is distributed in the hope that it will be useful, but 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. 6 + * based on arch/arm/kernel/topology.c 14 7 * 15 - * You should have received a copy of the GNU General Public License 16 - * along with this program; if not, write to the Free Software 17 - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 8 + * This file is subject to the terms and conditions of the GNU General Public 9 + * License. See the file "COPYING" in the main directory of this archive 10 + * for more details. 18 11 */ 19 12 20 - #include <linux/init.h> 21 - #include <linux/smp.h> 22 - #include <linux/cpu.h> 23 - #include <linux/cache.h> 13 + #include <linux/percpu.h> 14 + #include <linux/sched.h> 15 + #include <linux/sched/topology.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; 30 - 31 - for_each_present_cpu(num) { 32 - register_cpu(&per_cpu(cpu_devices, num), num); 33 - } 34 - return 0; 27 + return &cpu_topology[cpu].core_sibling; 35 28 } 36 29 37 - subsys_initcall(topology_init); 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; 73 + 74 + /* create cpu topology mapping */ 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); 97 + } 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); 108 + } 109 + 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 + }