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