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, |