Re: [PATCH] x86-64: Disable local APIC timer use on AMD systems with C1E

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

 



On Tuesday, 25 September 2007 21:37, Thomas Gleixner wrote:
> commit 3556ddfa9284a86a59a9b78fe5894430f6ab4eef titled
> 
>  [PATCH] x86-64: Disable local APIC timer use on AMD systems with C1E
> 
> solves a problem with AMD dual core laptops e.g. HP nx6325 (Turion 64
> X2) with C1E enabled:
> 
> When both cores go into idle at the same time, then the system switches
> into C1E state, which is basically the same as C3. This stops the local
> apic timer.
> 
> This was debugged right after the dyntick merge on i386 and despite the
> patch title it fixes only the 32 bit path.
> 
> x86_64 is still missing this fix. It seems that mainline is not really
> affected by this issue, as the PIT is running and keeps jiffies
> incrementing, but that's just waiting for trouble. 
> 
> -mm suffers from this problem due to the x86_64 high resolution timer
> patches.
> 
> This is a quick and dirty port of the i386 code to x86_64. 
> 
> I spent quite a time with Rafael to debug the -mm / hrt wreckage until
> someone pointed us to this. I really had forgotten that we debugged this
> half a year ago already. 
> 
> Sigh, is it just me or is there something yelling arch/x86 into my ear?
> 
> Signed-off-by: Thomas Gleixner <[email protected]>

I have reworked the patch a bit so that it applies on top of 2.6.23-rc8-mm1
and compiles (my version is attached).

With this patch applied, the kernel boots correctly on the nx6325.

Greetings,
Rafael
---
 arch/x86_64/kernel/apic.c  |    2 +-
 arch/x86_64/kernel/setup.c |   34 ++++++++++++++++++++++++++++++++++
 include/asm-x86_64/apic.h  |    1 +
 3 files changed, 36 insertions(+), 1 deletion(-)

Index: linux-2.6.23-rc8-mm1/arch/x86_64/kernel/setup.c
===================================================================
--- linux-2.6.23-rc8-mm1.orig/arch/x86_64/kernel/setup.c
+++ linux-2.6.23-rc8-mm1/arch/x86_64/kernel/setup.c
@@ -620,6 +620,37 @@ static void __cpuinit early_init_amd(str
 #endif
 }
 
+#define ENABLE_C1E_MASK		0x18000000
+#define CPUID_PROCESSOR_SIGNATURE	1
+#define CPUID_XFAM		0x0ff00000
+#define CPUID_XFAM_K8		0x00000000
+#define CPUID_XFAM_10H		0x00100000
+#define CPUID_XFAM_11H		0x00200000
+#define CPUID_XMOD		0x000f0000
+#define CPUID_XMOD_REV_F	0x00040000
+
+/* AMD systems with C1E don't have a working lAPIC timer. Check for that. */
+static __cpuinit int amd_apic_timer_broken(void)
+{
+	u32 lo, hi;
+	u32 eax = cpuid_eax(CPUID_PROCESSOR_SIGNATURE);
+	switch (eax & CPUID_XFAM) {
+	case CPUID_XFAM_K8:
+		if ((eax & CPUID_XMOD) < CPUID_XMOD_REV_F)
+			break;
+	case CPUID_XFAM_10H:
+	case CPUID_XFAM_11H:
+		rdmsr(MSR_K8_ENABLE_C1E, lo, hi);
+		if (lo & ENABLE_C1E_MASK)
+			return 1;
+		break;
+	default:
+		/* err on the side of caution */
+		return 1;
+	}
+	return 0;
+}
+
 static void __cpuinit init_amd(struct cpuinfo_x86 *c)
 {
 	unsigned level, flags, dummy;
@@ -692,6 +723,9 @@ static void __cpuinit init_amd(struct cp
 	if (c->x86 == 0x10 && !force_mwait)
 		clear_bit(X86_FEATURE_MWAIT, &c->x86_capability);
 
+	if (amd_apic_timer_broken())
+		disable_apic_timer = 1;
+
 	if (c->x86 >= 0xf && c->x86 <= 0x11 &&
 	    !rdmsr_safe(MSR_VM_CR, &flags, &dummy) &&
 	    (flags & 0x18))
Index: linux-2.6.23-rc8-mm1/include/asm-x86_64/apic.h
===================================================================
--- linux-2.6.23-rc8-mm1.orig/include/asm-x86_64/apic.h
+++ linux-2.6.23-rc8-mm1/include/asm-x86_64/apic.h
@@ -19,6 +19,7 @@
 extern int apic_verbosity;
 extern int apic_runs_main_timer;
 extern int ioapic_force;
+extern int disable_apic_timer;
 
 /*
  * Define the default level of output to be very little
Index: linux-2.6.23-rc8-mm1/arch/x86_64/kernel/apic.c
===================================================================
--- linux-2.6.23-rc8-mm1.orig/arch/x86_64/kernel/apic.c
+++ linux-2.6.23-rc8-mm1/arch/x86_64/kernel/apic.c
@@ -41,8 +41,8 @@
 #include <asm/apic.h>
 
 int apic_verbosity;
+int disable_apic_timer __initdata;
 static int apic_calibrate_pmtmr __initdata;
-static int disable_apic_timer __initdata;
 
 /* Local APIC timer works in C2? */
 int local_apic_timer_c2_ok;

[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