diff options
author | Glenn Elliott <gelliott@cs.unc.edu> | 2012-03-04 19:47:13 -0500 |
---|---|---|
committer | Glenn Elliott <gelliott@cs.unc.edu> | 2012-03-04 19:47:13 -0500 |
commit | c71c03bda1e86c9d5198c5d83f712e695c4f2a1e (patch) | |
tree | ecb166cb3e2b7e2adb3b5e292245fefd23381ac8 /arch/s390/kernel/topology.c | |
parent | ea53c912f8a86a8567697115b6a0d8152beee5c8 (diff) | |
parent | 6a00f206debf8a5c8899055726ad127dbeeed098 (diff) |
Merge branch 'mpi-master' into wip-k-fmlpwip-k-fmlp
Conflicts:
litmus/sched_cedf.c
Diffstat (limited to 'arch/s390/kernel/topology.c')
-rw-r--r-- | arch/s390/kernel/topology.c | 250 |
1 files changed, 123 insertions, 127 deletions
diff --git a/arch/s390/kernel/topology.c b/arch/s390/kernel/topology.c index bcef00766a64..0cd340b72632 100644 --- a/arch/s390/kernel/topology.c +++ b/arch/s390/kernel/topology.c | |||
@@ -17,159 +17,140 @@ | |||
17 | #include <linux/smp.h> | 17 | #include <linux/smp.h> |
18 | #include <linux/cpuset.h> | 18 | #include <linux/cpuset.h> |
19 | #include <asm/delay.h> | 19 | #include <asm/delay.h> |
20 | #include <asm/s390_ext.h> | ||
21 | #include <asm/sysinfo.h> | ||
22 | |||
23 | #define CPU_BITS 64 | ||
24 | #define NR_MAG 6 | ||
25 | 20 | ||
26 | #define PTF_HORIZONTAL (0UL) | 21 | #define PTF_HORIZONTAL (0UL) |
27 | #define PTF_VERTICAL (1UL) | 22 | #define PTF_VERTICAL (1UL) |
28 | #define PTF_CHECK (2UL) | 23 | #define PTF_CHECK (2UL) |
29 | 24 | ||
30 | struct tl_cpu { | 25 | struct mask_info { |
31 | unsigned char reserved0[4]; | 26 | struct mask_info *next; |
32 | unsigned char :6; | ||
33 | unsigned char pp:2; | ||
34 | unsigned char reserved1; | ||
35 | unsigned short origin; | ||
36 | unsigned long mask[CPU_BITS / BITS_PER_LONG]; | ||
37 | }; | ||
38 | |||
39 | struct tl_container { | ||
40 | unsigned char reserved[7]; | ||
41 | unsigned char id; | ||
42 | }; | ||
43 | |||
44 | union tl_entry { | ||
45 | unsigned char nl; | ||
46 | struct tl_cpu cpu; | ||
47 | struct tl_container container; | ||
48 | }; | ||
49 | |||
50 | struct tl_info { | ||
51 | unsigned char reserved0[2]; | ||
52 | unsigned short length; | ||
53 | unsigned char mag[NR_MAG]; | ||
54 | unsigned char reserved1; | ||
55 | unsigned char mnest; | ||
56 | unsigned char reserved2[4]; | ||
57 | union tl_entry tle[0]; | ||
58 | }; | ||
59 | |||
60 | struct core_info { | ||
61 | struct core_info *next; | ||
62 | unsigned char id; | 27 | unsigned char id; |
63 | cpumask_t mask; | 28 | cpumask_t mask; |
64 | }; | 29 | }; |
65 | 30 | ||
66 | static int topology_enabled; | 31 | static int topology_enabled = 1; |
67 | static void topology_work_fn(struct work_struct *work); | 32 | static void topology_work_fn(struct work_struct *work); |
68 | static struct tl_info *tl_info; | 33 | static struct sysinfo_15_1_x *tl_info; |
69 | static struct core_info core_info; | ||
70 | static int machine_has_topology; | ||
71 | static struct timer_list topology_timer; | 34 | static struct timer_list topology_timer; |
72 | static void set_topology_timer(void); | 35 | static void set_topology_timer(void); |
73 | static DECLARE_WORK(topology_work, topology_work_fn); | 36 | static DECLARE_WORK(topology_work, topology_work_fn); |
74 | /* topology_lock protects the core linked list */ | 37 | /* topology_lock protects the core linked list */ |
75 | static DEFINE_SPINLOCK(topology_lock); | 38 | static DEFINE_SPINLOCK(topology_lock); |
76 | 39 | ||
40 | static struct mask_info core_info; | ||
77 | cpumask_t cpu_core_map[NR_CPUS]; | 41 | cpumask_t cpu_core_map[NR_CPUS]; |
78 | unsigned char cpu_core_id[NR_CPUS]; | 42 | unsigned char cpu_core_id[NR_CPUS]; |
79 | 43 | ||
80 | static cpumask_t cpu_coregroup_map(unsigned int cpu) | 44 | #ifdef CONFIG_SCHED_BOOK |
45 | static struct mask_info book_info; | ||
46 | cpumask_t cpu_book_map[NR_CPUS]; | ||
47 | unsigned char cpu_book_id[NR_CPUS]; | ||
48 | #endif | ||
49 | |||
50 | static cpumask_t cpu_group_map(struct mask_info *info, unsigned int cpu) | ||
81 | { | 51 | { |
82 | struct core_info *core = &core_info; | ||
83 | unsigned long flags; | ||
84 | cpumask_t mask; | 52 | cpumask_t mask; |
85 | 53 | ||
86 | cpus_clear(mask); | 54 | cpumask_clear(&mask); |
87 | if (!topology_enabled || !machine_has_topology) | 55 | if (!topology_enabled || !MACHINE_HAS_TOPOLOGY) { |
88 | return cpu_possible_map; | 56 | cpumask_copy(&mask, cpumask_of(cpu)); |
89 | spin_lock_irqsave(&topology_lock, flags); | 57 | return mask; |
90 | while (core) { | 58 | } |
91 | if (cpu_isset(cpu, core->mask)) { | 59 | while (info) { |
92 | mask = core->mask; | 60 | if (cpumask_test_cpu(cpu, &info->mask)) { |
61 | mask = info->mask; | ||
93 | break; | 62 | break; |
94 | } | 63 | } |
95 | core = core->next; | 64 | info = info->next; |
96 | } | 65 | } |
97 | spin_unlock_irqrestore(&topology_lock, flags); | 66 | if (cpumask_empty(&mask)) |
98 | if (cpus_empty(mask)) | 67 | cpumask_copy(&mask, cpumask_of(cpu)); |
99 | mask = cpumask_of_cpu(cpu); | ||
100 | return mask; | 68 | return mask; |
101 | } | 69 | } |
102 | 70 | ||
103 | const struct cpumask *cpu_coregroup_mask(unsigned int cpu) | 71 | static void add_cpus_to_mask(struct topology_cpu *tl_cpu, |
104 | { | 72 | struct mask_info *book, struct mask_info *core) |
105 | return &cpu_core_map[cpu]; | ||
106 | } | ||
107 | |||
108 | static void add_cpus_to_core(struct tl_cpu *tl_cpu, struct core_info *core) | ||
109 | { | 73 | { |
110 | unsigned int cpu; | 74 | unsigned int cpu; |
111 | 75 | ||
112 | for (cpu = find_first_bit(&tl_cpu->mask[0], CPU_BITS); | 76 | for (cpu = find_first_bit(&tl_cpu->mask[0], TOPOLOGY_CPU_BITS); |
113 | cpu < CPU_BITS; | 77 | cpu < TOPOLOGY_CPU_BITS; |
114 | cpu = find_next_bit(&tl_cpu->mask[0], CPU_BITS, cpu + 1)) | 78 | cpu = find_next_bit(&tl_cpu->mask[0], TOPOLOGY_CPU_BITS, cpu + 1)) |
115 | { | 79 | { |
116 | unsigned int rcpu, lcpu; | 80 | unsigned int rcpu, lcpu; |
117 | 81 | ||
118 | rcpu = CPU_BITS - 1 - cpu + tl_cpu->origin; | 82 | rcpu = TOPOLOGY_CPU_BITS - 1 - cpu + tl_cpu->origin; |
119 | for_each_present_cpu(lcpu) { | 83 | for_each_present_cpu(lcpu) { |
120 | if (cpu_logical_map(lcpu) == rcpu) { | 84 | if (cpu_logical_map(lcpu) != rcpu) |
121 | cpu_set(lcpu, core->mask); | 85 | continue; |
122 | cpu_core_id[lcpu] = core->id; | 86 | #ifdef CONFIG_SCHED_BOOK |
123 | smp_cpu_polarization[lcpu] = tl_cpu->pp; | 87 | cpumask_set_cpu(lcpu, &book->mask); |
124 | } | 88 | cpu_book_id[lcpu] = book->id; |
89 | #endif | ||
90 | cpumask_set_cpu(lcpu, &core->mask); | ||
91 | cpu_core_id[lcpu] = core->id; | ||
92 | smp_cpu_polarization[lcpu] = tl_cpu->pp; | ||
125 | } | 93 | } |
126 | } | 94 | } |
127 | } | 95 | } |
128 | 96 | ||
129 | static void clear_cores(void) | 97 | static void clear_masks(void) |
130 | { | 98 | { |
131 | struct core_info *core = &core_info; | 99 | struct mask_info *info; |
132 | 100 | ||
133 | while (core) { | 101 | info = &core_info; |
134 | cpus_clear(core->mask); | 102 | while (info) { |
135 | core = core->next; | 103 | cpumask_clear(&info->mask); |
104 | info = info->next; | ||
136 | } | 105 | } |
106 | #ifdef CONFIG_SCHED_BOOK | ||
107 | info = &book_info; | ||
108 | while (info) { | ||
109 | cpumask_clear(&info->mask); | ||
110 | info = info->next; | ||
111 | } | ||
112 | #endif | ||
137 | } | 113 | } |
138 | 114 | ||
139 | static union tl_entry *next_tle(union tl_entry *tle) | 115 | static union topology_entry *next_tle(union topology_entry *tle) |
140 | { | 116 | { |
141 | if (tle->nl) | 117 | if (!tle->nl) |
142 | return (union tl_entry *)((struct tl_container *)tle + 1); | 118 | return (union topology_entry *)((struct topology_cpu *)tle + 1); |
143 | else | 119 | return (union topology_entry *)((struct topology_container *)tle + 1); |
144 | return (union tl_entry *)((struct tl_cpu *)tle + 1); | ||
145 | } | 120 | } |
146 | 121 | ||
147 | static void tl_to_cores(struct tl_info *info) | 122 | static void tl_to_cores(struct sysinfo_15_1_x *info) |
148 | { | 123 | { |
149 | union tl_entry *tle, *end; | 124 | #ifdef CONFIG_SCHED_BOOK |
150 | struct core_info *core = &core_info; | 125 | struct mask_info *book = &book_info; |
126 | #else | ||
127 | struct mask_info *book = NULL; | ||
128 | #endif | ||
129 | struct mask_info *core = &core_info; | ||
130 | union topology_entry *tle, *end; | ||
131 | |||
151 | 132 | ||
152 | spin_lock_irq(&topology_lock); | 133 | spin_lock_irq(&topology_lock); |
153 | clear_cores(); | 134 | clear_masks(); |
154 | tle = info->tle; | 135 | tle = info->tle; |
155 | end = (union tl_entry *)((unsigned long)info + info->length); | 136 | end = (union topology_entry *)((unsigned long)info + info->length); |
156 | while (tle < end) { | 137 | while (tle < end) { |
157 | switch (tle->nl) { | 138 | switch (tle->nl) { |
158 | case 5: | 139 | #ifdef CONFIG_SCHED_BOOK |
159 | case 4: | ||
160 | case 3: | ||
161 | case 2: | 140 | case 2: |
141 | book = book->next; | ||
142 | book->id = tle->container.id; | ||
162 | break; | 143 | break; |
144 | #endif | ||
163 | case 1: | 145 | case 1: |
164 | core = core->next; | 146 | core = core->next; |
165 | core->id = tle->container.id; | 147 | core->id = tle->container.id; |
166 | break; | 148 | break; |
167 | case 0: | 149 | case 0: |
168 | add_cpus_to_core(&tle->cpu, core); | 150 | add_cpus_to_mask(&tle->cpu, book, core); |
169 | break; | 151 | break; |
170 | default: | 152 | default: |
171 | clear_cores(); | 153 | clear_masks(); |
172 | machine_has_topology = 0; | ||
173 | goto out; | 154 | goto out; |
174 | } | 155 | } |
175 | tle = next_tle(tle); | 156 | tle = next_tle(tle); |
@@ -206,7 +187,7 @@ int topology_set_cpu_management(int fc) | |||
206 | int cpu; | 187 | int cpu; |
207 | int rc; | 188 | int rc; |
208 | 189 | ||
209 | if (!machine_has_topology) | 190 | if (!MACHINE_HAS_TOPOLOGY) |
210 | return -EOPNOTSUPP; | 191 | return -EOPNOTSUPP; |
211 | if (fc) | 192 | if (fc) |
212 | rc = ptf(PTF_VERTICAL); | 193 | rc = ptf(PTF_VERTICAL); |
@@ -221,24 +202,43 @@ int topology_set_cpu_management(int fc) | |||
221 | 202 | ||
222 | static void update_cpu_core_map(void) | 203 | static void update_cpu_core_map(void) |
223 | { | 204 | { |
205 | unsigned long flags; | ||
224 | int cpu; | 206 | int cpu; |
225 | 207 | ||
226 | for_each_possible_cpu(cpu) | 208 | spin_lock_irqsave(&topology_lock, flags); |
227 | cpu_core_map[cpu] = cpu_coregroup_map(cpu); | 209 | for_each_possible_cpu(cpu) { |
210 | cpu_core_map[cpu] = cpu_group_map(&core_info, cpu); | ||
211 | #ifdef CONFIG_SCHED_BOOK | ||
212 | cpu_book_map[cpu] = cpu_group_map(&book_info, cpu); | ||
213 | #endif | ||
214 | } | ||
215 | spin_unlock_irqrestore(&topology_lock, flags); | ||
216 | } | ||
217 | |||
218 | void store_topology(struct sysinfo_15_1_x *info) | ||
219 | { | ||
220 | #ifdef CONFIG_SCHED_BOOK | ||
221 | int rc; | ||
222 | |||
223 | rc = stsi(info, 15, 1, 3); | ||
224 | if (rc != -ENOSYS) | ||
225 | return; | ||
226 | #endif | ||
227 | stsi(info, 15, 1, 2); | ||
228 | } | 228 | } |
229 | 229 | ||
230 | int arch_update_cpu_topology(void) | 230 | int arch_update_cpu_topology(void) |
231 | { | 231 | { |
232 | struct tl_info *info = tl_info; | 232 | struct sysinfo_15_1_x *info = tl_info; |
233 | struct sys_device *sysdev; | 233 | struct sys_device *sysdev; |
234 | int cpu; | 234 | int cpu; |
235 | 235 | ||
236 | if (!machine_has_topology) { | 236 | if (!MACHINE_HAS_TOPOLOGY) { |
237 | update_cpu_core_map(); | 237 | update_cpu_core_map(); |
238 | topology_update_polarization_simple(); | 238 | topology_update_polarization_simple(); |
239 | return 0; | 239 | return 0; |
240 | } | 240 | } |
241 | stsi(info, 15, 1, 2); | 241 | store_topology(info); |
242 | tl_to_cores(info); | 242 | tl_to_cores(info); |
243 | update_cpu_core_map(); | 243 | update_cpu_core_map(); |
244 | for_each_online_cpu(cpu) { | 244 | for_each_online_cpu(cpu) { |
@@ -275,9 +275,9 @@ static void set_topology_timer(void) | |||
275 | 275 | ||
276 | static int __init early_parse_topology(char *p) | 276 | static int __init early_parse_topology(char *p) |
277 | { | 277 | { |
278 | if (strncmp(p, "on", 2)) | 278 | if (strncmp(p, "off", 3)) |
279 | return 0; | 279 | return 0; |
280 | topology_enabled = 1; | 280 | topology_enabled = 0; |
281 | return 0; | 281 | return 0; |
282 | } | 282 | } |
283 | early_param("topology", early_parse_topology); | 283 | early_param("topology", early_parse_topology); |
@@ -287,7 +287,7 @@ static int __init init_topology_update(void) | |||
287 | int rc; | 287 | int rc; |
288 | 288 | ||
289 | rc = 0; | 289 | rc = 0; |
290 | if (!machine_has_topology) { | 290 | if (!MACHINE_HAS_TOPOLOGY) { |
291 | topology_update_polarization_simple(); | 291 | topology_update_polarization_simple(); |
292 | goto out; | 292 | goto out; |
293 | } | 293 | } |
@@ -299,41 +299,37 @@ out: | |||
299 | } | 299 | } |
300 | __initcall(init_topology_update); | 300 | __initcall(init_topology_update); |
301 | 301 | ||
302 | static void alloc_masks(struct sysinfo_15_1_x *info, struct mask_info *mask, | ||
303 | int offset) | ||
304 | { | ||
305 | int i, nr_masks; | ||
306 | |||
307 | nr_masks = info->mag[TOPOLOGY_NR_MAG - offset]; | ||
308 | for (i = 0; i < info->mnest - offset; i++) | ||
309 | nr_masks *= info->mag[TOPOLOGY_NR_MAG - offset - 1 - i]; | ||
310 | nr_masks = max(nr_masks, 1); | ||
311 | for (i = 0; i < nr_masks; i++) { | ||
312 | mask->next = alloc_bootmem(sizeof(struct mask_info)); | ||
313 | mask = mask->next; | ||
314 | } | ||
315 | } | ||
316 | |||
302 | void __init s390_init_cpu_topology(void) | 317 | void __init s390_init_cpu_topology(void) |
303 | { | 318 | { |
304 | unsigned long long facility_bits; | 319 | struct sysinfo_15_1_x *info; |
305 | struct tl_info *info; | ||
306 | struct core_info *core; | ||
307 | int nr_cores; | ||
308 | int i; | 320 | int i; |
309 | 321 | ||
310 | if (stfle(&facility_bits, 1) <= 0) | 322 | if (!MACHINE_HAS_TOPOLOGY) |
311 | return; | ||
312 | if (!(facility_bits & (1ULL << 52)) || !(facility_bits & (1ULL << 61))) | ||
313 | return; | 323 | return; |
314 | machine_has_topology = 1; | ||
315 | |||
316 | tl_info = alloc_bootmem_pages(PAGE_SIZE); | 324 | tl_info = alloc_bootmem_pages(PAGE_SIZE); |
317 | info = tl_info; | 325 | info = tl_info; |
318 | stsi(info, 15, 1, 2); | 326 | store_topology(info); |
319 | |||
320 | nr_cores = info->mag[NR_MAG - 2]; | ||
321 | for (i = 0; i < info->mnest - 2; i++) | ||
322 | nr_cores *= info->mag[NR_MAG - 3 - i]; | ||
323 | |||
324 | pr_info("The CPU configuration topology of the machine is:"); | 327 | pr_info("The CPU configuration topology of the machine is:"); |
325 | for (i = 0; i < NR_MAG; i++) | 328 | for (i = 0; i < TOPOLOGY_NR_MAG; i++) |
326 | printk(" %d", info->mag[i]); | 329 | printk(" %d", info->mag[i]); |
327 | printk(" / %d\n", info->mnest); | 330 | printk(" / %d\n", info->mnest); |
328 | 331 | alloc_masks(info, &core_info, 2); | |
329 | core = &core_info; | 332 | #ifdef CONFIG_SCHED_BOOK |
330 | for (i = 0; i < nr_cores; i++) { | 333 | alloc_masks(info, &book_info, 3); |
331 | core->next = alloc_bootmem(sizeof(struct core_info)); | 334 | #endif |
332 | core = core->next; | ||
333 | if (!core) | ||
334 | goto error; | ||
335 | } | ||
336 | return; | ||
337 | error: | ||
338 | machine_has_topology = 0; | ||
339 | } | 335 | } |