diff options
Diffstat (limited to 'arch/i386/kernel/cpu/mtrr/generic.c')
-rw-r--r-- | arch/i386/kernel/cpu/mtrr/generic.c | 78 |
1 files changed, 66 insertions, 12 deletions
diff --git a/arch/i386/kernel/cpu/mtrr/generic.c b/arch/i386/kernel/cpu/mtrr/generic.c index 0b61eed8bbd8..f77fc53db654 100644 --- a/arch/i386/kernel/cpu/mtrr/generic.c +++ b/arch/i386/kernel/cpu/mtrr/generic.c | |||
@@ -3,6 +3,7 @@ | |||
3 | #include <linux/init.h> | 3 | #include <linux/init.h> |
4 | #include <linux/slab.h> | 4 | #include <linux/slab.h> |
5 | #include <linux/mm.h> | 5 | #include <linux/mm.h> |
6 | #include <linux/module.h> | ||
6 | #include <asm/io.h> | 7 | #include <asm/io.h> |
7 | #include <asm/mtrr.h> | 8 | #include <asm/mtrr.h> |
8 | #include <asm/msr.h> | 9 | #include <asm/msr.h> |
@@ -15,12 +16,19 @@ struct mtrr_state { | |||
15 | struct mtrr_var_range *var_ranges; | 16 | struct mtrr_var_range *var_ranges; |
16 | mtrr_type fixed_ranges[NUM_FIXED_RANGES]; | 17 | mtrr_type fixed_ranges[NUM_FIXED_RANGES]; |
17 | unsigned char enabled; | 18 | unsigned char enabled; |
19 | unsigned char have_fixed; | ||
18 | mtrr_type def_type; | 20 | mtrr_type def_type; |
19 | }; | 21 | }; |
20 | 22 | ||
21 | static unsigned long smp_changes_mask; | 23 | static unsigned long smp_changes_mask; |
22 | static struct mtrr_state mtrr_state = {}; | 24 | static struct mtrr_state mtrr_state = {}; |
23 | 25 | ||
26 | #undef MODULE_PARAM_PREFIX | ||
27 | #define MODULE_PARAM_PREFIX "mtrr." | ||
28 | |||
29 | static __initdata int mtrr_show; | ||
30 | module_param_named(show, mtrr_show, bool, 0); | ||
31 | |||
24 | /* Get the MSR pair relating to a var range */ | 32 | /* Get the MSR pair relating to a var range */ |
25 | static void __init | 33 | static void __init |
26 | get_mtrr_var_range(unsigned int index, struct mtrr_var_range *vr) | 34 | get_mtrr_var_range(unsigned int index, struct mtrr_var_range *vr) |
@@ -43,6 +51,14 @@ get_fixed_ranges(mtrr_type * frs) | |||
43 | rdmsr(MTRRfix4K_C0000_MSR + i, p[6 + i * 2], p[7 + i * 2]); | 51 | rdmsr(MTRRfix4K_C0000_MSR + i, p[6 + i * 2], p[7 + i * 2]); |
44 | } | 52 | } |
45 | 53 | ||
54 | static void __init print_fixed(unsigned base, unsigned step, const mtrr_type*types) | ||
55 | { | ||
56 | unsigned i; | ||
57 | |||
58 | for (i = 0; i < 8; ++i, ++types, base += step) | ||
59 | printk(KERN_INFO "MTRR %05X-%05X %s\n", base, base + step - 1, mtrr_attrib_to_str(*types)); | ||
60 | } | ||
61 | |||
46 | /* Grab all of the MTRR state for this CPU into *state */ | 62 | /* Grab all of the MTRR state for this CPU into *state */ |
47 | void __init get_mtrr_state(void) | 63 | void __init get_mtrr_state(void) |
48 | { | 64 | { |
@@ -58,13 +74,49 @@ void __init get_mtrr_state(void) | |||
58 | } | 74 | } |
59 | vrs = mtrr_state.var_ranges; | 75 | vrs = mtrr_state.var_ranges; |
60 | 76 | ||
77 | rdmsr(MTRRcap_MSR, lo, dummy); | ||
78 | mtrr_state.have_fixed = (lo >> 8) & 1; | ||
79 | |||
61 | for (i = 0; i < num_var_ranges; i++) | 80 | for (i = 0; i < num_var_ranges; i++) |
62 | get_mtrr_var_range(i, &vrs[i]); | 81 | get_mtrr_var_range(i, &vrs[i]); |
63 | get_fixed_ranges(mtrr_state.fixed_ranges); | 82 | if (mtrr_state.have_fixed) |
83 | get_fixed_ranges(mtrr_state.fixed_ranges); | ||
64 | 84 | ||
65 | rdmsr(MTRRdefType_MSR, lo, dummy); | 85 | rdmsr(MTRRdefType_MSR, lo, dummy); |
66 | mtrr_state.def_type = (lo & 0xff); | 86 | mtrr_state.def_type = (lo & 0xff); |
67 | mtrr_state.enabled = (lo & 0xc00) >> 10; | 87 | mtrr_state.enabled = (lo & 0xc00) >> 10; |
88 | |||
89 | if (mtrr_show) { | ||
90 | int high_width; | ||
91 | |||
92 | printk(KERN_INFO "MTRR default type: %s\n", mtrr_attrib_to_str(mtrr_state.def_type)); | ||
93 | if (mtrr_state.have_fixed) { | ||
94 | printk(KERN_INFO "MTRR fixed ranges %sabled:\n", | ||
95 | mtrr_state.enabled & 1 ? "en" : "dis"); | ||
96 | print_fixed(0x00000, 0x10000, mtrr_state.fixed_ranges + 0); | ||
97 | for (i = 0; i < 2; ++i) | ||
98 | print_fixed(0x80000 + i * 0x20000, 0x04000, mtrr_state.fixed_ranges + (i + 1) * 8); | ||
99 | for (i = 0; i < 8; ++i) | ||
100 | print_fixed(0xC0000 + i * 0x08000, 0x01000, mtrr_state.fixed_ranges + (i + 3) * 8); | ||
101 | } | ||
102 | printk(KERN_INFO "MTRR variable ranges %sabled:\n", | ||
103 | mtrr_state.enabled & 2 ? "en" : "dis"); | ||
104 | high_width = ((size_or_mask ? ffs(size_or_mask) - 1 : 32) - (32 - PAGE_SHIFT) + 3) / 4; | ||
105 | for (i = 0; i < num_var_ranges; ++i) { | ||
106 | if (mtrr_state.var_ranges[i].mask_lo & (1 << 11)) | ||
107 | printk(KERN_INFO "MTRR %u base %0*X%05X000 mask %0*X%05X000 %s\n", | ||
108 | i, | ||
109 | high_width, | ||
110 | mtrr_state.var_ranges[i].base_hi, | ||
111 | mtrr_state.var_ranges[i].base_lo >> 12, | ||
112 | high_width, | ||
113 | mtrr_state.var_ranges[i].mask_hi, | ||
114 | mtrr_state.var_ranges[i].mask_lo >> 12, | ||
115 | mtrr_attrib_to_str(mtrr_state.var_ranges[i].base_lo & 0xff)); | ||
116 | else | ||
117 | printk(KERN_INFO "MTRR %u disabled\n", i); | ||
118 | } | ||
119 | } | ||
68 | } | 120 | } |
69 | 121 | ||
70 | /* Some BIOS's are fucked and don't set all MTRRs the same! */ | 122 | /* Some BIOS's are fucked and don't set all MTRRs the same! */ |
@@ -95,7 +147,7 @@ void mtrr_wrmsr(unsigned msr, unsigned a, unsigned b) | |||
95 | smp_processor_id(), msr, a, b); | 147 | smp_processor_id(), msr, a, b); |
96 | } | 148 | } |
97 | 149 | ||
98 | int generic_get_free_region(unsigned long base, unsigned long size) | 150 | int generic_get_free_region(unsigned long base, unsigned long size, int replace_reg) |
99 | /* [SUMMARY] Get a free MTRR. | 151 | /* [SUMMARY] Get a free MTRR. |
100 | <base> The starting (base) address of the region. | 152 | <base> The starting (base) address of the region. |
101 | <size> The size (in bytes) of the region. | 153 | <size> The size (in bytes) of the region. |
@@ -104,10 +156,11 @@ int generic_get_free_region(unsigned long base, unsigned long size) | |||
104 | { | 156 | { |
105 | int i, max; | 157 | int i, max; |
106 | mtrr_type ltype; | 158 | mtrr_type ltype; |
107 | unsigned long lbase; | 159 | unsigned long lbase, lsize; |
108 | unsigned lsize; | ||
109 | 160 | ||
110 | max = num_var_ranges; | 161 | max = num_var_ranges; |
162 | if (replace_reg >= 0 && replace_reg < max) | ||
163 | return replace_reg; | ||
111 | for (i = 0; i < max; ++i) { | 164 | for (i = 0; i < max; ++i) { |
112 | mtrr_if->get(i, &lbase, &lsize, <ype); | 165 | mtrr_if->get(i, &lbase, &lsize, <ype); |
113 | if (lsize == 0) | 166 | if (lsize == 0) |
@@ -117,7 +170,7 @@ int generic_get_free_region(unsigned long base, unsigned long size) | |||
117 | } | 170 | } |
118 | 171 | ||
119 | static void generic_get_mtrr(unsigned int reg, unsigned long *base, | 172 | static void generic_get_mtrr(unsigned int reg, unsigned long *base, |
120 | unsigned int *size, mtrr_type * type) | 173 | unsigned long *size, mtrr_type *type) |
121 | { | 174 | { |
122 | unsigned int mask_lo, mask_hi, base_lo, base_hi; | 175 | unsigned int mask_lo, mask_hi, base_lo, base_hi; |
123 | 176 | ||
@@ -202,7 +255,9 @@ static int set_mtrr_var_ranges(unsigned int index, struct mtrr_var_range *vr) | |||
202 | return changed; | 255 | return changed; |
203 | } | 256 | } |
204 | 257 | ||
205 | static unsigned long set_mtrr_state(u32 deftype_lo, u32 deftype_hi) | 258 | static u32 deftype_lo, deftype_hi; |
259 | |||
260 | static unsigned long set_mtrr_state(void) | ||
206 | /* [SUMMARY] Set the MTRR state for this CPU. | 261 | /* [SUMMARY] Set the MTRR state for this CPU. |
207 | <state> The MTRR state information to read. | 262 | <state> The MTRR state information to read. |
208 | <ctxt> Some relevant CPU context. | 263 | <ctxt> Some relevant CPU context. |
@@ -217,14 +272,14 @@ static unsigned long set_mtrr_state(u32 deftype_lo, u32 deftype_hi) | |||
217 | if (set_mtrr_var_ranges(i, &mtrr_state.var_ranges[i])) | 272 | if (set_mtrr_var_ranges(i, &mtrr_state.var_ranges[i])) |
218 | change_mask |= MTRR_CHANGE_MASK_VARIABLE; | 273 | change_mask |= MTRR_CHANGE_MASK_VARIABLE; |
219 | 274 | ||
220 | if (set_fixed_ranges(mtrr_state.fixed_ranges)) | 275 | if (mtrr_state.have_fixed && set_fixed_ranges(mtrr_state.fixed_ranges)) |
221 | change_mask |= MTRR_CHANGE_MASK_FIXED; | 276 | change_mask |= MTRR_CHANGE_MASK_FIXED; |
222 | 277 | ||
223 | /* Set_mtrr_restore restores the old value of MTRRdefType, | 278 | /* Set_mtrr_restore restores the old value of MTRRdefType, |
224 | so to set it we fiddle with the saved value */ | 279 | so to set it we fiddle with the saved value */ |
225 | if ((deftype_lo & 0xff) != mtrr_state.def_type | 280 | if ((deftype_lo & 0xff) != mtrr_state.def_type |
226 | || ((deftype_lo & 0xc00) >> 10) != mtrr_state.enabled) { | 281 | || ((deftype_lo & 0xc00) >> 10) != mtrr_state.enabled) { |
227 | deftype_lo |= (mtrr_state.def_type | mtrr_state.enabled << 10); | 282 | deftype_lo = (deftype_lo & ~0xcff) | mtrr_state.def_type | (mtrr_state.enabled << 10); |
228 | change_mask |= MTRR_CHANGE_MASK_DEFTYPE; | 283 | change_mask |= MTRR_CHANGE_MASK_DEFTYPE; |
229 | } | 284 | } |
230 | 285 | ||
@@ -233,7 +288,6 @@ static unsigned long set_mtrr_state(u32 deftype_lo, u32 deftype_hi) | |||
233 | 288 | ||
234 | 289 | ||
235 | static unsigned long cr4 = 0; | 290 | static unsigned long cr4 = 0; |
236 | static u32 deftype_lo, deftype_hi; | ||
237 | static DEFINE_SPINLOCK(set_atomicity_lock); | 291 | static DEFINE_SPINLOCK(set_atomicity_lock); |
238 | 292 | ||
239 | /* | 293 | /* |
@@ -271,7 +325,7 @@ static void prepare_set(void) __acquires(set_atomicity_lock) | |||
271 | rdmsr(MTRRdefType_MSR, deftype_lo, deftype_hi); | 325 | rdmsr(MTRRdefType_MSR, deftype_lo, deftype_hi); |
272 | 326 | ||
273 | /* Disable MTRRs, and set the default type to uncached */ | 327 | /* Disable MTRRs, and set the default type to uncached */ |
274 | mtrr_wrmsr(MTRRdefType_MSR, deftype_lo & 0xf300UL, deftype_hi); | 328 | mtrr_wrmsr(MTRRdefType_MSR, deftype_lo & ~0xcff, deftype_hi); |
275 | } | 329 | } |
276 | 330 | ||
277 | static void post_set(void) __releases(set_atomicity_lock) | 331 | static void post_set(void) __releases(set_atomicity_lock) |
@@ -300,7 +354,7 @@ static void generic_set_all(void) | |||
300 | prepare_set(); | 354 | prepare_set(); |
301 | 355 | ||
302 | /* Actually set the state */ | 356 | /* Actually set the state */ |
303 | mask = set_mtrr_state(deftype_lo,deftype_hi); | 357 | mask = set_mtrr_state(); |
304 | 358 | ||
305 | post_set(); | 359 | post_set(); |
306 | local_irq_restore(flags); | 360 | local_irq_restore(flags); |
@@ -366,7 +420,7 @@ int generic_validate_add_page(unsigned long base, unsigned long size, unsigned i | |||
366 | printk(KERN_WARNING "mtrr: base(0x%lx000) is not 4 MiB aligned\n", base); | 420 | printk(KERN_WARNING "mtrr: base(0x%lx000) is not 4 MiB aligned\n", base); |
367 | return -EINVAL; | 421 | return -EINVAL; |
368 | } | 422 | } |
369 | if (!(base + size < 0x70000000 || base > 0x7003FFFF) && | 423 | if (!(base + size < 0x70000 || base > 0x7003F) && |
370 | (type == MTRR_TYPE_WRCOMB | 424 | (type == MTRR_TYPE_WRCOMB |
371 | || type == MTRR_TYPE_WRBACK)) { | 425 | || type == MTRR_TYPE_WRBACK)) { |
372 | printk(KERN_WARNING "mtrr: writable mtrr between 0x70000000 and 0x7003FFFF may hang the CPU.\n"); | 426 | printk(KERN_WARNING "mtrr: writable mtrr between 0x70000000 and 0x7003FFFF may hang the CPU.\n"); |