~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/arch/ia64/kernel/palinfo.c

Version: ~ [ linux-4.20-rc2 ] ~ [ linux-4.19.1 ] ~ [ linux-4.18.18 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.80 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.136 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.163 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.125 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.60 ] ~ [ linux-3.15.10 ] ~ [ linux-3.14.79 ] ~ [ linux-3.13.11 ] ~ [ linux-3.12.74 ] ~ [ linux-3.11.10 ] ~ [ linux-3.10.108 ] ~ [ linux-3.9.11 ] ~ [ linux-3.8.13 ] ~ [ linux-3.7.10 ] ~ [ linux-3.6.11 ] ~ [ linux-3.5.7 ] ~ [ linux-3.4.113 ] ~ [ linux-3.3.8 ] ~ [ linux-3.2.102 ] ~ [ linux-3.1.10 ] ~ [ linux-3.0.101 ] ~ [ linux-2.6.39.4 ] ~ [ linux-2.6.38.8 ] ~ [ linux-2.6.37.6 ] ~ [ linux-2.6.36.4 ] ~ [ linux-2.6.35.14 ] ~ [ linux-2.6.34.15 ] ~ [ linux-2.6.33.20 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.31.14 ] ~ [ linux-2.6.30.10 ] ~ [ linux-2.6.29.6 ] ~ [ linux-2.6.28.10 ] ~ [ linux-2.6.27.62 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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 
 39 MODULE_AUTHOR("Stephane Eranian <eranian@hpl.hp.com>");
 40 MODULE_DESCRIPTION("/proc interface to IA-64 PAL");
 41 MODULE_LICENSE("GPL");
 42 
 43 #define PALINFO_VERSION "0.5"
 44 
 45 typedef int (*palinfo_func_t)(struct seq_file *);
 46 
 47 typedef 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 
 58 static const char *cache_types[] = {
 59         "",                     /* not used */
 60         "Instruction",
 61         "Data",
 62         "Data/Instruction"      /* unified */
 63 };
 64 
 65 static const char *cache_mattrib[]={
 66         "WriteThrough",
 67         "WriteBack",
 68         "",             /* reserved */
 69         ""              /* reserved */
 70 };
 71 
 72 static 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 
 83 static 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 
 94 static 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 
103 static 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  */
126 static 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  */
150 static 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 
182 static 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 
211 static 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 
289 static 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 
419 static 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, &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');
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 
458 static 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 
490 static 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 
510 static 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 
518 static 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 
551 static 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 
574 static 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 
600 static 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 
626 static 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 
650 static 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 
690 static 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 
710 static 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  */
811 static 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 
826 static 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  */
835 typedef 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  */
851 typedef 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  */
862 static void
863 palinfo_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  */
875 static
876 int 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 */
895 static
896 int 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  */
906 static 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 
923 static int proc_palinfo_open(struct inode *inode, struct file *file)
924 {
925         return single_open(file, proc_palinfo_show, PDE_DATA(inode));
926 }
927 
928 static 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 
935 static 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 
957 static 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 
966 static enum cpuhp_state hp_online;
967 
968 static 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 
987 static void __exit palinfo_exit(void)
988 {
989         cpuhp_remove_state(hp_online);
990         remove_proc_subtree("pal", NULL);
991 }
992 
993 module_init(palinfo_init);
994 module_exit(palinfo_exit);
995 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp