2 * drivers/s390/sysinfo.c
4 * Copyright (C) 2001 IBM Deutschland Entwicklung GmbH, IBM Corporation
5 * Author(s): Ulrich Weigand (Ulrich.Weigand@de.ibm.com)
8 #include <linux/kernel.h>
10 #include <linux/proc_fs.h>
11 #include <linux/init.h>
12 #include <linux/delay.h>
13 #include <asm/ebcdic.h>
14 #include <asm/sysinfo.h>
16 /* Sigh, math-emu. Don't ask. */
17 #include <asm/sfp-util.h>
18 #include <math-emu/soft-fp.h>
19 #include <math-emu/single.h>
21 static inline int stsi_0(void)
23 int rc = stsi (NULL, 0, 0, 0);
24 return rc == -ENOSYS ? rc : (((unsigned int) rc) >> 28);
27 static int stsi_1_1_1(struct sysinfo_1_1_1 *info, char *page, int len)
29 if (stsi(info, 1, 1, 1) == -ENOSYS)
32 EBCASC(info->manufacturer, sizeof(info->manufacturer));
33 EBCASC(info->type, sizeof(info->type));
34 EBCASC(info->model, sizeof(info->model));
35 EBCASC(info->sequence, sizeof(info->sequence));
36 EBCASC(info->plant, sizeof(info->plant));
37 EBCASC(info->model_capacity, sizeof(info->model_capacity));
38 len += sprintf(page + len, "Manufacturer: %-16.16s\n",
40 len += sprintf(page + len, "Type: %-4.4s\n",
42 if (info->model[0] != '\0')
44 * Sigh: the model field has been renamed with System z9
45 * to model_capacity and a new model field has been added
46 * after the plant field. To avoid confusing older programs
47 * the "Model:" prints "model_capacity model" or just
48 * "model_capacity" if the model string is empty .
50 len += sprintf(page + len,
51 "Model: %-16.16s %-16.16s\n",
52 info->model_capacity, info->model);
54 len += sprintf(page + len, "Model: %-16.16s\n",
55 info->model_capacity);
56 len += sprintf(page + len, "Sequence Code: %-16.16s\n",
58 len += sprintf(page + len, "Plant: %-4.4s\n",
60 len += sprintf(page + len, "Model Capacity: %-16.16s\n",
61 info->model_capacity);
65 #if 0 /* Currently unused */
66 static int stsi_1_2_1(struct sysinfo_1_2_1 *info, char *page, int len)
68 if (stsi(info, 1, 2, 1) == -ENOSYS)
71 len += sprintf(page + len, "\n");
72 EBCASC(info->sequence, sizeof(info->sequence));
73 EBCASC(info->plant, sizeof(info->plant));
74 len += sprintf(page + len, "Sequence Code of CPU: %-16.16s\n",
76 len += sprintf(page + len, "Plant of CPU: %-16.16s\n",
82 static int stsi_1_2_2(struct sysinfo_1_2_2 *info, char *page, int len)
84 struct sysinfo_1_2_2_extension *ext;
87 if (stsi(info, 1, 2, 2) == -ENOSYS)
89 ext = (struct sysinfo_1_2_2_extension *)
90 ((unsigned long) info + info->acc_offset);
92 len += sprintf(page + len, "\n");
93 len += sprintf(page + len, "CPUs Total: %d\n",
95 len += sprintf(page + len, "CPUs Configured: %d\n",
96 info->cpus_configured);
97 len += sprintf(page + len, "CPUs Standby: %d\n",
99 len += sprintf(page + len, "CPUs Reserved: %d\n",
100 info->cpus_reserved);
102 if (info->format == 1) {
104 * Sigh 2. According to the specification the alternate
105 * capability field is a 32 bit floating point number
106 * if the higher order 8 bits are not zero. Printing
107 * a floating point number in the kernel is a no-no,
108 * always print the number as 32 bit unsigned integer.
109 * The user-space needs to know about the strange
110 * encoding of the alternate cpu capability.
112 len += sprintf(page + len, "Capability: %u %u\n",
113 info->capability, ext->alt_capability);
114 for (i = 2; i <= info->cpus_total; i++)
115 len += sprintf(page + len,
116 "Adjustment %02d-way: %u %u\n",
117 i, info->adjustment[i-2],
118 ext->alt_adjustment[i-2]);
121 len += sprintf(page + len, "Capability: %u\n",
123 for (i = 2; i <= info->cpus_total; i++)
124 len += sprintf(page + len,
125 "Adjustment %02d-way: %u\n",
126 i, info->adjustment[i-2]);
129 if (info->secondary_capability != 0)
130 len += sprintf(page + len, "Secondary Capability: %d\n",
131 info->secondary_capability);
136 #if 0 /* Currently unused */
137 static int stsi_2_2_1(struct sysinfo_2_2_1 *info, char *page, int len)
139 if (stsi(info, 2, 2, 1) == -ENOSYS)
142 len += sprintf(page + len, "\n");
143 EBCASC (info->sequence, sizeof(info->sequence));
144 EBCASC (info->plant, sizeof(info->plant));
145 len += sprintf(page + len, "Sequence Code of logical CPU: %-16.16s\n",
147 len += sprintf(page + len, "Plant of logical CPU: %-16.16s\n",
153 static int stsi_2_2_2(struct sysinfo_2_2_2 *info, char *page, int len)
155 if (stsi(info, 2, 2, 2) == -ENOSYS)
158 EBCASC (info->name, sizeof(info->name));
160 len += sprintf(page + len, "\n");
161 len += sprintf(page + len, "LPAR Number: %d\n",
164 len += sprintf(page + len, "LPAR Characteristics: ");
165 if (info->characteristics & LPAR_CHAR_DEDICATED)
166 len += sprintf(page + len, "Dedicated ");
167 if (info->characteristics & LPAR_CHAR_SHARED)
168 len += sprintf(page + len, "Shared ");
169 if (info->characteristics & LPAR_CHAR_LIMITED)
170 len += sprintf(page + len, "Limited ");
171 len += sprintf(page + len, "\n");
173 len += sprintf(page + len, "LPAR Name: %-8.8s\n",
176 len += sprintf(page + len, "LPAR Adjustment: %d\n",
179 len += sprintf(page + len, "LPAR CPUs Total: %d\n",
181 len += sprintf(page + len, "LPAR CPUs Configured: %d\n",
182 info->cpus_configured);
183 len += sprintf(page + len, "LPAR CPUs Standby: %d\n",
185 len += sprintf(page + len, "LPAR CPUs Reserved: %d\n",
186 info->cpus_reserved);
187 len += sprintf(page + len, "LPAR CPUs Dedicated: %d\n",
188 info->cpus_dedicated);
189 len += sprintf(page + len, "LPAR CPUs Shared: %d\n",
194 static int stsi_3_2_2(struct sysinfo_3_2_2 *info, char *page, int len)
198 if (stsi(info, 3, 2, 2) == -ENOSYS)
200 for (i = 0; i < info->count; i++) {
201 EBCASC (info->vm[i].name, sizeof(info->vm[i].name));
202 EBCASC (info->vm[i].cpi, sizeof(info->vm[i].cpi));
203 len += sprintf(page + len, "\n");
204 len += sprintf(page + len, "VM%02d Name: %-8.8s\n",
205 i, info->vm[i].name);
206 len += sprintf(page + len, "VM%02d Control Program: %-16.16s\n",
209 len += sprintf(page + len, "VM%02d Adjustment: %d\n",
212 len += sprintf(page + len, "VM%02d CPUs Total: %d\n",
213 i, info->vm[i].cpus_total);
214 len += sprintf(page + len, "VM%02d CPUs Configured: %d\n",
215 i, info->vm[i].cpus_configured);
216 len += sprintf(page + len, "VM%02d CPUs Standby: %d\n",
217 i, info->vm[i].cpus_standby);
218 len += sprintf(page + len, "VM%02d CPUs Reserved: %d\n",
219 i, info->vm[i].cpus_reserved);
225 static int proc_read_sysinfo(char *page, char **start,
226 off_t off, int count,
227 int *eof, void *data)
229 unsigned long info = get_zeroed_page (GFP_KERNEL);
238 len = stsi_1_1_1((struct sysinfo_1_1_1 *) info, page, len);
241 len = stsi_1_2_2((struct sysinfo_1_2_2 *) info, page, len);
244 len = stsi_2_2_2((struct sysinfo_2_2_2 *) info, page, len);
247 len = stsi_3_2_2((struct sysinfo_3_2_2 *) info, page, len);
253 static __init int create_proc_sysinfo(void)
255 create_proc_read_entry("sysinfo", 0444, NULL,
256 proc_read_sysinfo, NULL);
260 __initcall(create_proc_sysinfo);
262 int get_cpu_capability(unsigned int *capability)
264 struct sysinfo_1_2_2 *info;
267 info = (void *) get_zeroed_page(GFP_KERNEL);
270 rc = stsi(info, 1, 2, 2);
274 *capability = info->capability;
276 free_page((unsigned long) info);
281 * CPU capability might have changed. Therefore recalculate loops_per_jiffy.
283 void s390_adjust_jiffies(void)
285 struct sysinfo_1_2_2 *info;
286 const unsigned int fmil = 0x4b189680; /* 1e7 as 32-bit float. */
287 FP_DECL_S(SA); FP_DECL_S(SB); FP_DECL_S(SR);
289 unsigned int capability;
291 info = (void *) get_zeroed_page(GFP_KERNEL);
295 if (stsi(info, 1, 2, 2) != -ENOSYS) {
297 * Major sigh. The cpu capability encoding is "special".
298 * If the first 9 bits of info->capability are 0 then it
299 * is a 32 bit unsigned integer in the range 0 .. 2^23.
300 * If the first 9 bits are != 0 then it is a 32 bit float.
301 * In addition a lower value indicates a proportionally
302 * higher cpu capacity. Bogomips are the other way round.
303 * To get to a halfway suitable number we divide 1e7
304 * by the cpu capability number. Yes, that means a floating
305 * point division .. math-emu here we come :-)
307 FP_UNPACK_SP(SA, &fmil);
308 if ((info->capability >> 23) == 0)
309 FP_FROM_INT_S(SB, info->capability, 32, int);
311 FP_UNPACK_SP(SB, &info->capability);
312 FP_DIV_S(SR, SA, SB);
313 FP_TO_INT_S(capability, SR, 32, 0);
316 * Really old machine without stsi block for basic
317 * cpu information. Report 42.0 bogomips.
320 loops_per_jiffy = capability * (500000/HZ);
321 free_page((unsigned long) info);
325 * calibrate the delay loop
327 void __cpuinit calibrate_delay(void)
329 s390_adjust_jiffies();
330 /* Print the good old Bogomips line .. */
331 printk(KERN_DEBUG "Calibrating delay loop (skipped)... "
332 "%lu.%02lu BogoMIPS preset\n", loops_per_jiffy/(500000/HZ),
333 (loops_per_jiffy/(5000/HZ)) % 100);