linux/arch/powerpc/kernel/perf_event_fsl_emb.c
<<
>>
Prefs
   1/*
   2 * Performance event support - Freescale Embedded Performance Monitor
   3 *
   4 * Copyright 2008-2009 Paul Mackerras, IBM Corporation.
   5 * Copyright 2010 Freescale Semiconductor, Inc.
   6 *
   7 * This program is free software; you can redistribute it and/or
   8 * modify it under the terms of the GNU General Public License
   9 * as published by the Free Software Foundation; either version
  10 * 2 of the License, or (at your option) any later version.
  11 */
  12#include <linux/kernel.h>
  13#include <linux/sched.h>
  14#include <linux/perf_event.h>
  15#include <linux/percpu.h>
  16#include <linux/hardirq.h>
  17#include <asm/reg_fsl_emb.h>
  18#include <asm/pmc.h>
  19#include <asm/machdep.h>
  20#include <asm/firmware.h>
  21#include <asm/ptrace.h>
  22
  23struct cpu_hw_events {
  24        int n_events;
  25        int disabled;
  26        u8  pmcs_enabled;
  27        struct perf_event *event[MAX_HWEVENTS];
  28};
  29static DEFINE_PER_CPU(struct cpu_hw_events, cpu_hw_events);
  30
  31static struct fsl_emb_pmu *ppmu;
  32
  33/* Number of perf_events counting hardware events */
  34static atomic_t num_events;
  35/* Used to avoid races in calling reserve/release_pmc_hardware */
  36static DEFINE_MUTEX(pmc_reserve_mutex);
  37
  38/*
  39 * If interrupts were soft-disabled when a PMU interrupt occurs, treat
  40 * it as an NMI.
  41 */
  42static inline int perf_intr_is_nmi(struct pt_regs *regs)
  43{
  44#ifdef __powerpc64__
  45        return !regs->softe;
  46#else
  47        return 0;
  48#endif
  49}
  50
  51static void perf_event_interrupt(struct pt_regs *regs);
  52
  53/*
  54 * Read one performance monitor counter (PMC).
  55 */
  56static unsigned long read_pmc(int idx)
  57{
  58        unsigned long val;
  59
  60        switch (idx) {
  61        case 0:
  62                val = mfpmr(PMRN_PMC0);
  63                break;
  64        case 1:
  65                val = mfpmr(PMRN_PMC1);
  66                break;
  67        case 2:
  68                val = mfpmr(PMRN_PMC2);
  69                break;
  70        case 3:
  71                val = mfpmr(PMRN_PMC3);
  72                break;
  73        default:
  74                printk(KERN_ERR "oops trying to read PMC%d\n", idx);
  75                val = 0;
  76        }
  77        return val;
  78}
  79
  80/*
  81 * Write one PMC.
  82 */
  83static void write_pmc(int idx, unsigned long val)
  84{
  85        switch (idx) {
  86        case 0:
  87                mtpmr(PMRN_PMC0, val);
  88                break;
  89        case 1:
  90                mtpmr(PMRN_PMC1, val);
  91                break;
  92        case 2:
  93                mtpmr(PMRN_PMC2, val);
  94                break;
  95        case 3:
  96                mtpmr(PMRN_PMC3, val);
  97                break;
  98        default:
  99                printk(KERN_ERR "oops trying to write PMC%d\n", idx);
 100        }
 101
 102        isync();
 103}
 104
 105/*
 106 * Write one local control A register
 107 */
 108static void write_pmlca(int idx, unsigned long val)
 109{
 110        switch (idx) {
 111        case 0:
 112                mtpmr(PMRN_PMLCA0, val);
 113                break;
 114        case 1:
 115                mtpmr(PMRN_PMLCA1, val);
 116                break;
 117        case 2:
 118                mtpmr(PMRN_PMLCA2, val);
 119                break;
 120        case 3:
 121                mtpmr(PMRN_PMLCA3, val);
 122                break;
 123        default:
 124                printk(KERN_ERR "oops trying to write PMLCA%d\n", idx);
 125        }
 126
 127        isync();
 128}
 129
 130/*
 131 * Write one local control B register
 132 */
 133static void write_pmlcb(int idx, unsigned long val)
 134{
 135        switch (idx) {
 136        case 0:
 137                mtpmr(PMRN_PMLCB0, val);
 138                break;
 139        case 1:
 140                mtpmr(PMRN_PMLCB1, val);
 141                break;
 142        case 2:
 143                mtpmr(PMRN_PMLCB2, val);
 144                break;
 145        case 3:
 146                mtpmr(PMRN_PMLCB3, val);
 147                break;
 148        default:
 149                printk(KERN_ERR "oops trying to write PMLCB%d\n", idx);
 150        }
 151
 152        isync();
 153}
 154
 155static void fsl_emb_pmu_read(struct perf_event *event)
 156{
 157        s64 val, delta, prev;
 158
 159        if (event->hw.state & PERF_HES_STOPPED)
 160                return;
 161
 162        /*
 163         * Performance monitor interrupts come even when interrupts
 164         * are soft-disabled, as long as interrupts are hard-enabled.
 165         * Therefore we treat them like NMIs.
 166         */
 167        do {
 168                prev = local64_read(&event->hw.prev_count);
 169                barrier();
 170                val = read_pmc(event->hw.idx);
 171        } while (local64_cmpxchg(&event->hw.prev_count, prev, val) != prev);
 172
 173        /* The counters are only 32 bits wide */
 174        delta = (val - prev) & 0xfffffffful;
 175        local64_add(delta, &event->count);
 176        local64_sub(delta, &event->hw.period_left);
 177}
 178
 179/*
 180 * Disable all events to prevent PMU interrupts and to allow
 181 * events to be added or removed.
 182 */
 183static void fsl_emb_pmu_disable(struct pmu *pmu)
 184{
 185        struct cpu_hw_events *cpuhw;
 186        unsigned long flags;
 187
 188        local_irq_save(flags);
 189        cpuhw = &__get_cpu_var(cpu_hw_events);
 190
 191        if (!cpuhw->disabled) {
 192                cpuhw->disabled = 1;
 193
 194                /*
 195                 * Check if we ever enabled the PMU on this cpu.
 196                 */
 197                if (!cpuhw->pmcs_enabled) {
 198                        ppc_enable_pmcs();
 199                        cpuhw->pmcs_enabled = 1;
 200                }
 201
 202                if (atomic_read(&num_events)) {
 203                        /*
 204                         * Set the 'freeze all counters' bit, and disable
 205                         * interrupts.  The barrier is to make sure the
 206                         * mtpmr has been executed and the PMU has frozen
 207                         * the events before we return.
 208                         */
 209
 210                        mtpmr(PMRN_PMGC0, PMGC0_FAC);
 211                        isync();
 212                }
 213        }
 214        local_irq_restore(flags);
 215}
 216
 217/*
 218 * Re-enable all events if disable == 0.
 219 * If we were previously disabled and events were added, then
 220 * put the new config on the PMU.
 221 */
 222static void fsl_emb_pmu_enable(struct pmu *pmu)
 223{
 224        struct cpu_hw_events *cpuhw;
 225        unsigned long flags;
 226
 227        local_irq_save(flags);
 228        cpuhw = &__get_cpu_var(cpu_hw_events);
 229        if (!cpuhw->disabled)
 230                goto out;
 231
 232        cpuhw->disabled = 0;
 233        ppc_set_pmu_inuse(cpuhw->n_events != 0);
 234
 235        if (cpuhw->n_events > 0) {
 236                mtpmr(PMRN_PMGC0, PMGC0_PMIE | PMGC0_FCECE);
 237                isync();
 238        }
 239
 240 out:
 241        local_irq_restore(flags);
 242}
 243
 244static int collect_events(struct perf_event *group, int max_count,
 245                          struct perf_event *ctrs[])
 246{
 247        int n = 0;
 248        struct perf_event *event;
 249
 250        if (!is_software_event(group)) {
 251                if (n >= max_count)
 252                        return -1;
 253                ctrs[n] = group;
 254                n++;
 255        }
 256        list_for_each_entry(event, &group->sibling_list, group_entry) {
 257                if (!is_software_event(event) &&
 258                    event->state != PERF_EVENT_STATE_OFF) {
 259                        if (n >= max_count)
 260                                return -1;
 261                        ctrs[n] = event;
 262                        n++;
 263                }
 264        }
 265        return n;
 266}
 267
 268/* context locked on entry */
 269static int fsl_emb_pmu_add(struct perf_event *event, int flags)
 270{
 271        struct cpu_hw_events *cpuhw;
 272        int ret = -EAGAIN;
 273        int num_counters = ppmu->n_counter;
 274        u64 val;
 275        int i;
 276
 277        perf_pmu_disable(event->pmu);
 278        cpuhw = &get_cpu_var(cpu_hw_events);
 279
 280        if (event->hw.config & FSL_EMB_EVENT_RESTRICTED)
 281                num_counters = ppmu->n_restricted;
 282
 283        /*
 284         * Allocate counters from top-down, so that restricted-capable
 285         * counters are kept free as long as possible.
 286         */
 287        for (i = num_counters - 1; i >= 0; i--) {
 288                if (cpuhw->event[i])
 289                        continue;
 290
 291                break;
 292        }
 293
 294        if (i < 0)
 295                goto out;
 296
 297        event->hw.idx = i;
 298        cpuhw->event[i] = event;
 299        ++cpuhw->n_events;
 300
 301        val = 0;
 302        if (event->hw.sample_period) {
 303                s64 left = local64_read(&event->hw.period_left);
 304                if (left < 0x80000000L)
 305                        val = 0x80000000L - left;
 306        }
 307        local64_set(&event->hw.prev_count, val);
 308
 309        if (!(flags & PERF_EF_START)) {
 310                event->hw.state = PERF_HES_STOPPED | PERF_HES_UPTODATE;
 311                val = 0;
 312        }
 313
 314        write_pmc(i, val);
 315        perf_event_update_userpage(event);
 316
 317        write_pmlcb(i, event->hw.config >> 32);
 318        write_pmlca(i, event->hw.config_base);
 319
 320        ret = 0;
 321 out:
 322        put_cpu_var(cpu_hw_events);
 323        perf_pmu_enable(event->pmu);
 324        return ret;
 325}
 326
 327/* context locked on entry */
 328static void fsl_emb_pmu_del(struct perf_event *event, int flags)
 329{
 330        struct cpu_hw_events *cpuhw;
 331        int i = event->hw.idx;
 332
 333        perf_pmu_disable(event->pmu);
 334        if (i < 0)
 335                goto out;
 336
 337        fsl_emb_pmu_read(event);
 338
 339        cpuhw = &get_cpu_var(cpu_hw_events);
 340
 341        WARN_ON(event != cpuhw->event[event->hw.idx]);
 342
 343        write_pmlca(i, 0);
 344        write_pmlcb(i, 0);
 345        write_pmc(i, 0);
 346
 347        cpuhw->event[i] = NULL;
 348        event->hw.idx = -1;
 349
 350        /*
 351         * TODO: if at least one restricted event exists, and we
 352         * just freed up a non-restricted-capable counter, and
 353         * there is a restricted-capable counter occupied by
 354         * a non-restricted event, migrate that event to the
 355         * vacated counter.
 356         */
 357
 358        cpuhw->n_events--;
 359
 360 out:
 361        perf_pmu_enable(event->pmu);
 362        put_cpu_var(cpu_hw_events);
 363}
 364
 365static void fsl_emb_pmu_start(struct perf_event *event, int ef_flags)
 366{
 367        unsigned long flags;
 368        s64 left;
 369
 370        if (event->hw.idx < 0 || !event->hw.sample_period)
 371                return;
 372
 373        if (!(event->hw.state & PERF_HES_STOPPED))
 374                return;
 375
 376        if (ef_flags & PERF_EF_RELOAD)
 377                WARN_ON_ONCE(!(event->hw.state & PERF_HES_UPTODATE));
 378
 379        local_irq_save(flags);
 380        perf_pmu_disable(event->pmu);
 381
 382        event->hw.state = 0;
 383        left = local64_read(&event->hw.period_left);
 384        write_pmc(event->hw.idx, left);
 385
 386        perf_event_update_userpage(event);
 387        perf_pmu_enable(event->pmu);
 388        local_irq_restore(flags);
 389}
 390
 391static void fsl_emb_pmu_stop(struct perf_event *event, int ef_flags)
 392{
 393        unsigned long flags;
 394
 395        if (event->hw.idx < 0 || !event->hw.sample_period)
 396                return;
 397
 398        if (event->hw.state & PERF_HES_STOPPED)
 399                return;
 400
 401        local_irq_save(flags);
 402        perf_pmu_disable(event->pmu);
 403
 404        fsl_emb_pmu_read(event);
 405        event->hw.state |= PERF_HES_STOPPED | PERF_HES_UPTODATE;
 406        write_pmc(event->hw.idx, 0);
 407
 408        perf_event_update_userpage(event);
 409        perf_pmu_enable(event->pmu);
 410        local_irq_restore(flags);
 411}
 412
 413/*
 414 * Release the PMU if this is the last perf_event.
 415 */
 416static void hw_perf_event_destroy(struct perf_event *event)
 417{
 418        if (!atomic_add_unless(&num_events, -1, 1)) {
 419                mutex_lock(&pmc_reserve_mutex);
 420                if (atomic_dec_return(&num_events) == 0)
 421                        release_pmc_hardware();
 422                mutex_unlock(&pmc_reserve_mutex);
 423        }
 424}
 425
 426/*
 427 * Translate a generic cache event_id config to a raw event_id code.
 428 */
 429static int hw_perf_cache_event(u64 config, u64 *eventp)
 430{
 431        unsigned long type, op, result;
 432        int ev;
 433
 434        if (!ppmu->cache_events)
 435                return -EINVAL;
 436
 437        /* unpack config */
 438        type = config & 0xff;
 439        op = (config >> 8) & 0xff;
 440        result = (config >> 16) & 0xff;
 441
 442        if (type >= PERF_COUNT_HW_CACHE_MAX ||
 443            op >= PERF_COUNT_HW_CACHE_OP_MAX ||
 444            result >= PERF_COUNT_HW_CACHE_RESULT_MAX)
 445                return -EINVAL;
 446
 447        ev = (*ppmu->cache_events)[type][op][result];
 448        if (ev == 0)
 449                return -EOPNOTSUPP;
 450        if (ev == -1)
 451                return -EINVAL;
 452        *eventp = ev;
 453        return 0;
 454}
 455
 456static int fsl_emb_pmu_event_init(struct perf_event *event)
 457{
 458        u64 ev;
 459        struct perf_event *events[MAX_HWEVENTS];
 460        int n;
 461        int err;
 462        int num_restricted;
 463        int i;
 464
 465        switch (event->attr.type) {
 466        case PERF_TYPE_HARDWARE:
 467                ev = event->attr.config;
 468                if (ev >= ppmu->n_generic || ppmu->generic_events[ev] == 0)
 469                        return -EOPNOTSUPP;
 470                ev = ppmu->generic_events[ev];
 471                break;
 472
 473        case PERF_TYPE_HW_CACHE:
 474                err = hw_perf_cache_event(event->attr.config, &ev);
 475                if (err)
 476                        return err;
 477                break;
 478
 479        case PERF_TYPE_RAW:
 480                ev = event->attr.config;
 481                break;
 482
 483        default:
 484                return -ENOENT;
 485        }
 486
 487        event->hw.config = ppmu->xlate_event(ev);
 488        if (!(event->hw.config & FSL_EMB_EVENT_VALID))
 489                return -EINVAL;
 490
 491        /*
 492         * If this is in a group, check if it can go on with all the
 493         * other hardware events in the group.  We assume the event
 494         * hasn't been linked into its leader's sibling list at this point.
 495         */
 496        n = 0;
 497        if (event->group_leader != event) {
 498                n = collect_events(event->group_leader,
 499                                   ppmu->n_counter - 1, events);
 500                if (n < 0)
 501                        return -EINVAL;
 502        }
 503
 504        if (event->hw.config & FSL_EMB_EVENT_RESTRICTED) {
 505                num_restricted = 0;
 506                for (i = 0; i < n; i++) {
 507                        if (events[i]->hw.config & FSL_EMB_EVENT_RESTRICTED)
 508                                num_restricted++;
 509                }
 510
 511                if (num_restricted >= ppmu->n_restricted)
 512                        return -EINVAL;
 513        }
 514
 515        event->hw.idx = -1;
 516
 517        event->hw.config_base = PMLCA_CE | PMLCA_FCM1 |
 518                                (u32)((ev << 16) & PMLCA_EVENT_MASK);
 519
 520        if (event->attr.exclude_user)
 521                event->hw.config_base |= PMLCA_FCU;
 522        if (event->attr.exclude_kernel)
 523                event->hw.config_base |= PMLCA_FCS;
 524        if (event->attr.exclude_idle)
 525                return -ENOTSUPP;
 526
 527        event->hw.last_period = event->hw.sample_period;
 528        local64_set(&event->hw.period_left, event->hw.last_period);
 529
 530        /*
 531         * See if we need to reserve the PMU.
 532         * If no events are currently in use, then we have to take a
 533         * mutex to ensure that we don't race with another task doing
 534         * reserve_pmc_hardware or release_pmc_hardware.
 535         */
 536        err = 0;
 537        if (!atomic_inc_not_zero(&num_events)) {
 538                mutex_lock(&pmc_reserve_mutex);
 539                if (atomic_read(&num_events) == 0 &&
 540                    reserve_pmc_hardware(perf_event_interrupt))
 541                        err = -EBUSY;
 542                else
 543                        atomic_inc(&num_events);
 544                mutex_unlock(&pmc_reserve_mutex);
 545
 546                mtpmr(PMRN_PMGC0, PMGC0_FAC);
 547                isync();
 548        }
 549        event->destroy = hw_perf_event_destroy;
 550
 551        return err;
 552}
 553
 554static struct pmu fsl_emb_pmu = {
 555        .pmu_enable     = fsl_emb_pmu_enable,
 556        .pmu_disable    = fsl_emb_pmu_disable,
 557        .event_init     = fsl_emb_pmu_event_init,
 558        .add            = fsl_emb_pmu_add,
 559        .del            = fsl_emb_pmu_del,
 560        .start          = fsl_emb_pmu_start,
 561        .stop           = fsl_emb_pmu_stop,
 562        .read           = fsl_emb_pmu_read,
 563};
 564
 565/*
 566 * A counter has overflowed; update its count and record
 567 * things if requested.  Note that interrupts are hard-disabled
 568 * here so there is no possibility of being interrupted.
 569 */
 570static void record_and_restart(struct perf_event *event, unsigned long val,
 571                               struct pt_regs *regs, int nmi)
 572{
 573        u64 period = event->hw.sample_period;
 574        s64 prev, delta, left;
 575        int record = 0;
 576
 577        if (event->hw.state & PERF_HES_STOPPED) {
 578                write_pmc(event->hw.idx, 0);
 579                return;
 580        }
 581
 582        /* we don't have to worry about interrupts here */
 583        prev = local64_read(&event->hw.prev_count);
 584        delta = (val - prev) & 0xfffffffful;
 585        local64_add(delta, &event->count);
 586
 587        /*
 588         * See if the total period for this event has expired,
 589         * and update for the next period.
 590         */
 591        val = 0;
 592        left = local64_read(&event->hw.period_left) - delta;
 593        if (period) {
 594                if (left <= 0) {
 595                        left += period;
 596                        if (left <= 0)
 597                                left = period;
 598                        record = 1;
 599                        event->hw.last_period = event->hw.sample_period;
 600                }
 601                if (left < 0x80000000LL)
 602                        val = 0x80000000LL - left;
 603        }
 604
 605        write_pmc(event->hw.idx, val);
 606        local64_set(&event->hw.prev_count, val);
 607        local64_set(&event->hw.period_left, left);
 608        perf_event_update_userpage(event);
 609
 610        /*
 611         * Finally record data if requested.
 612         */
 613        if (record) {
 614                struct perf_sample_data data;
 615
 616                perf_sample_data_init(&data, 0);
 617                data.period = event->hw.last_period;
 618
 619                if (perf_event_overflow(event, nmi, &data, regs))
 620                        fsl_emb_pmu_stop(event, 0);
 621        }
 622}
 623
 624static void perf_event_interrupt(struct pt_regs *regs)
 625{
 626        int i;
 627        struct cpu_hw_events *cpuhw = &__get_cpu_var(cpu_hw_events);
 628        struct perf_event *event;
 629        unsigned long val;
 630        int found = 0;
 631        int nmi;
 632
 633        nmi = perf_intr_is_nmi(regs);
 634        if (nmi)
 635                nmi_enter();
 636        else
 637                irq_enter();
 638
 639        for (i = 0; i < ppmu->n_counter; ++i) {
 640                event = cpuhw->event[i];
 641
 642                val = read_pmc(i);
 643                if ((int)val < 0) {
 644                        if (event) {
 645                                /* event has overflowed */
 646                                found = 1;
 647                                record_and_restart(event, val, regs, nmi);
 648                        } else {
 649                                /*
 650                                 * Disabled counter is negative,
 651                                 * reset it just in case.
 652                                 */
 653                                write_pmc(i, 0);
 654                        }
 655                }
 656        }
 657
 658        /* PMM will keep counters frozen until we return from the interrupt. */
 659        mtmsr(mfmsr() | MSR_PMM);
 660        mtpmr(PMRN_PMGC0, PMGC0_PMIE | PMGC0_FCECE);
 661        isync();
 662
 663        if (nmi)
 664                nmi_exit();
 665        else
 666                irq_exit();
 667}
 668
 669void hw_perf_event_setup(int cpu)
 670{
 671        struct cpu_hw_events *cpuhw = &per_cpu(cpu_hw_events, cpu);
 672
 673        memset(cpuhw, 0, sizeof(*cpuhw));
 674}
 675
 676int register_fsl_emb_pmu(struct fsl_emb_pmu *pmu)
 677{
 678        if (ppmu)
 679                return -EBUSY;          /* something's already registered */
 680
 681        ppmu = pmu;
 682        pr_info("%s performance monitor hardware support registered\n",
 683                pmu->name);
 684
 685        perf_pmu_register(&fsl_emb_pmu, "cpu", PERF_TYPE_RAW);
 686
 687        return 0;
 688}
 689