in kernel/perf_event_cpu.c [225:285]
static irqreturn_t nds32_pmu_handle_irq(int irq_num, void *dev)
{
u32 pfm;
struct perf_sample_data data;
struct nds32_pmu *cpu_pmu = (struct nds32_pmu *)dev;
struct pmu_hw_events *cpuc = cpu_pmu->get_hw_events();
struct pt_regs *regs;
int idx;
/*
* Get and reset the IRQ flags
*/
pfm = nds32_pfm_getreset_flags();
/*
* Did an overflow occur?
*/
if (!nds32_pfm_has_overflowed(pfm))
return IRQ_NONE;
/*
* Handle the counter(s) overflow(s)
*/
regs = get_irq_regs();
nds32_pmu_stop(cpu_pmu);
for (idx = 0; idx < cpu_pmu->num_events; ++idx) {
struct perf_event *event = cpuc->events[idx];
struct hw_perf_event *hwc;
/* Ignore if we don't have an event. */
if (!event)
continue;
/*
* We have a single interrupt for all counters. Check that
* each counter has overflowed before we process it.
*/
if (!nds32_pfm_counter_has_overflowed(pfm, idx))
continue;
hwc = &event->hw;
nds32_pmu_event_update(event);
perf_sample_data_init(&data, 0, hwc->last_period);
if (!nds32_pmu_event_set_period(event))
continue;
if (perf_event_overflow(event, &data, regs))
cpu_pmu->disable(event);
}
nds32_pmu_start(cpu_pmu);
/*
* Handle the pending perf events.
*
* Note: this call *must* be run with interrupts disabled. For
* platforms that can have the PMU interrupts raised as an NMI, this
* will not work.
*/
irq_work_run();
return IRQ_HANDLED;
}