[SPARC64]: Make smp_processor_id() functional before start_kernel()
[linux-2.6] / drivers / s390 / sysinfo.c
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_64BIT
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