Commit 91f3469a authored by Athira Rajeev's avatar Athira Rajeev Committed by Michael Ellerman
Browse files

powerpc/perf: Include PMCs as part of per-cpu cpuhw_events struct



To support capturing of PMC's as part of extended registers, the
value of SPR's PMC1 to PMC6 has to be saved in the starting of PMI
interrupt handler. This is needed since we are resetting the
overflown PMC before creating sample and hence directly reading
SPRN_PMCx in 'perf_reg_value' will be capturing the modified value.

To solve this, add a per-cpu array as part of structure cpu_hw_events
and use this array to capture PMC values in the perf interrupt handler.
Patch also re-factor's the interrupt handler code to use this per-cpu
array instead of current local array.

Signed-off-by: default avatarAthira Rajeev <atrajeev@linux.vnet.ibm.com>
Signed-off-by: default avatarMichael Ellerman <mpe@ellerman.id.au>
Link: https://lore.kernel.org/r/1612335337-1888-2-git-send-email-atrajeev@linux.vnet.ibm.com
parent 266d8f75
Loading
Loading
Loading
Loading
+12 −6
Original line number Diff line number Diff line
@@ -54,6 +54,9 @@ struct cpu_hw_events {
	struct	perf_branch_stack	bhrb_stack;
	struct	perf_branch_entry	bhrb_entries[BHRB_MAX_ENTRIES];
	u64				ic_init;

	/* Store the PMC values */
	unsigned long pmcs[MAX_HWEVENTS];
};

static DEFINE_PER_CPU(struct cpu_hw_events, cpu_hw_events);
@@ -2264,7 +2267,6 @@ static void __perf_event_interrupt(struct pt_regs *regs)
	int i, j;
	struct cpu_hw_events *cpuhw = this_cpu_ptr(&cpu_hw_events);
	struct perf_event *event;
	unsigned long val[8];
	int found, active;

	if (cpuhw->n_limited)
@@ -2275,12 +2277,12 @@ static void __perf_event_interrupt(struct pt_regs *regs)

	/* Read all the PMCs since we'll need them a bunch of times */
	for (i = 0; i < ppmu->n_counter; ++i)
		val[i] = read_pmc(i + 1);
		cpuhw->pmcs[i] = read_pmc(i + 1);

	/* Try to find what caused the IRQ */
	found = 0;
	for (i = 0; i < ppmu->n_counter; ++i) {
		if (!pmc_overflow(val[i]))
		if (!pmc_overflow(cpuhw->pmcs[i]))
			continue;
		if (is_limited_pmc(i + 1))
			continue; /* these won't generate IRQs */
@@ -2295,7 +2297,7 @@ static void __perf_event_interrupt(struct pt_regs *regs)
			event = cpuhw->event[j];
			if (event->hw.idx == (i + 1)) {
				active = 1;
				record_and_restart(event, val[i], regs);
				record_and_restart(event, cpuhw->pmcs[i], regs);
				break;
			}
		}
@@ -2309,11 +2311,11 @@ static void __perf_event_interrupt(struct pt_regs *regs)
			event = cpuhw->event[i];
			if (!event->hw.idx || is_limited_pmc(event->hw.idx))
				continue;
			if (pmc_overflow_power7(val[event->hw.idx - 1])) {
			if (pmc_overflow_power7(cpuhw->pmcs[event->hw.idx - 1])) {
				/* event has overflowed in a buggy way*/
				found = 1;
				record_and_restart(event,
						   val[event->hw.idx - 1],
						   cpuhw->pmcs[event->hw.idx - 1],
						   regs);
			}
		}
@@ -2329,6 +2331,10 @@ static void __perf_event_interrupt(struct pt_regs *regs)
	 * we get back out of this interrupt.
	 */
	write_mmcr0(cpuhw, cpuhw->mmcr.mmcr0);

	/* Clear the cpuhw->pmcs */
	memset(&cpuhw->pmcs, 0, sizeof(cpuhw->pmcs));

}

static void perf_event_interrupt(struct pt_regs *regs)