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