static irqreturn_t csky_pmu_handle_irq()

in kernel/perf_event.c [1103:1158]


static irqreturn_t csky_pmu_handle_irq(int irq_num, void *dev)
{
	struct perf_sample_data data;
	struct pmu_hw_events *cpuc = this_cpu_ptr(csky_pmu.hw_events);
	struct pt_regs *regs;
	int idx;

	/*
	 * Did an overflow occur?
	 */
	if (!cprcr(HPOFSR))
		return IRQ_NONE;

	/*
	 * Handle the counter(s) overflow(s)
	 */
	regs = get_irq_regs();

	csky_pmu_disable(&csky_pmu.pmu);

	for (idx = 0; idx < CSKY_PMU_MAX_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 (!(cprcr(HPOFSR) & BIT(idx)))
			continue;

		hwc = &event->hw;
		csky_perf_event_update(event, &event->hw);
		perf_sample_data_init(&data, 0, hwc->last_period);
		csky_pmu_event_set_period(event);

		if (perf_event_overflow(event, &data, regs))
			csky_pmu_stop_event(event);
	}

	csky_pmu_enable(&csky_pmu.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;
}