prominfo_proc.c 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  1. /*
  2. * This file is subject to the terms and conditions of the GNU General Public
  3. * License. See the file "COPYING" in the main directory of this archive
  4. * for more details.
  5. *
  6. * Copyright (C) 1999,2001-2004, 2006 Silicon Graphics, Inc. All Rights Reserved.
  7. *
  8. * Module to export the system's Firmware Interface Tables, including
  9. * PROM revision numbers and banners, in /proc
  10. */
  11. #include <linux/module.h>
  12. #include <linux/slab.h>
  13. #include <linux/proc_fs.h>
  14. #include <linux/nodemask.h>
  15. #include <asm/io.h>
  16. #include <asm/sn/sn_sal.h>
  17. #include <asm/sn/sn_cpuid.h>
  18. #include <asm/sn/addrs.h>
  19. MODULE_DESCRIPTION("PROM version reporting for /proc");
  20. MODULE_AUTHOR("Chad Talbott");
  21. MODULE_LICENSE("GPL");
  22. /* Standard Intel FIT entry types */
  23. #define FIT_ENTRY_FIT_HEADER 0x00 /* FIT header entry */
  24. #define FIT_ENTRY_PAL_B 0x01 /* PAL_B entry */
  25. /* Entries 0x02 through 0x0D reserved by Intel */
  26. #define FIT_ENTRY_PAL_A_PROC 0x0E /* Processor-specific PAL_A entry */
  27. #define FIT_ENTRY_PAL_A 0x0F /* PAL_A entry, same as... */
  28. #define FIT_ENTRY_PAL_A_GEN 0x0F /* ...Generic PAL_A entry */
  29. #define FIT_ENTRY_UNUSED 0x7F /* Unused (reserved by Intel?) */
  30. /* OEM-defined entries range from 0x10 to 0x7E. */
  31. #define FIT_ENTRY_SAL_A 0x10 /* SAL_A entry */
  32. #define FIT_ENTRY_SAL_B 0x11 /* SAL_B entry */
  33. #define FIT_ENTRY_SALRUNTIME 0x12 /* SAL runtime entry */
  34. #define FIT_ENTRY_EFI 0x1F /* EFI entry */
  35. #define FIT_ENTRY_FPSWA 0x20 /* embedded fpswa entry */
  36. #define FIT_ENTRY_VMLINUX 0x21 /* embedded vmlinux entry */
  37. #define FIT_MAJOR_SHIFT (32 + 8)
  38. #define FIT_MAJOR_MASK ((1 << 8) - 1)
  39. #define FIT_MINOR_SHIFT 32
  40. #define FIT_MINOR_MASK ((1 << 8) - 1)
  41. #define FIT_MAJOR(q) \
  42. ((unsigned) ((q) >> FIT_MAJOR_SHIFT) & FIT_MAJOR_MASK)
  43. #define FIT_MINOR(q) \
  44. ((unsigned) ((q) >> FIT_MINOR_SHIFT) & FIT_MINOR_MASK)
  45. #define FIT_TYPE_SHIFT (32 + 16)
  46. #define FIT_TYPE_MASK ((1 << 7) - 1)
  47. #define FIT_TYPE(q) \
  48. ((unsigned) ((q) >> FIT_TYPE_SHIFT) & FIT_TYPE_MASK)
  49. struct fit_type_map_t {
  50. unsigned char type;
  51. const char *name;
  52. };
  53. static const struct fit_type_map_t fit_entry_types[] = {
  54. {FIT_ENTRY_FIT_HEADER, "FIT Header"},
  55. {FIT_ENTRY_PAL_A_GEN, "Generic PAL_A"},
  56. {FIT_ENTRY_PAL_A_PROC, "Processor-specific PAL_A"},
  57. {FIT_ENTRY_PAL_A, "PAL_A"},
  58. {FIT_ENTRY_PAL_B, "PAL_B"},
  59. {FIT_ENTRY_SAL_A, "SAL_A"},
  60. {FIT_ENTRY_SAL_B, "SAL_B"},
  61. {FIT_ENTRY_SALRUNTIME, "SAL runtime"},
  62. {FIT_ENTRY_EFI, "EFI"},
  63. {FIT_ENTRY_VMLINUX, "Embedded Linux"},
  64. {FIT_ENTRY_FPSWA, "Embedded FPSWA"},
  65. {FIT_ENTRY_UNUSED, "Unused"},
  66. {0xff, "Error"},
  67. };
  68. static const char *fit_type_name(unsigned char type)
  69. {
  70. struct fit_type_map_t const *mapp;
  71. for (mapp = fit_entry_types; mapp->type != 0xff; mapp++)
  72. if (type == mapp->type)
  73. return mapp->name;
  74. if ((type > FIT_ENTRY_PAL_A) && (type < FIT_ENTRY_UNUSED))
  75. return "OEM type";
  76. if ((type > FIT_ENTRY_PAL_B) && (type < FIT_ENTRY_PAL_A))
  77. return "Reserved";
  78. return "Unknown type";
  79. }
  80. static int
  81. get_fit_entry(unsigned long nasid, int index, unsigned long *fentry,
  82. char *banner, int banlen)
  83. {
  84. return ia64_sn_get_fit_compt(nasid, index, fentry, banner, banlen);
  85. }
  86. /*
  87. * These two routines display the FIT table for each node.
  88. */
  89. static int dump_fit_entry(char *page, unsigned long *fentry)
  90. {
  91. unsigned type;
  92. type = FIT_TYPE(fentry[1]);
  93. return sprintf(page, "%02x %-25s %x.%02x %016lx %u\n",
  94. type,
  95. fit_type_name(type),
  96. FIT_MAJOR(fentry[1]), FIT_MINOR(fentry[1]),
  97. fentry[0],
  98. /* mult by sixteen to get size in bytes */
  99. (unsigned)(fentry[1] & 0xffffff) * 16);
  100. }
  101. /*
  102. * We assume that the fit table will be small enough that we can print
  103. * the whole thing into one page. (This is true for our default 16kB
  104. * pages -- each entry is about 60 chars wide when printed.) I read
  105. * somewhere that the maximum size of the FIT is 128 entries, so we're
  106. * OK except for 4kB pages (and no one is going to do that on SN
  107. * anyway).
  108. */
  109. static int
  110. dump_fit(char *page, unsigned long nasid)
  111. {
  112. unsigned long fentry[2];
  113. int index;
  114. char *p;
  115. p = page;
  116. for (index=0;;index++) {
  117. BUG_ON(index * 60 > PAGE_SIZE);
  118. if (get_fit_entry(nasid, index, fentry, NULL, 0))
  119. break;
  120. p += dump_fit_entry(p, fentry);
  121. }
  122. return p - page;
  123. }
  124. static int
  125. dump_version(char *page, unsigned long nasid)
  126. {
  127. unsigned long fentry[2];
  128. char banner[128];
  129. int index;
  130. int len;
  131. for (index = 0; ; index++) {
  132. if (get_fit_entry(nasid, index, fentry, banner,
  133. sizeof(banner)))
  134. return 0;
  135. if (FIT_TYPE(fentry[1]) == FIT_ENTRY_SAL_A)
  136. break;
  137. }
  138. len = sprintf(page, "%x.%02x\n", FIT_MAJOR(fentry[1]),
  139. FIT_MINOR(fentry[1]));
  140. page += len;
  141. if (banner[0])
  142. len += snprintf(page, PAGE_SIZE-len, "%s\n", banner);
  143. return len;
  144. }
  145. /* same as in proc_misc.c */
  146. static int
  147. proc_calc_metrics(char *page, char **start, off_t off, int count, int *eof,
  148. int len)
  149. {
  150. if (len <= off + count)
  151. *eof = 1;
  152. *start = page + off;
  153. len -= off;
  154. if (len > count)
  155. len = count;
  156. if (len < 0)
  157. len = 0;
  158. return len;
  159. }
  160. static int
  161. read_version_entry(char *page, char **start, off_t off, int count, int *eof,
  162. void *data)
  163. {
  164. int len;
  165. /* data holds the NASID of the node */
  166. len = dump_version(page, (unsigned long)data);
  167. len = proc_calc_metrics(page, start, off, count, eof, len);
  168. return len;
  169. }
  170. static int
  171. read_fit_entry(char *page, char **start, off_t off, int count, int *eof,
  172. void *data)
  173. {
  174. int len;
  175. /* data holds the NASID of the node */
  176. len = dump_fit(page, (unsigned long)data);
  177. len = proc_calc_metrics(page, start, off, count, eof, len);
  178. return len;
  179. }
  180. /* module entry points */
  181. int __init prominfo_init(void);
  182. void __exit prominfo_exit(void);
  183. module_init(prominfo_init);
  184. module_exit(prominfo_exit);
  185. static struct proc_dir_entry **proc_entries;
  186. static struct proc_dir_entry *sgi_prominfo_entry;
  187. #define NODE_NAME_LEN 11
  188. int __init prominfo_init(void)
  189. {
  190. struct proc_dir_entry **entp;
  191. cnodeid_t cnodeid;
  192. unsigned long nasid;
  193. int size;
  194. char name[NODE_NAME_LEN];
  195. if (!ia64_platform_is("sn2"))
  196. return 0;
  197. size = num_online_nodes() * sizeof(struct proc_dir_entry *);
  198. proc_entries = kzalloc(size, GFP_KERNEL);
  199. if (!proc_entries)
  200. return -ENOMEM;
  201. sgi_prominfo_entry = proc_mkdir("sgi_prominfo", NULL);
  202. entp = proc_entries;
  203. for_each_online_node(cnodeid) {
  204. sprintf(name, "node%d", cnodeid);
  205. *entp = proc_mkdir(name, sgi_prominfo_entry);
  206. nasid = cnodeid_to_nasid(cnodeid);
  207. create_proc_read_entry("fit", 0, *entp, read_fit_entry,
  208. (void *)nasid);
  209. create_proc_read_entry("version", 0, *entp,
  210. read_version_entry, (void *)nasid);
  211. entp++;
  212. }
  213. return 0;
  214. }
  215. void __exit prominfo_exit(void)
  216. {
  217. struct proc_dir_entry **entp;
  218. unsigned int cnodeid;
  219. char name[NODE_NAME_LEN];
  220. entp = proc_entries;
  221. for_each_online_node(cnodeid) {
  222. remove_proc_entry("fit", *entp);
  223. remove_proc_entry("version", *entp);
  224. sprintf(name, "node%d", cnodeid);
  225. remove_proc_entry(name, sgi_prominfo_entry);
  226. entp++;
  227. }
  228. remove_proc_entry("sgi_prominfo", NULL);
  229. kfree(proc_entries);
  230. }