in kernel/perf_event.c [562:614]
static irqreturn_t arc_pmu_intr(int irq, void *dev)
{
struct perf_sample_data data;
struct arc_pmu_cpu *pmu_cpu = this_cpu_ptr(&arc_pmu_cpu);
struct pt_regs *regs;
unsigned int active_ints;
int idx;
arc_pmu_disable(&arc_pmu->pmu);
active_ints = read_aux_reg(ARC_REG_PCT_INT_ACT);
if (!active_ints)
goto done;
regs = get_irq_regs();
do {
struct perf_event *event;
struct hw_perf_event *hwc;
idx = __ffs(active_ints);
/* Reset interrupt flag by writing of 1 */
write_aux_reg(ARC_REG_PCT_INT_ACT, BIT(idx));
/*
* On reset of "interrupt active" bit corresponding
* "interrupt enable" bit gets automatically reset as well.
* Now we need to re-enable interrupt for the counter.
*/
write_aux_reg(ARC_REG_PCT_INT_CTRL,
read_aux_reg(ARC_REG_PCT_INT_CTRL) | BIT(idx));
event = pmu_cpu->act_counter[idx];
hwc = &event->hw;
WARN_ON_ONCE(hwc->idx != idx);
arc_perf_event_update(event, &event->hw, event->hw.idx);
perf_sample_data_init(&data, 0, hwc->last_period);
if (arc_pmu_event_set_period(event)) {
if (perf_event_overflow(event, &data, regs))
arc_pmu_stop(event, 0);
}
active_ints &= ~BIT(idx);
} while (active_ints);
done:
arc_pmu_enable(&arc_pmu->pmu);
return IRQ_HANDLED;
}