prominfo_proc.c 7.0 KB

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