From: Antti P M. <an...@ik...> - 2008-12-06 09:17:48
|
Some ARM11 PMUs seem to be suffering from lost interrupts (at least OMAP2420 and ARM11MPCore). The below tries to remedy the situation at least somehow by checking the PMU counters for overflow in the interrupt handler. For this to make sense, several events need to be enabled. It seems that the workaround does help significantly - CPI figures start to make sense on OMAP2420 with this. Signed-off-by: Antti P Miettinen <an...@ik...> diff -ur linux-2.6.27.7/arch/arm/oprofile/op_model_arm11_core.c linux-2.6.27.7-arm11-opr/arch/arm/oprofile/op_model_arm11_core.c --- linux-2.6.27.7/arch/arm/oprofile/op_model_arm11_core.c 2008-11-21 01:02:37.000000000 +0200 +++ linux-2.6.27.7-arm11-opr/arch/arm/oprofile/op_model_arm11_core.c 2008-12-05 11:51:14.000000000 +0200 @@ -31,9 +31,12 @@ return val; } +static u32 prev_cnt[4][3]; + static void arm11_reset_counter(unsigned int cnt) { - u32 val = -(u32)counter_config[CPU_COUNTER(smp_processor_id(), cnt)].count; + int cpu = smp_processor_id(); + u32 val = -(u32)counter_config[CPU_COUNTER(cpu, cnt)].count; switch (cnt) { case CCNT: asm volatile("mcr p15, 0, %0, c15, c12, 1" : : "r" (val)); @@ -47,6 +50,26 @@ asm volatile("mcr p15, 0, %0, c15, c12, 3" : : "r" (val)); break; } + prev_cnt[cpu][cnt] = val; +} + +static u32 arm11_read_counter(unsigned int cnt) +{ + u32 val; + switch (cnt) { + case CCNT: + asm volatile("mrc p15, 0, %0, c15, c12, 1" : "=r" (val)); + break; + + case PMN0: + asm volatile("mrc p15, 0, %0, c15, c12, 2" : "=r" (val)); + break; + + case PMN1: + asm volatile("mrc p15, 0, %0, c15, c12, 3" : "=r" (val)); + break; + } + return val; } int arm11_setup_pmu(void) @@ -94,7 +117,7 @@ int arm11_start_pmu(void) { - arm11_write_pmnc(arm11_read_pmnc() | PMCR_E); + arm11_write_pmnc((arm11_read_pmnc() | PMCR_E) & ~(PMCR_P | PMCR_C)); return 0; } @@ -102,7 +125,7 @@ { unsigned int cnt; - arm11_write_pmnc(arm11_read_pmnc() & ~PMCR_E); + arm11_write_pmnc(arm11_read_pmnc() & ~(PMCR_E | PMCR_P | PMCR_C)); for (cnt = PMN0; cnt <= CCNT; cnt++) arm11_reset_counter(cnt); @@ -118,17 +141,35 @@ struct pt_regs *regs = get_irq_regs(); unsigned int cnt; u32 pmnc; + int cpu = smp_processor_id(); pmnc = arm11_read_pmnc(); + /* disable PMU interrupts and counters */ + arm11_write_pmnc(pmnc + & ~(PMCR_IEN_PMN0 | PMCR_IEN_PMN1 | PMCR_IEN_CCNT + | PMCR_OFL_PMN0 | PMCR_OFL_PMN1 | PMCR_OFL_CCNT + | PMCR_P | PMCR_C | PMCR_E)); + + for (cnt = PMN0; cnt <= CCNT; cnt++) { + u32 val; + val = arm11_read_counter(cnt); + if (val < prev_cnt[cpu][cnt] + && (pmnc & (PMCR_IEN_PMN0 << cnt)) + && !(pmnc & (PMCR_OFL_PMN0 << cnt))) { + pmnc |= (PMCR_OFL_PMN0 << cnt); + } + prev_cnt[cpu][cnt] = val; + } + for (cnt = PMN0; cnt <= CCNT; cnt++) { if ((pmnc & (PMCR_OFL_PMN0 << cnt)) && (pmnc & (PMCR_IEN_PMN0 << cnt))) { arm11_reset_counter(cnt); - oprofile_add_sample(regs, CPU_COUNTER(smp_processor_id(), cnt)); + oprofile_add_sample(regs, CPU_COUNTER(cpu, cnt)); } } /* Clear counter flag(s) */ - arm11_write_pmnc(pmnc); + arm11_write_pmnc(pmnc & ~(PMCR_P | PMCR_C)); return IRQ_HANDLED; } |