aboutsummaryrefslogtreecommitdiffstats
path: root/arch/s390
diff options
context:
space:
mode:
authorHeiko Carstens <heiko.carstens@de.ibm.com>2008-04-17 01:46:12 -0400
committerHeiko Carstens <heiko.carstens@de.ibm.com>2008-04-17 01:47:01 -0400
commitdbd70fb499952d0ba282f0159dafacfc31d50313 (patch)
tree317ff61d9a98e61f233ac88950f7d9a3d3067965 /arch/s390
parent7b758389a29cb7f456ec2d27b7a08cb3cc4e1f1c (diff)
[S390] cpu topology support for s390.
Add s390 backend so we can give the scheduler some hints about the cpu topology. Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com> Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>
Diffstat (limited to 'arch/s390')
-rw-r--r--arch/s390/Kconfig4
-rw-r--r--arch/s390/defconfig1
-rw-r--r--arch/s390/kernel/Makefile2
-rw-r--r--arch/s390/kernel/setup.c2
-rw-r--r--arch/s390/kernel/smp.c4
-rw-r--r--arch/s390/kernel/topology.c272
6 files changed, 281 insertions, 4 deletions
diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig
index 1831833c430e..17cbc25c0c41 100644
--- a/arch/s390/Kconfig
+++ b/arch/s390/Kconfig
@@ -3,6 +3,10 @@
3# see Documentation/kbuild/kconfig-language.txt. 3# see Documentation/kbuild/kconfig-language.txt.
4# 4#
5 5
6config SCHED_MC
7 def_bool y
8 depends on SMP
9
6config MMU 10config MMU
7 def_bool y 11 def_bool y
8 12
diff --git a/arch/s390/defconfig b/arch/s390/defconfig
index 62f6b5a606dd..dcc3ec2ef643 100644
--- a/arch/s390/defconfig
+++ b/arch/s390/defconfig
@@ -3,6 +3,7 @@
3# Linux kernel version: 2.6.25-rc4 3# Linux kernel version: 2.6.25-rc4
4# Wed Mar 5 11:22:59 2008 4# Wed Mar 5 11:22:59 2008
5# 5#
6CONFIG_SCHED_MC=y
6CONFIG_MMU=y 7CONFIG_MMU=y
7CONFIG_ZONE_DMA=y 8CONFIG_ZONE_DMA=y
8CONFIG_LOCKDEP_SUPPORT=y 9CONFIG_LOCKDEP_SUPPORT=y
diff --git a/arch/s390/kernel/Makefile b/arch/s390/kernel/Makefile
index 4d3e38392cb1..ef2b2470c25c 100644
--- a/arch/s390/kernel/Makefile
+++ b/arch/s390/kernel/Makefile
@@ -19,7 +19,7 @@ obj-y += $(if $(CONFIG_64BIT),reipl64.o,reipl.o)
19extra-y += head.o init_task.o vmlinux.lds 19extra-y += head.o init_task.o vmlinux.lds
20 20
21obj-$(CONFIG_MODULES) += s390_ksyms.o module.o 21obj-$(CONFIG_MODULES) += s390_ksyms.o module.o
22obj-$(CONFIG_SMP) += smp.o 22obj-$(CONFIG_SMP) += smp.o topology.o
23 23
24obj-$(CONFIG_AUDIT) += audit.o 24obj-$(CONFIG_AUDIT) += audit.o
25compat-obj-$(CONFIG_AUDIT) += compat_audit.o 25compat-obj-$(CONFIG_AUDIT) += compat_audit.o
diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c
index d682ff135a1c..22040d087d8a 100644
--- a/arch/s390/kernel/setup.c
+++ b/arch/s390/kernel/setup.c
@@ -39,6 +39,7 @@
39#include <linux/pfn.h> 39#include <linux/pfn.h>
40#include <linux/ctype.h> 40#include <linux/ctype.h>
41#include <linux/reboot.h> 41#include <linux/reboot.h>
42#include <linux/topology.h>
42 43
43#include <asm/ipl.h> 44#include <asm/ipl.h>
44#include <asm/uaccess.h> 45#include <asm/uaccess.h>
@@ -830,6 +831,7 @@ setup_arch(char **cmdline_p)
830 831
831 cpu_init(); 832 cpu_init();
832 __cpu_logical_map[0] = S390_lowcore.cpu_data.cpu_addr; 833 __cpu_logical_map[0] = S390_lowcore.cpu_data.cpu_addr;
834 s390_init_cpu_topology();
833 835
834 /* 836 /*
835 * Setup capabilities (ELF_HWCAP & ELF_PLATFORM). 837 * Setup capabilities (ELF_HWCAP & ELF_PLATFORM).
diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c
index 8f894d380a62..5448aa87fa23 100644
--- a/arch/s390/kernel/smp.c
+++ b/arch/s390/kernel/smp.c
@@ -67,9 +67,7 @@ enum s390_cpu_state {
67 CPU_STATE_CONFIGURED, 67 CPU_STATE_CONFIGURED,
68}; 68};
69 69
70#ifdef CONFIG_HOTPLUG_CPU 70DEFINE_MUTEX(smp_cpu_state_mutex);
71static DEFINE_MUTEX(smp_cpu_state_mutex);
72#endif
73static int smp_cpu_state[NR_CPUS]; 71static int smp_cpu_state[NR_CPUS];
74 72
75static DEFINE_PER_CPU(struct cpu, cpu_devices); 73static DEFINE_PER_CPU(struct cpu, cpu_devices);
diff --git a/arch/s390/kernel/topology.c b/arch/s390/kernel/topology.c
new file mode 100644
index 000000000000..369dc1c3bd10
--- /dev/null
+++ b/arch/s390/kernel/topology.c
@@ -0,0 +1,272 @@
1/*
2 * arch/s390/kernel/topology.c
3 *
4 * Copyright IBM Corp. 2007
5 * Author(s): Heiko Carstens <heiko.carstens@de.ibm.com>
6 */
7
8#include <linux/kernel.h>
9#include <linux/mm.h>
10#include <linux/init.h>
11#include <linux/device.h>
12#include <linux/bootmem.h>
13#include <linux/sched.h>
14#include <linux/workqueue.h>
15#include <linux/cpu.h>
16#include <linux/smp.h>
17#include <asm/delay.h>
18#include <asm/s390_ext.h>
19#include <asm/sysinfo.h>
20
21#define CPU_BITS 64
22
23struct tl_cpu {
24 unsigned char reserved[6];
25 unsigned short origin;
26 unsigned long mask[CPU_BITS / BITS_PER_LONG];
27};
28
29struct tl_container {
30 unsigned char reserved[8];
31};
32
33union tl_entry {
34 unsigned char nl;
35 struct tl_cpu cpu;
36 struct tl_container container;
37};
38
39#define NR_MAG 6
40
41struct tl_info {
42 unsigned char reserved0[2];
43 unsigned short length;
44 unsigned char mag[NR_MAG];
45 unsigned char reserved1;
46 unsigned char mnest;
47 unsigned char reserved2[4];
48 union tl_entry tle[0];
49};
50
51struct core_info {
52 struct core_info *next;
53 cpumask_t mask;
54};
55
56static void topology_work_fn(struct work_struct *work);
57static struct tl_info *tl_info;
58static struct core_info core_info;
59static int machine_has_topology;
60static int machine_has_topology_irq;
61static struct timer_list topology_timer;
62static void set_topology_timer(void);
63static DECLARE_WORK(topology_work, topology_work_fn);
64
65cpumask_t cpu_coregroup_map(unsigned int cpu)
66{
67 struct core_info *core = &core_info;
68 cpumask_t mask;
69
70 cpus_clear(mask);
71 if (!machine_has_topology)
72 return cpu_present_map;
73 mutex_lock(&smp_cpu_state_mutex);
74 while (core) {
75 if (cpu_isset(cpu, core->mask)) {
76 mask = core->mask;
77 break;
78 }
79 core = core->next;
80 }
81 mutex_unlock(&smp_cpu_state_mutex);
82 if (cpus_empty(mask))
83 mask = cpumask_of_cpu(cpu);
84 return mask;
85}
86
87static void add_cpus_to_core(struct tl_cpu *tl_cpu, struct core_info *core)
88{
89 unsigned int cpu;
90
91 for (cpu = find_first_bit(&tl_cpu->mask[0], CPU_BITS);
92 cpu < CPU_BITS;
93 cpu = find_next_bit(&tl_cpu->mask[0], CPU_BITS, cpu + 1))
94 {
95 unsigned int rcpu, lcpu;
96
97 rcpu = CPU_BITS - 1 - cpu + tl_cpu->origin;
98 for_each_present_cpu(lcpu) {
99 if (__cpu_logical_map[lcpu] == rcpu)
100 cpu_set(lcpu, core->mask);
101 }
102 }
103}
104
105static void clear_cores(void)
106{
107 struct core_info *core = &core_info;
108
109 while (core) {
110 cpus_clear(core->mask);
111 core = core->next;
112 }
113}
114
115static union tl_entry *next_tle(union tl_entry *tle)
116{
117 if (tle->nl)
118 return (union tl_entry *)((struct tl_container *)tle + 1);
119 else
120 return (union tl_entry *)((struct tl_cpu *)tle + 1);
121}
122
123static void tl_to_cores(struct tl_info *info)
124{
125 union tl_entry *tle, *end;
126 struct core_info *core = &core_info;
127
128 mutex_lock(&smp_cpu_state_mutex);
129 clear_cores();
130 tle = (union tl_entry *)&info->tle;
131 end = (union tl_entry *)((unsigned long)info + info->length);
132 while (tle < end) {
133 switch (tle->nl) {
134 case 5:
135 case 4:
136 case 3:
137 case 2:
138 break;
139 case 1:
140 core = core->next;
141 break;
142 case 0:
143 add_cpus_to_core(&tle->cpu, core);
144 break;
145 default:
146 clear_cores();
147 machine_has_topology = 0;
148 return;
149 }
150 tle = next_tle(tle);
151 }
152 mutex_unlock(&smp_cpu_state_mutex);
153}
154
155static int ptf(void)
156{
157 int rc;
158
159 asm volatile(
160 " .insn rre,0xb9a20000,%1,%1\n"
161 " ipm %0\n"
162 " srl %0,28\n"
163 : "=d" (rc)
164 : "d" (2UL) : "cc");
165 return rc;
166}
167
168void arch_update_cpu_topology(void)
169{
170 struct tl_info *info = tl_info;
171 struct sys_device *sysdev;
172 int cpu;
173
174 if (!machine_has_topology)
175 return;
176 ptf();
177 stsi(info, 15, 1, 2);
178 tl_to_cores(info);
179 for_each_online_cpu(cpu) {
180 sysdev = get_cpu_sysdev(cpu);
181 kobject_uevent(&sysdev->kobj, KOBJ_CHANGE);
182 }
183}
184
185static void topology_work_fn(struct work_struct *work)
186{
187 arch_reinit_sched_domains();
188}
189
190static void topology_timer_fn(unsigned long ignored)
191{
192 if (ptf())
193 schedule_work(&topology_work);
194 set_topology_timer();
195}
196
197static void set_topology_timer(void)
198{
199 topology_timer.function = topology_timer_fn;
200 topology_timer.data = 0;
201 topology_timer.expires = jiffies + 60 * HZ;
202 add_timer(&topology_timer);
203}
204
205static void topology_interrupt(__u16 code)
206{
207 schedule_work(&topology_work);
208}
209
210static int __init init_topology_update(void)
211{
212 int rc;
213
214 if (!machine_has_topology)
215 return 0;
216 init_timer(&topology_timer);
217 if (machine_has_topology_irq) {
218 rc = register_external_interrupt(0x2005, topology_interrupt);
219 if (rc)
220 return rc;
221 ctl_set_bit(0, 8);
222 }
223 else
224 set_topology_timer();
225 return 0;
226}
227__initcall(init_topology_update);
228
229void __init s390_init_cpu_topology(void)
230{
231 unsigned long long facility_bits;
232 struct tl_info *info;
233 struct core_info *core;
234 int nr_cores;
235 int i;
236
237 if (stfle(&facility_bits, 1) <= 0)
238 return;
239 if (!(facility_bits & (1ULL << 52)) || !(facility_bits & (1ULL << 61)))
240 return;
241 machine_has_topology = 1;
242
243 if (facility_bits & (1ULL << 51))
244 machine_has_topology_irq = 1;
245
246 tl_info = alloc_bootmem_pages(PAGE_SIZE);
247 if (!tl_info)
248 goto error;
249 info = tl_info;
250 stsi(info, 15, 1, 2);
251
252 nr_cores = info->mag[NR_MAG - 2];
253 for (i = 0; i < info->mnest - 2; i++)
254 nr_cores *= info->mag[NR_MAG - 3 - i];
255
256 printk(KERN_INFO "CPU topology:");
257 for (i = 0; i < NR_MAG; i++)
258 printk(" %d", info->mag[i]);
259 printk(" / %d\n", info->mnest);
260
261 core = &core_info;
262 for (i = 0; i < nr_cores; i++) {
263 core->next = alloc_bootmem(sizeof(struct core_info));
264 core = core->next;
265 if (!core)
266 goto error;
267 }
268 return;
269error:
270 machine_has_topology = 0;
271 machine_has_topology_irq = 0;
272}