]>
Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
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 | ||
8 | #include <linux/config.h> | |
9 | #include <linux/kernel.h> | |
10 | #include <linux/mm.h> | |
11 | #include <linux/proc_fs.h> | |
12 | #include <linux/init.h> | |
13 | #include <asm/ebcdic.h> | |
14 | ||
15 | struct sysinfo_1_1_1 | |
16 | { | |
17 | char reserved_0[32]; | |
18 | char manufacturer[16]; | |
19 | char type[4]; | |
20 | char reserved_1[12]; | |
21 | char model[16]; | |
22 | char sequence[16]; | |
23 | char plant[4]; | |
24 | }; | |
25 | ||
26 | struct sysinfo_1_2_1 | |
27 | { | |
28 | char reserved_0[80]; | |
29 | char sequence[16]; | |
30 | char plant[4]; | |
31 | char reserved_1[2]; | |
32 | unsigned short cpu_address; | |
33 | }; | |
34 | ||
35 | struct sysinfo_1_2_2 | |
36 | { | |
37 | char reserved_0[32]; | |
38 | unsigned int capability; | |
39 | unsigned short cpus_total; | |
40 | unsigned short cpus_configured; | |
41 | unsigned short cpus_standby; | |
42 | unsigned short cpus_reserved; | |
43 | unsigned short adjustment[0]; | |
44 | }; | |
45 | ||
46 | struct sysinfo_2_2_1 | |
47 | { | |
48 | char reserved_0[80]; | |
49 | char sequence[16]; | |
50 | char plant[4]; | |
51 | unsigned short cpu_id; | |
52 | unsigned short cpu_address; | |
53 | }; | |
54 | ||
55 | struct sysinfo_2_2_2 | |
56 | { | |
57 | char reserved_0[32]; | |
58 | unsigned short lpar_number; | |
59 | char reserved_1; | |
60 | unsigned char characteristics; | |
61 | #define LPAR_CHAR_DEDICATED (1 << 7) | |
62 | #define LPAR_CHAR_SHARED (1 << 6) | |
63 | #define LPAR_CHAR_LIMITED (1 << 5) | |
64 | unsigned short cpus_total; | |
65 | unsigned short cpus_configured; | |
66 | unsigned short cpus_standby; | |
67 | unsigned short cpus_reserved; | |
68 | char name[8]; | |
69 | unsigned int caf; | |
70 | char reserved_2[16]; | |
71 | unsigned short cpus_dedicated; | |
72 | unsigned short cpus_shared; | |
73 | }; | |
74 | ||
75 | struct sysinfo_3_2_2 | |
76 | { | |
77 | char reserved_0[31]; | |
78 | unsigned char count; | |
79 | struct | |
80 | { | |
81 | char reserved_0[4]; | |
82 | unsigned short cpus_total; | |
83 | unsigned short cpus_configured; | |
84 | unsigned short cpus_standby; | |
85 | unsigned short cpus_reserved; | |
86 | char name[8]; | |
87 | unsigned int caf; | |
88 | char cpi[16]; | |
89 | char reserved_1[24]; | |
90 | ||
91 | } vm[8]; | |
92 | }; | |
93 | ||
94 | union s390_sysinfo | |
95 | { | |
96 | struct sysinfo_1_1_1 sysinfo_1_1_1; | |
97 | struct sysinfo_1_2_1 sysinfo_1_2_1; | |
98 | struct sysinfo_1_2_2 sysinfo_1_2_2; | |
99 | struct sysinfo_2_2_1 sysinfo_2_2_1; | |
100 | struct sysinfo_2_2_2 sysinfo_2_2_2; | |
101 | struct sysinfo_3_2_2 sysinfo_3_2_2; | |
102 | }; | |
103 | ||
104 | static inline int stsi (void *sysinfo, | |
105 | int fc, int sel1, int sel2) | |
106 | { | |
107 | int cc, retv; | |
108 | ||
109 | #ifndef CONFIG_ARCH_S390X | |
110 | __asm__ __volatile__ ( "lr\t0,%2\n" | |
111 | "\tlr\t1,%3\n" | |
112 | "\tstsi\t0(%4)\n" | |
113 | "0:\tipm\t%0\n" | |
114 | "\tsrl\t%0,28\n" | |
115 | "1:lr\t%1,0\n" | |
116 | ".section .fixup,\"ax\"\n" | |
117 | "2:\tlhi\t%0,3\n" | |
118 | "\tbras\t1,3f\n" | |
119 | "\t.long 1b\n" | |
120 | "3:\tl\t1,0(1)\n" | |
121 | "\tbr\t1\n" | |
122 | ".previous\n" | |
123 | ".section __ex_table,\"a\"\n" | |
124 | "\t.align 4\n" | |
125 | "\t.long 0b,2b\n" | |
126 | ".previous\n" | |
127 | : "=d" (cc), "=d" (retv) | |
128 | : "d" ((fc << 28) | sel1), "d" (sel2), "a" (sysinfo) | |
129 | : "cc", "memory", "0", "1" ); | |
130 | #else | |
131 | __asm__ __volatile__ ( "lr\t0,%2\n" | |
132 | "lr\t1,%3\n" | |
133 | "\tstsi\t0(%4)\n" | |
134 | "0:\tipm\t%0\n" | |
135 | "\tsrl\t%0,28\n" | |
136 | "1:lr\t%1,0\n" | |
137 | ".section .fixup,\"ax\"\n" | |
138 | "2:\tlhi\t%0,3\n" | |
139 | "\tjg\t1b\n" | |
140 | ".previous\n" | |
141 | ".section __ex_table,\"a\"\n" | |
142 | "\t.align 8\n" | |
143 | "\t.quad 0b,2b\n" | |
144 | ".previous\n" | |
145 | : "=d" (cc), "=d" (retv) | |
146 | : "d" ((fc << 28) | sel1), "d" (sel2), "a" (sysinfo) | |
147 | : "cc", "memory", "0", "1" ); | |
148 | #endif | |
149 | ||
150 | return cc? -1 : retv; | |
151 | } | |
152 | ||
153 | static inline int stsi_0 (void) | |
154 | { | |
155 | int rc = stsi (NULL, 0, 0, 0); | |
156 | return rc == -1 ? rc : (((unsigned int)rc) >> 28); | |
157 | } | |
158 | ||
159 | static inline int stsi_1_1_1 (struct sysinfo_1_1_1 *info) | |
160 | { | |
161 | int rc = stsi (info, 1, 1, 1); | |
162 | if (rc != -1) | |
163 | { | |
164 | EBCASC (info->manufacturer, sizeof(info->manufacturer)); | |
165 | EBCASC (info->type, sizeof(info->type)); | |
166 | EBCASC (info->model, sizeof(info->model)); | |
167 | EBCASC (info->sequence, sizeof(info->sequence)); | |
168 | EBCASC (info->plant, sizeof(info->plant)); | |
169 | } | |
170 | return rc == -1 ? rc : 0; | |
171 | } | |
172 | ||
173 | static inline int stsi_1_2_1 (struct sysinfo_1_2_1 *info) | |
174 | { | |
175 | int rc = stsi (info, 1, 2, 1); | |
176 | if (rc != -1) | |
177 | { | |
178 | EBCASC (info->sequence, sizeof(info->sequence)); | |
179 | EBCASC (info->plant, sizeof(info->plant)); | |
180 | } | |
181 | return rc == -1 ? rc : 0; | |
182 | } | |
183 | ||
184 | static inline int stsi_1_2_2 (struct sysinfo_1_2_2 *info) | |
185 | { | |
186 | int rc = stsi (info, 1, 2, 2); | |
187 | return rc == -1 ? rc : 0; | |
188 | } | |
189 | ||
190 | static inline int stsi_2_2_1 (struct sysinfo_2_2_1 *info) | |
191 | { | |
192 | int rc = stsi (info, 2, 2, 1); | |
193 | if (rc != -1) | |
194 | { | |
195 | EBCASC (info->sequence, sizeof(info->sequence)); | |
196 | EBCASC (info->plant, sizeof(info->plant)); | |
197 | } | |
198 | return rc == -1 ? rc : 0; | |
199 | } | |
200 | ||
201 | static inline int stsi_2_2_2 (struct sysinfo_2_2_2 *info) | |
202 | { | |
203 | int rc = stsi (info, 2, 2, 2); | |
204 | if (rc != -1) | |
205 | { | |
206 | EBCASC (info->name, sizeof(info->name)); | |
207 | } | |
208 | return rc == -1 ? rc : 0; | |
209 | } | |
210 | ||
211 | static inline int stsi_3_2_2 (struct sysinfo_3_2_2 *info) | |
212 | { | |
213 | int rc = stsi (info, 3, 2, 2); | |
214 | if (rc != -1) | |
215 | { | |
216 | int i; | |
217 | for (i = 0; i < info->count; i++) | |
218 | { | |
219 | EBCASC (info->vm[i].name, sizeof(info->vm[i].name)); | |
220 | EBCASC (info->vm[i].cpi, sizeof(info->vm[i].cpi)); | |
221 | } | |
222 | } | |
223 | return rc == -1 ? rc : 0; | |
224 | } | |
225 | ||
226 | ||
227 | static int proc_read_sysinfo(char *page, char **start, | |
228 | off_t off, int count, | |
229 | int *eof, void *data) | |
230 | { | |
231 | unsigned long info_page = get_zeroed_page (GFP_KERNEL); | |
232 | union s390_sysinfo *info = (union s390_sysinfo *) info_page; | |
233 | int len = 0; | |
234 | int level; | |
235 | int i; | |
236 | ||
237 | if (!info) | |
238 | return 0; | |
239 | ||
240 | level = stsi_0 (); | |
241 | ||
242 | if (level >= 1 && stsi_1_1_1 (&info->sysinfo_1_1_1) == 0) | |
243 | { | |
244 | len += sprintf (page+len, "Manufacturer: %-16.16s\n", | |
245 | info->sysinfo_1_1_1.manufacturer); | |
246 | len += sprintf (page+len, "Type: %-4.4s\n", | |
247 | info->sysinfo_1_1_1.type); | |
248 | len += sprintf (page+len, "Model: %-16.16s\n", | |
249 | info->sysinfo_1_1_1.model); | |
250 | len += sprintf (page+len, "Sequence Code: %-16.16s\n", | |
251 | info->sysinfo_1_1_1.sequence); | |
252 | len += sprintf (page+len, "Plant: %-4.4s\n", | |
253 | info->sysinfo_1_1_1.plant); | |
254 | } | |
255 | ||
256 | if (level >= 1 && stsi_1_2_2 (&info->sysinfo_1_2_2) == 0) | |
257 | { | |
258 | len += sprintf (page+len, "\n"); | |
259 | len += sprintf (page+len, "CPUs Total: %d\n", | |
260 | info->sysinfo_1_2_2.cpus_total); | |
261 | len += sprintf (page+len, "CPUs Configured: %d\n", | |
262 | info->sysinfo_1_2_2.cpus_configured); | |
263 | len += sprintf (page+len, "CPUs Standby: %d\n", | |
264 | info->sysinfo_1_2_2.cpus_standby); | |
265 | len += sprintf (page+len, "CPUs Reserved: %d\n", | |
266 | info->sysinfo_1_2_2.cpus_reserved); | |
267 | ||
268 | len += sprintf (page+len, "Capability: %d\n", | |
269 | info->sysinfo_1_2_2.capability); | |
270 | ||
271 | for (i = 2; i <= info->sysinfo_1_2_2.cpus_total; i++) | |
272 | len += sprintf (page+len, "Adjustment %02d-way: %d\n", | |
273 | i, info->sysinfo_1_2_2.adjustment[i-2]); | |
274 | } | |
275 | ||
276 | if (level >= 2 && stsi_2_2_2 (&info->sysinfo_2_2_2) == 0) | |
277 | { | |
278 | len += sprintf (page+len, "\n"); | |
279 | len += sprintf (page+len, "LPAR Number: %d\n", | |
280 | info->sysinfo_2_2_2.lpar_number); | |
281 | ||
282 | len += sprintf (page+len, "LPAR Characteristics: "); | |
283 | if (info->sysinfo_2_2_2.characteristics & LPAR_CHAR_DEDICATED) | |
284 | len += sprintf (page+len, "Dedicated "); | |
285 | if (info->sysinfo_2_2_2.characteristics & LPAR_CHAR_SHARED) | |
286 | len += sprintf (page+len, "Shared "); | |
287 | if (info->sysinfo_2_2_2.characteristics & LPAR_CHAR_LIMITED) | |
288 | len += sprintf (page+len, "Limited "); | |
289 | len += sprintf (page+len, "\n"); | |
290 | ||
291 | len += sprintf (page+len, "LPAR Name: %-8.8s\n", | |
292 | info->sysinfo_2_2_2.name); | |
293 | ||
294 | len += sprintf (page+len, "LPAR Adjustment: %d\n", | |
295 | info->sysinfo_2_2_2.caf); | |
296 | ||
297 | len += sprintf (page+len, "LPAR CPUs Total: %d\n", | |
298 | info->sysinfo_2_2_2.cpus_total); | |
299 | len += sprintf (page+len, "LPAR CPUs Configured: %d\n", | |
300 | info->sysinfo_2_2_2.cpus_configured); | |
301 | len += sprintf (page+len, "LPAR CPUs Standby: %d\n", | |
302 | info->sysinfo_2_2_2.cpus_standby); | |
303 | len += sprintf (page+len, "LPAR CPUs Reserved: %d\n", | |
304 | info->sysinfo_2_2_2.cpus_reserved); | |
305 | len += sprintf (page+len, "LPAR CPUs Dedicated: %d\n", | |
306 | info->sysinfo_2_2_2.cpus_dedicated); | |
307 | len += sprintf (page+len, "LPAR CPUs Shared: %d\n", | |
308 | info->sysinfo_2_2_2.cpus_shared); | |
309 | } | |
310 | ||
311 | if (level >= 3 && stsi_3_2_2 (&info->sysinfo_3_2_2) == 0) | |
312 | { | |
313 | for (i = 0; i < info->sysinfo_3_2_2.count; i++) | |
314 | { | |
315 | len += sprintf (page+len, "\n"); | |
316 | len += sprintf (page+len, "VM%02d Name: %-8.8s\n", | |
317 | i, info->sysinfo_3_2_2.vm[i].name); | |
318 | len += sprintf (page+len, "VM%02d Control Program: %-16.16s\n", | |
319 | i, info->sysinfo_3_2_2.vm[i].cpi); | |
320 | ||
321 | len += sprintf (page+len, "VM%02d Adjustment: %d\n", | |
322 | i, info->sysinfo_3_2_2.vm[i].caf); | |
323 | ||
324 | len += sprintf (page+len, "VM%02d CPUs Total: %d\n", | |
325 | i, info->sysinfo_3_2_2.vm[i].cpus_total); | |
326 | len += sprintf (page+len, "VM%02d CPUs Configured: %d\n", | |
327 | i, info->sysinfo_3_2_2.vm[i].cpus_configured); | |
328 | len += sprintf (page+len, "VM%02d CPUs Standby: %d\n", | |
329 | i, info->sysinfo_3_2_2.vm[i].cpus_standby); | |
330 | len += sprintf (page+len, "VM%02d CPUs Reserved: %d\n", | |
331 | i, info->sysinfo_3_2_2.vm[i].cpus_reserved); | |
332 | } | |
333 | } | |
334 | ||
335 | free_page (info_page); | |
336 | return len; | |
337 | } | |
338 | ||
339 | static __init int create_proc_sysinfo(void) | |
340 | { | |
341 | create_proc_read_entry ("sysinfo", 0444, NULL, | |
342 | proc_read_sysinfo, NULL); | |
343 | return 0; | |
344 | } | |
345 | ||
346 | __initcall(create_proc_sysinfo); | |
347 |