On Tue, Jul 31, 2012 at 18:20 +0200, Mike Belopuhov wrote:
> Hi,
>
> As it was recently discovered some newer machines have 40 bit
> physical address size which means that the math that is good
> for 36 bit paddr just doesn't cut it anymore. In fact the
> memory region lengths we program into the MSRs are completely
> off.
>
> The following diff has some code ported from FreeBSD to address
> this and other concerns. It substantiates a comment about TLB
> invalidation by doing an actual TLB flush before we enable the
> MTRR and also fixes an incorrect behavior and a race spotted by
> Theo when we're setting MSR_MTRRdefType to be the same as in
> boot CPU.
>
> Please give this diff a spin as it might solve some weird problems
> in X as well as fixing the speed problem for me which we believe is
> caused by screwing up the uncacheable PCI device memory mappings.
>
The same treatment is needed for i386.
diff --git arch/i386/i386/i686_mem.c arch/i386/i386/i686_mem.c
index 8997e4b..8c9635e 100644
--- arch/i386/i386/i686_mem.c
+++ arch/i386/i386/i686_mem.c
@@ -291,7 +291,7 @@ i686_mrstoreone(struct mem_range_softc *sc)
if (cr4save & CR4_PGE)
lcr4(cr4save & ~CR4_PGE);
lcr0((rcr0() & ~CR0_NW) | CR0_CD); /* disable caches (CD = 1, NW = 0) */
- wbinvd(); /* flush caches, TLBs */
+ wbinvd(); /* flush caches */
wrmsr(MSR_MTRRdefType, rdmsr(MSR_MTRRdefType) & ~0x800); /*
disable MTRRs (E = 0) */
/* Set fixed-range MTRRs */
@@ -340,7 +340,7 @@ i686_mrstoreone(struct mem_range_softc *sc)
/* base/type register */
omsrv = rdmsr(msr);
if (mrd->mr_flags & MDF_ACTIVE) {
- msrv = mrd->mr_base & 0x0000000ffffff000LL;
+ msrv = mrd->mr_base & mtrrmask;
msrv |= i686_mrt2mtrr(mrd->mr_flags, omsrv);
} else {
msrv = 0;
@@ -349,14 +349,15 @@ i686_mrstoreone(struct mem_range_softc *sc)
/* mask/active register */
if (mrd->mr_flags & MDF_ACTIVE) {
- msrv = 0x800 | (~(mrd->mr_len - 1) &
0x0000000ffffff000LL);
+ msrv = 0x800 | (~(mrd->mr_len - 1) & mtrrmask);
} else {
msrv = 0;
}
wrmsr(msr + 1, msrv);
}
- wbinvd(); /*
flush caches, TLBs */
- wrmsr(MSR_MTRRdefType, rdmsr(MSR_MTRRdefType) | 0x800); /* restore MTRR
state */
+ wbinvd(); /* flush caches */
+ tlbflushg(); /* flush TLB */
+ wrmsr(MSR_MTRRdefType, mtrrdef | 0x800); /* restore MTRR state */
lcr0(rcr0() & ~(CR0_CD | CR0_NW)); /* enable
caches CD = 0 and NW = 0 */
lcr4(cr4save); /* restore cr4
*/
}
@@ -616,7 +617,6 @@ void
i686_mrinit_cpu(struct mem_range_softc *sc)
{
i686_mrstoreone(sc); /* set MTRRs to match BSP */
- wrmsr(MSR_MTRRdefType, mtrrdef); /* set MTRR behaviour to match BSP */
}
void