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 */ 20 #include <linux/config.h> 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 : %lu 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 return 0; 311 } 312 313 314 p += sprintf(p, 315 "Physical Address Space : %d bits\n" 316 "Virtual Address Space : %d bits\n" 317 "Protection Key Registers(PKR) : %d\n" 318 "Implemented bits in PKR.key : %d\n" 319 "Hash Tag ID : 0x%x\n" 320 "Size of RR.rid : %d\n", 321 vm_info_1.pal_vm_info_1_s.phys_add_size, 322 vm_info_2.pal_vm_info_2_s.impl_va_msb+1, vm_info_1.pal_vm_info_1_s.max_pkr+1, 323 vm_info_1.pal_vm_info_1_s.key_size, vm_info_1.pal_vm_info_1_s.hash_tag_id, 324 vm_info_2.pal_vm_info_2_s.rid_size); 325 326 if (ia64_pal_mem_attrib(&attrib) != 0) 327 return 0; 328 329 p += sprintf(p, "Supported memory attributes : "); 330 sep = ""; 331 for (i = 0; i < 8; i++) { 332 if (attrib & (1 << i)) { 333 p += sprintf(p, "%s%s", sep, mem_attrib[i]); 334 sep = ", "; 335 } 336 } 337 p += sprintf(p, "\n"); 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 return 0; 342 } 343 344 p += sprintf(p, 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 354 p = bitvector_process(p, tr_pages); 355 356 p += sprintf(p, "\nTLB purgeable page sizes : "); 357 358 p = bitvector_process(p, vw_pages); 359 360 if ((status=ia64_get_ptce(&ptce)) != 0) { 361 printk(KERN_ERR "ia64_get_ptce=%ld\n", status); 362 return 0; 363 } 364 365 p += sprintf(p, 366 "\nPurge base address : 0x%016lx\n" 367 "Purge outer loop count : %d\n" 368 "Purge inner loop count : %d\n" 369 "Purge outer loop stride : %d\n" 370 "Purge inner loop stride : %d\n", 371 ptce.base, ptce.count[0], ptce.count[1], ptce.stride[0], ptce.stride[1]); 372 373 p += sprintf(p, 374 "TC Levels : %d\n" 375 "Unique TC(s) : %d\n", 376 vm_info_1.pal_vm_info_1_s.num_tc_levels, 377 vm_info_1.pal_vm_info_1_s.max_unique_tcs); 378 379 for(i=0; i < vm_info_1.pal_vm_info_1_s.num_tc_levels; i++) { 380 for (j=2; j>0 ; j--) { 381 tc_pages = 0; /* just in case */ 382 383 384 /* even without unification, some levels may not be present */ 385 if ((status=ia64_pal_vm_info(i,j, &tc_info, &tc_pages)) != 0) { 386 continue; 387 } 388 389 p += sprintf(p, 390 "\n%s Translation Cache Level %d:\n" 391 "\tHash sets : %d\n" 392 "\tAssociativity : %d\n" 393 "\tNumber of entries : %d\n" 394 "\tFlags : ", 395 cache_types[j+tc_info.tc_unified], i+1, tc_info.tc_num_sets, 396 tc_info.tc_associativity, tc_info.tc_num_entries); 397 398 if (tc_info.tc_pf) p += sprintf(p, "PreferredPageSizeOptimized "); 399 if (tc_info.tc_unified) p += sprintf(p, "Unified "); 400 if (tc_info.tc_reduce_tr) p += sprintf(p, "TCReduction"); 401 402 p += sprintf(p, "\n\tSupported page sizes: "); 403 404 p = bitvector_process(p, tc_pages); 405 406 /* when unified date (j=2) is enough */ 407 if (tc_info.tc_unified) break; 408 } 409 } 410 p += sprintf(p, "\n"); 411 412 return p - page; 413 } 414 415 416 static int 417 register_info(char *page) 418 { 419 char *p = page; 420 u64 reg_info[2]; 421 u64 info; 422 u64 phys_stacked; 423 pal_hints_u_t hints; 424 u64 iregs, dregs; 425 char *info_type[]={ 426 "Implemented AR(s)", 427 "AR(s) with read side-effects", 428 "Implemented CR(s)", 429 "CR(s) with read side-effects", 430 }; 431 432 for(info=0; info < 4; info++) { 433 434 if (ia64_pal_register_info(info, ®_info[0], ®_info[1]) != 0) return 0; 435 436 p += sprintf(p, "%-32s : ", info_type[info]); 437 438 p = bitregister_process(p, reg_info, 128); 439 440 p += sprintf(p, "\n"); 441 } 442 443 if (ia64_pal_rse_info(&phys_stacked, &hints) != 0) return 0; 444 445 p += sprintf(p, 446 "RSE stacked physical registers : %ld\n" 447 "RSE load/store hints : %ld (%s)\n", 448 phys_stacked, hints.ph_data, 449 hints.ph_data < RSE_HINTS_COUNT ? rse_hints[hints.ph_data]: "(??)"); 450 451 if (ia64_pal_debug_info(&iregs, &dregs)) 452 return 0; 453 454 p += sprintf(p, 455 "Instruction debug register pairs : %ld\n" 456 "Data debug register pairs : %ld\n", iregs, dregs); 457 458 return p - page; 459 } 460 461 static const char *proc_features[]={ 462 NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL, 463 NULL,NULL,NULL,NULL,NULL,NULL,NULL, NULL,NULL, 464 NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL, 465 NULL,NULL,NULL,NULL,NULL, NULL,NULL,NULL,NULL, 466 NULL,NULL,NULL,NULL,NULL, 467 "XIP,XPSR,XFS implemented", 468 "XR1-XR3 implemented", 469 "Disable dynamic predicate prediction", 470 "Disable processor physical number", 471 "Disable dynamic data cache prefetch", 472 "Disable dynamic inst cache prefetch", 473 "Disable dynamic branch prediction", 474 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 475 "Disable BINIT on processor time-out", 476 "Disable dynamic power management (DPM)", 477 "Disable coherency", 478 "Disable cache", 479 "Enable CMCI promotion", 480 "Enable MCA to BINIT promotion", 481 "Enable MCA promotion", 482 "Enable BERR promotion" 483 }; 484 485 486 static int 487 processor_info(char *page) 488 { 489 char *p = page; 490 const char **v = proc_features; 491 u64 avail=1, status=1, control=1; 492 int i; 493 s64 ret; 494 495 if ((ret=ia64_pal_proc_get_features(&avail, &status, &control)) != 0) return 0; 496 497 for(i=0; i < 64; i++, v++,avail >>=1, status >>=1, control >>=1) { 498 if ( ! *v ) continue; 499 p += sprintf(p, "%-40s : %s%s %s\n", *v, 500 avail & 0x1 ? "" : "NotImpl", 501 avail & 0x1 ? (status & 0x1 ? "On" : "Off"): "", 502 avail & 0x1 ? (control & 0x1 ? "Ctrl" : "NoCtrl"): ""); 503 } 504 return p - page; 505 } 506 507 static const char *bus_features[]={ 508 NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL, 509 NULL,NULL,NULL,NULL,NULL,NULL,NULL, NULL,NULL, 510 NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL, 511 NULL,NULL, 512 "Request Bus Parking", 513 "Bus Lock Mask", 514 "Enable Half Transfer", 515 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 516 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 517 NULL, NULL, NULL, NULL, 518 "Enable Cache Line Repl. Shared", 519 "Enable Cache Line Repl. Exclusive", 520 "Disable Transaction Queuing", 521 "Disable Response Error Checking", 522 "Disable Bus Error Checking", 523 "Disable Bus Requester Internal Error Signalling", 524 "Disable Bus Requester Error Signalling", 525 "Disable Bus Initialization Event Checking", 526 "Disable Bus Initialization Event Signalling", 527 "Disable Bus Address Error Checking", 528 "Disable Bus Address Error Signalling", 529 "Disable Bus Data Error Checking" 530 }; 531 532 533 static int 534 bus_info(char *page) 535 { 536 char *p = page; 537 const char **v = bus_features; 538 pal_bus_features_u_t av, st, ct; 539 u64 avail, status, control; 540 int i; 541 s64 ret; 542 543 if ((ret=ia64_pal_bus_get_features(&av, &st, &ct)) != 0) return 0; 544 545 avail = av.pal_bus_features_val; 546 status = st.pal_bus_features_val; 547 control = ct.pal_bus_features_val; 548 549 for(i=0; i < 64; i++, v++, avail >>=1, status >>=1, control >>=1) { 550 if ( ! *v ) continue; 551 p += sprintf(p, "%-48s : %s%s %s\n", *v, 552 avail & 0x1 ? "" : "NotImpl", 553 avail & 0x1 ? (status & 0x1 ? "On" : "Off"): "", 554 avail & 0x1 ? (control & 0x1 ? "Ctrl" : "NoCtrl"): ""); 555 } 556 return p - page; 557 } 558 559 static int 560 version_info(char *page) 561 { 562 pal_version_u_t min_ver, cur_ver; 563 char *p = page; 564 565 /* The PAL_VERSION call is advertised as being able to support 566 * both physical and virtual mode calls. This seems to be a documentation 567 * bug rather than firmware bug. In fact, it does only support physical mode. 568 * So now the code reflects this fact and the pal_version() has been updated 569 * accordingly. 570 */ 571 if (ia64_pal_version(&min_ver, &cur_ver) != 0) return 0; 572 573 p += sprintf(p, 574 "PAL_vendor : 0x%02x (min=0x%02x)\n" 575 "PAL_A : %x.%x.%x (min=%x.%x.%x)\n" 576 "PAL_B : %x.%x.%x (min=%x.%x.%x)\n", 577 cur_ver.pal_version_s.pv_pal_vendor, min_ver.pal_version_s.pv_pal_vendor, 578 579 cur_ver.pal_version_s.pv_pal_a_model>>4, 580 cur_ver.pal_version_s.pv_pal_a_model&0xf, cur_ver.pal_version_s.pv_pal_a_rev, 581 min_ver.pal_version_s.pv_pal_a_model>>4, 582 min_ver.pal_version_s.pv_pal_a_model&0xf, min_ver.pal_version_s.pv_pal_a_rev, 583 584 cur_ver.pal_version_s.pv_pal_b_model>>4, 585 cur_ver.pal_version_s.pv_pal_b_model&0xf, cur_ver.pal_version_s.pv_pal_b_rev, 586 min_ver.pal_version_s.pv_pal_b_model>>4, 587 min_ver.pal_version_s.pv_pal_b_model&0xf, min_ver.pal_version_s.pv_pal_b_rev); 588 return p - page; 589 } 590 591 static int 592 perfmon_info(char *page) 593 { 594 char *p = page; 595 u64 pm_buffer[16]; 596 pal_perf_mon_info_u_t pm_info; 597 598 if (ia64_pal_perf_mon_info(pm_buffer, &pm_info) != 0) return 0; 599 600 p += sprintf(p, 601 "PMC/PMD pairs : %d\n" 602 "Counter width : %d bits\n" 603 "Cycle event number : %d\n" 604 "Retired event number : %d\n" 605 "Implemented PMC : ", 606 pm_info.pal_perf_mon_info_s.generic, pm_info.pal_perf_mon_info_s.width, 607 pm_info.pal_perf_mon_info_s.cycles, pm_info.pal_perf_mon_info_s.retired); 608 609 p = bitregister_process(p, pm_buffer, 256); 610 p += sprintf(p, "\nImplemented PMD : "); 611 p = bitregister_process(p, pm_buffer+4, 256); 612 p += sprintf(p, "\nCycles count capable : "); 613 p = bitregister_process(p, pm_buffer+8, 256); 614 p += sprintf(p, "\nRetired bundles count capable : "); 615 616 #ifdef CONFIG_ITANIUM 617 /* 618 * PAL_PERF_MON_INFO reports that only PMC4 can be used to count CPU_CYCLES 619 * which is wrong, both PMC4 and PMD5 support it. 620 */ 621 if (pm_buffer[12] == 0x10) pm_buffer[12]=0x30; 622 #endif 623 624 p = bitregister_process(p, pm_buffer+12, 256); 625 626 p += sprintf(p, "\n"); 627 628 return p - page; 629 } 630 631 static int 632 frequency_info(char *page) 633 { 634 char *p = page; 635 struct pal_freq_ratio proc, itc, bus; 636 u64 base; 637 638 if (ia64_pal_freq_base(&base) == -1) 639 p += sprintf(p, "Output clock : not implemented\n"); 640 else 641 p += sprintf(p, "Output clock : %ld ticks/s\n", base); 642 643 if (ia64_pal_freq_ratios(&proc, &bus, &itc) != 0) return 0; 644 645 p += sprintf(p, 646 "Processor/Clock ratio : %ld/%ld\n" 647 "Bus/Clock ratio : %ld/%ld\n" 648 "ITC/Clock ratio : %ld/%ld\n", 649 proc.num, proc.den, bus.num, bus.den, itc.num, itc.den); 650 651 return p - page; 652 } 653 654 static int 655 tr_info(char *page) 656 { 657 char *p = page; 658 s64 status; 659 pal_tr_valid_u_t tr_valid; 660 u64 tr_buffer[4]; 661 pal_vm_info_1_u_t vm_info_1; 662 pal_vm_info_2_u_t vm_info_2; 663 u64 i, j; 664 u64 max[3], pgm; 665 struct ifa_reg { 666 u64 valid:1; 667 u64 ig:11; 668 u64 vpn:52; 669 } *ifa_reg; 670 struct itir_reg { 671 u64 rv1:2; 672 u64 ps:6; 673 u64 key:24; 674 u64 rv2:32; 675 } *itir_reg; 676 struct gr_reg { 677 u64 p:1; 678 u64 rv1:1; 679 u64 ma:3; 680 u64 a:1; 681 u64 d:1; 682 u64 pl:2; 683 u64 ar:3; 684 u64 ppn:38; 685 u64 rv2:2; 686 u64 ed:1; 687 u64 ig:11; 688 } *gr_reg; 689 struct rid_reg { 690 u64 ig1:1; 691 u64 rv1:1; 692 u64 ig2:6; 693 u64 rid:24; 694 u64 rv2:32; 695 } *rid_reg; 696 697 if ((status = ia64_pal_vm_summary(&vm_info_1, &vm_info_2)) !=0) { 698 printk(KERN_ERR "ia64_pal_vm_summary=%ld\n", status); 699 return 0; 700 } 701 max[0] = vm_info_1.pal_vm_info_1_s.max_itr_entry+1; 702 max[1] = vm_info_1.pal_vm_info_1_s.max_dtr_entry+1; 703 704 for (i=0; i < 2; i++ ) { 705 for (j=0; j < max[i]; j++) { 706 707 status = ia64_pal_tr_read(j, i, tr_buffer, &tr_valid); 708 if (status != 0) { 709 printk(KERN_ERR "palinfo: pal call failed on tr[%lu:%lu]=%ld\n", 710 i, j, status); 711 continue; 712 } 713 714 ifa_reg = (struct ifa_reg *)&tr_buffer[2]; 715 716 if (ifa_reg->valid == 0) continue; 717 718 gr_reg = (struct gr_reg *)tr_buffer; 719 itir_reg = (struct itir_reg *)&tr_buffer[1]; 720 rid_reg = (struct rid_reg *)&tr_buffer[3]; 721 722 pgm = -1 << (itir_reg->ps - 12); 723 p += sprintf(p, 724 "%cTR%lu: av=%d pv=%d dv=%d mv=%d\n" 725 "\tppn : 0x%lx\n" 726 "\tvpn : 0x%lx\n" 727 "\tps : ", 728 "ID"[i], j, 729 tr_valid.pal_tr_valid_s.access_rights_valid, 730 tr_valid.pal_tr_valid_s.priv_level_valid, 731 tr_valid.pal_tr_valid_s.dirty_bit_valid, 732 tr_valid.pal_tr_valid_s.mem_attr_valid, 733 (gr_reg->ppn & pgm)<< 12, (ifa_reg->vpn & pgm)<< 12); 734 735 p = bitvector_process(p, 1<< itir_reg->ps); 736 737 p += sprintf(p, 738 "\n\tpl : %d\n" 739 "\tar : %d\n" 740 "\trid : %x\n" 741 "\tp : %d\n" 742 "\tma : %d\n" 743 "\td : %d\n", 744 gr_reg->pl, gr_reg->ar, rid_reg->rid, gr_reg->p, gr_reg->ma, 745 gr_reg->d); 746 } 747 } 748 return p - page; 749 } 750 751 752 753 /* 754 * List {name,function} pairs for every entry in /proc/palinfo/cpu* 755 */ 756 static palinfo_entry_t palinfo_entries[]={ 757 { "version_info", version_info, }, 758 { "vm_info", vm_info, }, 759 { "cache_info", cache_info, }, 760 { "power_info", power_info, }, 761 { "register_info", register_info, }, 762 { "processor_info", processor_info, }, 763 { "perfmon_info", perfmon_info, }, 764 { "frequency_info", frequency_info, }, 765 { "bus_info", bus_info }, 766 { "tr_info", tr_info, } 767 }; 768 769 #define NR_PALINFO_ENTRIES (int) ARRAY_SIZE(palinfo_entries) 770 771 /* 772 * this array is used to keep track of the proc entries we create. This is 773 * required in the module mode when we need to remove all entries. The procfs code 774 * does not do recursion of deletion 775 * 776 * Notes: 777 * - +1 accounts for the cpuN directory entry in /proc/pal 778 */ 779 #define NR_PALINFO_PROC_ENTRIES (NR_CPUS*(NR_PALINFO_ENTRIES+1)) 780 781 static struct proc_dir_entry *palinfo_proc_entries[NR_PALINFO_PROC_ENTRIES]; 782 static struct proc_dir_entry *palinfo_dir; 783 784 /* 785 * This data structure is used to pass which cpu,function is being requested 786 * It must fit in a 64bit quantity to be passed to the proc callback routine 787 * 788 * In SMP mode, when we get a request for another CPU, we must call that 789 * other CPU using IPI and wait for the result before returning. 790 */ 791 typedef union { 792 u64 value; 793 struct { 794 unsigned req_cpu: 32; /* for which CPU this info is */ 795 unsigned func_id: 32; /* which function is requested */ 796 } pal_func_cpu; 797 } pal_func_cpu_u_t; 798 799 #define req_cpu pal_func_cpu.req_cpu 800 #define func_id pal_func_cpu.func_id 801 802 #ifdef CONFIG_SMP 803 804 /* 805 * used to hold information about final function to call 806 */ 807 typedef struct { 808 palinfo_func_t func; /* pointer to function to call */ 809 char *page; /* buffer to store results */ 810 int ret; /* return value from call */ 811 } palinfo_smp_data_t; 812 813 814 /* 815 * this function does the actual final call and he called 816 * from the smp code, i.e., this is the palinfo callback routine 817 */ 818 static void 819 palinfo_smp_call(void *info) 820 { 821 palinfo_smp_data_t *data = (palinfo_smp_data_t *)info; 822 if (data == NULL) { 823 printk(KERN_ERR "palinfo: data pointer is NULL\n"); 824 data->ret = 0; /* no output */ 825 return; 826 } 827 /* does this actual call */ 828 data->ret = (*data->func)(data->page); 829 } 830 831 /* 832 * function called to trigger the IPI, we need to access a remote CPU 833 * Return: 834 * 0 : error or nothing to output 835 * otherwise how many bytes in the "page" buffer were written 836 */ 837 static 838 int palinfo_handle_smp(pal_func_cpu_u_t *f, char *page) 839 { 840 palinfo_smp_data_t ptr; 841 int ret; 842 843 ptr.func = palinfo_entries[f->func_id].proc_read; 844 ptr.page = page; 845 ptr.ret = 0; /* just in case */ 846 847 848 /* will send IPI to other CPU and wait for completion of remote call */ 849 if ((ret=smp_call_function_single(f->req_cpu, palinfo_smp_call, &ptr, 0, 1))) { 850 printk(KERN_ERR "palinfo: remote CPU call from %d to %d on function %d: " 851 "error %d\n", smp_processor_id(), f->req_cpu, f->func_id, ret); 852 return 0; 853 } 854 return ptr.ret; 855 } 856 #else /* ! CONFIG_SMP */ 857 static 858 int palinfo_handle_smp(pal_func_cpu_u_t *f, char *page) 859 { 860 printk(KERN_ERR "palinfo: should not be called with non SMP kernel\n"); 861 return 0; 862 } 863 #endif /* CONFIG_SMP */ 864 865 /* 866 * Entry point routine: all calls go through this function 867 */ 868 static int 869 palinfo_read_entry(char *page, char **start, off_t off, int count, int *eof, void *data) 870 { 871 int len=0; 872 pal_func_cpu_u_t *f = (pal_func_cpu_u_t *)&data; 873 874 /* 875 * in SMP mode, we may need to call another CPU to get correct 876 * information. PAL, by definition, is processor specific 877 */ 878 if (f->req_cpu == get_cpu()) 879 len = (*palinfo_entries[f->func_id].proc_read)(page); 880 else 881 len = palinfo_handle_smp(f, page); 882 883 put_cpu(); 884 885 if (len <= off+count) *eof = 1; 886 887 *start = page + off; 888 len -= off; 889 890 if (len>count) len = count; 891 if (len<0) len = 0; 892 893 return len; 894 } 895 896 static void 897 create_palinfo_proc_entries(unsigned int cpu) 898 { 899 # define CPUSTR "cpu%d" 900 901 pal_func_cpu_u_t f; 902 struct proc_dir_entry **pdir; 903 struct proc_dir_entry *cpu_dir; 904 int j; 905 char cpustr[sizeof(CPUSTR)]; 906 907 908 /* 909 * we keep track of created entries in a depth-first order for 910 * cleanup purposes. Each entry is stored into palinfo_proc_entries 911 */ 912 sprintf(cpustr,CPUSTR, cpu); 913 914 cpu_dir = proc_mkdir(cpustr, palinfo_dir); 915 916 f.req_cpu = cpu; 917 918 /* 919 * Compute the location to store per cpu entries 920 * We dont store the top level entry in this list, but 921 * remove it finally after removing all cpu entries. 922 */ 923 pdir = &palinfo_proc_entries[cpu*(NR_PALINFO_ENTRIES+1)]; 924 *pdir++ = cpu_dir; 925 for (j=0; j < NR_PALINFO_ENTRIES; j++) { 926 f.func_id = j; 927 *pdir = create_proc_read_entry( 928 palinfo_entries[j].name, 0, cpu_dir, 929 palinfo_read_entry, (void *)f.value); 930 if (*pdir) 931 (*pdir)->owner = THIS_MODULE; 932 pdir++; 933 } 934 } 935 936 static void 937 remove_palinfo_proc_entries(unsigned int hcpu) 938 { 939 int j; 940 struct proc_dir_entry *cpu_dir, **pdir; 941 942 pdir = &palinfo_proc_entries[hcpu*(NR_PALINFO_ENTRIES+1)]; 943 cpu_dir = *pdir; 944 *pdir++=NULL; 945 for (j=0; j < (NR_PALINFO_ENTRIES); j++) { 946 if ((*pdir)) { 947 remove_proc_entry ((*pdir)->name, cpu_dir); 948 *pdir ++= NULL; 949 } 950 } 951 952 if (cpu_dir) { 953 remove_proc_entry(cpu_dir->name, palinfo_dir); 954 } 955 } 956 957 static int __devinit palinfo_cpu_callback(struct notifier_block *nfb, 958 unsigned long action, 959 void *hcpu) 960 { 961 unsigned int hotcpu = (unsigned long)hcpu; 962 963 switch (action) { 964 case CPU_ONLINE: 965 create_palinfo_proc_entries(hotcpu); 966 break; 967 #ifdef CONFIG_HOTPLUG_CPU 968 case CPU_DEAD: 969 remove_palinfo_proc_entries(hotcpu); 970 break; 971 #endif 972 } 973 return NOTIFY_OK; 974 } 975 976 static struct notifier_block palinfo_cpu_notifier = 977 { 978 .notifier_call = palinfo_cpu_callback, 979 .priority = 0, 980 }; 981 982 static int __init 983 palinfo_init(void) 984 { 985 int i = 0; 986 987 printk(KERN_INFO "PAL Information Facility v%s\n", PALINFO_VERSION); 988 palinfo_dir = proc_mkdir("pal", NULL); 989 990 /* Create palinfo dirs in /proc for all online cpus */ 991 for_each_online_cpu(i) { 992 create_palinfo_proc_entries(i); 993 } 994 995 /* Register for future delivery via notify registration */ 996 register_cpu_notifier(&palinfo_cpu_notifier); 997 998 return 0; 999 } 1000 1001 static void __exit 1002 palinfo_exit(void) 1003 { 1004 int i = 0; 1005 1006 /* remove all nodes: depth first pass. Could optimize this */ 1007 for_each_online_cpu(i) { 1008 remove_palinfo_proc_entries(i); 1009 } 1010 1011 /* 1012 * Remove the top level entry finally 1013 */ 1014 remove_proc_entry(palinfo_dir->name, NULL); 1015 1016 /* 1017 * Unregister from cpu notifier callbacks 1018 */ 1019 unregister_cpu_notifier(&palinfo_cpu_notifier); 1020 } 1021 1022 module_init(palinfo_init); 1023 module_exit(palinfo_exit); 1024