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

Commit 11164cd4 authored by Peter Zijlstra's avatar Peter Zijlstra Committed by Ingo Molnar
Browse files

perf, x86: Add Nehelem PMU programming errata workaround



Implement the workaround for Intel Errata AAK100 and AAP53.

Also, remove the Core-i7 name for Nehalem events since there are
also Westmere based i7 chips.

Signed-off-by: default avatarPeter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Stephane Eranian <eranian@google.com>
LKML-Reference: <1269608924.12097.147.camel@laptop>
Signed-off-by: default avatarIngo Molnar <mingo@elte.hu>
parent ea8e61b7
Loading
Loading
Loading
Loading
+4 −4
Original line number Diff line number Diff line
@@ -184,7 +184,7 @@ struct x86_pmu {
	int		version;
	int		(*handle_irq)(struct pt_regs *);
	void		(*disable_all)(void);
	void		(*enable_all)(void);
	void		(*enable_all)(int added);
	void		(*enable)(struct perf_event *);
	void		(*disable)(struct perf_event *);
	int		(*hw_config)(struct perf_event_attr *attr, struct hw_perf_event *hwc);
@@ -576,7 +576,7 @@ void hw_perf_disable(void)
	x86_pmu.disable_all();
}

static void x86_pmu_enable_all(void)
static void x86_pmu_enable_all(int added)
{
	struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
	int idx;
@@ -784,7 +784,7 @@ void hw_perf_enable(void)
	struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
	struct perf_event *event;
	struct hw_perf_event *hwc;
	int i;
	int i, added = cpuc->n_added;

	if (!x86_pmu_initialized())
		return;
@@ -836,7 +836,7 @@ void hw_perf_enable(void)
	cpuc->enabled = 1;
	barrier();

	x86_pmu.enable_all();
	x86_pmu.enable_all(added);
}

static inline void __x86_pmu_enable_event(struct hw_perf_event *hwc)
+39 −4
Original line number Diff line number Diff line
@@ -483,7 +483,7 @@ static void intel_pmu_disable_all(void)
	intel_pmu_lbr_disable_all();
}

static void intel_pmu_enable_all(void)
static void intel_pmu_enable_all(int added)
{
	struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);

@@ -502,6 +502,40 @@ static void intel_pmu_enable_all(void)
	}
}

/*
 * Workaround for:
 *   Intel Errata AAK100 (model 26)
 *   Intel Errata AAP53  (model 30)
 *
 * These chips need to be 'reset' when adding counters by programming
 * the magic three (non counting) events 0x4300D2, 0x4300B1 and 0x4300B5
 * either in sequence on the same PMC or on different PMCs.
 */
static void intel_pmu_nhm_enable_all(int added)
{
	if (added) {
		struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
		int i;

		wrmsrl(MSR_ARCH_PERFMON_EVENTSEL0 + 0, 0x4300D2);
		wrmsrl(MSR_ARCH_PERFMON_EVENTSEL0 + 1, 0x4300B1);
		wrmsrl(MSR_ARCH_PERFMON_EVENTSEL0 + 2, 0x4300B5);

		wrmsrl(MSR_CORE_PERF_GLOBAL_CTRL, 0x3);
		wrmsrl(MSR_CORE_PERF_GLOBAL_CTRL, 0x0);

		for (i = 0; i < 3; i++) {
			struct perf_event *event = cpuc->events[i];

			if (!event)
				continue;

			__x86_pmu_enable_event(&event->hw);
		}
	}
	intel_pmu_enable_all(added);
}

static inline u64 intel_pmu_get_status(void)
{
	u64 status;
@@ -658,7 +692,7 @@ static int intel_pmu_handle_irq(struct pt_regs *regs)
	intel_pmu_drain_bts_buffer();
	status = intel_pmu_get_status();
	if (!status) {
		intel_pmu_enable_all();
		intel_pmu_enable_all(0);
		return 0;
	}

@@ -707,7 +741,7 @@ static int intel_pmu_handle_irq(struct pt_regs *regs)
		goto again;

done:
	intel_pmu_enable_all();
	intel_pmu_enable_all(0);
	return 1;
}

@@ -920,7 +954,8 @@ static __init int intel_pmu_init(void)
		intel_pmu_lbr_init_nhm();

		x86_pmu.event_constraints = intel_nehalem_event_constraints;
		pr_cont("Nehalem/Corei7 events, ");
		x86_pmu.enable_all = intel_pmu_nhm_enable_all;
		pr_cont("Nehalem events, ");
		break;

	case 28: /* Atom */
+1 −1
Original line number Diff line number Diff line
@@ -535,7 +535,7 @@ static void p4_pmu_enable_event(struct perf_event *event)
				(cccr & ~P4_CCCR_RESERVED) | P4_CCCR_ENABLE);
}

static void p4_pmu_enable_all(void)
static void p4_pmu_enable_all(int added)
{
	struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events);
	int idx;
+1 −1
Original line number Diff line number Diff line
@@ -66,7 +66,7 @@ static void p6_pmu_disable_all(void)
	wrmsrl(MSR_P6_EVNTSEL0, val);
}

static void p6_pmu_enable_all(void)
static void p6_pmu_enable_all(int added)
{
	unsigned long val;