diff options
Diffstat (limited to 'arch/s390/kernel/smp.c')
-rw-r--r-- | arch/s390/kernel/smp.c | 91 |
1 files changed, 84 insertions, 7 deletions
diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c index 8f894d380a62..0dfa988c1b26 100644 --- a/arch/s390/kernel/smp.c +++ b/arch/s390/kernel/smp.c | |||
@@ -44,6 +44,7 @@ | |||
44 | #include <asm/lowcore.h> | 44 | #include <asm/lowcore.h> |
45 | #include <asm/sclp.h> | 45 | #include <asm/sclp.h> |
46 | #include <asm/cpu.h> | 46 | #include <asm/cpu.h> |
47 | #include "entry.h" | ||
47 | 48 | ||
48 | /* | 49 | /* |
49 | * An array with a pointer the lowcore of every CPU. | 50 | * An array with a pointer the lowcore of every CPU. |
@@ -67,13 +68,12 @@ enum s390_cpu_state { | |||
67 | CPU_STATE_CONFIGURED, | 68 | CPU_STATE_CONFIGURED, |
68 | }; | 69 | }; |
69 | 70 | ||
70 | #ifdef CONFIG_HOTPLUG_CPU | 71 | DEFINE_MUTEX(smp_cpu_state_mutex); |
71 | static DEFINE_MUTEX(smp_cpu_state_mutex); | 72 | int smp_cpu_polarization[NR_CPUS]; |
72 | #endif | ||
73 | static int smp_cpu_state[NR_CPUS]; | 73 | static int smp_cpu_state[NR_CPUS]; |
74 | static int cpu_management; | ||
74 | 75 | ||
75 | static DEFINE_PER_CPU(struct cpu, cpu_devices); | 76 | static DEFINE_PER_CPU(struct cpu, cpu_devices); |
76 | DEFINE_PER_CPU(struct s390_idle_data, s390_idle); | ||
77 | 77 | ||
78 | static void smp_ext_bitcall(int, ec_bit_sig); | 78 | static void smp_ext_bitcall(int, ec_bit_sig); |
79 | 79 | ||
@@ -298,7 +298,7 @@ static void smp_ext_bitcall(int cpu, ec_bit_sig sig) | |||
298 | /* | 298 | /* |
299 | * this function sends a 'purge tlb' signal to another CPU. | 299 | * this function sends a 'purge tlb' signal to another CPU. |
300 | */ | 300 | */ |
301 | void smp_ptlb_callback(void *info) | 301 | static void smp_ptlb_callback(void *info) |
302 | { | 302 | { |
303 | __tlb_flush_local(); | 303 | __tlb_flush_local(); |
304 | } | 304 | } |
@@ -456,6 +456,7 @@ static int smp_rescan_cpus_sigp(cpumask_t avail) | |||
456 | if (cpu_known(cpu_id)) | 456 | if (cpu_known(cpu_id)) |
457 | continue; | 457 | continue; |
458 | __cpu_logical_map[logical_cpu] = cpu_id; | 458 | __cpu_logical_map[logical_cpu] = cpu_id; |
459 | smp_cpu_polarization[logical_cpu] = POLARIZATION_UNKNWN; | ||
459 | if (!cpu_stopped(logical_cpu)) | 460 | if (!cpu_stopped(logical_cpu)) |
460 | continue; | 461 | continue; |
461 | cpu_set(logical_cpu, cpu_present_map); | 462 | cpu_set(logical_cpu, cpu_present_map); |
@@ -489,6 +490,7 @@ static int smp_rescan_cpus_sclp(cpumask_t avail) | |||
489 | if (cpu_known(cpu_id)) | 490 | if (cpu_known(cpu_id)) |
490 | continue; | 491 | continue; |
491 | __cpu_logical_map[logical_cpu] = cpu_id; | 492 | __cpu_logical_map[logical_cpu] = cpu_id; |
493 | smp_cpu_polarization[logical_cpu] = POLARIZATION_UNKNWN; | ||
492 | cpu_set(logical_cpu, cpu_present_map); | 494 | cpu_set(logical_cpu, cpu_present_map); |
493 | if (cpu >= info->configured) | 495 | if (cpu >= info->configured) |
494 | smp_cpu_state[logical_cpu] = CPU_STATE_STANDBY; | 496 | smp_cpu_state[logical_cpu] = CPU_STATE_STANDBY; |
@@ -846,6 +848,7 @@ void __init smp_prepare_boot_cpu(void) | |||
846 | S390_lowcore.percpu_offset = __per_cpu_offset[0]; | 848 | S390_lowcore.percpu_offset = __per_cpu_offset[0]; |
847 | current_set[0] = current; | 849 | current_set[0] = current; |
848 | smp_cpu_state[0] = CPU_STATE_CONFIGURED; | 850 | smp_cpu_state[0] = CPU_STATE_CONFIGURED; |
851 | smp_cpu_polarization[0] = POLARIZATION_UNKNWN; | ||
849 | spin_lock_init(&(&__get_cpu_var(s390_idle))->lock); | 852 | spin_lock_init(&(&__get_cpu_var(s390_idle))->lock); |
850 | } | 853 | } |
851 | 854 | ||
@@ -897,15 +900,19 @@ static ssize_t cpu_configure_store(struct sys_device *dev, const char *buf, | |||
897 | case 0: | 900 | case 0: |
898 | if (smp_cpu_state[cpu] == CPU_STATE_CONFIGURED) { | 901 | if (smp_cpu_state[cpu] == CPU_STATE_CONFIGURED) { |
899 | rc = sclp_cpu_deconfigure(__cpu_logical_map[cpu]); | 902 | rc = sclp_cpu_deconfigure(__cpu_logical_map[cpu]); |
900 | if (!rc) | 903 | if (!rc) { |
901 | smp_cpu_state[cpu] = CPU_STATE_STANDBY; | 904 | smp_cpu_state[cpu] = CPU_STATE_STANDBY; |
905 | smp_cpu_polarization[cpu] = POLARIZATION_UNKNWN; | ||
906 | } | ||
902 | } | 907 | } |
903 | break; | 908 | break; |
904 | case 1: | 909 | case 1: |
905 | if (smp_cpu_state[cpu] == CPU_STATE_STANDBY) { | 910 | if (smp_cpu_state[cpu] == CPU_STATE_STANDBY) { |
906 | rc = sclp_cpu_configure(__cpu_logical_map[cpu]); | 911 | rc = sclp_cpu_configure(__cpu_logical_map[cpu]); |
907 | if (!rc) | 912 | if (!rc) { |
908 | smp_cpu_state[cpu] = CPU_STATE_CONFIGURED; | 913 | smp_cpu_state[cpu] = CPU_STATE_CONFIGURED; |
914 | smp_cpu_polarization[cpu] = POLARIZATION_UNKNWN; | ||
915 | } | ||
909 | } | 916 | } |
910 | break; | 917 | break; |
911 | default: | 918 | default: |
@@ -919,6 +926,34 @@ out: | |||
919 | static SYSDEV_ATTR(configure, 0644, cpu_configure_show, cpu_configure_store); | 926 | static SYSDEV_ATTR(configure, 0644, cpu_configure_show, cpu_configure_store); |
920 | #endif /* CONFIG_HOTPLUG_CPU */ | 927 | #endif /* CONFIG_HOTPLUG_CPU */ |
921 | 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 | |||
922 | 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) |
923 | { | 958 | { |
924 | return sprintf(buf, "%d\n", __cpu_logical_map[dev->id]); | 959 | return sprintf(buf, "%d\n", __cpu_logical_map[dev->id]); |
@@ -931,6 +966,7 @@ static struct attribute *cpu_common_attrs[] = { | |||
931 | &attr_configure.attr, | 966 | &attr_configure.attr, |
932 | #endif | 967 | #endif |
933 | &attr_address.attr, | 968 | &attr_address.attr, |
969 | &attr_polarization.attr, | ||
934 | NULL, | 970 | NULL, |
935 | }; | 971 | }; |
936 | 972 | ||
@@ -1075,11 +1111,48 @@ static ssize_t __ref rescan_store(struct sys_device *dev, | |||
1075 | out: | 1111 | out: |
1076 | put_online_cpus(); | 1112 | put_online_cpus(); |
1077 | mutex_unlock(&smp_cpu_state_mutex); | 1113 | mutex_unlock(&smp_cpu_state_mutex); |
1114 | if (!cpus_empty(newcpus)) | ||
1115 | topology_schedule_update(); | ||
1078 | return rc ? rc : count; | 1116 | return rc ? rc : count; |
1079 | } | 1117 | } |
1080 | static SYSDEV_ATTR(rescan, 0200, NULL, rescan_store); | 1118 | static SYSDEV_ATTR(rescan, 0200, NULL, rescan_store); |
1081 | #endif /* CONFIG_HOTPLUG_CPU */ | 1119 | #endif /* CONFIG_HOTPLUG_CPU */ |
1082 | 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 | |||
1083 | static int __init topology_init(void) | 1156 | static int __init topology_init(void) |
1084 | { | 1157 | { |
1085 | int cpu; | 1158 | int cpu; |
@@ -1093,6 +1166,10 @@ static int __init topology_init(void) | |||
1093 | if (rc) | 1166 | if (rc) |
1094 | return rc; | 1167 | return rc; |
1095 | #endif | 1168 | #endif |
1169 | rc = sysfs_create_file(&cpu_sysdev_class.kset.kobj, | ||
1170 | &attr_dispatching.attr); | ||
1171 | if (rc) | ||
1172 | return rc; | ||
1096 | for_each_present_cpu(cpu) { | 1173 | for_each_present_cpu(cpu) { |
1097 | rc = smp_add_present_cpu(cpu); | 1174 | rc = smp_add_present_cpu(cpu); |
1098 | if (rc) | 1175 | if (rc) |