[lkml]   [2009]   [Apr]   [30]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
Messages in this thread
    Patch in this message
    Subject[patch 19/88] x86: mtrr: dont modify RdDram/WrDram bits of fixed MTRRs
    2.6.28-stable review patch.  If anyone has any objections, please let us know.


    From: Andreas Herrmann <>

    upstream commit: 3ff42da5048649503e343a32be37b14a6a4e8aaf

    Impact: bug fix + BIOS workaround

    BIOS is expected to clear the SYSCFG[MtrrFixDramModEn] on AMD CPUs
    after fixed MTRRs are configured.

    Some BIOSes do not clear SYSCFG[MtrrFixDramModEn] on BP (and on APs).

    This can lead to obfuscation in Linux when this bit is not cleared on
    BP but cleared on APs. A consequence of this is that the saved
    fixed-MTRR state (from BP) differs from the fixed-MTRRs of APs --
    because RdDram/WrDram bits are read as zero when
    SYSCFG[MtrrFixDramModEn] is cleared -- and Linux tries to sync
    fixed-MTRR state from BP to AP. This implies that Linux sets
    SYSCFG[MtrrFixDramEn] and activates those bits.

    More important is that (some) systems change these bits in SMM when
    ACPI is enabled. Hence it is racy if Linux modifies RdMem/WrMem bits,

    (1) The patch modifies an old fix from Bernhard Kaindl to get
    suspend/resume working on some Acer Laptops. Bernhard's patch
    tried to sync RdMem/WrMem bits of fixed MTRR registers and that
    helped on those old Laptops. (Don't ask me why -- can't test it
    myself). But this old problem was not the motivation for the
    patch. (See

    (2) The more important effect is to fix issues on some more current systems.

    On those systems Linux panics or just freezes, see
    (and also duplicates of this bug:

    The affected systems boot only using acpi=ht, acpi=off or
    when the kernel is built with CONFIG_MTRR=n.

    The acpi options prevent full enablement of ACPI. Obviously when
    ACPI is enabled the BIOS/SMM modfies RdMem/WrMem bits. When
    CONFIG_MTRR=y Linux also accesses and modifies those bits when it
    needs to sync fixed-MTRRs across cores (Bernhard's fix, see (1)).
    How do you synchronize that? You can't. As a consequence Linux
    shouldn't touch those bits at all (Rationale are AMD's BKDGs which
    recommend to clear the bit that makes RdMem/WrMem accessible).
    This is the purpose of this patch. And (so far) this suffices to
    fix (1) and (2).

    I suggest not to touch RdDram/WrDram bits of fixed-MTRRs and
    SYSCFG[MtrrFixDramEn] and to clear SYSCFG[MtrrFixDramModEn] as
    suggested by AMD K8, and AMD family 10h/11h BKDGs.
    BIOS is expected to do this anyway. This should avoid that
    Linux and SMM tread on each other's toes ...

    Signed-off-by: Andreas Herrmann <>
    Cc: Yinghai Lu <>
    LKML-Reference: <>
    Signed-off-by: Ingo Molnar <>
    Signed-off-by: Chris Wright <>
    Signed-off-by: Greg Kroah-Hartman <>
    arch/x86/kernel/cpu/mtrr/generic.c | 51 +++++++++++++++++++++----------------
    1 file changed, 30 insertions(+), 21 deletions(-)

    --- a/arch/x86/kernel/cpu/mtrr/generic.c
    +++ b/arch/x86/kernel/cpu/mtrr/generic.c
    @@ -45,6 +45,32 @@ u64 mtrr_tom2;
    static int mtrr_show;
    module_param_named(show, mtrr_show, bool, 0);

    + * BIOS is expected to clear MtrrFixDramModEn bit, see for example
    + * "BIOS and Kernel Developer's Guide for the AMD Athlon 64 and AMD
    + * Opteron Processors" (26094 Rev. 3.30 February 2006), section
    + * " SYSCFG Register": "The MtrrFixDramModEn bit should be set
    + * to 1 during BIOS initalization of the fixed MTRRs, then cleared to
    + * 0 for operation."
    + */
    +static inline void k8_check_syscfg_dram_mod_en(void)
    + u32 lo, hi;
    + if (!((boot_cpu_data.x86_vendor == X86_VENDOR_AMD) &&
    + (boot_cpu_data.x86 >= 0x0f)))
    + return;
    + rdmsr(MSR_K8_SYSCFG, lo, hi);
    + printk(KERN_ERR FW_WARN "MTRR: CPU %u: SYSCFG[MtrrFixDramModEn]"
    + " not cleared by BIOS, clearing this bit\n",
    + smp_processor_id());
    + mtrr_wrmsr(MSR_K8_SYSCFG, lo, hi);
    + }
    * Returns the effective MTRR type for the region
    * Error returns:
    @@ -178,6 +204,8 @@ get_fixed_ranges(mtrr_type * frs)
    unsigned int *p = (unsigned int *) frs;
    int i;

    + k8_check_syscfg_dram_mod_en();
    rdmsr(MTRRfix64K_00000_MSR, p[0], p[1]);

    for (i = 0; i < 2; i++)
    @@ -312,27 +340,10 @@ void mtrr_wrmsr(unsigned msr, unsigned a

    - * Enable and allow read/write of extended fixed-range MTRR bits on K8 CPUs
    - * see AMD publication no. 24593, chapter 3.2.1 for more information
    - */
    -static inline void k8_enable_fixed_iorrs(void)
    - unsigned lo, hi;
    - rdmsr(MSR_K8_SYSCFG, lo, hi);
    - mtrr_wrmsr(MSR_K8_SYSCFG, lo
    * set_fixed_range - checks & updates a fixed-range MTRR if it differs from the value it should have
    * @msr: MSR address of the MTTR which should be checked and updated
    * @changed: pointer which indicates whether the MTRR needed to be changed
    * @msrwords: pointer to the MSR values which the MSR should have
    - *
    - * If K8 extentions are wanted, update the K8 SYSCFG MSR also.
    - * See AMD publication no. 24593, chapter 7.8.1, page 233 for more information.
    static void set_fixed_range(int msr, bool *changed, unsigned int *msrwords)
    @@ -341,10 +352,6 @@ static void set_fixed_range(int msr, boo
    rdmsr(msr, lo, hi);

    if (lo != msrwords[0] || hi != msrwords[1]) {
    - if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD &&
    - (boot_cpu_data.x86 >= 0x0f && boot_cpu_data.x86 <= 0x11) &&
    - ((msrwords[0] | msrwords[1]) & K8_MTRR_RDMEM_WRMEM_MASK))
    - k8_enable_fixed_iorrs();
    mtrr_wrmsr(msr, msrwords[0], msrwords[1]);
    *changed = true;
    @@ -423,6 +430,8 @@ static int set_fixed_ranges(mtrr_type *
    bool changed = false;
    int block=-1, range;

    + k8_check_syscfg_dram_mod_en();
    while (fixed_range_blocks[++block].ranges)
    for (range=0; range < fixed_range_blocks[block].ranges; range++)
    set_fixed_range(fixed_range_blocks[block].base_msr + range,

     \ /
      Last update: 2009-04-30 19:19    [W:0.027 / U:109.224 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site