diff options
| -rw-r--r-- | arch/x86/kernel/cpu/mtrr/generic.c | 51 |
1 files changed, 30 insertions, 21 deletions
diff --git a/arch/x86/kernel/cpu/mtrr/generic.c b/arch/x86/kernel/cpu/mtrr/generic.c index 964403520100..950c434f793d 100644 --- a/arch/x86/kernel/cpu/mtrr/generic.c +++ b/arch/x86/kernel/cpu/mtrr/generic.c | |||
| @@ -33,6 +33,32 @@ u64 mtrr_tom2; | |||
| 33 | struct mtrr_state_type mtrr_state = {}; | 33 | struct mtrr_state_type mtrr_state = {}; |
| 34 | EXPORT_SYMBOL_GPL(mtrr_state); | 34 | EXPORT_SYMBOL_GPL(mtrr_state); |
| 35 | 35 | ||
| 36 | /** | ||
| 37 | * BIOS is expected to clear MtrrFixDramModEn bit, see for example | ||
| 38 | * "BIOS and Kernel Developer's Guide for the AMD Athlon 64 and AMD | ||
| 39 | * Opteron Processors" (26094 Rev. 3.30 February 2006), section | ||
| 40 | * "13.2.1.2 SYSCFG Register": "The MtrrFixDramModEn bit should be set | ||
| 41 | * to 1 during BIOS initalization of the fixed MTRRs, then cleared to | ||
| 42 | * 0 for operation." | ||
| 43 | */ | ||
| 44 | static inline void k8_check_syscfg_dram_mod_en(void) | ||
| 45 | { | ||
| 46 | u32 lo, hi; | ||
| 47 | |||
| 48 | if (!((boot_cpu_data.x86_vendor == X86_VENDOR_AMD) && | ||
| 49 | (boot_cpu_data.x86 >= 0x0f))) | ||
| 50 | return; | ||
| 51 | |||
| 52 | rdmsr(MSR_K8_SYSCFG, lo, hi); | ||
| 53 | if (lo & K8_MTRRFIXRANGE_DRAM_MODIFY) { | ||
| 54 | printk(KERN_ERR FW_WARN "MTRR: CPU %u: SYSCFG[MtrrFixDramModEn]" | ||
| 55 | " not cleared by BIOS, clearing this bit\n", | ||
| 56 | smp_processor_id()); | ||
| 57 | lo &= ~K8_MTRRFIXRANGE_DRAM_MODIFY; | ||
| 58 | mtrr_wrmsr(MSR_K8_SYSCFG, lo, hi); | ||
| 59 | } | ||
| 60 | } | ||
| 61 | |||
| 36 | /* | 62 | /* |
| 37 | * Returns the effective MTRR type for the region | 63 | * Returns the effective MTRR type for the region |
| 38 | * Error returns: | 64 | * Error returns: |
| @@ -166,6 +192,8 @@ get_fixed_ranges(mtrr_type * frs) | |||
| 166 | unsigned int *p = (unsigned int *) frs; | 192 | unsigned int *p = (unsigned int *) frs; |
| 167 | int i; | 193 | int i; |
| 168 | 194 | ||
| 195 | k8_check_syscfg_dram_mod_en(); | ||
| 196 | |||
| 169 | rdmsr(MTRRfix64K_00000_MSR, p[0], p[1]); | 197 | rdmsr(MTRRfix64K_00000_MSR, p[0], p[1]); |
| 170 | 198 | ||
| 171 | for (i = 0; i < 2; i++) | 199 | for (i = 0; i < 2; i++) |
| @@ -306,27 +334,10 @@ void mtrr_wrmsr(unsigned msr, unsigned a, unsigned b) | |||
| 306 | } | 334 | } |
| 307 | 335 | ||
| 308 | /** | 336 | /** |
| 309 | * Enable and allow read/write of extended fixed-range MTRR bits on K8 CPUs | ||
| 310 | * see AMD publication no. 24593, chapter 3.2.1 for more information | ||
| 311 | */ | ||
| 312 | static inline void k8_enable_fixed_iorrs(void) | ||
| 313 | { | ||
| 314 | unsigned lo, hi; | ||
| 315 | |||
| 316 | rdmsr(MSR_K8_SYSCFG, lo, hi); | ||
| 317 | mtrr_wrmsr(MSR_K8_SYSCFG, lo | ||
| 318 | | K8_MTRRFIXRANGE_DRAM_ENABLE | ||
| 319 | | K8_MTRRFIXRANGE_DRAM_MODIFY, hi); | ||
| 320 | } | ||
| 321 | |||
| 322 | /** | ||
| 323 | * set_fixed_range - checks & updates a fixed-range MTRR if it differs from the value it should have | 337 | * set_fixed_range - checks & updates a fixed-range MTRR if it differs from the value it should have |
| 324 | * @msr: MSR address of the MTTR which should be checked and updated | 338 | * @msr: MSR address of the MTTR which should be checked and updated |
| 325 | * @changed: pointer which indicates whether the MTRR needed to be changed | 339 | * @changed: pointer which indicates whether the MTRR needed to be changed |
| 326 | * @msrwords: pointer to the MSR values which the MSR should have | 340 | * @msrwords: pointer to the MSR values which the MSR should have |
| 327 | * | ||
| 328 | * If K8 extentions are wanted, update the K8 SYSCFG MSR also. | ||
| 329 | * See AMD publication no. 24593, chapter 7.8.1, page 233 for more information. | ||
| 330 | */ | 341 | */ |
| 331 | static void set_fixed_range(int msr, bool *changed, unsigned int *msrwords) | 342 | static void set_fixed_range(int msr, bool *changed, unsigned int *msrwords) |
| 332 | { | 343 | { |
| @@ -335,10 +346,6 @@ static void set_fixed_range(int msr, bool *changed, unsigned int *msrwords) | |||
| 335 | rdmsr(msr, lo, hi); | 346 | rdmsr(msr, lo, hi); |
| 336 | 347 | ||
| 337 | if (lo != msrwords[0] || hi != msrwords[1]) { | 348 | if (lo != msrwords[0] || hi != msrwords[1]) { |
| 338 | if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD && | ||
| 339 | (boot_cpu_data.x86 >= 0x0f && boot_cpu_data.x86 <= 0x11) && | ||
| 340 | ((msrwords[0] | msrwords[1]) & K8_MTRR_RDMEM_WRMEM_MASK)) | ||
| 341 | k8_enable_fixed_iorrs(); | ||
| 342 | mtrr_wrmsr(msr, msrwords[0], msrwords[1]); | 349 | mtrr_wrmsr(msr, msrwords[0], msrwords[1]); |
| 343 | *changed = true; | 350 | *changed = true; |
| 344 | } | 351 | } |
| @@ -426,6 +433,8 @@ static int set_fixed_ranges(mtrr_type * frs) | |||
| 426 | bool changed = false; | 433 | bool changed = false; |
| 427 | int block=-1, range; | 434 | int block=-1, range; |
| 428 | 435 | ||
| 436 | k8_check_syscfg_dram_mod_en(); | ||
| 437 | |||
| 429 | while (fixed_range_blocks[++block].ranges) | 438 | while (fixed_range_blocks[++block].ranges) |
| 430 | for (range=0; range < fixed_range_blocks[block].ranges; range++) | 439 | for (range=0; range < fixed_range_blocks[block].ranges; range++) |
| 431 | set_fixed_range(fixed_range_blocks[block].base_msr + range, | 440 | set_fixed_range(fixed_range_blocks[block].base_msr + range, |
