📄 op_model_fsl_booke.c
字号:
/* * arch/powerpc/oprofile/op_model_fsl_booke.c * * Freescale Book-E oprofile support, based on ppc64 oprofile support * Copyright (C) 2004 Anton Blanchard <anton@au.ibm.com>, IBM * * Copyright (c) 2004 Freescale Semiconductor, Inc * * Author: Andy Fleming * Maintainer: Kumar Gala <galak@kernel.crashing.org> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. */#include <linux/oprofile.h>#include <linux/init.h>#include <linux/smp.h>#include <asm/ptrace.h>#include <asm/system.h>#include <asm/processor.h>#include <asm/cputable.h>#include <asm/reg_booke.h>#include <asm/page.h>#include <asm/pmc.h>#include <asm/oprofile_impl.h>static unsigned long reset_value[OP_MAX_COUNTER];static int num_counters;static int oprofile_running;static inline u32 get_pmlca(int ctr){ u32 pmlca; switch (ctr) { case 0: pmlca = mfpmr(PMRN_PMLCA0); break; case 1: pmlca = mfpmr(PMRN_PMLCA1); break; case 2: pmlca = mfpmr(PMRN_PMLCA2); break; case 3: pmlca = mfpmr(PMRN_PMLCA3); break; default: panic("Bad ctr number\n"); } return pmlca;}static inline void set_pmlca(int ctr, u32 pmlca){ switch (ctr) { case 0: mtpmr(PMRN_PMLCA0, pmlca); break; case 1: mtpmr(PMRN_PMLCA1, pmlca); break; case 2: mtpmr(PMRN_PMLCA2, pmlca); break; case 3: mtpmr(PMRN_PMLCA3, pmlca); break; default: panic("Bad ctr number\n"); }}static inline unsigned int ctr_read(unsigned int i){ switch(i) { case 0: return mfpmr(PMRN_PMC0); case 1: return mfpmr(PMRN_PMC1); case 2: return mfpmr(PMRN_PMC2); case 3: return mfpmr(PMRN_PMC3); default: return 0; }}static inline void ctr_write(unsigned int i, unsigned int val){ switch(i) { case 0: mtpmr(PMRN_PMC0, val); break; case 1: mtpmr(PMRN_PMC1, val); break; case 2: mtpmr(PMRN_PMC2, val); break; case 3: mtpmr(PMRN_PMC3, val); break; default: break; }}static void init_pmc_stop(int ctr){ u32 pmlca = (PMLCA_FC | PMLCA_FCS | PMLCA_FCU | PMLCA_FCM1 | PMLCA_FCM0); u32 pmlcb = 0; switch (ctr) { case 0: mtpmr(PMRN_PMLCA0, pmlca); mtpmr(PMRN_PMLCB0, pmlcb); break; case 1: mtpmr(PMRN_PMLCA1, pmlca); mtpmr(PMRN_PMLCB1, pmlcb); break; case 2: mtpmr(PMRN_PMLCA2, pmlca); mtpmr(PMRN_PMLCB2, pmlcb); break; case 3: mtpmr(PMRN_PMLCA3, pmlca); mtpmr(PMRN_PMLCB3, pmlcb); break; default: panic("Bad ctr number!\n"); }}static void set_pmc_event(int ctr, int event){ u32 pmlca; pmlca = get_pmlca(ctr); pmlca = (pmlca & ~PMLCA_EVENT_MASK) | ((event << PMLCA_EVENT_SHIFT) & PMLCA_EVENT_MASK); set_pmlca(ctr, pmlca);}static void set_pmc_user_kernel(int ctr, int user, int kernel){ u32 pmlca; pmlca = get_pmlca(ctr); if(user) pmlca &= ~PMLCA_FCU; else pmlca |= PMLCA_FCU; if(kernel) pmlca &= ~PMLCA_FCS; else pmlca |= PMLCA_FCS; set_pmlca(ctr, pmlca);}static void set_pmc_marked(int ctr, int mark0, int mark1){ u32 pmlca = get_pmlca(ctr); if(mark0) pmlca &= ~PMLCA_FCM0; else pmlca |= PMLCA_FCM0; if(mark1) pmlca &= ~PMLCA_FCM1; else pmlca |= PMLCA_FCM1; set_pmlca(ctr, pmlca);}static void pmc_start_ctr(int ctr, int enable){ u32 pmlca = get_pmlca(ctr); pmlca &= ~PMLCA_FC; if (enable) pmlca |= PMLCA_CE; else pmlca &= ~PMLCA_CE; set_pmlca(ctr, pmlca);}static void pmc_start_ctrs(int enable){ u32 pmgc0 = mfpmr(PMRN_PMGC0); pmgc0 &= ~PMGC0_FAC; pmgc0 |= PMGC0_FCECE; if (enable) pmgc0 |= PMGC0_PMIE; else pmgc0 &= ~PMGC0_PMIE; mtpmr(PMRN_PMGC0, pmgc0);}static void pmc_stop_ctrs(void){ u32 pmgc0 = mfpmr(PMRN_PMGC0); pmgc0 |= PMGC0_FAC; pmgc0 &= ~(PMGC0_PMIE | PMGC0_FCECE); mtpmr(PMRN_PMGC0, pmgc0);}static void dump_pmcs(void){ printk("pmgc0: %x\n", mfpmr(PMRN_PMGC0)); printk("pmc\t\tpmlca\t\tpmlcb\n"); printk("%8x\t%8x\t%8x\n", mfpmr(PMRN_PMC0), mfpmr(PMRN_PMLCA0), mfpmr(PMRN_PMLCB0)); printk("%8x\t%8x\t%8x\n", mfpmr(PMRN_PMC1), mfpmr(PMRN_PMLCA1), mfpmr(PMRN_PMLCB1)); printk("%8x\t%8x\t%8x\n", mfpmr(PMRN_PMC2), mfpmr(PMRN_PMLCA2), mfpmr(PMRN_PMLCB2)); printk("%8x\t%8x\t%8x\n", mfpmr(PMRN_PMC3), mfpmr(PMRN_PMLCA3), mfpmr(PMRN_PMLCB3));}static int fsl_booke_cpu_setup(struct op_counter_config *ctr){ int i; /* freeze all counters */ pmc_stop_ctrs(); for (i = 0;i < num_counters;i++) { init_pmc_stop(i); set_pmc_event(i, ctr[i].event); set_pmc_user_kernel(i, ctr[i].user, ctr[i].kernel); } return 0;}static int fsl_booke_reg_setup(struct op_counter_config *ctr, struct op_system_config *sys, int num_ctrs){ int i; num_counters = num_ctrs; /* Our counters count up, and "count" refers to * how much before the next interrupt, and we interrupt * on overflow. So we calculate the starting value * which will give us "count" until overflow. * Then we set the events on the enabled counters */ for (i = 0; i < num_counters; ++i) reset_value[i] = 0x80000000UL - ctr[i].count; return 0;}static int fsl_booke_start(struct op_counter_config *ctr){ int i; mtmsr(mfmsr() | MSR_PMM); for (i = 0; i < num_counters; ++i) { if (ctr[i].enabled) { ctr_write(i, reset_value[i]); /* Set each enabled counter to only * count when the Mark bit is *not* set */ set_pmc_marked(i, 1, 0); pmc_start_ctr(i, 1); } else { ctr_write(i, 0); /* Set the ctr to be stopped */ pmc_start_ctr(i, 0); } } /* Clear the freeze bit, and enable the interrupt. * The counters won't actually start until the rfi clears * the PMM bit */ pmc_start_ctrs(1); oprofile_running = 1; pr_debug("start on cpu %d, pmgc0 %x\n", smp_processor_id(), mfpmr(PMRN_PMGC0)); return 0;}static void fsl_booke_stop(void){ /* freeze counters */ pmc_stop_ctrs(); oprofile_running = 0; pr_debug("stop on cpu %d, pmgc0 %x\n", smp_processor_id(), mfpmr(PMRN_PMGC0)); mb();}static void fsl_booke_handle_interrupt(struct pt_regs *regs, struct op_counter_config *ctr){ unsigned long pc; int is_kernel; int val; int i; /* set the PMM bit (see comment below) */ mtmsr(mfmsr() | MSR_PMM); pc = regs->nip; is_kernel = is_kernel_addr(pc); for (i = 0; i < num_counters; ++i) { val = ctr_read(i); if (val < 0) { if (oprofile_running && ctr[i].enabled) { oprofile_add_ext_sample(pc, regs, i, is_kernel); ctr_write(i, reset_value[i]); } else { ctr_write(i, 0); } } } /* The freeze bit was set by the interrupt. */ /* Clear the freeze bit, and reenable the interrupt. * The counters won't actually start until the rfi clears * the PMM bit */ pmc_start_ctrs(1);}struct op_powerpc_model op_model_fsl_booke = { .reg_setup = fsl_booke_reg_setup, .cpu_setup = fsl_booke_cpu_setup, .start = fsl_booke_start, .stop = fsl_booke_stop, .handle_interrupt = fsl_booke_handle_interrupt,};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -