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