blob: 1e788e815ce7f872f629a91d75936f446f1835c8 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * drivers/s390/sysinfo.c
3 *
4 * Copyright (C) 2001 IBM Deutschland Entwicklung GmbH, IBM Corporation
5 * Author(s): Ulrich Weigand (Ulrich.Weigand@de.ibm.com)
6 */
7
Linus Torvalds1da177e2005-04-16 15:20:36 -07008#include <linux/kernel.h>
9#include <linux/mm.h>
10#include <linux/proc_fs.h>
11#include <linux/init.h>
12#include <asm/ebcdic.h>
13
Martin Schwidefsky0fee6442006-09-20 15:59:10 +020014struct sysinfo_1_1_1 {
Linus Torvalds1da177e2005-04-16 15:20:36 -070015 char reserved_0[32];
16 char manufacturer[16];
17 char type[4];
18 char reserved_1[12];
Martin Schwidefsky0fee6442006-09-20 15:59:10 +020019 char model_capacity[16];
Linus Torvalds1da177e2005-04-16 15:20:36 -070020 char sequence[16];
21 char plant[4];
Martin Schwidefsky0fee6442006-09-20 15:59:10 +020022 char model[16];
Linus Torvalds1da177e2005-04-16 15:20:36 -070023};
24
Martin Schwidefsky0fee6442006-09-20 15:59:10 +020025struct sysinfo_1_2_1 {
Linus Torvalds1da177e2005-04-16 15:20:36 -070026 char reserved_0[80];
27 char sequence[16];
28 char plant[4];
29 char reserved_1[2];
30 unsigned short cpu_address;
31};
32
Martin Schwidefsky0fee6442006-09-20 15:59:10 +020033struct sysinfo_1_2_2 {
34 char format;
35 char reserved_0[1];
36 unsigned short acc_offset;
37 char reserved_1[24];
38 unsigned int secondary_capability;
Linus Torvalds1da177e2005-04-16 15:20:36 -070039 unsigned int capability;
40 unsigned short cpus_total;
41 unsigned short cpus_configured;
42 unsigned short cpus_standby;
43 unsigned short cpus_reserved;
44 unsigned short adjustment[0];
45};
46
Martin Schwidefsky0fee6442006-09-20 15:59:10 +020047struct sysinfo_1_2_2_extension {
48 unsigned int alt_capability;
49 unsigned short alt_adjustment[0];
50};
51
52struct sysinfo_2_2_1 {
Linus Torvalds1da177e2005-04-16 15:20:36 -070053 char reserved_0[80];
54 char sequence[16];
55 char plant[4];
56 unsigned short cpu_id;
57 unsigned short cpu_address;
58};
59
Martin Schwidefsky0fee6442006-09-20 15:59:10 +020060struct sysinfo_2_2_2 {
Linus Torvalds1da177e2005-04-16 15:20:36 -070061 char reserved_0[32];
62 unsigned short lpar_number;
63 char reserved_1;
64 unsigned char characteristics;
Linus Torvalds1da177e2005-04-16 15:20:36 -070065 unsigned short cpus_total;
66 unsigned short cpus_configured;
67 unsigned short cpus_standby;
68 unsigned short cpus_reserved;
69 char name[8];
70 unsigned int caf;
71 char reserved_2[16];
72 unsigned short cpus_dedicated;
73 unsigned short cpus_shared;
74};
75
Martin Schwidefsky0fee6442006-09-20 15:59:10 +020076#define LPAR_CHAR_DEDICATED (1 << 7)
77#define LPAR_CHAR_SHARED (1 << 6)
78#define LPAR_CHAR_LIMITED (1 << 5)
79
80struct sysinfo_3_2_2 {
Linus Torvalds1da177e2005-04-16 15:20:36 -070081 char reserved_0[31];
82 unsigned char count;
Martin Schwidefsky0fee6442006-09-20 15:59:10 +020083 struct {
Linus Torvalds1da177e2005-04-16 15:20:36 -070084 char reserved_0[4];
85 unsigned short cpus_total;
86 unsigned short cpus_configured;
87 unsigned short cpus_standby;
88 unsigned short cpus_reserved;
89 char name[8];
90 unsigned int caf;
91 char cpi[16];
92 char reserved_1[24];
93
94 } vm[8];
95};
96
Martin Schwidefsky0fee6442006-09-20 15:59:10 +020097static inline int stsi(void *sysinfo, int fc, int sel1, int sel2)
Linus Torvalds1da177e2005-04-16 15:20:36 -070098{
Martin Schwidefsky0fee6442006-09-20 15:59:10 +020099 register int r0 asm("0") = (fc << 28) | sel1;
100 register int r1 asm("1") = sel2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700101
Martin Schwidefsky0fee6442006-09-20 15:59:10 +0200102 asm volatile(
103 " stsi 0(%2)\n"
104 "0: jz 2f\n"
105 "1: lhi %0,%3\n"
106 "2:\n"
107 EX_TABLE(0b,1b)
108 : "+d" (r0) : "d" (r1), "a" (sysinfo), "K" (-ENOSYS)
109 : "cc", "memory" );
110 return r0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111}
112
Martin Schwidefsky0fee6442006-09-20 15:59:10 +0200113static inline int stsi_0(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700114{
115 int rc = stsi (NULL, 0, 0, 0);
Martin Schwidefsky0fee6442006-09-20 15:59:10 +0200116 return rc == -ENOSYS ? rc : (((unsigned int) rc) >> 28);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700117}
118
Martin Schwidefsky0fee6442006-09-20 15:59:10 +0200119static int stsi_1_1_1(struct sysinfo_1_1_1 *info, char *page, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700120{
Martin Schwidefsky0fee6442006-09-20 15:59:10 +0200121 if (stsi(info, 1, 1, 1) == -ENOSYS)
122 return len;
123
124 EBCASC(info->manufacturer, sizeof(info->manufacturer));
125 EBCASC(info->type, sizeof(info->type));
126 EBCASC(info->model, sizeof(info->model));
127 EBCASC(info->sequence, sizeof(info->sequence));
128 EBCASC(info->plant, sizeof(info->plant));
129 EBCASC(info->model_capacity, sizeof(info->model_capacity));
130 len += sprintf(page + len, "Manufacturer: %-16.16s\n",
131 info->manufacturer);
132 len += sprintf(page + len, "Type: %-4.4s\n",
133 info->type);
134 if (info->model[0] != '\0')
135 /*
136 * Sigh: the model field has been renamed with System z9
137 * to model_capacity and a new model field has been added
138 * after the plant field. To avoid confusing older programs
139 * the "Model:" prints "model_capacity model" or just
140 * "model_capacity" if the model string is empty .
141 */
142 len += sprintf(page + len,
143 "Model: %-16.16s %-16.16s\n",
144 info->model_capacity, info->model);
145 else
146 len += sprintf(page + len, "Model: %-16.16s\n",
147 info->model_capacity);
148 len += sprintf(page + len, "Sequence Code: %-16.16s\n",
149 info->sequence);
150 len += sprintf(page + len, "Plant: %-4.4s\n",
151 info->plant);
152 len += sprintf(page + len, "Model Capacity: %-16.16s\n",
153 info->model_capacity);
154 return len;
155}
156
157#if 0 /* Currently unused */
158static int stsi_1_2_1(struct sysinfo_1_2_1 *info, char *page, int len)
159{
160 if (stsi(info, 1, 2, 1) == -ENOSYS)
161 return len;
162
163 len += sprintf(page + len, "\n");
164 EBCASC(info->sequence, sizeof(info->sequence));
165 EBCASC(info->plant, sizeof(info->plant));
166 len += sprintf(page + len, "Sequence Code of CPU: %-16.16s\n",
167 info->sequence);
168 len += sprintf(page + len, "Plant of CPU: %-16.16s\n",
169 info->plant);
170 return len;
171}
172#endif
173
174static int stsi_1_2_2(struct sysinfo_1_2_2 *info, char *page, int len)
175{
176 struct sysinfo_1_2_2_extension *ext;
177 int i;
178
179 if (stsi(info, 1, 2, 2) == -ENOSYS)
180 return len;
181 ext = (struct sysinfo_1_2_2_extension *)
182 ((unsigned long) info + info->acc_offset);
183
184 len += sprintf(page + len, "\n");
185 len += sprintf(page + len, "CPUs Total: %d\n",
186 info->cpus_total);
187 len += sprintf(page + len, "CPUs Configured: %d\n",
188 info->cpus_configured);
189 len += sprintf(page + len, "CPUs Standby: %d\n",
190 info->cpus_standby);
191 len += sprintf(page + len, "CPUs Reserved: %d\n",
192 info->cpus_reserved);
193
194 if (info->format == 1) {
195 /*
196 * Sigh 2. According to the specification the alternate
197 * capability field is a 32 bit floating point number
198 * if the higher order 8 bits are not zero. Printing
199 * a floating point number in the kernel is a no-no,
200 * always print the number as 32 bit unsigned integer.
201 * The user-space needs to know about the stange
202 * encoding of the alternate cpu capability.
203 */
204 len += sprintf(page + len, "Capability: %u %u\n",
205 info->capability, ext->alt_capability);
206 for (i = 2; i <= info->cpus_total; i++)
207 len += sprintf(page + len,
208 "Adjustment %02d-way: %u %u\n",
209 i, info->adjustment[i-2],
210 ext->alt_adjustment[i-2]);
211
212 } else {
213 len += sprintf(page + len, "Capability: %u\n",
214 info->capability);
215 for (i = 2; i <= info->cpus_total; i++)
216 len += sprintf(page + len,
217 "Adjustment %02d-way: %u\n",
218 i, info->adjustment[i-2]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700219 }
Martin Schwidefsky0fee6442006-09-20 15:59:10 +0200220
221 if (info->secondary_capability != 0)
222 len += sprintf(page + len, "Secondary Capability: %d\n",
223 info->secondary_capability);
224
225 return len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700226}
227
Martin Schwidefsky0fee6442006-09-20 15:59:10 +0200228#if 0 /* Currently unused */
229static int stsi_2_2_1(struct sysinfo_2_2_1 *info, char *page, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700230{
Martin Schwidefsky0fee6442006-09-20 15:59:10 +0200231 if (stsi(info, 2, 2, 1) == -ENOSYS)
232 return len;
233
234 len += sprintf(page + len, "\n");
235 EBCASC (info->sequence, sizeof(info->sequence));
236 EBCASC (info->plant, sizeof(info->plant));
237 len += sprintf(page + len, "Sequence Code of logical CPU: %-16.16s\n",
238 info->sequence);
239 len += sprintf(page + len, "Plant of logical CPU: %-16.16s\n",
240 info->plant);
241 return len;
242}
243#endif
244
245static int stsi_2_2_2(struct sysinfo_2_2_2 *info, char *page, int len)
246{
247 if (stsi(info, 2, 2, 2) == -ENOSYS)
248 return len;
249
250 EBCASC (info->name, sizeof(info->name));
251
252 len += sprintf(page + len, "\n");
253 len += sprintf(page + len, "LPAR Number: %d\n",
254 info->lpar_number);
255
256 len += sprintf(page + len, "LPAR Characteristics: ");
257 if (info->characteristics & LPAR_CHAR_DEDICATED)
258 len += sprintf(page + len, "Dedicated ");
259 if (info->characteristics & LPAR_CHAR_SHARED)
260 len += sprintf(page + len, "Shared ");
261 if (info->characteristics & LPAR_CHAR_LIMITED)
262 len += sprintf(page + len, "Limited ");
263 len += sprintf(page + len, "\n");
264
265 len += sprintf(page + len, "LPAR Name: %-8.8s\n",
266 info->name);
267
268 len += sprintf(page + len, "LPAR Adjustment: %d\n",
269 info->caf);
270
271 len += sprintf(page + len, "LPAR CPUs Total: %d\n",
272 info->cpus_total);
273 len += sprintf(page + len, "LPAR CPUs Configured: %d\n",
274 info->cpus_configured);
275 len += sprintf(page + len, "LPAR CPUs Standby: %d\n",
276 info->cpus_standby);
277 len += sprintf(page + len, "LPAR CPUs Reserved: %d\n",
278 info->cpus_reserved);
279 len += sprintf(page + len, "LPAR CPUs Dedicated: %d\n",
280 info->cpus_dedicated);
281 len += sprintf(page + len, "LPAR CPUs Shared: %d\n",
282 info->cpus_shared);
283 return len;
284}
285
286static int stsi_3_2_2(struct sysinfo_3_2_2 *info, char *page, int len)
287{
288 int i;
289
290 if (stsi(info, 3, 2, 2) == -ENOSYS)
291 return len;
292 for (i = 0; i < info->count; i++) {
293 EBCASC (info->vm[i].name, sizeof(info->vm[i].name));
294 EBCASC (info->vm[i].cpi, sizeof(info->vm[i].cpi));
295 len += sprintf(page + len, "\n");
296 len += sprintf(page + len, "VM%02d Name: %-8.8s\n",
297 i, info->vm[i].name);
298 len += sprintf(page + len, "VM%02d Control Program: %-16.16s\n",
299 i, info->vm[i].cpi);
300
301 len += sprintf(page + len, "VM%02d Adjustment: %d\n",
302 i, info->vm[i].caf);
303
304 len += sprintf(page + len, "VM%02d CPUs Total: %d\n",
305 i, info->vm[i].cpus_total);
306 len += sprintf(page + len, "VM%02d CPUs Configured: %d\n",
307 i, info->vm[i].cpus_configured);
308 len += sprintf(page + len, "VM%02d CPUs Standby: %d\n",
309 i, info->vm[i].cpus_standby);
310 len += sprintf(page + len, "VM%02d CPUs Reserved: %d\n",
311 i, info->vm[i].cpus_reserved);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312 }
Martin Schwidefsky0fee6442006-09-20 15:59:10 +0200313 return len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314}
315
316
317static int proc_read_sysinfo(char *page, char **start,
318 off_t off, int count,
319 int *eof, void *data)
320{
Martin Schwidefsky0fee6442006-09-20 15:59:10 +0200321 unsigned long info = get_zeroed_page (GFP_KERNEL);
322 int level, len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700323
324 if (!info)
325 return 0;
326
Martin Schwidefsky0fee6442006-09-20 15:59:10 +0200327 len = 0;
328 level = stsi_0();
329 if (level >= 1)
330 len = stsi_1_1_1((struct sysinfo_1_1_1 *) info, page, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700331
Martin Schwidefsky0fee6442006-09-20 15:59:10 +0200332 if (level >= 1)
333 len = stsi_1_2_2((struct sysinfo_1_2_2 *) info, page, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334
Martin Schwidefsky0fee6442006-09-20 15:59:10 +0200335 if (level >= 2)
336 len = stsi_2_2_2((struct sysinfo_2_2_2 *) info, page, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700337
Martin Schwidefsky0fee6442006-09-20 15:59:10 +0200338 if (level >= 3)
339 len = stsi_3_2_2((struct sysinfo_3_2_2 *) info, page, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700340
Martin Schwidefsky0fee6442006-09-20 15:59:10 +0200341 free_page (info);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700342 return len;
343}
344
345static __init int create_proc_sysinfo(void)
346{
Martin Schwidefsky0fee6442006-09-20 15:59:10 +0200347 create_proc_read_entry("sysinfo", 0444, NULL,
348 proc_read_sysinfo, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700349 return 0;
350}
351
352__initcall(create_proc_sysinfo);
353