palinfo fixes
[linux-3.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  * 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         unsigned long i, levels, unique_caches;
222         pal_cache_config_info_t cci;
223         int j, k;
224         long 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         long 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                      "Max Purges                     : ",
320                      vm_info_1.pal_vm_info_1_s.phys_add_size,
321                      vm_info_2.pal_vm_info_2_s.impl_va_msb+1,
322                      vm_info_1.pal_vm_info_1_s.max_pkr+1,
323                      vm_info_1.pal_vm_info_1_s.key_size,
324                      vm_info_1.pal_vm_info_1_s.hash_tag_id,
325                      vm_info_2.pal_vm_info_2_s.rid_size);
326                 if (vm_info_2.pal_vm_info_2_s.max_purges == PAL_MAX_PURGES)
327                         p += sprintf(p, "unlimited\n");
328                 else
329                         p += sprintf(p, "%d\n",
330                                 vm_info_2.pal_vm_info_2_s.max_purges ?
331                                 vm_info_2.pal_vm_info_2_s.max_purges : 1);
332         }
333
334         if (ia64_pal_mem_attrib(&attrib) == 0) {
335                 p += sprintf(p, "Supported memory attributes    : ");
336                 sep = "";
337                 for (i = 0; i < 8; i++) {
338                         if (attrib & (1 << i)) {
339                                 p += sprintf(p, "%s%s", sep, mem_attrib[i]);
340                                 sep = ", ";
341                         }
342                 }
343                 p += sprintf(p, "\n");
344         }
345
346         if ((status = ia64_pal_vm_page_size(&tr_pages, &vw_pages)) !=0) {
347                 printk(KERN_ERR "ia64_pal_vm_page_size=%ld\n", status);
348         } else {
349
350                 p += sprintf(p,
351                              "\nTLB walker                     : %simplemented\n"
352                              "Number of DTR                  : %d\n"
353                              "Number of ITR                  : %d\n"
354                              "TLB insertable page sizes      : ",
355                              vm_info_1.pal_vm_info_1_s.vw ? "" : "not ",
356                              vm_info_1.pal_vm_info_1_s.max_dtr_entry+1,
357                              vm_info_1.pal_vm_info_1_s.max_itr_entry+1);
358
359
360                 p = bitvector_process(p, tr_pages);
361
362                 p += sprintf(p, "\nTLB purgeable page sizes       : ");
363
364                 p = bitvector_process(p, vw_pages);
365         }
366         if ((status=ia64_get_ptce(&ptce)) != 0) {
367                 printk(KERN_ERR "ia64_get_ptce=%ld\n", status);
368         } else {
369                 p += sprintf(p,
370                      "\nPurge base address             : 0x%016lx\n"
371                      "Purge outer loop count         : %d\n"
372                      "Purge inner loop count         : %d\n"
373                      "Purge outer loop stride        : %d\n"
374                      "Purge inner loop stride        : %d\n",
375                      ptce.base, ptce.count[0], ptce.count[1],
376                      ptce.stride[0], ptce.stride[1]);
377
378                 p += sprintf(p,
379                      "TC Levels                      : %d\n"
380                      "Unique TC(s)                   : %d\n",
381                      vm_info_1.pal_vm_info_1_s.num_tc_levels,
382                      vm_info_1.pal_vm_info_1_s.max_unique_tcs);
383
384                 for(i=0; i < vm_info_1.pal_vm_info_1_s.num_tc_levels; i++) {
385                         for (j=2; j>0 ; j--) {
386                                 tc_pages = 0; /* just in case */
387
388
389                                 /* even without unification, some levels may not be present */
390                                 if ((status=ia64_pal_vm_info(i,j, &tc_info, &tc_pages)) != 0) {
391                                         continue;
392                                 }
393
394                                 p += sprintf(p,
395                                      "\n%s Translation Cache Level %d:\n"
396                                      "\tHash sets           : %d\n"
397                                      "\tAssociativity       : %d\n"
398                                      "\tNumber of entries   : %d\n"
399                                      "\tFlags               : ",
400                                      cache_types[j+tc_info.tc_unified], i+1,
401                                      tc_info.tc_num_sets,
402                                      tc_info.tc_associativity,
403                                      tc_info.tc_num_entries);
404
405                                 if (tc_info.tc_pf)
406                                         p += sprintf(p, "PreferredPageSizeOptimized ");
407                                 if (tc_info.tc_unified)
408                                         p += sprintf(p, "Unified ");
409                                 if (tc_info.tc_reduce_tr)
410                                         p += sprintf(p, "TCReduction");
411
412                                 p += sprintf(p, "\n\tSupported page sizes: ");
413
414                                 p = bitvector_process(p, tc_pages);
415
416                                 /* when unified date (j=2) is enough */
417                                 if (tc_info.tc_unified)
418                                         break;
419                         }
420                 }
421         }
422         p += sprintf(p, "\n");
423
424         return p - page;
425 }
426
427
428 static int
429 register_info(char *page)
430 {
431         char *p = page;
432         u64 reg_info[2];
433         u64 info;
434         unsigned long phys_stacked;
435         pal_hints_u_t hints;
436         unsigned long iregs, dregs;
437         static const char * const info_type[] = {
438                 "Implemented AR(s)",
439                 "AR(s) with read side-effects",
440                 "Implemented CR(s)",
441                 "CR(s) with read side-effects",
442         };
443
444         for(info=0; info < 4; info++) {
445
446                 if (ia64_pal_register_info(info, &reg_info[0], &reg_info[1]) != 0) return 0;
447
448                 p += sprintf(p, "%-32s : ", info_type[info]);
449
450                 p = bitregister_process(p, reg_info, 128);
451
452                 p += sprintf(p, "\n");
453         }
454
455         if (ia64_pal_rse_info(&phys_stacked, &hints) == 0) {
456
457         p += sprintf(p,
458                      "RSE stacked physical registers   : %ld\n"
459                      "RSE load/store hints             : %ld (%s)\n",
460                      phys_stacked, hints.ph_data,
461                      hints.ph_data < RSE_HINTS_COUNT ? rse_hints[hints.ph_data]: "(??)");
462         }
463         if (ia64_pal_debug_info(&iregs, &dregs))
464                 return 0;
465
466         p += sprintf(p,
467                      "Instruction debug register pairs : %ld\n"
468                      "Data debug register pairs        : %ld\n", iregs, dregs);
469
470         return p - page;
471 }
472
473 static char *proc_features_0[]={                /* Feature set 0 */
474         NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,
475         NULL,NULL,NULL,NULL,NULL,NULL,NULL, NULL,NULL,
476         NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,
477         NULL,NULL,NULL,NULL,NULL, NULL,NULL,NULL,NULL,
478         "Unimplemented instruction address fault",
479         "INIT, PMI, and LINT pins",
480         "Simple unimplemented instr addresses",
481         "Variable P-state performance",
482         "Virtual machine features implemented",
483         "XIP,XPSR,XFS implemented",
484         "XR1-XR3 implemented",
485         "Disable dynamic predicate prediction",
486         "Disable processor physical number",
487         "Disable dynamic data cache prefetch",
488         "Disable dynamic inst cache prefetch",
489         "Disable dynamic branch prediction",
490         NULL, NULL, NULL, NULL,
491         "Disable P-states",
492         "Enable MCA on Data Poisoning",
493         "Enable vmsw instruction",
494         "Enable extern environmental notification",
495         "Disable BINIT on processor time-out",
496         "Disable dynamic power management (DPM)",
497         "Disable coherency",
498         "Disable cache",
499         "Enable CMCI promotion",
500         "Enable MCA to BINIT promotion",
501         "Enable MCA promotion",
502         "Enable BERR promotion"
503 };
504
505 static char *proc_features_16[]={               /* Feature set 16 */
506         "Disable ETM",
507         "Enable ETM",
508         "Enable MCA on half-way timer",
509         "Enable snoop WC",
510         NULL,
511         "Enable Fast Deferral",
512         "Disable MCA on memory aliasing",
513         "Enable RSB",
514         NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
515         "DP system processor",
516         "Low Voltage",
517         "HT supported",
518         NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
519         NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
520         NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
521         NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
522         NULL, NULL, NULL, NULL, NULL
523 };
524
525 static char **proc_features[]={
526         proc_features_0,
527         NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
528         NULL, NULL, NULL, NULL,
529         proc_features_16,
530         NULL, NULL, NULL, NULL,
531 };
532
533 static char * feature_set_info(char *page, u64 avail, u64 status, u64 control,
534                                                         unsigned long set)
535 {
536         char *p = page;
537         char **vf, **v;
538         int i;
539
540         vf = v = proc_features[set];
541         for(i=0; i < 64; i++, avail >>=1, status >>=1, control >>=1) {
542
543                 if (!(control))         /* No remaining bits set */
544                         break;
545                 if (!(avail & 0x1))     /* Print only bits that are available */
546                         continue;
547                 if (vf)
548                         v = vf + i;
549                 if ( v && *v ) {
550                         p += sprintf(p, "%-40s : %s %s\n", *v,
551                                 avail & 0x1 ? (status & 0x1 ?
552                                                 "On " : "Off"): "",
553                                 avail & 0x1 ? (control & 0x1 ?
554                                                 "Ctrl" : "NoCtrl"): "");
555                 } else {
556                         p += sprintf(p, "Feature set %2ld bit %2d\t\t\t"
557                                         " : %s %s\n",
558                                 set, i,
559                                 avail & 0x1 ? (status & 0x1 ?
560                                                 "On " : "Off"): "",
561                                 avail & 0x1 ? (control & 0x1 ?
562                                                 "Ctrl" : "NoCtrl"): "");
563                 }
564         }
565         return p;
566 }
567
568 static int
569 processor_info(char *page)
570 {
571         char *p = page;
572         u64 avail=1, status=1, control=1, feature_set=0;
573         s64 ret;
574
575         do {
576                 ret = ia64_pal_proc_get_features(&avail, &status, &control,
577                                                 feature_set);
578                 if (ret < 0) {
579                         return p - page;
580                 }
581                 if (ret == 1) {
582                         feature_set++;
583                         continue;
584                 }
585
586                 p = feature_set_info(p, avail, status, control, feature_set);
587
588                 feature_set++;
589         } while(1);
590
591         return p - page;
592 }
593
594 static const char *bus_features[]={
595         NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,
596         NULL,NULL,NULL,NULL,NULL,NULL,NULL, NULL,NULL,
597         NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,
598         NULL,NULL,
599         "Request  Bus Parking",
600         "Bus Lock Mask",
601         "Enable Half Transfer",
602         NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
603         NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
604         NULL, NULL, NULL, NULL,
605         "Enable Cache Line Repl. Shared",
606         "Enable Cache Line Repl. Exclusive",
607         "Disable Transaction Queuing",
608         "Disable Response Error Checking",
609         "Disable Bus Error Checking",
610         "Disable Bus Requester Internal Error Signalling",
611         "Disable Bus Requester Error Signalling",
612         "Disable Bus Initialization Event Checking",
613         "Disable Bus Initialization Event Signalling",
614         "Disable Bus Address Error Checking",
615         "Disable Bus Address Error Signalling",
616         "Disable Bus Data Error Checking"
617 };
618
619
620 static int
621 bus_info(char *page)
622 {
623         char *p = page;
624         const char **v = bus_features;
625         pal_bus_features_u_t av, st, ct;
626         u64 avail, status, control;
627         int i;
628         s64 ret;
629
630         if ((ret=ia64_pal_bus_get_features(&av, &st, &ct)) != 0) return 0;
631
632         avail   = av.pal_bus_features_val;
633         status  = st.pal_bus_features_val;
634         control = ct.pal_bus_features_val;
635
636         for(i=0; i < 64; i++, v++, avail >>=1, status >>=1, control >>=1) {
637                 if ( ! *v ) continue;
638                 p += sprintf(p, "%-48s : %s%s %s\n", *v,
639                                 avail & 0x1 ? "" : "NotImpl",
640                                 avail & 0x1 ? (status  & 0x1 ? "On" : "Off"): "",
641                                 avail & 0x1 ? (control & 0x1 ? "Ctrl" : "NoCtrl"): "");
642         }
643         return p - page;
644 }
645
646 static int
647 version_info(char *page)
648 {
649         pal_version_u_t min_ver, cur_ver;
650         char *p = page;
651
652         if (ia64_pal_version(&min_ver, &cur_ver) != 0)
653                 return 0;
654
655         p += sprintf(p,
656                      "PAL_vendor : 0x%02x (min=0x%02x)\n"
657                      "PAL_A      : %02x.%02x (min=%02x.%02x)\n"
658                      "PAL_B      : %02x.%02x (min=%02x.%02x)\n",
659                      cur_ver.pal_version_s.pv_pal_vendor,
660                      min_ver.pal_version_s.pv_pal_vendor,
661                      cur_ver.pal_version_s.pv_pal_a_model,
662                      cur_ver.pal_version_s.pv_pal_a_rev,
663                      min_ver.pal_version_s.pv_pal_a_model,
664                      min_ver.pal_version_s.pv_pal_a_rev,
665                      cur_ver.pal_version_s.pv_pal_b_model,
666                      cur_ver.pal_version_s.pv_pal_b_rev,
667                      min_ver.pal_version_s.pv_pal_b_model,
668                      min_ver.pal_version_s.pv_pal_b_rev);
669         return p - page;
670 }
671
672 static int
673 perfmon_info(char *page)
674 {
675         char *p = page;
676         u64 pm_buffer[16];
677         pal_perf_mon_info_u_t pm_info;
678
679         if (ia64_pal_perf_mon_info(pm_buffer, &pm_info) != 0) return 0;
680
681         p += sprintf(p,
682                      "PMC/PMD pairs                 : %d\n"
683                      "Counter width                 : %d bits\n"
684                      "Cycle event number            : %d\n"
685                      "Retired event number          : %d\n"
686                      "Implemented PMC               : ",
687                      pm_info.pal_perf_mon_info_s.generic, pm_info.pal_perf_mon_info_s.width,
688                      pm_info.pal_perf_mon_info_s.cycles, pm_info.pal_perf_mon_info_s.retired);
689
690         p = bitregister_process(p, pm_buffer, 256);
691         p += sprintf(p, "\nImplemented PMD               : ");
692         p = bitregister_process(p, pm_buffer+4, 256);
693         p += sprintf(p, "\nCycles count capable          : ");
694         p = bitregister_process(p, pm_buffer+8, 256);
695         p += sprintf(p, "\nRetired bundles count capable : ");
696
697 #ifdef CONFIG_ITANIUM
698         /*
699          * PAL_PERF_MON_INFO reports that only PMC4 can be used to count CPU_CYCLES
700          * which is wrong, both PMC4 and PMD5 support it.
701          */
702         if (pm_buffer[12] == 0x10) pm_buffer[12]=0x30;
703 #endif
704
705         p = bitregister_process(p, pm_buffer+12, 256);
706
707         p += sprintf(p, "\n");
708
709         return p - page;
710 }
711
712 static int
713 frequency_info(char *page)
714 {
715         char *p = page;
716         struct pal_freq_ratio proc, itc, bus;
717         unsigned long base;
718
719         if (ia64_pal_freq_base(&base) == -1)
720                 p += sprintf(p, "Output clock            : not implemented\n");
721         else
722                 p += sprintf(p, "Output clock            : %ld ticks/s\n", base);
723
724         if (ia64_pal_freq_ratios(&proc, &bus, &itc) != 0) return 0;
725
726         p += sprintf(p,
727                      "Processor/Clock ratio   : %d/%d\n"
728                      "Bus/Clock ratio         : %d/%d\n"
729                      "ITC/Clock ratio         : %d/%d\n",
730                      proc.num, proc.den, bus.num, bus.den, itc.num, itc.den);
731
732         return p - page;
733 }
734
735 static int
736 tr_info(char *page)
737 {
738         char *p = page;
739         long status;
740         pal_tr_valid_u_t tr_valid;
741         u64 tr_buffer[4];
742         pal_vm_info_1_u_t vm_info_1;
743         pal_vm_info_2_u_t vm_info_2;
744         unsigned long i, j;
745         unsigned long max[3], pgm;
746         struct ifa_reg {
747                 unsigned long valid:1;
748                 unsigned long ig:11;
749                 unsigned long vpn:52;
750         } *ifa_reg;
751         struct itir_reg {
752                 unsigned long rv1:2;
753                 unsigned long ps:6;
754                 unsigned long key:24;
755                 unsigned long rv2:32;
756         } *itir_reg;
757         struct gr_reg {
758                 unsigned long p:1;
759                 unsigned long rv1:1;
760                 unsigned long ma:3;
761                 unsigned long a:1;
762                 unsigned long d:1;
763                 unsigned long pl:2;
764                 unsigned long ar:3;
765                 unsigned long ppn:38;
766                 unsigned long rv2:2;
767                 unsigned long ed:1;
768                 unsigned long ig:11;
769         } *gr_reg;
770         struct rid_reg {
771                 unsigned long ig1:1;
772                 unsigned long rv1:1;
773                 unsigned long ig2:6;
774                 unsigned long rid:24;
775                 unsigned long rv2:32;
776         } *rid_reg;
777
778         if ((status = ia64_pal_vm_summary(&vm_info_1, &vm_info_2)) !=0) {
779                 printk(KERN_ERR "ia64_pal_vm_summary=%ld\n", status);
780                 return 0;
781         }
782         max[0] = vm_info_1.pal_vm_info_1_s.max_itr_entry+1;
783         max[1] = vm_info_1.pal_vm_info_1_s.max_dtr_entry+1;
784
785         for (i=0; i < 2; i++ ) {
786                 for (j=0; j < max[i]; j++) {
787
788                 status = ia64_pal_tr_read(j, i, tr_buffer, &tr_valid);
789                 if (status != 0) {
790                         printk(KERN_ERR "palinfo: pal call failed on tr[%lu:%lu]=%ld\n",
791                                i, j, status);
792                         continue;
793                 }
794
795                 ifa_reg  = (struct ifa_reg *)&tr_buffer[2];
796
797                 if (ifa_reg->valid == 0) continue;
798
799                 gr_reg   = (struct gr_reg *)tr_buffer;
800                 itir_reg = (struct itir_reg *)&tr_buffer[1];
801                 rid_reg  = (struct rid_reg *)&tr_buffer[3];
802
803                 pgm      = -1 << (itir_reg->ps - 12);
804                 p += sprintf(p,
805                              "%cTR%lu: av=%d pv=%d dv=%d mv=%d\n"
806                              "\tppn  : 0x%lx\n"
807                              "\tvpn  : 0x%lx\n"
808                              "\tps   : ",
809                              "ID"[i], j,
810                              tr_valid.pal_tr_valid_s.access_rights_valid,
811                              tr_valid.pal_tr_valid_s.priv_level_valid,
812                              tr_valid.pal_tr_valid_s.dirty_bit_valid,
813                              tr_valid.pal_tr_valid_s.mem_attr_valid,
814                              (gr_reg->ppn & pgm)<< 12, (ifa_reg->vpn & pgm)<< 12);
815
816                 p = bitvector_process(p, 1<< itir_reg->ps);
817
818                 p += sprintf(p,
819                              "\n\tpl   : %d\n"
820                              "\tar   : %d\n"
821                              "\trid  : %x\n"
822                              "\tp    : %d\n"
823                              "\tma   : %d\n"
824                              "\td    : %d\n",
825                              gr_reg->pl, gr_reg->ar, rid_reg->rid, gr_reg->p, gr_reg->ma,
826                              gr_reg->d);
827                 }
828         }
829         return p - page;
830 }
831
832
833
834 /*
835  * List {name,function} pairs for every entry in /proc/palinfo/cpu*
836  */
837 static palinfo_entry_t palinfo_entries[]={
838         { "version_info",       version_info, },
839         { "vm_info",            vm_info, },
840         { "cache_info",         cache_info, },
841         { "power_info",         power_info, },
842         { "register_info",      register_info, },
843         { "processor_info",     processor_info, },
844         { "perfmon_info",       perfmon_info, },
845         { "frequency_info",     frequency_info, },
846         { "bus_info",           bus_info },
847         { "tr_info",            tr_info, }
848 };
849
850 #define NR_PALINFO_ENTRIES      (int) ARRAY_SIZE(palinfo_entries)
851
852 static struct proc_dir_entry *palinfo_dir;
853
854 /*
855  * This data structure is used to pass which cpu,function is being requested
856  * It must fit in a 64bit quantity to be passed to the proc callback routine
857  *
858  * In SMP mode, when we get a request for another CPU, we must call that
859  * other CPU using IPI and wait for the result before returning.
860  */
861 typedef union {
862         u64 value;
863         struct {
864                 unsigned        req_cpu: 32;    /* for which CPU this info is */
865                 unsigned        func_id: 32;    /* which function is requested */
866         } pal_func_cpu;
867 } pal_func_cpu_u_t;
868
869 #define req_cpu pal_func_cpu.req_cpu
870 #define func_id pal_func_cpu.func_id
871
872 #ifdef CONFIG_SMP
873
874 /*
875  * used to hold information about final function to call
876  */
877 typedef struct {
878         palinfo_func_t  func;   /* pointer to function to call */
879         char            *page;  /* buffer to store results */
880         int             ret;    /* return value from call */
881 } palinfo_smp_data_t;
882
883
884 /*
885  * this function does the actual final call and he called
886  * from the smp code, i.e., this is the palinfo callback routine
887  */
888 static void
889 palinfo_smp_call(void *info)
890 {
891         palinfo_smp_data_t *data = (palinfo_smp_data_t *)info;
892         data->ret = (*data->func)(data->page);
893 }
894
895 /*
896  * function called to trigger the IPI, we need to access a remote CPU
897  * Return:
898  *      0 : error or nothing to output
899  *      otherwise how many bytes in the "page" buffer were written
900  */
901 static
902 int palinfo_handle_smp(pal_func_cpu_u_t *f, char *page)
903 {
904         palinfo_smp_data_t ptr;
905         int ret;
906
907         ptr.func = palinfo_entries[f->func_id].proc_read;
908         ptr.page = page;
909         ptr.ret  = 0; /* just in case */
910
911
912         /* will send IPI to other CPU and wait for completion of remote call */
913         if ((ret=smp_call_function_single(f->req_cpu, palinfo_smp_call, &ptr, 1))) {
914                 printk(KERN_ERR "palinfo: remote CPU call from %d to %d on function %d: "
915                        "error %d\n", smp_processor_id(), f->req_cpu, f->func_id, ret);
916                 return 0;
917         }
918         return ptr.ret;
919 }
920 #else /* ! CONFIG_SMP */
921 static
922 int palinfo_handle_smp(pal_func_cpu_u_t *f, char *page)
923 {
924         printk(KERN_ERR "palinfo: should not be called with non SMP kernel\n");
925         return 0;
926 }
927 #endif /* CONFIG_SMP */
928
929 /*
930  * Entry point routine: all calls go through this function
931  */
932 static int
933 palinfo_read_entry(char *page, char **start, off_t off, int count, int *eof, void *data)
934 {
935         int len=0;
936         pal_func_cpu_u_t *f = (pal_func_cpu_u_t *)&data;
937
938         /*
939          * in SMP mode, we may need to call another CPU to get correct
940          * information. PAL, by definition, is processor specific
941          */
942         if (f->req_cpu == get_cpu())
943                 len = (*palinfo_entries[f->func_id].proc_read)(page);
944         else
945                 len = palinfo_handle_smp(f, page);
946
947         put_cpu();
948
949         if (len <= off+count) *eof = 1;
950
951         *start = page + off;
952         len   -= off;
953
954         if (len>count) len = count;
955         if (len<0) len = 0;
956
957         return len;
958 }
959
960 static void __cpuinit
961 create_palinfo_proc_entries(unsigned int cpu)
962 {
963         pal_func_cpu_u_t f;
964         struct proc_dir_entry *cpu_dir;
965         int j;
966         char cpustr[3+4+1];     /* cpu numbers are up to 4095 on itanic */
967         sprintf(cpustr, "cpu%d", cpu);
968
969         cpu_dir = proc_mkdir(cpustr, palinfo_dir);
970         if (!cpu_dir)
971                 return;
972
973         f.req_cpu = cpu;
974
975         for (j=0; j < NR_PALINFO_ENTRIES; j++) {
976                 f.func_id = j;
977                 create_proc_read_entry(
978                         palinfo_entries[j].name, 0, cpu_dir,
979                         palinfo_read_entry, (void *)f.value);
980         }
981 }
982
983 static void
984 remove_palinfo_proc_entries(unsigned int hcpu)
985 {
986         char cpustr[3+4+1];     /* cpu numbers are up to 4095 on itanic */
987         sprintf(cpustr, "cpu%d", hcpu);
988         remove_proc_subtree(cpustr, palinfo_dir);
989 }
990
991 static int __cpuinit palinfo_cpu_callback(struct notifier_block *nfb,
992                                         unsigned long action, void *hcpu)
993 {
994         unsigned int hotcpu = (unsigned long)hcpu;
995
996         switch (action) {
997         case CPU_ONLINE:
998         case CPU_ONLINE_FROZEN:
999                 create_palinfo_proc_entries(hotcpu);
1000                 break;
1001         case CPU_DEAD:
1002         case CPU_DEAD_FROZEN:
1003                 remove_palinfo_proc_entries(hotcpu);
1004                 break;
1005         }
1006         return NOTIFY_OK;
1007 }
1008
1009 static struct notifier_block __refdata palinfo_cpu_notifier =
1010 {
1011         .notifier_call = palinfo_cpu_callback,
1012         .priority = 0,
1013 };
1014
1015 static int __init
1016 palinfo_init(void)
1017 {
1018         int i = 0;
1019
1020         printk(KERN_INFO "PAL Information Facility v%s\n", PALINFO_VERSION);
1021         palinfo_dir = proc_mkdir("pal", NULL);
1022         if (!palinfo_dir)
1023                 return -ENOMEM;
1024
1025         /* Create palinfo dirs in /proc for all online cpus */
1026         for_each_online_cpu(i) {
1027                 create_palinfo_proc_entries(i);
1028         }
1029
1030         /* Register for future delivery via notify registration */
1031         register_hotcpu_notifier(&palinfo_cpu_notifier);
1032
1033         return 0;
1034 }
1035
1036 static void __exit
1037 palinfo_exit(void)
1038 {
1039         unregister_hotcpu_notifier(&palinfo_cpu_notifier);
1040         remove_proc_subtree("pal", NULL);
1041 }
1042
1043 module_init(palinfo_init);
1044 module_exit(palinfo_exit);