2 * MTRR (Memory Type Range Register) cleanup
4 * Copyright (C) 2009 Yinghai Lu
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
16 * You should have received a copy of the GNU Library General Public
17 * License along with this library; if not, write to the Free
18 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 #include <linux/init.h>
21 #include <linux/pci.h>
22 #include <linux/smp.h>
23 #include <linux/cpu.h>
24 #include <linux/mutex.h>
25 #include <linux/uaccess.h>
26 #include <linux/kvm_para.h>
27 #include <linux/range.h>
29 #include <asm/processor.h>
30 #include <asm/e820/api.h>
36 struct var_mtrr_range_state
{
37 unsigned long base_pfn
;
38 unsigned long size_pfn
;
42 struct var_mtrr_state
{
43 unsigned long range_startk
;
44 unsigned long range_sizek
;
45 unsigned long chunk_sizek
;
46 unsigned long gran_sizek
;
50 /* Should be related to MTRR_VAR_RANGES nums */
53 static struct range __initdata range
[RANGE_NUM
];
54 static int __initdata nr_range
;
56 static struct var_mtrr_range_state __initdata range_state
[RANGE_NUM
];
58 #define BIOS_BUG_MSG \
59 "WARNING: BIOS bug: VAR MTRR %d contains strange UC entry under 1M, check with your system vendor!\n"
62 x86_get_mtrr_mem_range(struct range
*range
, int nr_range
,
63 unsigned long extra_remove_base
,
64 unsigned long extra_remove_size
)
66 unsigned long base
, size
;
70 for (i
= 0; i
< num_var_ranges
; i
++) {
71 type
= range_state
[i
].type
;
72 if (type
!= MTRR_TYPE_WRBACK
)
74 base
= range_state
[i
].base_pfn
;
75 size
= range_state
[i
].size_pfn
;
76 nr_range
= add_range_with_merge(range
, RANGE_NUM
, nr_range
,
80 Dprintk("After WB checking\n");
81 for (i
= 0; i
< nr_range
; i
++)
82 Dprintk("MTRR MAP PFN: %016llx - %016llx\n",
83 range
[i
].start
, range
[i
].end
);
85 /* Take out UC ranges: */
86 for (i
= 0; i
< num_var_ranges
; i
++) {
87 type
= range_state
[i
].type
;
88 if (type
!= MTRR_TYPE_UNCACHABLE
&&
89 type
!= MTRR_TYPE_WRPROT
)
91 size
= range_state
[i
].size_pfn
;
94 base
= range_state
[i
].base_pfn
;
95 if (base
< (1<<(20-PAGE_SHIFT
)) && mtrr_state
.have_fixed
&&
96 (mtrr_state
.enabled
& MTRR_STATE_MTRR_ENABLED
) &&
97 (mtrr_state
.enabled
& MTRR_STATE_MTRR_FIXED_ENABLED
)) {
98 /* Var MTRR contains UC entry below 1M? Skip it: */
99 pr_warn(BIOS_BUG_MSG
, i
);
100 if (base
+ size
<= (1<<(20-PAGE_SHIFT
)))
102 size
-= (1<<(20-PAGE_SHIFT
)) - base
;
103 base
= 1<<(20-PAGE_SHIFT
);
105 subtract_range(range
, RANGE_NUM
, base
, base
+ size
);
107 if (extra_remove_size
)
108 subtract_range(range
, RANGE_NUM
, extra_remove_base
,
109 extra_remove_base
+ extra_remove_size
);
111 Dprintk("After UC checking\n");
112 for (i
= 0; i
< RANGE_NUM
; i
++) {
116 Dprintk("MTRR MAP PFN: %016llx - %016llx\n",
117 range
[i
].start
, range
[i
].end
);
120 /* sort the ranges */
121 nr_range
= clean_sort_range(range
, RANGE_NUM
);
123 Dprintk("After sorting\n");
124 for (i
= 0; i
< nr_range
; i
++)
125 Dprintk("MTRR MAP PFN: %016llx - %016llx\n",
126 range
[i
].start
, range
[i
].end
);
131 #ifdef CONFIG_MTRR_SANITIZER
133 static unsigned long __init
sum_ranges(struct range
*range
, int nr_range
)
135 unsigned long sum
= 0;
138 for (i
= 0; i
< nr_range
; i
++)
139 sum
+= range
[i
].end
- range
[i
].start
;
144 static int enable_mtrr_cleanup __initdata
=
145 CONFIG_MTRR_SANITIZER_ENABLE_DEFAULT
;
147 static int __init
disable_mtrr_cleanup_setup(char *str
)
149 enable_mtrr_cleanup
= 0;
152 early_param("disable_mtrr_cleanup", disable_mtrr_cleanup_setup
);
154 static int __init
enable_mtrr_cleanup_setup(char *str
)
156 enable_mtrr_cleanup
= 1;
159 early_param("enable_mtrr_cleanup", enable_mtrr_cleanup_setup
);
162 set_var_mtrr(unsigned int reg
, unsigned long basek
, unsigned long sizek
,
165 u32 base_lo
, base_hi
, mask_lo
, mask_hi
;
169 fill_mtrr_var_range(reg
, 0, 0, 0, 0);
173 mask
= (1ULL << boot_cpu_data
.x86_phys_bits
) - 1;
174 mask
&= ~((((u64
)sizek
) << 10) - 1);
176 base
= ((u64
)basek
) << 10;
181 base_lo
= base
& ((1ULL<<32) - 1);
182 base_hi
= base
>> 32;
184 mask_lo
= mask
& ((1ULL<<32) - 1);
185 mask_hi
= mask
>> 32;
187 fill_mtrr_var_range(reg
, base_lo
, base_hi
, mask_lo
, mask_hi
);
191 save_var_mtrr(unsigned int reg
, unsigned long basek
, unsigned long sizek
,
194 range_state
[reg
].base_pfn
= basek
>> (PAGE_SHIFT
- 10);
195 range_state
[reg
].size_pfn
= sizek
>> (PAGE_SHIFT
- 10);
196 range_state
[reg
].type
= type
;
199 static void __init
set_var_mtrr_all(void)
201 unsigned long basek
, sizek
;
205 for (reg
= 0; reg
< num_var_ranges
; reg
++) {
206 basek
= range_state
[reg
].base_pfn
<< (PAGE_SHIFT
- 10);
207 sizek
= range_state
[reg
].size_pfn
<< (PAGE_SHIFT
- 10);
208 type
= range_state
[reg
].type
;
210 set_var_mtrr(reg
, basek
, sizek
, type
);
214 static unsigned long to_size_factor(unsigned long sizek
, char *factorp
)
216 unsigned long base
= sizek
;
219 if (base
& ((1<<10) - 1)) {
220 /* Not MB-aligned: */
222 } else if (base
& ((1<<20) - 1)) {
235 static unsigned int __init
236 range_to_mtrr(unsigned int reg
, unsigned long range_startk
,
237 unsigned long range_sizek
, unsigned char type
)
239 if (!range_sizek
|| (reg
>= num_var_ranges
))
242 while (range_sizek
) {
243 unsigned long max_align
, align
;
246 /* Compute the maximum size with which we can make a range: */
248 max_align
= __ffs(range_startk
);
250 max_align
= BITS_PER_LONG
- 1;
252 align
= __fls(range_sizek
);
253 if (align
> max_align
)
256 sizek
= 1UL << align
;
258 char start_factor
= 'K', size_factor
= 'K';
259 unsigned long start_base
, size_base
;
261 start_base
= to_size_factor(range_startk
, &start_factor
);
262 size_base
= to_size_factor(sizek
, &size_factor
);
264 Dprintk("Setting variable MTRR %d, "
265 "base: %ld%cB, range: %ld%cB, type %s\n",
266 reg
, start_base
, start_factor
,
267 size_base
, size_factor
,
268 (type
== MTRR_TYPE_UNCACHABLE
) ? "UC" :
269 ((type
== MTRR_TYPE_WRBACK
) ? "WB" : "Other")
272 save_var_mtrr(reg
++, range_startk
, sizek
, type
);
273 range_startk
+= sizek
;
274 range_sizek
-= sizek
;
275 if (reg
>= num_var_ranges
)
281 static unsigned __init
282 range_to_mtrr_with_hole(struct var_mtrr_state
*state
, unsigned long basek
,
285 unsigned long hole_basek
, hole_sizek
;
286 unsigned long second_sizek
;
287 unsigned long range0_basek
, range0_sizek
;
288 unsigned long range_basek
, range_sizek
;
289 unsigned long chunk_sizek
;
290 unsigned long gran_sizek
;
295 chunk_sizek
= state
->chunk_sizek
;
296 gran_sizek
= state
->gran_sizek
;
298 /* Align with gran size, prevent small block used up MTRRs: */
299 range_basek
= ALIGN(state
->range_startk
, gran_sizek
);
300 if ((range_basek
> basek
) && basek
)
303 state
->range_sizek
-= (range_basek
- state
->range_startk
);
304 range_sizek
= ALIGN(state
->range_sizek
, gran_sizek
);
306 while (range_sizek
> state
->range_sizek
) {
307 range_sizek
-= gran_sizek
;
311 state
->range_sizek
= range_sizek
;
313 /* Try to append some small hole: */
314 range0_basek
= state
->range_startk
;
315 range0_sizek
= ALIGN(state
->range_sizek
, chunk_sizek
);
318 if (range0_sizek
== state
->range_sizek
) {
319 Dprintk("rangeX: %016lx - %016lx\n",
321 (range0_basek
+ state
->range_sizek
)<<10);
322 state
->reg
= range_to_mtrr(state
->reg
, range0_basek
,
323 state
->range_sizek
, MTRR_TYPE_WRBACK
);
327 /* Only cut back when it is not the last: */
329 while (range0_basek
+ range0_sizek
> (basek
+ sizek
)) {
330 if (range0_sizek
>= chunk_sizek
)
331 range0_sizek
-= chunk_sizek
;
341 range_basek
= range0_basek
+ range0_sizek
;
343 /* One hole in the middle: */
344 if (range_basek
> basek
&& range_basek
<= (basek
+ sizek
))
345 second_sizek
= range_basek
- basek
;
347 if (range0_sizek
> state
->range_sizek
) {
349 /* One hole in middle or at the end: */
350 hole_sizek
= range0_sizek
- state
->range_sizek
- second_sizek
;
352 /* Hole size should be less than half of range0 size: */
353 if (hole_sizek
>= (range0_sizek
>> 1) &&
354 range0_sizek
>= chunk_sizek
) {
355 range0_sizek
-= chunk_sizek
;
364 Dprintk("range0: %016lx - %016lx\n",
366 (range0_basek
+ range0_sizek
)<<10);
367 state
->reg
= range_to_mtrr(state
->reg
, range0_basek
,
368 range0_sizek
, MTRR_TYPE_WRBACK
);
371 if (range0_sizek
< state
->range_sizek
) {
372 /* Need to handle left over range: */
373 range_sizek
= state
->range_sizek
- range0_sizek
;
375 Dprintk("range: %016lx - %016lx\n",
377 (range_basek
+ range_sizek
)<<10);
379 state
->reg
= range_to_mtrr(state
->reg
, range_basek
,
380 range_sizek
, MTRR_TYPE_WRBACK
);
384 hole_basek
= range_basek
- hole_sizek
- second_sizek
;
385 Dprintk("hole: %016lx - %016lx\n",
387 (hole_basek
+ hole_sizek
)<<10);
388 state
->reg
= range_to_mtrr(state
->reg
, hole_basek
,
389 hole_sizek
, MTRR_TYPE_UNCACHABLE
);
396 set_var_mtrr_range(struct var_mtrr_state
*state
, unsigned long base_pfn
,
397 unsigned long size_pfn
)
399 unsigned long basek
, sizek
;
400 unsigned long second_sizek
= 0;
402 if (state
->reg
>= num_var_ranges
)
405 basek
= base_pfn
<< (PAGE_SHIFT
- 10);
406 sizek
= size_pfn
<< (PAGE_SHIFT
- 10);
408 /* See if I can merge with the last range: */
409 if ((basek
<= 1024) ||
410 (state
->range_startk
+ state
->range_sizek
== basek
)) {
411 unsigned long endk
= basek
+ sizek
;
412 state
->range_sizek
= endk
- state
->range_startk
;
415 /* Write the range mtrrs: */
416 if (state
->range_sizek
!= 0)
417 second_sizek
= range_to_mtrr_with_hole(state
, basek
, sizek
);
419 /* Allocate an msr: */
420 state
->range_startk
= basek
+ second_sizek
;
421 state
->range_sizek
= sizek
- second_sizek
;
424 /* Minimum size of mtrr block that can take hole: */
425 static u64 mtrr_chunk_size __initdata
= (256ULL<<20);
427 static int __init
parse_mtrr_chunk_size_opt(char *p
)
431 mtrr_chunk_size
= memparse(p
, &p
);
434 early_param("mtrr_chunk_size", parse_mtrr_chunk_size_opt
);
436 /* Granularity of mtrr of block: */
437 static u64 mtrr_gran_size __initdata
;
439 static int __init
parse_mtrr_gran_size_opt(char *p
)
443 mtrr_gran_size
= memparse(p
, &p
);
446 early_param("mtrr_gran_size", parse_mtrr_gran_size_opt
);
448 static unsigned long nr_mtrr_spare_reg __initdata
=
449 CONFIG_MTRR_SANITIZER_SPARE_REG_NR_DEFAULT
;
451 static int __init
parse_mtrr_spare_reg(char *arg
)
454 nr_mtrr_spare_reg
= simple_strtoul(arg
, NULL
, 0);
457 early_param("mtrr_spare_reg_nr", parse_mtrr_spare_reg
);
460 x86_setup_var_mtrrs(struct range
*range
, int nr_range
,
461 u64 chunk_size
, u64 gran_size
)
463 struct var_mtrr_state var_state
;
467 var_state
.range_startk
= 0;
468 var_state
.range_sizek
= 0;
470 var_state
.chunk_sizek
= chunk_size
>> 10;
471 var_state
.gran_sizek
= gran_size
>> 10;
473 memset(range_state
, 0, sizeof(range_state
));
475 /* Write the range: */
476 for (i
= 0; i
< nr_range
; i
++) {
477 set_var_mtrr_range(&var_state
, range
[i
].start
,
478 range
[i
].end
- range
[i
].start
);
481 /* Write the last range: */
482 if (var_state
.range_sizek
!= 0)
483 range_to_mtrr_with_hole(&var_state
, 0, 0);
485 num_reg
= var_state
.reg
;
486 /* Clear out the extra MTRR's: */
487 while (var_state
.reg
< num_var_ranges
) {
488 save_var_mtrr(var_state
.reg
, 0, 0, 0);
495 struct mtrr_cleanup_result
{
496 unsigned long gran_sizek
;
497 unsigned long chunk_sizek
;
498 unsigned long lose_cover_sizek
;
499 unsigned int num_reg
;
504 * gran_size: 64K, 128K, 256K, 512K, 1M, 2M, ..., 2G
505 * chunk size: gran_size, ..., 2G
506 * so we need (1+16)*8
508 #define NUM_RESULT 136
509 #define PSHIFT (PAGE_SHIFT - 10)
511 static struct mtrr_cleanup_result __initdata result
[NUM_RESULT
];
512 static unsigned long __initdata min_loss_pfn
[RANGE_NUM
];
514 static void __init
print_out_mtrr_range_state(void)
516 char start_factor
= 'K', size_factor
= 'K';
517 unsigned long start_base
, size_base
;
521 for (i
= 0; i
< num_var_ranges
; i
++) {
523 size_base
= range_state
[i
].size_pfn
<< (PAGE_SHIFT
- 10);
527 size_base
= to_size_factor(size_base
, &size_factor
);
528 start_base
= range_state
[i
].base_pfn
<< (PAGE_SHIFT
- 10);
529 start_base
= to_size_factor(start_base
, &start_factor
);
530 type
= range_state
[i
].type
;
532 Dprintk("reg %d, base: %ld%cB, range: %ld%cB, type %s\n",
533 i
, start_base
, start_factor
,
534 size_base
, size_factor
,
535 (type
== MTRR_TYPE_UNCACHABLE
) ? "UC" :
536 ((type
== MTRR_TYPE_WRPROT
) ? "WP" :
537 ((type
== MTRR_TYPE_WRBACK
) ? "WB" : "Other"))
542 static int __init
mtrr_need_cleanup(void)
547 /* Extra one for all 0: */
548 int num
[MTRR_NUM_TYPES
+ 1];
550 /* Check entries number: */
551 memset(num
, 0, sizeof(num
));
552 for (i
= 0; i
< num_var_ranges
; i
++) {
553 type
= range_state
[i
].type
;
554 size
= range_state
[i
].size_pfn
;
555 if (type
>= MTRR_NUM_TYPES
)
558 type
= MTRR_NUM_TYPES
;
562 /* Check if we got UC entries: */
563 if (!num
[MTRR_TYPE_UNCACHABLE
])
566 /* Check if we only had WB and UC */
567 if (num
[MTRR_TYPE_WRBACK
] + num
[MTRR_TYPE_UNCACHABLE
] !=
568 num_var_ranges
- num
[MTRR_NUM_TYPES
])
574 static unsigned long __initdata range_sums
;
577 mtrr_calc_range_state(u64 chunk_size
, u64 gran_size
,
578 unsigned long x_remove_base
,
579 unsigned long x_remove_size
, int i
)
582 * range_new should really be an automatic variable, but
583 * putting 4096 bytes on the stack is frowned upon, to put it
584 * mildly. It is safe to make it a static __initdata variable,
585 * since mtrr_calc_range_state is only called during init and
586 * there's no way it will call itself recursively.
588 static struct range range_new
[RANGE_NUM
] __initdata
;
589 unsigned long range_sums_new
;
593 /* Convert ranges to var ranges state: */
594 num_reg
= x86_setup_var_mtrrs(range
, nr_range
, chunk_size
, gran_size
);
596 /* We got new setting in range_state, check it: */
597 memset(range_new
, 0, sizeof(range_new
));
598 nr_range_new
= x86_get_mtrr_mem_range(range_new
, 0,
599 x_remove_base
, x_remove_size
);
600 range_sums_new
= sum_ranges(range_new
, nr_range_new
);
602 result
[i
].chunk_sizek
= chunk_size
>> 10;
603 result
[i
].gran_sizek
= gran_size
>> 10;
604 result
[i
].num_reg
= num_reg
;
606 if (range_sums
< range_sums_new
) {
607 result
[i
].lose_cover_sizek
= (range_sums_new
- range_sums
) << PSHIFT
;
610 result
[i
].lose_cover_sizek
= (range_sums
- range_sums_new
) << PSHIFT
;
613 /* Double check it: */
614 if (!result
[i
].bad
&& !result
[i
].lose_cover_sizek
) {
615 if (nr_range_new
!= nr_range
|| memcmp(range
, range_new
, sizeof(range
)))
619 if (!result
[i
].bad
&& (range_sums
- range_sums_new
< min_loss_pfn
[num_reg
]))
620 min_loss_pfn
[num_reg
] = range_sums
- range_sums_new
;
623 static void __init
mtrr_print_out_one_result(int i
)
625 unsigned long gran_base
, chunk_base
, lose_base
;
626 char gran_factor
, chunk_factor
, lose_factor
;
628 gran_base
= to_size_factor(result
[i
].gran_sizek
, &gran_factor
);
629 chunk_base
= to_size_factor(result
[i
].chunk_sizek
, &chunk_factor
);
630 lose_base
= to_size_factor(result
[i
].lose_cover_sizek
, &lose_factor
);
632 pr_info("%sgran_size: %ld%c \tchunk_size: %ld%c \t",
633 result
[i
].bad
? "*BAD*" : " ",
634 gran_base
, gran_factor
, chunk_base
, chunk_factor
);
635 pr_cont("num_reg: %d \tlose cover RAM: %s%ld%c\n",
636 result
[i
].num_reg
, result
[i
].bad
? "-" : "",
637 lose_base
, lose_factor
);
640 static int __init
mtrr_search_optimal_index(void)
646 if (nr_mtrr_spare_reg
>= num_var_ranges
)
647 nr_mtrr_spare_reg
= num_var_ranges
- 1;
650 for (i
= num_var_ranges
- nr_mtrr_spare_reg
; i
> 0; i
--) {
651 if (!min_loss_pfn
[i
])
656 if (num_reg_good
!= -1) {
657 for (i
= 0; i
< NUM_RESULT
; i
++) {
658 if (!result
[i
].bad
&&
659 result
[i
].num_reg
== num_reg_good
&&
660 !result
[i
].lose_cover_sizek
) {
670 int __init
mtrr_cleanup(void)
672 unsigned long x_remove_base
, x_remove_size
;
673 unsigned long base
, size
, def
, dummy
;
674 u64 chunk_size
, gran_size
;
682 if (!cpu_feature_enabled(X86_FEATURE_MTRR
) || enable_mtrr_cleanup
< 1)
685 rdmsr(MSR_MTRRdefType
, def
, dummy
);
687 if (def
!= MTRR_TYPE_UNCACHABLE
)
690 /* Get it and store it aside: */
691 memset(range_state
, 0, sizeof(range_state
));
692 for (i
= 0; i
< num_var_ranges
; i
++) {
693 mtrr_if
->get(i
, &base
, &size
, &type
);
694 range_state
[i
].base_pfn
= base
;
695 range_state
[i
].size_pfn
= size
;
696 range_state
[i
].type
= type
;
699 /* Check if we need handle it and can handle it: */
700 if (!mtrr_need_cleanup())
703 /* Print original var MTRRs at first, for debugging: */
704 Dprintk("original variable MTRRs\n");
705 print_out_mtrr_range_state();
707 memset(range
, 0, sizeof(range
));
709 x_remove_base
= 1 << (32 - PAGE_SHIFT
);
711 x_remove_size
= (mtrr_tom2
>> PAGE_SHIFT
) - x_remove_base
;
714 * [0, 1M) should always be covered by var mtrr with WB
715 * and fixed mtrrs should take effect before var mtrr for it:
717 nr_range
= add_range_with_merge(range
, RANGE_NUM
, 0, 0,
718 1ULL<<(20 - PAGE_SHIFT
));
719 /* add from var mtrr at last */
720 nr_range
= x86_get_mtrr_mem_range(range
, nr_range
,
721 x_remove_base
, x_remove_size
);
723 range_sums
= sum_ranges(range
, nr_range
);
724 pr_info("total RAM covered: %ldM\n",
725 range_sums
>> (20 - PAGE_SHIFT
));
727 if (mtrr_chunk_size
&& mtrr_gran_size
) {
729 mtrr_calc_range_state(mtrr_chunk_size
, mtrr_gran_size
,
730 x_remove_base
, x_remove_size
, i
);
732 mtrr_print_out_one_result(i
);
734 if (!result
[i
].bad
) {
736 Dprintk("New variable MTRRs\n");
737 print_out_mtrr_range_state();
740 pr_info("invalid mtrr_gran_size or mtrr_chunk_size, will find optimal one\n");
744 memset(min_loss_pfn
, 0xff, sizeof(min_loss_pfn
));
745 memset(result
, 0, sizeof(result
));
746 for (gran_size
= (1ULL<<16); gran_size
< (1ULL<<32); gran_size
<<= 1) {
748 for (chunk_size
= gran_size
; chunk_size
< (1ULL<<32);
754 mtrr_calc_range_state(chunk_size
, gran_size
,
755 x_remove_base
, x_remove_size
, i
);
757 mtrr_print_out_one_result(i
);
765 /* Try to find the optimal index: */
766 index_good
= mtrr_search_optimal_index();
768 if (index_good
!= -1) {
769 pr_info("Found optimal setting for mtrr clean up\n");
771 mtrr_print_out_one_result(i
);
773 /* Convert ranges to var ranges state: */
774 chunk_size
= result
[i
].chunk_sizek
;
776 gran_size
= result
[i
].gran_sizek
;
778 x86_setup_var_mtrrs(range
, nr_range
, chunk_size
, gran_size
);
780 Dprintk("New variable MTRRs\n");
781 print_out_mtrr_range_state();
785 for (i
= 0; i
< NUM_RESULT
; i
++)
786 mtrr_print_out_one_result(i
);
789 pr_info("mtrr_cleanup: can not find optimal value\n");
790 pr_info("please specify mtrr_gran_size/mtrr_chunk_size\n");
795 int __init
mtrr_cleanup(void)
801 static int disable_mtrr_trim
;
803 static int __init
disable_mtrr_trim_setup(char *str
)
805 disable_mtrr_trim
= 1;
808 early_param("disable_mtrr_trim", disable_mtrr_trim_setup
);
811 * Newer AMD K8s and later CPUs have a special magic MSR way to force WB
812 * for memory >4GB. Check for that here.
813 * Note this won't check if the MTRRs < 4GB where the magic bit doesn't
814 * apply to are wrong, but so far we don't know of any such case in the wild.
816 #define Tom2Enabled (1U << 21)
817 #define Tom2ForceMemTypeWB (1U << 22)
819 int __init
amd_special_default_mtrr(void)
823 if (boot_cpu_data
.x86_vendor
!= X86_VENDOR_AMD
&&
824 boot_cpu_data
.x86_vendor
!= X86_VENDOR_HYGON
)
826 if (boot_cpu_data
.x86
< 0xf)
828 /* In case some hypervisor doesn't pass SYSCFG through: */
829 if (rdmsr_safe(MSR_AMD64_SYSCFG
, &l
, &h
) < 0)
832 * Memory between 4GB and top of mem is forced WB by this magic bit.
833 * Reserved before K8RevF, but should be zero there.
835 if ((l
& (Tom2Enabled
| Tom2ForceMemTypeWB
)) ==
836 (Tom2Enabled
| Tom2ForceMemTypeWB
))
842 real_trim_memory(unsigned long start_pfn
, unsigned long limit_pfn
)
844 u64 trim_start
, trim_size
;
846 trim_start
= start_pfn
;
847 trim_start
<<= PAGE_SHIFT
;
849 trim_size
= limit_pfn
;
850 trim_size
<<= PAGE_SHIFT
;
851 trim_size
-= trim_start
;
853 return e820__range_update(trim_start
, trim_size
, E820_TYPE_RAM
, E820_TYPE_RESERVED
);
857 * mtrr_trim_uncached_memory - trim RAM not covered by MTRRs
858 * @end_pfn: ending page frame number
860 * Some buggy BIOSes don't setup the MTRRs properly for systems with certain
861 * memory configurations. This routine checks that the highest MTRR matches
862 * the end of memory, to make sure the MTRRs having a write back type cover
863 * all of the memory the kernel is intending to use. If not, it'll trim any
864 * memory off the end by adjusting end_pfn, removing it from the kernel's
865 * allocation pools, warning the user with an obnoxious message.
867 int __init
mtrr_trim_uncached_memory(unsigned long end_pfn
)
869 unsigned long i
, base
, size
, highest_pfn
= 0, def
, dummy
;
872 /* extra one for all 0 */
873 int num
[MTRR_NUM_TYPES
+ 1];
879 * Make sure we only trim uncachable memory on machines that
880 * support the Intel MTRR architecture:
882 if (!cpu_feature_enabled(X86_FEATURE_MTRR
) || disable_mtrr_trim
)
885 rdmsr(MSR_MTRRdefType
, def
, dummy
);
886 def
&= MTRR_DEF_TYPE_TYPE
;
887 if (def
!= MTRR_TYPE_UNCACHABLE
)
890 /* Get it and store it aside: */
891 memset(range_state
, 0, sizeof(range_state
));
892 for (i
= 0; i
< num_var_ranges
; i
++) {
893 mtrr_if
->get(i
, &base
, &size
, &type
);
894 range_state
[i
].base_pfn
= base
;
895 range_state
[i
].size_pfn
= size
;
896 range_state
[i
].type
= type
;
899 /* Find highest cached pfn: */
900 for (i
= 0; i
< num_var_ranges
; i
++) {
901 type
= range_state
[i
].type
;
902 if (type
!= MTRR_TYPE_WRBACK
)
904 base
= range_state
[i
].base_pfn
;
905 size
= range_state
[i
].size_pfn
;
906 if (highest_pfn
< base
+ size
)
907 highest_pfn
= base
+ size
;
910 /* kvm/qemu doesn't have mtrr set right, don't trim them all: */
912 pr_info("CPU MTRRs all blank - virtualized system.\n");
916 /* Check entries number: */
917 memset(num
, 0, sizeof(num
));
918 for (i
= 0; i
< num_var_ranges
; i
++) {
919 type
= range_state
[i
].type
;
920 if (type
>= MTRR_NUM_TYPES
)
922 size
= range_state
[i
].size_pfn
;
924 type
= MTRR_NUM_TYPES
;
928 /* No entry for WB? */
929 if (!num
[MTRR_TYPE_WRBACK
])
932 /* Check if we only had WB and UC: */
933 if (num
[MTRR_TYPE_WRBACK
] + num
[MTRR_TYPE_UNCACHABLE
] !=
934 num_var_ranges
- num
[MTRR_NUM_TYPES
])
937 memset(range
, 0, sizeof(range
));
940 range
[nr_range
].start
= (1ULL<<(32 - PAGE_SHIFT
));
941 range
[nr_range
].end
= mtrr_tom2
>> PAGE_SHIFT
;
942 if (highest_pfn
< range
[nr_range
].end
)
943 highest_pfn
= range
[nr_range
].end
;
946 nr_range
= x86_get_mtrr_mem_range(range
, nr_range
, 0, 0);
948 /* Check the head: */
951 total_trim_size
+= real_trim_memory(0, range
[0].start
);
953 /* Check the holes: */
954 for (i
= 0; i
< nr_range
- 1; i
++) {
955 if (range
[i
].end
< range
[i
+1].start
)
956 total_trim_size
+= real_trim_memory(range
[i
].end
,
962 if (range
[i
].end
< end_pfn
)
963 total_trim_size
+= real_trim_memory(range
[i
].end
,
966 if (total_trim_size
) {
967 pr_warn("WARNING: BIOS bug: CPU MTRRs don't cover all of memory, losing %lluMB of RAM.\n",
968 total_trim_size
>> 20);
970 if (!changed_by_mtrr_cleanup
)
973 pr_info("update e820 for mtrr\n");
974 e820__update_table_print();