Merge branch '83xx' into for_paulus
[linux-2.6] / 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  * 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  */
20 #include <linux/types.h>
21 #include <linux/errno.h>
22 #include <linux/init.h>
23 #include <linux/proc_fs.h>
24 #include <linux/mm.h>
25 #include <linux/module.h>
26 #include <linux/efi.h>
27 #include <linux/notifier.h>
28 #include <linux/cpu.h>
29 #include <linux/cpumask.h>
30
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
37 MODULE_AUTHOR("Stephane Eranian <eranian@hpl.hp.com>");
38 MODULE_DESCRIPTION("/proc interface to IA-64 PAL");
39 MODULE_LICENSE("GPL");
40
41 #define PALINFO_VERSION "0.5"
42
43 typedef int (*palinfo_func_t)(char*);
44
45 typedef struct {
46         const char              *name;          /* name of the proc entry */
47         palinfo_func_t          proc_read;      /* function to call for reading */
48         struct proc_dir_entry   *entry;         /* registered entry (removal) */
49 } palinfo_entry_t;
50
51
52 /*
53  *  A bunch of string array to get pretty printing
54  */
55
56 static char *cache_types[] = {
57         "",                     /* not used */
58         "Instruction",
59         "Data",
60         "Data/Instruction"      /* unified */
61 };
62
63 static const char *cache_mattrib[]={
64         "WriteThrough",
65         "WriteBack",
66         "",             /* reserved */
67         ""              /* reserved */
68 };
69
70 static const char *cache_st_hints[]={
71         "Temporal, level 1",
72         "Reserved",
73         "Reserved",
74         "Non-temporal, all levels",
75         "Reserved",
76         "Reserved",
77         "Reserved",
78         "Reserved"
79 };
80
81 static const char *cache_ld_hints[]={
82         "Temporal, level 1",
83         "Non-temporal, level 1",
84         "Reserved",
85         "Non-temporal, all levels",
86         "Reserved",
87         "Reserved",
88         "Reserved",
89         "Reserved"
90 };
91
92 static const char *rse_hints[]={
93         "enforced lazy",
94         "eager stores",
95         "eager loads",
96         "eager loads and stores"
97 };
98
99 #define RSE_HINTS_COUNT ARRAY_SIZE(rse_hints)
100
101 static const char *mem_attrib[]={
102         "WB",           /* 000 */
103         "SW",           /* 001 */
104         "010",          /* 010 */
105         "011",          /* 011 */
106         "UC",           /* 100 */
107         "UCE",          /* 101 */
108         "WC",           /* 110 */
109         "NaTPage"       /* 111 */
110 };
111
112 /*
113  * Take a 64bit vector and produces a string such that
114  * if bit n is set then 2^n in clear text is generated. The adjustment
115  * to the right unit is also done.
116  *
117  * Input:
118  *      - a pointer to a buffer to hold the string
119  *      - a 64-bit vector
120  * Ouput:
121  *      - a pointer to the end of the buffer
122  *
123  */
124 static char *
125 bitvector_process(char *p, u64 vector)
126 {
127         int i,j;
128         const char *units[]={ "", "K", "M", "G", "T" };
129
130         for (i=0, j=0; i < 64; i++ , j=i/10) {
131                 if (vector & 0x1) {
132                         p += sprintf(p, "%d%s ", 1 << (i-j*10), units[j]);
133                 }
134                 vector >>= 1;
135         }
136         return p;
137 }
138
139 /*
140  * Take a 64bit vector and produces a string such that
141  * if bit n is set then register n is present. The function
142  * takes into account consecutive registers and prints out ranges.
143  *
144  * Input:
145  *      - a pointer to a buffer to hold the string
146  *      - a 64-bit vector
147  * Ouput:
148  *      - a pointer to the end of the buffer
149  *
150  */
151 static char *
152 bitregister_process(char *p, u64 *reg_info, int max)
153 {
154         int i, begin, skip = 0;
155         u64 value = reg_info[0];
156
157         value >>= i = begin = ffs(value) - 1;
158
159         for(; i < max; i++ ) {
160
161                 if (i != 0 && (i%64) == 0) value = *++reg_info;
162
163                 if ((value & 0x1) == 0 && skip == 0) {
164                         if (begin  <= i - 2)
165                                 p += sprintf(p, "%d-%d ", begin, i-1);
166                         else
167                                 p += sprintf(p, "%d ", i-1);
168                         skip  = 1;
169                         begin = -1;
170                 } else if ((value & 0x1) && skip == 1) {
171                         skip = 0;
172                         begin = i;
173                 }
174                 value >>=1;
175         }
176         if (begin > -1) {
177                 if (begin < 127)
178                         p += sprintf(p, "%d-127", begin);
179                 else
180                         p += sprintf(p, "127");
181         }
182
183         return p;
184 }
185
186 static int
187 power_info(char *page)
188 {
189         s64 status;
190         char *p = page;
191         u64 halt_info_buffer[8];
192         pal_power_mgmt_info_u_t *halt_info =(pal_power_mgmt_info_u_t *)halt_info_buffer;
193         int i;
194
195         status = ia64_pal_halt_info(halt_info);
196         if (status != 0) return 0;
197
198         for (i=0; i < 8 ; i++ ) {
199                 if (halt_info[i].pal_power_mgmt_info_s.im == 1) {
200                         p += sprintf(p, "Power level %d:\n"
201                                      "\tentry_latency       : %d cycles\n"
202                                      "\texit_latency        : %d cycles\n"
203                                      "\tpower consumption   : %d mW\n"
204                                      "\tCache+TLB coherency : %s\n", i,
205                                      halt_info[i].pal_power_mgmt_info_s.entry_latency,
206                                      halt_info[i].pal_power_mgmt_info_s.exit_latency,
207                                      halt_info[i].pal_power_mgmt_info_s.power_consumption,
208                                      halt_info[i].pal_power_mgmt_info_s.co ? "Yes" : "No");
209                 } else {
210                         p += sprintf(p,"Power level %d: not implemented\n",i);
211                 }
212         }
213         return p - page;
214 }
215
216 static int
217 cache_info(char *page)
218 {
219         char *p = page;
220         u64 i, levels, unique_caches;
221         pal_cache_config_info_t cci;
222         int j, k;
223         s64 status;
224
225         if ((status = ia64_pal_cache_summary(&levels, &unique_caches)) != 0) {
226                 printk(KERN_ERR "ia64_pal_cache_summary=%ld\n", status);
227                 return 0;
228         }
229
230         p += sprintf(p, "Cache levels  : %ld\nUnique caches : %ld\n\n", levels, unique_caches);
231
232         for (i=0; i < levels; i++) {
233
234                 for (j=2; j >0 ; j--) {
235
236                         /* even without unification some level may not be present */
237                         if ((status=ia64_pal_cache_config_info(i,j, &cci)) != 0) {
238                                 continue;
239                         }
240                         p += sprintf(p,
241                                      "%s Cache level %lu:\n"
242                                      "\tSize           : %u bytes\n"
243                                      "\tAttributes     : ",
244                                      cache_types[j+cci.pcci_unified], i+1,
245                                      cci.pcci_cache_size);
246
247                         if (cci.pcci_unified) p += sprintf(p, "Unified ");
248
249                         p += sprintf(p, "%s\n", cache_mattrib[cci.pcci_cache_attr]);
250
251                         p += sprintf(p,
252                                      "\tAssociativity  : %d\n"
253                                      "\tLine size      : %d bytes\n"
254                                      "\tStride         : %d bytes\n",
255                                      cci.pcci_assoc, 1<<cci.pcci_line_size, 1<<cci.pcci_stride);
256                         if (j == 1)
257                                 p += sprintf(p, "\tStore latency  : N/A\n");
258                         else
259                                 p += sprintf(p, "\tStore latency  : %d cycle(s)\n",
260                                                 cci.pcci_st_latency);
261
262                         p += sprintf(p,
263                                      "\tLoad latency   : %d cycle(s)\n"
264                                      "\tStore hints    : ", cci.pcci_ld_latency);
265
266                         for(k=0; k < 8; k++ ) {
267                                 if ( cci.pcci_st_hints & 0x1)
268                                         p += sprintf(p, "[%s]", cache_st_hints[k]);
269                                 cci.pcci_st_hints >>=1;
270                         }
271                         p += sprintf(p, "\n\tLoad hints     : ");
272
273                         for(k=0; k < 8; k++ ) {
274                                 if (cci.pcci_ld_hints & 0x1)
275                                         p += sprintf(p, "[%s]", cache_ld_hints[k]);
276                                 cci.pcci_ld_hints >>=1;
277                         }
278                         p += sprintf(p,
279                                      "\n\tAlias boundary : %d byte(s)\n"
280                                      "\tTag LSB        : %d\n"
281                                      "\tTag MSB        : %d\n",
282                                      1<<cci.pcci_alias_boundary, cci.pcci_tag_lsb,
283                                      cci.pcci_tag_msb);
284
285                         /* when unified, data(j=2) is enough */
286                         if (cci.pcci_unified) break;
287                 }
288         }
289         return p - page;
290 }
291
292
293 static int
294 vm_info(char *page)
295 {
296         char *p = page;
297         u64 tr_pages =0, vw_pages=0, tc_pages;
298         u64 attrib;
299         pal_vm_info_1_u_t vm_info_1;
300         pal_vm_info_2_u_t vm_info_2;
301         pal_tc_info_u_t tc_info;
302         ia64_ptce_info_t ptce;
303         const char *sep;
304         int i, j;
305         s64 status;
306
307         if ((status = ia64_pal_vm_summary(&vm_info_1, &vm_info_2)) !=0) {
308                 printk(KERN_ERR "ia64_pal_vm_summary=%ld\n", status);
309         } else {
310
311                 p += sprintf(p,
312                      "Physical Address Space         : %d bits\n"
313                      "Virtual Address Space          : %d bits\n"
314                      "Protection Key Registers(PKR)  : %d\n"
315                      "Implemented bits in PKR.key    : %d\n"
316                      "Hash Tag ID                    : 0x%x\n"
317                      "Size of RR.rid                 : %d\n",
318                      vm_info_1.pal_vm_info_1_s.phys_add_size,
319                      vm_info_2.pal_vm_info_2_s.impl_va_msb+1,
320                      vm_info_1.pal_vm_info_1_s.max_pkr+1,
321                      vm_info_1.pal_vm_info_1_s.key_size,
322                      vm_info_1.pal_vm_info_1_s.hash_tag_id,
323                      vm_info_2.pal_vm_info_2_s.rid_size);
324         }
325
326         if (ia64_pal_mem_attrib(&attrib) == 0) {
327                 p += sprintf(p, "Supported memory attributes    : ");
328                 sep = "";
329                 for (i = 0; i < 8; i++) {
330                         if (attrib & (1 << i)) {
331                                 p += sprintf(p, "%s%s", sep, mem_attrib[i]);
332                                 sep = ", ";
333                         }
334                 }
335                 p += sprintf(p, "\n");
336         }
337
338         if ((status = ia64_pal_vm_page_size(&tr_pages, &vw_pages)) !=0) {
339                 printk(KERN_ERR "ia64_pal_vm_page_size=%ld\n", status);
340         } else {
341
342                 p += sprintf(p,
343                              "\nTLB walker                     : %simplemented\n"
344                              "Number of DTR                  : %d\n"
345                              "Number of ITR                  : %d\n"
346                              "TLB insertable page sizes      : ",
347                              vm_info_1.pal_vm_info_1_s.vw ? "" : "not ",
348                              vm_info_1.pal_vm_info_1_s.max_dtr_entry+1,
349                              vm_info_1.pal_vm_info_1_s.max_itr_entry+1);
350
351
352                 p = bitvector_process(p, tr_pages);
353
354                 p += sprintf(p, "\nTLB purgeable page sizes       : ");
355
356                 p = bitvector_process(p, vw_pages);
357         }
358         if ((status=ia64_get_ptce(&ptce)) != 0) {
359                 printk(KERN_ERR "ia64_get_ptce=%ld\n", status);
360         } else {
361                 p += sprintf(p,
362                      "\nPurge base address             : 0x%016lx\n"
363                      "Purge outer loop count         : %d\n"
364                      "Purge inner loop count         : %d\n"
365                      "Purge outer loop stride        : %d\n"
366                      "Purge inner loop stride        : %d\n",
367                      ptce.base, ptce.count[0], ptce.count[1],
368                      ptce.stride[0], ptce.stride[1]);
369
370                 p += sprintf(p,
371                      "TC Levels                      : %d\n"
372                      "Unique TC(s)                   : %d\n",
373                      vm_info_1.pal_vm_info_1_s.num_tc_levels,
374                      vm_info_1.pal_vm_info_1_s.max_unique_tcs);
375
376                 for(i=0; i < vm_info_1.pal_vm_info_1_s.num_tc_levels; i++) {
377                         for (j=2; j>0 ; j--) {
378                                 tc_pages = 0; /* just in case */
379
380
381                                 /* even without unification, some levels may not be present */
382                                 if ((status=ia64_pal_vm_info(i,j, &tc_info, &tc_pages)) != 0) {
383                                         continue;
384                                 }
385
386                                 p += sprintf(p,
387                                      "\n%s Translation Cache Level %d:\n"
388                                      "\tHash sets           : %d\n"
389                                      "\tAssociativity       : %d\n"
390                                      "\tNumber of entries   : %d\n"
391                                      "\tFlags               : ",
392                                      cache_types[j+tc_info.tc_unified], i+1,
393                                      tc_info.tc_num_sets,
394                                      tc_info.tc_associativity,
395                                      tc_info.tc_num_entries);
396
397                                 if (tc_info.tc_pf)
398                                         p += sprintf(p, "PreferredPageSizeOptimized ");
399                                 if (tc_info.tc_unified)
400                                         p += sprintf(p, "Unified ");
401                                 if (tc_info.tc_reduce_tr)
402                                         p += sprintf(p, "TCReduction");
403
404                                 p += sprintf(p, "\n\tSupported page sizes: ");
405
406                                 p = bitvector_process(p, tc_pages);
407
408                                 /* when unified date (j=2) is enough */
409                                 if (tc_info.tc_unified)
410                                         break;
411                         }
412                 }
413         }
414         p += sprintf(p, "\n");
415
416         return p - page;
417 }
418
419
420 static int
421 register_info(char *page)
422 {
423         char *p = page;
424         u64 reg_info[2];
425         u64 info;
426         u64 phys_stacked;
427         pal_hints_u_t hints;
428         u64 iregs, dregs;
429         char *info_type[]={
430                 "Implemented AR(s)",
431                 "AR(s) with read side-effects",
432                 "Implemented CR(s)",
433                 "CR(s) with read side-effects",
434         };
435
436         for(info=0; info < 4; info++) {
437
438                 if (ia64_pal_register_info(info, &reg_info[0], &reg_info[1]) != 0) return 0;
439
440                 p += sprintf(p, "%-32s : ", info_type[info]);
441
442                 p = bitregister_process(p, reg_info, 128);
443
444                 p += sprintf(p, "\n");
445         }
446
447         if (ia64_pal_rse_info(&phys_stacked, &hints) == 0) {
448
449         p += sprintf(p,
450                      "RSE stacked physical registers   : %ld\n"
451                      "RSE load/store hints             : %ld (%s)\n",
452                      phys_stacked, hints.ph_data,
453                      hints.ph_data < RSE_HINTS_COUNT ? rse_hints[hints.ph_data]: "(??)");
454         }
455         if (ia64_pal_debug_info(&iregs, &dregs))
456                 return 0;
457
458         p += sprintf(p,
459                      "Instruction debug register pairs : %ld\n"
460                      "Data debug register pairs        : %ld\n", 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 BERR 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. Shared",
523         "Enable Cache Line Repl. Exclusive",
524         "Disable Transaction Queuing",
525         "Disable Response 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,
578                      "PAL_vendor : 0x%02x (min=0x%02x)\n"
579                      "PAL_A      : %x.%x.%x (min=%x.%x.%x)\n"
580                      "PAL_B      : %x.%x.%x (min=%x.%x.%x)\n",
581                      cur_ver.pal_version_s.pv_pal_vendor, 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, cur_ver.pal_version_s.pv_pal_a_rev,
585                      min_ver.pal_version_s.pv_pal_a_model>>4,
586                      min_ver.pal_version_s.pv_pal_a_model&0xf, min_ver.pal_version_s.pv_pal_a_rev,
587
588                      cur_ver.pal_version_s.pv_pal_b_model>>4,
589                      cur_ver.pal_version_s.pv_pal_b_model&0xf, cur_ver.pal_version_s.pv_pal_b_rev,
590                      min_ver.pal_version_s.pv_pal_b_model>>4,
591                      min_ver.pal_version_s.pv_pal_b_model&0xf, min_ver.pal_version_s.pv_pal_b_rev);
592         return p - page;
593 }
594
595 static int
596 perfmon_info(char *page)
597 {
598         char *p = page;
599         u64 pm_buffer[16];
600         pal_perf_mon_info_u_t pm_info;
601
602         if (ia64_pal_perf_mon_info(pm_buffer, &pm_info) != 0) return 0;
603
604         p += sprintf(p,
605                      "PMC/PMD pairs                 : %d\n"
606                      "Counter width                 : %d bits\n"
607                      "Cycle event number            : %d\n"
608                      "Retired event number          : %d\n"
609                      "Implemented PMC               : ",
610                      pm_info.pal_perf_mon_info_s.generic, pm_info.pal_perf_mon_info_s.width,
611                      pm_info.pal_perf_mon_info_s.cycles, pm_info.pal_perf_mon_info_s.retired);
612
613         p = bitregister_process(p, pm_buffer, 256);
614         p += sprintf(p, "\nImplemented PMD               : ");
615         p = bitregister_process(p, pm_buffer+4, 256);
616         p += sprintf(p, "\nCycles count capable          : ");
617         p = bitregister_process(p, pm_buffer+8, 256);
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,
650                      "Processor/Clock ratio   : %d/%d\n"
651                      "Bus/Clock ratio         : %d/%d\n"
652                      "ITC/Clock ratio         : %d/%d\n",
653                      proc.num, proc.den, bus.num, bus.den, itc.num, itc.den);
654
655         return p - page;
656 }
657
658 static int
659 tr_info(char *page)
660 {
661         char *p = page;
662         s64 status;
663         pal_tr_valid_u_t tr_valid;
664         u64 tr_buffer[4];
665         pal_vm_info_1_u_t vm_info_1;
666         pal_vm_info_2_u_t vm_info_2;
667         u64 i, j;
668         u64 max[3], pgm;
669         struct ifa_reg {
670                 u64 valid:1;
671                 u64 ig:11;
672                 u64 vpn:52;
673         } *ifa_reg;
674         struct itir_reg {
675                 u64 rv1:2;
676                 u64 ps:6;
677                 u64 key:24;
678                 u64 rv2:32;
679         } *itir_reg;
680         struct gr_reg {
681                 u64 p:1;
682                 u64 rv1:1;
683                 u64 ma:3;
684                 u64 a:1;
685                 u64 d:1;
686                 u64 pl:2;
687                 u64 ar:3;
688                 u64 ppn:38;
689                 u64 rv2:2;
690                 u64 ed:1;
691                 u64 ig:11;
692         } *gr_reg;
693         struct rid_reg {
694                 u64 ig1:1;
695                 u64 rv1:1;
696                 u64 ig2:6;
697                 u64 rid:24;
698                 u64 rv2:32;
699         } *rid_reg;
700
701         if ((status = ia64_pal_vm_summary(&vm_info_1, &vm_info_2)) !=0) {
702                 printk(KERN_ERR "ia64_pal_vm_summary=%ld\n", status);
703                 return 0;
704         }
705         max[0] = vm_info_1.pal_vm_info_1_s.max_itr_entry+1;
706         max[1] = vm_info_1.pal_vm_info_1_s.max_dtr_entry+1;
707
708         for (i=0; i < 2; i++ ) {
709                 for (j=0; j < max[i]; j++) {
710
711                 status = ia64_pal_tr_read(j, i, tr_buffer, &tr_valid);
712                 if (status != 0) {
713                         printk(KERN_ERR "palinfo: pal call failed on tr[%lu:%lu]=%ld\n",
714                                i, j, status);
715                         continue;
716                 }
717
718                 ifa_reg  = (struct ifa_reg *)&tr_buffer[2];
719
720                 if (ifa_reg->valid == 0) continue;
721
722                 gr_reg   = (struct gr_reg *)tr_buffer;
723                 itir_reg = (struct itir_reg *)&tr_buffer[1];
724                 rid_reg  = (struct rid_reg *)&tr_buffer[3];
725
726                 pgm      = -1 << (itir_reg->ps - 12);
727                 p += sprintf(p,
728                              "%cTR%lu: av=%d pv=%d dv=%d mv=%d\n"
729                              "\tppn  : 0x%lx\n"
730                              "\tvpn  : 0x%lx\n"
731                              "\tps   : ",
732                              "ID"[i], j,
733                              tr_valid.pal_tr_valid_s.access_rights_valid,
734                              tr_valid.pal_tr_valid_s.priv_level_valid,
735                              tr_valid.pal_tr_valid_s.dirty_bit_valid,
736                              tr_valid.pal_tr_valid_s.mem_attr_valid,
737                              (gr_reg->ppn & pgm)<< 12, (ifa_reg->vpn & pgm)<< 12);
738
739                 p = bitvector_process(p, 1<< itir_reg->ps);
740
741                 p += sprintf(p,
742                              "\n\tpl   : %d\n"
743                              "\tar   : %d\n"
744                              "\trid  : %x\n"
745                              "\tp    : %d\n"
746                              "\tma   : %d\n"
747                              "\td    : %d\n",
748                              gr_reg->pl, gr_reg->ar, rid_reg->rid, gr_reg->p, gr_reg->ma,
749                              gr_reg->d);
750                 }
751         }
752         return p - page;
753 }
754
755
756
757 /*
758  * List {name,function} pairs for every entry in /proc/palinfo/cpu*
759  */
760 static palinfo_entry_t palinfo_entries[]={
761         { "version_info",       version_info, },
762         { "vm_info",            vm_info, },
763         { "cache_info",         cache_info, },
764         { "power_info",         power_info, },
765         { "register_info",      register_info, },
766         { "processor_info",     processor_info, },
767         { "perfmon_info",       perfmon_info, },
768         { "frequency_info",     frequency_info, },
769         { "bus_info",           bus_info },
770         { "tr_info",            tr_info, }
771 };
772
773 #define NR_PALINFO_ENTRIES      (int) ARRAY_SIZE(palinfo_entries)
774
775 /*
776  * this array is used to keep track of the proc entries we create. This is
777  * required in the module mode when we need to remove all entries. The procfs code
778  * does not do recursion of deletion
779  *
780  * Notes:
781  *      - +1 accounts for the cpuN directory entry in /proc/pal
782  */
783 #define NR_PALINFO_PROC_ENTRIES (NR_CPUS*(NR_PALINFO_ENTRIES+1))
784
785 static struct proc_dir_entry *palinfo_proc_entries[NR_PALINFO_PROC_ENTRIES];
786 static struct proc_dir_entry *palinfo_dir;
787
788 /*
789  * This data structure is used to pass which cpu,function is being requested
790  * It must fit in a 64bit quantity to be passed to the proc callback routine
791  *
792  * In SMP mode, when we get a request for another CPU, we must call that
793  * other CPU using IPI and wait for the result before returning.
794  */
795 typedef union {
796         u64 value;
797         struct {
798                 unsigned        req_cpu: 32;    /* for which CPU this info is */
799                 unsigned        func_id: 32;    /* which function is requested */
800         } pal_func_cpu;
801 } pal_func_cpu_u_t;
802
803 #define req_cpu pal_func_cpu.req_cpu
804 #define func_id pal_func_cpu.func_id
805
806 #ifdef CONFIG_SMP
807
808 /*
809  * used to hold information about final function to call
810  */
811 typedef struct {
812         palinfo_func_t  func;   /* pointer to function to call */
813         char            *page;  /* buffer to store results */
814         int             ret;    /* return value from call */
815 } palinfo_smp_data_t;
816
817
818 /*
819  * this function does the actual final call and he called
820  * from the smp code, i.e., this is the palinfo callback routine
821  */
822 static void
823 palinfo_smp_call(void *info)
824 {
825         palinfo_smp_data_t *data = (palinfo_smp_data_t *)info;
826         if (data == NULL) {
827                 printk(KERN_ERR "palinfo: data pointer is NULL\n");
828                 data->ret = 0; /* no output */
829                 return;
830         }
831         /* does this actual call */
832         data->ret = (*data->func)(data->page);
833 }
834
835 /*
836  * function called to trigger the IPI, we need to access a remote CPU
837  * Return:
838  *      0 : error or nothing to output
839  *      otherwise how many bytes in the "page" buffer were written
840  */
841 static
842 int palinfo_handle_smp(pal_func_cpu_u_t *f, char *page)
843 {
844         palinfo_smp_data_t ptr;
845         int ret;
846
847         ptr.func = palinfo_entries[f->func_id].proc_read;
848         ptr.page = page;
849         ptr.ret  = 0; /* just in case */
850
851
852         /* will send IPI to other CPU and wait for completion of remote call */
853         if ((ret=smp_call_function_single(f->req_cpu, palinfo_smp_call, &ptr, 0, 1))) {
854                 printk(KERN_ERR "palinfo: remote CPU call from %d to %d on function %d: "
855                        "error %d\n", smp_processor_id(), f->req_cpu, f->func_id, ret);
856                 return 0;
857         }
858         return ptr.ret;
859 }
860 #else /* ! CONFIG_SMP */
861 static
862 int palinfo_handle_smp(pal_func_cpu_u_t *f, char *page)
863 {
864         printk(KERN_ERR "palinfo: should not be called with non SMP kernel\n");
865         return 0;
866 }
867 #endif /* CONFIG_SMP */
868
869 /*
870  * Entry point routine: all calls go through this function
871  */
872 static int
873 palinfo_read_entry(char *page, char **start, off_t off, int count, int *eof, void *data)
874 {
875         int len=0;
876         pal_func_cpu_u_t *f = (pal_func_cpu_u_t *)&data;
877
878         /*
879          * in SMP mode, we may need to call another CPU to get correct
880          * information. PAL, by definition, is processor specific
881          */
882         if (f->req_cpu == get_cpu())
883                 len = (*palinfo_entries[f->func_id].proc_read)(page);
884         else
885                 len = palinfo_handle_smp(f, page);
886
887         put_cpu();
888
889         if (len <= off+count) *eof = 1;
890
891         *start = page + off;
892         len   -= off;
893
894         if (len>count) len = count;
895         if (len<0) len = 0;
896
897         return len;
898 }
899
900 static void
901 create_palinfo_proc_entries(unsigned int cpu)
902 {
903 #       define CPUSTR   "cpu%d"
904
905         pal_func_cpu_u_t f;
906         struct proc_dir_entry **pdir;
907         struct proc_dir_entry *cpu_dir;
908         int j;
909         char cpustr[sizeof(CPUSTR)];
910
911
912         /*
913          * we keep track of created entries in a depth-first order for
914          * cleanup purposes. Each entry is stored into palinfo_proc_entries
915          */
916         sprintf(cpustr,CPUSTR, cpu);
917
918         cpu_dir = proc_mkdir(cpustr, palinfo_dir);
919
920         f.req_cpu = cpu;
921
922         /*
923          * Compute the location to store per cpu entries
924          * We dont store the top level entry in this list, but
925          * remove it finally after removing all cpu entries.
926          */
927         pdir = &palinfo_proc_entries[cpu*(NR_PALINFO_ENTRIES+1)];
928         *pdir++ = cpu_dir;
929         for (j=0; j < NR_PALINFO_ENTRIES; j++) {
930                 f.func_id = j;
931                 *pdir = create_proc_read_entry(
932                                 palinfo_entries[j].name, 0, cpu_dir,
933                                 palinfo_read_entry, (void *)f.value);
934                 if (*pdir)
935                         (*pdir)->owner = THIS_MODULE;
936                 pdir++;
937         }
938 }
939
940 static void
941 remove_palinfo_proc_entries(unsigned int hcpu)
942 {
943         int j;
944         struct proc_dir_entry *cpu_dir, **pdir;
945
946         pdir = &palinfo_proc_entries[hcpu*(NR_PALINFO_ENTRIES+1)];
947         cpu_dir = *pdir;
948         *pdir++=NULL;
949         for (j=0; j < (NR_PALINFO_ENTRIES); j++) {
950                 if ((*pdir)) {
951                         remove_proc_entry ((*pdir)->name, cpu_dir);
952                         *pdir ++= NULL;
953                 }
954         }
955
956         if (cpu_dir) {
957                 remove_proc_entry(cpu_dir->name, palinfo_dir);
958         }
959 }
960
961 static int __cpuinit palinfo_cpu_callback(struct notifier_block *nfb,
962                                                                 unsigned long action,
963                                                                 void *hcpu)
964 {
965         unsigned int hotcpu = (unsigned long)hcpu;
966
967         switch (action) {
968         case CPU_ONLINE:
969                 create_palinfo_proc_entries(hotcpu);
970                 break;
971 #ifdef CONFIG_HOTPLUG_CPU
972         case CPU_DEAD:
973                 remove_palinfo_proc_entries(hotcpu);
974                 break;
975 #endif
976         }
977         return NOTIFY_OK;
978 }
979
980 static struct notifier_block __cpuinitdata palinfo_cpu_notifier =
981 {
982         .notifier_call = palinfo_cpu_callback,
983         .priority = 0,
984 };
985
986 static int __init
987 palinfo_init(void)
988 {
989         int i = 0;
990
991         printk(KERN_INFO "PAL Information Facility v%s\n", PALINFO_VERSION);
992         palinfo_dir = proc_mkdir("pal", NULL);
993
994         /* Create palinfo dirs in /proc for all online cpus */
995         for_each_online_cpu(i) {
996                 create_palinfo_proc_entries(i);
997         }
998
999         /* Register for future delivery via notify registration */
1000         register_hotcpu_notifier(&palinfo_cpu_notifier);
1001
1002         return 0;
1003 }
1004
1005 static void __exit
1006 palinfo_exit(void)
1007 {
1008         int i = 0;
1009
1010         /* remove all nodes: depth first pass. Could optimize this  */
1011         for_each_online_cpu(i) {
1012                 remove_palinfo_proc_entries(i);
1013         }
1014
1015         /*
1016          * Remove the top level entry finally
1017          */
1018         remove_proc_entry(palinfo_dir->name, NULL);
1019
1020         /*
1021          * Unregister from cpu notifier callbacks
1022          */
1023         unregister_cpu_notifier(&palinfo_cpu_notifier);
1024 }
1025
1026 module_init(palinfo_init);
1027 module_exit(palinfo_exit);