From: Mikael Pettersson This patch is a cleanup and correction to perfctr's PPC32 low-level driver. This is a prerequisite for the next patch which enables performance monitor interrupts. Details from my RELEASE-NOTES entry: - PPC32: Correct MMCR0 handling for FCECE/TRIGGER. Read MMCR0 at suspend and then freeze the counters. Move this code from read_counters() to suspend(). At resume, reload MMCR0 to unfreeze the counters. Clean up the cstatus checks controlling this behaviour. Signed-off-by: Mikael Pettersson Signed-off-by: Andrew Morton --- 25-akpm/drivers/perfctr/ppc.c | 37 ++++++++++++++++++++++++++----------- 1 files changed, 26 insertions(+), 11 deletions(-) diff -puN drivers/perfctr/ppc.c~perfctr-ppc32-mmcr0-handling-fixes drivers/perfctr/ppc.c --- 25/drivers/perfctr/ppc.c~perfctr-ppc32-mmcr0-handling-fixes Fri Nov 12 16:19:46 2004 +++ 25-akpm/drivers/perfctr/ppc.c Fri Nov 12 16:19:46 2004 @@ -106,6 +106,18 @@ static inline int is_isuspend_cpu(const static inline void clear_isuspend_cpu(struct perfctr_cpu_state *state) { } #endif +/* The ppc driver internally uses cstatus & (1<<30) to record that + a context has an asynchronously changing MMCR0. */ +static inline unsigned int perfctr_cstatus_set_mmcr0_quirk(unsigned int cstatus) +{ + return cstatus | (1 << 30); +} + +static inline int perfctr_cstatus_has_mmcr0_quirk(unsigned int cstatus) +{ + return cstatus & (1 << 30); +} + /**************************************************************** * * * Driver procedures. * @@ -230,7 +242,7 @@ static inline unsigned int read_pmc(unsi } } -static void ppc_read_counters(/*const*/ struct perfctr_cpu_state *state, +static void ppc_read_counters(struct perfctr_cpu_state *state, struct perfctr_low_ctrs *ctrs) { unsigned int cstatus, nrctrs, i; @@ -243,12 +255,6 @@ static void ppc_read_counters(/*const*/ unsigned int pmc = state->pmc[i].map; ctrs->pmc[i] = read_pmc(pmc); } - /* handle MMCR0 changes due to FCECE or TRIGGER on 74xx */ - if (state->cstatus & (1<<30)) { - unsigned int mmcr0 = mfspr(SPRN_MMCR0); - state->ppc_mmcr[0] = mmcr0; - get_cpu_cache()->ppc_mmcr[0] = mmcr0; - } } static unsigned int pmc_max_event(unsigned int pmc) @@ -338,14 +344,15 @@ static int ppc_check_control(struct perf /* * MMCR0[FC] and MMCR0[TRIGGER] may change on 74xx if FCECE or - * TRIGGER is set. To avoid undoing those changes, we must read - * MMCR0 back into state->ppc_mmcr[0] and the cache at suspends. + * TRIGGER is set. At suspends we must read MMCR0 back into + * the state and the cache and then freeze the counters, and + * at resumes we must unfreeze the counters and reload MMCR0. */ switch (pm_type) { case PM_7450: case PM_7400: if (state->ppc_mmcr[0] & (MMCR0_FCECE | MMCR0_TRIGGER)) - state->cstatus |= (1<<30); + state->cstatus = perfctr_cstatus_set_mmcr0_quirk(state->cstatus); default: ; } @@ -445,7 +452,7 @@ static void perfctr_cpu_write_control(co return ppc_write_control(state); } -static void perfctr_cpu_read_counters(/*const*/ struct perfctr_cpu_state *state, +static void perfctr_cpu_read_counters(struct perfctr_cpu_state *state, struct perfctr_low_ctrs *ctrs) { return ppc_read_counters(state, ctrs); @@ -559,6 +566,12 @@ void perfctr_cpu_suspend(struct perfctr_ unsigned int i, cstatus, nractrs; struct perfctr_low_ctrs now; + if (perfctr_cstatus_has_mmcr0_quirk(state->cstatus)) { + unsigned int mmcr0 = mfspr(SPRN_MMCR0); + mtspr(SPRN_MMCR0, mmcr0 | MMCR0_FC); + get_cpu_cache()->ppc_mmcr[0] = mmcr0 | MMCR0_FC; + state->ppc_mmcr[0] = mmcr0; + } if (perfctr_cstatus_has_ictrs(state->cstatus)) perfctr_cpu_isuspend(state); perfctr_cpu_read_counters(state, &now); @@ -574,6 +587,8 @@ void perfctr_cpu_resume(struct perfctr_c { if (perfctr_cstatus_has_ictrs(state->cstatus)) perfctr_cpu_iresume(state); + if (perfctr_cstatus_has_mmcr0_quirk(state->cstatus)) + get_cpu_cache()->k1.id = 0; /* force reload of MMCR0 */ perfctr_cpu_write_control(state); //perfctr_cpu_read_counters(state, &state->start); { _