aboutsummaryrefslogtreecommitdiffstats
path: root/arch/s390/kernel/sysinfo.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/s390/kernel/sysinfo.c')
-rw-r--r--arch/s390/kernel/sysinfo.c351
1 files changed, 165 insertions, 186 deletions
diff --git a/arch/s390/kernel/sysinfo.c b/arch/s390/kernel/sysinfo.c
index fa0eb238dac7..62f89d98e880 100644
--- a/arch/s390/kernel/sysinfo.c
+++ b/arch/s390/kernel/sysinfo.c
@@ -22,17 +22,41 @@
22#include <math-emu/soft-fp.h> 22#include <math-emu/soft-fp.h>
23#include <math-emu/single.h> 23#include <math-emu/single.h>
24 24
25static inline int stsi_0(void) 25int topology_max_mnest;
26
27/*
28 * stsi - store system information
29 *
30 * Returns the current configuration level if function code 0 was specified.
31 * Otherwise returns 0 on success or a negative value on error.
32 */
33int stsi(void *sysinfo, int fc, int sel1, int sel2)
26{ 34{
27 int rc = stsi(NULL, 0, 0, 0); 35 register int r0 asm("0") = (fc << 28) | sel1;
28 return rc == -ENOSYS ? rc : (((unsigned int) rc) >> 28); 36 register int r1 asm("1") = sel2;
37 int rc = 0;
38
39 asm volatile(
40 " stsi 0(%3)\n"
41 "0: jz 2f\n"
42 "1: lhi %1,%4\n"
43 "2:\n"
44 EX_TABLE(0b, 1b)
45 : "+d" (r0), "+d" (rc)
46 : "d" (r1), "a" (sysinfo), "K" (-EOPNOTSUPP)
47 : "cc", "memory");
48 if (rc)
49 return rc;
50 return fc ? 0 : ((unsigned int) r0) >> 28;
29} 51}
52EXPORT_SYMBOL(stsi);
30 53
31static int stsi_1_1_1(struct sysinfo_1_1_1 *info, char *page, int len) 54static void stsi_1_1_1(struct seq_file *m, struct sysinfo_1_1_1 *info)
32{ 55{
33 if (stsi(info, 1, 1, 1) == -ENOSYS) 56 int i;
34 return len;
35 57
58 if (stsi(info, 1, 1, 1))
59 return;
36 EBCASC(info->manufacturer, sizeof(info->manufacturer)); 60 EBCASC(info->manufacturer, sizeof(info->manufacturer));
37 EBCASC(info->type, sizeof(info->type)); 61 EBCASC(info->type, sizeof(info->type));
38 EBCASC(info->model, sizeof(info->model)); 62 EBCASC(info->model, sizeof(info->model));
@@ -41,242 +65,197 @@ static int stsi_1_1_1(struct sysinfo_1_1_1 *info, char *page, int len)
41 EBCASC(info->model_capacity, sizeof(info->model_capacity)); 65 EBCASC(info->model_capacity, sizeof(info->model_capacity));
42 EBCASC(info->model_perm_cap, sizeof(info->model_perm_cap)); 66 EBCASC(info->model_perm_cap, sizeof(info->model_perm_cap));
43 EBCASC(info->model_temp_cap, sizeof(info->model_temp_cap)); 67 EBCASC(info->model_temp_cap, sizeof(info->model_temp_cap));
44 len += sprintf(page + len, "Manufacturer: %-16.16s\n", 68 seq_printf(m, "Manufacturer: %-16.16s\n", info->manufacturer);
45 info->manufacturer); 69 seq_printf(m, "Type: %-4.4s\n", info->type);
46 len += sprintf(page + len, "Type: %-4.4s\n", 70 /*
47 info->type); 71 * Sigh: the model field has been renamed with System z9
72 * to model_capacity and a new model field has been added
73 * after the plant field. To avoid confusing older programs
74 * the "Model:" prints "model_capacity model" or just
75 * "model_capacity" if the model string is empty .
76 */
77 seq_printf(m, "Model: %-16.16s", info->model_capacity);
48 if (info->model[0] != '\0') 78 if (info->model[0] != '\0')
49 /* 79 seq_printf(m, " %-16.16s", info->model);
50 * Sigh: the model field has been renamed with System z9 80 seq_putc(m, '\n');
51 * to model_capacity and a new model field has been added 81 seq_printf(m, "Sequence Code: %-16.16s\n", info->sequence);
52 * after the plant field. To avoid confusing older programs 82 seq_printf(m, "Plant: %-4.4s\n", info->plant);
53 * the "Model:" prints "model_capacity model" or just 83 seq_printf(m, "Model Capacity: %-16.16s %08u\n",
54 * "model_capacity" if the model string is empty . 84 info->model_capacity, info->model_cap_rating);
55 */ 85 if (info->model_perm_cap_rating)
56 len += sprintf(page + len, 86 seq_printf(m, "Model Perm. Capacity: %-16.16s %08u\n",
57 "Model: %-16.16s %-16.16s\n", 87 info->model_perm_cap,
58 info->model_capacity, info->model); 88 info->model_perm_cap_rating);
59 else 89 if (info->model_temp_cap_rating)
60 len += sprintf(page + len, "Model: %-16.16s\n", 90 seq_printf(m, "Model Temp. Capacity: %-16.16s %08u\n",
61 info->model_capacity); 91 info->model_temp_cap,
62 len += sprintf(page + len, "Sequence Code: %-16.16s\n", 92 info->model_temp_cap_rating);
63 info->sequence); 93 if (info->ncr)
64 len += sprintf(page + len, "Plant: %-4.4s\n", 94 seq_printf(m, "Nominal Cap. Rating: %08u\n", info->ncr);
65 info->plant); 95 if (info->npr)
66 len += sprintf(page + len, "Model Capacity: %-16.16s %08u\n", 96 seq_printf(m, "Nominal Perm. Rating: %08u\n", info->npr);
67 info->model_capacity, *(u32 *) info->model_cap_rating); 97 if (info->ntr)
68 if (info->model_perm_cap[0] != '\0') 98 seq_printf(m, "Nominal Temp. Rating: %08u\n", info->ntr);
69 len += sprintf(page + len,
70 "Model Perm. Capacity: %-16.16s %08u\n",
71 info->model_perm_cap,
72 *(u32 *) info->model_perm_cap_rating);
73 if (info->model_temp_cap[0] != '\0')
74 len += sprintf(page + len,
75 "Model Temp. Capacity: %-16.16s %08u\n",
76 info->model_temp_cap,
77 *(u32 *) info->model_temp_cap_rating);
78 if (info->cai) { 99 if (info->cai) {
79 len += sprintf(page + len, 100 seq_printf(m, "Capacity Adj. Ind.: %d\n", info->cai);
80 "Capacity Adj. Ind.: %d\n", 101 seq_printf(m, "Capacity Ch. Reason: %d\n", info->ccr);
81 info->cai); 102 seq_printf(m, "Capacity Transient: %d\n", info->t);
82 len += sprintf(page + len, "Capacity Ch. Reason: %d\n", 103 }
83 info->ccr); 104 if (info->p) {
105 for (i = 1; i <= ARRAY_SIZE(info->typepct); i++) {
106 seq_printf(m, "Type %d Percentage: %d\n",
107 i, info->typepct[i - 1]);
108 }
84 } 109 }
85 return len;
86} 110}
87 111
88static int stsi_15_1_x(struct sysinfo_15_1_x *info, char *page, int len) 112static void stsi_15_1_x(struct seq_file *m, struct sysinfo_15_1_x *info)
89{ 113{
90 static int max_mnest; 114 static int max_mnest;
91 int i, rc; 115 int i, rc;
92 116
93 len += sprintf(page + len, "\n"); 117 seq_putc(m, '\n');
94 if (!MACHINE_HAS_TOPOLOGY) 118 if (!MACHINE_HAS_TOPOLOGY)
95 return len; 119 return;
96 if (max_mnest) { 120 if (stsi(info, 15, 1, topology_max_mnest))
97 stsi(info, 15, 1, max_mnest); 121 return;
98 } else { 122 seq_printf(m, "CPU Topology HW: ");
99 for (max_mnest = 6; max_mnest > 1; max_mnest--) {
100 rc = stsi(info, 15, 1, max_mnest);
101 if (rc != -ENOSYS)
102 break;
103 }
104 }
105 len += sprintf(page + len, "CPU Topology HW: ");
106 for (i = 0; i < TOPOLOGY_NR_MAG; i++) 123 for (i = 0; i < TOPOLOGY_NR_MAG; i++)
107 len += sprintf(page + len, " %d", info->mag[i]); 124 seq_printf(m, " %d", info->mag[i]);
108 len += sprintf(page + len, "\n"); 125 seq_putc(m, '\n');
109#ifdef CONFIG_SCHED_MC 126#ifdef CONFIG_SCHED_MC
110 store_topology(info); 127 store_topology(info);
111 len += sprintf(page + len, "CPU Topology SW: "); 128 seq_printf(m, "CPU Topology SW: ");
112 for (i = 0; i < TOPOLOGY_NR_MAG; i++) 129 for (i = 0; i < TOPOLOGY_NR_MAG; i++)
113 len += sprintf(page + len, " %d", info->mag[i]); 130 seq_printf(m, " %d", info->mag[i]);
114 len += sprintf(page + len, "\n"); 131 seq_putc(m, '\n');
115#endif 132#endif
116 return len;
117} 133}
118 134
119static int stsi_1_2_2(struct sysinfo_1_2_2 *info, char *page, int len) 135static void stsi_1_2_2(struct seq_file *m, struct sysinfo_1_2_2 *info)
120{ 136{
121 struct sysinfo_1_2_2_extension *ext; 137 struct sysinfo_1_2_2_extension *ext;
122 int i; 138 int i;
123 139
124 if (stsi(info, 1, 2, 2) == -ENOSYS) 140 if (stsi(info, 1, 2, 2))
125 return len; 141 return;
126 ext = (struct sysinfo_1_2_2_extension *) 142 ext = (struct sysinfo_1_2_2_extension *)
127 ((unsigned long) info + info->acc_offset); 143 ((unsigned long) info + info->acc_offset);
128 144 seq_printf(m, "CPUs Total: %d\n", info->cpus_total);
129 len += sprintf(page + len, "CPUs Total: %d\n", 145 seq_printf(m, "CPUs Configured: %d\n", info->cpus_configured);
130 info->cpus_total); 146 seq_printf(m, "CPUs Standby: %d\n", info->cpus_standby);
131 len += sprintf(page + len, "CPUs Configured: %d\n", 147 seq_printf(m, "CPUs Reserved: %d\n", info->cpus_reserved);
132 info->cpus_configured); 148 /*
133 len += sprintf(page + len, "CPUs Standby: %d\n", 149 * Sigh 2. According to the specification the alternate
134 info->cpus_standby); 150 * capability field is a 32 bit floating point number
135 len += sprintf(page + len, "CPUs Reserved: %d\n", 151 * if the higher order 8 bits are not zero. Printing
136 info->cpus_reserved); 152 * a floating point number in the kernel is a no-no,
137 153 * always print the number as 32 bit unsigned integer.
138 if (info->format == 1) { 154 * The user-space needs to know about the strange
139 /* 155 * encoding of the alternate cpu capability.
140 * Sigh 2. According to the specification the alternate 156 */
141 * capability field is a 32 bit floating point number 157 seq_printf(m, "Capability: %u", info->capability);
142 * if the higher order 8 bits are not zero. Printing 158 if (info->format == 1)
143 * a floating point number in the kernel is a no-no, 159 seq_printf(m, " %u", ext->alt_capability);
144 * always print the number as 32 bit unsigned integer. 160 seq_putc(m, '\n');
145 * The user-space needs to know about the strange 161 if (info->nominal_cap)
146 * encoding of the alternate cpu capability. 162 seq_printf(m, "Nominal Capability: %d\n", info->nominal_cap);
147 */ 163 if (info->secondary_cap)
148 len += sprintf(page + len, "Capability: %u %u\n", 164 seq_printf(m, "Secondary Capability: %d\n", info->secondary_cap);
149 info->capability, ext->alt_capability); 165 for (i = 2; i <= info->cpus_total; i++) {
150 for (i = 2; i <= info->cpus_total; i++) 166 seq_printf(m, "Adjustment %02d-way: %u",
151 len += sprintf(page + len, 167 i, info->adjustment[i-2]);
152 "Adjustment %02d-way: %u %u\n", 168 if (info->format == 1)
153 i, info->adjustment[i-2], 169 seq_printf(m, " %u", ext->alt_adjustment[i-2]);
154 ext->alt_adjustment[i-2]); 170 seq_putc(m, '\n');
155
156 } else {
157 len += sprintf(page + len, "Capability: %u\n",
158 info->capability);
159 for (i = 2; i <= info->cpus_total; i++)
160 len += sprintf(page + len,
161 "Adjustment %02d-way: %u\n",
162 i, info->adjustment[i-2]);
163 } 171 }
164
165 if (info->secondary_capability != 0)
166 len += sprintf(page + len, "Secondary Capability: %d\n",
167 info->secondary_capability);
168 return len;
169} 172}
170 173
171static int stsi_2_2_2(struct sysinfo_2_2_2 *info, char *page, int len) 174static void stsi_2_2_2(struct seq_file *m, struct sysinfo_2_2_2 *info)
172{ 175{
173 if (stsi(info, 2, 2, 2) == -ENOSYS) 176 if (stsi(info, 2, 2, 2))
174 return len; 177 return;
175
176 EBCASC(info->name, sizeof(info->name)); 178 EBCASC(info->name, sizeof(info->name));
177 179 seq_putc(m, '\n');
178 len += sprintf(page + len, "\n"); 180 seq_printf(m, "LPAR Number: %d\n", info->lpar_number);
179 len += sprintf(page + len, "LPAR Number: %d\n", 181 seq_printf(m, "LPAR Characteristics: ");
180 info->lpar_number);
181
182 len += sprintf(page + len, "LPAR Characteristics: ");
183 if (info->characteristics & LPAR_CHAR_DEDICATED) 182 if (info->characteristics & LPAR_CHAR_DEDICATED)
184 len += sprintf(page + len, "Dedicated "); 183 seq_printf(m, "Dedicated ");
185 if (info->characteristics & LPAR_CHAR_SHARED) 184 if (info->characteristics & LPAR_CHAR_SHARED)
186 len += sprintf(page + len, "Shared "); 185 seq_printf(m, "Shared ");
187 if (info->characteristics & LPAR_CHAR_LIMITED) 186 if (info->characteristics & LPAR_CHAR_LIMITED)
188 len += sprintf(page + len, "Limited "); 187 seq_printf(m, "Limited ");
189 len += sprintf(page + len, "\n"); 188 seq_putc(m, '\n');
190 189 seq_printf(m, "LPAR Name: %-8.8s\n", info->name);
191 len += sprintf(page + len, "LPAR Name: %-8.8s\n", 190 seq_printf(m, "LPAR Adjustment: %d\n", info->caf);
192 info->name); 191 seq_printf(m, "LPAR CPUs Total: %d\n", info->cpus_total);
193 192 seq_printf(m, "LPAR CPUs Configured: %d\n", info->cpus_configured);
194 len += sprintf(page + len, "LPAR Adjustment: %d\n", 193 seq_printf(m, "LPAR CPUs Standby: %d\n", info->cpus_standby);
195 info->caf); 194 seq_printf(m, "LPAR CPUs Reserved: %d\n", info->cpus_reserved);
196 195 seq_printf(m, "LPAR CPUs Dedicated: %d\n", info->cpus_dedicated);
197 len += sprintf(page + len, "LPAR CPUs Total: %d\n", 196 seq_printf(m, "LPAR CPUs Shared: %d\n", info->cpus_shared);
198 info->cpus_total);
199 len += sprintf(page + len, "LPAR CPUs Configured: %d\n",
200 info->cpus_configured);
201 len += sprintf(page + len, "LPAR CPUs Standby: %d\n",
202 info->cpus_standby);
203 len += sprintf(page + len, "LPAR CPUs Reserved: %d\n",
204 info->cpus_reserved);
205 len += sprintf(page + len, "LPAR CPUs Dedicated: %d\n",
206 info->cpus_dedicated);
207 len += sprintf(page + len, "LPAR CPUs Shared: %d\n",
208 info->cpus_shared);
209 return len;
210} 197}
211 198
212static int stsi_3_2_2(struct sysinfo_3_2_2 *info, char *page, int len) 199static void stsi_3_2_2(struct seq_file *m, struct sysinfo_3_2_2 *info)
213{ 200{
214 int i; 201 int i;
215 202
216 if (stsi(info, 3, 2, 2) == -ENOSYS) 203 if (stsi(info, 3, 2, 2))
217 return len; 204 return;
218 for (i = 0; i < info->count; i++) { 205 for (i = 0; i < info->count; i++) {
219 EBCASC(info->vm[i].name, sizeof(info->vm[i].name)); 206 EBCASC(info->vm[i].name, sizeof(info->vm[i].name));
220 EBCASC(info->vm[i].cpi, sizeof(info->vm[i].cpi)); 207 EBCASC(info->vm[i].cpi, sizeof(info->vm[i].cpi));
221 len += sprintf(page + len, "\n"); 208 seq_putc(m, '\n');
222 len += sprintf(page + len, "VM%02d Name: %-8.8s\n", 209 seq_printf(m, "VM%02d Name: %-8.8s\n", i, info->vm[i].name);
223 i, info->vm[i].name); 210 seq_printf(m, "VM%02d Control Program: %-16.16s\n", i, info->vm[i].cpi);
224 len += sprintf(page + len, "VM%02d Control Program: %-16.16s\n", 211 seq_printf(m, "VM%02d Adjustment: %d\n", i, info->vm[i].caf);
225 i, info->vm[i].cpi); 212 seq_printf(m, "VM%02d CPUs Total: %d\n", i, info->vm[i].cpus_total);
226 213 seq_printf(m, "VM%02d CPUs Configured: %d\n", i, info->vm[i].cpus_configured);
227 len += sprintf(page + len, "VM%02d Adjustment: %d\n", 214 seq_printf(m, "VM%02d CPUs Standby: %d\n", i, info->vm[i].cpus_standby);
228 i, info->vm[i].caf); 215 seq_printf(m, "VM%02d CPUs Reserved: %d\n", i, info->vm[i].cpus_reserved);
229
230 len += sprintf(page + len, "VM%02d CPUs Total: %d\n",
231 i, info->vm[i].cpus_total);
232 len += sprintf(page + len, "VM%02d CPUs Configured: %d\n",
233 i, info->vm[i].cpus_configured);
234 len += sprintf(page + len, "VM%02d CPUs Standby: %d\n",
235 i, info->vm[i].cpus_standby);
236 len += sprintf(page + len, "VM%02d CPUs Reserved: %d\n",
237 i, info->vm[i].cpus_reserved);
238 } 216 }
239 return len;
240} 217}
241 218
242static int proc_read_sysinfo(char *page, char **start, 219static int sysinfo_show(struct seq_file *m, void *v)
243 off_t off, int count,
244 int *eof, void *data)
245{ 220{
246 unsigned long info = get_zeroed_page(GFP_KERNEL); 221 void *info = (void *)get_zeroed_page(GFP_KERNEL);
247 int level, len; 222 int level;
248 223
249 if (!info) 224 if (!info)
250 return 0; 225 return 0;
251 226 level = stsi(NULL, 0, 0, 0);
252 len = 0;
253 level = stsi_0();
254 if (level >= 1) 227 if (level >= 1)
255 len = stsi_1_1_1((struct sysinfo_1_1_1 *) info, page, len); 228 stsi_1_1_1(m, info);
256
257 if (level >= 1) 229 if (level >= 1)
258 len = stsi_15_1_x((struct sysinfo_15_1_x *) info, page, len); 230 stsi_15_1_x(m, info);
259
260 if (level >= 1) 231 if (level >= 1)
261 len = stsi_1_2_2((struct sysinfo_1_2_2 *) info, page, len); 232 stsi_1_2_2(m, info);
262
263 if (level >= 2) 233 if (level >= 2)
264 len = stsi_2_2_2((struct sysinfo_2_2_2 *) info, page, len); 234 stsi_2_2_2(m, info);
265
266 if (level >= 3) 235 if (level >= 3)
267 len = stsi_3_2_2((struct sysinfo_3_2_2 *) info, page, len); 236 stsi_3_2_2(m, info);
237 free_page((unsigned long)info);
238 return 0;
239}
268 240
269 free_page(info); 241static int sysinfo_open(struct inode *inode, struct file *file)
270 return len; 242{
243 return single_open(file, sysinfo_show, NULL);
271} 244}
272 245
273static __init int create_proc_sysinfo(void) 246static const struct file_operations sysinfo_fops = {
247 .open = sysinfo_open,
248 .read = seq_read,
249 .llseek = seq_lseek,
250 .release = single_release,
251};
252
253static int __init sysinfo_create_proc(void)
274{ 254{
275 create_proc_read_entry("sysinfo", 0444, NULL, 255 proc_create("sysinfo", 0444, NULL, &sysinfo_fops);
276 proc_read_sysinfo, NULL);
277 return 0; 256 return 0;
278} 257}
279device_initcall(create_proc_sysinfo); 258device_initcall(sysinfo_create_proc);
280 259
281/* 260/*
282 * Service levels interface. 261 * Service levels interface.
@@ -407,7 +386,7 @@ void s390_adjust_jiffies(void)
407 if (!info) 386 if (!info)
408 return; 387 return;
409 388
410 if (stsi(info, 1, 2, 2) != -ENOSYS) { 389 if (stsi(info, 1, 2, 2) == 0) {
411 /* 390 /*
412 * Major sigh. The cpu capability encoding is "special". 391 * Major sigh. The cpu capability encoding is "special".
413 * If the first 9 bits of info->capability are 0 then it 392 * If the first 9 bits of info->capability are 0 then it