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