ALSA: pcm: Move PCM_RUNTIME_CHECK() macro into local header
[linux-2.6-block.git] / arch / ia64 / kernel / palinfo.c
CommitLineData
09c434b8 1// SPDX-License-Identifier: GPL-2.0-only
1da177e4
LT
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
895309ff 20 * 10/26/2006 Russ Anderson updated processor features to rev 2.2 spec
1da177e4 21 */
1da177e4
LT
22#include <linux/types.h>
23#include <linux/errno.h>
24#include <linux/init.h>
25#include <linux/proc_fs.h>
e781c3d7 26#include <linux/seq_file.h>
1da177e4
LT
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
e781c3d7 46typedef int (*palinfo_func_t)(struct seq_file *);
1da177e4
LT
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
e781c3d7 59static const char *cache_types[] = {
1da177e4
LT
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 */
e781c3d7 127static void bitvector_process(struct seq_file *m, u64 vector)
1da177e4
LT
128{
129 int i,j;
e781c3d7 130 static const char *units[]={ "", "K", "M", "G", "T" };
1da177e4
LT
131
132 for (i=0, j=0; i < 64; i++ , j=i/10) {
e781c3d7
DH
133 if (vector & 0x1)
134 seq_printf(m, "%d%s ", 1 << (i-j*10), units[j]);
1da177e4
LT
135 vector >>= 1;
136 }
1da177e4
LT
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 */
e781c3d7 151static void bitregister_process(struct seq_file *m, u64 *reg_info, int max)
1da177e4
LT
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)
e781c3d7 164 seq_printf(m, "%d-%d ", begin, i-1);
1da177e4 165 else
e781c3d7 166 seq_printf(m, "%d ", i-1);
1da177e4
LT
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)
e781c3d7 177 seq_printf(m, "%d-127", begin);
1da177e4 178 else
e781c3d7 179 seq_puts(m, "127");
1da177e4 180 }
1da177e4
LT
181}
182
e781c3d7 183static int power_info(struct seq_file *m)
1da177e4
LT
184{
185 s64 status;
1da177e4
LT
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) {
e781c3d7
DH
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");
1da177e4 205 } else {
e781c3d7 206 seq_printf(m,"Power level %d: not implemented\n", i);
1da177e4
LT
207 }
208 }
e781c3d7 209 return 0;
1da177e4
LT
210}
211
e781c3d7 212static int cache_info(struct seq_file *m)
1da177e4 213{
e088a4ad 214 unsigned long i, levels, unique_caches;
1da177e4
LT
215 pal_cache_config_info_t cci;
216 int j, k;
e088a4ad 217 long status;
1da177e4
LT
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
e781c3d7
DH
224 seq_printf(m, "Cache levels : %ld\nUnique caches : %ld\n\n",
225 levels, unique_caches);
1da177e4
LT
226
227 for (i=0; i < levels; i++) {
1da177e4 228 for (j=2; j >0 ; j--) {
1da177e4 229 /* even without unification some level may not be present */
e781c3d7 230 if ((status=ia64_pal_cache_config_info(i,j, &cci)) != 0)
1da177e4 231 continue;
e781c3d7
DH
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);
1da177e4 252 if (j == 1)
e781c3d7 253 seq_puts(m, "\tStore latency : N/A\n");
1da177e4 254 else
e781c3d7
DH
255 seq_printf(m, "\tStore latency : %d cycle(s)\n",
256 cci.pcci_st_latency);
1da177e4 257
e781c3d7
DH
258 seq_printf(m,
259 "\tLoad latency : %d cycle(s)\n"
260 "\tStore hints : ", cci.pcci_ld_latency);
1da177e4
LT
261
262 for(k=0; k < 8; k++ ) {
263 if ( cci.pcci_st_hints & 0x1)
e781c3d7 264 seq_printf(m, "[%s]", cache_st_hints[k]);
1da177e4
LT
265 cci.pcci_st_hints >>=1;
266 }
e781c3d7 267 seq_puts(m, "\n\tLoad hints : ");
1da177e4
LT
268
269 for(k=0; k < 8; k++ ) {
270 if (cci.pcci_ld_hints & 0x1)
e781c3d7 271 seq_printf(m, "[%s]", cache_ld_hints[k]);
1da177e4
LT
272 cci.pcci_ld_hints >>=1;
273 }
e781c3d7
DH
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);
1da177e4
LT
280
281 /* when unified, data(j=2) is enough */
e781c3d7
DH
282 if (cci.pcci_unified)
283 break;
1da177e4
LT
284 }
285 }
e781c3d7 286 return 0;
1da177e4
LT
287}
288
289
e781c3d7 290static int vm_info(struct seq_file *m)
1da177e4 291{
1da177e4
LT
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;
e088a4ad 300 long status;
1da177e4
LT
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);
714d2dc1 304 } else {
1da177e4 305
e781c3d7 306 seq_printf(m,
1da177e4
LT
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"
5b4d5681
RA
312 "Size of RR.rid : %d\n"
313 "Max Purges : ",
1da177e4 314 vm_info_1.pal_vm_info_1_s.phys_add_size,
714d2dc1
PC
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,
1da177e4 319 vm_info_2.pal_vm_info_2_s.rid_size);
5b4d5681 320 if (vm_info_2.pal_vm_info_2_s.max_purges == PAL_MAX_PURGES)
e781c3d7 321 seq_puts(m, "unlimited\n");
5b4d5681 322 else
e781c3d7 323 seq_printf(m, "%d\n",
5b4d5681
RA
324 vm_info_2.pal_vm_info_2_s.max_purges ?
325 vm_info_2.pal_vm_info_2_s.max_purges : 1);
714d2dc1 326 }
1da177e4 327
714d2dc1 328 if (ia64_pal_mem_attrib(&attrib) == 0) {
e781c3d7 329 seq_puts(m, "Supported memory attributes : ");
714d2dc1
PC
330 sep = "";
331 for (i = 0; i < 8; i++) {
332 if (attrib & (1 << i)) {
e781c3d7 333 seq_printf(m, "%s%s", sep, mem_attrib[i]);
714d2dc1
PC
334 sep = ", ";
335 }
1da177e4 336 }
e781c3d7 337 seq_putc(m, '\n');
1da177e4 338 }
1da177e4
LT
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);
714d2dc1 342 } else {
1da177e4 343
e781c3d7
DH
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);
1da177e4 352
e781c3d7 353 bitvector_process(m, tr_pages);
1da177e4 354
e781c3d7 355 seq_puts(m, "\nTLB purgeable page sizes : ");
1da177e4 356
e781c3d7 357 bitvector_process(m, vw_pages);
714d2dc1 358 }
e781c3d7
DH
359
360 if ((status = ia64_get_ptce(&ptce)) != 0) {
1da177e4 361 printk(KERN_ERR "ia64_get_ptce=%ld\n", status);
714d2dc1 362 } else {
e781c3d7 363 seq_printf(m,
1da177e4
LT
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",
714d2dc1
PC
369 ptce.base, ptce.count[0], ptce.count[1],
370 ptce.stride[0], ptce.stride[1]);
1da177e4 371
e781c3d7 372 seq_printf(m,
1da177e4
LT
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
714d2dc1
PC
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 */
1da177e4 381
714d2dc1 382 /* even without unification, some levels may not be present */
e781c3d7 383 if ((status=ia64_pal_vm_info(i,j, &tc_info, &tc_pages)) != 0)
714d2dc1 384 continue;
1da177e4 385
e781c3d7 386 seq_printf(m,
1da177e4
LT
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 : ",
714d2dc1
PC
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);
1da177e4 396
714d2dc1 397 if (tc_info.tc_pf)
e781c3d7 398 seq_puts(m, "PreferredPageSizeOptimized ");
714d2dc1 399 if (tc_info.tc_unified)
e781c3d7 400 seq_puts(m, "Unified ");
714d2dc1 401 if (tc_info.tc_reduce_tr)
e781c3d7 402 seq_puts(m, "TCReduction");
1da177e4 403
e781c3d7 404 seq_puts(m, "\n\tSupported page sizes: ");
1da177e4 405
e781c3d7 406 bitvector_process(m, tc_pages);
1da177e4 407
714d2dc1
PC
408 /* when unified date (j=2) is enough */
409 if (tc_info.tc_unified)
410 break;
411 }
1da177e4
LT
412 }
413 }
1da177e4 414
e781c3d7
DH
415 seq_putc(m, '\n');
416 return 0;
1da177e4
LT
417}
418
419
e781c3d7 420static int register_info(struct seq_file *m)
1da177e4 421{
1da177e4
LT
422 u64 reg_info[2];
423 u64 info;
e088a4ad 424 unsigned long phys_stacked;
1da177e4 425 pal_hints_u_t hints;
e088a4ad 426 unsigned long iregs, dregs;
c216488c 427 static const char * const info_type[] = {
1da177e4
LT
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++) {
e781c3d7
DH
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');
1da177e4
LT
440 }
441
e781c3d7
DH
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]: "(??)");
1da177e4 448
1da177e4
LT
449 if (ia64_pal_debug_info(&iregs, &dregs))
450 return 0;
451
e781c3d7
DH
452 seq_printf(m,
453 "Instruction debug register pairs : %ld\n"
454 "Data debug register pairs : %ld\n", iregs, dregs);
1da177e4 455
e781c3d7 456 return 0;
1da177e4
LT
457}
458
e781c3d7 459static const char *const proc_features_0[]={ /* Feature set 0 */
1da177e4
LT
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,
895309ff
RA
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",
1da177e4
LT
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",
895309ff
RA
476 NULL, NULL, NULL, NULL,
477 "Disable P-states",
478 "Enable MCA on Data Poisoning",
479 "Enable vmsw instruction",
480 "Enable extern environmental notification",
1da177e4
LT
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
e781c3d7 491static const char *const proc_features_16[]={ /* Feature set 16 */
b8de471f
RA
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
e781c3d7 511static const char *const *const proc_features[]={
b8de471f
RA
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
e781c3d7
DH
519static void feature_set_info(struct seq_file *m, u64 avail, u64 status, u64 control,
520 unsigned long set)
b8de471f 521{
e781c3d7 522 const char *const *vf, *const *v;
b8de471f
RA
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 ) {
e781c3d7 535 seq_printf(m, "%-40s : %s %s\n", *v,
b8de471f 536 avail & 0x1 ? (status & 0x1 ?
e781c3d7 537 "On " : "Off"): "",
b8de471f
RA
538 avail & 0x1 ? (control & 0x1 ?
539 "Ctrl" : "NoCtrl"): "");
540 } else {
e781c3d7 541 seq_printf(m, "Feature set %2ld bit %2d\t\t\t"
b8de471f
RA
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 }
b8de471f 550}
1da177e4 551
e781c3d7 552static int processor_info(struct seq_file *m)
1da177e4 553{
b8de471f 554 u64 avail=1, status=1, control=1, feature_set=0;
1da177e4
LT
555 s64 ret;
556
b8de471f
RA
557 do {
558 ret = ia64_pal_proc_get_features(&avail, &status, &control,
559 feature_set);
e781c3d7
DH
560 if (ret < 0)
561 return 0;
562
b8de471f
RA
563 if (ret == 1) {
564 feature_set++;
565 continue;
566 }
567
e781c3d7 568 feature_set_info(m, avail, status, control, feature_set);
b8de471f
RA
569 feature_set++;
570 } while(1);
1da177e4 571
e781c3d7 572 return 0;
1da177e4
LT
573}
574
e781c3d7 575static const char *const bus_features[]={
1da177e4
LT
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
e781c3d7 601static int bus_info(struct seq_file *m)
1da177e4 602{
e781c3d7 603 const char *const *v = bus_features;
1da177e4
LT
604 pal_bus_features_u_t av, st, ct;
605 u64 avail, status, control;
606 int i;
607 s64 ret;
608
e781c3d7
DH
609 if ((ret=ia64_pal_bus_get_features(&av, &st, &ct)) != 0)
610 return 0;
1da177e4
LT
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) {
e781c3d7
DH
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"): "");
1da177e4 623 }
e781c3d7 624 return 0;
1da177e4
LT
625}
626
e781c3d7 627static int version_info(struct seq_file *m)
1da177e4
LT
628{
629 pal_version_u_t min_ver, cur_ver;
1da177e4 630
1bf1eba7
MW
631 if (ia64_pal_version(&min_ver, &cur_ver) != 0)
632 return 0;
1da177e4 633
e781c3d7
DH
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;
1da177e4
LT
649}
650
e781c3d7 651static int perfmon_info(struct seq_file *m)
1da177e4 652{
1da177e4
LT
653 u64 pm_buffer[16];
654 pal_perf_mon_info_u_t pm_info;
655
e781c3d7
DH
656 if (ia64_pal_perf_mon_info(pm_buffer, &pm_info) != 0)
657 return 0;
1da177e4 658
e781c3d7
DH
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 : ");
1da177e4
LT
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 */
e781c3d7
DH
682 if (pm_buffer[12] == 0x10)
683 pm_buffer[12]=0x30;
1da177e4
LT
684#endif
685
e781c3d7
DH
686 bitregister_process(m, pm_buffer+12, 256);
687 seq_putc(m, '\n');
688 return 0;
1da177e4
LT
689}
690
e781c3d7 691static int frequency_info(struct seq_file *m)
1da177e4 692{
1da177e4 693 struct pal_freq_ratio proc, itc, bus;
e088a4ad 694 unsigned long base;
1da177e4
LT
695
696 if (ia64_pal_freq_base(&base) == -1)
e781c3d7 697 seq_puts(m, "Output clock : not implemented\n");
1da177e4 698 else
e781c3d7 699 seq_printf(m, "Output clock : %ld ticks/s\n", base);
1da177e4
LT
700
701 if (ia64_pal_freq_ratios(&proc, &bus, &itc) != 0) return 0;
702
e781c3d7 703 seq_printf(m,
2ab9391d
TL
704 "Processor/Clock ratio : %d/%d\n"
705 "Bus/Clock ratio : %d/%d\n"
706 "ITC/Clock ratio : %d/%d\n",
1da177e4 707 proc.num, proc.den, bus.num, bus.den, itc.num, itc.den);
e781c3d7 708 return 0;
1da177e4
LT
709}
710
e781c3d7 711static int tr_info(struct seq_file *m)
1da177e4 712{
e088a4ad 713 long status;
1da177e4
LT
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;
e088a4ad
MW
718 unsigned long i, j;
719 unsigned long max[3], pgm;
1da177e4 720 struct ifa_reg {
e088a4ad
MW
721 unsigned long valid:1;
722 unsigned long ig:11;
723 unsigned long vpn:52;
1da177e4
LT
724 } *ifa_reg;
725 struct itir_reg {
e088a4ad
MW
726 unsigned long rv1:2;
727 unsigned long ps:6;
728 unsigned long key:24;
729 unsigned long rv2:32;
1da177e4
LT
730 } *itir_reg;
731 struct gr_reg {
e088a4ad
MW
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;
1da177e4
LT
743 } *gr_reg;
744 struct rid_reg {
e088a4ad
MW
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;
1da177e4
LT
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
e781c3d7
DH
771 if (ifa_reg->valid == 0)
772 continue;
1da177e4
LT
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);
e781c3d7
DH
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);
1da177e4
LT
802 }
803 }
e781c3d7 804 return 0;
1da177e4
LT
805}
806
807
808
809/*
810 * List {name,function} pairs for every entry in /proc/palinfo/cpu*
811 */
e781c3d7 812static const palinfo_entry_t palinfo_entries[]={
1da177e4
LT
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
1da177e4
LT
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 */
e781c3d7 854 struct seq_file *m; /* buffer to store results */
1da177e4
LT
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;
e781c3d7 867 data->ret = (*data->func)(data->m);
1da177e4
LT
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
e781c3d7 877int palinfo_handle_smp(struct seq_file *m, pal_func_cpu_u_t *f)
1da177e4
LT
878{
879 palinfo_smp_data_t ptr;
880 int ret;
881
882 ptr.func = palinfo_entries[f->func_id].proc_read;
e781c3d7 883 ptr.m = m;
1da177e4
LT
884 ptr.ret = 0; /* just in case */
885
886
887 /* will send IPI to other CPU and wait for completion of remote call */
8691e5a8 888 if ((ret=smp_call_function_single(f->req_cpu, palinfo_smp_call, &ptr, 1))) {
1da177e4
LT
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
e781c3d7 897int palinfo_handle_smp(struct seq_file *m, pal_func_cpu_u_t *f)
1da177e4
LT
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 */
e781c3d7 907static int proc_palinfo_show(struct seq_file *m, void *v)
1da177e4 908{
e781c3d7 909 pal_func_cpu_u_t *f = (pal_func_cpu_u_t *)&m->private;
1da177e4
LT
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())
e781c3d7 916 (*palinfo_entries[f->func_id].proc_read)(m);
1da177e4 917 else
e781c3d7 918 palinfo_handle_smp(m, f);
1da177e4
LT
919
920 put_cpu();
e781c3d7
DH
921 return 0;
922}
1da177e4 923
715c3211 924static int palinfo_add_proc(unsigned int cpu)
1da177e4 925{
1da177e4 926 pal_func_cpu_u_t f;
1da177e4
LT
927 struct proc_dir_entry *cpu_dir;
928 int j;
ccf93204
AV
929 char cpustr[3+4+1]; /* cpu numbers are up to 4095 on itanic */
930 sprintf(cpustr, "cpu%d", cpu);
1da177e4
LT
931
932 cpu_dir = proc_mkdir(cpustr, palinfo_dir);
ccf93204 933 if (!cpu_dir)
715c3211 934 return -EINVAL;
1da177e4
LT
935
936 f.req_cpu = cpu;
937
1da177e4
LT
938 for (j=0; j < NR_PALINFO_ENTRIES; j++) {
939 f.func_id = j;
3f3942ac
CH
940 proc_create_single_data(palinfo_entries[j].name, 0, cpu_dir,
941 proc_palinfo_show, (void *)f.value);
1da177e4 942 }
715c3211 943 return 0;
1da177e4
LT
944}
945
715c3211 946static int palinfo_del_proc(unsigned int hcpu)
1da177e4 947{
ccf93204 948 char cpustr[3+4+1]; /* cpu numbers are up to 4095 on itanic */
715c3211 949
ccf93204
AV
950 sprintf(cpustr, "cpu%d", hcpu);
951 remove_proc_subtree(cpustr, palinfo_dir);
715c3211 952 return 0;
1da177e4
LT
953}
954
715c3211 955static enum cpuhp_state hp_online;
1da177e4 956
715c3211 957static int __init palinfo_init(void)
1da177e4
LT
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);
ccf93204
AV
963 if (!palinfo_dir)
964 return -ENOMEM;
1da177e4 965
715c3211
SAS
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;
1da177e4 971 }
715c3211 972 hp_online = i;
1da177e4
LT
973 return 0;
974}
975
715c3211 976static void __exit palinfo_exit(void)
1da177e4 977{
715c3211 978 cpuhp_remove_state(hp_online);
ccf93204 979 remove_proc_subtree("pal", NULL);
1da177e4
LT
980}
981
982module_init(palinfo_init);
983module_exit(palinfo_exit);