diff options
-rw-r--r-- | arch/s390/kernel/smp.c | 83 | ||||
-rw-r--r-- | arch/s390/kernel/topology.c | 72 | ||||
-rw-r--r-- | include/asm-s390/smp.h | 1 | ||||
-rw-r--r-- | include/asm-s390/topology.h | 9 |
4 files changed, 148 insertions, 17 deletions
diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c index 5448aa87fa23..d1e8e8a3fb66 100644 --- a/arch/s390/kernel/smp.c +++ b/arch/s390/kernel/smp.c | |||
@@ -68,7 +68,9 @@ enum s390_cpu_state { | |||
68 | }; | 68 | }; |
69 | 69 | ||
70 | DEFINE_MUTEX(smp_cpu_state_mutex); | 70 | DEFINE_MUTEX(smp_cpu_state_mutex); |
71 | int smp_cpu_polarization[NR_CPUS]; | ||
71 | static int smp_cpu_state[NR_CPUS]; | 72 | static int smp_cpu_state[NR_CPUS]; |
73 | static int cpu_management; | ||
72 | 74 | ||
73 | static DEFINE_PER_CPU(struct cpu, cpu_devices); | 75 | static DEFINE_PER_CPU(struct cpu, cpu_devices); |
74 | DEFINE_PER_CPU(struct s390_idle_data, s390_idle); | 76 | DEFINE_PER_CPU(struct s390_idle_data, s390_idle); |
@@ -454,6 +456,7 @@ static int smp_rescan_cpus_sigp(cpumask_t avail) | |||
454 | if (cpu_known(cpu_id)) | 456 | if (cpu_known(cpu_id)) |
455 | continue; | 457 | continue; |
456 | __cpu_logical_map[logical_cpu] = cpu_id; | 458 | __cpu_logical_map[logical_cpu] = cpu_id; |
459 | smp_cpu_polarization[logical_cpu] = POLARIZATION_UNKNWN; | ||
457 | if (!cpu_stopped(logical_cpu)) | 460 | if (!cpu_stopped(logical_cpu)) |
458 | continue; | 461 | continue; |
459 | cpu_set(logical_cpu, cpu_present_map); | 462 | cpu_set(logical_cpu, cpu_present_map); |
@@ -487,6 +490,7 @@ static int smp_rescan_cpus_sclp(cpumask_t avail) | |||
487 | if (cpu_known(cpu_id)) | 490 | if (cpu_known(cpu_id)) |
488 | continue; | 491 | continue; |
489 | __cpu_logical_map[logical_cpu] = cpu_id; | 492 | __cpu_logical_map[logical_cpu] = cpu_id; |
493 | smp_cpu_polarization[logical_cpu] = POLARIZATION_UNKNWN; | ||
490 | cpu_set(logical_cpu, cpu_present_map); | 494 | cpu_set(logical_cpu, cpu_present_map); |
491 | if (cpu >= info->configured) | 495 | if (cpu >= info->configured) |
492 | smp_cpu_state[logical_cpu] = CPU_STATE_STANDBY; | 496 | smp_cpu_state[logical_cpu] = CPU_STATE_STANDBY; |
@@ -844,6 +848,7 @@ void __init smp_prepare_boot_cpu(void) | |||
844 | S390_lowcore.percpu_offset = __per_cpu_offset[0]; | 848 | S390_lowcore.percpu_offset = __per_cpu_offset[0]; |
845 | current_set[0] = current; | 849 | current_set[0] = current; |
846 | smp_cpu_state[0] = CPU_STATE_CONFIGURED; | 850 | smp_cpu_state[0] = CPU_STATE_CONFIGURED; |
851 | smp_cpu_polarization[0] = POLARIZATION_UNKNWN; | ||
847 | spin_lock_init(&(&__get_cpu_var(s390_idle))->lock); | 852 | spin_lock_init(&(&__get_cpu_var(s390_idle))->lock); |
848 | } | 853 | } |
849 | 854 | ||
@@ -895,15 +900,19 @@ static ssize_t cpu_configure_store(struct sys_device *dev, const char *buf, | |||
895 | case 0: | 900 | case 0: |
896 | if (smp_cpu_state[cpu] == CPU_STATE_CONFIGURED) { | 901 | if (smp_cpu_state[cpu] == CPU_STATE_CONFIGURED) { |
897 | rc = sclp_cpu_deconfigure(__cpu_logical_map[cpu]); | 902 | rc = sclp_cpu_deconfigure(__cpu_logical_map[cpu]); |
898 | if (!rc) | 903 | if (!rc) { |
899 | smp_cpu_state[cpu] = CPU_STATE_STANDBY; | 904 | smp_cpu_state[cpu] = CPU_STATE_STANDBY; |
905 | smp_cpu_polarization[cpu] = POLARIZATION_UNKNWN; | ||
906 | } | ||
900 | } | 907 | } |
901 | break; | 908 | break; |
902 | case 1: | 909 | case 1: |
903 | if (smp_cpu_state[cpu] == CPU_STATE_STANDBY) { | 910 | if (smp_cpu_state[cpu] == CPU_STATE_STANDBY) { |
904 | rc = sclp_cpu_configure(__cpu_logical_map[cpu]); | 911 | rc = sclp_cpu_configure(__cpu_logical_map[cpu]); |
905 | if (!rc) | 912 | if (!rc) { |
906 | smp_cpu_state[cpu] = CPU_STATE_CONFIGURED; | 913 | smp_cpu_state[cpu] = CPU_STATE_CONFIGURED; |
914 | smp_cpu_polarization[cpu] = POLARIZATION_UNKNWN; | ||
915 | } | ||
907 | } | 916 | } |
908 | break; | 917 | break; |
909 | default: | 918 | default: |
@@ -917,6 +926,34 @@ out: | |||
917 | static SYSDEV_ATTR(configure, 0644, cpu_configure_show, cpu_configure_store); | 926 | static SYSDEV_ATTR(configure, 0644, cpu_configure_show, cpu_configure_store); |
918 | #endif /* CONFIG_HOTPLUG_CPU */ | 927 | #endif /* CONFIG_HOTPLUG_CPU */ |
919 | 928 | ||
929 | static ssize_t cpu_polarization_show(struct sys_device *dev, char *buf) | ||
930 | { | ||
931 | int cpu = dev->id; | ||
932 | ssize_t count; | ||
933 | |||
934 | mutex_lock(&smp_cpu_state_mutex); | ||
935 | switch (smp_cpu_polarization[cpu]) { | ||
936 | case POLARIZATION_HRZ: | ||
937 | count = sprintf(buf, "horizontal\n"); | ||
938 | break; | ||
939 | case POLARIZATION_VL: | ||
940 | count = sprintf(buf, "vertical:low\n"); | ||
941 | break; | ||
942 | case POLARIZATION_VM: | ||
943 | count = sprintf(buf, "vertical:medium\n"); | ||
944 | break; | ||
945 | case POLARIZATION_VH: | ||
946 | count = sprintf(buf, "vertical:high\n"); | ||
947 | break; | ||
948 | default: | ||
949 | count = sprintf(buf, "unknown\n"); | ||
950 | break; | ||
951 | } | ||
952 | mutex_unlock(&smp_cpu_state_mutex); | ||
953 | return count; | ||
954 | } | ||
955 | static SYSDEV_ATTR(polarization, 0444, cpu_polarization_show, NULL); | ||
956 | |||
920 | static ssize_t show_cpu_address(struct sys_device *dev, char *buf) | 957 | static ssize_t show_cpu_address(struct sys_device *dev, char *buf) |
921 | { | 958 | { |
922 | return sprintf(buf, "%d\n", __cpu_logical_map[dev->id]); | 959 | return sprintf(buf, "%d\n", __cpu_logical_map[dev->id]); |
@@ -929,6 +966,7 @@ static struct attribute *cpu_common_attrs[] = { | |||
929 | &attr_configure.attr, | 966 | &attr_configure.attr, |
930 | #endif | 967 | #endif |
931 | &attr_address.attr, | 968 | &attr_address.attr, |
969 | &attr_polarization.attr, | ||
932 | NULL, | 970 | NULL, |
933 | }; | 971 | }; |
934 | 972 | ||
@@ -1073,11 +1111,48 @@ static ssize_t __ref rescan_store(struct sys_device *dev, | |||
1073 | out: | 1111 | out: |
1074 | put_online_cpus(); | 1112 | put_online_cpus(); |
1075 | mutex_unlock(&smp_cpu_state_mutex); | 1113 | mutex_unlock(&smp_cpu_state_mutex); |
1114 | if (!cpus_empty(newcpus)) | ||
1115 | topology_schedule_update(); | ||
1076 | return rc ? rc : count; | 1116 | return rc ? rc : count; |
1077 | } | 1117 | } |
1078 | static SYSDEV_ATTR(rescan, 0200, NULL, rescan_store); | 1118 | static SYSDEV_ATTR(rescan, 0200, NULL, rescan_store); |
1079 | #endif /* CONFIG_HOTPLUG_CPU */ | 1119 | #endif /* CONFIG_HOTPLUG_CPU */ |
1080 | 1120 | ||
1121 | static ssize_t dispatching_show(struct sys_device *dev, char *buf) | ||
1122 | { | ||
1123 | ssize_t count; | ||
1124 | |||
1125 | mutex_lock(&smp_cpu_state_mutex); | ||
1126 | count = sprintf(buf, "%d\n", cpu_management); | ||
1127 | mutex_unlock(&smp_cpu_state_mutex); | ||
1128 | return count; | ||
1129 | } | ||
1130 | |||
1131 | static ssize_t dispatching_store(struct sys_device *dev, const char *buf, | ||
1132 | size_t count) | ||
1133 | { | ||
1134 | int val, rc; | ||
1135 | char delim; | ||
1136 | |||
1137 | if (sscanf(buf, "%d %c", &val, &delim) != 1) | ||
1138 | return -EINVAL; | ||
1139 | if (val != 0 && val != 1) | ||
1140 | return -EINVAL; | ||
1141 | rc = 0; | ||
1142 | mutex_lock(&smp_cpu_state_mutex); | ||
1143 | get_online_cpus(); | ||
1144 | if (cpu_management == val) | ||
1145 | goto out; | ||
1146 | rc = topology_set_cpu_management(val); | ||
1147 | if (!rc) | ||
1148 | cpu_management = val; | ||
1149 | out: | ||
1150 | put_online_cpus(); | ||
1151 | mutex_unlock(&smp_cpu_state_mutex); | ||
1152 | return rc ? rc : count; | ||
1153 | } | ||
1154 | static SYSDEV_ATTR(dispatching, 0644, dispatching_show, dispatching_store); | ||
1155 | |||
1081 | static int __init topology_init(void) | 1156 | static int __init topology_init(void) |
1082 | { | 1157 | { |
1083 | int cpu; | 1158 | int cpu; |
@@ -1091,6 +1166,10 @@ static int __init topology_init(void) | |||
1091 | if (rc) | 1166 | if (rc) |
1092 | return rc; | 1167 | return rc; |
1093 | #endif | 1168 | #endif |
1169 | rc = sysfs_create_file(&cpu_sysdev_class.kset.kobj, | ||
1170 | &attr_dispatching.attr); | ||
1171 | if (rc) | ||
1172 | return rc; | ||
1094 | for_each_present_cpu(cpu) { | 1173 | for_each_present_cpu(cpu) { |
1095 | rc = smp_add_present_cpu(cpu); | 1174 | rc = smp_add_present_cpu(cpu); |
1096 | if (rc) | 1175 | if (rc) |
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 | ||
23 | struct tl_cpu { | 26 | struct 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 | |||
41 | struct tl_info { | 45 | struct 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 | ||
155 | static int ptf(void) | 161 | static 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 | |||
171 | static 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 | |||
184 | int 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 | ||
225 | void topology_schedule_update(void) | ||
226 | { | ||
227 | schedule_work(&topology_work); | ||
228 | } | ||
229 | |||
190 | static void topology_timer_fn(unsigned long ignored) | 230 | static 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) |
diff --git a/include/asm-s390/smp.h b/include/asm-s390/smp.h index a464a66c65d3..6f3821a6a902 100644 --- a/include/asm-s390/smp.h +++ b/include/asm-s390/smp.h | |||
@@ -91,6 +91,7 @@ extern void cpu_die (void) __attribute__ ((noreturn)); | |||
91 | extern int __cpu_up (unsigned int cpu); | 91 | extern int __cpu_up (unsigned int cpu); |
92 | 92 | ||
93 | extern struct mutex smp_cpu_state_mutex; | 93 | extern struct mutex smp_cpu_state_mutex; |
94 | extern int smp_cpu_polarization[]; | ||
94 | 95 | ||
95 | extern int smp_call_function_mask(cpumask_t mask, void (*func)(void *), | 96 | extern int smp_call_function_mask(cpumask_t mask, void (*func)(void *), |
96 | void *info, int wait); | 97 | void *info, int wait); |
diff --git a/include/asm-s390/topology.h b/include/asm-s390/topology.h index 3b28a09a2108..8e97b06f298a 100644 --- a/include/asm-s390/topology.h +++ b/include/asm-s390/topology.h | |||
@@ -7,6 +7,15 @@ | |||
7 | 7 | ||
8 | cpumask_t cpu_coregroup_map(unsigned int cpu); | 8 | cpumask_t cpu_coregroup_map(unsigned int cpu); |
9 | 9 | ||
10 | int topology_set_cpu_management(int fc); | ||
11 | void topology_schedule_update(void); | ||
12 | |||
13 | #define POLARIZATION_UNKNWN (-1) | ||
14 | #define POLARIZATION_HRZ (0) | ||
15 | #define POLARIZATION_VL (1) | ||
16 | #define POLARIZATION_VM (2) | ||
17 | #define POLARIZATION_VH (3) | ||
18 | |||
10 | #ifdef CONFIG_SMP | 19 | #ifdef CONFIG_SMP |
11 | void s390_init_cpu_topology(void); | 20 | void s390_init_cpu_topology(void); |
12 | #else | 21 | #else |