|
@@ -33,6 +33,32 @@ u64 mtrr_tom2;
|
|
struct mtrr_state_type mtrr_state = {};
|
|
struct mtrr_state_type mtrr_state = {};
|
|
EXPORT_SYMBOL_GPL(mtrr_state);
|
|
EXPORT_SYMBOL_GPL(mtrr_state);
|
|
|
|
|
|
|
|
+/**
|
|
|
|
+ * 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
|
|
|
|
+ * "13.2.1.2 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);
|
|
|
|
+ if (lo & K8_MTRRFIXRANGE_DRAM_MODIFY) {
|
|
|
|
+ printk(KERN_ERR FW_WARN "MTRR: CPU %u: SYSCFG[MtrrFixDramModEn]"
|
|
|
|
+ " not cleared by BIOS, clearing this bit\n",
|
|
|
|
+ smp_processor_id());
|
|
|
|
+ lo &= ~K8_MTRRFIXRANGE_DRAM_MODIFY;
|
|
|
|
+ mtrr_wrmsr(MSR_K8_SYSCFG, lo, hi);
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
/*
|
|
/*
|
|
* Returns the effective MTRR type for the region
|
|
* Returns the effective MTRR type for the region
|
|
* Error returns:
|
|
* Error returns:
|
|
@@ -166,6 +192,8 @@ get_fixed_ranges(mtrr_type * frs)
|
|
unsigned int *p = (unsigned int *) frs;
|
|
unsigned int *p = (unsigned int *) frs;
|
|
int i;
|
|
int i;
|
|
|
|
|
|
|
|
+ k8_check_syscfg_dram_mod_en();
|
|
|
|
+
|
|
rdmsr(MTRRfix64K_00000_MSR, p[0], p[1]);
|
|
rdmsr(MTRRfix64K_00000_MSR, p[0], p[1]);
|
|
|
|
|
|
for (i = 0; i < 2; i++)
|
|
for (i = 0; i < 2; i++)
|
|
@@ -305,28 +333,11 @@ void mtrr_wrmsr(unsigned msr, unsigned a, unsigned b)
|
|
smp_processor_id(), msr, a, b);
|
|
smp_processor_id(), msr, a, b);
|
|
}
|
|
}
|
|
|
|
|
|
-/**
|
|
|
|
- * 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
|
|
|
|
- | K8_MTRRFIXRANGE_DRAM_ENABLE
|
|
|
|
- | K8_MTRRFIXRANGE_DRAM_MODIFY, hi);
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
/**
|
|
/**
|
|
* set_fixed_range - checks & updates a fixed-range MTRR if it differs from the value it should have
|
|
* 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
|
|
* @msr: MSR address of the MTTR which should be checked and updated
|
|
* @changed: pointer which indicates whether the MTRR needed to be changed
|
|
* @changed: pointer which indicates whether the MTRR needed to be changed
|
|
* @msrwords: pointer to the MSR values which the MSR should have
|
|
* @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)
|
|
static void set_fixed_range(int msr, bool *changed, unsigned int *msrwords)
|
|
{
|
|
{
|
|
@@ -335,10 +346,6 @@ static void set_fixed_range(int msr, bool *changed, unsigned int *msrwords)
|
|
rdmsr(msr, lo, hi);
|
|
rdmsr(msr, lo, hi);
|
|
|
|
|
|
if (lo != msrwords[0] || hi != msrwords[1]) {
|
|
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]);
|
|
mtrr_wrmsr(msr, msrwords[0], msrwords[1]);
|
|
*changed = true;
|
|
*changed = true;
|
|
}
|
|
}
|
|
@@ -426,6 +433,8 @@ static int set_fixed_ranges(mtrr_type * frs)
|
|
bool changed = false;
|
|
bool changed = false;
|
|
int block=-1, range;
|
|
int block=-1, range;
|
|
|
|
|
|
|
|
+ k8_check_syscfg_dram_mod_en();
|
|
|
|
+
|
|
while (fixed_range_blocks[++block].ranges)
|
|
while (fixed_range_blocks[++block].ranges)
|
|
for (range=0; range < fixed_range_blocks[block].ranges; range++)
|
|
for (range=0; range < fixed_range_blocks[block].ranges; range++)
|
|
set_fixed_range(fixed_range_blocks[block].base_msr + range,
|
|
set_fixed_range(fixed_range_blocks[block].base_msr + range,
|