Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2bce5dac authored by Don Zickus's avatar Don Zickus Committed by Ingo Molnar
Browse files

perf, x86, nmi: Move LVT un-masking into irq handlers



It was noticed that P4 machines were generating double NMIs for
each perf event.  These extra NMIs lead to 'Dazed and confused'
messages on the screen.

I tracked this down to a P4 quirk that said the overflow bit had
to be cleared before re-enabling the apic LVT mask.  My first
attempt was to move the un-masking inside the perf nmi handler
from before the chipset NMI handler to after.

This broke Nehalem boxes that seem to like the unmasking before
the counters themselves are re-enabled.

In order to keep this change simple for 2.6.39, I decided to
just simply move the apic LVT un-masking to the beginning of all
the chipset NMI handlers, with the exception of Pentium4's to
fix the double NMI issue.

Later on we can move the un-masking to later in the handlers to
save a number of 'extra' NMIs on those particular chipsets.

I tested this change on a P4 machine, an AMD machine, a Nehalem
box, and a core2quad box.  'perf top' worked correctly along
with various other small 'perf record' runs.  Anything high
stress breaks all the machines but that is a different problem.

Thanks to various people for testing different versions of this
patch.

Reported-and-tested-by: default avatarShaun Ruffell <sruffell@digium.com>
Signed-off-by: default avatarDon Zickus <dzickus@redhat.com>
Cc: Cyrill Gorcunov <gorcunov@gmail.com>
Link: http://lkml.kernel.org/r/1303900353-10242-1-git-send-email-dzickus@redhat.com


Signed-off-by: default avatarIngo Molnar <mingo@elte.hu>
CC: Cyrill Gorcunov <gorcunov@gmail.com>
parent 6c8a7213
Loading
Loading
Loading
Loading
+10 −2
Original line number Diff line number Diff line
@@ -1288,6 +1288,16 @@ static int x86_pmu_handle_irq(struct pt_regs *regs)

	cpuc = &__get_cpu_var(cpu_hw_events);

	/*
	 * Some chipsets need to unmask the LVTPC in a particular spot
	 * inside the nmi handler.  As a result, the unmasking was pushed
	 * into all the nmi handlers.
	 *
	 * This generic handler doesn't seem to have any issues where the
	 * unmasking occurs so it was left at the top.
	 */
	apic_write(APIC_LVTPC, APIC_DM_NMI);

	for (idx = 0; idx < x86_pmu.num_counters; idx++) {
		if (!test_bit(idx, cpuc->active_mask)) {
			/*
@@ -1374,8 +1384,6 @@ perf_event_nmi_handler(struct notifier_block *self,
		return NOTIFY_DONE;
	}

	apic_write(APIC_LVTPC, APIC_DM_NMI);

	handled = x86_pmu.handle_irq(args->regs);
	if (!handled)
		return NOTIFY_DONE;
+10 −0
Original line number Diff line number Diff line
@@ -933,6 +933,16 @@ static int intel_pmu_handle_irq(struct pt_regs *regs)

	cpuc = &__get_cpu_var(cpu_hw_events);

	/*
	 * Some chipsets need to unmask the LVTPC in a particular spot
	 * inside the nmi handler.  As a result, the unmasking was pushed
	 * into all the nmi handlers.
	 *
	 * This handler doesn't seem to have any issues with the unmasking
	 * so it was left at the top.
	 */
	apic_write(APIC_LVTPC, APIC_DM_NMI);

	intel_pmu_disable_all();
	handled = intel_pmu_drain_bts_buffer();
	status = intel_pmu_get_status();
+13 −4
Original line number Diff line number Diff line
@@ -950,11 +950,20 @@ static int p4_pmu_handle_irq(struct pt_regs *regs)
			x86_pmu_stop(event, 0);
	}

	if (handled) {
		/* p4 quirk: unmask it again */
		apic_write(APIC_LVTPC, apic_read(APIC_LVTPC) & ~APIC_LVT_MASKED);
	if (handled)
		inc_irq_stat(apic_perf_irqs);
	}

	/*
	 * When dealing with the unmasking of the LVTPC on P4 perf hw, it has
	 * been observed that the OVF bit flag has to be cleared first _before_
	 * the LVTPC can be unmasked.
	 *
	 * The reason is the NMI line will continue to be asserted while the OVF
	 * bit is set.  This causes a second NMI to generate if the LVTPC is
	 * unmasked before the OVF bit is cleared, leading to unknown NMI
	 * messages.
	 */
	apic_write(APIC_LVTPC, APIC_DM_NMI);

	return handled;
}