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