linux/arch/x86/oprofile/op_model_amd.c
<<
>>
Prefs
   1/*
   2 * @file op_model_amd.c
   3 * athlon / K7 / K8 / Family 10h model-specific MSR operations
   4 *
   5 * @remark Copyright 2002-2009 OProfile authors
   6 * @remark Read the file COPYING
   7 *
   8 * @author John Levon
   9 * @author Philippe Elie
  10 * @author Graydon Hoare
  11 * @author Robert Richter <robert.richter@amd.com>
  12 * @author Barry Kasindorf <barry.kasindorf@amd.com>
  13 * @author Jason Yeh <jason.yeh@amd.com>
  14 * @author Suravee Suthikulpanit <suravee.suthikulpanit@amd.com>
  15 */
  16
  17#include <linux/oprofile.h>
  18#include <linux/device.h>
  19#include <linux/pci.h>
  20#include <linux/percpu.h>
  21
  22#include <asm/ptrace.h>
  23#include <asm/msr.h>
  24#include <asm/nmi.h>
  25#include <asm/apic.h>
  26#include <asm/processor.h>
  27#include <asm/cpufeature.h>
  28
  29#include "op_x86_model.h"
  30#include "op_counter.h"
  31
  32#define NUM_COUNTERS            4
  33#define NUM_COUNTERS_F15H       6
  34#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX
  35#define NUM_VIRT_COUNTERS       32
  36#else
  37#define NUM_VIRT_COUNTERS       0
  38#endif
  39
  40#define OP_EVENT_MASK                   0x0FFF
  41#define OP_CTR_OVERFLOW                 (1ULL<<31)
  42
  43#define MSR_AMD_EVENTSEL_RESERVED       ((0xFFFFFCF0ULL<<32)|(1ULL<<21))
  44
  45static int num_counters;
  46static unsigned long reset_value[OP_MAX_COUNTER];
  47
  48#define IBS_FETCH_SIZE                  6
  49#define IBS_OP_SIZE                     12
  50
  51static u32 ibs_caps;
  52
  53struct ibs_config {
  54        unsigned long op_enabled;
  55        unsigned long fetch_enabled;
  56        unsigned long max_cnt_fetch;
  57        unsigned long max_cnt_op;
  58        unsigned long rand_en;
  59        unsigned long dispatched_ops;
  60        unsigned long branch_target;
  61};
  62
  63struct ibs_state {
  64        u64             ibs_op_ctl;
  65        int             branch_target;
  66        unsigned long   sample_size;
  67};
  68
  69static struct ibs_config ibs_config;
  70static struct ibs_state ibs_state;
  71
  72/*
  73 * IBS cpuid feature detection
  74 */
  75
  76#define IBS_CPUID_FEATURES              0x8000001b
  77
  78/*
  79 * Same bit mask as for IBS cpuid feature flags (Fn8000_001B_EAX), but
  80 * bit 0 is used to indicate the existence of IBS.
  81 */
  82#define IBS_CAPS_AVAIL                  (1U<<0)
  83#define IBS_CAPS_FETCHSAM               (1U<<1)
  84#define IBS_CAPS_OPSAM                  (1U<<2)
  85#define IBS_CAPS_RDWROPCNT              (1U<<3)
  86#define IBS_CAPS_OPCNT                  (1U<<4)
  87#define IBS_CAPS_BRNTRGT                (1U<<5)
  88#define IBS_CAPS_OPCNTEXT               (1U<<6)
  89
  90#define IBS_CAPS_DEFAULT                (IBS_CAPS_AVAIL         \
  91                                         | IBS_CAPS_FETCHSAM    \
  92                                         | IBS_CAPS_OPSAM)
  93
  94/*
  95 * IBS APIC setup
  96 */
  97#define IBSCTL                          0x1cc
  98#define IBSCTL_LVT_OFFSET_VALID         (1ULL<<8)
  99#define IBSCTL_LVT_OFFSET_MASK          0x0F
 100
 101/*
 102 * IBS randomization macros
 103 */
 104#define IBS_RANDOM_BITS                 12
 105#define IBS_RANDOM_MASK                 ((1ULL << IBS_RANDOM_BITS) - 1)
 106#define IBS_RANDOM_MAXCNT_OFFSET        (1ULL << (IBS_RANDOM_BITS - 5))
 107
 108static u32 get_ibs_caps(void)
 109{
 110        u32 ibs_caps;
 111        unsigned int max_level;
 112
 113        if (!boot_cpu_has(X86_FEATURE_IBS))
 114                return 0;
 115
 116        /* check IBS cpuid feature flags */
 117        max_level = cpuid_eax(0x80000000);
 118        if (max_level < IBS_CPUID_FEATURES)
 119                return IBS_CAPS_DEFAULT;
 120
 121        ibs_caps = cpuid_eax(IBS_CPUID_FEATURES);
 122        if (!(ibs_caps & IBS_CAPS_AVAIL))
 123                /* cpuid flags not valid */
 124                return IBS_CAPS_DEFAULT;
 125
 126        return ibs_caps;
 127}
 128
 129/*
 130 * 16-bit Linear Feedback Shift Register (LFSR)
 131 *
 132 *                       16   14   13    11
 133 * Feedback polynomial = X  + X  + X  +  X  + 1
 134 */
 135static unsigned int lfsr_random(void)
 136{
 137        static unsigned int lfsr_value = 0xF00D;
 138        unsigned int bit;
 139
 140        /* Compute next bit to shift in */
 141        bit = ((lfsr_value >> 0) ^
 142               (lfsr_value >> 2) ^
 143               (lfsr_value >> 3) ^
 144               (lfsr_value >> 5)) & 0x0001;
 145
 146        /* Advance to next register value */
 147        lfsr_value = (lfsr_value >> 1) | (bit << 15);
 148
 149        return lfsr_value;
 150}
 151
 152/*
 153 * IBS software randomization
 154 *
 155 * The IBS periodic op counter is randomized in software. The lower 12
 156 * bits of the 20 bit counter are randomized. IbsOpCurCnt is
 157 * initialized with a 12 bit random value.
 158 */
 159static inline u64 op_amd_randomize_ibs_op(u64 val)
 160{
 161        unsigned int random = lfsr_random();
 162
 163        if (!(ibs_caps & IBS_CAPS_RDWROPCNT))
 164                /*
 165                 * Work around if the hw can not write to IbsOpCurCnt
 166                 *
 167                 * Randomize the lower 8 bits of the 16 bit
 168                 * IbsOpMaxCnt [15:0] value in the range of -128 to
 169                 * +127 by adding/subtracting an offset to the
 170                 * maximum count (IbsOpMaxCnt).
 171                 *
 172                 * To avoid over or underflows and protect upper bits
 173                 * starting at bit 16, the initial value for
 174                 * IbsOpMaxCnt must fit in the range from 0x0081 to
 175                 * 0xff80.
 176                 */
 177                val += (s8)(random >> 4);
 178        else
 179                val |= (u64)(random & IBS_RANDOM_MASK) << 32;
 180
 181        return val;
 182}
 183
 184static inline void
 185op_amd_handle_ibs(struct pt_regs * const regs,
 186                  struct op_msrs const * const msrs)
 187{
 188        u64 val, ctl;
 189        struct op_entry entry;
 190
 191        if (!ibs_caps)
 192                return;
 193
 194        if (ibs_config.fetch_enabled) {
 195                rdmsrl(MSR_AMD64_IBSFETCHCTL, ctl);
 196                if (ctl & IBS_FETCH_VAL) {
 197                        rdmsrl(MSR_AMD64_IBSFETCHLINAD, val);
 198                        oprofile_write_reserve(&entry, regs, val,
 199                                               IBS_FETCH_CODE, IBS_FETCH_SIZE);
 200                        oprofile_add_data64(&entry, val);
 201                        oprofile_add_data64(&entry, ctl);
 202                        rdmsrl(MSR_AMD64_IBSFETCHPHYSAD, val);
 203                        oprofile_add_data64(&entry, val);
 204                        oprofile_write_commit(&entry);
 205
 206                        /* reenable the IRQ */
 207                        ctl &= ~(IBS_FETCH_VAL | IBS_FETCH_CNT);
 208                        ctl |= IBS_FETCH_ENABLE;
 209                        wrmsrl(MSR_AMD64_IBSFETCHCTL, ctl);
 210                }
 211        }
 212
 213        if (ibs_config.op_enabled) {
 214                rdmsrl(MSR_AMD64_IBSOPCTL, ctl);
 215                if (ctl & IBS_OP_VAL) {
 216                        rdmsrl(MSR_AMD64_IBSOPRIP, val);
 217                        oprofile_write_reserve(&entry, regs, val, IBS_OP_CODE,
 218                                               ibs_state.sample_size);
 219                        oprofile_add_data64(&entry, val);
 220                        rdmsrl(MSR_AMD64_IBSOPDATA, val);
 221                        oprofile_add_data64(&entry, val);
 222                        rdmsrl(MSR_AMD64_IBSOPDATA2, val);
 223                        oprofile_add_data64(&entry, val);
 224                        rdmsrl(MSR_AMD64_IBSOPDATA3, val);
 225                        oprofile_add_data64(&entry, val);
 226                        rdmsrl(MSR_AMD64_IBSDCLINAD, val);
 227                        oprofile_add_data64(&entry, val);
 228                        rdmsrl(MSR_AMD64_IBSDCPHYSAD, val);
 229                        oprofile_add_data64(&entry, val);
 230                        if (ibs_state.branch_target) {
 231                                rdmsrl(MSR_AMD64_IBSBRTARGET, val);
 232                                oprofile_add_data(&entry, (unsigned long)val);
 233                        }
 234                        oprofile_write_commit(&entry);
 235
 236                        /* reenable the IRQ */
 237                        ctl = op_amd_randomize_ibs_op(ibs_state.ibs_op_ctl);
 238                        wrmsrl(MSR_AMD64_IBSOPCTL, ctl);
 239                }
 240        }
 241}
 242
 243static inline void op_amd_start_ibs(void)
 244{
 245        u64 val;
 246
 247        if (!ibs_caps)
 248                return;
 249
 250        memset(&ibs_state, 0, sizeof(ibs_state));
 251
 252        /*
 253         * Note: Since the max count settings may out of range we
 254         * write back the actual used values so that userland can read
 255         * it.
 256         */
 257
 258        if (ibs_config.fetch_enabled) {
 259                val = ibs_config.max_cnt_fetch >> 4;
 260                val = min(val, IBS_FETCH_MAX_CNT);
 261                ibs_config.max_cnt_fetch = val << 4;
 262                val |= ibs_config.rand_en ? IBS_FETCH_RAND_EN : 0;
 263                val |= IBS_FETCH_ENABLE;
 264                wrmsrl(MSR_AMD64_IBSFETCHCTL, val);
 265        }
 266
 267        if (ibs_config.op_enabled) {
 268                val = ibs_config.max_cnt_op >> 4;
 269                if (!(ibs_caps & IBS_CAPS_RDWROPCNT)) {
 270                        /*
 271                         * IbsOpCurCnt not supported.  See
 272                         * op_amd_randomize_ibs_op() for details.
 273                         */
 274                        val = clamp(val, 0x0081ULL, 0xFF80ULL);
 275                        ibs_config.max_cnt_op = val << 4;
 276                } else {
 277                        /*
 278                         * The start value is randomized with a
 279                         * positive offset, we need to compensate it
 280                         * with the half of the randomized range. Also
 281                         * avoid underflows.
 282                         */
 283                        val += IBS_RANDOM_MAXCNT_OFFSET;
 284                        if (ibs_caps & IBS_CAPS_OPCNTEXT)
 285                                val = min(val, IBS_OP_MAX_CNT_EXT);
 286                        else
 287                                val = min(val, IBS_OP_MAX_CNT);
 288                        ibs_config.max_cnt_op =
 289                                (val - IBS_RANDOM_MAXCNT_OFFSET) << 4;
 290                }
 291                val = ((val & ~IBS_OP_MAX_CNT) << 4) | (val & IBS_OP_MAX_CNT);
 292                val |= ibs_config.dispatched_ops ? IBS_OP_CNT_CTL : 0;
 293                val |= IBS_OP_ENABLE;
 294                ibs_state.ibs_op_ctl = val;
 295                ibs_state.sample_size = IBS_OP_SIZE;
 296                if (ibs_config.branch_target) {
 297                        ibs_state.branch_target = 1;
 298                        ibs_state.sample_size++;
 299                }
 300                val = op_amd_randomize_ibs_op(ibs_state.ibs_op_ctl);
 301                wrmsrl(MSR_AMD64_IBSOPCTL, val);
 302        }
 303}
 304
 305static void op_amd_stop_ibs(void)
 306{
 307        if (!ibs_caps)
 308                return;
 309
 310        if (ibs_config.fetch_enabled)
 311                /* clear max count and enable */
 312                wrmsrl(MSR_AMD64_IBSFETCHCTL, 0);
 313
 314        if (ibs_config.op_enabled)
 315                /* clear max count and enable */
 316                wrmsrl(MSR_AMD64_IBSOPCTL, 0);
 317}
 318
 319static inline int eilvt_is_available(int offset)
 320{
 321        /* check if we may assign a vector */
 322        return !setup_APIC_eilvt(offset, 0, APIC_EILVT_MSG_NMI, 1);
 323}
 324
 325static inline int ibs_eilvt_valid(void)
 326{
 327        int offset;
 328        u64 val;
 329
 330        rdmsrl(MSR_AMD64_IBSCTL, val);
 331        offset = val & IBSCTL_LVT_OFFSET_MASK;
 332
 333        if (!(val & IBSCTL_LVT_OFFSET_VALID)) {
 334                pr_err(FW_BUG "cpu %d, invalid IBS interrupt offset %d (MSR%08X=0x%016llx)\n",
 335                       smp_processor_id(), offset, MSR_AMD64_IBSCTL, val);
 336                return 0;
 337        }
 338
 339        if (!eilvt_is_available(offset)) {
 340                pr_err(FW_BUG "cpu %d, IBS interrupt offset %d not available (MSR%08X=0x%016llx)\n",
 341                       smp_processor_id(), offset, MSR_AMD64_IBSCTL, val);
 342                return 0;
 343        }
 344
 345        return 1;
 346}
 347
 348static inline int get_ibs_offset(void)
 349{
 350        u64 val;
 351
 352        rdmsrl(MSR_AMD64_IBSCTL, val);
 353        if (!(val & IBSCTL_LVT_OFFSET_VALID))
 354                return -EINVAL;
 355
 356        return val & IBSCTL_LVT_OFFSET_MASK;
 357}
 358
 359static void setup_APIC_ibs(void)
 360{
 361        int offset;
 362
 363        offset = get_ibs_offset();
 364        if (offset < 0)
 365                goto failed;
 366
 367        if (!setup_APIC_eilvt(offset, 0, APIC_EILVT_MSG_NMI, 0))
 368                return;
 369failed:
 370        pr_warn("oprofile: IBS APIC setup failed on cpu #%d\n",
 371                smp_processor_id());
 372}
 373
 374static void clear_APIC_ibs(void)
 375{
 376        int offset;
 377
 378        offset = get_ibs_offset();
 379        if (offset >= 0)
 380                setup_APIC_eilvt(offset, 0, APIC_EILVT_MSG_FIX, 1);
 381}
 382
 383#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX
 384
 385static void op_mux_switch_ctrl(struct op_x86_model_spec const *model,
 386                               struct op_msrs const * const msrs)
 387{
 388        u64 val;
 389        int i;
 390
 391        /* enable active counters */
 392        for (i = 0; i < num_counters; ++i) {
 393                int virt = op_x86_phys_to_virt(i);
 394                if (!reset_value[virt])
 395                        continue;
 396                rdmsrl(msrs->controls[i].addr, val);
 397                val &= model->reserved;
 398                val |= op_x86_get_ctrl(model, &counter_config[virt]);
 399                wrmsrl(msrs->controls[i].addr, val);
 400        }
 401}
 402
 403#endif
 404
 405/* functions for op_amd_spec */
 406
 407static void op_amd_shutdown(struct op_msrs const * const msrs)
 408{
 409        int i;
 410
 411        for (i = 0; i < num_counters; ++i) {
 412                if (!msrs->counters[i].addr)
 413                        continue;
 414                release_perfctr_nmi(MSR_K7_PERFCTR0 + i);
 415                release_evntsel_nmi(MSR_K7_EVNTSEL0 + i);
 416        }
 417}
 418
 419static int op_amd_fill_in_addresses(struct op_msrs * const msrs)
 420{
 421        int i;
 422
 423        for (i = 0; i < num_counters; i++) {
 424                if (!reserve_perfctr_nmi(MSR_K7_PERFCTR0 + i))
 425                        goto fail;
 426                if (!reserve_evntsel_nmi(MSR_K7_EVNTSEL0 + i)) {
 427                        release_perfctr_nmi(MSR_K7_PERFCTR0 + i);
 428                        goto fail;
 429                }
 430                /* both registers must be reserved */
 431                if (num_counters == NUM_COUNTERS_F15H) {
 432                        msrs->counters[i].addr = MSR_F15H_PERF_CTR + (i << 1);
 433                        msrs->controls[i].addr = MSR_F15H_PERF_CTL + (i << 1);
 434                } else {
 435                        msrs->controls[i].addr = MSR_K7_EVNTSEL0 + i;
 436                        msrs->counters[i].addr = MSR_K7_PERFCTR0 + i;
 437                }
 438                continue;
 439        fail:
 440                if (!counter_config[i].enabled)
 441                        continue;
 442                op_x86_warn_reserved(i);
 443                op_amd_shutdown(msrs);
 444                return -EBUSY;
 445        }
 446
 447        return 0;
 448}
 449
 450static void op_amd_setup_ctrs(struct op_x86_model_spec const *model,
 451                              struct op_msrs const * const msrs)
 452{
 453        u64 val;
 454        int i;
 455
 456        /* setup reset_value */
 457        for (i = 0; i < OP_MAX_COUNTER; ++i) {
 458                if (counter_config[i].enabled
 459                    && msrs->counters[op_x86_virt_to_phys(i)].addr)
 460                        reset_value[i] = counter_config[i].count;
 461                else
 462                        reset_value[i] = 0;
 463        }
 464
 465        /* clear all counters */
 466        for (i = 0; i < num_counters; ++i) {
 467                if (!msrs->controls[i].addr)
 468                        continue;
 469                rdmsrl(msrs->controls[i].addr, val);
 470                if (val & ARCH_PERFMON_EVENTSEL_ENABLE)
 471                        op_x86_warn_in_use(i);
 472                val &= model->reserved;
 473                wrmsrl(msrs->controls[i].addr, val);
 474                /*
 475                 * avoid a false detection of ctr overflows in NMI
 476                 * handler
 477                 */
 478                wrmsrl(msrs->counters[i].addr, -1LL);
 479        }
 480
 481        /* enable active counters */
 482        for (i = 0; i < num_counters; ++i) {
 483                int virt = op_x86_phys_to_virt(i);
 484                if (!reset_value[virt])
 485                        continue;
 486
 487                /* setup counter registers */
 488                wrmsrl(msrs->counters[i].addr, -(u64)reset_value[virt]);
 489
 490                /* setup control registers */
 491                rdmsrl(msrs->controls[i].addr, val);
 492                val &= model->reserved;
 493                val |= op_x86_get_ctrl(model, &counter_config[virt]);
 494                wrmsrl(msrs->controls[i].addr, val);
 495        }
 496
 497        if (ibs_caps)
 498                setup_APIC_ibs();
 499}
 500
 501static void op_amd_cpu_shutdown(void)
 502{
 503        if (ibs_caps)
 504                clear_APIC_ibs();
 505}
 506
 507static int op_amd_check_ctrs(struct pt_regs * const regs,
 508                             struct op_msrs const * const msrs)
 509{
 510        u64 val;
 511        int i;
 512
 513        for (i = 0; i < num_counters; ++i) {
 514                int virt = op_x86_phys_to_virt(i);
 515                if (!reset_value[virt])
 516                        continue;
 517                rdmsrl(msrs->counters[i].addr, val);
 518                /* bit is clear if overflowed: */
 519                if (val & OP_CTR_OVERFLOW)
 520                        continue;
 521                oprofile_add_sample(regs, virt);
 522                wrmsrl(msrs->counters[i].addr, -(u64)reset_value[virt]);
 523        }
 524
 525        op_amd_handle_ibs(regs, msrs);
 526
 527        /* See op_model_ppro.c */
 528        return 1;
 529}
 530
 531static void op_amd_start(struct op_msrs const * const msrs)
 532{
 533        u64 val;
 534        int i;
 535
 536        for (i = 0; i < num_counters; ++i) {
 537                if (!reset_value[op_x86_phys_to_virt(i)])
 538                        continue;
 539                rdmsrl(msrs->controls[i].addr, val);
 540                val |= ARCH_PERFMON_EVENTSEL_ENABLE;
 541                wrmsrl(msrs->controls[i].addr, val);
 542        }
 543
 544        op_amd_start_ibs();
 545}
 546
 547static void op_amd_stop(struct op_msrs const * const msrs)
 548{
 549        u64 val;
 550        int i;
 551
 552        /*
 553         * Subtle: stop on all counters to avoid race with setting our
 554         * pm callback
 555         */
 556        for (i = 0; i < num_counters; ++i) {
 557                if (!reset_value[op_x86_phys_to_virt(i)])
 558                        continue;
 559                rdmsrl(msrs->controls[i].addr, val);
 560                val &= ~ARCH_PERFMON_EVENTSEL_ENABLE;
 561                wrmsrl(msrs->controls[i].addr, val);
 562        }
 563
 564        op_amd_stop_ibs();
 565}
 566
 567static int setup_ibs_ctl(int ibs_eilvt_off)
 568{
 569        struct pci_dev *cpu_cfg;
 570        int nodes;
 571        u32 value = 0;
 572
 573        nodes = 0;
 574        cpu_cfg = NULL;
 575        do {
 576                cpu_cfg = pci_get_device(PCI_VENDOR_ID_AMD,
 577                                         PCI_DEVICE_ID_AMD_10H_NB_MISC,
 578                                         cpu_cfg);
 579                if (!cpu_cfg)
 580                        break;
 581                ++nodes;
 582                pci_write_config_dword(cpu_cfg, IBSCTL, ibs_eilvt_off
 583                                       | IBSCTL_LVT_OFFSET_VALID);
 584                pci_read_config_dword(cpu_cfg, IBSCTL, &value);
 585                if (value != (ibs_eilvt_off | IBSCTL_LVT_OFFSET_VALID)) {
 586                        pci_dev_put(cpu_cfg);
 587                        printk(KERN_DEBUG "Failed to setup IBS LVT offset, "
 588                               "IBSCTL = 0x%08x\n", value);
 589                        return -EINVAL;
 590                }
 591        } while (1);
 592
 593        if (!nodes) {
 594                printk(KERN_DEBUG "No CPU node configured for IBS\n");
 595                return -ENODEV;
 596        }
 597
 598        return 0;
 599}
 600
 601static int force_ibs_eilvt_setup(void)
 602{
 603        int i;
 604        int ret;
 605
 606        /* find the next free available EILVT entry */
 607        for (i = 1; i < 4; i++) {
 608                if (!eilvt_is_available(i))
 609                        continue;
 610                ret = setup_ibs_ctl(i);
 611                if (ret)
 612                        return ret;
 613                pr_err(FW_BUG "using offset %d for IBS interrupts\n", i);
 614                return 0;
 615        }
 616
 617        printk(KERN_DEBUG "No EILVT entry available\n");
 618
 619        return -EBUSY;
 620}
 621
 622static int __init_ibs_nmi(void)
 623{
 624        int ret;
 625
 626        if (ibs_eilvt_valid())
 627                return 0;
 628
 629        ret = force_ibs_eilvt_setup();
 630        if (ret)
 631                return ret;
 632
 633        if (!ibs_eilvt_valid())
 634                return -EFAULT;
 635
 636        pr_err(FW_BUG "workaround enabled for IBS LVT offset\n");
 637
 638        return 0;
 639}
 640
 641/*
 642 * check and reserve APIC extended interrupt LVT offset for IBS if
 643 * available
 644 *
 645 * init_ibs() preforms implicitly cpu-local operations, so pin this
 646 * thread to its current CPU
 647 */
 648
 649static void init_ibs(void)
 650{
 651        preempt_disable();
 652
 653        ibs_caps = get_ibs_caps();
 654        if (!ibs_caps)
 655                goto out;
 656
 657        if (__init_ibs_nmi() < 0)
 658                ibs_caps = 0;
 659        else
 660                printk(KERN_INFO "oprofile: AMD IBS detected (0x%08x)\n", ibs_caps);
 661
 662out:
 663        preempt_enable();
 664}
 665
 666static int (*create_arch_files)(struct super_block *sb, struct dentry *root);
 667
 668static int setup_ibs_files(struct super_block *sb, struct dentry *root)
 669{
 670        struct dentry *dir;
 671        int ret = 0;
 672
 673        /* architecture specific files */
 674        if (create_arch_files)
 675                ret = create_arch_files(sb, root);
 676
 677        if (ret)
 678                return ret;
 679
 680        if (!ibs_caps)
 681                return ret;
 682
 683        /* model specific files */
 684
 685        /* setup some reasonable defaults */
 686        memset(&ibs_config, 0, sizeof(ibs_config));
 687        ibs_config.max_cnt_fetch = 250000;
 688        ibs_config.max_cnt_op = 250000;
 689
 690        if (ibs_caps & IBS_CAPS_FETCHSAM) {
 691                dir = oprofilefs_mkdir(sb, root, "ibs_fetch");
 692                oprofilefs_create_ulong(sb, dir, "enable",
 693                                        &ibs_config.fetch_enabled);
 694                oprofilefs_create_ulong(sb, dir, "max_count",
 695                                        &ibs_config.max_cnt_fetch);
 696                oprofilefs_create_ulong(sb, dir, "rand_enable",
 697                                        &ibs_config.rand_en);
 698        }
 699
 700        if (ibs_caps & IBS_CAPS_OPSAM) {
 701                dir = oprofilefs_mkdir(sb, root, "ibs_op");
 702                oprofilefs_create_ulong(sb, dir, "enable",
 703                                        &ibs_config.op_enabled);
 704                oprofilefs_create_ulong(sb, dir, "max_count",
 705                                        &ibs_config.max_cnt_op);
 706                if (ibs_caps & IBS_CAPS_OPCNT)
 707                        oprofilefs_create_ulong(sb, dir, "dispatched_ops",
 708                                                &ibs_config.dispatched_ops);
 709                if (ibs_caps & IBS_CAPS_BRNTRGT)
 710                        oprofilefs_create_ulong(sb, dir, "branch_target",
 711                                                &ibs_config.branch_target);
 712        }
 713
 714        return 0;
 715}
 716
 717struct op_x86_model_spec op_amd_spec;
 718
 719static int op_amd_init(struct oprofile_operations *ops)
 720{
 721        init_ibs();
 722        create_arch_files = ops->create_files;
 723        ops->create_files = setup_ibs_files;
 724
 725        if (boot_cpu_data.x86 == 0x15) {
 726                num_counters = NUM_COUNTERS_F15H;
 727        } else {
 728                num_counters = NUM_COUNTERS;
 729        }
 730
 731        op_amd_spec.num_counters = num_counters;
 732        op_amd_spec.num_controls = num_counters;
 733        op_amd_spec.num_virt_counters = max(num_counters, NUM_VIRT_COUNTERS);
 734
 735        return 0;
 736}
 737
 738struct op_x86_model_spec op_amd_spec = {
 739        /* num_counters/num_controls filled in at runtime */
 740        .reserved               = MSR_AMD_EVENTSEL_RESERVED,
 741        .event_mask             = OP_EVENT_MASK,
 742        .init                   = op_amd_init,
 743        .fill_in_addresses      = &op_amd_fill_in_addresses,
 744        .setup_ctrs             = &op_amd_setup_ctrs,
 745        .cpu_down               = &op_amd_cpu_shutdown,
 746        .check_ctrs             = &op_amd_check_ctrs,
 747        .start                  = &op_amd_start,
 748        .stop                   = &op_amd_stop,
 749        .shutdown               = &op_amd_shutdown,
 750#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX
 751        .switch_ctrl            = &op_mux_switch_ctrl,
 752#endif
 753};
 754