static int stop_pmu(void) { u32 intenc_value; u32 flag_value; u32 pmnc_value; intenc_value = 0xffffffff; flag_value = 0xffffffff; /* disable all counters */ pmnc_value = PJ4_Read_PMNC(); pmnc_value &= ~0x1; PJ4_Write_PMNC(pmnc_value); /* clear overflow flags */ PJ4_Write_FLAG(flag_value); /* disable all interrupts */ PJ4_Write_INTENC(intenc_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_PJ4_PMU_CCNT] = PJ4_ReadPMUCounter(COUNTER_PJ4_PMU_CCNT); reg_value[COUNTER_PJ4_PMU_PMN0] = PJ4_ReadPMUCounter(COUNTER_PJ4_PMU_PMN0); reg_value[COUNTER_PJ4_PMU_PMN1] = PJ4_ReadPMUCounter(COUNTER_PJ4_PMU_PMN1); reg_value[COUNTER_PJ4_PMU_PMN2] = PJ4_ReadPMUCounter(COUNTER_PJ4_PMU_PMN2); reg_value[COUNTER_PJ4_PMU_PMN3] = PJ4_ReadPMUCounter(COUNTER_PJ4_PMU_PMN3); unregister_pmu_isr(); free_pmu(); return 0; }
static int resume_pmu(void) { u32 pmnc_value; /* enable all counters */ pmnc_value = PJ4_Read_PMNC(); pmnc_value |= 0x1; PJ4_Write_PMNC(pmnc_value); return 0; }
static int pause_pmu(void) { u32 pmnc_value; /* disable all counters */ pmnc_value = PJ4_Read_PMNC(); pmnc_value &= ~0x1; PJ4_Write_PMNC(pmnc_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) { u32 pmnc_value; u32 flag_value; unsigned int i; unsigned int reg_id; 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 = PJ4_Read_PMNC(); pmnc_value &= ~0x1; PJ4_Write_PMNC(pmnc_value); /* clear the overflow flag */ flag_value = PJ4_Read_FLAG(); PJ4_Write_FLAG(0xffffffff); if (flag_value != 0) backtrace(regs, cpu, pid, tid, css_data); if ((flag_value & 0x80000000) && es[COUNTER_PJ4_PMU_CCNT].enabled) { reg_id = COUNTER_PJ4_PMU_CCNT; /* ccnt overflow */ if (es[reg_id].calibration == false) { /* write css data in non-calibration mode */ 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++; } PJ4_WritePMUCounter(reg_id, es[reg_id].reset_value); } for (i=0; i<PJ4_PMN_NUM; i++) { if (flag_value & (0x1 << i)) { switch (i) { case 0: reg_id = COUNTER_PJ4_PMU_PMN0; break; case 1: reg_id = COUNTER_PJ4_PMU_PMN1; break; case 2: reg_id = COUNTER_PJ4_PMU_PMN2; break; case 3: reg_id = COUNTER_PJ4_PMU_PMN3; break; default: break; } if (es[reg_id].calibration == false) { /* write css data in non-calibration mode */ 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++; } PJ4_WritePMUCounter(reg_id, es[reg_id].reset_value); } } if (!buffer_full) { /* enable the counters */ pmnc_value |= 0x1; PJ4_Write_PMNC(pmnc_value); } return IRQ_HANDLED; }
static int start_pmu(bool is_start_paused) { int i; int ret; struct pmu_registers_pj4 pmu_regs; pmu_regs.pmnc = 0x0; pmu_regs.ccnt = 0x0; pmu_regs.cntens = 0x0; pmu_regs.cntenc = 0x0; pmu_regs.intens = 0x0; pmu_regs.intenc = 0x0; pmu_regs.flag = 0x0; for (i=0; i<PJ4_PMN_NUM; i++) { pmu_regs.evtsel[i] = 0; pmu_regs.pmncnt[i] = 0; } ret = allocate_pmu(); if (ret != 0) { return ret; } ret = register_pmu_isr(px_css_isr); if (ret != 0) { return ret; } /* disable PMU and clear CCNT & PMNx */ pmu_regs.pmnc = PJ4_Read_PMNC(); pmu_regs.pmnc &= ~0x1; //pmu_regs.pmnc |= 0x6; PJ4_Write_PMNC(pmu_regs.pmnc); for (i=0; i<g_ebs_settings.eventNumber; i++) { switch (g_ebs_settings.event[i].registerId) { case COUNTER_PJ4_PMU_CCNT: set_ccnt_events(&g_ebs_settings.event[i], &pmu_regs); break; case COUNTER_PJ4_PMU_PMN0: set_pmn_events(0, &g_ebs_settings.event[i], &pmu_regs); break; case COUNTER_PJ4_PMU_PMN1: set_pmn_events(1, &g_ebs_settings.event[i], &pmu_regs); break; case COUNTER_PJ4_PMU_PMN2: set_pmn_events(2, &g_ebs_settings.event[i], &pmu_regs); break; case COUNTER_PJ4_PMU_PMN3: set_pmn_events(3, &g_ebs_settings.event[i], &pmu_regs); break; default: break; } } /* disable all counters */ PJ4_Write_CNTENC(0xffffffff); /* disable all interrupts */ PJ4_Write_INTENC(0xffffffff); /* clear overflow flags */ PJ4_Write_FLAG(0xffffffff); /* write the counter values */ PJ4_WritePMUCounter(COUNTER_PJ4_PMU_CCNT, pmu_regs.ccnt); PJ4_WritePMUCounter(COUNTER_PJ4_PMU_PMN0, pmu_regs.pmncnt[0]); PJ4_WritePMUCounter(COUNTER_PJ4_PMU_PMN1, pmu_regs.pmncnt[1]); PJ4_WritePMUCounter(COUNTER_PJ4_PMU_PMN2, pmu_regs.pmncnt[2]); PJ4_WritePMUCounter(COUNTER_PJ4_PMU_PMN3, pmu_regs.pmncnt[3]); /* set events */ for (i=0; i<PJ4_PMN_NUM; i++) { PJ4_Write_PMNXSEL(i); PJ4_Write_PMNCNT(pmu_regs.pmncnt[i]); PJ4_Write_EVTSEL(pmu_regs.evtsel[i]); } if (is_start_paused) { pmu_regs.pmnc &= ~0x1; } else { pmu_regs.pmnc |= 0x1; } /* enable the interrupts */ PJ4_Write_INTENS(pmu_regs.intens); /* enable the counters */ PJ4_Write_CNTENS(pmu_regs.cntens); /* Enable PMU */ PJ4_Write_PMNC(pmu_regs.pmnc); return 0; }
static irqreturn_t px_pmu_isr(unsigned int pid, unsigned int tid, unsigned int pc, unsigned int timestamp) { u32 pmnc_value; u32 flag_value; unsigned int i; bool buffer_full = false; PXD32_Hotspot_Sample sample_rec; /* disable the counters */ pmnc_value = PJ4_Read_PMNC(); pmnc_value &= ~0x1; PJ4_Write_PMNC(pmnc_value); /* clear the overflow flag */ flag_value = PJ4_Read_FLAG(); PJ4_Write_FLAG(0x8000000f); sample_rec.pc = pc; sample_rec.pid = pid; sample_rec.tid = tid; memcpy(sample_rec.timestamp, ×tamp, 3); if ((flag_value & 0x80000000) && es[COUNTER_PJ4_PMU_CCNT].enabled) { sample_rec.registerId = COUNTER_PJ4_PMU_CCNT; /* ccnt overflow */ 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++; } PJ4_WritePMUCounter(sample_rec.registerId, es[sample_rec.registerId].reset_value); } for (i=0; i<4; i++) { if (flag_value & (0x1 << i)) { switch (i) { case 0: sample_rec.registerId = COUNTER_PJ4_PMU_PMN0; break; case 1: sample_rec.registerId = COUNTER_PJ4_PMU_PMN1; break; case 2: sample_rec.registerId = COUNTER_PJ4_PMU_PMN2; break; case 3: sample_rec.registerId = COUNTER_PJ4_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++; } PJ4_WritePMUCounter(sample_rec.registerId, es[sample_rec.registerId].reset_value); } } if (!buffer_full) { /* enable the counters */ pmnc_value |= 0x1; PJ4_Write_PMNC(pmnc_value); } return IRQ_HANDLED; }