1 /* 2 * Copyright IBM Corp. 2001, 2009 3 * Author(s): Ulrich Weigand <Ulrich.Weigand@de.ibm.com>, 4 * Martin Schwidefsky <schwidefsky@de.ibm.com>, 5 */ 6 7 #include <linux/kernel.h> 8 #include <linux/mm.h> 9 #include <linux/proc_fs.h> 10 #include <linux/seq_file.h> 11 #include <linux/init.h> 12 #include <linux/delay.h> 13 #include <linux/module.h> 14 #include <linux/slab.h> 15 #include <asm/ebcdic.h> 16 #include <asm/sysinfo.h> 17 #include <asm/cpcmd.h> 18 #include <asm/topology.h> 19 20 /* Sigh, math-emu. Don't ask. */ 21 #include <asm/sfp-util.h> 22 #include <math-emu/soft-fp.h> 23 #include <math-emu/single.h> 24 25 int 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 */ 33 int stsi(void *sysinfo, int fc, int sel1, int sel2) 34 { 35 register int r0 asm("0") = (fc << 28) | sel1; 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; 51 } 52 EXPORT_SYMBOL(stsi); 53 54 static void stsi_1_1_1(struct seq_file *m, struct sysinfo_1_1_1 *info) 55 { 56 int i; 57 58 if (stsi(info, 1, 1, 1)) 59 return; 60 EBCASC(info->manufacturer, sizeof(info->manufacturer)); 61 EBCASC(info->type, sizeof(info->type)); 62 EBCASC(info->model, sizeof(info->model)); 63 EBCASC(info->sequence, sizeof(info->sequence)); 64 EBCASC(info->plant, sizeof(info->plant)); 65 EBCASC(info->model_capacity, sizeof(info->model_capacity)); 66 EBCASC(info->model_perm_cap, sizeof(info->model_perm_cap)); 67 EBCASC(info->model_temp_cap, sizeof(info->model_temp_cap)); 68 seq_printf(m, "Manufacturer: %-16.16s\n", info->manufacturer); 69 seq_printf(m, "Type: %-4.4s\n", info->type); 70 /* 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); 78 if (info->model[0] != '\0') 79 seq_printf(m, " %-16.16s", info->model); 80 seq_putc(m, '\n'); 81 seq_printf(m, "Sequence Code: %-16.16s\n", info->sequence); 82 seq_printf(m, "Plant: %-4.4s\n", info->plant); 83 seq_printf(m, "Model Capacity: %-16.16s %08u\n", 84 info->model_capacity, info->model_cap_rating); 85 if (info->model_perm_cap_rating) 86 seq_printf(m, "Model Perm. Capacity: %-16.16s %08u\n", 87 info->model_perm_cap, 88 info->model_perm_cap_rating); 89 if (info->model_temp_cap_rating) 90 seq_printf(m, "Model Temp. Capacity: %-16.16s %08u\n", 91 info->model_temp_cap, 92 info->model_temp_cap_rating); 93 if (info->ncr) 94 seq_printf(m, "Nominal Cap. Rating: %08u\n", info->ncr); 95 if (info->npr) 96 seq_printf(m, "Nominal Perm. Rating: %08u\n", info->npr); 97 if (info->ntr) 98 seq_printf(m, "Nominal Temp. Rating: %08u\n", info->ntr); 99 if (info->cai) { 100 seq_printf(m, "Capacity Adj. Ind.: %d\n", info->cai); 101 seq_printf(m, "Capacity Ch. Reason: %d\n", info->ccr); 102 seq_printf(m, "Capacity Transient: %d\n", info->t); 103 } 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 } 109 } 110 } 111 112 static void stsi_15_1_x(struct seq_file *m, struct sysinfo_15_1_x *info) 113 { 114 static int max_mnest; 115 int i, rc; 116 117 seq_putc(m, '\n'); 118 if (!MACHINE_HAS_TOPOLOGY) 119 return; 120 if (stsi(info, 15, 1, topology_max_mnest)) 121 return; 122 seq_printf(m, "CPU Topology HW: "); 123 for (i = 0; i < TOPOLOGY_NR_MAG; i++) 124 seq_printf(m, " %d", info->mag[i]); 125 seq_putc(m, '\n'); 126 #ifdef CONFIG_SCHED_MC 127 store_topology(info); 128 seq_printf(m, "CPU Topology SW: "); 129 for (i = 0; i < TOPOLOGY_NR_MAG; i++) 130 seq_printf(m, " %d", info->mag[i]); 131 seq_putc(m, '\n'); 132 #endif 133 } 134 135 static void stsi_1_2_2(struct seq_file *m, struct sysinfo_1_2_2 *info) 136 { 137 struct sysinfo_1_2_2_extension *ext; 138 int i; 139 140 if (stsi(info, 1, 2, 2)) 141 return; 142 ext = (struct sysinfo_1_2_2_extension *) 143 ((unsigned long) info + info->acc_offset); 144 seq_printf(m, "CPUs Total: %d\n", info->cpus_total); 145 seq_printf(m, "CPUs Configured: %d\n", info->cpus_configured); 146 seq_printf(m, "CPUs Standby: %d\n", info->cpus_standby); 147 seq_printf(m, "CPUs Reserved: %d\n", info->cpus_reserved); 148 /* 149 * Sigh 2. According to the specification the alternate 150 * capability field is a 32 bit floating point number 151 * if the higher order 8 bits are not zero. Printing 152 * a floating point number in the kernel is a no-no, 153 * always print the number as 32 bit unsigned integer. 154 * The user-space needs to know about the strange 155 * encoding of the alternate cpu capability. 156 */ 157 seq_printf(m, "Capability: %u", info->capability); 158 if (info->format == 1) 159 seq_printf(m, " %u", ext->alt_capability); 160 seq_putc(m, '\n'); 161 if (info->nominal_cap) 162 seq_printf(m, "Nominal Capability: %d\n", info->nominal_cap); 163 if (info->secondary_cap) 164 seq_printf(m, "Secondary Capability: %d\n", info->secondary_cap); 165 for (i = 2; i <= info->cpus_total; i++) { 166 seq_printf(m, "Adjustment %02d-way: %u", 167 i, info->adjustment[i-2]); 168 if (info->format == 1) 169 seq_printf(m, " %u", ext->alt_adjustment[i-2]); 170 seq_putc(m, '\n'); 171 } 172 } 173 174 static void stsi_2_2_2(struct seq_file *m, struct sysinfo_2_2_2 *info) 175 { 176 if (stsi(info, 2, 2, 2)) 177 return; 178 EBCASC(info->name, sizeof(info->name)); 179 seq_putc(m, '\n'); 180 seq_printf(m, "LPAR Number: %d\n", info->lpar_number); 181 seq_printf(m, "LPAR Characteristics: "); 182 if (info->characteristics & LPAR_CHAR_DEDICATED) 183 seq_printf(m, "Dedicated "); 184 if (info->characteristics & LPAR_CHAR_SHARED) 185 seq_printf(m, "Shared "); 186 if (info->characteristics & LPAR_CHAR_LIMITED) 187 seq_printf(m, "Limited "); 188 seq_putc(m, '\n'); 189 seq_printf(m, "LPAR Name: %-8.8s\n", info->name); 190 seq_printf(m, "LPAR Adjustment: %d\n", info->caf); 191 seq_printf(m, "LPAR CPUs Total: %d\n", info->cpus_total); 192 seq_printf(m, "LPAR CPUs Configured: %d\n", info->cpus_configured); 193 seq_printf(m, "LPAR CPUs Standby: %d\n", info->cpus_standby); 194 seq_printf(m, "LPAR CPUs Reserved: %d\n", info->cpus_reserved); 195 seq_printf(m, "LPAR CPUs Dedicated: %d\n", info->cpus_dedicated); 196 seq_printf(m, "LPAR CPUs Shared: %d\n", info->cpus_shared); 197 } 198 199 static void stsi_3_2_2(struct seq_file *m, struct sysinfo_3_2_2 *info) 200 { 201 int i; 202 203 if (stsi(info, 3, 2, 2)) 204 return; 205 for (i = 0; i < info->count; i++) { 206 EBCASC(info->vm[i].name, sizeof(info->vm[i].name)); 207 EBCASC(info->vm[i].cpi, sizeof(info->vm[i].cpi)); 208 seq_putc(m, '\n'); 209 seq_printf(m, "VM%02d Name: %-8.8s\n", i, info->vm[i].name); 210 seq_printf(m, "VM%02d Control Program: %-16.16s\n", i, info->vm[i].cpi); 211 seq_printf(m, "VM%02d Adjustment: %d\n", i, info->vm[i].caf); 212 seq_printf(m, "VM%02d CPUs Total: %d\n", i, info->vm[i].cpus_total); 213 seq_printf(m, "VM%02d CPUs Configured: %d\n", i, info->vm[i].cpus_configured); 214 seq_printf(m, "VM%02d CPUs Standby: %d\n", i, info->vm[i].cpus_standby); 215 seq_printf(m, "VM%02d CPUs Reserved: %d\n", i, info->vm[i].cpus_reserved); 216 } 217 } 218 219 static int sysinfo_show(struct seq_file *m, void *v) 220 { 221 void *info = (void *)get_zeroed_page(GFP_KERNEL); 222 int level; 223 224 if (!info) 225 return 0; 226 level = stsi(NULL, 0, 0, 0); 227 if (level >= 1) 228 stsi_1_1_1(m, info); 229 if (level >= 1) 230 stsi_15_1_x(m, info); 231 if (level >= 1) 232 stsi_1_2_2(m, info); 233 if (level >= 2) 234 stsi_2_2_2(m, info); 235 if (level >= 3) 236 stsi_3_2_2(m, info); 237 free_page((unsigned long)info); 238 return 0; 239 } 240 241 static int sysinfo_open(struct inode *inode, struct file *file) 242 { 243 return single_open(file, sysinfo_show, NULL); 244 } 245 246 static const struct file_operations sysinfo_fops = { 247 .open = sysinfo_open, 248 .read = seq_read, 249 .llseek = seq_lseek, 250 .release = single_release, 251 }; 252 253 static int __init sysinfo_create_proc(void) 254 { 255 proc_create("sysinfo", 0444, NULL, &sysinfo_fops); 256 return 0; 257 } 258 device_initcall(sysinfo_create_proc); 259 260 /* 261 * Service levels interface. 262 */ 263 264 static DECLARE_RWSEM(service_level_sem); 265 static LIST_HEAD(service_level_list); 266 267 int register_service_level(struct service_level *slr) 268 { 269 struct service_level *ptr; 270 271 down_write(&service_level_sem); 272 list_for_each_entry(ptr, &service_level_list, list) 273 if (ptr == slr) { 274 up_write(&service_level_sem); 275 return -EEXIST; 276 } 277 list_add_tail(&slr->list, &service_level_list); 278 up_write(&service_level_sem); 279 return 0; 280 } 281 EXPORT_SYMBOL(register_service_level); 282 283 int unregister_service_level(struct service_level *slr) 284 { 285 struct service_level *ptr, *next; 286 int rc = -ENOENT; 287 288 down_write(&service_level_sem); 289 list_for_each_entry_safe(ptr, next, &service_level_list, list) { 290 if (ptr != slr) 291 continue; 292 list_del(&ptr->list); 293 rc = 0; 294 break; 295 } 296 up_write(&service_level_sem); 297 return rc; 298 } 299 EXPORT_SYMBOL(unregister_service_level); 300 301 static void *service_level_start(struct seq_file *m, loff_t *pos) 302 { 303 down_read(&service_level_sem); 304 return seq_list_start(&service_level_list, *pos); 305 } 306 307 static void *service_level_next(struct seq_file *m, void *p, loff_t *pos) 308 { 309 return seq_list_next(p, &service_level_list, pos); 310 } 311 312 static void service_level_stop(struct seq_file *m, void *p) 313 { 314 up_read(&service_level_sem); 315 } 316 317 static int service_level_show(struct seq_file *m, void *p) 318 { 319 struct service_level *slr; 320 321 slr = list_entry(p, struct service_level, list); 322 slr->seq_print(m, slr); 323 return 0; 324 } 325 326 static const struct seq_operations service_level_seq_ops = { 327 .start = service_level_start, 328 .next = service_level_next, 329 .stop = service_level_stop, 330 .show = service_level_show 331 }; 332 333 static int service_level_open(struct inode *inode, struct file *file) 334 { 335 return seq_open(file, &service_level_seq_ops); 336 } 337 338 static const struct file_operations service_level_ops = { 339 .open = service_level_open, 340 .read = seq_read, 341 .llseek = seq_lseek, 342 .release = seq_release 343 }; 344 345 static void service_level_vm_print(struct seq_file *m, 346 struct service_level *slr) 347 { 348 char *query_buffer, *str; 349 350 query_buffer = kmalloc(1024, GFP_KERNEL | GFP_DMA); 351 if (!query_buffer) 352 return; 353 cpcmd("QUERY CPLEVEL", query_buffer, 1024, NULL); 354 str = strchr(query_buffer, '\n'); 355 if (str) 356 *str = 0; 357 seq_printf(m, "VM: %s\n", query_buffer); 358 kfree(query_buffer); 359 } 360 361 static struct service_level service_level_vm = { 362 .seq_print = service_level_vm_print 363 }; 364 365 static __init int create_proc_service_level(void) 366 { 367 proc_create("service_levels", 0, NULL, &service_level_ops); 368 if (MACHINE_IS_VM) 369 register_service_level(&service_level_vm); 370 return 0; 371 } 372 subsys_initcall(create_proc_service_level); 373 374 /* 375 * CPU capability might have changed. Therefore recalculate loops_per_jiffy. 376 */ 377 void s390_adjust_jiffies(void) 378 { 379 struct sysinfo_1_2_2 *info; 380 const unsigned int fmil = 0x4b189680; /* 1e7 as 32-bit float. */ 381 FP_DECL_S(SA); FP_DECL_S(SB); FP_DECL_S(SR); 382 FP_DECL_EX; 383 unsigned int capability; 384 385 info = (void *) get_zeroed_page(GFP_KERNEL); 386 if (!info) 387 return; 388 389 if (stsi(info, 1, 2, 2) == 0) { 390 /* 391 * Major sigh. The cpu capability encoding is "special". 392 * If the first 9 bits of info->capability are 0 then it 393 * is a 32 bit unsigned integer in the range 0 .. 2^23. 394 * If the first 9 bits are != 0 then it is a 32 bit float. 395 * In addition a lower value indicates a proportionally 396 * higher cpu capacity. Bogomips are the other way round. 397 * To get to a halfway suitable number we divide 1e7 398 * by the cpu capability number. Yes, that means a floating 399 * point division .. math-emu here we come :-) 400 */ 401 FP_UNPACK_SP(SA, &fmil); 402 if ((info->capability >> 23) == 0) 403 FP_FROM_INT_S(SB, (long) info->capability, 64, long); 404 else 405 FP_UNPACK_SP(SB, &info->capability); 406 FP_DIV_S(SR, SA, SB); 407 FP_TO_INT_S(capability, SR, 32, 0); 408 } else 409 /* 410 * Really old machine without stsi block for basic 411 * cpu information. Report 42.0 bogomips. 412 */ 413 capability = 42; 414 loops_per_jiffy = capability * (500000/HZ); 415 free_page((unsigned long) info); 416 } 417 418 /* 419 * calibrate the delay loop 420 */ 421 void __cpuinit calibrate_delay(void) 422 { 423 s390_adjust_jiffies(); 424 /* Print the good old Bogomips line .. */ 425 printk(KERN_DEBUG "Calibrating delay loop (skipped)... " 426 "%lu.%02lu BogoMIPS preset\n", loops_per_jiffy/(500000/HZ), 427 (loops_per_jiffy/(5000/HZ)) % 100); 428 } 429