palinfo.c 27 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096
  1. /*
  2. * palinfo.c
  3. *
  4. * Prints processor specific information reported by PAL.
  5. * This code is based on specification of PAL as of the
  6. * Intel IA-64 Architecture Software Developer's Manual v1.0.
  7. *
  8. *
  9. * Copyright (C) 2000-2001, 2003 Hewlett-Packard Co
  10. * Stephane Eranian <eranian@hpl.hp.com>
  11. * Copyright (C) 2004 Intel Corporation
  12. * Ashok Raj <ashok.raj@intel.com>
  13. *
  14. * 05/26/2000 S.Eranian initial release
  15. * 08/21/2000 S.Eranian updated to July 2000 PAL specs
  16. * 02/05/2001 S.Eranian fixed module support
  17. * 10/23/2001 S.Eranian updated pal_perf_mon_info bug fixes
  18. * 03/24/2004 Ashok Raj updated to work with CPU Hotplug
  19. * 10/26/2006 Russ Anderson updated processor features to rev 2.2 spec
  20. */
  21. #include <linux/types.h>
  22. #include <linux/errno.h>
  23. #include <linux/init.h>
  24. #include <linux/proc_fs.h>
  25. #include <linux/mm.h>
  26. #include <linux/module.h>
  27. #include <linux/efi.h>
  28. #include <linux/notifier.h>
  29. #include <linux/cpu.h>
  30. #include <linux/cpumask.h>
  31. #include <asm/pal.h>
  32. #include <asm/sal.h>
  33. #include <asm/page.h>
  34. #include <asm/processor.h>
  35. #include <linux/smp.h>
  36. MODULE_AUTHOR("Stephane Eranian <eranian@hpl.hp.com>");
  37. MODULE_DESCRIPTION("/proc interface to IA-64 PAL");
  38. MODULE_LICENSE("GPL");
  39. #define PALINFO_VERSION "0.5"
  40. typedef int (*palinfo_func_t)(char*);
  41. typedef struct {
  42. const char *name; /* name of the proc entry */
  43. palinfo_func_t proc_read; /* function to call for reading */
  44. struct proc_dir_entry *entry; /* registered entry (removal) */
  45. } palinfo_entry_t;
  46. /*
  47. * A bunch of string array to get pretty printing
  48. */
  49. static char *cache_types[] = {
  50. "", /* not used */
  51. "Instruction",
  52. "Data",
  53. "Data/Instruction" /* unified */
  54. };
  55. static const char *cache_mattrib[]={
  56. "WriteThrough",
  57. "WriteBack",
  58. "", /* reserved */
  59. "" /* reserved */
  60. };
  61. static const char *cache_st_hints[]={
  62. "Temporal, level 1",
  63. "Reserved",
  64. "Reserved",
  65. "Non-temporal, all levels",
  66. "Reserved",
  67. "Reserved",
  68. "Reserved",
  69. "Reserved"
  70. };
  71. static const char *cache_ld_hints[]={
  72. "Temporal, level 1",
  73. "Non-temporal, level 1",
  74. "Reserved",
  75. "Non-temporal, all levels",
  76. "Reserved",
  77. "Reserved",
  78. "Reserved",
  79. "Reserved"
  80. };
  81. static const char *rse_hints[]={
  82. "enforced lazy",
  83. "eager stores",
  84. "eager loads",
  85. "eager loads and stores"
  86. };
  87. #define RSE_HINTS_COUNT ARRAY_SIZE(rse_hints)
  88. static const char *mem_attrib[]={
  89. "WB", /* 000 */
  90. "SW", /* 001 */
  91. "010", /* 010 */
  92. "011", /* 011 */
  93. "UC", /* 100 */
  94. "UCE", /* 101 */
  95. "WC", /* 110 */
  96. "NaTPage" /* 111 */
  97. };
  98. /*
  99. * Take a 64bit vector and produces a string such that
  100. * if bit n is set then 2^n in clear text is generated. The adjustment
  101. * to the right unit is also done.
  102. *
  103. * Input:
  104. * - a pointer to a buffer to hold the string
  105. * - a 64-bit vector
  106. * Ouput:
  107. * - a pointer to the end of the buffer
  108. *
  109. */
  110. static char *
  111. bitvector_process(char *p, u64 vector)
  112. {
  113. int i,j;
  114. const char *units[]={ "", "K", "M", "G", "T" };
  115. for (i=0, j=0; i < 64; i++ , j=i/10) {
  116. if (vector & 0x1) {
  117. p += sprintf(p, "%d%s ", 1 << (i-j*10), units[j]);
  118. }
  119. vector >>= 1;
  120. }
  121. return p;
  122. }
  123. /*
  124. * Take a 64bit vector and produces a string such that
  125. * if bit n is set then register n is present. The function
  126. * takes into account consecutive registers and prints out ranges.
  127. *
  128. * Input:
  129. * - a pointer to a buffer to hold the string
  130. * - a 64-bit vector
  131. * Ouput:
  132. * - a pointer to the end of the buffer
  133. *
  134. */
  135. static char *
  136. bitregister_process(char *p, u64 *reg_info, int max)
  137. {
  138. int i, begin, skip = 0;
  139. u64 value = reg_info[0];
  140. value >>= i = begin = ffs(value) - 1;
  141. for(; i < max; i++ ) {
  142. if (i != 0 && (i%64) == 0) value = *++reg_info;
  143. if ((value & 0x1) == 0 && skip == 0) {
  144. if (begin <= i - 2)
  145. p += sprintf(p, "%d-%d ", begin, i-1);
  146. else
  147. p += sprintf(p, "%d ", i-1);
  148. skip = 1;
  149. begin = -1;
  150. } else if ((value & 0x1) && skip == 1) {
  151. skip = 0;
  152. begin = i;
  153. }
  154. value >>=1;
  155. }
  156. if (begin > -1) {
  157. if (begin < 127)
  158. p += sprintf(p, "%d-127", begin);
  159. else
  160. p += sprintf(p, "127");
  161. }
  162. return p;
  163. }
  164. static int
  165. power_info(char *page)
  166. {
  167. s64 status;
  168. char *p = page;
  169. u64 halt_info_buffer[8];
  170. pal_power_mgmt_info_u_t *halt_info =(pal_power_mgmt_info_u_t *)halt_info_buffer;
  171. int i;
  172. status = ia64_pal_halt_info(halt_info);
  173. if (status != 0) return 0;
  174. for (i=0; i < 8 ; i++ ) {
  175. if (halt_info[i].pal_power_mgmt_info_s.im == 1) {
  176. p += sprintf(p, "Power level %d:\n"
  177. "\tentry_latency : %d cycles\n"
  178. "\texit_latency : %d cycles\n"
  179. "\tpower consumption : %d mW\n"
  180. "\tCache+TLB coherency : %s\n", i,
  181. halt_info[i].pal_power_mgmt_info_s.entry_latency,
  182. halt_info[i].pal_power_mgmt_info_s.exit_latency,
  183. halt_info[i].pal_power_mgmt_info_s.power_consumption,
  184. halt_info[i].pal_power_mgmt_info_s.co ? "Yes" : "No");
  185. } else {
  186. p += sprintf(p,"Power level %d: not implemented\n",i);
  187. }
  188. }
  189. return p - page;
  190. }
  191. static int
  192. cache_info(char *page)
  193. {
  194. char *p = page;
  195. unsigned long i, levels, unique_caches;
  196. pal_cache_config_info_t cci;
  197. int j, k;
  198. long status;
  199. if ((status = ia64_pal_cache_summary(&levels, &unique_caches)) != 0) {
  200. printk(KERN_ERR "ia64_pal_cache_summary=%ld\n", status);
  201. return 0;
  202. }
  203. p += sprintf(p, "Cache levels : %ld\nUnique caches : %ld\n\n", levels, unique_caches);
  204. for (i=0; i < levels; i++) {
  205. for (j=2; j >0 ; j--) {
  206. /* even without unification some level may not be present */
  207. if ((status=ia64_pal_cache_config_info(i,j, &cci)) != 0) {
  208. continue;
  209. }
  210. p += sprintf(p,
  211. "%s Cache level %lu:\n"
  212. "\tSize : %u bytes\n"
  213. "\tAttributes : ",
  214. cache_types[j+cci.pcci_unified], i+1,
  215. cci.pcci_cache_size);
  216. if (cci.pcci_unified) p += sprintf(p, "Unified ");
  217. p += sprintf(p, "%s\n", cache_mattrib[cci.pcci_cache_attr]);
  218. p += sprintf(p,
  219. "\tAssociativity : %d\n"
  220. "\tLine size : %d bytes\n"
  221. "\tStride : %d bytes\n",
  222. cci.pcci_assoc, 1<<cci.pcci_line_size, 1<<cci.pcci_stride);
  223. if (j == 1)
  224. p += sprintf(p, "\tStore latency : N/A\n");
  225. else
  226. p += sprintf(p, "\tStore latency : %d cycle(s)\n",
  227. cci.pcci_st_latency);
  228. p += sprintf(p,
  229. "\tLoad latency : %d cycle(s)\n"
  230. "\tStore hints : ", cci.pcci_ld_latency);
  231. for(k=0; k < 8; k++ ) {
  232. if ( cci.pcci_st_hints & 0x1)
  233. p += sprintf(p, "[%s]", cache_st_hints[k]);
  234. cci.pcci_st_hints >>=1;
  235. }
  236. p += sprintf(p, "\n\tLoad hints : ");
  237. for(k=0; k < 8; k++ ) {
  238. if (cci.pcci_ld_hints & 0x1)
  239. p += sprintf(p, "[%s]", cache_ld_hints[k]);
  240. cci.pcci_ld_hints >>=1;
  241. }
  242. p += sprintf(p,
  243. "\n\tAlias boundary : %d byte(s)\n"
  244. "\tTag LSB : %d\n"
  245. "\tTag MSB : %d\n",
  246. 1<<cci.pcci_alias_boundary, cci.pcci_tag_lsb,
  247. cci.pcci_tag_msb);
  248. /* when unified, data(j=2) is enough */
  249. if (cci.pcci_unified) break;
  250. }
  251. }
  252. return p - page;
  253. }
  254. static int
  255. vm_info(char *page)
  256. {
  257. char *p = page;
  258. u64 tr_pages =0, vw_pages=0, tc_pages;
  259. u64 attrib;
  260. pal_vm_info_1_u_t vm_info_1;
  261. pal_vm_info_2_u_t vm_info_2;
  262. pal_tc_info_u_t tc_info;
  263. ia64_ptce_info_t ptce;
  264. const char *sep;
  265. int i, j;
  266. long status;
  267. if ((status = ia64_pal_vm_summary(&vm_info_1, &vm_info_2)) !=0) {
  268. printk(KERN_ERR "ia64_pal_vm_summary=%ld\n", status);
  269. } else {
  270. p += sprintf(p,
  271. "Physical Address Space : %d bits\n"
  272. "Virtual Address Space : %d bits\n"
  273. "Protection Key Registers(PKR) : %d\n"
  274. "Implemented bits in PKR.key : %d\n"
  275. "Hash Tag ID : 0x%x\n"
  276. "Size of RR.rid : %d\n"
  277. "Max Purges : ",
  278. vm_info_1.pal_vm_info_1_s.phys_add_size,
  279. vm_info_2.pal_vm_info_2_s.impl_va_msb+1,
  280. vm_info_1.pal_vm_info_1_s.max_pkr+1,
  281. vm_info_1.pal_vm_info_1_s.key_size,
  282. vm_info_1.pal_vm_info_1_s.hash_tag_id,
  283. vm_info_2.pal_vm_info_2_s.rid_size);
  284. if (vm_info_2.pal_vm_info_2_s.max_purges == PAL_MAX_PURGES)
  285. p += sprintf(p, "unlimited\n");
  286. else
  287. p += sprintf(p, "%d\n",
  288. vm_info_2.pal_vm_info_2_s.max_purges ?
  289. vm_info_2.pal_vm_info_2_s.max_purges : 1);
  290. }
  291. if (ia64_pal_mem_attrib(&attrib) == 0) {
  292. p += sprintf(p, "Supported memory attributes : ");
  293. sep = "";
  294. for (i = 0; i < 8; i++) {
  295. if (attrib & (1 << i)) {
  296. p += sprintf(p, "%s%s", sep, mem_attrib[i]);
  297. sep = ", ";
  298. }
  299. }
  300. p += sprintf(p, "\n");
  301. }
  302. if ((status = ia64_pal_vm_page_size(&tr_pages, &vw_pages)) !=0) {
  303. printk(KERN_ERR "ia64_pal_vm_page_size=%ld\n", status);
  304. } else {
  305. p += sprintf(p,
  306. "\nTLB walker : %simplemented\n"
  307. "Number of DTR : %d\n"
  308. "Number of ITR : %d\n"
  309. "TLB insertable page sizes : ",
  310. vm_info_1.pal_vm_info_1_s.vw ? "" : "not ",
  311. vm_info_1.pal_vm_info_1_s.max_dtr_entry+1,
  312. vm_info_1.pal_vm_info_1_s.max_itr_entry+1);
  313. p = bitvector_process(p, tr_pages);
  314. p += sprintf(p, "\nTLB purgeable page sizes : ");
  315. p = bitvector_process(p, vw_pages);
  316. }
  317. if ((status=ia64_get_ptce(&ptce)) != 0) {
  318. printk(KERN_ERR "ia64_get_ptce=%ld\n", status);
  319. } else {
  320. p += sprintf(p,
  321. "\nPurge base address : 0x%016lx\n"
  322. "Purge outer loop count : %d\n"
  323. "Purge inner loop count : %d\n"
  324. "Purge outer loop stride : %d\n"
  325. "Purge inner loop stride : %d\n",
  326. ptce.base, ptce.count[0], ptce.count[1],
  327. ptce.stride[0], ptce.stride[1]);
  328. p += sprintf(p,
  329. "TC Levels : %d\n"
  330. "Unique TC(s) : %d\n",
  331. vm_info_1.pal_vm_info_1_s.num_tc_levels,
  332. vm_info_1.pal_vm_info_1_s.max_unique_tcs);
  333. for(i=0; i < vm_info_1.pal_vm_info_1_s.num_tc_levels; i++) {
  334. for (j=2; j>0 ; j--) {
  335. tc_pages = 0; /* just in case */
  336. /* even without unification, some levels may not be present */
  337. if ((status=ia64_pal_vm_info(i,j, &tc_info, &tc_pages)) != 0) {
  338. continue;
  339. }
  340. p += sprintf(p,
  341. "\n%s Translation Cache Level %d:\n"
  342. "\tHash sets : %d\n"
  343. "\tAssociativity : %d\n"
  344. "\tNumber of entries : %d\n"
  345. "\tFlags : ",
  346. cache_types[j+tc_info.tc_unified], i+1,
  347. tc_info.tc_num_sets,
  348. tc_info.tc_associativity,
  349. tc_info.tc_num_entries);
  350. if (tc_info.tc_pf)
  351. p += sprintf(p, "PreferredPageSizeOptimized ");
  352. if (tc_info.tc_unified)
  353. p += sprintf(p, "Unified ");
  354. if (tc_info.tc_reduce_tr)
  355. p += sprintf(p, "TCReduction");
  356. p += sprintf(p, "\n\tSupported page sizes: ");
  357. p = bitvector_process(p, tc_pages);
  358. /* when unified date (j=2) is enough */
  359. if (tc_info.tc_unified)
  360. break;
  361. }
  362. }
  363. }
  364. p += sprintf(p, "\n");
  365. return p - page;
  366. }
  367. static int
  368. register_info(char *page)
  369. {
  370. char *p = page;
  371. u64 reg_info[2];
  372. u64 info;
  373. unsigned long phys_stacked;
  374. pal_hints_u_t hints;
  375. unsigned long iregs, dregs;
  376. static const char * const info_type[] = {
  377. "Implemented AR(s)",
  378. "AR(s) with read side-effects",
  379. "Implemented CR(s)",
  380. "CR(s) with read side-effects",
  381. };
  382. for(info=0; info < 4; info++) {
  383. if (ia64_pal_register_info(info, &reg_info[0], &reg_info[1]) != 0) return 0;
  384. p += sprintf(p, "%-32s : ", info_type[info]);
  385. p = bitregister_process(p, reg_info, 128);
  386. p += sprintf(p, "\n");
  387. }
  388. if (ia64_pal_rse_info(&phys_stacked, &hints) == 0) {
  389. p += sprintf(p,
  390. "RSE stacked physical registers : %ld\n"
  391. "RSE load/store hints : %ld (%s)\n",
  392. phys_stacked, hints.ph_data,
  393. hints.ph_data < RSE_HINTS_COUNT ? rse_hints[hints.ph_data]: "(??)");
  394. }
  395. if (ia64_pal_debug_info(&iregs, &dregs))
  396. return 0;
  397. p += sprintf(p,
  398. "Instruction debug register pairs : %ld\n"
  399. "Data debug register pairs : %ld\n", iregs, dregs);
  400. return p - page;
  401. }
  402. static char *proc_features_0[]={ /* Feature set 0 */
  403. NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,
  404. NULL,NULL,NULL,NULL,NULL,NULL,NULL, NULL,NULL,
  405. NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,
  406. NULL,NULL,NULL,NULL,NULL, NULL,NULL,NULL,NULL,
  407. "Unimplemented instruction address fault",
  408. "INIT, PMI, and LINT pins",
  409. "Simple unimplemented instr addresses",
  410. "Variable P-state performance",
  411. "Virtual machine features implemented",
  412. "XIP,XPSR,XFS implemented",
  413. "XR1-XR3 implemented",
  414. "Disable dynamic predicate prediction",
  415. "Disable processor physical number",
  416. "Disable dynamic data cache prefetch",
  417. "Disable dynamic inst cache prefetch",
  418. "Disable dynamic branch prediction",
  419. NULL, NULL, NULL, NULL,
  420. "Disable P-states",
  421. "Enable MCA on Data Poisoning",
  422. "Enable vmsw instruction",
  423. "Enable extern environmental notification",
  424. "Disable BINIT on processor time-out",
  425. "Disable dynamic power management (DPM)",
  426. "Disable coherency",
  427. "Disable cache",
  428. "Enable CMCI promotion",
  429. "Enable MCA to BINIT promotion",
  430. "Enable MCA promotion",
  431. "Enable BERR promotion"
  432. };
  433. static char *proc_features_16[]={ /* Feature set 16 */
  434. "Disable ETM",
  435. "Enable ETM",
  436. "Enable MCA on half-way timer",
  437. "Enable snoop WC",
  438. NULL,
  439. "Enable Fast Deferral",
  440. "Disable MCA on memory aliasing",
  441. "Enable RSB",
  442. NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
  443. "DP system processor",
  444. "Low Voltage",
  445. "HT supported",
  446. NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
  447. NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
  448. NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
  449. NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
  450. NULL, NULL, NULL, NULL, NULL
  451. };
  452. static char **proc_features[]={
  453. proc_features_0,
  454. NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
  455. NULL, NULL, NULL, NULL,
  456. proc_features_16,
  457. NULL, NULL, NULL, NULL,
  458. };
  459. static char * feature_set_info(char *page, u64 avail, u64 status, u64 control,
  460. unsigned long set)
  461. {
  462. char *p = page;
  463. char **vf, **v;
  464. int i;
  465. vf = v = proc_features[set];
  466. for(i=0; i < 64; i++, avail >>=1, status >>=1, control >>=1) {
  467. if (!(control)) /* No remaining bits set */
  468. break;
  469. if (!(avail & 0x1)) /* Print only bits that are available */
  470. continue;
  471. if (vf)
  472. v = vf + i;
  473. if ( v && *v ) {
  474. p += sprintf(p, "%-40s : %s %s\n", *v,
  475. avail & 0x1 ? (status & 0x1 ?
  476. "On " : "Off"): "",
  477. avail & 0x1 ? (control & 0x1 ?
  478. "Ctrl" : "NoCtrl"): "");
  479. } else {
  480. p += sprintf(p, "Feature set %2ld bit %2d\t\t\t"
  481. " : %s %s\n",
  482. set, i,
  483. avail & 0x1 ? (status & 0x1 ?
  484. "On " : "Off"): "",
  485. avail & 0x1 ? (control & 0x1 ?
  486. "Ctrl" : "NoCtrl"): "");
  487. }
  488. }
  489. return p;
  490. }
  491. static int
  492. processor_info(char *page)
  493. {
  494. char *p = page;
  495. u64 avail=1, status=1, control=1, feature_set=0;
  496. s64 ret;
  497. do {
  498. ret = ia64_pal_proc_get_features(&avail, &status, &control,
  499. feature_set);
  500. if (ret < 0) {
  501. return p - page;
  502. }
  503. if (ret == 1) {
  504. feature_set++;
  505. continue;
  506. }
  507. p = feature_set_info(p, avail, status, control, feature_set);
  508. feature_set++;
  509. } while(1);
  510. return p - page;
  511. }
  512. static const char *bus_features[]={
  513. NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,
  514. NULL,NULL,NULL,NULL,NULL,NULL,NULL, NULL,NULL,
  515. NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,
  516. NULL,NULL,
  517. "Request Bus Parking",
  518. "Bus Lock Mask",
  519. "Enable Half Transfer",
  520. NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
  521. NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
  522. NULL, NULL, NULL, NULL,
  523. "Enable Cache Line Repl. Shared",
  524. "Enable Cache Line Repl. Exclusive",
  525. "Disable Transaction Queuing",
  526. "Disable Response Error Checking",
  527. "Disable Bus Error Checking",
  528. "Disable Bus Requester Internal Error Signalling",
  529. "Disable Bus Requester Error Signalling",
  530. "Disable Bus Initialization Event Checking",
  531. "Disable Bus Initialization Event Signalling",
  532. "Disable Bus Address Error Checking",
  533. "Disable Bus Address Error Signalling",
  534. "Disable Bus Data Error Checking"
  535. };
  536. static int
  537. bus_info(char *page)
  538. {
  539. char *p = page;
  540. const char **v = bus_features;
  541. pal_bus_features_u_t av, st, ct;
  542. u64 avail, status, control;
  543. int i;
  544. s64 ret;
  545. if ((ret=ia64_pal_bus_get_features(&av, &st, &ct)) != 0) return 0;
  546. avail = av.pal_bus_features_val;
  547. status = st.pal_bus_features_val;
  548. control = ct.pal_bus_features_val;
  549. for(i=0; i < 64; i++, v++, avail >>=1, status >>=1, control >>=1) {
  550. if ( ! *v ) continue;
  551. p += sprintf(p, "%-48s : %s%s %s\n", *v,
  552. avail & 0x1 ? "" : "NotImpl",
  553. avail & 0x1 ? (status & 0x1 ? "On" : "Off"): "",
  554. avail & 0x1 ? (control & 0x1 ? "Ctrl" : "NoCtrl"): "");
  555. }
  556. return p - page;
  557. }
  558. static int
  559. version_info(char *page)
  560. {
  561. pal_version_u_t min_ver, cur_ver;
  562. char *p = page;
  563. if (ia64_pal_version(&min_ver, &cur_ver) != 0)
  564. return 0;
  565. p += sprintf(p,
  566. "PAL_vendor : 0x%02x (min=0x%02x)\n"
  567. "PAL_A : %02x.%02x (min=%02x.%02x)\n"
  568. "PAL_B : %02x.%02x (min=%02x.%02x)\n",
  569. cur_ver.pal_version_s.pv_pal_vendor,
  570. min_ver.pal_version_s.pv_pal_vendor,
  571. cur_ver.pal_version_s.pv_pal_a_model,
  572. cur_ver.pal_version_s.pv_pal_a_rev,
  573. min_ver.pal_version_s.pv_pal_a_model,
  574. min_ver.pal_version_s.pv_pal_a_rev,
  575. cur_ver.pal_version_s.pv_pal_b_model,
  576. cur_ver.pal_version_s.pv_pal_b_rev,
  577. min_ver.pal_version_s.pv_pal_b_model,
  578. min_ver.pal_version_s.pv_pal_b_rev);
  579. return p - page;
  580. }
  581. static int
  582. perfmon_info(char *page)
  583. {
  584. char *p = page;
  585. u64 pm_buffer[16];
  586. pal_perf_mon_info_u_t pm_info;
  587. if (ia64_pal_perf_mon_info(pm_buffer, &pm_info) != 0) return 0;
  588. p += sprintf(p,
  589. "PMC/PMD pairs : %d\n"
  590. "Counter width : %d bits\n"
  591. "Cycle event number : %d\n"
  592. "Retired event number : %d\n"
  593. "Implemented PMC : ",
  594. pm_info.pal_perf_mon_info_s.generic, pm_info.pal_perf_mon_info_s.width,
  595. pm_info.pal_perf_mon_info_s.cycles, pm_info.pal_perf_mon_info_s.retired);
  596. p = bitregister_process(p, pm_buffer, 256);
  597. p += sprintf(p, "\nImplemented PMD : ");
  598. p = bitregister_process(p, pm_buffer+4, 256);
  599. p += sprintf(p, "\nCycles count capable : ");
  600. p = bitregister_process(p, pm_buffer+8, 256);
  601. p += sprintf(p, "\nRetired bundles count capable : ");
  602. #ifdef CONFIG_ITANIUM
  603. /*
  604. * PAL_PERF_MON_INFO reports that only PMC4 can be used to count CPU_CYCLES
  605. * which is wrong, both PMC4 and PMD5 support it.
  606. */
  607. if (pm_buffer[12] == 0x10) pm_buffer[12]=0x30;
  608. #endif
  609. p = bitregister_process(p, pm_buffer+12, 256);
  610. p += sprintf(p, "\n");
  611. return p - page;
  612. }
  613. static int
  614. frequency_info(char *page)
  615. {
  616. char *p = page;
  617. struct pal_freq_ratio proc, itc, bus;
  618. unsigned long base;
  619. if (ia64_pal_freq_base(&base) == -1)
  620. p += sprintf(p, "Output clock : not implemented\n");
  621. else
  622. p += sprintf(p, "Output clock : %ld ticks/s\n", base);
  623. if (ia64_pal_freq_ratios(&proc, &bus, &itc) != 0) return 0;
  624. p += sprintf(p,
  625. "Processor/Clock ratio : %d/%d\n"
  626. "Bus/Clock ratio : %d/%d\n"
  627. "ITC/Clock ratio : %d/%d\n",
  628. proc.num, proc.den, bus.num, bus.den, itc.num, itc.den);
  629. return p - page;
  630. }
  631. static int
  632. tr_info(char *page)
  633. {
  634. char *p = page;
  635. long status;
  636. pal_tr_valid_u_t tr_valid;
  637. u64 tr_buffer[4];
  638. pal_vm_info_1_u_t vm_info_1;
  639. pal_vm_info_2_u_t vm_info_2;
  640. unsigned long i, j;
  641. unsigned long max[3], pgm;
  642. struct ifa_reg {
  643. unsigned long valid:1;
  644. unsigned long ig:11;
  645. unsigned long vpn:52;
  646. } *ifa_reg;
  647. struct itir_reg {
  648. unsigned long rv1:2;
  649. unsigned long ps:6;
  650. unsigned long key:24;
  651. unsigned long rv2:32;
  652. } *itir_reg;
  653. struct gr_reg {
  654. unsigned long p:1;
  655. unsigned long rv1:1;
  656. unsigned long ma:3;
  657. unsigned long a:1;
  658. unsigned long d:1;
  659. unsigned long pl:2;
  660. unsigned long ar:3;
  661. unsigned long ppn:38;
  662. unsigned long rv2:2;
  663. unsigned long ed:1;
  664. unsigned long ig:11;
  665. } *gr_reg;
  666. struct rid_reg {
  667. unsigned long ig1:1;
  668. unsigned long rv1:1;
  669. unsigned long ig2:6;
  670. unsigned long rid:24;
  671. unsigned long rv2:32;
  672. } *rid_reg;
  673. if ((status = ia64_pal_vm_summary(&vm_info_1, &vm_info_2)) !=0) {
  674. printk(KERN_ERR "ia64_pal_vm_summary=%ld\n", status);
  675. return 0;
  676. }
  677. max[0] = vm_info_1.pal_vm_info_1_s.max_itr_entry+1;
  678. max[1] = vm_info_1.pal_vm_info_1_s.max_dtr_entry+1;
  679. for (i=0; i < 2; i++ ) {
  680. for (j=0; j < max[i]; j++) {
  681. status = ia64_pal_tr_read(j, i, tr_buffer, &tr_valid);
  682. if (status != 0) {
  683. printk(KERN_ERR "palinfo: pal call failed on tr[%lu:%lu]=%ld\n",
  684. i, j, status);
  685. continue;
  686. }
  687. ifa_reg = (struct ifa_reg *)&tr_buffer[2];
  688. if (ifa_reg->valid == 0) continue;
  689. gr_reg = (struct gr_reg *)tr_buffer;
  690. itir_reg = (struct itir_reg *)&tr_buffer[1];
  691. rid_reg = (struct rid_reg *)&tr_buffer[3];
  692. pgm = -1 << (itir_reg->ps - 12);
  693. p += sprintf(p,
  694. "%cTR%lu: av=%d pv=%d dv=%d mv=%d\n"
  695. "\tppn : 0x%lx\n"
  696. "\tvpn : 0x%lx\n"
  697. "\tps : ",
  698. "ID"[i], j,
  699. tr_valid.pal_tr_valid_s.access_rights_valid,
  700. tr_valid.pal_tr_valid_s.priv_level_valid,
  701. tr_valid.pal_tr_valid_s.dirty_bit_valid,
  702. tr_valid.pal_tr_valid_s.mem_attr_valid,
  703. (gr_reg->ppn & pgm)<< 12, (ifa_reg->vpn & pgm)<< 12);
  704. p = bitvector_process(p, 1<< itir_reg->ps);
  705. p += sprintf(p,
  706. "\n\tpl : %d\n"
  707. "\tar : %d\n"
  708. "\trid : %x\n"
  709. "\tp : %d\n"
  710. "\tma : %d\n"
  711. "\td : %d\n",
  712. gr_reg->pl, gr_reg->ar, rid_reg->rid, gr_reg->p, gr_reg->ma,
  713. gr_reg->d);
  714. }
  715. }
  716. return p - page;
  717. }
  718. /*
  719. * List {name,function} pairs for every entry in /proc/palinfo/cpu*
  720. */
  721. static palinfo_entry_t palinfo_entries[]={
  722. { "version_info", version_info, },
  723. { "vm_info", vm_info, },
  724. { "cache_info", cache_info, },
  725. { "power_info", power_info, },
  726. { "register_info", register_info, },
  727. { "processor_info", processor_info, },
  728. { "perfmon_info", perfmon_info, },
  729. { "frequency_info", frequency_info, },
  730. { "bus_info", bus_info },
  731. { "tr_info", tr_info, }
  732. };
  733. #define NR_PALINFO_ENTRIES (int) ARRAY_SIZE(palinfo_entries)
  734. /*
  735. * this array is used to keep track of the proc entries we create. This is
  736. * required in the module mode when we need to remove all entries. The procfs code
  737. * does not do recursion of deletion
  738. *
  739. * Notes:
  740. * - +1 accounts for the cpuN directory entry in /proc/pal
  741. */
  742. #define NR_PALINFO_PROC_ENTRIES (NR_CPUS*(NR_PALINFO_ENTRIES+1))
  743. static struct proc_dir_entry *palinfo_proc_entries[NR_PALINFO_PROC_ENTRIES];
  744. static struct proc_dir_entry *palinfo_dir;
  745. /*
  746. * This data structure is used to pass which cpu,function is being requested
  747. * It must fit in a 64bit quantity to be passed to the proc callback routine
  748. *
  749. * In SMP mode, when we get a request for another CPU, we must call that
  750. * other CPU using IPI and wait for the result before returning.
  751. */
  752. typedef union {
  753. u64 value;
  754. struct {
  755. unsigned req_cpu: 32; /* for which CPU this info is */
  756. unsigned func_id: 32; /* which function is requested */
  757. } pal_func_cpu;
  758. } pal_func_cpu_u_t;
  759. #define req_cpu pal_func_cpu.req_cpu
  760. #define func_id pal_func_cpu.func_id
  761. #ifdef CONFIG_SMP
  762. /*
  763. * used to hold information about final function to call
  764. */
  765. typedef struct {
  766. palinfo_func_t func; /* pointer to function to call */
  767. char *page; /* buffer to store results */
  768. int ret; /* return value from call */
  769. } palinfo_smp_data_t;
  770. /*
  771. * this function does the actual final call and he called
  772. * from the smp code, i.e., this is the palinfo callback routine
  773. */
  774. static void
  775. palinfo_smp_call(void *info)
  776. {
  777. palinfo_smp_data_t *data = (palinfo_smp_data_t *)info;
  778. data->ret = (*data->func)(data->page);
  779. }
  780. /*
  781. * function called to trigger the IPI, we need to access a remote CPU
  782. * Return:
  783. * 0 : error or nothing to output
  784. * otherwise how many bytes in the "page" buffer were written
  785. */
  786. static
  787. int palinfo_handle_smp(pal_func_cpu_u_t *f, char *page)
  788. {
  789. palinfo_smp_data_t ptr;
  790. int ret;
  791. ptr.func = palinfo_entries[f->func_id].proc_read;
  792. ptr.page = page;
  793. ptr.ret = 0; /* just in case */
  794. /* will send IPI to other CPU and wait for completion of remote call */
  795. if ((ret=smp_call_function_single(f->req_cpu, palinfo_smp_call, &ptr, 1))) {
  796. printk(KERN_ERR "palinfo: remote CPU call from %d to %d on function %d: "
  797. "error %d\n", smp_processor_id(), f->req_cpu, f->func_id, ret);
  798. return 0;
  799. }
  800. return ptr.ret;
  801. }
  802. #else /* ! CONFIG_SMP */
  803. static
  804. int palinfo_handle_smp(pal_func_cpu_u_t *f, char *page)
  805. {
  806. printk(KERN_ERR "palinfo: should not be called with non SMP kernel\n");
  807. return 0;
  808. }
  809. #endif /* CONFIG_SMP */
  810. /*
  811. * Entry point routine: all calls go through this function
  812. */
  813. static int
  814. palinfo_read_entry(char *page, char **start, off_t off, int count, int *eof, void *data)
  815. {
  816. int len=0;
  817. pal_func_cpu_u_t *f = (pal_func_cpu_u_t *)&data;
  818. /*
  819. * in SMP mode, we may need to call another CPU to get correct
  820. * information. PAL, by definition, is processor specific
  821. */
  822. if (f->req_cpu == get_cpu())
  823. len = (*palinfo_entries[f->func_id].proc_read)(page);
  824. else
  825. len = palinfo_handle_smp(f, page);
  826. put_cpu();
  827. if (len <= off+count) *eof = 1;
  828. *start = page + off;
  829. len -= off;
  830. if (len>count) len = count;
  831. if (len<0) len = 0;
  832. return len;
  833. }
  834. static void __cpuinit
  835. create_palinfo_proc_entries(unsigned int cpu)
  836. {
  837. # define CPUSTR "cpu%d"
  838. pal_func_cpu_u_t f;
  839. struct proc_dir_entry **pdir;
  840. struct proc_dir_entry *cpu_dir;
  841. int j;
  842. char cpustr[sizeof(CPUSTR)];
  843. /*
  844. * we keep track of created entries in a depth-first order for
  845. * cleanup purposes. Each entry is stored into palinfo_proc_entries
  846. */
  847. sprintf(cpustr,CPUSTR, cpu);
  848. cpu_dir = proc_mkdir(cpustr, palinfo_dir);
  849. f.req_cpu = cpu;
  850. /*
  851. * Compute the location to store per cpu entries
  852. * We dont store the top level entry in this list, but
  853. * remove it finally after removing all cpu entries.
  854. */
  855. pdir = &palinfo_proc_entries[cpu*(NR_PALINFO_ENTRIES+1)];
  856. *pdir++ = cpu_dir;
  857. for (j=0; j < NR_PALINFO_ENTRIES; j++) {
  858. f.func_id = j;
  859. *pdir = create_proc_read_entry(
  860. palinfo_entries[j].name, 0, cpu_dir,
  861. palinfo_read_entry, (void *)f.value);
  862. pdir++;
  863. }
  864. }
  865. static void
  866. remove_palinfo_proc_entries(unsigned int hcpu)
  867. {
  868. int j;
  869. struct proc_dir_entry *cpu_dir, **pdir;
  870. pdir = &palinfo_proc_entries[hcpu*(NR_PALINFO_ENTRIES+1)];
  871. cpu_dir = *pdir;
  872. *pdir++=NULL;
  873. for (j=0; j < (NR_PALINFO_ENTRIES); j++) {
  874. if ((*pdir)) {
  875. remove_proc_entry ((*pdir)->name, cpu_dir);
  876. *pdir ++= NULL;
  877. }
  878. }
  879. if (cpu_dir) {
  880. remove_proc_entry(cpu_dir->name, palinfo_dir);
  881. }
  882. }
  883. static int __cpuinit palinfo_cpu_callback(struct notifier_block *nfb,
  884. unsigned long action, void *hcpu)
  885. {
  886. unsigned int hotcpu = (unsigned long)hcpu;
  887. switch (action) {
  888. case CPU_ONLINE:
  889. case CPU_ONLINE_FROZEN:
  890. create_palinfo_proc_entries(hotcpu);
  891. break;
  892. case CPU_DEAD:
  893. case CPU_DEAD_FROZEN:
  894. remove_palinfo_proc_entries(hotcpu);
  895. break;
  896. }
  897. return NOTIFY_OK;
  898. }
  899. static struct notifier_block __refdata palinfo_cpu_notifier =
  900. {
  901. .notifier_call = palinfo_cpu_callback,
  902. .priority = 0,
  903. };
  904. static int __init
  905. palinfo_init(void)
  906. {
  907. int i = 0;
  908. printk(KERN_INFO "PAL Information Facility v%s\n", PALINFO_VERSION);
  909. palinfo_dir = proc_mkdir("pal", NULL);
  910. /* Create palinfo dirs in /proc for all online cpus */
  911. for_each_online_cpu(i) {
  912. create_palinfo_proc_entries(i);
  913. }
  914. /* Register for future delivery via notify registration */
  915. register_hotcpu_notifier(&palinfo_cpu_notifier);
  916. return 0;
  917. }
  918. static void __exit
  919. palinfo_exit(void)
  920. {
  921. int i = 0;
  922. /* remove all nodes: depth first pass. Could optimize this */
  923. for_each_online_cpu(i) {
  924. remove_palinfo_proc_entries(i);
  925. }
  926. /*
  927. * Remove the top level entry finally
  928. */
  929. remove_proc_entry(palinfo_dir->name, NULL);
  930. /*
  931. * Unregister from cpu notifier callbacks
  932. */
  933. unregister_hotcpu_notifier(&palinfo_cpu_notifier);
  934. }
  935. module_init(palinfo_init);
  936. module_exit(palinfo_exit);