diff options
author | Paul Mackerras <paulus@samba.org> | 2008-01-30 19:25:51 -0500 |
---|---|---|
committer | Paul Mackerras <paulus@samba.org> | 2008-01-30 19:25:51 -0500 |
commit | bd45ac0c5daae35e7c71138172e63df5cf644cf6 (patch) | |
tree | 5eb5a599bf6a9d7a8a34e802db932aa9e9555de4 /arch/x86/kernel/cpu/mtrr | |
parent | 4eece4ccf997c0e6d8fdad3d842e37b16b8d705f (diff) | |
parent | 5bdeae46be6dfe9efa44a548bd622af325f4bdb4 (diff) |
Merge branch 'linux-2.6'
Diffstat (limited to 'arch/x86/kernel/cpu/mtrr')
-rw-r--r-- | arch/x86/kernel/cpu/mtrr/amd.c | 2 | ||||
-rw-r--r-- | arch/x86/kernel/cpu/mtrr/cyrix.c | 3 | ||||
-rw-r--r-- | arch/x86/kernel/cpu/mtrr/generic.c | 27 | ||||
-rw-r--r-- | arch/x86/kernel/cpu/mtrr/if.c | 23 | ||||
-rw-r--r-- | arch/x86/kernel/cpu/mtrr/main.c | 155 | ||||
-rw-r--r-- | arch/x86/kernel/cpu/mtrr/mtrr.h | 9 | ||||
-rw-r--r-- | arch/x86/kernel/cpu/mtrr/state.c | 3 |
7 files changed, 155 insertions, 67 deletions
diff --git a/arch/x86/kernel/cpu/mtrr/amd.c b/arch/x86/kernel/cpu/mtrr/amd.c index 0949cdbf848a..ee2331b0e58f 100644 --- a/arch/x86/kernel/cpu/mtrr/amd.c +++ b/arch/x86/kernel/cpu/mtrr/amd.c | |||
@@ -53,8 +53,6 @@ static void amd_set_mtrr(unsigned int reg, unsigned long base, | |||
53 | <base> The base address of the region. | 53 | <base> The base address of the region. |
54 | <size> The size of the region. If this is 0 the region is disabled. | 54 | <size> The size of the region. If this is 0 the region is disabled. |
55 | <type> The type of the region. | 55 | <type> The type of the region. |
56 | <do_safe> If TRUE, do the change safely. If FALSE, safety measures should | ||
57 | be done externally. | ||
58 | [RETURNS] Nothing. | 56 | [RETURNS] Nothing. |
59 | */ | 57 | */ |
60 | { | 58 | { |
diff --git a/arch/x86/kernel/cpu/mtrr/cyrix.c b/arch/x86/kernel/cpu/mtrr/cyrix.c index 9964be3de2b7..8e139c70f888 100644 --- a/arch/x86/kernel/cpu/mtrr/cyrix.c +++ b/arch/x86/kernel/cpu/mtrr/cyrix.c | |||
@@ -4,6 +4,7 @@ | |||
4 | #include <asm/msr.h> | 4 | #include <asm/msr.h> |
5 | #include <asm/io.h> | 5 | #include <asm/io.h> |
6 | #include <asm/processor-cyrix.h> | 6 | #include <asm/processor-cyrix.h> |
7 | #include <asm/processor-flags.h> | ||
7 | #include "mtrr.h" | 8 | #include "mtrr.h" |
8 | 9 | ||
9 | int arr3_protected; | 10 | int arr3_protected; |
@@ -142,7 +143,7 @@ static void prepare_set(void) | |||
142 | 143 | ||
143 | /* Disable and flush caches. Note that wbinvd flushes the TLBs as | 144 | /* Disable and flush caches. Note that wbinvd flushes the TLBs as |
144 | a side-effect */ | 145 | a side-effect */ |
145 | cr0 = read_cr0() | 0x40000000; | 146 | cr0 = read_cr0() | X86_CR0_CD; |
146 | wbinvd(); | 147 | wbinvd(); |
147 | write_cr0(cr0); | 148 | write_cr0(cr0); |
148 | wbinvd(); | 149 | wbinvd(); |
diff --git a/arch/x86/kernel/cpu/mtrr/generic.c b/arch/x86/kernel/cpu/mtrr/generic.c index 992f08dfbb6c..103d61a59b19 100644 --- a/arch/x86/kernel/cpu/mtrr/generic.c +++ b/arch/x86/kernel/cpu/mtrr/generic.c | |||
@@ -9,11 +9,12 @@ | |||
9 | #include <asm/msr.h> | 9 | #include <asm/msr.h> |
10 | #include <asm/system.h> | 10 | #include <asm/system.h> |
11 | #include <asm/cpufeature.h> | 11 | #include <asm/cpufeature.h> |
12 | #include <asm/processor-flags.h> | ||
12 | #include <asm/tlbflush.h> | 13 | #include <asm/tlbflush.h> |
13 | #include "mtrr.h" | 14 | #include "mtrr.h" |
14 | 15 | ||
15 | struct mtrr_state { | 16 | struct mtrr_state { |
16 | struct mtrr_var_range *var_ranges; | 17 | struct mtrr_var_range var_ranges[MAX_VAR_RANGES]; |
17 | mtrr_type fixed_ranges[NUM_FIXED_RANGES]; | 18 | mtrr_type fixed_ranges[NUM_FIXED_RANGES]; |
18 | unsigned char enabled; | 19 | unsigned char enabled; |
19 | unsigned char have_fixed; | 20 | unsigned char have_fixed; |
@@ -85,12 +86,6 @@ void __init get_mtrr_state(void) | |||
85 | struct mtrr_var_range *vrs; | 86 | struct mtrr_var_range *vrs; |
86 | unsigned lo, dummy; | 87 | unsigned lo, dummy; |
87 | 88 | ||
88 | if (!mtrr_state.var_ranges) { | ||
89 | mtrr_state.var_ranges = kmalloc(num_var_ranges * sizeof (struct mtrr_var_range), | ||
90 | GFP_KERNEL); | ||
91 | if (!mtrr_state.var_ranges) | ||
92 | return; | ||
93 | } | ||
94 | vrs = mtrr_state.var_ranges; | 89 | vrs = mtrr_state.var_ranges; |
95 | 90 | ||
96 | rdmsr(MTRRcap_MSR, lo, dummy); | 91 | rdmsr(MTRRcap_MSR, lo, dummy); |
@@ -188,7 +183,7 @@ static inline void k8_enable_fixed_iorrs(void) | |||
188 | * \param changed pointer which indicates whether the MTRR needed to be changed | 183 | * \param changed pointer which indicates whether the MTRR needed to be changed |
189 | * \param msrwords pointer to the MSR values which the MSR should have | 184 | * \param msrwords pointer to the MSR values which the MSR should have |
190 | */ | 185 | */ |
191 | static void set_fixed_range(int msr, int * changed, unsigned int * msrwords) | 186 | static void set_fixed_range(int msr, bool *changed, unsigned int *msrwords) |
192 | { | 187 | { |
193 | unsigned lo, hi; | 188 | unsigned lo, hi; |
194 | 189 | ||
@@ -200,7 +195,7 @@ static void set_fixed_range(int msr, int * changed, unsigned int * msrwords) | |||
200 | ((msrwords[0] | msrwords[1]) & K8_MTRR_RDMEM_WRMEM_MASK)) | 195 | ((msrwords[0] | msrwords[1]) & K8_MTRR_RDMEM_WRMEM_MASK)) |
201 | k8_enable_fixed_iorrs(); | 196 | k8_enable_fixed_iorrs(); |
202 | mtrr_wrmsr(msr, msrwords[0], msrwords[1]); | 197 | mtrr_wrmsr(msr, msrwords[0], msrwords[1]); |
203 | *changed = TRUE; | 198 | *changed = true; |
204 | } | 199 | } |
205 | } | 200 | } |
206 | 201 | ||
@@ -260,7 +255,7 @@ static void generic_get_mtrr(unsigned int reg, unsigned long *base, | |||
260 | static int set_fixed_ranges(mtrr_type * frs) | 255 | static int set_fixed_ranges(mtrr_type * frs) |
261 | { | 256 | { |
262 | unsigned long long *saved = (unsigned long long *) frs; | 257 | unsigned long long *saved = (unsigned long long *) frs; |
263 | int changed = FALSE; | 258 | bool changed = false; |
264 | int block=-1, range; | 259 | int block=-1, range; |
265 | 260 | ||
266 | while (fixed_range_blocks[++block].ranges) | 261 | while (fixed_range_blocks[++block].ranges) |
@@ -273,17 +268,17 @@ static int set_fixed_ranges(mtrr_type * frs) | |||
273 | 268 | ||
274 | /* Set the MSR pair relating to a var range. Returns TRUE if | 269 | /* Set the MSR pair relating to a var range. Returns TRUE if |
275 | changes are made */ | 270 | changes are made */ |
276 | static int set_mtrr_var_ranges(unsigned int index, struct mtrr_var_range *vr) | 271 | static bool set_mtrr_var_ranges(unsigned int index, struct mtrr_var_range *vr) |
277 | { | 272 | { |
278 | unsigned int lo, hi; | 273 | unsigned int lo, hi; |
279 | int changed = FALSE; | 274 | bool changed = false; |
280 | 275 | ||
281 | rdmsr(MTRRphysBase_MSR(index), lo, hi); | 276 | rdmsr(MTRRphysBase_MSR(index), lo, hi); |
282 | if ((vr->base_lo & 0xfffff0ffUL) != (lo & 0xfffff0ffUL) | 277 | if ((vr->base_lo & 0xfffff0ffUL) != (lo & 0xfffff0ffUL) |
283 | || (vr->base_hi & (size_and_mask >> (32 - PAGE_SHIFT))) != | 278 | || (vr->base_hi & (size_and_mask >> (32 - PAGE_SHIFT))) != |
284 | (hi & (size_and_mask >> (32 - PAGE_SHIFT)))) { | 279 | (hi & (size_and_mask >> (32 - PAGE_SHIFT)))) { |
285 | mtrr_wrmsr(MTRRphysBase_MSR(index), vr->base_lo, vr->base_hi); | 280 | mtrr_wrmsr(MTRRphysBase_MSR(index), vr->base_lo, vr->base_hi); |
286 | changed = TRUE; | 281 | changed = true; |
287 | } | 282 | } |
288 | 283 | ||
289 | rdmsr(MTRRphysMask_MSR(index), lo, hi); | 284 | rdmsr(MTRRphysMask_MSR(index), lo, hi); |
@@ -292,7 +287,7 @@ static int set_mtrr_var_ranges(unsigned int index, struct mtrr_var_range *vr) | |||
292 | || (vr->mask_hi & (size_and_mask >> (32 - PAGE_SHIFT))) != | 287 | || (vr->mask_hi & (size_and_mask >> (32 - PAGE_SHIFT))) != |
293 | (hi & (size_and_mask >> (32 - PAGE_SHIFT)))) { | 288 | (hi & (size_and_mask >> (32 - PAGE_SHIFT)))) { |
294 | mtrr_wrmsr(MTRRphysMask_MSR(index), vr->mask_lo, vr->mask_hi); | 289 | mtrr_wrmsr(MTRRphysMask_MSR(index), vr->mask_lo, vr->mask_hi); |
295 | changed = TRUE; | 290 | changed = true; |
296 | } | 291 | } |
297 | return changed; | 292 | return changed; |
298 | } | 293 | } |
@@ -350,7 +345,7 @@ static void prepare_set(void) __acquires(set_atomicity_lock) | |||
350 | spin_lock(&set_atomicity_lock); | 345 | spin_lock(&set_atomicity_lock); |
351 | 346 | ||
352 | /* Enter the no-fill (CD=1, NW=0) cache mode and flush caches. */ | 347 | /* Enter the no-fill (CD=1, NW=0) cache mode and flush caches. */ |
353 | cr0 = read_cr0() | 0x40000000; /* set CD flag */ | 348 | cr0 = read_cr0() | X86_CR0_CD; |
354 | write_cr0(cr0); | 349 | write_cr0(cr0); |
355 | wbinvd(); | 350 | wbinvd(); |
356 | 351 | ||
@@ -417,8 +412,6 @@ static void generic_set_mtrr(unsigned int reg, unsigned long base, | |||
417 | <base> The base address of the region. | 412 | <base> The base address of the region. |
418 | <size> The size of the region. If this is 0 the region is disabled. | 413 | <size> The size of the region. If this is 0 the region is disabled. |
419 | <type> The type of the region. | 414 | <type> The type of the region. |
420 | <do_safe> If TRUE, do the change safely. If FALSE, safety measures should | ||
421 | be done externally. | ||
422 | [RETURNS] Nothing. | 415 | [RETURNS] Nothing. |
423 | */ | 416 | */ |
424 | { | 417 | { |
diff --git a/arch/x86/kernel/cpu/mtrr/if.c b/arch/x86/kernel/cpu/mtrr/if.c index c7d8f1756745..91e150acb46c 100644 --- a/arch/x86/kernel/cpu/mtrr/if.c +++ b/arch/x86/kernel/cpu/mtrr/if.c | |||
@@ -11,10 +11,6 @@ | |||
11 | #include <asm/mtrr.h> | 11 | #include <asm/mtrr.h> |
12 | #include "mtrr.h" | 12 | #include "mtrr.h" |
13 | 13 | ||
14 | /* RED-PEN: this is accessed without any locking */ | ||
15 | extern unsigned int *usage_table; | ||
16 | |||
17 | |||
18 | #define FILE_FCOUNT(f) (((struct seq_file *)((f)->private_data))->private) | 14 | #define FILE_FCOUNT(f) (((struct seq_file *)((f)->private_data))->private) |
19 | 15 | ||
20 | static const char *const mtrr_strings[MTRR_NUM_TYPES] = | 16 | static const char *const mtrr_strings[MTRR_NUM_TYPES] = |
@@ -37,7 +33,7 @@ const char *mtrr_attrib_to_str(int x) | |||
37 | 33 | ||
38 | static int | 34 | static int |
39 | mtrr_file_add(unsigned long base, unsigned long size, | 35 | mtrr_file_add(unsigned long base, unsigned long size, |
40 | unsigned int type, char increment, struct file *file, int page) | 36 | unsigned int type, bool increment, struct file *file, int page) |
41 | { | 37 | { |
42 | int reg, max; | 38 | int reg, max; |
43 | unsigned int *fcount = FILE_FCOUNT(file); | 39 | unsigned int *fcount = FILE_FCOUNT(file); |
@@ -55,7 +51,7 @@ mtrr_file_add(unsigned long base, unsigned long size, | |||
55 | base >>= PAGE_SHIFT; | 51 | base >>= PAGE_SHIFT; |
56 | size >>= PAGE_SHIFT; | 52 | size >>= PAGE_SHIFT; |
57 | } | 53 | } |
58 | reg = mtrr_add_page(base, size, type, 1); | 54 | reg = mtrr_add_page(base, size, type, true); |
59 | if (reg >= 0) | 55 | if (reg >= 0) |
60 | ++fcount[reg]; | 56 | ++fcount[reg]; |
61 | return reg; | 57 | return reg; |
@@ -141,7 +137,7 @@ mtrr_write(struct file *file, const char __user *buf, size_t len, loff_t * ppos) | |||
141 | size >>= PAGE_SHIFT; | 137 | size >>= PAGE_SHIFT; |
142 | err = | 138 | err = |
143 | mtrr_add_page((unsigned long) base, (unsigned long) size, i, | 139 | mtrr_add_page((unsigned long) base, (unsigned long) size, i, |
144 | 1); | 140 | true); |
145 | if (err < 0) | 141 | if (err < 0) |
146 | return err; | 142 | return err; |
147 | return len; | 143 | return len; |
@@ -217,7 +213,7 @@ mtrr_ioctl(struct file *file, unsigned int cmd, unsigned long __arg) | |||
217 | if (!capable(CAP_SYS_ADMIN)) | 213 | if (!capable(CAP_SYS_ADMIN)) |
218 | return -EPERM; | 214 | return -EPERM; |
219 | err = | 215 | err = |
220 | mtrr_file_add(sentry.base, sentry.size, sentry.type, 1, | 216 | mtrr_file_add(sentry.base, sentry.size, sentry.type, true, |
221 | file, 0); | 217 | file, 0); |
222 | break; | 218 | break; |
223 | case MTRRIOC_SET_ENTRY: | 219 | case MTRRIOC_SET_ENTRY: |
@@ -226,7 +222,7 @@ mtrr_ioctl(struct file *file, unsigned int cmd, unsigned long __arg) | |||
226 | #endif | 222 | #endif |
227 | if (!capable(CAP_SYS_ADMIN)) | 223 | if (!capable(CAP_SYS_ADMIN)) |
228 | return -EPERM; | 224 | return -EPERM; |
229 | err = mtrr_add(sentry.base, sentry.size, sentry.type, 0); | 225 | err = mtrr_add(sentry.base, sentry.size, sentry.type, false); |
230 | break; | 226 | break; |
231 | case MTRRIOC_DEL_ENTRY: | 227 | case MTRRIOC_DEL_ENTRY: |
232 | #ifdef CONFIG_COMPAT | 228 | #ifdef CONFIG_COMPAT |
@@ -270,7 +266,7 @@ mtrr_ioctl(struct file *file, unsigned int cmd, unsigned long __arg) | |||
270 | if (!capable(CAP_SYS_ADMIN)) | 266 | if (!capable(CAP_SYS_ADMIN)) |
271 | return -EPERM; | 267 | return -EPERM; |
272 | err = | 268 | err = |
273 | mtrr_file_add(sentry.base, sentry.size, sentry.type, 1, | 269 | mtrr_file_add(sentry.base, sentry.size, sentry.type, true, |
274 | file, 1); | 270 | file, 1); |
275 | break; | 271 | break; |
276 | case MTRRIOC_SET_PAGE_ENTRY: | 272 | case MTRRIOC_SET_PAGE_ENTRY: |
@@ -279,7 +275,8 @@ mtrr_ioctl(struct file *file, unsigned int cmd, unsigned long __arg) | |||
279 | #endif | 275 | #endif |
280 | if (!capable(CAP_SYS_ADMIN)) | 276 | if (!capable(CAP_SYS_ADMIN)) |
281 | return -EPERM; | 277 | return -EPERM; |
282 | err = mtrr_add_page(sentry.base, sentry.size, sentry.type, 0); | 278 | err = |
279 | mtrr_add_page(sentry.base, sentry.size, sentry.type, false); | ||
283 | break; | 280 | break; |
284 | case MTRRIOC_DEL_PAGE_ENTRY: | 281 | case MTRRIOC_DEL_PAGE_ENTRY: |
285 | #ifdef CONFIG_COMPAT | 282 | #ifdef CONFIG_COMPAT |
@@ -396,7 +393,7 @@ static int mtrr_seq_show(struct seq_file *seq, void *offset) | |||
396 | for (i = 0; i < max; i++) { | 393 | for (i = 0; i < max; i++) { |
397 | mtrr_if->get(i, &base, &size, &type); | 394 | mtrr_if->get(i, &base, &size, &type); |
398 | if (size == 0) | 395 | if (size == 0) |
399 | usage_table[i] = 0; | 396 | mtrr_usage_table[i] = 0; |
400 | else { | 397 | else { |
401 | if (size < (0x100000 >> PAGE_SHIFT)) { | 398 | if (size < (0x100000 >> PAGE_SHIFT)) { |
402 | /* less than 1MB */ | 399 | /* less than 1MB */ |
@@ -410,7 +407,7 @@ static int mtrr_seq_show(struct seq_file *seq, void *offset) | |||
410 | len += seq_printf(seq, | 407 | len += seq_printf(seq, |
411 | "reg%02i: base=0x%05lx000 (%4luMB), size=%4lu%cB: %s, count=%d\n", | 408 | "reg%02i: base=0x%05lx000 (%4luMB), size=%4lu%cB: %s, count=%d\n", |
412 | i, base, base >> (20 - PAGE_SHIFT), size, factor, | 409 | i, base, base >> (20 - PAGE_SHIFT), size, factor, |
413 | mtrr_attrib_to_str(type), usage_table[i]); | 410 | mtrr_attrib_to_str(type), mtrr_usage_table[i]); |
414 | } | 411 | } |
415 | } | 412 | } |
416 | return 0; | 413 | return 0; |
diff --git a/arch/x86/kernel/cpu/mtrr/main.c b/arch/x86/kernel/cpu/mtrr/main.c index 3b20613325dc..715919582657 100644 --- a/arch/x86/kernel/cpu/mtrr/main.c +++ b/arch/x86/kernel/cpu/mtrr/main.c | |||
@@ -38,8 +38,8 @@ | |||
38 | #include <linux/cpu.h> | 38 | #include <linux/cpu.h> |
39 | #include <linux/mutex.h> | 39 | #include <linux/mutex.h> |
40 | 40 | ||
41 | #include <asm/e820.h> | ||
41 | #include <asm/mtrr.h> | 42 | #include <asm/mtrr.h> |
42 | |||
43 | #include <asm/uaccess.h> | 43 | #include <asm/uaccess.h> |
44 | #include <asm/processor.h> | 44 | #include <asm/processor.h> |
45 | #include <asm/msr.h> | 45 | #include <asm/msr.h> |
@@ -47,7 +47,7 @@ | |||
47 | 47 | ||
48 | u32 num_var_ranges = 0; | 48 | u32 num_var_ranges = 0; |
49 | 49 | ||
50 | unsigned int *usage_table; | 50 | unsigned int mtrr_usage_table[MAX_VAR_RANGES]; |
51 | static DEFINE_MUTEX(mtrr_mutex); | 51 | static DEFINE_MUTEX(mtrr_mutex); |
52 | 52 | ||
53 | u64 size_or_mask, size_and_mask; | 53 | u64 size_or_mask, size_and_mask; |
@@ -121,13 +121,8 @@ static void __init init_table(void) | |||
121 | int i, max; | 121 | int i, max; |
122 | 122 | ||
123 | max = num_var_ranges; | 123 | max = num_var_ranges; |
124 | if ((usage_table = kmalloc(max * sizeof *usage_table, GFP_KERNEL)) | ||
125 | == NULL) { | ||
126 | printk(KERN_ERR "mtrr: could not allocate\n"); | ||
127 | return; | ||
128 | } | ||
129 | for (i = 0; i < max; i++) | 124 | for (i = 0; i < max; i++) |
130 | usage_table[i] = 1; | 125 | mtrr_usage_table[i] = 1; |
131 | } | 126 | } |
132 | 127 | ||
133 | struct set_mtrr_data { | 128 | struct set_mtrr_data { |
@@ -311,7 +306,7 @@ static void set_mtrr(unsigned int reg, unsigned long base, | |||
311 | */ | 306 | */ |
312 | 307 | ||
313 | int mtrr_add_page(unsigned long base, unsigned long size, | 308 | int mtrr_add_page(unsigned long base, unsigned long size, |
314 | unsigned int type, char increment) | 309 | unsigned int type, bool increment) |
315 | { | 310 | { |
316 | int i, replace, error; | 311 | int i, replace, error; |
317 | mtrr_type ltype; | 312 | mtrr_type ltype; |
@@ -349,7 +344,7 @@ int mtrr_add_page(unsigned long base, unsigned long size, | |||
349 | replace = -1; | 344 | replace = -1; |
350 | 345 | ||
351 | /* No CPU hotplug when we change MTRR entries */ | 346 | /* No CPU hotplug when we change MTRR entries */ |
352 | lock_cpu_hotplug(); | 347 | get_online_cpus(); |
353 | /* Search for existing MTRR */ | 348 | /* Search for existing MTRR */ |
354 | mutex_lock(&mtrr_mutex); | 349 | mutex_lock(&mtrr_mutex); |
355 | for (i = 0; i < num_var_ranges; ++i) { | 350 | for (i = 0; i < num_var_ranges; ++i) { |
@@ -383,7 +378,7 @@ int mtrr_add_page(unsigned long base, unsigned long size, | |||
383 | goto out; | 378 | goto out; |
384 | } | 379 | } |
385 | if (increment) | 380 | if (increment) |
386 | ++usage_table[i]; | 381 | ++mtrr_usage_table[i]; |
387 | error = i; | 382 | error = i; |
388 | goto out; | 383 | goto out; |
389 | } | 384 | } |
@@ -391,13 +386,15 @@ int mtrr_add_page(unsigned long base, unsigned long size, | |||
391 | i = mtrr_if->get_free_region(base, size, replace); | 386 | i = mtrr_if->get_free_region(base, size, replace); |
392 | if (i >= 0) { | 387 | if (i >= 0) { |
393 | set_mtrr(i, base, size, type); | 388 | set_mtrr(i, base, size, type); |
394 | if (likely(replace < 0)) | 389 | if (likely(replace < 0)) { |
395 | usage_table[i] = 1; | 390 | mtrr_usage_table[i] = 1; |
396 | else { | 391 | } else { |
397 | usage_table[i] = usage_table[replace] + !!increment; | 392 | mtrr_usage_table[i] = mtrr_usage_table[replace]; |
393 | if (increment) | ||
394 | mtrr_usage_table[i]++; | ||
398 | if (unlikely(replace != i)) { | 395 | if (unlikely(replace != i)) { |
399 | set_mtrr(replace, 0, 0, 0); | 396 | set_mtrr(replace, 0, 0, 0); |
400 | usage_table[replace] = 0; | 397 | mtrr_usage_table[replace] = 0; |
401 | } | 398 | } |
402 | } | 399 | } |
403 | } else | 400 | } else |
@@ -405,7 +402,7 @@ int mtrr_add_page(unsigned long base, unsigned long size, | |||
405 | error = i; | 402 | error = i; |
406 | out: | 403 | out: |
407 | mutex_unlock(&mtrr_mutex); | 404 | mutex_unlock(&mtrr_mutex); |
408 | unlock_cpu_hotplug(); | 405 | put_online_cpus(); |
409 | return error; | 406 | return error; |
410 | } | 407 | } |
411 | 408 | ||
@@ -460,7 +457,7 @@ static int mtrr_check(unsigned long base, unsigned long size) | |||
460 | 457 | ||
461 | int | 458 | int |
462 | mtrr_add(unsigned long base, unsigned long size, unsigned int type, | 459 | mtrr_add(unsigned long base, unsigned long size, unsigned int type, |
463 | char increment) | 460 | bool increment) |
464 | { | 461 | { |
465 | if (mtrr_check(base, size)) | 462 | if (mtrr_check(base, size)) |
466 | return -EINVAL; | 463 | return -EINVAL; |
@@ -495,7 +492,7 @@ int mtrr_del_page(int reg, unsigned long base, unsigned long size) | |||
495 | 492 | ||
496 | max = num_var_ranges; | 493 | max = num_var_ranges; |
497 | /* No CPU hotplug when we change MTRR entries */ | 494 | /* No CPU hotplug when we change MTRR entries */ |
498 | lock_cpu_hotplug(); | 495 | get_online_cpus(); |
499 | mutex_lock(&mtrr_mutex); | 496 | mutex_lock(&mtrr_mutex); |
500 | if (reg < 0) { | 497 | if (reg < 0) { |
501 | /* Search for existing MTRR */ | 498 | /* Search for existing MTRR */ |
@@ -527,16 +524,16 @@ int mtrr_del_page(int reg, unsigned long base, unsigned long size) | |||
527 | printk(KERN_WARNING "mtrr: MTRR %d not used\n", reg); | 524 | printk(KERN_WARNING "mtrr: MTRR %d not used\n", reg); |
528 | goto out; | 525 | goto out; |
529 | } | 526 | } |
530 | if (usage_table[reg] < 1) { | 527 | if (mtrr_usage_table[reg] < 1) { |
531 | printk(KERN_WARNING "mtrr: reg: %d has count=0\n", reg); | 528 | printk(KERN_WARNING "mtrr: reg: %d has count=0\n", reg); |
532 | goto out; | 529 | goto out; |
533 | } | 530 | } |
534 | if (--usage_table[reg] < 1) | 531 | if (--mtrr_usage_table[reg] < 1) |
535 | set_mtrr(reg, 0, 0, 0); | 532 | set_mtrr(reg, 0, 0, 0); |
536 | error = reg; | 533 | error = reg; |
537 | out: | 534 | out: |
538 | mutex_unlock(&mtrr_mutex); | 535 | mutex_unlock(&mtrr_mutex); |
539 | unlock_cpu_hotplug(); | 536 | put_online_cpus(); |
540 | return error; | 537 | return error; |
541 | } | 538 | } |
542 | /** | 539 | /** |
@@ -591,16 +588,11 @@ struct mtrr_value { | |||
591 | unsigned long lsize; | 588 | unsigned long lsize; |
592 | }; | 589 | }; |
593 | 590 | ||
594 | static struct mtrr_value * mtrr_state; | 591 | static struct mtrr_value mtrr_state[MAX_VAR_RANGES]; |
595 | 592 | ||
596 | static int mtrr_save(struct sys_device * sysdev, pm_message_t state) | 593 | static int mtrr_save(struct sys_device * sysdev, pm_message_t state) |
597 | { | 594 | { |
598 | int i; | 595 | int i; |
599 | int size = num_var_ranges * sizeof(struct mtrr_value); | ||
600 | |||
601 | mtrr_state = kzalloc(size,GFP_ATOMIC); | ||
602 | if (!mtrr_state) | ||
603 | return -ENOMEM; | ||
604 | 596 | ||
605 | for (i = 0; i < num_var_ranges; i++) { | 597 | for (i = 0; i < num_var_ranges; i++) { |
606 | mtrr_if->get(i, | 598 | mtrr_if->get(i, |
@@ -622,7 +614,6 @@ static int mtrr_restore(struct sys_device * sysdev) | |||
622 | mtrr_state[i].lsize, | 614 | mtrr_state[i].lsize, |
623 | mtrr_state[i].ltype); | 615 | mtrr_state[i].ltype); |
624 | } | 616 | } |
625 | kfree(mtrr_state); | ||
626 | return 0; | 617 | return 0; |
627 | } | 618 | } |
628 | 619 | ||
@@ -633,6 +624,112 @@ static struct sysdev_driver mtrr_sysdev_driver = { | |||
633 | .resume = mtrr_restore, | 624 | .resume = mtrr_restore, |
634 | }; | 625 | }; |
635 | 626 | ||
627 | static int disable_mtrr_trim; | ||
628 | |||
629 | static int __init disable_mtrr_trim_setup(char *str) | ||
630 | { | ||
631 | disable_mtrr_trim = 1; | ||
632 | return 0; | ||
633 | } | ||
634 | early_param("disable_mtrr_trim", disable_mtrr_trim_setup); | ||
635 | |||
636 | /* | ||
637 | * Newer AMD K8s and later CPUs have a special magic MSR way to force WB | ||
638 | * for memory >4GB. Check for that here. | ||
639 | * Note this won't check if the MTRRs < 4GB where the magic bit doesn't | ||
640 | * apply to are wrong, but so far we don't know of any such case in the wild. | ||
641 | */ | ||
642 | #define Tom2Enabled (1U << 21) | ||
643 | #define Tom2ForceMemTypeWB (1U << 22) | ||
644 | |||
645 | static __init int amd_special_default_mtrr(void) | ||
646 | { | ||
647 | u32 l, h; | ||
648 | |||
649 | if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD) | ||
650 | return 0; | ||
651 | if (boot_cpu_data.x86 < 0xf || boot_cpu_data.x86 > 0x11) | ||
652 | return 0; | ||
653 | /* In case some hypervisor doesn't pass SYSCFG through */ | ||
654 | if (rdmsr_safe(MSR_K8_SYSCFG, &l, &h) < 0) | ||
655 | return 0; | ||
656 | /* | ||
657 | * Memory between 4GB and top of mem is forced WB by this magic bit. | ||
658 | * Reserved before K8RevF, but should be zero there. | ||
659 | */ | ||
660 | if ((l & (Tom2Enabled | Tom2ForceMemTypeWB)) == | ||
661 | (Tom2Enabled | Tom2ForceMemTypeWB)) | ||
662 | return 1; | ||
663 | return 0; | ||
664 | } | ||
665 | |||
666 | /** | ||
667 | * mtrr_trim_uncached_memory - trim RAM not covered by MTRRs | ||
668 | * | ||
669 | * Some buggy BIOSes don't setup the MTRRs properly for systems with certain | ||
670 | * memory configurations. This routine checks that the highest MTRR matches | ||
671 | * the end of memory, to make sure the MTRRs having a write back type cover | ||
672 | * all of the memory the kernel is intending to use. If not, it'll trim any | ||
673 | * memory off the end by adjusting end_pfn, removing it from the kernel's | ||
674 | * allocation pools, warning the user with an obnoxious message. | ||
675 | */ | ||
676 | int __init mtrr_trim_uncached_memory(unsigned long end_pfn) | ||
677 | { | ||
678 | unsigned long i, base, size, highest_addr = 0, def, dummy; | ||
679 | mtrr_type type; | ||
680 | u64 trim_start, trim_size; | ||
681 | |||
682 | /* | ||
683 | * Make sure we only trim uncachable memory on machines that | ||
684 | * support the Intel MTRR architecture: | ||
685 | */ | ||
686 | if (!is_cpu(INTEL) || disable_mtrr_trim) | ||
687 | return 0; | ||
688 | rdmsr(MTRRdefType_MSR, def, dummy); | ||
689 | def &= 0xff; | ||
690 | if (def != MTRR_TYPE_UNCACHABLE) | ||
691 | return 0; | ||
692 | |||
693 | if (amd_special_default_mtrr()) | ||
694 | return 0; | ||
695 | |||
696 | /* Find highest cached pfn */ | ||
697 | for (i = 0; i < num_var_ranges; i++) { | ||
698 | mtrr_if->get(i, &base, &size, &type); | ||
699 | if (type != MTRR_TYPE_WRBACK) | ||
700 | continue; | ||
701 | base <<= PAGE_SHIFT; | ||
702 | size <<= PAGE_SHIFT; | ||
703 | if (highest_addr < base + size) | ||
704 | highest_addr = base + size; | ||
705 | } | ||
706 | |||
707 | /* kvm/qemu doesn't have mtrr set right, don't trim them all */ | ||
708 | if (!highest_addr) { | ||
709 | printk(KERN_WARNING "WARNING: strange, CPU MTRRs all blank?\n"); | ||
710 | WARN_ON(1); | ||
711 | return 0; | ||
712 | } | ||
713 | |||
714 | if ((highest_addr >> PAGE_SHIFT) < end_pfn) { | ||
715 | printk(KERN_WARNING "WARNING: BIOS bug: CPU MTRRs don't cover" | ||
716 | " all of memory, losing %LdMB of RAM.\n", | ||
717 | (((u64)end_pfn << PAGE_SHIFT) - highest_addr) >> 20); | ||
718 | |||
719 | WARN_ON(1); | ||
720 | |||
721 | printk(KERN_INFO "update e820 for mtrr\n"); | ||
722 | trim_start = highest_addr; | ||
723 | trim_size = end_pfn; | ||
724 | trim_size <<= PAGE_SHIFT; | ||
725 | trim_size -= trim_start; | ||
726 | add_memory_region(trim_start, trim_size, E820_RESERVED); | ||
727 | update_e820(); | ||
728 | return 1; | ||
729 | } | ||
730 | |||
731 | return 0; | ||
732 | } | ||
636 | 733 | ||
637 | /** | 734 | /** |
638 | * mtrr_bp_init - initialize mtrrs on the boot CPU | 735 | * mtrr_bp_init - initialize mtrrs on the boot CPU |
diff --git a/arch/x86/kernel/cpu/mtrr/mtrr.h b/arch/x86/kernel/cpu/mtrr/mtrr.h index 289dfe6030e3..fb74a2c20814 100644 --- a/arch/x86/kernel/cpu/mtrr/mtrr.h +++ b/arch/x86/kernel/cpu/mtrr/mtrr.h | |||
@@ -2,10 +2,8 @@ | |||
2 | * local mtrr defines. | 2 | * local mtrr defines. |
3 | */ | 3 | */ |
4 | 4 | ||
5 | #ifndef TRUE | 5 | #include <linux/types.h> |
6 | #define TRUE 1 | 6 | #include <linux/stddef.h> |
7 | #define FALSE 0 | ||
8 | #endif | ||
9 | 7 | ||
10 | #define MTRRcap_MSR 0x0fe | 8 | #define MTRRcap_MSR 0x0fe |
11 | #define MTRRdefType_MSR 0x2ff | 9 | #define MTRRdefType_MSR 0x2ff |
@@ -14,6 +12,7 @@ | |||
14 | #define MTRRphysMask_MSR(reg) (0x200 + 2 * (reg) + 1) | 12 | #define MTRRphysMask_MSR(reg) (0x200 + 2 * (reg) + 1) |
15 | 13 | ||
16 | #define NUM_FIXED_RANGES 88 | 14 | #define NUM_FIXED_RANGES 88 |
15 | #define MAX_VAR_RANGES 256 | ||
17 | #define MTRRfix64K_00000_MSR 0x250 | 16 | #define MTRRfix64K_00000_MSR 0x250 |
18 | #define MTRRfix16K_80000_MSR 0x258 | 17 | #define MTRRfix16K_80000_MSR 0x258 |
19 | #define MTRRfix16K_A0000_MSR 0x259 | 18 | #define MTRRfix16K_A0000_MSR 0x259 |
@@ -34,6 +33,8 @@ | |||
34 | an 8 bit field: */ | 33 | an 8 bit field: */ |
35 | typedef u8 mtrr_type; | 34 | typedef u8 mtrr_type; |
36 | 35 | ||
36 | extern unsigned int mtrr_usage_table[MAX_VAR_RANGES]; | ||
37 | |||
37 | struct mtrr_ops { | 38 | struct mtrr_ops { |
38 | u32 vendor; | 39 | u32 vendor; |
39 | u32 use_intel_if; | 40 | u32 use_intel_if; |
diff --git a/arch/x86/kernel/cpu/mtrr/state.c b/arch/x86/kernel/cpu/mtrr/state.c index 49e20c2afcdf..9f8ba923d1c9 100644 --- a/arch/x86/kernel/cpu/mtrr/state.c +++ b/arch/x86/kernel/cpu/mtrr/state.c | |||
@@ -4,6 +4,7 @@ | |||
4 | #include <asm/mtrr.h> | 4 | #include <asm/mtrr.h> |
5 | #include <asm/msr.h> | 5 | #include <asm/msr.h> |
6 | #include <asm/processor-cyrix.h> | 6 | #include <asm/processor-cyrix.h> |
7 | #include <asm/processor-flags.h> | ||
7 | #include "mtrr.h" | 8 | #include "mtrr.h" |
8 | 9 | ||
9 | 10 | ||
@@ -25,7 +26,7 @@ void set_mtrr_prepare_save(struct set_mtrr_context *ctxt) | |||
25 | 26 | ||
26 | /* Disable and flush caches. Note that wbinvd flushes the TLBs as | 27 | /* Disable and flush caches. Note that wbinvd flushes the TLBs as |
27 | a side-effect */ | 28 | a side-effect */ |
28 | cr0 = read_cr0() | 0x40000000; | 29 | cr0 = read_cr0() | X86_CR0_CD; |
29 | wbinvd(); | 30 | wbinvd(); |
30 | write_cr0(cr0); | 31 | write_cr0(cr0); |
31 | wbinvd(); | 32 | wbinvd(); |