linux/arch/ia64/kernel/palinfo.c
<<
>>
Prefs
   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
  38MODULE_AUTHOR("Stephane Eranian <eranian@hpl.hp.com>");
  39MODULE_DESCRIPTION("/proc interface to IA-64 PAL");
  40MODULE_LICENSE("GPL");
  41
  42#define PALINFO_VERSION "0.5"
  43
  44typedef int (*palinfo_func_t)(char*);
  45
  46typedef 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
  57static char *cache_types[] = {
  58        "",                     /* not used */
  59        "Instruction",
  60        "Data",
  61        "Data/Instruction"      /* unified */
  62};
  63
  64static const char *cache_mattrib[]={
  65        "WriteThrough",
  66        "WriteBack",
  67        "",             /* reserved */
  68        ""              /* reserved */
  69};
  70
  71static 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
  82static 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
  93static 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
 102static 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 */
 125static char *
 126bitvector_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 */
 152static char *
 153bitregister_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
 187static int
 188power_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
 217static int
 218cache_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
 294static int
 295vm_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
 428static int
 429register_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, &reg_info[0], &reg_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
 473static 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
 505static 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
 525static 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
 533static char *
 534feature_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
 568static int
 569processor_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
 594static 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
 620static int
 621bus_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
 646static int
 647version_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
 672static int
 673perfmon_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
 712static int
 713frequency_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
 735static int
 736tr_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 */
 837static 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
 862static struct proc_dir_entry *palinfo_proc_entries[NR_PALINFO_PROC_ENTRIES];
 863static 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 */
 872typedef 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 */
 888typedef 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 */
 899static void
 900palinfo_smp_call(void *info)
 901{
 902        palinfo_smp_data_t *data = (palinfo_smp_data_t *)info;
 903        if (data == NULL) {
 904                printk(KERN_ERR "palinfo: data pointer is NULL\n");
 905                data->ret = 0; /* no output */
 906                return;
 907        }
 908        /* does this actual call */
 909        data->ret = (*data->func)(data->page);
 910}
 911
 912/*
 913 * function called to trigger the IPI, we need to access a remote CPU
 914 * Return:
 915 *      0 : error or nothing to output
 916 *      otherwise how many bytes in the "page" buffer were written
 917 */
 918static
 919int palinfo_handle_smp(pal_func_cpu_u_t *f, char *page)
 920{
 921        palinfo_smp_data_t ptr;
 922        int ret;
 923
 924        ptr.func = palinfo_entries[f->func_id].proc_read;
 925        ptr.page = page;
 926        ptr.ret  = 0; /* just in case */
 927
 928
 929        /* will send IPI to other CPU and wait for completion of remote call */
 930        if ((ret=smp_call_function_single(f->req_cpu, palinfo_smp_call, &ptr, 0, 1))) {
 931                printk(KERN_ERR "palinfo: remote CPU call from %d to %d on function %d: "
 932                       "error %d\n", smp_processor_id(), f->req_cpu, f->func_id, ret);
 933                return 0;
 934        }
 935        return ptr.ret;
 936}
 937#else /* ! CONFIG_SMP */
 938static
 939int palinfo_handle_smp(pal_func_cpu_u_t *f, char *page)
 940{
 941        printk(KERN_ERR "palinfo: should not be called with non SMP kernel\n");
 942        return 0;
 943}
 944#endif /* CONFIG_SMP */
 945
 946/*
 947 * Entry point routine: all calls go through this function
 948 */
 949static int
 950palinfo_read_entry(char *page, char **start, off_t off, int count, int *eof, void *data)
 951{
 952        int len=0;
 953        pal_func_cpu_u_t *f = (pal_func_cpu_u_t *)&data;
 954
 955        /*
 956         * in SMP mode, we may need to call another CPU to get correct
 957         * information. PAL, by definition, is processor specific
 958         */
 959        if (f->req_cpu == get_cpu())
 960                len = (*palinfo_entries[f->func_id].proc_read)(page);
 961        else
 962                len = palinfo_handle_smp(f, page);
 963
 964        put_cpu();
 965
 966        if (len <= off+count) *eof = 1;
 967
 968        *start = page + off;
 969        len   -= off;
 970
 971        if (len>count) len = count;
 972        if (len<0) len = 0;
 973
 974        return len;
 975}
 976
 977static void __cpuinit
 978create_palinfo_proc_entries(unsigned int cpu)
 979{
 980#       define CPUSTR   "cpu%d"
 981
 982        pal_func_cpu_u_t f;
 983        struct proc_dir_entry **pdir;
 984        struct proc_dir_entry *cpu_dir;
 985        int j;
 986        char cpustr[sizeof(CPUSTR)];
 987
 988
 989        /*
 990         * we keep track of created entries in a depth-first order for
 991         * cleanup purposes. Each entry is stored into palinfo_proc_entries
 992         */
 993        sprintf(cpustr,CPUSTR, cpu);
 994
 995        cpu_dir = proc_mkdir(cpustr, palinfo_dir);
 996
 997        f.req_cpu = cpu;
 998
 999        /*
1000         * Compute the location to store per cpu entries
1001         * We dont store the top level entry in this list, but
1002         * remove it finally after removing all cpu entries.
1003         */
1004        pdir = &palinfo_proc_entries[cpu*(NR_PALINFO_ENTRIES+1)];
1005        *pdir++ = cpu_dir;
1006        for (j=0; j < NR_PALINFO_ENTRIES; j++) {
1007                f.func_id = j;
1008                *pdir = create_proc_read_entry(
1009                                palinfo_entries[j].name, 0, cpu_dir,
1010                                palinfo_read_entry, (void *)f.value);
1011                if (*pdir)
1012                        (*pdir)->owner = THIS_MODULE;
1013                pdir++;
1014        }
1015}
1016
1017static void
1018remove_palinfo_proc_entries(unsigned int hcpu)
1019{
1020        int j;
1021        struct proc_dir_entry *cpu_dir, **pdir;
1022
1023        pdir = &palinfo_proc_entries[hcpu*(NR_PALINFO_ENTRIES+1)];
1024        cpu_dir = *pdir;
1025        *pdir++=NULL;
1026        for (j=0; j < (NR_PALINFO_ENTRIES); j++) {
1027                if ((*pdir)) {
1028                        remove_proc_entry ((*pdir)->name, cpu_dir);
1029                        *pdir ++= NULL;
1030                }
1031        }
1032
1033        if (cpu_dir) {
1034                remove_proc_entry(cpu_dir->name, palinfo_dir);
1035        }
1036}
1037
1038static int __cpuinit palinfo_cpu_callback(struct notifier_block *nfb,
1039                                        unsigned long action, void *hcpu)
1040{
1041        unsigned int hotcpu = (unsigned long)hcpu;
1042
1043        switch (action) {
1044        case CPU_ONLINE:
1045        case CPU_ONLINE_FROZEN:
1046                create_palinfo_proc_entries(hotcpu);
1047                break;
1048        case CPU_DEAD:
1049        case CPU_DEAD_FROZEN:
1050                remove_palinfo_proc_entries(hotcpu);
1051                break;
1052        }
1053        return NOTIFY_OK;
1054}
1055
1056static struct notifier_block palinfo_cpu_notifier __cpuinitdata =
1057{
1058        .notifier_call = palinfo_cpu_callback,
1059        .priority = 0,
1060};
1061
1062static int __init
1063palinfo_init(void)
1064{
1065        int i = 0;
1066
1067        printk(KERN_INFO "PAL Information Facility v%s\n", PALINFO_VERSION);
1068        palinfo_dir = proc_mkdir("pal", NULL);
1069
1070        /* Create palinfo dirs in /proc for all online cpus */
1071        for_each_online_cpu(i) {
1072                create_palinfo_proc_entries(i);
1073        }
1074
1075        /* Register for future delivery via notify registration */
1076        register_hotcpu_notifier(&palinfo_cpu_notifier);
1077
1078        return 0;
1079}
1080
1081static void __exit
1082palinfo_exit(void)
1083{
1084        int i = 0;
1085
1086        /* remove all nodes: depth first pass. Could optimize this  */
1087        for_each_online_cpu(i) {
1088                remove_palinfo_proc_entries(i);
1089        }
1090
1091        /*
1092         * Remove the top level entry finally
1093         */
1094        remove_proc_entry(palinfo_dir->name, NULL);
1095
1096        /*
1097         * Unregister from cpu notifier callbacks
1098         */
1099        unregister_hotcpu_notifier(&palinfo_cpu_notifier);
1100}
1101
1102module_init(palinfo_init);
1103module_exit(palinfo_exit);
1104