palinfo.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:24k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

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