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
  26#include "op_x86_model.h"
  27#include "op_counter.h"
  28
  29#define NUM_COUNTERS 4
  30#define NUM_CONTROLS 4
  31#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX
  32#define NUM_VIRT_COUNTERS 32
  33#define NUM_VIRT_CONTROLS 32
  34#else
  35#define NUM_VIRT_COUNTERS NUM_COUNTERS
  36#define NUM_VIRT_CONTROLS NUM_CONTROLS
  37#endif
  38
  39#define OP_EVENT_MASK                   0x0FFF
  40#define OP_CTR_OVERFLOW                 (1ULL<<31)
  41
  42#define MSR_AMD_EVENTSEL_RESERVED       ((0xFFFFFCF0ULL<<32)|(1ULL<<21))
  43
  44static unsigned long reset_value[NUM_VIRT_COUNTERS];
  45
  46#ifdef CONFIG_OPROFILE_IBS
  47
  48/* IbsFetchCtl bits/masks */
  49#define IBS_FETCH_RAND_EN               (1ULL<<57)
  50#define IBS_FETCH_VAL                   (1ULL<<49)
  51#define IBS_FETCH_ENABLE                (1ULL<<48)
  52#define IBS_FETCH_CNT_MASK              0xFFFF0000ULL
  53
  54/*IbsOpCtl bits */
  55#define IBS_OP_CNT_CTL                  (1ULL<<19)
  56#define IBS_OP_VAL                      (1ULL<<18)
  57#define IBS_OP_ENABLE                   (1ULL<<17)
  58
  59#define IBS_FETCH_SIZE                  6
  60#define IBS_OP_SIZE                     12
  61
  62static int has_ibs;     /* AMD Family10h and later */
  63
  64struct op_ibs_config {
  65        unsigned long op_enabled;
  66        unsigned long fetch_enabled;
  67        unsigned long max_cnt_fetch;
  68        unsigned long max_cnt_op;
  69        unsigned long rand_en;
  70        unsigned long dispatched_ops;
  71};
  72
  73static struct op_ibs_config ibs_config;
  74
  75#endif
  76
  77#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX
  78
  79static void op_mux_fill_in_addresses(struct op_msrs * const msrs)
  80{
  81        int i;
  82
  83        for (i = 0; i < NUM_VIRT_COUNTERS; i++) {
  84                int hw_counter = op_x86_virt_to_phys(i);
  85                if (reserve_perfctr_nmi(MSR_K7_PERFCTR0 + i))
  86                        msrs->multiplex[i].addr = MSR_K7_PERFCTR0 + hw_counter;
  87                else
  88                        msrs->multiplex[i].addr = 0;
  89        }
  90}
  91
  92static void op_mux_switch_ctrl(struct op_x86_model_spec const *model,
  93                               struct op_msrs const * const msrs)
  94{
  95        u64 val;
  96        int i;
  97
  98        /* enable active counters */
  99        for (i = 0; i < NUM_COUNTERS; ++i) {
 100                int virt = op_x86_phys_to_virt(i);
 101                if (!counter_config[virt].enabled)
 102                        continue;
 103                rdmsrl(msrs->controls[i].addr, val);
 104                val &= model->reserved;
 105                val |= op_x86_get_ctrl(model, &counter_config[virt]);
 106                wrmsrl(msrs->controls[i].addr, val);
 107        }
 108}
 109
 110#else
 111
 112static inline void op_mux_fill_in_addresses(struct op_msrs * const msrs) { }
 113
 114#endif
 115
 116/* functions for op_amd_spec */
 117
 118static void op_amd_fill_in_addresses(struct op_msrs * const msrs)
 119{
 120        int i;
 121
 122        for (i = 0; i < NUM_COUNTERS; i++) {
 123                if (reserve_perfctr_nmi(MSR_K7_PERFCTR0 + i))
 124                        msrs->counters[i].addr = MSR_K7_PERFCTR0 + i;
 125                else
 126                        msrs->counters[i].addr = 0;
 127        }
 128
 129        for (i = 0; i < NUM_CONTROLS; i++) {
 130                if (reserve_evntsel_nmi(MSR_K7_EVNTSEL0 + i))
 131                        msrs->controls[i].addr = MSR_K7_EVNTSEL0 + i;
 132                else
 133                        msrs->controls[i].addr = 0;
 134        }
 135
 136        op_mux_fill_in_addresses(msrs);
 137}
 138
 139static void op_amd_setup_ctrs(struct op_x86_model_spec const *model,
 140                              struct op_msrs const * const msrs)
 141{
 142        u64 val;
 143        int i;
 144
 145        /* setup reset_value */
 146        for (i = 0; i < NUM_VIRT_COUNTERS; ++i) {
 147                if (counter_config[i].enabled)
 148                        reset_value[i] = counter_config[i].count;
 149                else
 150                        reset_value[i] = 0;
 151        }
 152
 153        /* clear all counters */
 154        for (i = 0; i < NUM_CONTROLS; ++i) {
 155                if (unlikely(!msrs->controls[i].addr))
 156                        continue;
 157                rdmsrl(msrs->controls[i].addr, val);
 158                val &= model->reserved;
 159                wrmsrl(msrs->controls[i].addr, val);
 160        }
 161
 162        /* avoid a false detection of ctr overflows in NMI handler */
 163        for (i = 0; i < NUM_COUNTERS; ++i) {
 164                if (unlikely(!msrs->counters[i].addr))
 165                        continue;
 166                wrmsrl(msrs->counters[i].addr, -1LL);
 167        }
 168
 169        /* enable active counters */
 170        for (i = 0; i < NUM_COUNTERS; ++i) {
 171                int virt = op_x86_phys_to_virt(i);
 172                if (!counter_config[virt].enabled)
 173                        continue;
 174                if (!msrs->counters[i].addr)
 175                        continue;
 176
 177                /* setup counter registers */
 178                wrmsrl(msrs->counters[i].addr, -(u64)reset_value[virt]);
 179
 180                /* setup control registers */
 181                rdmsrl(msrs->controls[i].addr, val);
 182                val &= model->reserved;
 183                val |= op_x86_get_ctrl(model, &counter_config[virt]);
 184                wrmsrl(msrs->controls[i].addr, val);
 185        }
 186}
 187
 188#ifdef CONFIG_OPROFILE_IBS
 189
 190static inline void
 191op_amd_handle_ibs(struct pt_regs * const regs,
 192                  struct op_msrs const * const msrs)
 193{
 194        u64 val, ctl;
 195        struct op_entry entry;
 196
 197        if (!has_ibs)
 198                return;
 199
 200        if (ibs_config.fetch_enabled) {
 201                rdmsrl(MSR_AMD64_IBSFETCHCTL, ctl);
 202                if (ctl & IBS_FETCH_VAL) {
 203                        rdmsrl(MSR_AMD64_IBSFETCHLINAD, val);
 204                        oprofile_write_reserve(&entry, regs, val,
 205                                               IBS_FETCH_CODE, IBS_FETCH_SIZE);
 206                        oprofile_add_data64(&entry, val);
 207                        oprofile_add_data64(&entry, ctl);
 208                        rdmsrl(MSR_AMD64_IBSFETCHPHYSAD, val);
 209                        oprofile_add_data64(&entry, val);
 210                        oprofile_write_commit(&entry);
 211
 212                        /* reenable the IRQ */
 213                        ctl &= ~(IBS_FETCH_VAL | IBS_FETCH_CNT_MASK);
 214                        ctl |= IBS_FETCH_ENABLE;
 215                        wrmsrl(MSR_AMD64_IBSFETCHCTL, ctl);
 216                }
 217        }
 218
 219        if (ibs_config.op_enabled) {
 220                rdmsrl(MSR_AMD64_IBSOPCTL, ctl);
 221                if (ctl & IBS_OP_VAL) {
 222                        rdmsrl(MSR_AMD64_IBSOPRIP, val);
 223                        oprofile_write_reserve(&entry, regs, val,
 224                                               IBS_OP_CODE, IBS_OP_SIZE);
 225                        oprofile_add_data64(&entry, val);
 226                        rdmsrl(MSR_AMD64_IBSOPDATA, val);
 227                        oprofile_add_data64(&entry, val);
 228                        rdmsrl(MSR_AMD64_IBSOPDATA2, val);
 229                        oprofile_add_data64(&entry, val);
 230                        rdmsrl(MSR_AMD64_IBSOPDATA3, val);
 231                        oprofile_add_data64(&entry, val);
 232                        rdmsrl(MSR_AMD64_IBSDCLINAD, val);
 233                        oprofile_add_data64(&entry, val);
 234                        rdmsrl(MSR_AMD64_IBSDCPHYSAD, val);
 235                        oprofile_add_data64(&entry, val);
 236                        oprofile_write_commit(&entry);
 237
 238                        /* reenable the IRQ */
 239                        ctl &= ~IBS_OP_VAL & 0xFFFFFFFF;
 240                        ctl |= IBS_OP_ENABLE;
 241                        wrmsrl(MSR_AMD64_IBSOPCTL, ctl);
 242                }
 243        }
 244}
 245
 246static inline void op_amd_start_ibs(void)
 247{
 248        u64 val;
 249        if (has_ibs && ibs_config.fetch_enabled) {
 250                val = (ibs_config.max_cnt_fetch >> 4) & 0xFFFF;
 251                val |= ibs_config.rand_en ? IBS_FETCH_RAND_EN : 0;
 252                val |= IBS_FETCH_ENABLE;
 253                wrmsrl(MSR_AMD64_IBSFETCHCTL, val);
 254        }
 255
 256        if (has_ibs && ibs_config.op_enabled) {
 257                val = (ibs_config.max_cnt_op >> 4) & 0xFFFF;
 258                val |= ibs_config.dispatched_ops ? IBS_OP_CNT_CTL : 0;
 259                val |= IBS_OP_ENABLE;
 260                wrmsrl(MSR_AMD64_IBSOPCTL, val);
 261        }
 262}
 263
 264static void op_amd_stop_ibs(void)
 265{
 266        if (has_ibs && ibs_config.fetch_enabled)
 267                /* clear max count and enable */
 268                wrmsrl(MSR_AMD64_IBSFETCHCTL, 0);
 269
 270        if (has_ibs && ibs_config.op_enabled)
 271                /* clear max count and enable */
 272                wrmsrl(MSR_AMD64_IBSOPCTL, 0);
 273}
 274
 275#else
 276
 277static inline void op_amd_handle_ibs(struct pt_regs * const regs,
 278                                    struct op_msrs const * const msrs) { }
 279static inline void op_amd_start_ibs(void) { }
 280static inline void op_amd_stop_ibs(void) { }
 281
 282#endif
 283
 284static int op_amd_check_ctrs(struct pt_regs * const regs,
 285                             struct op_msrs const * const msrs)
 286{
 287        u64 val;
 288        int i;
 289
 290        for (i = 0; i < NUM_COUNTERS; ++i) {
 291                int virt = op_x86_phys_to_virt(i);
 292                if (!reset_value[virt])
 293                        continue;
 294                rdmsrl(msrs->counters[i].addr, val);
 295                /* bit is clear if overflowed: */
 296                if (val & OP_CTR_OVERFLOW)
 297                        continue;
 298                oprofile_add_sample(regs, virt);
 299                wrmsrl(msrs->counters[i].addr, -(u64)reset_value[virt]);
 300        }
 301
 302        op_amd_handle_ibs(regs, msrs);
 303
 304        /* See op_model_ppro.c */
 305        return 1;
 306}
 307
 308static void op_amd_start(struct op_msrs const * const msrs)
 309{
 310        u64 val;
 311        int i;
 312
 313        for (i = 0; i < NUM_COUNTERS; ++i) {
 314                if (!reset_value[op_x86_phys_to_virt(i)])
 315                        continue;
 316                rdmsrl(msrs->controls[i].addr, val);
 317                val |= ARCH_PERFMON_EVENTSEL0_ENABLE;
 318                wrmsrl(msrs->controls[i].addr, val);
 319        }
 320
 321        op_amd_start_ibs();
 322}
 323
 324static void op_amd_stop(struct op_msrs const * const msrs)
 325{
 326        u64 val;
 327        int i;
 328
 329        /*
 330         * Subtle: stop on all counters to avoid race with setting our
 331         * pm callback
 332         */
 333        for (i = 0; i < NUM_COUNTERS; ++i) {
 334                if (!reset_value[op_x86_phys_to_virt(i)])
 335                        continue;
 336                rdmsrl(msrs->controls[i].addr, val);
 337                val &= ~ARCH_PERFMON_EVENTSEL0_ENABLE;
 338                wrmsrl(msrs->controls[i].addr, val);
 339        }
 340
 341        op_amd_stop_ibs();
 342}
 343
 344static void op_amd_shutdown(struct op_msrs const * const msrs)
 345{
 346        int i;
 347
 348        for (i = 0; i < NUM_COUNTERS; ++i) {
 349                if (msrs->counters[i].addr)
 350                        release_perfctr_nmi(MSR_K7_PERFCTR0 + i);
 351        }
 352        for (i = 0; i < NUM_CONTROLS; ++i) {
 353                if (msrs->controls[i].addr)
 354                        release_evntsel_nmi(MSR_K7_EVNTSEL0 + i);
 355        }
 356}
 357
 358#ifdef CONFIG_OPROFILE_IBS
 359
 360static u8 ibs_eilvt_off;
 361
 362static inline void apic_init_ibs_nmi_per_cpu(void *arg)
 363{
 364        ibs_eilvt_off = setup_APIC_eilvt_ibs(0, APIC_EILVT_MSG_NMI, 0);
 365}
 366
 367static inline void apic_clear_ibs_nmi_per_cpu(void *arg)
 368{
 369        setup_APIC_eilvt_ibs(0, APIC_EILVT_MSG_FIX, 1);
 370}
 371
 372static int init_ibs_nmi(void)
 373{
 374#define IBSCTL_LVTOFFSETVAL             (1 << 8)
 375#define IBSCTL                          0x1cc
 376        struct pci_dev *cpu_cfg;
 377        int nodes;
 378        u32 value = 0;
 379
 380        /* per CPU setup */
 381        on_each_cpu(apic_init_ibs_nmi_per_cpu, NULL, 1);
 382
 383        nodes = 0;
 384        cpu_cfg = NULL;
 385        do {
 386                cpu_cfg = pci_get_device(PCI_VENDOR_ID_AMD,
 387                                         PCI_DEVICE_ID_AMD_10H_NB_MISC,
 388                                         cpu_cfg);
 389                if (!cpu_cfg)
 390                        break;
 391                ++nodes;
 392                pci_write_config_dword(cpu_cfg, IBSCTL, ibs_eilvt_off
 393                                       | IBSCTL_LVTOFFSETVAL);
 394                pci_read_config_dword(cpu_cfg, IBSCTL, &value);
 395                if (value != (ibs_eilvt_off | IBSCTL_LVTOFFSETVAL)) {
 396                        pci_dev_put(cpu_cfg);
 397                        printk(KERN_DEBUG "Failed to setup IBS LVT offset, "
 398                                "IBSCTL = 0x%08x", value);
 399                        return 1;
 400                }
 401        } while (1);
 402
 403        if (!nodes) {
 404                printk(KERN_DEBUG "No CPU node configured for IBS");
 405                return 1;
 406        }
 407
 408#ifdef CONFIG_NUMA
 409        /* Sanity check */
 410        /* Works only for 64bit with proper numa implementation. */
 411        if (nodes != num_possible_nodes()) {
 412                printk(KERN_DEBUG "Failed to setup CPU node(s) for IBS, "
 413                        "found: %d, expected %d",
 414                        nodes, num_possible_nodes());
 415                return 1;
 416        }
 417#endif
 418        return 0;
 419}
 420
 421/* uninitialize the APIC for the IBS interrupts if needed */
 422static void clear_ibs_nmi(void)
 423{
 424        if (has_ibs)
 425                on_each_cpu(apic_clear_ibs_nmi_per_cpu, NULL, 1);
 426}
 427
 428/* initialize the APIC for the IBS interrupts if available */
 429static void ibs_init(void)
 430{
 431        has_ibs = boot_cpu_has(X86_FEATURE_IBS);
 432
 433        if (!has_ibs)
 434                return;
 435
 436        if (init_ibs_nmi()) {
 437                has_ibs = 0;
 438                return;
 439        }
 440
 441        printk(KERN_INFO "oprofile: AMD IBS detected\n");
 442}
 443
 444static void ibs_exit(void)
 445{
 446        if (!has_ibs)
 447                return;
 448
 449        clear_ibs_nmi();
 450}
 451
 452static int (*create_arch_files)(struct super_block *sb, struct dentry *root);
 453
 454static int setup_ibs_files(struct super_block *sb, struct dentry *root)
 455{
 456        struct dentry *dir;
 457        int ret = 0;
 458
 459        /* architecture specific files */
 460        if (create_arch_files)
 461                ret = create_arch_files(sb, root);
 462
 463        if (ret)
 464                return ret;
 465
 466        if (!has_ibs)
 467                return ret;
 468
 469        /* model specific files */
 470
 471        /* setup some reasonable defaults */
 472        ibs_config.max_cnt_fetch = 250000;
 473        ibs_config.fetch_enabled = 0;
 474        ibs_config.max_cnt_op = 250000;
 475        ibs_config.op_enabled = 0;
 476        ibs_config.dispatched_ops = 1;
 477
 478        dir = oprofilefs_mkdir(sb, root, "ibs_fetch");
 479        oprofilefs_create_ulong(sb, dir, "enable",
 480                                &ibs_config.fetch_enabled);
 481        oprofilefs_create_ulong(sb, dir, "max_count",
 482                                &ibs_config.max_cnt_fetch);
 483        oprofilefs_create_ulong(sb, dir, "rand_enable",
 484                                &ibs_config.rand_en);
 485
 486        dir = oprofilefs_mkdir(sb, root, "ibs_op");
 487        oprofilefs_create_ulong(sb, dir, "enable",
 488                                &ibs_config.op_enabled);
 489        oprofilefs_create_ulong(sb, dir, "max_count",
 490                                &ibs_config.max_cnt_op);
 491        oprofilefs_create_ulong(sb, dir, "dispatched_ops",
 492                                &ibs_config.dispatched_ops);
 493
 494        return 0;
 495}
 496
 497static int op_amd_init(struct oprofile_operations *ops)
 498{
 499        ibs_init();
 500        create_arch_files = ops->create_files;
 501        ops->create_files = setup_ibs_files;
 502        return 0;
 503}
 504
 505static void op_amd_exit(void)
 506{
 507        ibs_exit();
 508}
 509
 510#else
 511
 512/* no IBS support */
 513
 514static int op_amd_init(struct oprofile_operations *ops)
 515{
 516        return 0;
 517}
 518
 519static void op_amd_exit(void) {}
 520
 521#endif /* CONFIG_OPROFILE_IBS */
 522
 523struct op_x86_model_spec op_amd_spec = {
 524        .num_counters           = NUM_COUNTERS,
 525        .num_controls           = NUM_CONTROLS,
 526        .num_virt_counters      = NUM_VIRT_COUNTERS,
 527        .reserved               = MSR_AMD_EVENTSEL_RESERVED,
 528        .event_mask             = OP_EVENT_MASK,
 529        .init                   = op_amd_init,
 530        .exit                   = op_amd_exit,
 531        .fill_in_addresses      = &op_amd_fill_in_addresses,
 532        .setup_ctrs             = &op_amd_setup_ctrs,
 533        .check_ctrs             = &op_amd_check_ctrs,
 534        .start                  = &op_amd_start,
 535        .stop                   = &op_amd_stop,
 536        .shutdown               = &op_amd_shutdown,
 537#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX
 538        .switch_ctrl            = &op_mux_switch_ctrl,
 539#endif
 540};
 541
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.