Back to home page

LXR

 
 

    


0001 /*
0002  * Freescale Embedded oprofile support, based on ppc64 oprofile support
0003  * Copyright (C) 2004 Anton Blanchard <anton@au.ibm.com>, IBM
0004  *
0005  * Copyright (c) 2004, 2010 Freescale Semiconductor, Inc
0006  *
0007  * Author: Andy Fleming
0008  * Maintainer: Kumar Gala <galak@kernel.crashing.org>
0009  *
0010  * This program is free software; you can redistribute it and/or
0011  * modify it under the terms of the GNU General Public License
0012  * as published by the Free Software Foundation; either version
0013  * 2 of the License, or (at your option) any later version.
0014  */
0015 
0016 #include <linux/oprofile.h>
0017 #include <linux/smp.h>
0018 #include <asm/ptrace.h>
0019 #include <asm/processor.h>
0020 #include <asm/cputable.h>
0021 #include <asm/reg_fsl_emb.h>
0022 #include <asm/page.h>
0023 #include <asm/pmc.h>
0024 #include <asm/oprofile_impl.h>
0025 
0026 static unsigned long reset_value[OP_MAX_COUNTER];
0027 
0028 static int num_counters;
0029 static int oprofile_running;
0030 
0031 static inline u32 get_pmlca(int ctr)
0032 {
0033     u32 pmlca;
0034 
0035     switch (ctr) {
0036         case 0:
0037             pmlca = mfpmr(PMRN_PMLCA0);
0038             break;
0039         case 1:
0040             pmlca = mfpmr(PMRN_PMLCA1);
0041             break;
0042         case 2:
0043             pmlca = mfpmr(PMRN_PMLCA2);
0044             break;
0045         case 3:
0046             pmlca = mfpmr(PMRN_PMLCA3);
0047             break;
0048         case 4:
0049             pmlca = mfpmr(PMRN_PMLCA4);
0050             break;
0051         case 5:
0052             pmlca = mfpmr(PMRN_PMLCA5);
0053             break;
0054         default:
0055             panic("Bad ctr number\n");
0056     }
0057 
0058     return pmlca;
0059 }
0060 
0061 static inline void set_pmlca(int ctr, u32 pmlca)
0062 {
0063     switch (ctr) {
0064         case 0:
0065             mtpmr(PMRN_PMLCA0, pmlca);
0066             break;
0067         case 1:
0068             mtpmr(PMRN_PMLCA1, pmlca);
0069             break;
0070         case 2:
0071             mtpmr(PMRN_PMLCA2, pmlca);
0072             break;
0073         case 3:
0074             mtpmr(PMRN_PMLCA3, pmlca);
0075             break;
0076         case 4:
0077             mtpmr(PMRN_PMLCA4, pmlca);
0078             break;
0079         case 5:
0080             mtpmr(PMRN_PMLCA5, pmlca);
0081             break;
0082         default:
0083             panic("Bad ctr number\n");
0084     }
0085 }
0086 
0087 static inline unsigned int ctr_read(unsigned int i)
0088 {
0089     switch(i) {
0090         case 0:
0091             return mfpmr(PMRN_PMC0);
0092         case 1:
0093             return mfpmr(PMRN_PMC1);
0094         case 2:
0095             return mfpmr(PMRN_PMC2);
0096         case 3:
0097             return mfpmr(PMRN_PMC3);
0098         case 4:
0099             return mfpmr(PMRN_PMC4);
0100         case 5:
0101             return mfpmr(PMRN_PMC5);
0102         default:
0103             return 0;
0104     }
0105 }
0106 
0107 static inline void ctr_write(unsigned int i, unsigned int val)
0108 {
0109     switch(i) {
0110         case 0:
0111             mtpmr(PMRN_PMC0, val);
0112             break;
0113         case 1:
0114             mtpmr(PMRN_PMC1, val);
0115             break;
0116         case 2:
0117             mtpmr(PMRN_PMC2, val);
0118             break;
0119         case 3:
0120             mtpmr(PMRN_PMC3, val);
0121             break;
0122         case 4:
0123             mtpmr(PMRN_PMC4, val);
0124             break;
0125         case 5:
0126             mtpmr(PMRN_PMC5, val);
0127             break;
0128         default:
0129             break;
0130     }
0131 }
0132 
0133 
0134 static void init_pmc_stop(int ctr)
0135 {
0136     u32 pmlca = (PMLCA_FC | PMLCA_FCS | PMLCA_FCU |
0137             PMLCA_FCM1 | PMLCA_FCM0);
0138     u32 pmlcb = 0;
0139 
0140     switch (ctr) {
0141         case 0:
0142             mtpmr(PMRN_PMLCA0, pmlca);
0143             mtpmr(PMRN_PMLCB0, pmlcb);
0144             break;
0145         case 1:
0146             mtpmr(PMRN_PMLCA1, pmlca);
0147             mtpmr(PMRN_PMLCB1, pmlcb);
0148             break;
0149         case 2:
0150             mtpmr(PMRN_PMLCA2, pmlca);
0151             mtpmr(PMRN_PMLCB2, pmlcb);
0152             break;
0153         case 3:
0154             mtpmr(PMRN_PMLCA3, pmlca);
0155             mtpmr(PMRN_PMLCB3, pmlcb);
0156             break;
0157         case 4:
0158             mtpmr(PMRN_PMLCA4, pmlca);
0159             mtpmr(PMRN_PMLCB4, pmlcb);
0160             break;
0161         case 5:
0162             mtpmr(PMRN_PMLCA5, pmlca);
0163             mtpmr(PMRN_PMLCB5, pmlcb);
0164             break;
0165         default:
0166             panic("Bad ctr number!\n");
0167     }
0168 }
0169 
0170 static void set_pmc_event(int ctr, int event)
0171 {
0172     u32 pmlca;
0173 
0174     pmlca = get_pmlca(ctr);
0175 
0176     pmlca = (pmlca & ~PMLCA_EVENT_MASK) |
0177         ((event << PMLCA_EVENT_SHIFT) &
0178          PMLCA_EVENT_MASK);
0179 
0180     set_pmlca(ctr, pmlca);
0181 }
0182 
0183 static void set_pmc_user_kernel(int ctr, int user, int kernel)
0184 {
0185     u32 pmlca;
0186 
0187     pmlca = get_pmlca(ctr);
0188 
0189     if(user)
0190         pmlca &= ~PMLCA_FCU;
0191     else
0192         pmlca |= PMLCA_FCU;
0193 
0194     if(kernel)
0195         pmlca &= ~PMLCA_FCS;
0196     else
0197         pmlca |= PMLCA_FCS;
0198 
0199     set_pmlca(ctr, pmlca);
0200 }
0201 
0202 static void set_pmc_marked(int ctr, int mark0, int mark1)
0203 {
0204     u32 pmlca = get_pmlca(ctr);
0205 
0206     if(mark0)
0207         pmlca &= ~PMLCA_FCM0;
0208     else
0209         pmlca |= PMLCA_FCM0;
0210 
0211     if(mark1)
0212         pmlca &= ~PMLCA_FCM1;
0213     else
0214         pmlca |= PMLCA_FCM1;
0215 
0216     set_pmlca(ctr, pmlca);
0217 }
0218 
0219 static void pmc_start_ctr(int ctr, int enable)
0220 {
0221     u32 pmlca = get_pmlca(ctr);
0222 
0223     pmlca &= ~PMLCA_FC;
0224 
0225     if (enable)
0226         pmlca |= PMLCA_CE;
0227     else
0228         pmlca &= ~PMLCA_CE;
0229 
0230     set_pmlca(ctr, pmlca);
0231 }
0232 
0233 static void pmc_start_ctrs(int enable)
0234 {
0235     u32 pmgc0 = mfpmr(PMRN_PMGC0);
0236 
0237     pmgc0 &= ~PMGC0_FAC;
0238     pmgc0 |= PMGC0_FCECE;
0239 
0240     if (enable)
0241         pmgc0 |= PMGC0_PMIE;
0242     else
0243         pmgc0 &= ~PMGC0_PMIE;
0244 
0245     mtpmr(PMRN_PMGC0, pmgc0);
0246 }
0247 
0248 static void pmc_stop_ctrs(void)
0249 {
0250     u32 pmgc0 = mfpmr(PMRN_PMGC0);
0251 
0252     pmgc0 |= PMGC0_FAC;
0253 
0254     pmgc0 &= ~(PMGC0_PMIE | PMGC0_FCECE);
0255 
0256     mtpmr(PMRN_PMGC0, pmgc0);
0257 }
0258 
0259 static int fsl_emb_cpu_setup(struct op_counter_config *ctr)
0260 {
0261     int i;
0262 
0263     /* freeze all counters */
0264     pmc_stop_ctrs();
0265 
0266     for (i = 0;i < num_counters;i++) {
0267         init_pmc_stop(i);
0268 
0269         set_pmc_event(i, ctr[i].event);
0270 
0271         set_pmc_user_kernel(i, ctr[i].user, ctr[i].kernel);
0272     }
0273 
0274     return 0;
0275 }
0276 
0277 static int fsl_emb_reg_setup(struct op_counter_config *ctr,
0278                  struct op_system_config *sys,
0279                  int num_ctrs)
0280 {
0281     int i;
0282 
0283     num_counters = num_ctrs;
0284 
0285     /* Our counters count up, and "count" refers to
0286      * how much before the next interrupt, and we interrupt
0287      * on overflow.  So we calculate the starting value
0288      * which will give us "count" until overflow.
0289      * Then we set the events on the enabled counters */
0290     for (i = 0; i < num_counters; ++i)
0291         reset_value[i] = 0x80000000UL - ctr[i].count;
0292 
0293     return 0;
0294 }
0295 
0296 static int fsl_emb_start(struct op_counter_config *ctr)
0297 {
0298     int i;
0299 
0300     mtmsr(mfmsr() | MSR_PMM);
0301 
0302     for (i = 0; i < num_counters; ++i) {
0303         if (ctr[i].enabled) {
0304             ctr_write(i, reset_value[i]);
0305             /* Set each enabled counter to only
0306              * count when the Mark bit is *not* set */
0307             set_pmc_marked(i, 1, 0);
0308             pmc_start_ctr(i, 1);
0309         } else {
0310             ctr_write(i, 0);
0311 
0312             /* Set the ctr to be stopped */
0313             pmc_start_ctr(i, 0);
0314         }
0315     }
0316 
0317     /* Clear the freeze bit, and enable the interrupt.
0318      * The counters won't actually start until the rfi clears
0319      * the PMM bit */
0320     pmc_start_ctrs(1);
0321 
0322     oprofile_running = 1;
0323 
0324     pr_debug("start on cpu %d, pmgc0 %x\n", smp_processor_id(),
0325             mfpmr(PMRN_PMGC0));
0326 
0327     return 0;
0328 }
0329 
0330 static void fsl_emb_stop(void)
0331 {
0332     /* freeze counters */
0333     pmc_stop_ctrs();
0334 
0335     oprofile_running = 0;
0336 
0337     pr_debug("stop on cpu %d, pmgc0 %x\n", smp_processor_id(),
0338             mfpmr(PMRN_PMGC0));
0339 
0340     mb();
0341 }
0342 
0343 
0344 static void fsl_emb_handle_interrupt(struct pt_regs *regs,
0345                     struct op_counter_config *ctr)
0346 {
0347     unsigned long pc;
0348     int is_kernel;
0349     int val;
0350     int i;
0351 
0352     pc = regs->nip;
0353     is_kernel = is_kernel_addr(pc);
0354 
0355     for (i = 0; i < num_counters; ++i) {
0356         val = ctr_read(i);
0357         if (val < 0) {
0358             if (oprofile_running && ctr[i].enabled) {
0359                 oprofile_add_ext_sample(pc, regs, i, is_kernel);
0360                 ctr_write(i, reset_value[i]);
0361             } else {
0362                 ctr_write(i, 0);
0363             }
0364         }
0365     }
0366 
0367     /* The freeze bit was set by the interrupt. */
0368     /* Clear the freeze bit, and reenable the interrupt.  The
0369      * counters won't actually start until the rfi clears the PMM
0370      * bit.  The PMM bit should not be set until after the interrupt
0371      * is cleared to avoid it getting lost in some hypervisor
0372      * environments.
0373      */
0374     mtmsr(mfmsr() | MSR_PMM);
0375     pmc_start_ctrs(1);
0376 }
0377 
0378 struct op_powerpc_model op_model_fsl_emb = {
0379     .reg_setup      = fsl_emb_reg_setup,
0380     .cpu_setup      = fsl_emb_cpu_setup,
0381     .start          = fsl_emb_start,
0382     .stop           = fsl_emb_stop,
0383     .handle_interrupt   = fsl_emb_handle_interrupt,
0384 };