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