aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYinghai Lu <yinghai@kernel.org>2009-03-11 23:07:39 -0400
committerIngo Molnar <mingo@elte.hu>2009-03-12 21:52:19 -0400
commit0d890355bff25e1dc03a577a90ed80741489ca54 (patch)
tree0cb740303fd6d94108e2e18086f77716fec32586
parentc1ab7e93c6ddf8a068719b97b7e26c3d8eba7c32 (diff)
x86: separate mtrr cleanup/mtrr_e820 trim to separate file
Impact: cleanup mtrr main.c is too big, seperate mtrr cleanup and mtrr e820 trim code to another file. Signed-off-by: Yinghai Lu <yinghai@kernel.org> LKML-Reference: <49B87C7B.80809@kernel.org> Signed-off-by: Ingo Molnar <mingo@elte.hu>
-rw-r--r--arch/x86/kernel/cpu/mtrr/Makefile2
-rw-r--r--arch/x86/kernel/cpu/mtrr/cleanup.c1089
-rw-r--r--arch/x86/kernel/cpu/mtrr/main.c1055
-rw-r--r--arch/x86/kernel/cpu/mtrr/mtrr.h3
4 files changed, 1094 insertions, 1055 deletions
diff --git a/arch/x86/kernel/cpu/mtrr/Makefile b/arch/x86/kernel/cpu/mtrr/Makefile
index 191fc0533649..f4361b56f8e9 100644
--- a/arch/x86/kernel/cpu/mtrr/Makefile
+++ b/arch/x86/kernel/cpu/mtrr/Makefile
@@ -1,3 +1,3 @@
1obj-y := main.o if.o generic.o state.o 1obj-y := main.o if.o generic.o state.o cleanup.o
2obj-$(CONFIG_X86_32) += amd.o cyrix.o centaur.o 2obj-$(CONFIG_X86_32) += amd.o cyrix.o centaur.o
3 3
diff --git a/arch/x86/kernel/cpu/mtrr/cleanup.c b/arch/x86/kernel/cpu/mtrr/cleanup.c
new file mode 100644
index 000000000000..58b58bbf7eb3
--- /dev/null
+++ b/arch/x86/kernel/cpu/mtrr/cleanup.c
@@ -0,0 +1,1089 @@
1/* MTRR (Memory Type Range Register) cleanup
2
3 Copyright (C) 2009 Yinghai Lu
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public
16 License along with this library; if not, write to the Free
17 Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18*/
19
20#include <linux/module.h>
21#include <linux/init.h>
22#include <linux/pci.h>
23#include <linux/smp.h>
24#include <linux/cpu.h>
25#include <linux/mutex.h>
26#include <linux/sort.h>
27
28#include <asm/e820.h>
29#include <asm/mtrr.h>
30#include <asm/uaccess.h>
31#include <asm/processor.h>
32#include <asm/msr.h>
33#include <asm/kvm_para.h>
34#include "mtrr.h"
35
36/* should be related to MTRR_VAR_RANGES nums */
37#define RANGE_NUM 256
38
39struct res_range {
40 unsigned long start;
41 unsigned long end;
42};
43
44static int __init
45add_range(struct res_range *range, int nr_range, unsigned long start,
46 unsigned long end)
47{
48 /* out of slots */
49 if (nr_range >= RANGE_NUM)
50 return nr_range;
51
52 range[nr_range].start = start;
53 range[nr_range].end = end;
54
55 nr_range++;
56
57 return nr_range;
58}
59
60static int __init
61add_range_with_merge(struct res_range *range, int nr_range, unsigned long start,
62 unsigned long end)
63{
64 int i;
65
66 /* try to merge it with old one */
67 for (i = 0; i < nr_range; i++) {
68 unsigned long final_start, final_end;
69 unsigned long common_start, common_end;
70
71 if (!range[i].end)
72 continue;
73
74 common_start = max(range[i].start, start);
75 common_end = min(range[i].end, end);
76 if (common_start > common_end + 1)
77 continue;
78
79 final_start = min(range[i].start, start);
80 final_end = max(range[i].end, end);
81
82 range[i].start = final_start;
83 range[i].end = final_end;
84 return nr_range;
85 }
86
87 /* need to add that */
88 return add_range(range, nr_range, start, end);
89}
90
91static void __init
92subtract_range(struct res_range *range, unsigned long start, unsigned long end)
93{
94 int i, j;
95
96 for (j = 0; j < RANGE_NUM; j++) {
97 if (!range[j].end)
98 continue;
99
100 if (start <= range[j].start && end >= range[j].end) {
101 range[j].start = 0;
102 range[j].end = 0;
103 continue;
104 }
105
106 if (start <= range[j].start && end < range[j].end &&
107 range[j].start < end + 1) {
108 range[j].start = end + 1;
109 continue;
110 }
111
112
113 if (start > range[j].start && end >= range[j].end &&
114 range[j].end > start - 1) {
115 range[j].end = start - 1;
116 continue;
117 }
118
119 if (start > range[j].start && end < range[j].end) {
120 /* find the new spare */
121 for (i = 0; i < RANGE_NUM; i++) {
122 if (range[i].end == 0)
123 break;
124 }
125 if (i < RANGE_NUM) {
126 range[i].end = range[j].end;
127 range[i].start = end + 1;
128 } else {
129 printk(KERN_ERR "run of slot in ranges\n");
130 }
131 range[j].end = start - 1;
132 continue;
133 }
134 }
135}
136
137static int __init cmp_range(const void *x1, const void *x2)
138{
139 const struct res_range *r1 = x1;
140 const struct res_range *r2 = x2;
141 long start1, start2;
142
143 start1 = r1->start;
144 start2 = r2->start;
145
146 return start1 - start2;
147}
148
149struct var_mtrr_range_state {
150 unsigned long base_pfn;
151 unsigned long size_pfn;
152 mtrr_type type;
153};
154
155static struct var_mtrr_range_state __initdata range_state[RANGE_NUM];
156static int __initdata debug_print;
157
158static int __init
159x86_get_mtrr_mem_range(struct res_range *range, int nr_range,
160 unsigned long extra_remove_base,
161 unsigned long extra_remove_size)
162{
163 unsigned long i, base, size;
164 mtrr_type type;
165
166 for (i = 0; i < num_var_ranges; i++) {
167 type = range_state[i].type;
168 if (type != MTRR_TYPE_WRBACK)
169 continue;
170 base = range_state[i].base_pfn;
171 size = range_state[i].size_pfn;
172 nr_range = add_range_with_merge(range, nr_range, base,
173 base + size - 1);
174 }
175 if (debug_print) {
176 printk(KERN_DEBUG "After WB checking\n");
177 for (i = 0; i < nr_range; i++)
178 printk(KERN_DEBUG "MTRR MAP PFN: %016lx - %016lx\n",
179 range[i].start, range[i].end + 1);
180 }
181
182 /* take out UC ranges */
183 for (i = 0; i < num_var_ranges; i++) {
184 type = range_state[i].type;
185 if (type != MTRR_TYPE_UNCACHABLE &&
186 type != MTRR_TYPE_WRPROT)
187 continue;
188 size = range_state[i].size_pfn;
189 if (!size)
190 continue;
191 base = range_state[i].base_pfn;
192 subtract_range(range, base, base + size - 1);
193 }
194 if (extra_remove_size)
195 subtract_range(range, extra_remove_base,
196 extra_remove_base + extra_remove_size - 1);
197
198 /* get new range num */
199 nr_range = 0;
200 for (i = 0; i < RANGE_NUM; i++) {
201 if (!range[i].end)
202 continue;
203 nr_range++;
204 }
205 if (debug_print) {
206 printk(KERN_DEBUG "After UC checking\n");
207 for (i = 0; i < nr_range; i++)
208 printk(KERN_DEBUG "MTRR MAP PFN: %016lx - %016lx\n",
209 range[i].start, range[i].end + 1);
210 }
211
212 /* sort the ranges */
213 sort(range, nr_range, sizeof(struct res_range), cmp_range, NULL);
214 if (debug_print) {
215 printk(KERN_DEBUG "After sorting\n");
216 for (i = 0; i < nr_range; i++)
217 printk(KERN_DEBUG "MTRR MAP PFN: %016lx - %016lx\n",
218 range[i].start, range[i].end + 1);
219 }
220
221 /* clear those is not used */
222 for (i = nr_range; i < RANGE_NUM; i++)
223 memset(&range[i], 0, sizeof(range[i]));
224
225 return nr_range;
226}
227
228static struct res_range __initdata range[RANGE_NUM];
229static int __initdata nr_range;
230
231#ifdef CONFIG_MTRR_SANITIZER
232
233static unsigned long __init sum_ranges(struct res_range *range, int nr_range)
234{
235 unsigned long sum;
236 int i;
237
238 sum = 0;
239 for (i = 0; i < nr_range; i++)
240 sum += range[i].end + 1 - range[i].start;
241
242 return sum;
243}
244
245static int enable_mtrr_cleanup __initdata =
246 CONFIG_MTRR_SANITIZER_ENABLE_DEFAULT;
247
248static int __init disable_mtrr_cleanup_setup(char *str)
249{
250 enable_mtrr_cleanup = 0;
251 return 0;
252}
253early_param("disable_mtrr_cleanup", disable_mtrr_cleanup_setup);
254
255static int __init enable_mtrr_cleanup_setup(char *str)
256{
257 enable_mtrr_cleanup = 1;
258 return 0;
259}
260early_param("enable_mtrr_cleanup", enable_mtrr_cleanup_setup);
261
262static int __init mtrr_cleanup_debug_setup(char *str)
263{
264 debug_print = 1;
265 return 0;
266}
267early_param("mtrr_cleanup_debug", mtrr_cleanup_debug_setup);
268
269struct var_mtrr_state {
270 unsigned long range_startk;
271 unsigned long range_sizek;
272 unsigned long chunk_sizek;
273 unsigned long gran_sizek;
274 unsigned int reg;
275};
276
277static void __init
278set_var_mtrr(unsigned int reg, unsigned long basek, unsigned long sizek,
279 unsigned char type, unsigned int address_bits)
280{
281 u32 base_lo, base_hi, mask_lo, mask_hi;
282 u64 base, mask;
283
284 if (!sizek) {
285 fill_mtrr_var_range(reg, 0, 0, 0, 0);
286 return;
287 }
288
289 mask = (1ULL << address_bits) - 1;
290 mask &= ~((((u64)sizek) << 10) - 1);
291
292 base = ((u64)basek) << 10;
293
294 base |= type;
295 mask |= 0x800;
296
297 base_lo = base & ((1ULL<<32) - 1);
298 base_hi = base >> 32;
299
300 mask_lo = mask & ((1ULL<<32) - 1);
301 mask_hi = mask >> 32;
302
303 fill_mtrr_var_range(reg, base_lo, base_hi, mask_lo, mask_hi);
304}
305
306static void __init
307save_var_mtrr(unsigned int reg, unsigned long basek, unsigned long sizek,
308 unsigned char type)
309{
310 range_state[reg].base_pfn = basek >> (PAGE_SHIFT - 10);
311 range_state[reg].size_pfn = sizek >> (PAGE_SHIFT - 10);
312 range_state[reg].type = type;
313}
314
315static void __init
316set_var_mtrr_all(unsigned int address_bits)
317{
318 unsigned long basek, sizek;
319 unsigned char type;
320 unsigned int reg;
321
322 for (reg = 0; reg < num_var_ranges; reg++) {
323 basek = range_state[reg].base_pfn << (PAGE_SHIFT - 10);
324 sizek = range_state[reg].size_pfn << (PAGE_SHIFT - 10);
325 type = range_state[reg].type;
326
327 set_var_mtrr(reg, basek, sizek, type, address_bits);
328 }
329}
330
331static unsigned long to_size_factor(unsigned long sizek, char *factorp)
332{
333 char factor;
334 unsigned long base = sizek;
335
336 if (base & ((1<<10) - 1)) {
337 /* not MB alignment */
338 factor = 'K';
339 } else if (base & ((1<<20) - 1)) {
340 factor = 'M';
341 base >>= 10;
342 } else {
343 factor = 'G';
344 base >>= 20;
345 }
346
347 *factorp = factor;
348
349 return base;
350}
351
352static unsigned int __init
353range_to_mtrr(unsigned int reg, unsigned long range_startk,
354 unsigned long range_sizek, unsigned char type)
355{
356 if (!range_sizek || (reg >= num_var_ranges))
357 return reg;
358
359 while (range_sizek) {
360 unsigned long max_align, align;
361 unsigned long sizek;
362
363 /* Compute the maximum size I can make a range */
364 if (range_startk)
365 max_align = ffs(range_startk) - 1;
366 else
367 max_align = 32;
368 align = fls(range_sizek) - 1;
369 if (align > max_align)
370 align = max_align;
371
372 sizek = 1 << align;
373 if (debug_print) {
374 char start_factor = 'K', size_factor = 'K';
375 unsigned long start_base, size_base;
376
377 start_base = to_size_factor(range_startk,
378 &start_factor),
379 size_base = to_size_factor(sizek, &size_factor),
380
381 printk(KERN_DEBUG "Setting variable MTRR %d, "
382 "base: %ld%cB, range: %ld%cB, type %s\n",
383 reg, start_base, start_factor,
384 size_base, size_factor,
385 (type == MTRR_TYPE_UNCACHABLE) ? "UC" :
386 ((type == MTRR_TYPE_WRBACK) ? "WB" : "Other")
387 );
388 }
389 save_var_mtrr(reg++, range_startk, sizek, type);
390 range_startk += sizek;
391 range_sizek -= sizek;
392 if (reg >= num_var_ranges)
393 break;
394 }
395 return reg;
396}
397
398static unsigned __init
399range_to_mtrr_with_hole(struct var_mtrr_state *state, unsigned long basek,
400 unsigned long sizek)
401{
402 unsigned long hole_basek, hole_sizek;
403 unsigned long second_basek, second_sizek;
404 unsigned long range0_basek, range0_sizek;
405 unsigned long range_basek, range_sizek;
406 unsigned long chunk_sizek;
407 unsigned long gran_sizek;
408
409 hole_basek = 0;
410 hole_sizek = 0;
411 second_basek = 0;
412 second_sizek = 0;
413 chunk_sizek = state->chunk_sizek;
414 gran_sizek = state->gran_sizek;
415
416 /* align with gran size, prevent small block used up MTRRs */
417 range_basek = ALIGN(state->range_startk, gran_sizek);
418 if ((range_basek > basek) && basek)
419 return second_sizek;
420 state->range_sizek -= (range_basek - state->range_startk);
421 range_sizek = ALIGN(state->range_sizek, gran_sizek);
422
423 while (range_sizek > state->range_sizek) {
424 range_sizek -= gran_sizek;
425 if (!range_sizek)
426 return 0;
427 }
428 state->range_sizek = range_sizek;
429
430 /* try to append some small hole */
431 range0_basek = state->range_startk;
432 range0_sizek = ALIGN(state->range_sizek, chunk_sizek);
433
434 /* no increase */
435 if (range0_sizek == state->range_sizek) {
436 if (debug_print)
437 printk(KERN_DEBUG "rangeX: %016lx - %016lx\n",
438 range0_basek<<10,
439 (range0_basek + state->range_sizek)<<10);
440 state->reg = range_to_mtrr(state->reg, range0_basek,
441 state->range_sizek, MTRR_TYPE_WRBACK);
442 return 0;
443 }
444
445 /* only cut back, when it is not the last */
446 if (sizek) {
447 while (range0_basek + range0_sizek > (basek + sizek)) {
448 if (range0_sizek >= chunk_sizek)
449 range0_sizek -= chunk_sizek;
450 else
451 range0_sizek = 0;
452
453 if (!range0_sizek)
454 break;
455 }
456 }
457
458second_try:
459 range_basek = range0_basek + range0_sizek;
460
461 /* one hole in the middle */
462 if (range_basek > basek && range_basek <= (basek + sizek))
463 second_sizek = range_basek - basek;
464
465 if (range0_sizek > state->range_sizek) {
466
467 /* one hole in middle or at end */
468 hole_sizek = range0_sizek - state->range_sizek - second_sizek;
469
470 /* hole size should be less than half of range0 size */
471 if (hole_sizek >= (range0_sizek >> 1) &&
472 range0_sizek >= chunk_sizek) {
473 range0_sizek -= chunk_sizek;
474 second_sizek = 0;
475 hole_sizek = 0;
476
477 goto second_try;
478 }
479 }
480
481 if (range0_sizek) {
482 if (debug_print)
483 printk(KERN_DEBUG "range0: %016lx - %016lx\n",
484 range0_basek<<10,
485 (range0_basek + range0_sizek)<<10);
486 state->reg = range_to_mtrr(state->reg, range0_basek,
487 range0_sizek, MTRR_TYPE_WRBACK);
488 }
489
490 if (range0_sizek < state->range_sizek) {
491 /* need to handle left over */
492 range_sizek = state->range_sizek - range0_sizek;
493
494 if (debug_print)
495 printk(KERN_DEBUG "range: %016lx - %016lx\n",
496 range_basek<<10,
497 (range_basek + range_sizek)<<10);
498 state->reg = range_to_mtrr(state->reg, range_basek,
499 range_sizek, MTRR_TYPE_WRBACK);
500 }
501
502 if (hole_sizek) {
503 hole_basek = range_basek - hole_sizek - second_sizek;
504 if (debug_print)
505 printk(KERN_DEBUG "hole: %016lx - %016lx\n",
506 hole_basek<<10,
507 (hole_basek + hole_sizek)<<10);
508 state->reg = range_to_mtrr(state->reg, hole_basek,
509 hole_sizek, MTRR_TYPE_UNCACHABLE);
510 }
511
512 return second_sizek;
513}
514
515static void __init
516set_var_mtrr_range(struct var_mtrr_state *state, unsigned long base_pfn,
517 unsigned long size_pfn)
518{
519 unsigned long basek, sizek;
520 unsigned long second_sizek = 0;
521
522 if (state->reg >= num_var_ranges)
523 return;
524
525 basek = base_pfn << (PAGE_SHIFT - 10);
526 sizek = size_pfn << (PAGE_SHIFT - 10);
527
528 /* See if I can merge with the last range */
529 if ((basek <= 1024) ||
530 (state->range_startk + state->range_sizek == basek)) {
531 unsigned long endk = basek + sizek;
532 state->range_sizek = endk - state->range_startk;
533 return;
534 }
535 /* Write the range mtrrs */
536 if (state->range_sizek != 0)
537 second_sizek = range_to_mtrr_with_hole(state, basek, sizek);
538
539 /* Allocate an msr */
540 state->range_startk = basek + second_sizek;
541 state->range_sizek = sizek - second_sizek;
542}
543
544/* mininum size of mtrr block that can take hole */
545static u64 mtrr_chunk_size __initdata = (256ULL<<20);
546
547static int __init parse_mtrr_chunk_size_opt(char *p)
548{
549 if (!p)
550 return -EINVAL;
551 mtrr_chunk_size = memparse(p, &p);
552 return 0;
553}
554early_param("mtrr_chunk_size", parse_mtrr_chunk_size_opt);
555
556/* granity of mtrr of block */
557static u64 mtrr_gran_size __initdata;
558
559static int __init parse_mtrr_gran_size_opt(char *p)
560{
561 if (!p)
562 return -EINVAL;
563 mtrr_gran_size = memparse(p, &p);
564 return 0;
565}
566early_param("mtrr_gran_size", parse_mtrr_gran_size_opt);
567
568static int nr_mtrr_spare_reg __initdata =
569 CONFIG_MTRR_SANITIZER_SPARE_REG_NR_DEFAULT;
570
571static int __init parse_mtrr_spare_reg(char *arg)
572{
573 if (arg)
574 nr_mtrr_spare_reg = simple_strtoul(arg, NULL, 0);
575 return 0;
576}
577
578early_param("mtrr_spare_reg_nr", parse_mtrr_spare_reg);
579
580static int __init
581x86_setup_var_mtrrs(struct res_range *range, int nr_range,
582 u64 chunk_size, u64 gran_size)
583{
584 struct var_mtrr_state var_state;
585 int i;
586 int num_reg;
587
588 var_state.range_startk = 0;
589 var_state.range_sizek = 0;
590 var_state.reg = 0;
591 var_state.chunk_sizek = chunk_size >> 10;
592 var_state.gran_sizek = gran_size >> 10;
593
594 memset(range_state, 0, sizeof(range_state));
595
596 /* Write the range etc */
597 for (i = 0; i < nr_range; i++)
598 set_var_mtrr_range(&var_state, range[i].start,
599 range[i].end - range[i].start + 1);
600
601 /* Write the last range */
602 if (var_state.range_sizek != 0)
603 range_to_mtrr_with_hole(&var_state, 0, 0);
604
605 num_reg = var_state.reg;
606 /* Clear out the extra MTRR's */
607 while (var_state.reg < num_var_ranges) {
608 save_var_mtrr(var_state.reg, 0, 0, 0);
609 var_state.reg++;
610 }
611
612 return num_reg;
613}
614
615struct mtrr_cleanup_result {
616 unsigned long gran_sizek;
617 unsigned long chunk_sizek;
618 unsigned long lose_cover_sizek;
619 unsigned int num_reg;
620 int bad;
621};
622
623/*
624 * gran_size: 64K, 128K, 256K, 512K, 1M, 2M, ..., 2G
625 * chunk size: gran_size, ..., 2G
626 * so we need (1+16)*8
627 */
628#define NUM_RESULT 136
629#define PSHIFT (PAGE_SHIFT - 10)
630
631static struct mtrr_cleanup_result __initdata result[NUM_RESULT];
632static unsigned long __initdata min_loss_pfn[RANGE_NUM];
633
634static void __init print_out_mtrr_range_state(void)
635{
636 int i;
637 char start_factor = 'K', size_factor = 'K';
638 unsigned long start_base, size_base;
639 mtrr_type type;
640
641 for (i = 0; i < num_var_ranges; i++) {
642
643 size_base = range_state[i].size_pfn << (PAGE_SHIFT - 10);
644 if (!size_base)
645 continue;
646
647 size_base = to_size_factor(size_base, &size_factor),
648 start_base = range_state[i].base_pfn << (PAGE_SHIFT - 10);
649 start_base = to_size_factor(start_base, &start_factor),
650 type = range_state[i].type;
651
652 printk(KERN_DEBUG "reg %d, base: %ld%cB, range: %ld%cB, type %s\n",
653 i, start_base, start_factor,
654 size_base, size_factor,
655 (type == MTRR_TYPE_UNCACHABLE) ? "UC" :
656 ((type == MTRR_TYPE_WRPROT) ? "WP" :
657 ((type == MTRR_TYPE_WRBACK) ? "WB" : "Other"))
658 );
659 }
660}
661
662static int __init mtrr_need_cleanup(void)
663{
664 int i;
665 mtrr_type type;
666 unsigned long size;
667 /* extra one for all 0 */
668 int num[MTRR_NUM_TYPES + 1];
669
670 /* check entries number */
671 memset(num, 0, sizeof(num));
672 for (i = 0; i < num_var_ranges; i++) {
673 type = range_state[i].type;
674 size = range_state[i].size_pfn;
675 if (type >= MTRR_NUM_TYPES)
676 continue;
677 if (!size)
678 type = MTRR_NUM_TYPES;
679 if (type == MTRR_TYPE_WRPROT)
680 type = MTRR_TYPE_UNCACHABLE;
681 num[type]++;
682 }
683
684 /* check if we got UC entries */
685 if (!num[MTRR_TYPE_UNCACHABLE])
686 return 0;
687
688 /* check if we only had WB and UC */
689 if (num[MTRR_TYPE_WRBACK] + num[MTRR_TYPE_UNCACHABLE] !=
690 num_var_ranges - num[MTRR_NUM_TYPES])
691 return 0;
692
693 return 1;
694}
695
696static unsigned long __initdata range_sums;
697static void __init mtrr_calc_range_state(u64 chunk_size, u64 gran_size,
698 unsigned long extra_remove_base,
699 unsigned long extra_remove_size,
700 int i)
701{
702 int num_reg;
703 static struct res_range range_new[RANGE_NUM];
704 static int nr_range_new;
705 unsigned long range_sums_new;
706
707 /* convert ranges to var ranges state */
708 num_reg = x86_setup_var_mtrrs(range, nr_range,
709 chunk_size, gran_size);
710
711 /* we got new setting in range_state, check it */
712 memset(range_new, 0, sizeof(range_new));
713 nr_range_new = x86_get_mtrr_mem_range(range_new, 0,
714 extra_remove_base, extra_remove_size);
715 range_sums_new = sum_ranges(range_new, nr_range_new);
716
717 result[i].chunk_sizek = chunk_size >> 10;
718 result[i].gran_sizek = gran_size >> 10;
719 result[i].num_reg = num_reg;
720 if (range_sums < range_sums_new) {
721 result[i].lose_cover_sizek =
722 (range_sums_new - range_sums) << PSHIFT;
723 result[i].bad = 1;
724 } else
725 result[i].lose_cover_sizek =
726 (range_sums - range_sums_new) << PSHIFT;
727
728 /* double check it */
729 if (!result[i].bad && !result[i].lose_cover_sizek) {
730 if (nr_range_new != nr_range ||
731 memcmp(range, range_new, sizeof(range)))
732 result[i].bad = 1;
733 }
734
735 if (!result[i].bad && (range_sums - range_sums_new <
736 min_loss_pfn[num_reg])) {
737 min_loss_pfn[num_reg] =
738 range_sums - range_sums_new;
739 }
740}
741
742static void __init mtrr_print_out_one_result(int i)
743{
744 char gran_factor, chunk_factor, lose_factor;
745 unsigned long gran_base, chunk_base, lose_base;
746
747 gran_base = to_size_factor(result[i].gran_sizek, &gran_factor),
748 chunk_base = to_size_factor(result[i].chunk_sizek, &chunk_factor),
749 lose_base = to_size_factor(result[i].lose_cover_sizek, &lose_factor),
750 printk(KERN_INFO "%sgran_size: %ld%c \tchunk_size: %ld%c \t",
751 result[i].bad ? "*BAD*" : " ",
752 gran_base, gran_factor, chunk_base, chunk_factor);
753 printk(KERN_CONT "num_reg: %d \tlose cover RAM: %s%ld%c\n",
754 result[i].num_reg, result[i].bad ? "-" : "",
755 lose_base, lose_factor);
756}
757
758static int __init mtrr_search_optimal_index(void)
759{
760 int i;
761 int num_reg_good;
762 int index_good;
763
764 if (nr_mtrr_spare_reg >= num_var_ranges)
765 nr_mtrr_spare_reg = num_var_ranges - 1;
766 num_reg_good = -1;
767 for (i = num_var_ranges - nr_mtrr_spare_reg; i > 0; i--) {
768 if (!min_loss_pfn[i])
769 num_reg_good = i;
770 }
771
772 index_good = -1;
773 if (num_reg_good != -1) {
774 for (i = 0; i < NUM_RESULT; i++) {
775 if (!result[i].bad &&
776 result[i].num_reg == num_reg_good &&
777 !result[i].lose_cover_sizek) {
778 index_good = i;
779 break;
780 }
781 }
782 }
783
784 return index_good;
785}
786
787
788int __init mtrr_cleanup(unsigned address_bits)
789{
790 unsigned long extra_remove_base, extra_remove_size;
791 unsigned long base, size, def, dummy;
792 mtrr_type type;
793 u64 chunk_size, gran_size;
794 int index_good;
795 int i;
796
797 if (!is_cpu(INTEL) || enable_mtrr_cleanup < 1)
798 return 0;
799 rdmsr(MTRRdefType_MSR, def, dummy);
800 def &= 0xff;
801 if (def != MTRR_TYPE_UNCACHABLE)
802 return 0;
803
804 /* get it and store it aside */
805 memset(range_state, 0, sizeof(range_state));
806 for (i = 0; i < num_var_ranges; i++) {
807 mtrr_if->get(i, &base, &size, &type);
808 range_state[i].base_pfn = base;
809 range_state[i].size_pfn = size;
810 range_state[i].type = type;
811 }
812
813 /* check if we need handle it and can handle it */
814 if (!mtrr_need_cleanup())
815 return 0;
816
817 /* print original var MTRRs at first, for debugging: */
818 printk(KERN_DEBUG "original variable MTRRs\n");
819 print_out_mtrr_range_state();
820
821 memset(range, 0, sizeof(range));
822 extra_remove_size = 0;
823 extra_remove_base = 1 << (32 - PAGE_SHIFT);
824 if (mtrr_tom2)
825 extra_remove_size =
826 (mtrr_tom2 >> PAGE_SHIFT) - extra_remove_base;
827 nr_range = x86_get_mtrr_mem_range(range, 0, extra_remove_base,
828 extra_remove_size);
829 /*
830 * [0, 1M) should always be coverred by var mtrr with WB
831 * and fixed mtrrs should take effective before var mtrr for it
832 */
833 nr_range = add_range_with_merge(range, nr_range, 0,
834 (1ULL<<(20 - PAGE_SHIFT)) - 1);
835 /* sort the ranges */
836 sort(range, nr_range, sizeof(struct res_range), cmp_range, NULL);
837
838 range_sums = sum_ranges(range, nr_range);
839 printk(KERN_INFO "total RAM coverred: %ldM\n",
840 range_sums >> (20 - PAGE_SHIFT));
841
842 if (mtrr_chunk_size && mtrr_gran_size) {
843 i = 0;
844 mtrr_calc_range_state(mtrr_chunk_size, mtrr_gran_size,
845 extra_remove_base, extra_remove_size, i);
846
847 mtrr_print_out_one_result(i);
848
849 if (!result[i].bad) {
850 set_var_mtrr_all(address_bits);
851 printk(KERN_DEBUG "New variable MTRRs\n");
852 print_out_mtrr_range_state();
853 return 1;
854 }
855 printk(KERN_INFO "invalid mtrr_gran_size or mtrr_chunk_size, "
856 "will find optimal one\n");
857 }
858
859 i = 0;
860 memset(min_loss_pfn, 0xff, sizeof(min_loss_pfn));
861 memset(result, 0, sizeof(result));
862 for (gran_size = (1ULL<<16); gran_size < (1ULL<<32); gran_size <<= 1) {
863
864 for (chunk_size = gran_size; chunk_size < (1ULL<<32);
865 chunk_size <<= 1) {
866
867 if (i >= NUM_RESULT)
868 continue;
869
870 mtrr_calc_range_state(chunk_size, gran_size,
871 extra_remove_base, extra_remove_size, i);
872 if (debug_print) {
873 mtrr_print_out_one_result(i);
874 printk(KERN_INFO "\n");
875 }
876
877 i++;
878 }
879 }
880
881 /* try to find the optimal index */
882 index_good = mtrr_search_optimal_index();
883
884 if (index_good != -1) {
885 printk(KERN_INFO "Found optimal setting for mtrr clean up\n");
886 i = index_good;
887 mtrr_print_out_one_result(i);
888
889 /* convert ranges to var ranges state */
890 chunk_size = result[i].chunk_sizek;
891 chunk_size <<= 10;
892 gran_size = result[i].gran_sizek;
893 gran_size <<= 10;
894 x86_setup_var_mtrrs(range, nr_range, chunk_size, gran_size);
895 set_var_mtrr_all(address_bits);
896 printk(KERN_DEBUG "New variable MTRRs\n");
897 print_out_mtrr_range_state();
898 return 1;
899 } else {
900 /* print out all */
901 for (i = 0; i < NUM_RESULT; i++)
902 mtrr_print_out_one_result(i);
903 }
904
905 printk(KERN_INFO "mtrr_cleanup: can not find optimal value\n");
906 printk(KERN_INFO "please specify mtrr_gran_size/mtrr_chunk_size\n");
907
908 return 0;
909}
910#else
911int __init mtrr_cleanup(unsigned address_bits)
912{
913 return 0;
914}
915#endif
916
917static int disable_mtrr_trim;
918
919static int __init disable_mtrr_trim_setup(char *str)
920{
921 disable_mtrr_trim = 1;
922 return 0;
923}
924early_param("disable_mtrr_trim", disable_mtrr_trim_setup);
925
926/*
927 * Newer AMD K8s and later CPUs have a special magic MSR way to force WB
928 * for memory >4GB. Check for that here.
929 * Note this won't check if the MTRRs < 4GB where the magic bit doesn't
930 * apply to are wrong, but so far we don't know of any such case in the wild.
931 */
932#define Tom2Enabled (1U << 21)
933#define Tom2ForceMemTypeWB (1U << 22)
934
935int __init amd_special_default_mtrr(void)
936{
937 u32 l, h;
938
939 if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD)
940 return 0;
941 if (boot_cpu_data.x86 < 0xf || boot_cpu_data.x86 > 0x11)
942 return 0;
943 /* In case some hypervisor doesn't pass SYSCFG through */
944 if (rdmsr_safe(MSR_K8_SYSCFG, &l, &h) < 0)
945 return 0;
946 /*
947 * Memory between 4GB and top of mem is forced WB by this magic bit.
948 * Reserved before K8RevF, but should be zero there.
949 */
950 if ((l & (Tom2Enabled | Tom2ForceMemTypeWB)) ==
951 (Tom2Enabled | Tom2ForceMemTypeWB))
952 return 1;
953 return 0;
954}
955
956static u64 __init real_trim_memory(unsigned long start_pfn,
957 unsigned long limit_pfn)
958{
959 u64 trim_start, trim_size;
960 trim_start = start_pfn;
961 trim_start <<= PAGE_SHIFT;
962 trim_size = limit_pfn;
963 trim_size <<= PAGE_SHIFT;
964 trim_size -= trim_start;
965
966 return e820_update_range(trim_start, trim_size, E820_RAM,
967 E820_RESERVED);
968}
969/**
970 * mtrr_trim_uncached_memory - trim RAM not covered by MTRRs
971 * @end_pfn: ending page frame number
972 *
973 * Some buggy BIOSes don't setup the MTRRs properly for systems with certain
974 * memory configurations. This routine checks that the highest MTRR matches
975 * the end of memory, to make sure the MTRRs having a write back type cover
976 * all of the memory the kernel is intending to use. If not, it'll trim any
977 * memory off the end by adjusting end_pfn, removing it from the kernel's
978 * allocation pools, warning the user with an obnoxious message.
979 */
980int __init mtrr_trim_uncached_memory(unsigned long end_pfn)
981{
982 unsigned long i, base, size, highest_pfn = 0, def, dummy;
983 mtrr_type type;
984 u64 total_trim_size;
985
986 /* extra one for all 0 */
987 int num[MTRR_NUM_TYPES + 1];
988 /*
989 * Make sure we only trim uncachable memory on machines that
990 * support the Intel MTRR architecture:
991 */
992 if (!is_cpu(INTEL) || disable_mtrr_trim)
993 return 0;
994 rdmsr(MTRRdefType_MSR, def, dummy);
995 def &= 0xff;
996 if (def != MTRR_TYPE_UNCACHABLE)
997 return 0;
998
999 /* get it and store it aside */
1000 memset(range_state, 0, sizeof(range_state));
1001 for (i = 0; i < num_var_ranges; i++) {
1002 mtrr_if->get(i, &base, &size, &type);
1003 range_state[i].base_pfn = base;
1004 range_state[i].size_pfn = size;
1005 range_state[i].type = type;
1006 }
1007
1008 /* Find highest cached pfn */
1009 for (i = 0; i < num_var_ranges; i++) {
1010 type = range_state[i].type;
1011 if (type != MTRR_TYPE_WRBACK)
1012 continue;
1013 base = range_state[i].base_pfn;
1014 size = range_state[i].size_pfn;
1015 if (highest_pfn < base + size)
1016 highest_pfn = base + size;
1017 }
1018
1019 /* kvm/qemu doesn't have mtrr set right, don't trim them all */
1020 if (!highest_pfn) {
1021 printk(KERN_INFO "CPU MTRRs all blank - virtualized system.\n");
1022 return 0;
1023 }
1024
1025 /* check entries number */
1026 memset(num, 0, sizeof(num));
1027 for (i = 0; i < num_var_ranges; i++) {
1028 type = range_state[i].type;
1029 if (type >= MTRR_NUM_TYPES)
1030 continue;
1031 size = range_state[i].size_pfn;
1032 if (!size)
1033 type = MTRR_NUM_TYPES;
1034 num[type]++;
1035 }
1036
1037 /* no entry for WB? */
1038 if (!num[MTRR_TYPE_WRBACK])
1039 return 0;
1040
1041 /* check if we only had WB and UC */
1042 if (num[MTRR_TYPE_WRBACK] + num[MTRR_TYPE_UNCACHABLE] !=
1043 num_var_ranges - num[MTRR_NUM_TYPES])
1044 return 0;
1045
1046 memset(range, 0, sizeof(range));
1047 nr_range = 0;
1048 if (mtrr_tom2) {
1049 range[nr_range].start = (1ULL<<(32 - PAGE_SHIFT));
1050 range[nr_range].end = (mtrr_tom2 >> PAGE_SHIFT) - 1;
1051 if (highest_pfn < range[nr_range].end + 1)
1052 highest_pfn = range[nr_range].end + 1;
1053 nr_range++;
1054 }
1055 nr_range = x86_get_mtrr_mem_range(range, nr_range, 0, 0);
1056
1057 total_trim_size = 0;
1058 /* check the head */
1059 if (range[0].start)
1060 total_trim_size += real_trim_memory(0, range[0].start);
1061 /* check the holes */
1062 for (i = 0; i < nr_range - 1; i++) {
1063 if (range[i].end + 1 < range[i+1].start)
1064 total_trim_size += real_trim_memory(range[i].end + 1,
1065 range[i+1].start);
1066 }
1067 /* check the top */
1068 i = nr_range - 1;
1069 if (range[i].end + 1 < end_pfn)
1070 total_trim_size += real_trim_memory(range[i].end + 1,
1071 end_pfn);
1072
1073 if (total_trim_size) {
1074 printk(KERN_WARNING "WARNING: BIOS bug: CPU MTRRs don't cover"
1075 " all of memory, losing %lluMB of RAM.\n",
1076 total_trim_size >> 20);
1077
1078 if (!changed_by_mtrr_cleanup)
1079 WARN_ON(1);
1080
1081 printk(KERN_INFO "update e820 for mtrr\n");
1082 update_e820();
1083
1084 return 1;
1085 }
1086
1087 return 0;
1088}
1089
diff --git a/arch/x86/kernel/cpu/mtrr/main.c b/arch/x86/kernel/cpu/mtrr/main.c
index 311a4734609b..5c2e266f41d7 100644
--- a/arch/x86/kernel/cpu/mtrr/main.c
+++ b/arch/x86/kernel/cpu/mtrr/main.c
@@ -610,1060 +610,7 @@ static struct sysdev_driver mtrr_sysdev_driver = {
610 .resume = mtrr_restore, 610 .resume = mtrr_restore,
611}; 611};
612 612
613/* should be related to MTRR_VAR_RANGES nums */ 613int __initdata changed_by_mtrr_cleanup;
614#define RANGE_NUM 256
615
616struct res_range {
617 unsigned long start;
618 unsigned long end;
619};
620
621static int __init
622add_range(struct res_range *range, int nr_range, unsigned long start,
623 unsigned long end)
624{
625 /* out of slots */
626 if (nr_range >= RANGE_NUM)
627 return nr_range;
628
629 range[nr_range].start = start;
630 range[nr_range].end = end;
631
632 nr_range++;
633
634 return nr_range;
635}
636
637static int __init
638add_range_with_merge(struct res_range *range, int nr_range, unsigned long start,
639 unsigned long end)
640{
641 int i;
642
643 /* try to merge it with old one */
644 for (i = 0; i < nr_range; i++) {
645 unsigned long final_start, final_end;
646 unsigned long common_start, common_end;
647
648 if (!range[i].end)
649 continue;
650
651 common_start = max(range[i].start, start);
652 common_end = min(range[i].end, end);
653 if (common_start > common_end + 1)
654 continue;
655
656 final_start = min(range[i].start, start);
657 final_end = max(range[i].end, end);
658
659 range[i].start = final_start;
660 range[i].end = final_end;
661 return nr_range;
662 }
663
664 /* need to add that */
665 return add_range(range, nr_range, start, end);
666}
667
668static void __init
669subtract_range(struct res_range *range, unsigned long start, unsigned long end)
670{
671 int i, j;
672
673 for (j = 0; j < RANGE_NUM; j++) {
674 if (!range[j].end)
675 continue;
676
677 if (start <= range[j].start && end >= range[j].end) {
678 range[j].start = 0;
679 range[j].end = 0;
680 continue;
681 }
682
683 if (start <= range[j].start && end < range[j].end &&
684 range[j].start < end + 1) {
685 range[j].start = end + 1;
686 continue;
687 }
688
689
690 if (start > range[j].start && end >= range[j].end &&
691 range[j].end > start - 1) {
692 range[j].end = start - 1;
693 continue;
694 }
695
696 if (start > range[j].start && end < range[j].end) {
697 /* find the new spare */
698 for (i = 0; i < RANGE_NUM; i++) {
699 if (range[i].end == 0)
700 break;
701 }
702 if (i < RANGE_NUM) {
703 range[i].end = range[j].end;
704 range[i].start = end + 1;
705 } else {
706 printk(KERN_ERR "run of slot in ranges\n");
707 }
708 range[j].end = start - 1;
709 continue;
710 }
711 }
712}
713
714static int __init cmp_range(const void *x1, const void *x2)
715{
716 const struct res_range *r1 = x1;
717 const struct res_range *r2 = x2;
718 long start1, start2;
719
720 start1 = r1->start;
721 start2 = r2->start;
722
723 return start1 - start2;
724}
725
726struct var_mtrr_range_state {
727 unsigned long base_pfn;
728 unsigned long size_pfn;
729 mtrr_type type;
730};
731
732static struct var_mtrr_range_state __initdata range_state[RANGE_NUM];
733static int __initdata debug_print;
734
735static int __init
736x86_get_mtrr_mem_range(struct res_range *range, int nr_range,
737 unsigned long extra_remove_base,
738 unsigned long extra_remove_size)
739{
740 unsigned long i, base, size;
741 mtrr_type type;
742
743 for (i = 0; i < num_var_ranges; i++) {
744 type = range_state[i].type;
745 if (type != MTRR_TYPE_WRBACK)
746 continue;
747 base = range_state[i].base_pfn;
748 size = range_state[i].size_pfn;
749 nr_range = add_range_with_merge(range, nr_range, base,
750 base + size - 1);
751 }
752 if (debug_print) {
753 printk(KERN_DEBUG "After WB checking\n");
754 for (i = 0; i < nr_range; i++)
755 printk(KERN_DEBUG "MTRR MAP PFN: %016lx - %016lx\n",
756 range[i].start, range[i].end + 1);
757 }
758
759 /* take out UC ranges */
760 for (i = 0; i < num_var_ranges; i++) {
761 type = range_state[i].type;
762 if (type != MTRR_TYPE_UNCACHABLE &&
763 type != MTRR_TYPE_WRPROT)
764 continue;
765 size = range_state[i].size_pfn;
766 if (!size)
767 continue;
768 base = range_state[i].base_pfn;
769 subtract_range(range, base, base + size - 1);
770 }
771 if (extra_remove_size)
772 subtract_range(range, extra_remove_base,
773 extra_remove_base + extra_remove_size - 1);
774
775 /* get new range num */
776 nr_range = 0;
777 for (i = 0; i < RANGE_NUM; i++) {
778 if (!range[i].end)
779 continue;
780 nr_range++;
781 }
782 if (debug_print) {
783 printk(KERN_DEBUG "After UC checking\n");
784 for (i = 0; i < nr_range; i++)
785 printk(KERN_DEBUG "MTRR MAP PFN: %016lx - %016lx\n",
786 range[i].start, range[i].end + 1);
787 }
788
789 /* sort the ranges */
790 sort(range, nr_range, sizeof(struct res_range), cmp_range, NULL);
791 if (debug_print) {
792 printk(KERN_DEBUG "After sorting\n");
793 for (i = 0; i < nr_range; i++)
794 printk(KERN_DEBUG "MTRR MAP PFN: %016lx - %016lx\n",
795 range[i].start, range[i].end + 1);
796 }
797
798 /* clear those is not used */
799 for (i = nr_range; i < RANGE_NUM; i++)
800 memset(&range[i], 0, sizeof(range[i]));
801
802 return nr_range;
803}
804
805static struct res_range __initdata range[RANGE_NUM];
806static int __initdata nr_range;
807
808#ifdef CONFIG_MTRR_SANITIZER
809
810static unsigned long __init sum_ranges(struct res_range *range, int nr_range)
811{
812 unsigned long sum;
813 int i;
814
815 sum = 0;
816 for (i = 0; i < nr_range; i++)
817 sum += range[i].end + 1 - range[i].start;
818
819 return sum;
820}
821
822static int enable_mtrr_cleanup __initdata =
823 CONFIG_MTRR_SANITIZER_ENABLE_DEFAULT;
824
825static int __init disable_mtrr_cleanup_setup(char *str)
826{
827 enable_mtrr_cleanup = 0;
828 return 0;
829}
830early_param("disable_mtrr_cleanup", disable_mtrr_cleanup_setup);
831
832static int __init enable_mtrr_cleanup_setup(char *str)
833{
834 enable_mtrr_cleanup = 1;
835 return 0;
836}
837early_param("enable_mtrr_cleanup", enable_mtrr_cleanup_setup);
838
839static int __init mtrr_cleanup_debug_setup(char *str)
840{
841 debug_print = 1;
842 return 0;
843}
844early_param("mtrr_cleanup_debug", mtrr_cleanup_debug_setup);
845
846struct var_mtrr_state {
847 unsigned long range_startk;
848 unsigned long range_sizek;
849 unsigned long chunk_sizek;
850 unsigned long gran_sizek;
851 unsigned int reg;
852};
853
854static void __init
855set_var_mtrr(unsigned int reg, unsigned long basek, unsigned long sizek,
856 unsigned char type, unsigned int address_bits)
857{
858 u32 base_lo, base_hi, mask_lo, mask_hi;
859 u64 base, mask;
860
861 if (!sizek) {
862 fill_mtrr_var_range(reg, 0, 0, 0, 0);
863 return;
864 }
865
866 mask = (1ULL << address_bits) - 1;
867 mask &= ~((((u64)sizek) << 10) - 1);
868
869 base = ((u64)basek) << 10;
870
871 base |= type;
872 mask |= 0x800;
873
874 base_lo = base & ((1ULL<<32) - 1);
875 base_hi = base >> 32;
876
877 mask_lo = mask & ((1ULL<<32) - 1);
878 mask_hi = mask >> 32;
879
880 fill_mtrr_var_range(reg, base_lo, base_hi, mask_lo, mask_hi);
881}
882
883static void __init
884save_var_mtrr(unsigned int reg, unsigned long basek, unsigned long sizek,
885 unsigned char type)
886{
887 range_state[reg].base_pfn = basek >> (PAGE_SHIFT - 10);
888 range_state[reg].size_pfn = sizek >> (PAGE_SHIFT - 10);
889 range_state[reg].type = type;
890}
891
892static void __init
893set_var_mtrr_all(unsigned int address_bits)
894{
895 unsigned long basek, sizek;
896 unsigned char type;
897 unsigned int reg;
898
899 for (reg = 0; reg < num_var_ranges; reg++) {
900 basek = range_state[reg].base_pfn << (PAGE_SHIFT - 10);
901 sizek = range_state[reg].size_pfn << (PAGE_SHIFT - 10);
902 type = range_state[reg].type;
903
904 set_var_mtrr(reg, basek, sizek, type, address_bits);
905 }
906}
907
908static unsigned long to_size_factor(unsigned long sizek, char *factorp)
909{
910 char factor;
911 unsigned long base = sizek;
912
913 if (base & ((1<<10) - 1)) {
914 /* not MB alignment */
915 factor = 'K';
916 } else if (base & ((1<<20) - 1)){
917 factor = 'M';
918 base >>= 10;
919 } else {
920 factor = 'G';
921 base >>= 20;
922 }
923
924 *factorp = factor;
925
926 return base;
927}
928
929static unsigned int __init
930range_to_mtrr(unsigned int reg, unsigned long range_startk,
931 unsigned long range_sizek, unsigned char type)
932{
933 if (!range_sizek || (reg >= num_var_ranges))
934 return reg;
935
936 while (range_sizek) {
937 unsigned long max_align, align;
938 unsigned long sizek;
939
940 /* Compute the maximum size I can make a range */
941 if (range_startk)
942 max_align = ffs(range_startk) - 1;
943 else
944 max_align = 32;
945 align = fls(range_sizek) - 1;
946 if (align > max_align)
947 align = max_align;
948
949 sizek = 1 << align;
950 if (debug_print) {
951 char start_factor = 'K', size_factor = 'K';
952 unsigned long start_base, size_base;
953
954 start_base = to_size_factor(range_startk, &start_factor),
955 size_base = to_size_factor(sizek, &size_factor),
956
957 printk(KERN_DEBUG "Setting variable MTRR %d, "
958 "base: %ld%cB, range: %ld%cB, type %s\n",
959 reg, start_base, start_factor,
960 size_base, size_factor,
961 (type == MTRR_TYPE_UNCACHABLE)?"UC":
962 ((type == MTRR_TYPE_WRBACK)?"WB":"Other")
963 );
964 }
965 save_var_mtrr(reg++, range_startk, sizek, type);
966 range_startk += sizek;
967 range_sizek -= sizek;
968 if (reg >= num_var_ranges)
969 break;
970 }
971 return reg;
972}
973
974static unsigned __init
975range_to_mtrr_with_hole(struct var_mtrr_state *state, unsigned long basek,
976 unsigned long sizek)
977{
978 unsigned long hole_basek, hole_sizek;
979 unsigned long second_basek, second_sizek;
980 unsigned long range0_basek, range0_sizek;
981 unsigned long range_basek, range_sizek;
982 unsigned long chunk_sizek;
983 unsigned long gran_sizek;
984
985 hole_basek = 0;
986 hole_sizek = 0;
987 second_basek = 0;
988 second_sizek = 0;
989 chunk_sizek = state->chunk_sizek;
990 gran_sizek = state->gran_sizek;
991
992 /* align with gran size, prevent small block used up MTRRs */
993 range_basek = ALIGN(state->range_startk, gran_sizek);
994 if ((range_basek > basek) && basek)
995 return second_sizek;
996 state->range_sizek -= (range_basek - state->range_startk);
997 range_sizek = ALIGN(state->range_sizek, gran_sizek);
998
999 while (range_sizek > state->range_sizek) {
1000 range_sizek -= gran_sizek;
1001 if (!range_sizek)
1002 return 0;
1003 }
1004 state->range_sizek = range_sizek;
1005
1006 /* try to append some small hole */
1007 range0_basek = state->range_startk;
1008 range0_sizek = ALIGN(state->range_sizek, chunk_sizek);
1009
1010 /* no increase */
1011 if (range0_sizek == state->range_sizek) {
1012 if (debug_print)
1013 printk(KERN_DEBUG "rangeX: %016lx - %016lx\n",
1014 range0_basek<<10,
1015 (range0_basek + state->range_sizek)<<10);
1016 state->reg = range_to_mtrr(state->reg, range0_basek,
1017 state->range_sizek, MTRR_TYPE_WRBACK);
1018 return 0;
1019 }
1020
1021 /* only cut back, when it is not the last */
1022 if (sizek) {
1023 while (range0_basek + range0_sizek > (basek + sizek)) {
1024 if (range0_sizek >= chunk_sizek)
1025 range0_sizek -= chunk_sizek;
1026 else
1027 range0_sizek = 0;
1028
1029 if (!range0_sizek)
1030 break;
1031 }
1032 }
1033
1034second_try:
1035 range_basek = range0_basek + range0_sizek;
1036
1037 /* one hole in the middle */
1038 if (range_basek > basek && range_basek <= (basek + sizek))
1039 second_sizek = range_basek - basek;
1040
1041 if (range0_sizek > state->range_sizek) {
1042
1043 /* one hole in middle or at end */
1044 hole_sizek = range0_sizek - state->range_sizek - second_sizek;
1045
1046 /* hole size should be less than half of range0 size */
1047 if (hole_sizek >= (range0_sizek >> 1) &&
1048 range0_sizek >= chunk_sizek) {
1049 range0_sizek -= chunk_sizek;
1050 second_sizek = 0;
1051 hole_sizek = 0;
1052
1053 goto second_try;
1054 }
1055 }
1056
1057 if (range0_sizek) {
1058 if (debug_print)
1059 printk(KERN_DEBUG "range0: %016lx - %016lx\n",
1060 range0_basek<<10,
1061 (range0_basek + range0_sizek)<<10);
1062 state->reg = range_to_mtrr(state->reg, range0_basek,
1063 range0_sizek, MTRR_TYPE_WRBACK);
1064 }
1065
1066 if (range0_sizek < state->range_sizek) {
1067 /* need to handle left over */
1068 range_sizek = state->range_sizek - range0_sizek;
1069
1070 if (debug_print)
1071 printk(KERN_DEBUG "range: %016lx - %016lx\n",
1072 range_basek<<10,
1073 (range_basek + range_sizek)<<10);
1074 state->reg = range_to_mtrr(state->reg, range_basek,
1075 range_sizek, MTRR_TYPE_WRBACK);
1076 }
1077
1078 if (hole_sizek) {
1079 hole_basek = range_basek - hole_sizek - second_sizek;
1080 if (debug_print)
1081 printk(KERN_DEBUG "hole: %016lx - %016lx\n",
1082 hole_basek<<10,
1083 (hole_basek + hole_sizek)<<10);
1084 state->reg = range_to_mtrr(state->reg, hole_basek,
1085 hole_sizek, MTRR_TYPE_UNCACHABLE);
1086 }
1087
1088 return second_sizek;
1089}
1090
1091static void __init
1092set_var_mtrr_range(struct var_mtrr_state *state, unsigned long base_pfn,
1093 unsigned long size_pfn)
1094{
1095 unsigned long basek, sizek;
1096 unsigned long second_sizek = 0;
1097
1098 if (state->reg >= num_var_ranges)
1099 return;
1100
1101 basek = base_pfn << (PAGE_SHIFT - 10);
1102 sizek = size_pfn << (PAGE_SHIFT - 10);
1103
1104 /* See if I can merge with the last range */
1105 if ((basek <= 1024) ||
1106 (state->range_startk + state->range_sizek == basek)) {
1107 unsigned long endk = basek + sizek;
1108 state->range_sizek = endk - state->range_startk;
1109 return;
1110 }
1111 /* Write the range mtrrs */
1112 if (state->range_sizek != 0)
1113 second_sizek = range_to_mtrr_with_hole(state, basek, sizek);
1114
1115 /* Allocate an msr */
1116 state->range_startk = basek + second_sizek;
1117 state->range_sizek = sizek - second_sizek;
1118}
1119
1120/* mininum size of mtrr block that can take hole */
1121static u64 mtrr_chunk_size __initdata = (256ULL<<20);
1122
1123static int __init parse_mtrr_chunk_size_opt(char *p)
1124{
1125 if (!p)
1126 return -EINVAL;
1127 mtrr_chunk_size = memparse(p, &p);
1128 return 0;
1129}
1130early_param("mtrr_chunk_size", parse_mtrr_chunk_size_opt);
1131
1132/* granity of mtrr of block */
1133static u64 mtrr_gran_size __initdata;
1134
1135static int __init parse_mtrr_gran_size_opt(char *p)
1136{
1137 if (!p)
1138 return -EINVAL;
1139 mtrr_gran_size = memparse(p, &p);
1140 return 0;
1141}
1142early_param("mtrr_gran_size", parse_mtrr_gran_size_opt);
1143
1144static int nr_mtrr_spare_reg __initdata =
1145 CONFIG_MTRR_SANITIZER_SPARE_REG_NR_DEFAULT;
1146
1147static int __init parse_mtrr_spare_reg(char *arg)
1148{
1149 if (arg)
1150 nr_mtrr_spare_reg = simple_strtoul(arg, NULL, 0);
1151 return 0;
1152}
1153
1154early_param("mtrr_spare_reg_nr", parse_mtrr_spare_reg);
1155
1156static int __init
1157x86_setup_var_mtrrs(struct res_range *range, int nr_range,
1158 u64 chunk_size, u64 gran_size)
1159{
1160 struct var_mtrr_state var_state;
1161 int i;
1162 int num_reg;
1163
1164 var_state.range_startk = 0;
1165 var_state.range_sizek = 0;
1166 var_state.reg = 0;
1167 var_state.chunk_sizek = chunk_size >> 10;
1168 var_state.gran_sizek = gran_size >> 10;
1169
1170 memset(range_state, 0, sizeof(range_state));
1171
1172 /* Write the range etc */
1173 for (i = 0; i < nr_range; i++)
1174 set_var_mtrr_range(&var_state, range[i].start,
1175 range[i].end - range[i].start + 1);
1176
1177 /* Write the last range */
1178 if (var_state.range_sizek != 0)
1179 range_to_mtrr_with_hole(&var_state, 0, 0);
1180
1181 num_reg = var_state.reg;
1182 /* Clear out the extra MTRR's */
1183 while (var_state.reg < num_var_ranges) {
1184 save_var_mtrr(var_state.reg, 0, 0, 0);
1185 var_state.reg++;
1186 }
1187
1188 return num_reg;
1189}
1190
1191struct mtrr_cleanup_result {
1192 unsigned long gran_sizek;
1193 unsigned long chunk_sizek;
1194 unsigned long lose_cover_sizek;
1195 unsigned int num_reg;
1196 int bad;
1197};
1198
1199/*
1200 * gran_size: 64K, 128K, 256K, 512K, 1M, 2M, ..., 2G
1201 * chunk size: gran_size, ..., 2G
1202 * so we need (1+16)*8
1203 */
1204#define NUM_RESULT 136
1205#define PSHIFT (PAGE_SHIFT - 10)
1206
1207static struct mtrr_cleanup_result __initdata result[NUM_RESULT];
1208static unsigned long __initdata min_loss_pfn[RANGE_NUM];
1209
1210static void __init print_out_mtrr_range_state(void)
1211{
1212 int i;
1213 char start_factor = 'K', size_factor = 'K';
1214 unsigned long start_base, size_base;
1215 mtrr_type type;
1216
1217 for (i = 0; i < num_var_ranges; i++) {
1218
1219 size_base = range_state[i].size_pfn << (PAGE_SHIFT - 10);
1220 if (!size_base)
1221 continue;
1222
1223 size_base = to_size_factor(size_base, &size_factor),
1224 start_base = range_state[i].base_pfn << (PAGE_SHIFT - 10);
1225 start_base = to_size_factor(start_base, &start_factor),
1226 type = range_state[i].type;
1227
1228 printk(KERN_DEBUG "reg %d, base: %ld%cB, range: %ld%cB, type %s\n",
1229 i, start_base, start_factor,
1230 size_base, size_factor,
1231 (type == MTRR_TYPE_UNCACHABLE) ? "UC" :
1232 ((type == MTRR_TYPE_WRPROT) ? "WP" :
1233 ((type == MTRR_TYPE_WRBACK) ? "WB" : "Other"))
1234 );
1235 }
1236}
1237
1238static int __init mtrr_need_cleanup(void)
1239{
1240 int i;
1241 mtrr_type type;
1242 unsigned long size;
1243 /* extra one for all 0 */
1244 int num[MTRR_NUM_TYPES + 1];
1245
1246 /* check entries number */
1247 memset(num, 0, sizeof(num));
1248 for (i = 0; i < num_var_ranges; i++) {
1249 type = range_state[i].type;
1250 size = range_state[i].size_pfn;
1251 if (type >= MTRR_NUM_TYPES)
1252 continue;
1253 if (!size)
1254 type = MTRR_NUM_TYPES;
1255 if (type == MTRR_TYPE_WRPROT)
1256 type = MTRR_TYPE_UNCACHABLE;
1257 num[type]++;
1258 }
1259
1260 /* check if we got UC entries */
1261 if (!num[MTRR_TYPE_UNCACHABLE])
1262 return 0;
1263
1264 /* check if we only had WB and UC */
1265 if (num[MTRR_TYPE_WRBACK] + num[MTRR_TYPE_UNCACHABLE] !=
1266 num_var_ranges - num[MTRR_NUM_TYPES])
1267 return 0;
1268
1269 return 1;
1270}
1271
1272static unsigned long __initdata range_sums;
1273static void __init mtrr_calc_range_state(u64 chunk_size, u64 gran_size,
1274 unsigned long extra_remove_base,
1275 unsigned long extra_remove_size,
1276 int i)
1277{
1278 int num_reg;
1279 static struct res_range range_new[RANGE_NUM];
1280 static int nr_range_new;
1281 unsigned long range_sums_new;
1282
1283 /* convert ranges to var ranges state */
1284 num_reg = x86_setup_var_mtrrs(range, nr_range,
1285 chunk_size, gran_size);
1286
1287 /* we got new setting in range_state, check it */
1288 memset(range_new, 0, sizeof(range_new));
1289 nr_range_new = x86_get_mtrr_mem_range(range_new, 0,
1290 extra_remove_base, extra_remove_size);
1291 range_sums_new = sum_ranges(range_new, nr_range_new);
1292
1293 result[i].chunk_sizek = chunk_size >> 10;
1294 result[i].gran_sizek = gran_size >> 10;
1295 result[i].num_reg = num_reg;
1296 if (range_sums < range_sums_new) {
1297 result[i].lose_cover_sizek =
1298 (range_sums_new - range_sums) << PSHIFT;
1299 result[i].bad = 1;
1300 } else
1301 result[i].lose_cover_sizek =
1302 (range_sums - range_sums_new) << PSHIFT;
1303
1304 /* double check it */
1305 if (!result[i].bad && !result[i].lose_cover_sizek) {
1306 if (nr_range_new != nr_range ||
1307 memcmp(range, range_new, sizeof(range)))
1308 result[i].bad = 1;
1309 }
1310
1311 if (!result[i].bad && (range_sums - range_sums_new <
1312 min_loss_pfn[num_reg])) {
1313 min_loss_pfn[num_reg] =
1314 range_sums - range_sums_new;
1315 }
1316}
1317
1318static void __init mtrr_print_out_one_result(int i)
1319{
1320 char gran_factor, chunk_factor, lose_factor;
1321 unsigned long gran_base, chunk_base, lose_base;
1322
1323 gran_base = to_size_factor(result[i].gran_sizek, &gran_factor),
1324 chunk_base = to_size_factor(result[i].chunk_sizek, &chunk_factor),
1325 lose_base = to_size_factor(result[i].lose_cover_sizek, &lose_factor),
1326 printk(KERN_INFO "%sgran_size: %ld%c \tchunk_size: %ld%c \t",
1327 result[i].bad ? "*BAD*" : " ",
1328 gran_base, gran_factor, chunk_base, chunk_factor);
1329 printk(KERN_CONT "num_reg: %d \tlose cover RAM: %s%ld%c\n",
1330 result[i].num_reg, result[i].bad ? "-" : "",
1331 lose_base, lose_factor);
1332}
1333
1334static int __init mtrr_search_optimal_index(void)
1335{
1336 int i;
1337 int num_reg_good;
1338 int index_good;
1339
1340 if (nr_mtrr_spare_reg >= num_var_ranges)
1341 nr_mtrr_spare_reg = num_var_ranges - 1;
1342 num_reg_good = -1;
1343 for (i = num_var_ranges - nr_mtrr_spare_reg; i > 0; i--) {
1344 if (!min_loss_pfn[i])
1345 num_reg_good = i;
1346 }
1347
1348 index_good = -1;
1349 if (num_reg_good != -1) {
1350 for (i = 0; i < NUM_RESULT; i++) {
1351 if (!result[i].bad &&
1352 result[i].num_reg == num_reg_good &&
1353 !result[i].lose_cover_sizek) {
1354 index_good = i;
1355 break;
1356 }
1357 }
1358 }
1359
1360 return index_good;
1361}
1362
1363
1364static int __init mtrr_cleanup(unsigned address_bits)
1365{
1366 unsigned long extra_remove_base, extra_remove_size;
1367 unsigned long base, size, def, dummy;
1368 mtrr_type type;
1369 u64 chunk_size, gran_size;
1370 int index_good;
1371 int i;
1372
1373 if (!is_cpu(INTEL) || enable_mtrr_cleanup < 1)
1374 return 0;
1375 rdmsr(MTRRdefType_MSR, def, dummy);
1376 def &= 0xff;
1377 if (def != MTRR_TYPE_UNCACHABLE)
1378 return 0;
1379
1380 /* get it and store it aside */
1381 memset(range_state, 0, sizeof(range_state));
1382 for (i = 0; i < num_var_ranges; i++) {
1383 mtrr_if->get(i, &base, &size, &type);
1384 range_state[i].base_pfn = base;
1385 range_state[i].size_pfn = size;
1386 range_state[i].type = type;
1387 }
1388
1389 /* check if we need handle it and can handle it */
1390 if (!mtrr_need_cleanup())
1391 return 0;
1392
1393 /* print original var MTRRs at first, for debugging: */
1394 printk(KERN_DEBUG "original variable MTRRs\n");
1395 print_out_mtrr_range_state();
1396
1397 memset(range, 0, sizeof(range));
1398 extra_remove_size = 0;
1399 extra_remove_base = 1 << (32 - PAGE_SHIFT);
1400 if (mtrr_tom2)
1401 extra_remove_size =
1402 (mtrr_tom2 >> PAGE_SHIFT) - extra_remove_base;
1403 nr_range = x86_get_mtrr_mem_range(range, 0, extra_remove_base,
1404 extra_remove_size);
1405 /*
1406 * [0, 1M) should always be coverred by var mtrr with WB
1407 * and fixed mtrrs should take effective before var mtrr for it
1408 */
1409 nr_range = add_range_with_merge(range, nr_range, 0,
1410 (1ULL<<(20 - PAGE_SHIFT)) - 1);
1411 /* sort the ranges */
1412 sort(range, nr_range, sizeof(struct res_range), cmp_range, NULL);
1413
1414 range_sums = sum_ranges(range, nr_range);
1415 printk(KERN_INFO "total RAM coverred: %ldM\n",
1416 range_sums >> (20 - PAGE_SHIFT));
1417
1418 if (mtrr_chunk_size && mtrr_gran_size) {
1419 i = 0;
1420 mtrr_calc_range_state(mtrr_chunk_size, mtrr_gran_size,
1421 extra_remove_base, extra_remove_size, i);
1422
1423 mtrr_print_out_one_result(i);
1424
1425 if (!result[i].bad) {
1426 set_var_mtrr_all(address_bits);
1427 printk(KERN_DEBUG "New variable MTRRs\n");
1428 print_out_mtrr_range_state();
1429 return 1;
1430 }
1431 printk(KERN_INFO "invalid mtrr_gran_size or mtrr_chunk_size, "
1432 "will find optimal one\n");
1433 }
1434
1435 i = 0;
1436 memset(min_loss_pfn, 0xff, sizeof(min_loss_pfn));
1437 memset(result, 0, sizeof(result));
1438 for (gran_size = (1ULL<<16); gran_size < (1ULL<<32); gran_size <<= 1) {
1439
1440 for (chunk_size = gran_size; chunk_size < (1ULL<<32);
1441 chunk_size <<= 1) {
1442
1443 if (i >= NUM_RESULT)
1444 continue;
1445
1446 mtrr_calc_range_state(chunk_size, gran_size,
1447 extra_remove_base, extra_remove_size, i);
1448 if (debug_print) {
1449 mtrr_print_out_one_result(i);
1450 printk(KERN_INFO "\n");
1451 }
1452
1453 i++;
1454 }
1455 }
1456
1457 /* try to find the optimal index */
1458 index_good = mtrr_search_optimal_index();
1459
1460 if (index_good != -1) {
1461 printk(KERN_INFO "Found optimal setting for mtrr clean up\n");
1462 i = index_good;
1463 mtrr_print_out_one_result(i);
1464
1465 /* convert ranges to var ranges state */
1466 chunk_size = result[i].chunk_sizek;
1467 chunk_size <<= 10;
1468 gran_size = result[i].gran_sizek;
1469 gran_size <<= 10;
1470 x86_setup_var_mtrrs(range, nr_range, chunk_size, gran_size);
1471 set_var_mtrr_all(address_bits);
1472 printk(KERN_DEBUG "New variable MTRRs\n");
1473 print_out_mtrr_range_state();
1474 return 1;
1475 } else {
1476 /* print out all */
1477 for (i = 0; i < NUM_RESULT; i++)
1478 mtrr_print_out_one_result(i);
1479 }
1480
1481 printk(KERN_INFO "mtrr_cleanup: can not find optimal value\n");
1482 printk(KERN_INFO "please specify mtrr_gran_size/mtrr_chunk_size\n");
1483
1484 return 0;
1485}
1486#else
1487static int __init mtrr_cleanup(unsigned address_bits)
1488{
1489 return 0;
1490}
1491#endif
1492
1493static int __initdata changed_by_mtrr_cleanup;
1494
1495static int disable_mtrr_trim;
1496
1497static int __init disable_mtrr_trim_setup(char *str)
1498{
1499 disable_mtrr_trim = 1;
1500 return 0;
1501}
1502early_param("disable_mtrr_trim", disable_mtrr_trim_setup);
1503
1504/*
1505 * Newer AMD K8s and later CPUs have a special magic MSR way to force WB
1506 * for memory >4GB. Check for that here.
1507 * Note this won't check if the MTRRs < 4GB where the magic bit doesn't
1508 * apply to are wrong, but so far we don't know of any such case in the wild.
1509 */
1510#define Tom2Enabled (1U << 21)
1511#define Tom2ForceMemTypeWB (1U << 22)
1512
1513int __init amd_special_default_mtrr(void)
1514{
1515 u32 l, h;
1516
1517 if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD)
1518 return 0;
1519 if (boot_cpu_data.x86 < 0xf || boot_cpu_data.x86 > 0x11)
1520 return 0;
1521 /* In case some hypervisor doesn't pass SYSCFG through */
1522 if (rdmsr_safe(MSR_K8_SYSCFG, &l, &h) < 0)
1523 return 0;
1524 /*
1525 * Memory between 4GB and top of mem is forced WB by this magic bit.
1526 * Reserved before K8RevF, but should be zero there.
1527 */
1528 if ((l & (Tom2Enabled | Tom2ForceMemTypeWB)) ==
1529 (Tom2Enabled | Tom2ForceMemTypeWB))
1530 return 1;
1531 return 0;
1532}
1533
1534static u64 __init real_trim_memory(unsigned long start_pfn,
1535 unsigned long limit_pfn)
1536{
1537 u64 trim_start, trim_size;
1538 trim_start = start_pfn;
1539 trim_start <<= PAGE_SHIFT;
1540 trim_size = limit_pfn;
1541 trim_size <<= PAGE_SHIFT;
1542 trim_size -= trim_start;
1543
1544 return e820_update_range(trim_start, trim_size, E820_RAM,
1545 E820_RESERVED);
1546}
1547/**
1548 * mtrr_trim_uncached_memory - trim RAM not covered by MTRRs
1549 * @end_pfn: ending page frame number
1550 *
1551 * Some buggy BIOSes don't setup the MTRRs properly for systems with certain
1552 * memory configurations. This routine checks that the highest MTRR matches
1553 * the end of memory, to make sure the MTRRs having a write back type cover
1554 * all of the memory the kernel is intending to use. If not, it'll trim any
1555 * memory off the end by adjusting end_pfn, removing it from the kernel's
1556 * allocation pools, warning the user with an obnoxious message.
1557 */
1558int __init mtrr_trim_uncached_memory(unsigned long end_pfn)
1559{
1560 unsigned long i, base, size, highest_pfn = 0, def, dummy;
1561 mtrr_type type;
1562 u64 total_trim_size;
1563
1564 /* extra one for all 0 */
1565 int num[MTRR_NUM_TYPES + 1];
1566 /*
1567 * Make sure we only trim uncachable memory on machines that
1568 * support the Intel MTRR architecture:
1569 */
1570 if (!is_cpu(INTEL) || disable_mtrr_trim)
1571 return 0;
1572 rdmsr(MTRRdefType_MSR, def, dummy);
1573 def &= 0xff;
1574 if (def != MTRR_TYPE_UNCACHABLE)
1575 return 0;
1576
1577 /* get it and store it aside */
1578 memset(range_state, 0, sizeof(range_state));
1579 for (i = 0; i < num_var_ranges; i++) {
1580 mtrr_if->get(i, &base, &size, &type);
1581 range_state[i].base_pfn = base;
1582 range_state[i].size_pfn = size;
1583 range_state[i].type = type;
1584 }
1585
1586 /* Find highest cached pfn */
1587 for (i = 0; i < num_var_ranges; i++) {
1588 type = range_state[i].type;
1589 if (type != MTRR_TYPE_WRBACK)
1590 continue;
1591 base = range_state[i].base_pfn;
1592 size = range_state[i].size_pfn;
1593 if (highest_pfn < base + size)
1594 highest_pfn = base + size;
1595 }
1596
1597 /* kvm/qemu doesn't have mtrr set right, don't trim them all */
1598 if (!highest_pfn) {
1599 printk(KERN_INFO "CPU MTRRs all blank - virtualized system.\n");
1600 return 0;
1601 }
1602
1603 /* check entries number */
1604 memset(num, 0, sizeof(num));
1605 for (i = 0; i < num_var_ranges; i++) {
1606 type = range_state[i].type;
1607 if (type >= MTRR_NUM_TYPES)
1608 continue;
1609 size = range_state[i].size_pfn;
1610 if (!size)
1611 type = MTRR_NUM_TYPES;
1612 num[type]++;
1613 }
1614
1615 /* no entry for WB? */
1616 if (!num[MTRR_TYPE_WRBACK])
1617 return 0;
1618
1619 /* check if we only had WB and UC */
1620 if (num[MTRR_TYPE_WRBACK] + num[MTRR_TYPE_UNCACHABLE] !=
1621 num_var_ranges - num[MTRR_NUM_TYPES])
1622 return 0;
1623
1624 memset(range, 0, sizeof(range));
1625 nr_range = 0;
1626 if (mtrr_tom2) {
1627 range[nr_range].start = (1ULL<<(32 - PAGE_SHIFT));
1628 range[nr_range].end = (mtrr_tom2 >> PAGE_SHIFT) - 1;
1629 if (highest_pfn < range[nr_range].end + 1)
1630 highest_pfn = range[nr_range].end + 1;
1631 nr_range++;
1632 }
1633 nr_range = x86_get_mtrr_mem_range(range, nr_range, 0, 0);
1634
1635 total_trim_size = 0;
1636 /* check the head */
1637 if (range[0].start)
1638 total_trim_size += real_trim_memory(0, range[0].start);
1639 /* check the holes */
1640 for (i = 0; i < nr_range - 1; i++) {
1641 if (range[i].end + 1 < range[i+1].start)
1642 total_trim_size += real_trim_memory(range[i].end + 1,
1643 range[i+1].start);
1644 }
1645 /* check the top */
1646 i = nr_range - 1;
1647 if (range[i].end + 1 < end_pfn)
1648 total_trim_size += real_trim_memory(range[i].end + 1,
1649 end_pfn);
1650
1651 if (total_trim_size) {
1652 printk(KERN_WARNING "WARNING: BIOS bug: CPU MTRRs don't cover"
1653 " all of memory, losing %lluMB of RAM.\n",
1654 total_trim_size >> 20);
1655
1656 if (!changed_by_mtrr_cleanup)
1657 WARN_ON(1);
1658
1659 printk(KERN_INFO "update e820 for mtrr\n");
1660 update_e820();
1661
1662 return 1;
1663 }
1664
1665 return 0;
1666}
1667 614
1668/** 615/**
1669 * mtrr_bp_init - initialize mtrrs on the boot CPU 616 * 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 ffd60409cc6d..6710e93021a7 100644
--- a/arch/x86/kernel/cpu/mtrr/mtrr.h
+++ b/arch/x86/kernel/cpu/mtrr/mtrr.h
@@ -88,3 +88,6 @@ void mtrr_wrmsr(unsigned, unsigned, unsigned);
88int amd_init_mtrr(void); 88int amd_init_mtrr(void);
89int cyrix_init_mtrr(void); 89int cyrix_init_mtrr(void);
90int centaur_init_mtrr(void); 90int centaur_init_mtrr(void);
91
92extern int changed_by_mtrr_cleanup;
93extern int mtrr_cleanup(unsigned address_bits);