| From jejb@kernel.org Tue Sep 2 17:14:12 2008 |
| From: Yinghai Lu <yhlu.kernel@gmail.com> |
| Date: Fri, 22 Aug 2008 17:40:05 GMT |
| Subject: x86: work around MTRR mask setting |
| To: jejb@kernel.org, stable@kernel.org |
| Message-ID: <200808221740.m7MHe5ud013727@hera.kernel.org> |
| |
| From: Yinghai Lu <yhlu.kernel@gmail.com> |
| |
| commit 38cc1c3df77c1bb739a4766788eb9fa49f16ffdf upstream |
| |
| Joshua Hoblitt reported that only 3 GB of his 16 GB of RAM is |
| usable. Booting with mtrr_show showed us the BIOS-initialized |
| MTRR settings - which are all wrong. |
| |
| So the root cause is that the BIOS has not set the mask correctly: |
| |
| > [ 0.429971] MSR00000200: 00000000d0000000 |
| > [ 0.433305] MSR00000201: 0000000ff0000800 |
| > should be ==> [ 0.433305] MSR00000201: 0000003ff0000800 |
| > |
| > [ 0.436638] MSR00000202: 00000000e0000000 |
| > [ 0.439971] MSR00000203: 0000000fe0000800 |
| > should be ==> [ 0.439971] MSR00000203: 0000003fe0000800 |
| > |
| > [ 0.443304] MSR00000204: 0000000000000006 |
| > [ 0.446637] MSR00000205: 0000000c00000800 |
| > should be ==> [ 0.446637] MSR00000205: 0000003c00000800 |
| > |
| > [ 0.449970] MSR00000206: 0000000400000006 |
| > [ 0.453303] MSR00000207: 0000000fe0000800 |
| > should be ==> [ 0.453303] MSR00000207: 0000003fe0000800 |
| > |
| > [ 0.456636] MSR00000208: 0000000420000006 |
| > [ 0.459970] MSR00000209: 0000000ff0000800 |
| > should be ==> [ 0.459970] MSR00000209: 0000003ff0000800 |
| |
| So detect this borkage and add the prefix 111. |
| |
| Signed-off-by: Yinghai Lu <yhlu.kernel@gmail.com> |
| Signed-off-by: Ingo Molnar <mingo@elte.hu> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> |
| |
| --- |
| arch/x86/kernel/cpu/mtrr/generic.c | 15 +++++++++++++-- |
| 1 file changed, 13 insertions(+), 2 deletions(-) |
| |
| --- a/arch/x86/kernel/cpu/mtrr/generic.c |
| +++ b/arch/x86/kernel/cpu/mtrr/generic.c |
| @@ -229,6 +229,7 @@ static void generic_get_mtrr(unsigned in |
| unsigned long *size, mtrr_type *type) |
| { |
| unsigned int mask_lo, mask_hi, base_lo, base_hi; |
| + unsigned int tmp, hi; |
| |
| rdmsr(MTRRphysMask_MSR(reg), mask_lo, mask_hi); |
| if ((mask_lo & 0x800) == 0) { |
| @@ -242,8 +243,18 @@ static void generic_get_mtrr(unsigned in |
| rdmsr(MTRRphysBase_MSR(reg), base_lo, base_hi); |
| |
| /* Work out the shifted address mask. */ |
| - mask_lo = size_or_mask | mask_hi << (32 - PAGE_SHIFT) |
| - | mask_lo >> PAGE_SHIFT; |
| + tmp = mask_hi << (32 - PAGE_SHIFT) | mask_lo >> PAGE_SHIFT; |
| + mask_lo = size_or_mask | tmp; |
| + /* Expand tmp with high bits to all 1s*/ |
| + hi = fls(tmp); |
| + if (hi > 0) { |
| + tmp |= ~((1<<(hi - 1)) - 1); |
| + |
| + if (tmp != mask_lo) { |
| + WARN_ON("mtrr: your BIOS has set up an incorrect mask, fixing it up.\n"); |
| + mask_lo = tmp; |
| + } |
| + } |
| |
| /* This works correctly if size is a power of two, i.e. a |
| contiguous range. */ |