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