Attached is the revised version of the patch previously titled: "Avoid hang when 4GB or more DRAM is installed on AMD RS780 UMA systems"
The email subject line is changed to "MTRR related improvements for AMD family 10h and family 0Fh systems" because the patch corrects some additional problems. Changes to AMD northbridge.c now allow the patch to use the standard x86_setup_var_mtrrs() function. There is no longer a need for an AMD version of this function. This should also remove the concern about the patch breaking non-AMD UMA projects. A new fix is included that allows using CONFIG_GFXUMA=1 and CONFIG_VAR_MTRR_HOLE=0 together. CONFIG_VAR_MTRR_HOLE still defaults to 1. -- MTRR related improvements for AMD family 10h and family 0Fh systems -- When building for UMA, reduce the limit for DRAM below 4GB from E0000000 to C0000000. This is needed to accommodate the UMA frame buffer. -- Correct problem where msr C0010010 bits 21 and 22 (MtrrTom2En and Tom2ForceMemTypeWB) are not set consistently across cores. -- Enable TOM2 only if DRAM is present above 4GB. -- Use AMD Tom2ForceMemTypeWB feature to avoid the need for variable MTRR ranges above 4GB. -- Add above4gb flag argument to function x86_setup_var_mtrrs. Clearing this flag causes x86_setup_var_mtrrs() to omit MTRR ranges for DRAM above 4GB. AMD systems use this option to conserve MTRRs. -- Northbridge.c change to deduct UMA memory from DRAM size reported by ram_resource. This corrects a problem where mtrr.c generates an unexpected variable MTRR range. -- Correct problem causing build failure when CONFIG_GFXUMA=1 and CONFIG_VAR_MTRR_HOLE=0. -- Improve white space consistency for mtrr.c by using tabs in place of spaces. -- Reserve the UMA DRAM range for AMD K8 as is already done for AMD family 10h. Tested with mahogany on ECS A780G-GM with 2GB and 4GB. Tested with mahogany_fam10 on ECS A780G-GM with 2GB and 4GB. Signed-off-by: Scott Duplichan <[email protected]> Index: src/cpu/amd/mtrr/amd_mtrr.c =================================================================== --- src/cpu/amd/mtrr/amd_mtrr.c (revision 6064) +++ src/cpu/amd/mtrr/amd_mtrr.c (working copy) @@ -6,6 +6,10 @@ #include <cpu/x86/cache.h> #include <cpu/x86/msr.h> +#if CONFIG_GFXUMA == 1 +extern uint64_t uma_memory_size; +#endif + static unsigned long resk(uint64_t value) { unsigned long resultk; @@ -107,14 +111,14 @@ unsigned long address_bits; struct mem_state state; unsigned long i; - msr_t msr; + msr_t msr, sys_cfg; /* Enable the access to AMD RdDram and WrDram extension bits */ disable_cache(); - msr = rdmsr(SYSCFG_MSR); - msr.lo |= SYSCFG_MSR_MtrrFixDramModEn; - wrmsr(SYSCFG_MSR, msr); + sys_cfg = rdmsr(SYSCFG_MSR); + sys_cfg.lo |= SYSCFG_MSR_MtrrFixDramModEn; + wrmsr(SYSCFG_MSR, sys_cfg); enable_cache(); printk(BIOS_DEBUG, "\n"); @@ -146,13 +150,21 @@ /* Setup TOP_MEM */ msr.hi = state.mmio_basek >> 22; msr.lo = state.mmio_basek << 10; + + // If UMA graphics is enabled, the frame buffer memory has been deducted + // from the size of memory below 4GB. When setting TOM, include UMA DRAM. + #if CONFIG_GFXUMA == 1 + msr.lo += uma_memory_size; + #endif wrmsr(TOP_MEM, msr); + sys_cfg.lo &= ~(SYSCFG_MSR_TOM2En | SYSCFG_MSR_TOM2WB); if(state.tomk > (4*1024*1024)) { - /* Setup TOP_MEM2 */ + // DRAM above 4GB: set TOM2, SYSCFG_MSR_TOM2En and SYSCFG_MSR_TOM2WB msr.hi = state.tomk >> 22; msr.lo = state.tomk << 10; wrmsr(TOP_MEM2, msr); + sys_cfg.lo |= SYSCFG_MSR_TOM2En | SYSCFG_MSR_TOM2WB; } /* zero the IORR's before we enable to prevent @@ -167,10 +179,9 @@ * Enable the RdMem and WrMem bits in the fixed mtrrs. * Disable access to the RdMem and WrMem in the fixed mtrr. */ - msr = rdmsr(SYSCFG_MSR); - msr.lo |= SYSCFG_MSR_MtrrVarDramEn | SYSCFG_MSR_MtrrFixDramEn | SYSCFG_MSR_TOM2En; - msr.lo &= ~SYSCFG_MSR_MtrrFixDramModEn; - wrmsr(SYSCFG_MSR, msr); + sys_cfg.lo |= SYSCFG_MSR_MtrrVarDramEn | SYSCFG_MSR_MtrrFixDramEn; + sys_cfg.lo &= ~SYSCFG_MSR_MtrrFixDramModEn; + wrmsr(SYSCFG_MSR, sys_cfg); enable_fixed_mtrr(); @@ -186,5 +197,5 @@ /* Now that I have mapped what is memory and what is not * Setup the mtrrs so we can cache the memory. */ - x86_setup_var_mtrrs(address_bits); + x86_setup_var_mtrrs(address_bits, 0); } Index: src/cpu/x86/mtrr/mtrr.c =================================================================== --- src/cpu/x86/mtrr/mtrr.c (revision 6064) +++ src/cpu/x86/mtrr/mtrr.c (working copy) @@ -74,23 +74,23 @@ msr_t base, mask; unsigned address_mask_high; - if (reg >= 8) - return; + if (reg >= 8) + return; - // it is recommended that we disable and enable cache when we - // do this. - if (sizek == 0) { - disable_cache(); + // it is recommended that we disable and enable cache when we + // do this. + if (sizek == 0) { + disable_cache(); - msr_t zero; - zero.lo = zero.hi = 0; - /* The invalid bit is kept in the mask, so we simply clear the - relevant mask register to disable a range. */ - wrmsr (MTRRphysMask_MSR(reg), zero); + msr_t zero; + zero.lo = zero.hi = 0; + /* The invalid bit is kept in the mask, so we simply clear the + relevant mask register to disable a range. */ + wrmsr (MTRRphysMask_MSR(reg), zero); - enable_cache(); - return; - } + enable_cache(); + return; +} address_mask_high = ((1u << (address_bits - 32u)) - 1u); @@ -230,7 +230,8 @@ static unsigned int range_to_mtrr(unsigned int reg, unsigned long range_startk, unsigned long range_sizek, - unsigned long next_range_startk, unsigned char type, unsigned address_bits) + unsigned long next_range_startk, unsigned char type, + unsigned int address_bits, unsigned int above4gb) { if (!range_sizek) { /* If there's no MTRR hole, this function will bail out @@ -263,7 +264,10 @@ (type==MTRR_TYPE_UNCACHEABLE)?"UC": ((type==MTRR_TYPE_WRBACK)?"WB":"Other") ); - set_var_mtrr(reg++, range_startk, sizek, type, address_bits); + + // if range is above 4GB, MTRR is needed only if above4gb flag is set + if (range_startk < 0x100000000ull / 1024 || above4gb) + set_var_mtrr(reg++, range_startk, sizek, type, address_bits); range_startk += sizek; range_sizek -= sizek; if (reg >= BIOS_MTRRS) { @@ -308,10 +312,9 @@ struct var_mtrr_state { unsigned long range_startk, range_sizek; unsigned int reg; -#if CONFIG_VAR_MTRR_HOLE unsigned long hole_startk, hole_sizek; -#endif - unsigned address_bits; + unsigned int address_bits; + unsigned int above4gb; // Set if MTRRs are needed for DRAM above 4GB }; void set_var_mtrr_resource(void *gp, struct device *dev, struct resource *res) @@ -344,17 +347,17 @@ } #endif state->reg = range_to_mtrr(state->reg, state->range_startk, - state->range_sizek, basek, MTRR_TYPE_WRBACK, state->address_bits); + state->range_sizek, basek, MTRR_TYPE_WRBACK, + state->address_bits, state->above4gb); #if CONFIG_VAR_MTRR_HOLE state->reg = range_to_mtrr(state->reg, state->hole_startk, - state->hole_sizek, basek, MTRR_TYPE_UNCACHEABLE, state->address_bits); + state->hole_sizek, basek, MTRR_TYPE_UNCACHEABLE, + state->address_bits, state->above4gb); #endif state->range_startk = 0; state->range_sizek = 0; -#if CONFIG_VAR_MTRR_HOLE - state->hole_startk = 0; - state->hole_sizek = 0; -#endif + state->hole_startk = 0; + state->hole_sizek = 0; } /* Allocate an msr */ printk(BIOS_SPEW, " Allocate an msr - basek = %08lx, sizek = %08lx,\n", basek, sizek); @@ -364,36 +367,38 @@ void x86_setup_fixed_mtrrs(void) { - /* Try this the simple way of incrementally adding together - * mtrrs. If this doesn't work out we can get smart again - * and clear out the mtrrs. - */ + /* Try this the simple way of incrementally adding together + * mtrrs. If this doesn't work out we can get smart again + * and clear out the mtrrs. + */ - printk(BIOS_DEBUG, "\n"); - /* Initialized the fixed_mtrrs to uncached */ - printk(BIOS_DEBUG, "Setting fixed MTRRs(%d-%d) Type: UC\n", - 0, NUM_FIXED_RANGES); - set_fixed_mtrrs(0, NUM_FIXED_RANGES, MTRR_TYPE_UNCACHEABLE); + printk(BIOS_DEBUG, "\n"); + /* Initialized the fixed_mtrrs to uncached */ + printk(BIOS_DEBUG, "Setting fixed MTRRs(%d-%d) Type: UC\n", + 0, NUM_FIXED_RANGES); + set_fixed_mtrrs(0, NUM_FIXED_RANGES, MTRR_TYPE_UNCACHEABLE); - /* Now see which of the fixed mtrrs cover ram. - */ - search_global_resources( + /* Now see which of the fixed mtrrs cover ram. */ + search_global_resources( IORESOURCE_MEM | IORESOURCE_CACHEABLE, IORESOURCE_MEM | IORESOURCE_CACHEABLE, set_fixed_mtrr_resource, NULL); - printk(BIOS_DEBUG, "DONE fixed MTRRs\n"); + printk(BIOS_DEBUG, "DONE fixed MTRRs\n"); - /* enable fixed MTRR */ - printk(BIOS_SPEW, "call enable_fixed_mtrr()\n"); - enable_fixed_mtrr(); + /* enable fixed MTRR */ + printk(BIOS_SPEW, "call enable_fixed_mtrr()\n"); + enable_fixed_mtrr(); } -void x86_setup_var_mtrrs(unsigned address_bits) +void x86_setup_var_mtrrs(unsigned int address_bits, unsigned int above4gb) /* this routine needs to know how many address bits a given processor * supports. CPUs get grumpy when you set too many bits in * their mtrr registers :( I would generically call cpuid here * and find out how many physically supported but some cpus are * buggy, and report more bits then they actually support. + * If above4gb flag is set, variable MTRR ranges must be used to + * set cacheability of DRAM above 4GB. If above4gb flag is clear, + * some other mechanism is controlling cacheability of DRAM above 4GB. */ { /* Try this the simple way of incrementally adding together @@ -408,34 +413,38 @@ */ var_state.range_startk = 0; var_state.range_sizek = 0; -#if CONFIG_VAR_MTRR_HOLE var_state.hole_startk = 0; var_state.hole_sizek = 0; -#endif var_state.reg = 0; var_state.address_bits = address_bits; + var_state.above4gb = above4gb; search_global_resources( IORESOURCE_MEM | IORESOURCE_CACHEABLE, IORESOURCE_MEM | IORESOURCE_CACHEABLE, set_var_mtrr_resource, &var_state); + #if (CONFIG_GFXUMA == 1) /* UMA or SP. */ - // For now we assume the UMA space is at the end of memory + // For now we assume the UMA space is at the end of memory below 4GB if (var_state.hole_startk || var_state.hole_sizek) { printk(BIOS_DEBUG, "Warning: Can't set up MTRR hole for UMA due to pre-existing MTRR hole.\n"); } else { +#if CONFIG_VAR_MTRR_HOLE // Increase the base range and set up UMA as an UC hole instead var_state.range_sizek += (uma_memory_size >> 10); var_state.hole_startk = (uma_memory_base >> 10); var_state.hole_sizek = (uma_memory_size >> 10); +#endif } #endif /* Write the last range */ var_state.reg = range_to_mtrr(var_state.reg, var_state.range_startk, - var_state.range_sizek, 0, MTRR_TYPE_WRBACK, var_state.address_bits); + var_state.range_sizek, 0, MTRR_TYPE_WRBACK, + var_state.address_bits, var_state.above4gb); #if CONFIG_VAR_MTRR_HOLE var_state.reg = range_to_mtrr(var_state.reg, var_state.hole_startk, - var_state.hole_sizek, 0, MTRR_TYPE_UNCACHEABLE, var_state.address_bits); + var_state.hole_sizek, 0, MTRR_TYPE_UNCACHEABLE, + var_state.address_bits, var_state.above4gb); #endif printk(BIOS_DEBUG, "DONE variable MTRRs\n"); printk(BIOS_DEBUG, "Clear out the extra MTRR's\n"); @@ -449,10 +458,11 @@ post_code(0x6A); } + void x86_setup_mtrrs(unsigned address_bits) { x86_setup_fixed_mtrrs(); - x86_setup_var_mtrrs(address_bits); + x86_setup_var_mtrrs(address_bits, 1); } Index: src/include/cpu/amd/mtrr.h =================================================================== --- src/include/cpu/amd/mtrr.h (revision 6064) +++ src/include/cpu/amd/mtrr.h (working copy) @@ -8,6 +8,7 @@ #define MTRR_WRITE_MEM (1 << 3) #define SYSCFG_MSR 0xC0010010 +#define SYSCFG_MSR_TOM2WB (1 << 22) #define SYSCFG_MSR_TOM2En (1 << 21) #define SYSCFG_MSR_MtrrVarDramEn (1 << 20) #define SYSCFG_MSR_MtrrFixDramModEn (1 << 19) Index: src/include/cpu/x86/mtrr.h =================================================================== --- src/include/cpu/x86/mtrr.h (revision 6064) +++ src/include/cpu/x86/mtrr.h (working copy) @@ -37,7 +37,7 @@ #if !defined (ASSEMBLY) && !defined(__PRE_RAM__) #include <device/device.h> void enable_fixed_mtrr(void); -void x86_setup_var_mtrrs(unsigned address_bits); +void x86_setup_var_mtrrs(unsigned int address_bits, unsigned int above4gb); void x86_setup_mtrrs(unsigned address_bits); int x86_mtrr_check(void); void set_var_mtrr_resource(void *gp, struct device *dev, struct resource *res); Index: src/northbridge/amd/amdfam10/northbridge.c =================================================================== --- src/northbridge/amd/amdfam10/northbridge.c (revision 6064) +++ src/northbridge/amd/amdfam10/northbridge.c (working copy) @@ -1060,6 +1060,11 @@ sizek -= (4*1024*1024 - mmio_basek); } } + +#if CONFIG_GFXUMA == 1 + // Deduct uma memory before reporting because this is what the mtrr code expects + sizek -= uma_memory_size / 1024; +#endif ram_resource(dev, (idx | i), basek, sizek); idx += 0x10; #if CONFIG_WRITE_HIGH_TABLES==1 Index: src/northbridge/amd/amdk8/northbridge.c =================================================================== --- src/northbridge/amd/amdk8/northbridge.c (revision 6064) +++ src/northbridge/amd/amdk8/northbridge.c (working copy) @@ -824,10 +824,23 @@ #if CONFIG_WRITE_HIGH_TABLES==1 #define HIGH_TABLES_SIZE 64 // maximum size of high tables in KB extern uint64_t high_tables_base, high_tables_size; +#endif + #if CONFIG_GFXUMA == 1 extern uint64_t uma_memory_base, uma_memory_size; + +static void add_uma_resource(struct device *dev, int index) +{ + struct resource *resource; + + printk(BIOS_DEBUG, "Adding UMA memory area\n"); + resource = new_resource(dev, index); + resource->base = (resource_t) uma_memory_base; + resource->size = (resource_t) uma_memory_size; + resource->flags = IORESOURCE_MEM | IORESOURCE_RESERVE | + IORESOURCE_FIXED | IORESOURCE_STORED | IORESOURCE_ASSIGNED; +} #endif -#endif static void amdk8_domain_set_resources(device_t dev) { @@ -1040,6 +1053,10 @@ /* If sizek == 0, it was split at mmio_basek without a hole. * Don't create an empty ram_resource. */ +#if CONFIG_GFXUMA == 1 + // Deduct uma memory before reporting because this is what the mtrr code expects + sizek -= uma_memory_size / 1024; +#endif if (sizek) ram_resource(dev, (idx | i), basek, sizek); idx += 0x10; @@ -1057,6 +1074,10 @@ } #endif } + +#if CONFIG_GFXUMA == 1 + add_uma_resource(dev, 7); +#endif assign_resources(dev->link_list); } Index: src/northbridge/amd/amdmct/wrappers/mcti.h =================================================================== --- src/northbridge/amd/amdmct/wrappers/mcti.h (revision 6064) +++ src/northbridge/amd/amdmct/wrappers/mcti.h (working copy) @@ -42,11 +42,12 @@ //#define SYSTEM_TYPE MOBILE #endif -/*---------------------------------------------------------------------------- -COMMENT OUT ALL BUT 1 -----------------------------------------------------------------------------*/ +/*--------------------------------------------------------------------------*/ +#if (CONFIG_GFXUMA) +#define UMA_SUPPORT 1 /*Supported */ +#else #define UMA_SUPPORT 0 /*Not supported */ -//#define UMA_SUPPORT 1 /*Supported */ +#endif /*---------------------------------------------------------------------------- UPDATE AS NEEDED Index: src/northbridge/amd/amdmct/wrappers/mcti_d.c =================================================================== --- src/northbridge/amd/amdmct/wrappers/mcti_d.c (revision 6064) +++ src/northbridge/amd/amdmct/wrappers/mcti_d.c (working copy) @@ -132,13 +132,17 @@ //val = 1; /* enable */ break; case NV_BottomIO: +#if (UMA_SUPPORT == 0) val = 0xE0; /* address bits [31:24] */ +#elif (UMA_SUPPORT == 1) + val = 0xC0; /* address bits [31:24] */ +#endif break; case NV_BottomUMA: #if (UMA_SUPPORT == 0) val = 0xE0; /* address bits [31:24] */ #elif (UMA_SUPPORT == 1) - val = 0xB0; /* address bits [31:24] */ + val = 0xC0; /* address bits [31:24] */ #endif break; case NV_ECC:
MTRR related improvements for AMD family 10h and family 0Fh systems -- When building for UMA, reduce the limit for DRAM below 4GB from E0000000 to C0000000. This is needed to accomodate the UMA frame buffer. -- Correct problem where msr C0010010 bits 21 and 22 (MtrrTom2En and Tom2ForceMemTypeWB) are not set consistently across cores. -- Enable TOM2 only if DRAM is present above 4GB. -- Use AMD Tom2ForceMemTypeWB feature to avoid the need for variable MTRR ranges above 4GB. -- Add above4gb flag argument to function x86_setup_var_mtrrs. Clearing this flag causes x86_setup_var_mtrrs() to omit MTRR ranges for DRAM above 4GB. AMD systems use this option to conserve MTRRs. -- Northbridge.c change to deduct UMA memory from DRAM size reported by ram_resource. This corrects a problem where mtrr.c generates an unexpected variable MTRR range. -- Correct problem causing build failure when CONFIG_GFXUMA=1 and CONFIG_VAR_MTRR_HOLE=0. -- Improve white space consistency for mtrr.c by using tabs in place of spaces. -- Reserve the UMA DRAM range for AMD K8 as is already done for AMD family 10h. Tested with mahogany on ECS A780G-GM with 2GB and 4GB. Tested with mahogany_fam10 on ECS A780G-GM with 2GB and 4GB. Signed-off-by: Scott Duplichan <[email protected]> Index: src/cpu/amd/mtrr/amd_mtrr.c =================================================================== --- src/cpu/amd/mtrr/amd_mtrr.c (revision 6064) +++ src/cpu/amd/mtrr/amd_mtrr.c (working copy) @@ -6,6 +6,10 @@ #include <cpu/x86/cache.h> #include <cpu/x86/msr.h> +#if CONFIG_GFXUMA == 1 +extern uint64_t uma_memory_size; +#endif + static unsigned long resk(uint64_t value) { unsigned long resultk; @@ -107,14 +111,14 @@ unsigned long address_bits; struct mem_state state; unsigned long i; - msr_t msr; + msr_t msr, sys_cfg; /* Enable the access to AMD RdDram and WrDram extension bits */ disable_cache(); - msr = rdmsr(SYSCFG_MSR); - msr.lo |= SYSCFG_MSR_MtrrFixDramModEn; - wrmsr(SYSCFG_MSR, msr); + sys_cfg = rdmsr(SYSCFG_MSR); + sys_cfg.lo |= SYSCFG_MSR_MtrrFixDramModEn; + wrmsr(SYSCFG_MSR, sys_cfg); enable_cache(); printk(BIOS_DEBUG, "\n"); @@ -146,13 +150,21 @@ /* Setup TOP_MEM */ msr.hi = state.mmio_basek >> 22; msr.lo = state.mmio_basek << 10; + + // If UMA graphics is enabled, the frame buffer memory has been deducted + // from the size of memory below 4GB. When setting TOM, include UMA DRAM. + #if CONFIG_GFXUMA == 1 + msr.lo += uma_memory_size; + #endif wrmsr(TOP_MEM, msr); + sys_cfg.lo &= ~(SYSCFG_MSR_TOM2En | SYSCFG_MSR_TOM2WB); if(state.tomk > (4*1024*1024)) { - /* Setup TOP_MEM2 */ + // DRAM above 4GB: set TOM2, SYSCFG_MSR_TOM2En and SYSCFG_MSR_TOM2WB msr.hi = state.tomk >> 22; msr.lo = state.tomk << 10; wrmsr(TOP_MEM2, msr); + sys_cfg.lo |= SYSCFG_MSR_TOM2En | SYSCFG_MSR_TOM2WB; } /* zero the IORR's before we enable to prevent @@ -167,10 +179,9 @@ * Enable the RdMem and WrMem bits in the fixed mtrrs. * Disable access to the RdMem and WrMem in the fixed mtrr. */ - msr = rdmsr(SYSCFG_MSR); - msr.lo |= SYSCFG_MSR_MtrrVarDramEn | SYSCFG_MSR_MtrrFixDramEn | SYSCFG_MSR_TOM2En; - msr.lo &= ~SYSCFG_MSR_MtrrFixDramModEn; - wrmsr(SYSCFG_MSR, msr); + sys_cfg.lo |= SYSCFG_MSR_MtrrVarDramEn | SYSCFG_MSR_MtrrFixDramEn; + sys_cfg.lo &= ~SYSCFG_MSR_MtrrFixDramModEn; + wrmsr(SYSCFG_MSR, sys_cfg); enable_fixed_mtrr(); @@ -186,5 +197,5 @@ /* Now that I have mapped what is memory and what is not * Setup the mtrrs so we can cache the memory. */ - x86_setup_var_mtrrs(address_bits); + x86_setup_var_mtrrs(address_bits, 0); } Index: src/cpu/x86/mtrr/mtrr.c =================================================================== --- src/cpu/x86/mtrr/mtrr.c (revision 6064) +++ src/cpu/x86/mtrr/mtrr.c (working copy) @@ -74,23 +74,23 @@ msr_t base, mask; unsigned address_mask_high; - if (reg >= 8) - return; + if (reg >= 8) + return; - // it is recommended that we disable and enable cache when we - // do this. - if (sizek == 0) { - disable_cache(); + // it is recommended that we disable and enable cache when we + // do this. + if (sizek == 0) { + disable_cache(); - msr_t zero; - zero.lo = zero.hi = 0; - /* The invalid bit is kept in the mask, so we simply clear the - relevant mask register to disable a range. */ - wrmsr (MTRRphysMask_MSR(reg), zero); + msr_t zero; + zero.lo = zero.hi = 0; + /* The invalid bit is kept in the mask, so we simply clear the + relevant mask register to disable a range. */ + wrmsr (MTRRphysMask_MSR(reg), zero); - enable_cache(); - return; - } + enable_cache(); + return; +} address_mask_high = ((1u << (address_bits - 32u)) - 1u); @@ -230,7 +230,8 @@ static unsigned int range_to_mtrr(unsigned int reg, unsigned long range_startk, unsigned long range_sizek, - unsigned long next_range_startk, unsigned char type, unsigned address_bits) + unsigned long next_range_startk, unsigned char type, + unsigned int address_bits, unsigned int above4gb) { if (!range_sizek) { /* If there's no MTRR hole, this function will bail out @@ -263,7 +264,10 @@ (type==MTRR_TYPE_UNCACHEABLE)?"UC": ((type==MTRR_TYPE_WRBACK)?"WB":"Other") ); - set_var_mtrr(reg++, range_startk, sizek, type, address_bits); + + // if range is above 4GB, MTRR is needed only if above4gb flag is set + if (range_startk < 0x100000000ull / 1024 || above4gb) + set_var_mtrr(reg++, range_startk, sizek, type, address_bits); range_startk += sizek; range_sizek -= sizek; if (reg >= BIOS_MTRRS) { @@ -308,10 +312,9 @@ struct var_mtrr_state { unsigned long range_startk, range_sizek; unsigned int reg; -#if CONFIG_VAR_MTRR_HOLE unsigned long hole_startk, hole_sizek; -#endif - unsigned address_bits; + unsigned int address_bits; + unsigned int above4gb; // Set if MTRRs are needed for DRAM above 4GB }; void set_var_mtrr_resource(void *gp, struct device *dev, struct resource *res) @@ -344,17 +347,17 @@ } #endif state->reg = range_to_mtrr(state->reg, state->range_startk, - state->range_sizek, basek, MTRR_TYPE_WRBACK, state->address_bits); + state->range_sizek, basek, MTRR_TYPE_WRBACK, + state->address_bits, state->above4gb); #if CONFIG_VAR_MTRR_HOLE state->reg = range_to_mtrr(state->reg, state->hole_startk, - state->hole_sizek, basek, MTRR_TYPE_UNCACHEABLE, state->address_bits); + state->hole_sizek, basek, MTRR_TYPE_UNCACHEABLE, + state->address_bits, state->above4gb); #endif state->range_startk = 0; state->range_sizek = 0; -#if CONFIG_VAR_MTRR_HOLE - state->hole_startk = 0; - state->hole_sizek = 0; -#endif + state->hole_startk = 0; + state->hole_sizek = 0; } /* Allocate an msr */ printk(BIOS_SPEW, " Allocate an msr - basek = %08lx, sizek = %08lx,\n", basek, sizek); @@ -364,36 +367,38 @@ void x86_setup_fixed_mtrrs(void) { - /* Try this the simple way of incrementally adding together - * mtrrs. If this doesn't work out we can get smart again - * and clear out the mtrrs. - */ + /* Try this the simple way of incrementally adding together + * mtrrs. If this doesn't work out we can get smart again + * and clear out the mtrrs. + */ - printk(BIOS_DEBUG, "\n"); - /* Initialized the fixed_mtrrs to uncached */ - printk(BIOS_DEBUG, "Setting fixed MTRRs(%d-%d) Type: UC\n", - 0, NUM_FIXED_RANGES); - set_fixed_mtrrs(0, NUM_FIXED_RANGES, MTRR_TYPE_UNCACHEABLE); + printk(BIOS_DEBUG, "\n"); + /* Initialized the fixed_mtrrs to uncached */ + printk(BIOS_DEBUG, "Setting fixed MTRRs(%d-%d) Type: UC\n", + 0, NUM_FIXED_RANGES); + set_fixed_mtrrs(0, NUM_FIXED_RANGES, MTRR_TYPE_UNCACHEABLE); - /* Now see which of the fixed mtrrs cover ram. - */ - search_global_resources( + /* Now see which of the fixed mtrrs cover ram. */ + search_global_resources( IORESOURCE_MEM | IORESOURCE_CACHEABLE, IORESOURCE_MEM | IORESOURCE_CACHEABLE, set_fixed_mtrr_resource, NULL); - printk(BIOS_DEBUG, "DONE fixed MTRRs\n"); + printk(BIOS_DEBUG, "DONE fixed MTRRs\n"); - /* enable fixed MTRR */ - printk(BIOS_SPEW, "call enable_fixed_mtrr()\n"); - enable_fixed_mtrr(); + /* enable fixed MTRR */ + printk(BIOS_SPEW, "call enable_fixed_mtrr()\n"); + enable_fixed_mtrr(); } -void x86_setup_var_mtrrs(unsigned address_bits) +void x86_setup_var_mtrrs(unsigned int address_bits, unsigned int above4gb) /* this routine needs to know how many address bits a given processor * supports. CPUs get grumpy when you set too many bits in * their mtrr registers :( I would generically call cpuid here * and find out how many physically supported but some cpus are * buggy, and report more bits then they actually support. + * If above4gb flag is set, variable MTRR ranges must be used to + * set cacheability of DRAM above 4GB. If above4gb flag is clear, + * some other mechanism is controlling cacheability of DRAM above 4GB. */ { /* Try this the simple way of incrementally adding together @@ -408,34 +413,38 @@ */ var_state.range_startk = 0; var_state.range_sizek = 0; -#if CONFIG_VAR_MTRR_HOLE var_state.hole_startk = 0; var_state.hole_sizek = 0; -#endif var_state.reg = 0; var_state.address_bits = address_bits; + var_state.above4gb = above4gb; search_global_resources( IORESOURCE_MEM | IORESOURCE_CACHEABLE, IORESOURCE_MEM | IORESOURCE_CACHEABLE, set_var_mtrr_resource, &var_state); + #if (CONFIG_GFXUMA == 1) /* UMA or SP. */ - // For now we assume the UMA space is at the end of memory + // For now we assume the UMA space is at the end of memory below 4GB if (var_state.hole_startk || var_state.hole_sizek) { printk(BIOS_DEBUG, "Warning: Can't set up MTRR hole for UMA due to pre-existing MTRR hole.\n"); } else { +#if CONFIG_VAR_MTRR_HOLE // Increase the base range and set up UMA as an UC hole instead var_state.range_sizek += (uma_memory_size >> 10); var_state.hole_startk = (uma_memory_base >> 10); var_state.hole_sizek = (uma_memory_size >> 10); +#endif } #endif /* Write the last range */ var_state.reg = range_to_mtrr(var_state.reg, var_state.range_startk, - var_state.range_sizek, 0, MTRR_TYPE_WRBACK, var_state.address_bits); + var_state.range_sizek, 0, MTRR_TYPE_WRBACK, + var_state.address_bits, var_state.above4gb); #if CONFIG_VAR_MTRR_HOLE var_state.reg = range_to_mtrr(var_state.reg, var_state.hole_startk, - var_state.hole_sizek, 0, MTRR_TYPE_UNCACHEABLE, var_state.address_bits); + var_state.hole_sizek, 0, MTRR_TYPE_UNCACHEABLE, + var_state.address_bits, var_state.above4gb); #endif printk(BIOS_DEBUG, "DONE variable MTRRs\n"); printk(BIOS_DEBUG, "Clear out the extra MTRR's\n"); @@ -449,10 +458,11 @@ post_code(0x6A); } + void x86_setup_mtrrs(unsigned address_bits) { x86_setup_fixed_mtrrs(); - x86_setup_var_mtrrs(address_bits); + x86_setup_var_mtrrs(address_bits, 1); } Index: src/include/cpu/amd/mtrr.h =================================================================== --- src/include/cpu/amd/mtrr.h (revision 6064) +++ src/include/cpu/amd/mtrr.h (working copy) @@ -8,6 +8,7 @@ #define MTRR_WRITE_MEM (1 << 3) #define SYSCFG_MSR 0xC0010010 +#define SYSCFG_MSR_TOM2WB (1 << 22) #define SYSCFG_MSR_TOM2En (1 << 21) #define SYSCFG_MSR_MtrrVarDramEn (1 << 20) #define SYSCFG_MSR_MtrrFixDramModEn (1 << 19) Index: src/include/cpu/x86/mtrr.h =================================================================== --- src/include/cpu/x86/mtrr.h (revision 6064) +++ src/include/cpu/x86/mtrr.h (working copy) @@ -37,7 +37,7 @@ #if !defined (ASSEMBLY) && !defined(__PRE_RAM__) #include <device/device.h> void enable_fixed_mtrr(void); -void x86_setup_var_mtrrs(unsigned address_bits); +void x86_setup_var_mtrrs(unsigned int address_bits, unsigned int above4gb); void x86_setup_mtrrs(unsigned address_bits); int x86_mtrr_check(void); void set_var_mtrr_resource(void *gp, struct device *dev, struct resource *res); Index: src/northbridge/amd/amdfam10/northbridge.c =================================================================== --- src/northbridge/amd/amdfam10/northbridge.c (revision 6064) +++ src/northbridge/amd/amdfam10/northbridge.c (working copy) @@ -1060,6 +1060,11 @@ sizek -= (4*1024*1024 - mmio_basek); } } + +#if CONFIG_GFXUMA == 1 + // Deduct uma memory before reporting because this is what the mtrr code expects + sizek -= uma_memory_size / 1024; +#endif ram_resource(dev, (idx | i), basek, sizek); idx += 0x10; #if CONFIG_WRITE_HIGH_TABLES==1 Index: src/northbridge/amd/amdk8/northbridge.c =================================================================== --- src/northbridge/amd/amdk8/northbridge.c (revision 6064) +++ src/northbridge/amd/amdk8/northbridge.c (working copy) @@ -824,10 +824,23 @@ #if CONFIG_WRITE_HIGH_TABLES==1 #define HIGH_TABLES_SIZE 64 // maximum size of high tables in KB extern uint64_t high_tables_base, high_tables_size; +#endif + #if CONFIG_GFXUMA == 1 extern uint64_t uma_memory_base, uma_memory_size; + +static void add_uma_resource(struct device *dev, int index) +{ + struct resource *resource; + + printk(BIOS_DEBUG, "Adding UMA memory area\n"); + resource = new_resource(dev, index); + resource->base = (resource_t) uma_memory_base; + resource->size = (resource_t) uma_memory_size; + resource->flags = IORESOURCE_MEM | IORESOURCE_RESERVE | + IORESOURCE_FIXED | IORESOURCE_STORED | IORESOURCE_ASSIGNED; +} #endif -#endif static void amdk8_domain_set_resources(device_t dev) { @@ -1040,6 +1053,10 @@ /* If sizek == 0, it was split at mmio_basek without a hole. * Don't create an empty ram_resource. */ +#if CONFIG_GFXUMA == 1 + // Deduct uma memory before reporting because this is what the mtrr code expects + sizek -= uma_memory_size / 1024; +#endif if (sizek) ram_resource(dev, (idx | i), basek, sizek); idx += 0x10; @@ -1057,6 +1074,10 @@ } #endif } + +#if CONFIG_GFXUMA == 1 + add_uma_resource(dev, 7); +#endif assign_resources(dev->link_list); } Index: src/northbridge/amd/amdmct/wrappers/mcti.h =================================================================== --- src/northbridge/amd/amdmct/wrappers/mcti.h (revision 6064) +++ src/northbridge/amd/amdmct/wrappers/mcti.h (working copy) @@ -42,11 +42,12 @@ //#define SYSTEM_TYPE MOBILE #endif -/*---------------------------------------------------------------------------- -COMMENT OUT ALL BUT 1 -----------------------------------------------------------------------------*/ +/*--------------------------------------------------------------------------*/ +#if (CONFIG_GFXUMA) +#define UMA_SUPPORT 1 /*Supported */ +#else #define UMA_SUPPORT 0 /*Not supported */ -//#define UMA_SUPPORT 1 /*Supported */ +#endif /*---------------------------------------------------------------------------- UPDATE AS NEEDED Index: src/northbridge/amd/amdmct/wrappers/mcti_d.c =================================================================== --- src/northbridge/amd/amdmct/wrappers/mcti_d.c (revision 6064) +++ src/northbridge/amd/amdmct/wrappers/mcti_d.c (working copy) @@ -132,13 +132,17 @@ //val = 1; /* enable */ break; case NV_BottomIO: +#if (UMA_SUPPORT == 0) val = 0xE0; /* address bits [31:24] */ +#elif (UMA_SUPPORT == 1) + val = 0xC0; /* address bits [31:24] */ +#endif break; case NV_BottomUMA: #if (UMA_SUPPORT == 0) val = 0xE0; /* address bits [31:24] */ #elif (UMA_SUPPORT == 1) - val = 0xB0; /* address bits [31:24] */ + val = 0xC0; /* address bits [31:24] */ #endif break; case NV_ECC:
-- coreboot mailing list: [email protected] http://www.coreboot.org/mailman/listinfo/coreboot

