Re: 2.6.38.2 breaks suspend to disk

From: Yinghai Lu
Date: Fri Apr 01 2011 - 17:24:57 EST


On Fri, Apr 1, 2011 at 1:21 PM, H. Peter Anvin <hpa@xxxxxxxxx> wrote:
> On 04/01/2011 12:54 PM, Yinghai Lu wrote:
>>
>> ok, please check if you are happy with this one.
>>
>
> The best would simply be:
>
>        mmu_cr4_features = read_cr4_safe();
>
> If this has to run before we can handle exceptions, one can verify the
> existence by testing for the CPUID instruction (a CPU has CR4 if and
> only if it has CPUID):
>
>        if (boot_cpu_data.cpuid_level >= 0)
>                mmu_cr4_features = read_cr4_safe();
>
> ... since we set cpuid_level to -1 if there is no CPUID instruction.

in that case could use read_cr4 directly.

please check attached -v4

Thanks
From: Stefano Stabellini <stefano.stabellini@xxxxxxxxxxxxx>

[PATCH -v4] x86: Save cr4 to mmu_cr4_features at boot time

Save cr4 to mmu_cr4_features at boot time

Michael reported 2.6.38.2 hibernation is broken by one backported patch.
it cause a freeze when resuming from hibernation

| "x86: Cleanup highmap after brk is concluded"
| commit id e5f15b45ddf3afa2bbbb10c7ea34fb32b6de0a0e.

it turns out the mmu_cr4 save it lost somehow.

-v3: read back cr4 for 32bit too according to HPA
-v4: use cpuid_level to check if we can read cr4 according to HPA
don't touch mmu_cr4_features if CONFIG_HIBERNATION is defined from Yinghai

Bisected-and-tested-by: Michael Leun <lkml20101129@xxxxxxxxxxxxxxx>
Signed-off-by: Stefano Stabellini <stefano.stabellini@xxxxxxxxxxxxx>
Signed-off-by: Yinghai Lu <yinghai@xxxxxxxxxx>

---
arch/x86/include/asm/processor.h | 4 ++++
arch/x86/kernel/setup.c | 11 ++++++++++-
2 files changed, 14 insertions(+), 1 deletion(-)

Index: linux-2.6/arch/x86/kernel/setup.c
===================================================================
--- linux-2.6.orig/arch/x86/kernel/setup.c
+++ linux-2.6/arch/x86/kernel/setup.c
@@ -212,7 +212,11 @@ struct cpuinfo_x86 boot_cpu_data __read_
EXPORT_SYMBOL(boot_cpu_data);
#endif

-
+/*
+ * mmu_cr4_features two purpose:
+ * a. head_32.S will access cr4 according if X86_CR4_PAE is set in it.
+ * b. store read back cr4 for hibernation
+ */
#if !defined(CONFIG_X86_PAE) || defined(CONFIG_X86_64)
unsigned long mmu_cr4_features;
#else
@@ -892,6 +896,11 @@ void __init setup_arch(char **cmdline_p)

high_memory = (void *)__va(max_pfn * PAGE_SIZE - 1) + 1;
#endif
+#ifdef CONFIG_HIBERNATION
+ /* a CPU has CR4 iff it has CPUID --- hpa */
+ if (boot_cpu_data.cpuid_level >= 0)
+ mmu_cr4_features = read_cr4();
+#endif

/*
* Find and reserve possible boot-time SMP configuration:
Index: linux-2.6/arch/x86/include/asm/processor.h
===================================================================
--- linux-2.6.orig/arch/x86/include/asm/processor.h
+++ linux-2.6/arch/x86/include/asm/processor.h
@@ -601,7 +601,9 @@ static inline void set_in_cr4(unsigned l
{
unsigned long cr4;

+#ifdef CONFIG_HIBERNATION
mmu_cr4_features |= mask;
+#endif
cr4 = read_cr4();
cr4 |= mask;
write_cr4(cr4);
@@ -611,7 +613,9 @@ static inline void clear_in_cr4(unsigned
{
unsigned long cr4;

+#ifdef CONFIG_HIBERNATION
mmu_cr4_features &= ~mask;
+#endif
cr4 = read_cr4();
cr4 &= ~mask;
write_cr4(cr4);