1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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;
50 palinfo_func_t proc_read;
51 struct proc_dir_entry *entry;
52} palinfo_entry_t;
53
54
55
56
57
58
59static const char *cache_types[] = {
60 "",
61 "Instruction",
62 "Data",
63 "Data/Instruction"
64};
65
66static const char *cache_mattrib[]={
67 "WriteThrough",
68 "WriteBack",
69 "",
70 ""
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",
106 "SW",
107 "010",
108 "011",
109 "UC",
110 "UCE",
111 "WC",
112 "NaTPage"
113};
114
115
116
117
118
119
120
121
122
123
124
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
141
142
143
144
145
146
147
148
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
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
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;
381
382
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
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[]={
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[]={
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))
529 break;
530 if (!(avail & 0x1))
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 frequency_info(struct seq_file *m)
652{
653 struct pal_freq_ratio proc, itc, bus;
654 unsigned long base;
655
656 if (ia64_pal_freq_base(&base) == -1)
657 seq_puts(m, "Output clock : not implemented\n");
658 else
659 seq_printf(m, "Output clock : %ld ticks/s\n", base);
660
661 if (ia64_pal_freq_ratios(&proc, &bus, &itc) != 0) return 0;
662
663 seq_printf(m,
664 "Processor/Clock ratio : %d/%d\n"
665 "Bus/Clock ratio : %d/%d\n"
666 "ITC/Clock ratio : %d/%d\n",
667 proc.num, proc.den, bus.num, bus.den, itc.num, itc.den);
668 return 0;
669}
670
671static int tr_info(struct seq_file *m)
672{
673 long status;
674 pal_tr_valid_u_t tr_valid;
675 u64 tr_buffer[4];
676 pal_vm_info_1_u_t vm_info_1;
677 pal_vm_info_2_u_t vm_info_2;
678 unsigned long i, j;
679 unsigned long max[3], pgm;
680 struct ifa_reg {
681 unsigned long valid:1;
682 unsigned long ig:11;
683 unsigned long vpn:52;
684 } *ifa_reg;
685 struct itir_reg {
686 unsigned long rv1:2;
687 unsigned long ps:6;
688 unsigned long key:24;
689 unsigned long rv2:32;
690 } *itir_reg;
691 struct gr_reg {
692 unsigned long p:1;
693 unsigned long rv1:1;
694 unsigned long ma:3;
695 unsigned long a:1;
696 unsigned long d:1;
697 unsigned long pl:2;
698 unsigned long ar:3;
699 unsigned long ppn:38;
700 unsigned long rv2:2;
701 unsigned long ed:1;
702 unsigned long ig:11;
703 } *gr_reg;
704 struct rid_reg {
705 unsigned long ig1:1;
706 unsigned long rv1:1;
707 unsigned long ig2:6;
708 unsigned long rid:24;
709 unsigned long rv2:32;
710 } *rid_reg;
711
712 if ((status = ia64_pal_vm_summary(&vm_info_1, &vm_info_2)) !=0) {
713 printk(KERN_ERR "ia64_pal_vm_summary=%ld\n", status);
714 return 0;
715 }
716 max[0] = vm_info_1.pal_vm_info_1_s.max_itr_entry+1;
717 max[1] = vm_info_1.pal_vm_info_1_s.max_dtr_entry+1;
718
719 for (i=0; i < 2; i++ ) {
720 for (j=0; j < max[i]; j++) {
721
722 status = ia64_pal_tr_read(j, i, tr_buffer, &tr_valid);
723 if (status != 0) {
724 printk(KERN_ERR "palinfo: pal call failed on tr[%lu:%lu]=%ld\n",
725 i, j, status);
726 continue;
727 }
728
729 ifa_reg = (struct ifa_reg *)&tr_buffer[2];
730
731 if (ifa_reg->valid == 0)
732 continue;
733
734 gr_reg = (struct gr_reg *)tr_buffer;
735 itir_reg = (struct itir_reg *)&tr_buffer[1];
736 rid_reg = (struct rid_reg *)&tr_buffer[3];
737
738 pgm = -1 << (itir_reg->ps - 12);
739 seq_printf(m,
740 "%cTR%lu: av=%d pv=%d dv=%d mv=%d\n"
741 "\tppn : 0x%lx\n"
742 "\tvpn : 0x%lx\n"
743 "\tps : ",
744 "ID"[i], j,
745 tr_valid.pal_tr_valid_s.access_rights_valid,
746 tr_valid.pal_tr_valid_s.priv_level_valid,
747 tr_valid.pal_tr_valid_s.dirty_bit_valid,
748 tr_valid.pal_tr_valid_s.mem_attr_valid,
749 (gr_reg->ppn & pgm)<< 12, (ifa_reg->vpn & pgm)<< 12);
750
751 bitvector_process(m, 1<< itir_reg->ps);
752
753 seq_printf(m,
754 "\n\tpl : %d\n"
755 "\tar : %d\n"
756 "\trid : %x\n"
757 "\tp : %d\n"
758 "\tma : %d\n"
759 "\td : %d\n",
760 gr_reg->pl, gr_reg->ar, rid_reg->rid, gr_reg->p, gr_reg->ma,
761 gr_reg->d);
762 }
763 }
764 return 0;
765}
766
767
768
769
770
771
772static const palinfo_entry_t palinfo_entries[]={
773 { "version_info", version_info, },
774 { "vm_info", vm_info, },
775 { "cache_info", cache_info, },
776 { "power_info", power_info, },
777 { "register_info", register_info, },
778 { "processor_info", processor_info, },
779 { "frequency_info", frequency_info, },
780 { "bus_info", bus_info },
781 { "tr_info", tr_info, }
782};
783
784#define NR_PALINFO_ENTRIES (int) ARRAY_SIZE(palinfo_entries)
785
786static struct proc_dir_entry *palinfo_dir;
787
788
789
790
791
792
793
794
795typedef union {
796 u64 value;
797 struct {
798 unsigned req_cpu: 32;
799 unsigned func_id: 32;
800 } pal_func_cpu;
801} pal_func_cpu_u_t;
802
803#define req_cpu pal_func_cpu.req_cpu
804#define func_id pal_func_cpu.func_id
805
806#ifdef CONFIG_SMP
807
808
809
810
811typedef struct {
812 palinfo_func_t func;
813 struct seq_file *m;
814 int ret;
815} palinfo_smp_data_t;
816
817
818
819
820
821
822static void
823palinfo_smp_call(void *info)
824{
825 palinfo_smp_data_t *data = (palinfo_smp_data_t *)info;
826 data->ret = (*data->func)(data->m);
827}
828
829
830
831
832
833
834
835static
836int palinfo_handle_smp(struct seq_file *m, pal_func_cpu_u_t *f)
837{
838 palinfo_smp_data_t ptr;
839 int ret;
840
841 ptr.func = palinfo_entries[f->func_id].proc_read;
842 ptr.m = m;
843 ptr.ret = 0;
844
845
846
847 if ((ret=smp_call_function_single(f->req_cpu, palinfo_smp_call, &ptr, 1))) {
848 printk(KERN_ERR "palinfo: remote CPU call from %d to %d on function %d: "
849 "error %d\n", smp_processor_id(), f->req_cpu, f->func_id, ret);
850 return 0;
851 }
852 return ptr.ret;
853}
854#else
855static
856int palinfo_handle_smp(struct seq_file *m, pal_func_cpu_u_t *f)
857{
858 printk(KERN_ERR "palinfo: should not be called with non SMP kernel\n");
859 return 0;
860}
861#endif
862
863
864
865
866static int proc_palinfo_show(struct seq_file *m, void *v)
867{
868 pal_func_cpu_u_t *f = (pal_func_cpu_u_t *)&m->private;
869
870
871
872
873
874 if (f->req_cpu == get_cpu())
875 (*palinfo_entries[f->func_id].proc_read)(m);
876 else
877 palinfo_handle_smp(m, f);
878
879 put_cpu();
880 return 0;
881}
882
883static int palinfo_add_proc(unsigned int cpu)
884{
885 pal_func_cpu_u_t f;
886 struct proc_dir_entry *cpu_dir;
887 int j;
888 char cpustr[3+4+1];
889 sprintf(cpustr, "cpu%d", cpu);
890
891 cpu_dir = proc_mkdir(cpustr, palinfo_dir);
892 if (!cpu_dir)
893 return -EINVAL;
894
895 f.req_cpu = cpu;
896
897 for (j=0; j < NR_PALINFO_ENTRIES; j++) {
898 f.func_id = j;
899 proc_create_single_data(palinfo_entries[j].name, 0, cpu_dir,
900 proc_palinfo_show, (void *)f.value);
901 }
902 return 0;
903}
904
905static int palinfo_del_proc(unsigned int hcpu)
906{
907 char cpustr[3+4+1];
908
909 sprintf(cpustr, "cpu%d", hcpu);
910 remove_proc_subtree(cpustr, palinfo_dir);
911 return 0;
912}
913
914static enum cpuhp_state hp_online;
915
916static int __init palinfo_init(void)
917{
918 int i = 0;
919
920 printk(KERN_INFO "PAL Information Facility v%s\n", PALINFO_VERSION);
921 palinfo_dir = proc_mkdir("pal", NULL);
922 if (!palinfo_dir)
923 return -ENOMEM;
924
925 i = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "ia64/palinfo:online",
926 palinfo_add_proc, palinfo_del_proc);
927 if (i < 0) {
928 remove_proc_subtree("pal", NULL);
929 return i;
930 }
931 hp_online = i;
932 return 0;
933}
934
935static void __exit palinfo_exit(void)
936{
937 cpuhp_remove_state(hp_online);
938 remove_proc_subtree("pal", NULL);
939}
940
941module_init(palinfo_init);
942module_exit(palinfo_exit);
943