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

Reply via email to