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