[PATCH 2.6.12-rc3-mm3] perfctr: x86 update with K8 multicore fixes

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Andrew,

Here's an update for perfctr's x86/x86-64 low-level driver
which works around issues with current K8 multicore chips.

- Added code to detect multicore K8s and prevent threads in the
  thread-centric API from using northbridge events. This avoids
  resource conflicts, and an erratum in Revision E chips.

Signed-off-by: Mikael Pettersson <[email protected]>

 drivers/perfctr/x86.c |   60 +++++++++++++++++++++++++++++++++++++++++++++++---
 1 files changed, 57 insertions(+), 3 deletions(-)

diff -rupN linux-2.6.12-rc3-mm3/drivers/perfctr/x86.c linux-2.6.12-rc3-mm3.perfctr-k8-mc-fix/drivers/perfctr/x86.c
--- linux-2.6.12-rc3-mm3/drivers/perfctr/x86.c	2005-05-08 19:46:45.000000000 +0200
+++ linux-2.6.12-rc3-mm3.perfctr-k8-mc-fix/drivers/perfctr/x86.c	2005-05-08 19:53:54.000000000 +0200
@@ -66,6 +66,9 @@ struct perfctr_low_ctrs {
 #define MSR_K7_EVNTSEL0		0xC0010000	/* .. 0xC0010003 */
 #define MSR_K7_PERFCTR0		0xC0010004	/* .. 0xC0010007 */
 
+/* AMD K8 */
+#define IS_K8_NB_EVENT(EVNTSEL)	((((EVNTSEL) >> 5) & 0x7) == 0x7)
+
 /* Intel P4, Intel Pentium M */
 #define MSR_IA32_MISC_ENABLE	0x1A0
 #define MSR_IA32_MISC_ENABLE_PERF_AVAIL (1<<7)	/* read-only status bit */
@@ -398,8 +401,10 @@ static void c6_write_control(const struc
  * - Most events are symmetric, but a few are not.
  */
 
+static int k8_is_multicore;	/* affects northbridge events */
+
 /* shared with K7 */
-static int p6_like_check_control(struct perfctr_cpu_state *state, int is_k7)
+static int p6_like_check_control(struct perfctr_cpu_state *state, int is_k7, int is_global)
 {
 	unsigned int evntsel, i, nractrs, nrctrs, pmc_mask, pmc;
 
@@ -415,6 +420,9 @@ static int p6_like_check_control(struct 
 			return -EINVAL;
 		pmc_mask |= (1<<pmc);
 		evntsel = state->control.evntsel[pmc];
+		/* prevent the K8 multicore NB event clobber erratum */
+		if (!is_global && k8_is_multicore && IS_K8_NB_EVENT(evntsel))
+			return -EPERM;
 		/* protect reserved bits */
 		if (evntsel & P6_EVNTSEL_RESERVED)
 			return -EPERM;
@@ -451,7 +459,7 @@ static int p6_like_check_control(struct 
 
 static int p6_check_control(struct perfctr_cpu_state *state, int is_global)
 {
-	return p6_like_check_control(state, 0);
+	return p6_like_check_control(state, 0, is_global);
 }
 
 #ifdef CONFIG_X86_LOCAL_APIC
@@ -592,7 +600,7 @@ static void p6_clear_counters(void)
 
 static int k7_check_control(struct perfctr_cpu_state *state, int is_global)
 {
-	return p6_like_check_control(state, 1);
+	return p6_like_check_control(state, 1, is_global);
 }
 
 #ifdef CONFIG_X86_LOCAL_APIC
@@ -1409,6 +1417,50 @@ static int __init intel_init(void)
 	return -ENODEV;
 }
 
+/*
+ * Multicore K8s have issues with northbridge events:
+ * 1. The NB is shared between the cores, so two different cores
+ *    in the same node cannot count NB events simultaneously.
+ *    This can be handled by using perfctr_cpus_forbidden_mask to
+ *    restrict NB-using threads to core0 of all nodes.
+ * 2. The initial multicore chips (Revision E) have an erratum
+ *    which causes the NB counters to be reset when either core
+ *    reprograms its evntsels (even for non-NB events).
+ *    This is only an issue because of scheduling of threads, so
+ *    we restrict NB events to the non thread-centric API.
+ *
+ * For now we only implement the workaround for issue 2, as this
+ * also handles issue 1.
+ *
+ * TODO: Detect post Revision E chips and implement a weaker
+ * workaround for them.
+ */
+#ifdef CONFIG_SMP
+static void __init k8_multicore_init_cpu(void *non0cores)
+{
+	unsigned int core_id = cpuid_ebx(1) >> 27;
+	if (core_id != 0)
+		/* We rely on cpu_set() being atomic! */
+		cpu_set(smp_processor_id(), *(cpumask_t*)non0cores);
+}
+
+static void __init k8_multicore_init(void)
+{
+	cpumask_t non0cores;
+
+	cpus_clear(non0cores);
+	smp_call_function(k8_multicore_init_cpu, &non0cores, 1, 1);
+	k8_multicore_init_cpu(&non0cores);
+	if (cpus_empty(non0cores))
+		return;
+	k8_is_multicore = 1;
+	printk(KERN_INFO "perfctr/x86.c: multi-core K8s detected:"
+	       " restricting access to northbridge events\n");
+}
+#else
+#define k8_multicore_init()	do{}while(0)
+#endif
+
 static int __init amd_init(void)
 {
 	static char amd_name[] __initdata = "AMD K7/K8";
@@ -1417,7 +1469,9 @@ static int __init amd_init(void)
 		return -ENODEV;
 	switch (current_cpu_data.x86) {
 	case 6: /* K7 */
+		break;
 	case 15: /* K8. Like a K7 with a different event set. */
+		k8_multicore_init();
 		break;
 	default:
 		return -ENODEV;
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[Index of Archives]     [Kernel Newbies]     [Netfilter]     [Bugtraq]     [Photo]     [Stuff]     [Gimp]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Video 4 Linux]     [Linux for the blind]     [Linux Resources]
  Powered by Linux