static int stop_pmu(void) { unsigned int inten_value; unsigned int pmnc_value; unsigned int flag_value; inten_value = 0x0; flag_value = 0x1f; pmnc_value = ReadPMUReg(PXA2_PMU_PMNC); /* disable the counters */ pmnc_value |= 0x10; pmnc_value &= ~0x1; WritePMUReg(PXA2_PMU_PMNC, pmnc_value); WritePMUReg(PXA2_PMU_INTEN, inten_value); WritePMUReg(PXA2_PMU_FLAG, flag_value); /* We need to save the PMU counter value for calibration result before calling free_pmu() * because free_pmu() may cause these registers be modified by IPM */ reg_value[COUNTER_PXA2_PMU_CCNT] = ReadPMUReg(PXA2_PMU_CCNT); reg_value[COUNTER_PXA2_PMU_PMN0] = ReadPMUReg(PXA2_PMU_PMN0); reg_value[COUNTER_PXA2_PMU_PMN1] = ReadPMUReg(PXA2_PMU_PMN1); reg_value[COUNTER_PXA2_PMU_PMN2] = ReadPMUReg(PXA2_PMU_PMN2); reg_value[COUNTER_PXA2_PMU_PMN3] = ReadPMUReg(PXA2_PMU_PMN3); unregister_pmu_isr(); free_pmu(); return 0; }
static int resume_pmu(void) { unsigned int pmnc_value; pmnc_value = ReadPMUReg(PXA2_PMU_PMNC); pmnc_value |= 0x1; pmnc_value &= ~0x10; WritePMUReg(PXA2_PMU_PMNC, pmnc_value); return 0; }
static int pause_pmu(void) { unsigned int flag_value = 0; unsigned int pmnc_value; pmnc_value = ReadPMUReg(PXA2_PMU_PMNC); /* disable the counters */ pmnc_value |= 0x10; pmnc_value &= ~0x1; /* clear the overflow flags */ flag_value = 0x1f; WritePMUReg(PXA2_PMU_PMNC, pmnc_value); WritePMUReg(PXA2_PMU_FLAG, flag_value); return 0; }
static irqreturn_t px_pmu_isr(struct pt_regs * const regs, unsigned int pid, unsigned int tid, unsigned int cpu, unsigned long long ts) { int i; int reg = 0; unsigned long flag_value; unsigned long pmnc_value; bool buffer_full = false; char ** bt_buffer = &per_cpu(g_bt_buffer, cpu); PXD32_CSS_Call_Stack_V2 *css_data = (PXD32_CSS_Call_Stack_V2 *)*bt_buffer; /* disable the counters */ pmnc_value = ReadPMUReg(PXA2_PMU_PMNC); WritePMUReg(PXA2_PMU_PMNC, pmnc_value & ~PMNC_ENABLE_BIT); /* clear the overflow flag */ flag_value = ReadPMUReg(PXA2_PMU_FLAG); WritePMUReg(PXA2_PMU_FLAG, FLAG_OVERFLOW_BITS); backtrace(regs, cpu, pid, tid, css_data); /* write sample record to sample buffer */ if (flag_value & CCNT_OVERFLAG_BIT && es[COUNTER_PXA2_PMU_CCNT].enabled) { if (es[COUNTER_PXA2_PMU_CCNT].calibration == false) { /* write sample record in non-calibration mode */ //buffer_full |= backtrace(regs, pid, tid, COUNTER_PXA2_PMU_CCNT, cpu, ts); if (!buffer_full) { fill_css_data_head(css_data, pid, tid, COUNTER_PXA2_PMU_CCNT, ts); buffer_full |= write_css_data(cpu, css_data); } } else { /* calculate the overflow count in calibration mode */ es[COUNTER_PXA2_PMU_CCNT].overflow++; } /* reset the counter value */ WritePMUReg(PXA2_PMU_CCNT, es[COUNTER_PXA2_PMU_CCNT].reset_value); } for (i=0; i<PXA2_PMN_NUM; i++) { if (flag_value & (PMN0_OVERFLAG_BIT << i)) { unsigned int reg_id = 0; switch (i) { case 0: reg_id = COUNTER_PXA2_PMU_PMN0; reg = PXA2_PMU_PMN0; break; case 1: reg_id = COUNTER_PXA2_PMU_PMN1; reg = PXA2_PMU_PMN1; break; case 2: reg_id = COUNTER_PXA2_PMU_PMN2; reg = PXA2_PMU_PMN2; break; case 3: reg_id = COUNTER_PXA2_PMU_PMN3; reg = PXA2_PMU_PMN3; break; default: break; } if (es[reg_id].calibration == false) { /* write sample record in non-calibration mode */ //buffer_full |= backtrace(regs, pid, tid, reg_id, cpu, ts); if (!buffer_full) { fill_css_data_head(css_data, pid, tid, reg_id, ts); buffer_full |= write_css_data(cpu, css_data); } } else { /* calculate the overflow count in calibration mode */ es[reg_id].overflow++; } /* reset the counter value */ WritePMUReg(reg, es[reg_id].reset_value); } } if (!buffer_full) { /* enable the counters if buffer is not full */ WritePMUReg(PXA2_PMU_PMNC, pmnc_value | PMNC_ENABLE_BIT); } return IRQ_HANDLED; }
static irqreturn_t px_pmu_isr(unsigned int pid, unsigned int tid, unsigned int pc, unsigned int timestamp) { int i; int reg = 0; unsigned long flag_value; unsigned long pmnc_value; PXD32_Hotspot_Sample sample_rec; bool buffer_full = false; /* disable the timer interrupt */ //disable_irq(PX_IRQ_PXA2_TIMER); /* disable the counters */ pmnc_value = ReadPMUReg(PXA2_PMU_PMNC); WritePMUReg(PXA2_PMU_PMNC, pmnc_value & ~PMNC_ENABLE_BIT); /* clear the overflow flag */ flag_value = ReadPMUReg(PXA2_PMU_FLAG); WritePMUReg(PXA2_PMU_FLAG, FLAG_OVERFLOW_BITS); /* write sample record to sample buffer */ sample_rec.pc = pc; sample_rec.pid = pid; sample_rec.tid = tid; memcpy(sample_rec.timestamp, ×tamp, 3); if (flag_value & CCNT_OVERFLAG_BIT && es[COUNTER_PXA2_PMU_CCNT].enabled) { sample_rec.registerId = COUNTER_PXA2_PMU_CCNT; if (es[COUNTER_PXA2_PMU_CCNT].calibration == false) { /* write sample record in non-calibration mode */ buffer_full |= write_sample(&sample_rec); } else { /* calculate the overflow count in calibration mode */ es[sample_rec.registerId].overflow++; } /* reset the counter value */ WritePMUReg(PXA2_PMU_CCNT, es[COUNTER_PXA2_PMU_CCNT].reset_value); } for (i=0; i<4; i++) { if (flag_value & (PMN0_OVERFLAG_BIT << i)) { switch (i) { case 0: sample_rec.registerId = COUNTER_PXA2_PMU_PMN0; reg = PXA2_PMU_PMN0; break; case 1: sample_rec.registerId = COUNTER_PXA2_PMU_PMN1; reg = PXA2_PMU_PMN1; break; case 2: sample_rec.registerId = COUNTER_PXA2_PMU_PMN2; reg = PXA2_PMU_PMN2; break; case 3: sample_rec.registerId = COUNTER_PXA2_PMU_PMN3; reg = PXA2_PMU_PMN3; break; default: break; } if (es[sample_rec.registerId].calibration == false) { /* write sample record in non-calibration mode */ buffer_full |= write_sample(&sample_rec); } else { /* calculate the overflow count in calibration mode */ es[sample_rec.registerId].overflow++; } /* reset the counter value */ WritePMUReg(reg, es[sample_rec.registerId].reset_value); } } if (!buffer_full) { /* enable the counters if buffer is not full */ WritePMUReg(PXA2_PMU_PMNC, pmnc_value | PMNC_ENABLE_BIT); } /* enable the timer interrupt */ //enable_irq(PX_IRQ_PXA2_TIMER); return IRQ_HANDLED; }