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