linux/arch/powerpc/oprofile/op_model_fsl_emb.c
<<
>>
Prefs
   1/*
   2 * Freescale Embedded oprofile support, based on ppc64 oprofile support
   3 * Copyright (C) 2004 Anton Blanchard <anton@au.ibm.com>, IBM
   4 *
   5 * Copyright (c) 2004, 2010 Freescale Semiconductor, Inc
   6 *
   7 * Author: Andy Fleming
   8 * Maintainer: Kumar Gala <galak@kernel.crashing.org>
   9 *
  10 * This program is free software; you can redistribute it and/or
  11 * modify it under the terms of the GNU General Public License
  12 * as published by the Free Software Foundation; either version
  13 * 2 of the License, or (at your option) any later version.
  14 */
  15
  16#include <linux/oprofile.h>
  17#include <linux/init.h>
  18#include <linux/smp.h>
  19#include <asm/ptrace.h>
  20#include <asm/processor.h>
  21#include <asm/cputable.h>
  22#include <asm/reg_fsl_emb.h>
  23#include <asm/page.h>
  24#include <asm/pmc.h>
  25#include <asm/oprofile_impl.h>
  26
  27static unsigned long reset_value[OP_MAX_COUNTER];
  28
  29static int num_counters;
  30static int oprofile_running;
  31
  32static inline u32 get_pmlca(int ctr)
  33{
  34        u32 pmlca;
  35
  36        switch (ctr) {
  37                case 0:
  38                        pmlca = mfpmr(PMRN_PMLCA0);
  39                        break;
  40                case 1:
  41                        pmlca = mfpmr(PMRN_PMLCA1);
  42                        break;
  43                case 2:
  44                        pmlca = mfpmr(PMRN_PMLCA2);
  45                        break;
  46                case 3:
  47                        pmlca = mfpmr(PMRN_PMLCA3);
  48                        break;
  49                case 4:
  50                        pmlca = mfpmr(PMRN_PMLCA4);
  51                        break;
  52                case 5:
  53                        pmlca = mfpmr(PMRN_PMLCA5);
  54                        break;
  55                default:
  56                        panic("Bad ctr number\n");
  57        }
  58
  59        return pmlca;
  60}
  61
  62static inline void set_pmlca(int ctr, u32 pmlca)
  63{
  64        switch (ctr) {
  65                case 0:
  66                        mtpmr(PMRN_PMLCA0, pmlca);
  67                        break;
  68                case 1:
  69                        mtpmr(PMRN_PMLCA1, pmlca);
  70                        break;
  71                case 2:
  72                        mtpmr(PMRN_PMLCA2, pmlca);
  73                        break;
  74                case 3:
  75                        mtpmr(PMRN_PMLCA3, pmlca);
  76                        break;
  77                case 4:
  78                        mtpmr(PMRN_PMLCA4, pmlca);
  79                        break;
  80                case 5:
  81                        mtpmr(PMRN_PMLCA5, pmlca);
  82                        break;
  83                default:
  84                        panic("Bad ctr number\n");
  85        }
  86}
  87
  88static inline unsigned int ctr_read(unsigned int i)
  89{
  90        switch(i) {
  91                case 0:
  92                        return mfpmr(PMRN_PMC0);
  93                case 1:
  94                        return mfpmr(PMRN_PMC1);
  95                case 2:
  96                        return mfpmr(PMRN_PMC2);
  97                case 3:
  98                        return mfpmr(PMRN_PMC3);
  99                case 4:
 100                        return mfpmr(PMRN_PMC4);
 101                case 5:
 102                        return mfpmr(PMRN_PMC5);
 103                default:
 104                        return 0;
 105        }
 106}
 107
 108static inline void ctr_write(unsigned int i, unsigned int val)
 109{
 110        switch(i) {
 111                case 0:
 112                        mtpmr(PMRN_PMC0, val);
 113                        break;
 114                case 1:
 115                        mtpmr(PMRN_PMC1, val);
 116                        break;
 117                case 2:
 118                        mtpmr(PMRN_PMC2, val);
 119                        break;
 120                case 3:
 121                        mtpmr(PMRN_PMC3, val);
 122                        break;
 123                case 4:
 124                        mtpmr(PMRN_PMC4, val);
 125                        break;
 126                case 5:
 127                        mtpmr(PMRN_PMC5, val);
 128                        break;
 129                default:
 130                        break;
 131        }
 132}
 133
 134
 135static void init_pmc_stop(int ctr)
 136{
 137        u32 pmlca = (PMLCA_FC | PMLCA_FCS | PMLCA_FCU |
 138                        PMLCA_FCM1 | PMLCA_FCM0);
 139        u32 pmlcb = 0;
 140
 141        switch (ctr) {
 142                case 0:
 143                        mtpmr(PMRN_PMLCA0, pmlca);
 144                        mtpmr(PMRN_PMLCB0, pmlcb);
 145                        break;
 146                case 1:
 147                        mtpmr(PMRN_PMLCA1, pmlca);
 148                        mtpmr(PMRN_PMLCB1, pmlcb);
 149                        break;
 150                case 2:
 151                        mtpmr(PMRN_PMLCA2, pmlca);
 152                        mtpmr(PMRN_PMLCB2, pmlcb);
 153                        break;
 154                case 3:
 155                        mtpmr(PMRN_PMLCA3, pmlca);
 156                        mtpmr(PMRN_PMLCB3, pmlcb);
 157                        break;
 158                case 4:
 159                        mtpmr(PMRN_PMLCA4, pmlca);
 160                        mtpmr(PMRN_PMLCB4, pmlcb);
 161                        break;
 162                case 5:
 163                        mtpmr(PMRN_PMLCA5, pmlca);
 164                        mtpmr(PMRN_PMLCB5, pmlcb);
 165                        break;
 166                default:
 167                        panic("Bad ctr number!\n");
 168        }
 169}
 170
 171static void set_pmc_event(int ctr, int event)
 172{
 173        u32 pmlca;
 174
 175        pmlca = get_pmlca(ctr);
 176
 177        pmlca = (pmlca & ~PMLCA_EVENT_MASK) |
 178                ((event << PMLCA_EVENT_SHIFT) &
 179                 PMLCA_EVENT_MASK);
 180
 181        set_pmlca(ctr, pmlca);
 182}
 183
 184static void set_pmc_user_kernel(int ctr, int user, int kernel)
 185{
 186        u32 pmlca;
 187
 188        pmlca = get_pmlca(ctr);
 189
 190        if(user)
 191                pmlca &= ~PMLCA_FCU;
 192        else
 193                pmlca |= PMLCA_FCU;
 194
 195        if(kernel)
 196                pmlca &= ~PMLCA_FCS;
 197        else
 198                pmlca |= PMLCA_FCS;
 199
 200        set_pmlca(ctr, pmlca);
 201}
 202
 203static void set_pmc_marked(int ctr, int mark0, int mark1)
 204{
 205        u32 pmlca = get_pmlca(ctr);
 206
 207        if(mark0)
 208                pmlca &= ~PMLCA_FCM0;
 209        else
 210                pmlca |= PMLCA_FCM0;
 211
 212        if(mark1)
 213                pmlca &= ~PMLCA_FCM1;
 214        else
 215                pmlca |= PMLCA_FCM1;
 216
 217        set_pmlca(ctr, pmlca);
 218}
 219
 220static void pmc_start_ctr(int ctr, int enable)
 221{
 222        u32 pmlca = get_pmlca(ctr);
 223
 224        pmlca &= ~PMLCA_FC;
 225
 226        if (enable)
 227                pmlca |= PMLCA_CE;
 228        else
 229                pmlca &= ~PMLCA_CE;
 230
 231        set_pmlca(ctr, pmlca);
 232}
 233
 234static void pmc_start_ctrs(int enable)
 235{
 236        u32 pmgc0 = mfpmr(PMRN_PMGC0);
 237
 238        pmgc0 &= ~PMGC0_FAC;
 239        pmgc0 |= PMGC0_FCECE;
 240
 241        if (enable)
 242                pmgc0 |= PMGC0_PMIE;
 243        else
 244                pmgc0 &= ~PMGC0_PMIE;
 245
 246        mtpmr(PMRN_PMGC0, pmgc0);
 247}
 248
 249static void pmc_stop_ctrs(void)
 250{
 251        u32 pmgc0 = mfpmr(PMRN_PMGC0);
 252
 253        pmgc0 |= PMGC0_FAC;
 254
 255        pmgc0 &= ~(PMGC0_PMIE | PMGC0_FCECE);
 256
 257        mtpmr(PMRN_PMGC0, pmgc0);
 258}
 259
 260static int fsl_emb_cpu_setup(struct op_counter_config *ctr)
 261{
 262        int i;
 263
 264        /* freeze all counters */
 265        pmc_stop_ctrs();
 266
 267        for (i = 0;i < num_counters;i++) {
 268                init_pmc_stop(i);
 269
 270                set_pmc_event(i, ctr[i].event);
 271
 272                set_pmc_user_kernel(i, ctr[i].user, ctr[i].kernel);
 273        }
 274
 275        return 0;
 276}
 277
 278static int fsl_emb_reg_setup(struct op_counter_config *ctr,
 279                             struct op_system_config *sys,
 280                             int num_ctrs)
 281{
 282        int i;
 283
 284        num_counters = num_ctrs;
 285
 286        /* Our counters count up, and "count" refers to
 287         * how much before the next interrupt, and we interrupt
 288         * on overflow.  So we calculate the starting value
 289         * which will give us "count" until overflow.
 290         * Then we set the events on the enabled counters */
 291        for (i = 0; i < num_counters; ++i)
 292                reset_value[i] = 0x80000000UL - ctr[i].count;
 293
 294        return 0;
 295}
 296
 297static int fsl_emb_start(struct op_counter_config *ctr)
 298{
 299        int i;
 300
 301        mtmsr(mfmsr() | MSR_PMM);
 302
 303        for (i = 0; i < num_counters; ++i) {
 304                if (ctr[i].enabled) {
 305                        ctr_write(i, reset_value[i]);
 306                        /* Set each enabled counter to only
 307                         * count when the Mark bit is *not* set */
 308                        set_pmc_marked(i, 1, 0);
 309                        pmc_start_ctr(i, 1);
 310                } else {
 311                        ctr_write(i, 0);
 312
 313                        /* Set the ctr to be stopped */
 314                        pmc_start_ctr(i, 0);
 315                }
 316        }
 317
 318        /* Clear the freeze bit, and enable the interrupt.
 319         * The counters won't actually start until the rfi clears
 320         * the PMM bit */
 321        pmc_start_ctrs(1);
 322
 323        oprofile_running = 1;
 324
 325        pr_debug("start on cpu %d, pmgc0 %x\n", smp_processor_id(),
 326                        mfpmr(PMRN_PMGC0));
 327
 328        return 0;
 329}
 330
 331static void fsl_emb_stop(void)
 332{
 333        /* freeze counters */
 334        pmc_stop_ctrs();
 335
 336        oprofile_running = 0;
 337
 338        pr_debug("stop on cpu %d, pmgc0 %x\n", smp_processor_id(),
 339                        mfpmr(PMRN_PMGC0));
 340
 341        mb();
 342}
 343
 344
 345static void fsl_emb_handle_interrupt(struct pt_regs *regs,
 346                                    struct op_counter_config *ctr)
 347{
 348        unsigned long pc;
 349        int is_kernel;
 350        int val;
 351        int i;
 352
 353        pc = regs->nip;
 354        is_kernel = is_kernel_addr(pc);
 355
 356        for (i = 0; i < num_counters; ++i) {
 357                val = ctr_read(i);
 358                if (val < 0) {
 359                        if (oprofile_running && ctr[i].enabled) {
 360                                oprofile_add_ext_sample(pc, regs, i, is_kernel);
 361                                ctr_write(i, reset_value[i]);
 362                        } else {
 363                                ctr_write(i, 0);
 364                        }
 365                }
 366        }
 367
 368        /* The freeze bit was set by the interrupt. */
 369        /* Clear the freeze bit, and reenable the interrupt.  The
 370         * counters won't actually start until the rfi clears the PMM
 371         * bit.  The PMM bit should not be set until after the interrupt
 372         * is cleared to avoid it getting lost in some hypervisor
 373         * environments.
 374         */
 375        mtmsr(mfmsr() | MSR_PMM);
 376        pmc_start_ctrs(1);
 377}
 378
 379struct op_powerpc_model op_model_fsl_emb = {
 380        .reg_setup              = fsl_emb_reg_setup,
 381        .cpu_setup              = fsl_emb_cpu_setup,
 382        .start                  = fsl_emb_start,
 383        .stop                   = fsl_emb_stop,
 384        .handle_interrupt       = fsl_emb_handle_interrupt,
 385};
 386