0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020 #include <linux/init.h>
0021 #include <linux/pci.h>
0022 #include <linux/smp.h>
0023 #include <linux/cpu.h>
0024 #include <linux/mutex.h>
0025 #include <linux/uaccess.h>
0026 #include <linux/kvm_para.h>
0027 #include <linux/range.h>
0028
0029 #include <asm/processor.h>
0030 #include <asm/e820/api.h>
0031 #include <asm/mtrr.h>
0032 #include <asm/msr.h>
0033
0034 #include "mtrr.h"
0035
0036 struct var_mtrr_range_state {
0037 unsigned long base_pfn;
0038 unsigned long size_pfn;
0039 mtrr_type type;
0040 };
0041
0042 struct var_mtrr_state {
0043 unsigned long range_startk;
0044 unsigned long range_sizek;
0045 unsigned long chunk_sizek;
0046 unsigned long gran_sizek;
0047 unsigned int reg;
0048 };
0049
0050
0051 #define RANGE_NUM 256
0052
0053 static struct range __initdata range[RANGE_NUM];
0054 static int __initdata nr_range;
0055
0056 static struct var_mtrr_range_state __initdata range_state[RANGE_NUM];
0057
0058 static int __initdata debug_print;
0059 #define Dprintk(x...) do { if (debug_print) pr_debug(x); } while (0)
0060
0061 #define BIOS_BUG_MSG \
0062 "WARNING: BIOS bug: VAR MTRR %d contains strange UC entry under 1M, check with your system vendor!\n"
0063
0064 static int __init
0065 x86_get_mtrr_mem_range(struct range *range, int nr_range,
0066 unsigned long extra_remove_base,
0067 unsigned long extra_remove_size)
0068 {
0069 unsigned long base, size;
0070 mtrr_type type;
0071 int i;
0072
0073 for (i = 0; i < num_var_ranges; i++) {
0074 type = range_state[i].type;
0075 if (type != MTRR_TYPE_WRBACK)
0076 continue;
0077 base = range_state[i].base_pfn;
0078 size = range_state[i].size_pfn;
0079 nr_range = add_range_with_merge(range, RANGE_NUM, nr_range,
0080 base, base + size);
0081 }
0082 if (debug_print) {
0083 pr_debug("After WB checking\n");
0084 for (i = 0; i < nr_range; i++)
0085 pr_debug("MTRR MAP PFN: %016llx - %016llx\n",
0086 range[i].start, range[i].end);
0087 }
0088
0089
0090 for (i = 0; i < num_var_ranges; i++) {
0091 type = range_state[i].type;
0092 if (type != MTRR_TYPE_UNCACHABLE &&
0093 type != MTRR_TYPE_WRPROT)
0094 continue;
0095 size = range_state[i].size_pfn;
0096 if (!size)
0097 continue;
0098 base = range_state[i].base_pfn;
0099 if (base < (1<<(20-PAGE_SHIFT)) && mtrr_state.have_fixed &&
0100 (mtrr_state.enabled & MTRR_STATE_MTRR_ENABLED) &&
0101 (mtrr_state.enabled & MTRR_STATE_MTRR_FIXED_ENABLED)) {
0102
0103 pr_warn(BIOS_BUG_MSG, i);
0104 if (base + size <= (1<<(20-PAGE_SHIFT)))
0105 continue;
0106 size -= (1<<(20-PAGE_SHIFT)) - base;
0107 base = 1<<(20-PAGE_SHIFT);
0108 }
0109 subtract_range(range, RANGE_NUM, base, base + size);
0110 }
0111 if (extra_remove_size)
0112 subtract_range(range, RANGE_NUM, extra_remove_base,
0113 extra_remove_base + extra_remove_size);
0114
0115 if (debug_print) {
0116 pr_debug("After UC checking\n");
0117 for (i = 0; i < RANGE_NUM; i++) {
0118 if (!range[i].end)
0119 continue;
0120 pr_debug("MTRR MAP PFN: %016llx - %016llx\n",
0121 range[i].start, range[i].end);
0122 }
0123 }
0124
0125
0126 nr_range = clean_sort_range(range, RANGE_NUM);
0127 if (debug_print) {
0128 pr_debug("After sorting\n");
0129 for (i = 0; i < nr_range; i++)
0130 pr_debug("MTRR MAP PFN: %016llx - %016llx\n",
0131 range[i].start, range[i].end);
0132 }
0133
0134 return nr_range;
0135 }
0136
0137 #ifdef CONFIG_MTRR_SANITIZER
0138
0139 static unsigned long __init sum_ranges(struct range *range, int nr_range)
0140 {
0141 unsigned long sum = 0;
0142 int i;
0143
0144 for (i = 0; i < nr_range; i++)
0145 sum += range[i].end - range[i].start;
0146
0147 return sum;
0148 }
0149
0150 static int enable_mtrr_cleanup __initdata =
0151 CONFIG_MTRR_SANITIZER_ENABLE_DEFAULT;
0152
0153 static int __init disable_mtrr_cleanup_setup(char *str)
0154 {
0155 enable_mtrr_cleanup = 0;
0156 return 0;
0157 }
0158 early_param("disable_mtrr_cleanup", disable_mtrr_cleanup_setup);
0159
0160 static int __init enable_mtrr_cleanup_setup(char *str)
0161 {
0162 enable_mtrr_cleanup = 1;
0163 return 0;
0164 }
0165 early_param("enable_mtrr_cleanup", enable_mtrr_cleanup_setup);
0166
0167 static int __init mtrr_cleanup_debug_setup(char *str)
0168 {
0169 debug_print = 1;
0170 return 0;
0171 }
0172 early_param("mtrr_cleanup_debug", mtrr_cleanup_debug_setup);
0173
0174 static void __init
0175 set_var_mtrr(unsigned int reg, unsigned long basek, unsigned long sizek,
0176 unsigned char type, unsigned int address_bits)
0177 {
0178 u32 base_lo, base_hi, mask_lo, mask_hi;
0179 u64 base, mask;
0180
0181 if (!sizek) {
0182 fill_mtrr_var_range(reg, 0, 0, 0, 0);
0183 return;
0184 }
0185
0186 mask = (1ULL << address_bits) - 1;
0187 mask &= ~((((u64)sizek) << 10) - 1);
0188
0189 base = ((u64)basek) << 10;
0190
0191 base |= type;
0192 mask |= 0x800;
0193
0194 base_lo = base & ((1ULL<<32) - 1);
0195 base_hi = base >> 32;
0196
0197 mask_lo = mask & ((1ULL<<32) - 1);
0198 mask_hi = mask >> 32;
0199
0200 fill_mtrr_var_range(reg, base_lo, base_hi, mask_lo, mask_hi);
0201 }
0202
0203 static void __init
0204 save_var_mtrr(unsigned int reg, unsigned long basek, unsigned long sizek,
0205 unsigned char type)
0206 {
0207 range_state[reg].base_pfn = basek >> (PAGE_SHIFT - 10);
0208 range_state[reg].size_pfn = sizek >> (PAGE_SHIFT - 10);
0209 range_state[reg].type = type;
0210 }
0211
0212 static void __init set_var_mtrr_all(unsigned int address_bits)
0213 {
0214 unsigned long basek, sizek;
0215 unsigned char type;
0216 unsigned int reg;
0217
0218 for (reg = 0; reg < num_var_ranges; reg++) {
0219 basek = range_state[reg].base_pfn << (PAGE_SHIFT - 10);
0220 sizek = range_state[reg].size_pfn << (PAGE_SHIFT - 10);
0221 type = range_state[reg].type;
0222
0223 set_var_mtrr(reg, basek, sizek, type, address_bits);
0224 }
0225 }
0226
0227 static unsigned long to_size_factor(unsigned long sizek, char *factorp)
0228 {
0229 unsigned long base = sizek;
0230 char factor;
0231
0232 if (base & ((1<<10) - 1)) {
0233
0234 factor = 'K';
0235 } else if (base & ((1<<20) - 1)) {
0236 factor = 'M';
0237 base >>= 10;
0238 } else {
0239 factor = 'G';
0240 base >>= 20;
0241 }
0242
0243 *factorp = factor;
0244
0245 return base;
0246 }
0247
0248 static unsigned int __init
0249 range_to_mtrr(unsigned int reg, unsigned long range_startk,
0250 unsigned long range_sizek, unsigned char type)
0251 {
0252 if (!range_sizek || (reg >= num_var_ranges))
0253 return reg;
0254
0255 while (range_sizek) {
0256 unsigned long max_align, align;
0257 unsigned long sizek;
0258
0259
0260 if (range_startk)
0261 max_align = __ffs(range_startk);
0262 else
0263 max_align = BITS_PER_LONG - 1;
0264
0265 align = __fls(range_sizek);
0266 if (align > max_align)
0267 align = max_align;
0268
0269 sizek = 1UL << align;
0270 if (debug_print) {
0271 char start_factor = 'K', size_factor = 'K';
0272 unsigned long start_base, size_base;
0273
0274 start_base = to_size_factor(range_startk, &start_factor);
0275 size_base = to_size_factor(sizek, &size_factor);
0276
0277 Dprintk("Setting variable MTRR %d, "
0278 "base: %ld%cB, range: %ld%cB, type %s\n",
0279 reg, start_base, start_factor,
0280 size_base, size_factor,
0281 (type == MTRR_TYPE_UNCACHABLE) ? "UC" :
0282 ((type == MTRR_TYPE_WRBACK) ? "WB" : "Other")
0283 );
0284 }
0285 save_var_mtrr(reg++, range_startk, sizek, type);
0286 range_startk += sizek;
0287 range_sizek -= sizek;
0288 if (reg >= num_var_ranges)
0289 break;
0290 }
0291 return reg;
0292 }
0293
0294 static unsigned __init
0295 range_to_mtrr_with_hole(struct var_mtrr_state *state, unsigned long basek,
0296 unsigned long sizek)
0297 {
0298 unsigned long hole_basek, hole_sizek;
0299 unsigned long second_sizek;
0300 unsigned long range0_basek, range0_sizek;
0301 unsigned long range_basek, range_sizek;
0302 unsigned long chunk_sizek;
0303 unsigned long gran_sizek;
0304
0305 hole_basek = 0;
0306 hole_sizek = 0;
0307 second_sizek = 0;
0308 chunk_sizek = state->chunk_sizek;
0309 gran_sizek = state->gran_sizek;
0310
0311
0312 range_basek = ALIGN(state->range_startk, gran_sizek);
0313 if ((range_basek > basek) && basek)
0314 return second_sizek;
0315
0316 state->range_sizek -= (range_basek - state->range_startk);
0317 range_sizek = ALIGN(state->range_sizek, gran_sizek);
0318
0319 while (range_sizek > state->range_sizek) {
0320 range_sizek -= gran_sizek;
0321 if (!range_sizek)
0322 return 0;
0323 }
0324 state->range_sizek = range_sizek;
0325
0326
0327 range0_basek = state->range_startk;
0328 range0_sizek = ALIGN(state->range_sizek, chunk_sizek);
0329
0330
0331 if (range0_sizek == state->range_sizek) {
0332 Dprintk("rangeX: %016lx - %016lx\n",
0333 range0_basek<<10,
0334 (range0_basek + state->range_sizek)<<10);
0335 state->reg = range_to_mtrr(state->reg, range0_basek,
0336 state->range_sizek, MTRR_TYPE_WRBACK);
0337 return 0;
0338 }
0339
0340
0341 if (sizek) {
0342 while (range0_basek + range0_sizek > (basek + sizek)) {
0343 if (range0_sizek >= chunk_sizek)
0344 range0_sizek -= chunk_sizek;
0345 else
0346 range0_sizek = 0;
0347
0348 if (!range0_sizek)
0349 break;
0350 }
0351 }
0352
0353 second_try:
0354 range_basek = range0_basek + range0_sizek;
0355
0356
0357 if (range_basek > basek && range_basek <= (basek + sizek))
0358 second_sizek = range_basek - basek;
0359
0360 if (range0_sizek > state->range_sizek) {
0361
0362
0363 hole_sizek = range0_sizek - state->range_sizek - second_sizek;
0364
0365
0366 if (hole_sizek >= (range0_sizek >> 1) &&
0367 range0_sizek >= chunk_sizek) {
0368 range0_sizek -= chunk_sizek;
0369 second_sizek = 0;
0370 hole_sizek = 0;
0371
0372 goto second_try;
0373 }
0374 }
0375
0376 if (range0_sizek) {
0377 Dprintk("range0: %016lx - %016lx\n",
0378 range0_basek<<10,
0379 (range0_basek + range0_sizek)<<10);
0380 state->reg = range_to_mtrr(state->reg, range0_basek,
0381 range0_sizek, MTRR_TYPE_WRBACK);
0382 }
0383
0384 if (range0_sizek < state->range_sizek) {
0385
0386 range_sizek = state->range_sizek - range0_sizek;
0387
0388 Dprintk("range: %016lx - %016lx\n",
0389 range_basek<<10,
0390 (range_basek + range_sizek)<<10);
0391
0392 state->reg = range_to_mtrr(state->reg, range_basek,
0393 range_sizek, MTRR_TYPE_WRBACK);
0394 }
0395
0396 if (hole_sizek) {
0397 hole_basek = range_basek - hole_sizek - second_sizek;
0398 Dprintk("hole: %016lx - %016lx\n",
0399 hole_basek<<10,
0400 (hole_basek + hole_sizek)<<10);
0401 state->reg = range_to_mtrr(state->reg, hole_basek,
0402 hole_sizek, MTRR_TYPE_UNCACHABLE);
0403 }
0404
0405 return second_sizek;
0406 }
0407
0408 static void __init
0409 set_var_mtrr_range(struct var_mtrr_state *state, unsigned long base_pfn,
0410 unsigned long size_pfn)
0411 {
0412 unsigned long basek, sizek;
0413 unsigned long second_sizek = 0;
0414
0415 if (state->reg >= num_var_ranges)
0416 return;
0417
0418 basek = base_pfn << (PAGE_SHIFT - 10);
0419 sizek = size_pfn << (PAGE_SHIFT - 10);
0420
0421
0422 if ((basek <= 1024) ||
0423 (state->range_startk + state->range_sizek == basek)) {
0424 unsigned long endk = basek + sizek;
0425 state->range_sizek = endk - state->range_startk;
0426 return;
0427 }
0428
0429 if (state->range_sizek != 0)
0430 second_sizek = range_to_mtrr_with_hole(state, basek, sizek);
0431
0432
0433 state->range_startk = basek + second_sizek;
0434 state->range_sizek = sizek - second_sizek;
0435 }
0436
0437
0438 static u64 mtrr_chunk_size __initdata = (256ULL<<20);
0439
0440 static int __init parse_mtrr_chunk_size_opt(char *p)
0441 {
0442 if (!p)
0443 return -EINVAL;
0444 mtrr_chunk_size = memparse(p, &p);
0445 return 0;
0446 }
0447 early_param("mtrr_chunk_size", parse_mtrr_chunk_size_opt);
0448
0449
0450 static u64 mtrr_gran_size __initdata;
0451
0452 static int __init parse_mtrr_gran_size_opt(char *p)
0453 {
0454 if (!p)
0455 return -EINVAL;
0456 mtrr_gran_size = memparse(p, &p);
0457 return 0;
0458 }
0459 early_param("mtrr_gran_size", parse_mtrr_gran_size_opt);
0460
0461 static unsigned long nr_mtrr_spare_reg __initdata =
0462 CONFIG_MTRR_SANITIZER_SPARE_REG_NR_DEFAULT;
0463
0464 static int __init parse_mtrr_spare_reg(char *arg)
0465 {
0466 if (arg)
0467 nr_mtrr_spare_reg = simple_strtoul(arg, NULL, 0);
0468 return 0;
0469 }
0470 early_param("mtrr_spare_reg_nr", parse_mtrr_spare_reg);
0471
0472 static int __init
0473 x86_setup_var_mtrrs(struct range *range, int nr_range,
0474 u64 chunk_size, u64 gran_size)
0475 {
0476 struct var_mtrr_state var_state;
0477 int num_reg;
0478 int i;
0479
0480 var_state.range_startk = 0;
0481 var_state.range_sizek = 0;
0482 var_state.reg = 0;
0483 var_state.chunk_sizek = chunk_size >> 10;
0484 var_state.gran_sizek = gran_size >> 10;
0485
0486 memset(range_state, 0, sizeof(range_state));
0487
0488
0489 for (i = 0; i < nr_range; i++) {
0490 set_var_mtrr_range(&var_state, range[i].start,
0491 range[i].end - range[i].start);
0492 }
0493
0494
0495 if (var_state.range_sizek != 0)
0496 range_to_mtrr_with_hole(&var_state, 0, 0);
0497
0498 num_reg = var_state.reg;
0499
0500 while (var_state.reg < num_var_ranges) {
0501 save_var_mtrr(var_state.reg, 0, 0, 0);
0502 var_state.reg++;
0503 }
0504
0505 return num_reg;
0506 }
0507
0508 struct mtrr_cleanup_result {
0509 unsigned long gran_sizek;
0510 unsigned long chunk_sizek;
0511 unsigned long lose_cover_sizek;
0512 unsigned int num_reg;
0513 int bad;
0514 };
0515
0516
0517
0518
0519
0520
0521 #define NUM_RESULT 136
0522 #define PSHIFT (PAGE_SHIFT - 10)
0523
0524 static struct mtrr_cleanup_result __initdata result[NUM_RESULT];
0525 static unsigned long __initdata min_loss_pfn[RANGE_NUM];
0526
0527 static void __init print_out_mtrr_range_state(void)
0528 {
0529 char start_factor = 'K', size_factor = 'K';
0530 unsigned long start_base, size_base;
0531 mtrr_type type;
0532 int i;
0533
0534 for (i = 0; i < num_var_ranges; i++) {
0535
0536 size_base = range_state[i].size_pfn << (PAGE_SHIFT - 10);
0537 if (!size_base)
0538 continue;
0539
0540 size_base = to_size_factor(size_base, &size_factor);
0541 start_base = range_state[i].base_pfn << (PAGE_SHIFT - 10);
0542 start_base = to_size_factor(start_base, &start_factor);
0543 type = range_state[i].type;
0544
0545 pr_debug("reg %d, base: %ld%cB, range: %ld%cB, type %s\n",
0546 i, start_base, start_factor,
0547 size_base, size_factor,
0548 (type == MTRR_TYPE_UNCACHABLE) ? "UC" :
0549 ((type == MTRR_TYPE_WRPROT) ? "WP" :
0550 ((type == MTRR_TYPE_WRBACK) ? "WB" : "Other"))
0551 );
0552 }
0553 }
0554
0555 static int __init mtrr_need_cleanup(void)
0556 {
0557 int i;
0558 mtrr_type type;
0559 unsigned long size;
0560
0561 int num[MTRR_NUM_TYPES + 1];
0562
0563
0564 memset(num, 0, sizeof(num));
0565 for (i = 0; i < num_var_ranges; i++) {
0566 type = range_state[i].type;
0567 size = range_state[i].size_pfn;
0568 if (type >= MTRR_NUM_TYPES)
0569 continue;
0570 if (!size)
0571 type = MTRR_NUM_TYPES;
0572 num[type]++;
0573 }
0574
0575
0576 if (!num[MTRR_TYPE_UNCACHABLE])
0577 return 0;
0578
0579
0580 if (num[MTRR_TYPE_WRBACK] + num[MTRR_TYPE_UNCACHABLE] !=
0581 num_var_ranges - num[MTRR_NUM_TYPES])
0582 return 0;
0583
0584 return 1;
0585 }
0586
0587 static unsigned long __initdata range_sums;
0588
0589 static void __init
0590 mtrr_calc_range_state(u64 chunk_size, u64 gran_size,
0591 unsigned long x_remove_base,
0592 unsigned long x_remove_size, int i)
0593 {
0594
0595
0596
0597
0598
0599
0600
0601 static struct range range_new[RANGE_NUM] __initdata;
0602 unsigned long range_sums_new;
0603 int nr_range_new;
0604 int num_reg;
0605
0606
0607 num_reg = x86_setup_var_mtrrs(range, nr_range, chunk_size, gran_size);
0608
0609
0610 memset(range_new, 0, sizeof(range_new));
0611 nr_range_new = x86_get_mtrr_mem_range(range_new, 0,
0612 x_remove_base, x_remove_size);
0613 range_sums_new = sum_ranges(range_new, nr_range_new);
0614
0615 result[i].chunk_sizek = chunk_size >> 10;
0616 result[i].gran_sizek = gran_size >> 10;
0617 result[i].num_reg = num_reg;
0618
0619 if (range_sums < range_sums_new) {
0620 result[i].lose_cover_sizek = (range_sums_new - range_sums) << PSHIFT;
0621 result[i].bad = 1;
0622 } else {
0623 result[i].lose_cover_sizek = (range_sums - range_sums_new) << PSHIFT;
0624 }
0625
0626
0627 if (!result[i].bad && !result[i].lose_cover_sizek) {
0628 if (nr_range_new != nr_range || memcmp(range, range_new, sizeof(range)))
0629 result[i].bad = 1;
0630 }
0631
0632 if (!result[i].bad && (range_sums - range_sums_new < min_loss_pfn[num_reg]))
0633 min_loss_pfn[num_reg] = range_sums - range_sums_new;
0634 }
0635
0636 static void __init mtrr_print_out_one_result(int i)
0637 {
0638 unsigned long gran_base, chunk_base, lose_base;
0639 char gran_factor, chunk_factor, lose_factor;
0640
0641 gran_base = to_size_factor(result[i].gran_sizek, &gran_factor);
0642 chunk_base = to_size_factor(result[i].chunk_sizek, &chunk_factor);
0643 lose_base = to_size_factor(result[i].lose_cover_sizek, &lose_factor);
0644
0645 pr_info("%sgran_size: %ld%c \tchunk_size: %ld%c \t",
0646 result[i].bad ? "*BAD*" : " ",
0647 gran_base, gran_factor, chunk_base, chunk_factor);
0648 pr_cont("num_reg: %d \tlose cover RAM: %s%ld%c\n",
0649 result[i].num_reg, result[i].bad ? "-" : "",
0650 lose_base, lose_factor);
0651 }
0652
0653 static int __init mtrr_search_optimal_index(void)
0654 {
0655 int num_reg_good;
0656 int index_good;
0657 int i;
0658
0659 if (nr_mtrr_spare_reg >= num_var_ranges)
0660 nr_mtrr_spare_reg = num_var_ranges - 1;
0661
0662 num_reg_good = -1;
0663 for (i = num_var_ranges - nr_mtrr_spare_reg; i > 0; i--) {
0664 if (!min_loss_pfn[i])
0665 num_reg_good = i;
0666 }
0667
0668 index_good = -1;
0669 if (num_reg_good != -1) {
0670 for (i = 0; i < NUM_RESULT; i++) {
0671 if (!result[i].bad &&
0672 result[i].num_reg == num_reg_good &&
0673 !result[i].lose_cover_sizek) {
0674 index_good = i;
0675 break;
0676 }
0677 }
0678 }
0679
0680 return index_good;
0681 }
0682
0683 int __init mtrr_cleanup(unsigned address_bits)
0684 {
0685 unsigned long x_remove_base, x_remove_size;
0686 unsigned long base, size, def, dummy;
0687 u64 chunk_size, gran_size;
0688 mtrr_type type;
0689 int index_good;
0690 int i;
0691
0692 if (!is_cpu(INTEL) || enable_mtrr_cleanup < 1)
0693 return 0;
0694
0695 rdmsr(MSR_MTRRdefType, def, dummy);
0696 def &= 0xff;
0697 if (def != MTRR_TYPE_UNCACHABLE)
0698 return 0;
0699
0700
0701 memset(range_state, 0, sizeof(range_state));
0702 for (i = 0; i < num_var_ranges; i++) {
0703 mtrr_if->get(i, &base, &size, &type);
0704 range_state[i].base_pfn = base;
0705 range_state[i].size_pfn = size;
0706 range_state[i].type = type;
0707 }
0708
0709
0710 if (!mtrr_need_cleanup())
0711 return 0;
0712
0713
0714 pr_debug("original variable MTRRs\n");
0715 print_out_mtrr_range_state();
0716
0717 memset(range, 0, sizeof(range));
0718 x_remove_size = 0;
0719 x_remove_base = 1 << (32 - PAGE_SHIFT);
0720 if (mtrr_tom2)
0721 x_remove_size = (mtrr_tom2 >> PAGE_SHIFT) - x_remove_base;
0722
0723
0724
0725
0726
0727 nr_range = add_range_with_merge(range, RANGE_NUM, 0, 0,
0728 1ULL<<(20 - PAGE_SHIFT));
0729
0730 nr_range = x86_get_mtrr_mem_range(range, nr_range,
0731 x_remove_base, x_remove_size);
0732
0733 range_sums = sum_ranges(range, nr_range);
0734 pr_info("total RAM covered: %ldM\n",
0735 range_sums >> (20 - PAGE_SHIFT));
0736
0737 if (mtrr_chunk_size && mtrr_gran_size) {
0738 i = 0;
0739 mtrr_calc_range_state(mtrr_chunk_size, mtrr_gran_size,
0740 x_remove_base, x_remove_size, i);
0741
0742 mtrr_print_out_one_result(i);
0743
0744 if (!result[i].bad) {
0745 set_var_mtrr_all(address_bits);
0746 pr_debug("New variable MTRRs\n");
0747 print_out_mtrr_range_state();
0748 return 1;
0749 }
0750 pr_info("invalid mtrr_gran_size or mtrr_chunk_size, will find optimal one\n");
0751 }
0752
0753 i = 0;
0754 memset(min_loss_pfn, 0xff, sizeof(min_loss_pfn));
0755 memset(result, 0, sizeof(result));
0756 for (gran_size = (1ULL<<16); gran_size < (1ULL<<32); gran_size <<= 1) {
0757
0758 for (chunk_size = gran_size; chunk_size < (1ULL<<32);
0759 chunk_size <<= 1) {
0760
0761 if (i >= NUM_RESULT)
0762 continue;
0763
0764 mtrr_calc_range_state(chunk_size, gran_size,
0765 x_remove_base, x_remove_size, i);
0766 if (debug_print) {
0767 mtrr_print_out_one_result(i);
0768 pr_info("\n");
0769 }
0770
0771 i++;
0772 }
0773 }
0774
0775
0776 index_good = mtrr_search_optimal_index();
0777
0778 if (index_good != -1) {
0779 pr_info("Found optimal setting for mtrr clean up\n");
0780 i = index_good;
0781 mtrr_print_out_one_result(i);
0782
0783
0784 chunk_size = result[i].chunk_sizek;
0785 chunk_size <<= 10;
0786 gran_size = result[i].gran_sizek;
0787 gran_size <<= 10;
0788 x86_setup_var_mtrrs(range, nr_range, chunk_size, gran_size);
0789 set_var_mtrr_all(address_bits);
0790 pr_debug("New variable MTRRs\n");
0791 print_out_mtrr_range_state();
0792 return 1;
0793 } else {
0794
0795 for (i = 0; i < NUM_RESULT; i++)
0796 mtrr_print_out_one_result(i);
0797 }
0798
0799 pr_info("mtrr_cleanup: can not find optimal value\n");
0800 pr_info("please specify mtrr_gran_size/mtrr_chunk_size\n");
0801
0802 return 0;
0803 }
0804 #else
0805 int __init mtrr_cleanup(unsigned address_bits)
0806 {
0807 return 0;
0808 }
0809 #endif
0810
0811 static int disable_mtrr_trim;
0812
0813 static int __init disable_mtrr_trim_setup(char *str)
0814 {
0815 disable_mtrr_trim = 1;
0816 return 0;
0817 }
0818 early_param("disable_mtrr_trim", disable_mtrr_trim_setup);
0819
0820
0821
0822
0823
0824
0825
0826 #define Tom2Enabled (1U << 21)
0827 #define Tom2ForceMemTypeWB (1U << 22)
0828
0829 int __init amd_special_default_mtrr(void)
0830 {
0831 u32 l, h;
0832
0833 if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD &&
0834 boot_cpu_data.x86_vendor != X86_VENDOR_HYGON)
0835 return 0;
0836 if (boot_cpu_data.x86 < 0xf)
0837 return 0;
0838
0839 if (rdmsr_safe(MSR_AMD64_SYSCFG, &l, &h) < 0)
0840 return 0;
0841
0842
0843
0844
0845 if ((l & (Tom2Enabled | Tom2ForceMemTypeWB)) ==
0846 (Tom2Enabled | Tom2ForceMemTypeWB))
0847 return 1;
0848 return 0;
0849 }
0850
0851 static u64 __init
0852 real_trim_memory(unsigned long start_pfn, unsigned long limit_pfn)
0853 {
0854 u64 trim_start, trim_size;
0855
0856 trim_start = start_pfn;
0857 trim_start <<= PAGE_SHIFT;
0858
0859 trim_size = limit_pfn;
0860 trim_size <<= PAGE_SHIFT;
0861 trim_size -= trim_start;
0862
0863 return e820__range_update(trim_start, trim_size, E820_TYPE_RAM, E820_TYPE_RESERVED);
0864 }
0865
0866
0867
0868
0869
0870
0871
0872
0873
0874
0875
0876
0877 int __init mtrr_trim_uncached_memory(unsigned long end_pfn)
0878 {
0879 unsigned long i, base, size, highest_pfn = 0, def, dummy;
0880 mtrr_type type;
0881 u64 total_trim_size;
0882
0883 int num[MTRR_NUM_TYPES + 1];
0884
0885
0886
0887
0888
0889 if (!is_cpu(INTEL) || disable_mtrr_trim)
0890 return 0;
0891
0892 rdmsr(MSR_MTRRdefType, def, dummy);
0893 def &= 0xff;
0894 if (def != MTRR_TYPE_UNCACHABLE)
0895 return 0;
0896
0897
0898 memset(range_state, 0, sizeof(range_state));
0899 for (i = 0; i < num_var_ranges; i++) {
0900 mtrr_if->get(i, &base, &size, &type);
0901 range_state[i].base_pfn = base;
0902 range_state[i].size_pfn = size;
0903 range_state[i].type = type;
0904 }
0905
0906
0907 for (i = 0; i < num_var_ranges; i++) {
0908 type = range_state[i].type;
0909 if (type != MTRR_TYPE_WRBACK)
0910 continue;
0911 base = range_state[i].base_pfn;
0912 size = range_state[i].size_pfn;
0913 if (highest_pfn < base + size)
0914 highest_pfn = base + size;
0915 }
0916
0917
0918 if (!highest_pfn) {
0919 pr_info("CPU MTRRs all blank - virtualized system.\n");
0920 return 0;
0921 }
0922
0923
0924 memset(num, 0, sizeof(num));
0925 for (i = 0; i < num_var_ranges; i++) {
0926 type = range_state[i].type;
0927 if (type >= MTRR_NUM_TYPES)
0928 continue;
0929 size = range_state[i].size_pfn;
0930 if (!size)
0931 type = MTRR_NUM_TYPES;
0932 num[type]++;
0933 }
0934
0935
0936 if (!num[MTRR_TYPE_WRBACK])
0937 return 0;
0938
0939
0940 if (num[MTRR_TYPE_WRBACK] + num[MTRR_TYPE_UNCACHABLE] !=
0941 num_var_ranges - num[MTRR_NUM_TYPES])
0942 return 0;
0943
0944 memset(range, 0, sizeof(range));
0945 nr_range = 0;
0946 if (mtrr_tom2) {
0947 range[nr_range].start = (1ULL<<(32 - PAGE_SHIFT));
0948 range[nr_range].end = mtrr_tom2 >> PAGE_SHIFT;
0949 if (highest_pfn < range[nr_range].end)
0950 highest_pfn = range[nr_range].end;
0951 nr_range++;
0952 }
0953 nr_range = x86_get_mtrr_mem_range(range, nr_range, 0, 0);
0954
0955
0956 total_trim_size = 0;
0957 if (range[0].start)
0958 total_trim_size += real_trim_memory(0, range[0].start);
0959
0960
0961 for (i = 0; i < nr_range - 1; i++) {
0962 if (range[i].end < range[i+1].start)
0963 total_trim_size += real_trim_memory(range[i].end,
0964 range[i+1].start);
0965 }
0966
0967
0968 i = nr_range - 1;
0969 if (range[i].end < end_pfn)
0970 total_trim_size += real_trim_memory(range[i].end,
0971 end_pfn);
0972
0973 if (total_trim_size) {
0974 pr_warn("WARNING: BIOS bug: CPU MTRRs don't cover all of memory, losing %lluMB of RAM.\n",
0975 total_trim_size >> 20);
0976
0977 if (!changed_by_mtrr_cleanup)
0978 WARN_ON(1);
0979
0980 pr_info("update e820 for mtrr\n");
0981 e820__update_table_print();
0982
0983 return 1;
0984 }
0985
0986 return 0;
0987 }