sysinfo.c 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334
  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. #include <linux/kernel.h>
  8. #include <linux/mm.h>
  9. #include <linux/proc_fs.h>
  10. #include <linux/init.h>
  11. #include <linux/delay.h>
  12. #include <asm/ebcdic.h>
  13. #include <asm/sysinfo.h>
  14. /* Sigh, math-emu. Don't ask. */
  15. #include <asm/sfp-util.h>
  16. #include <math-emu/soft-fp.h>
  17. #include <math-emu/single.h>
  18. static inline int stsi_0(void)
  19. {
  20. int rc = stsi (NULL, 0, 0, 0);
  21. return rc == -ENOSYS ? rc : (((unsigned int) rc) >> 28);
  22. }
  23. static int stsi_1_1_1(struct sysinfo_1_1_1 *info, char *page, int len)
  24. {
  25. if (stsi(info, 1, 1, 1) == -ENOSYS)
  26. return len;
  27. EBCASC(info->manufacturer, sizeof(info->manufacturer));
  28. EBCASC(info->type, sizeof(info->type));
  29. EBCASC(info->model, sizeof(info->model));
  30. EBCASC(info->sequence, sizeof(info->sequence));
  31. EBCASC(info->plant, sizeof(info->plant));
  32. EBCASC(info->model_capacity, sizeof(info->model_capacity));
  33. len += sprintf(page + len, "Manufacturer: %-16.16s\n",
  34. info->manufacturer);
  35. len += sprintf(page + len, "Type: %-4.4s\n",
  36. info->type);
  37. if (info->model[0] != '\0')
  38. /*
  39. * Sigh: the model field has been renamed with System z9
  40. * to model_capacity and a new model field has been added
  41. * after the plant field. To avoid confusing older programs
  42. * the "Model:" prints "model_capacity model" or just
  43. * "model_capacity" if the model string is empty .
  44. */
  45. len += sprintf(page + len,
  46. "Model: %-16.16s %-16.16s\n",
  47. info->model_capacity, info->model);
  48. else
  49. len += sprintf(page + len, "Model: %-16.16s\n",
  50. info->model_capacity);
  51. len += sprintf(page + len, "Sequence Code: %-16.16s\n",
  52. info->sequence);
  53. len += sprintf(page + len, "Plant: %-4.4s\n",
  54. info->plant);
  55. len += sprintf(page + len, "Model Capacity: %-16.16s\n",
  56. info->model_capacity);
  57. return len;
  58. }
  59. #if 0 /* Currently unused */
  60. static int stsi_1_2_1(struct sysinfo_1_2_1 *info, char *page, int len)
  61. {
  62. if (stsi(info, 1, 2, 1) == -ENOSYS)
  63. return len;
  64. len += sprintf(page + len, "\n");
  65. EBCASC(info->sequence, sizeof(info->sequence));
  66. EBCASC(info->plant, sizeof(info->plant));
  67. len += sprintf(page + len, "Sequence Code of CPU: %-16.16s\n",
  68. info->sequence);
  69. len += sprintf(page + len, "Plant of CPU: %-16.16s\n",
  70. info->plant);
  71. return len;
  72. }
  73. #endif
  74. static int stsi_1_2_2(struct sysinfo_1_2_2 *info, char *page, int len)
  75. {
  76. struct sysinfo_1_2_2_extension *ext;
  77. int i;
  78. if (stsi(info, 1, 2, 2) == -ENOSYS)
  79. return len;
  80. ext = (struct sysinfo_1_2_2_extension *)
  81. ((unsigned long) info + info->acc_offset);
  82. len += sprintf(page + len, "\n");
  83. len += sprintf(page + len, "CPUs Total: %d\n",
  84. info->cpus_total);
  85. len += sprintf(page + len, "CPUs Configured: %d\n",
  86. info->cpus_configured);
  87. len += sprintf(page + len, "CPUs Standby: %d\n",
  88. info->cpus_standby);
  89. len += sprintf(page + len, "CPUs Reserved: %d\n",
  90. info->cpus_reserved);
  91. if (info->format == 1) {
  92. /*
  93. * Sigh 2. According to the specification the alternate
  94. * capability field is a 32 bit floating point number
  95. * if the higher order 8 bits are not zero. Printing
  96. * a floating point number in the kernel is a no-no,
  97. * always print the number as 32 bit unsigned integer.
  98. * The user-space needs to know about the strange
  99. * encoding of the alternate cpu capability.
  100. */
  101. len += sprintf(page + len, "Capability: %u %u\n",
  102. info->capability, ext->alt_capability);
  103. for (i = 2; i <= info->cpus_total; i++)
  104. len += sprintf(page + len,
  105. "Adjustment %02d-way: %u %u\n",
  106. i, info->adjustment[i-2],
  107. ext->alt_adjustment[i-2]);
  108. } else {
  109. len += sprintf(page + len, "Capability: %u\n",
  110. info->capability);
  111. for (i = 2; i <= info->cpus_total; i++)
  112. len += sprintf(page + len,
  113. "Adjustment %02d-way: %u\n",
  114. i, info->adjustment[i-2]);
  115. }
  116. if (info->secondary_capability != 0)
  117. len += sprintf(page + len, "Secondary Capability: %d\n",
  118. info->secondary_capability);
  119. return len;
  120. }
  121. #if 0 /* Currently unused */
  122. static int stsi_2_2_1(struct sysinfo_2_2_1 *info, char *page, int len)
  123. {
  124. if (stsi(info, 2, 2, 1) == -ENOSYS)
  125. return len;
  126. len += sprintf(page + len, "\n");
  127. EBCASC (info->sequence, sizeof(info->sequence));
  128. EBCASC (info->plant, sizeof(info->plant));
  129. len += sprintf(page + len, "Sequence Code of logical CPU: %-16.16s\n",
  130. info->sequence);
  131. len += sprintf(page + len, "Plant of logical CPU: %-16.16s\n",
  132. info->plant);
  133. return len;
  134. }
  135. #endif
  136. static int stsi_2_2_2(struct sysinfo_2_2_2 *info, char *page, int len)
  137. {
  138. if (stsi(info, 2, 2, 2) == -ENOSYS)
  139. return len;
  140. EBCASC (info->name, sizeof(info->name));
  141. len += sprintf(page + len, "\n");
  142. len += sprintf(page + len, "LPAR Number: %d\n",
  143. info->lpar_number);
  144. len += sprintf(page + len, "LPAR Characteristics: ");
  145. if (info->characteristics & LPAR_CHAR_DEDICATED)
  146. len += sprintf(page + len, "Dedicated ");
  147. if (info->characteristics & LPAR_CHAR_SHARED)
  148. len += sprintf(page + len, "Shared ");
  149. if (info->characteristics & LPAR_CHAR_LIMITED)
  150. len += sprintf(page + len, "Limited ");
  151. len += sprintf(page + len, "\n");
  152. len += sprintf(page + len, "LPAR Name: %-8.8s\n",
  153. info->name);
  154. len += sprintf(page + len, "LPAR Adjustment: %d\n",
  155. info->caf);
  156. len += sprintf(page + len, "LPAR CPUs Total: %d\n",
  157. info->cpus_total);
  158. len += sprintf(page + len, "LPAR CPUs Configured: %d\n",
  159. info->cpus_configured);
  160. len += sprintf(page + len, "LPAR CPUs Standby: %d\n",
  161. info->cpus_standby);
  162. len += sprintf(page + len, "LPAR CPUs Reserved: %d\n",
  163. info->cpus_reserved);
  164. len += sprintf(page + len, "LPAR CPUs Dedicated: %d\n",
  165. info->cpus_dedicated);
  166. len += sprintf(page + len, "LPAR CPUs Shared: %d\n",
  167. info->cpus_shared);
  168. return len;
  169. }
  170. static int stsi_3_2_2(struct sysinfo_3_2_2 *info, char *page, int len)
  171. {
  172. int i;
  173. if (stsi(info, 3, 2, 2) == -ENOSYS)
  174. return len;
  175. for (i = 0; i < info->count; i++) {
  176. EBCASC (info->vm[i].name, sizeof(info->vm[i].name));
  177. EBCASC (info->vm[i].cpi, sizeof(info->vm[i].cpi));
  178. len += sprintf(page + len, "\n");
  179. len += sprintf(page + len, "VM%02d Name: %-8.8s\n",
  180. i, info->vm[i].name);
  181. len += sprintf(page + len, "VM%02d Control Program: %-16.16s\n",
  182. i, info->vm[i].cpi);
  183. len += sprintf(page + len, "VM%02d Adjustment: %d\n",
  184. i, info->vm[i].caf);
  185. len += sprintf(page + len, "VM%02d CPUs Total: %d\n",
  186. i, info->vm[i].cpus_total);
  187. len += sprintf(page + len, "VM%02d CPUs Configured: %d\n",
  188. i, info->vm[i].cpus_configured);
  189. len += sprintf(page + len, "VM%02d CPUs Standby: %d\n",
  190. i, info->vm[i].cpus_standby);
  191. len += sprintf(page + len, "VM%02d CPUs Reserved: %d\n",
  192. i, info->vm[i].cpus_reserved);
  193. }
  194. return len;
  195. }
  196. static int proc_read_sysinfo(char *page, char **start,
  197. off_t off, int count,
  198. int *eof, void *data)
  199. {
  200. unsigned long info = get_zeroed_page (GFP_KERNEL);
  201. int level, len;
  202. if (!info)
  203. return 0;
  204. len = 0;
  205. level = stsi_0();
  206. if (level >= 1)
  207. len = stsi_1_1_1((struct sysinfo_1_1_1 *) info, page, len);
  208. if (level >= 1)
  209. len = stsi_1_2_2((struct sysinfo_1_2_2 *) info, page, len);
  210. if (level >= 2)
  211. len = stsi_2_2_2((struct sysinfo_2_2_2 *) info, page, len);
  212. if (level >= 3)
  213. len = stsi_3_2_2((struct sysinfo_3_2_2 *) info, page, len);
  214. free_page (info);
  215. return len;
  216. }
  217. static __init int create_proc_sysinfo(void)
  218. {
  219. create_proc_read_entry("sysinfo", 0444, NULL,
  220. proc_read_sysinfo, NULL);
  221. return 0;
  222. }
  223. __initcall(create_proc_sysinfo);
  224. int get_cpu_capability(unsigned int *capability)
  225. {
  226. struct sysinfo_1_2_2 *info;
  227. int rc;
  228. info = (void *) get_zeroed_page(GFP_KERNEL);
  229. if (!info)
  230. return -ENOMEM;
  231. rc = stsi(info, 1, 2, 2);
  232. if (rc == -ENOSYS)
  233. goto out;
  234. rc = 0;
  235. *capability = info->capability;
  236. out:
  237. free_page((unsigned long) info);
  238. return rc;
  239. }
  240. /*
  241. * CPU capability might have changed. Therefore recalculate loops_per_jiffy.
  242. */
  243. void s390_adjust_jiffies(void)
  244. {
  245. struct sysinfo_1_2_2 *info;
  246. const unsigned int fmil = 0x4b189680; /* 1e7 as 32-bit float. */
  247. FP_DECL_S(SA); FP_DECL_S(SB); FP_DECL_S(SR);
  248. FP_DECL_EX;
  249. unsigned int capability;
  250. info = (void *) get_zeroed_page(GFP_KERNEL);
  251. if (!info)
  252. return;
  253. if (stsi(info, 1, 2, 2) != -ENOSYS) {
  254. /*
  255. * Major sigh. The cpu capability encoding is "special".
  256. * If the first 9 bits of info->capability are 0 then it
  257. * is a 32 bit unsigned integer in the range 0 .. 2^23.
  258. * If the first 9 bits are != 0 then it is a 32 bit float.
  259. * In addition a lower value indicates a proportionally
  260. * higher cpu capacity. Bogomips are the other way round.
  261. * To get to a halfway suitable number we divide 1e7
  262. * by the cpu capability number. Yes, that means a floating
  263. * point division .. math-emu here we come :-)
  264. */
  265. FP_UNPACK_SP(SA, &fmil);
  266. if ((info->capability >> 23) == 0)
  267. FP_FROM_INT_S(SB, info->capability, 32, int);
  268. else
  269. FP_UNPACK_SP(SB, &info->capability);
  270. FP_DIV_S(SR, SA, SB);
  271. FP_TO_INT_S(capability, SR, 32, 0);
  272. } else
  273. /*
  274. * Really old machine without stsi block for basic
  275. * cpu information. Report 42.0 bogomips.
  276. */
  277. capability = 42;
  278. loops_per_jiffy = capability * (500000/HZ);
  279. free_page((unsigned long) info);
  280. }
  281. /*
  282. * calibrate the delay loop
  283. */
  284. void __cpuinit calibrate_delay(void)
  285. {
  286. s390_adjust_jiffies();
  287. /* Print the good old Bogomips line .. */
  288. printk(KERN_DEBUG "Calibrating delay loop (skipped)... "
  289. "%lu.%02lu BogoMIPS preset\n", loops_per_jiffy/(500000/HZ),
  290. (loops_per_jiffy/(5000/HZ)) % 100);
  291. }