static irqreturn_t arc_pmu_intr()

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;
}