aboutsummaryrefslogtreecommitdiffstats
path: root/arch/s390/kernel/topology.c
diff options
context:
space:
mode:
authorHeiko Carstens <heiko.carstens@de.ibm.com>2008-04-17 01:46:13 -0400
committerHeiko Carstens <heiko.carstens@de.ibm.com>2008-04-17 01:47:01 -0400
commitc10fde0d9e2112c25052a8742e893ec5965c0007 (patch)
tree8d0e3ad337e44e9e06caabd5f0667f27e9ddaca3 /arch/s390/kernel/topology.c
parentdbd70fb499952d0ba282f0159dafacfc31d50313 (diff)
[S390] Vertical cpu management.
If vertical cpu polarization is active then the hypervisor will dispatch certain cpus for a longer time than other cpus for maximum performance. For example if a guest would have three virtual cpus, each of them with a share of 33 percent, then in case of vertical cpu polarization all of the processing time would be combined to a single cpu which would run all the time, while the other two cpus would get nearly no cpu time. There are three different types of vertical cpus: high, medium and low. Low cpus hardly get any real cpu time, while high cpus get a full real cpu. Medium cpus get something in between. In order to switch between the two possible modes (default is horizontal) a 0 for horizontal polarization or a 1 for vertical polarization must be written to the dispatching sysfs attribute: /sys/devices/system/cpu/dispatching The polarization of each single cpu can be figured out by the polarization sysfs attribute of each cpu: /sys/devices/system/cpu/cpuX/polarization horizontal, vertical:high, vertical:medium, vertical:low or unknown. When switching polarization the polarization attribute may contain the value unknown until the configuration change is done and the kernel has figured out the new polarization of each cpu. Note that running a system with different types of vertical cpus may result in significant performance regressions. If possible only one type of vertical cpus should be used. All other cpus should be offlined. Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com> Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>
Diffstat (limited to 'arch/s390/kernel/topology.c')
-rw-r--r--arch/s390/kernel/topology.c72
1 files changed, 57 insertions, 15 deletions
diff --git a/arch/s390/kernel/topology.c b/arch/s390/kernel/topology.c
index 369dc1c3bd10..12b39b3d9c38 100644
--- a/arch/s390/kernel/topology.c
+++ b/arch/s390/kernel/topology.c
@@ -1,6 +1,4 @@
1/* 1/*
2 * arch/s390/kernel/topology.c
3 *
4 * Copyright IBM Corp. 2007 2 * Copyright IBM Corp. 2007
5 * Author(s): Heiko Carstens <heiko.carstens@de.ibm.com> 3 * Author(s): Heiko Carstens <heiko.carstens@de.ibm.com>
6 */ 4 */
@@ -19,9 +17,17 @@
19#include <asm/sysinfo.h> 17#include <asm/sysinfo.h>
20 18
21#define CPU_BITS 64 19#define CPU_BITS 64
20#define NR_MAG 6
21
22#define PTF_HORIZONTAL (0UL)
23#define PTF_VERTICAL (1UL)
24#define PTF_CHECK (2UL)
22 25
23struct tl_cpu { 26struct tl_cpu {
24 unsigned char reserved[6]; 27 unsigned char reserved0[4];
28 unsigned char :6;
29 unsigned char pp:2;
30 unsigned char reserved1;
25 unsigned short origin; 31 unsigned short origin;
26 unsigned long mask[CPU_BITS / BITS_PER_LONG]; 32 unsigned long mask[CPU_BITS / BITS_PER_LONG];
27}; 33};
@@ -36,8 +42,6 @@ union tl_entry {
36 struct tl_container container; 42 struct tl_container container;
37}; 43};
38 44
39#define NR_MAG 6
40
41struct tl_info { 45struct tl_info {
42 unsigned char reserved0[2]; 46 unsigned char reserved0[2];
43 unsigned short length; 47 unsigned short length;
@@ -96,8 +100,10 @@ static void add_cpus_to_core(struct tl_cpu *tl_cpu, struct core_info *core)
96 100
97 rcpu = CPU_BITS - 1 - cpu + tl_cpu->origin; 101 rcpu = CPU_BITS - 1 - cpu + tl_cpu->origin;
98 for_each_present_cpu(lcpu) { 102 for_each_present_cpu(lcpu) {
99 if (__cpu_logical_map[lcpu] == rcpu) 103 if (__cpu_logical_map[lcpu] == rcpu) {
100 cpu_set(lcpu, core->mask); 104 cpu_set(lcpu, core->mask);
105 smp_cpu_polarization[lcpu] = tl_cpu->pp;
106 }
101 } 107 }
102 } 108 }
103} 109}
@@ -127,7 +133,7 @@ static void tl_to_cores(struct tl_info *info)
127 133
128 mutex_lock(&smp_cpu_state_mutex); 134 mutex_lock(&smp_cpu_state_mutex);
129 clear_cores(); 135 clear_cores();
130 tle = (union tl_entry *)&info->tle; 136 tle = info->tle;
131 end = (union tl_entry *)((unsigned long)info + info->length); 137 end = (union tl_entry *)((unsigned long)info + info->length);
132 while (tle < end) { 138 while (tle < end) {
133 switch (tle->nl) { 139 switch (tle->nl) {
@@ -152,7 +158,17 @@ static void tl_to_cores(struct tl_info *info)
152 mutex_unlock(&smp_cpu_state_mutex); 158 mutex_unlock(&smp_cpu_state_mutex);
153} 159}
154 160
155static int ptf(void) 161static void topology_update_polarization_simple(void)
162{
163 int cpu;
164
165 mutex_lock(&smp_cpu_state_mutex);
166 for_each_present_cpu(cpu)
167 smp_cpu_polarization[cpu] = POLARIZATION_HRZ;
168 mutex_unlock(&smp_cpu_state_mutex);
169}
170
171static int ptf(unsigned long fc)
156{ 172{
157 int rc; 173 int rc;
158 174
@@ -161,7 +177,25 @@ static int ptf(void)
161 " ipm %0\n" 177 " ipm %0\n"
162 " srl %0,28\n" 178 " srl %0,28\n"
163 : "=d" (rc) 179 : "=d" (rc)
164 : "d" (2UL) : "cc"); 180 : "d" (fc) : "cc");
181 return rc;
182}
183
184int topology_set_cpu_management(int fc)
185{
186 int cpu;
187 int rc;
188
189 if (!machine_has_topology)
190 return -EOPNOTSUPP;
191 if (fc)
192 rc = ptf(PTF_VERTICAL);
193 else
194 rc = ptf(PTF_HORIZONTAL);
195 if (rc)
196 return -EBUSY;
197 for_each_present_cpu(cpu)
198 smp_cpu_polarization[cpu] = POLARIZATION_UNKNWN;
165 return rc; 199 return rc;
166} 200}
167 201
@@ -171,9 +205,10 @@ void arch_update_cpu_topology(void)
171 struct sys_device *sysdev; 205 struct sys_device *sysdev;
172 int cpu; 206 int cpu;
173 207
174 if (!machine_has_topology) 208 if (!machine_has_topology) {
209 topology_update_polarization_simple();
175 return; 210 return;
176 ptf(); 211 }
177 stsi(info, 15, 1, 2); 212 stsi(info, 15, 1, 2);
178 tl_to_cores(info); 213 tl_to_cores(info);
179 for_each_online_cpu(cpu) { 214 for_each_online_cpu(cpu) {
@@ -187,10 +222,15 @@ static void topology_work_fn(struct work_struct *work)
187 arch_reinit_sched_domains(); 222 arch_reinit_sched_domains();
188} 223}
189 224
225void topology_schedule_update(void)
226{
227 schedule_work(&topology_work);
228}
229
190static void topology_timer_fn(unsigned long ignored) 230static void topology_timer_fn(unsigned long ignored)
191{ 231{
192 if (ptf()) 232 if (ptf(PTF_CHECK))
193 schedule_work(&topology_work); 233 topology_schedule_update();
194 set_topology_timer(); 234 set_topology_timer();
195} 235}
196 236
@@ -211,9 +251,11 @@ static int __init init_topology_update(void)
211{ 251{
212 int rc; 252 int rc;
213 253
214 if (!machine_has_topology) 254 if (!machine_has_topology) {
255 topology_update_polarization_simple();
215 return 0; 256 return 0;
216 init_timer(&topology_timer); 257 }
258 init_timer_deferrable(&topology_timer);
217 if (machine_has_topology_irq) { 259 if (machine_has_topology_irq) {
218 rc = register_external_interrupt(0x2005, topology_interrupt); 260 rc = register_external_interrupt(0x2005, topology_interrupt);
219 if (rc) 261 if (rc)