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