x86: separate mtrr cleanup/mtrr_e820 trim to separate file
authorYinghai Lu <yinghai@kernel.org>
Thu, 12 Mar 2009 03:07:39 +0000 (20:07 -0700)
committerIngo Molnar <mingo@elte.hu>
Fri, 13 Mar 2009 01:52:19 +0000 (02:52 +0100)
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>
arch/x86/kernel/cpu/mtrr/Makefile
arch/x86/kernel/cpu/mtrr/cleanup.c [new file with mode: 0644]
arch/x86/kernel/cpu/mtrr/main.c
arch/x86/kernel/cpu/mtrr/mtrr.h

index 191fc05..f4361b5 100644 (file)
@@ -1,3 +1,3 @@
-obj-y          := main.o if.o generic.o state.o
+obj-y          := main.o if.o generic.o state.o cleanup.o
 obj-$(CONFIG_X86_32) += amd.o cyrix.o centaur.o
 
diff --git a/arch/x86/kernel/cpu/mtrr/cleanup.c b/arch/x86/kernel/cpu/mtrr/cleanup.c
new file mode 100644 (file)
index 0000000..58b58bb
--- /dev/null
@@ -0,0 +1,1089 @@
+/*  MTRR (Memory Type Range Register) cleanup
+
+    Copyright (C) 2009 Yinghai Lu
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Library General Public
+    License as published by the Free Software Foundation; either
+    version 2 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Library General Public License for more details.
+
+    You should have received a copy of the GNU Library General Public
+    License along with this library; if not, write to the Free
+    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/smp.h>
+#include <linux/cpu.h>
+#include <linux/mutex.h>
+#include <linux/sort.h>
+
+#include <asm/e820.h>
+#include <asm/mtrr.h>
+#include <asm/uaccess.h>
+#include <asm/processor.h>
+#include <asm/msr.h>
+#include <asm/kvm_para.h>
+#include "mtrr.h"
+
+/* should be related to MTRR_VAR_RANGES nums */
+#define RANGE_NUM 256
+
+struct res_range {
+       unsigned long start;
+       unsigned long end;
+};
+
+static int __init
+add_range(struct res_range *range, int nr_range, unsigned long start,
+                             unsigned long end)
+{
+       /* out of slots */
+       if (nr_range >= RANGE_NUM)
+               return nr_range;
+
+       range[nr_range].start = start;
+       range[nr_range].end = end;
+
+       nr_range++;
+
+       return nr_range;
+}
+
+static int __init
+add_range_with_merge(struct res_range *range, int nr_range, unsigned long start,
+                             unsigned long end)
+{
+       int i;
+
+       /* try to merge it with old one */
+       for (i = 0; i < nr_range; i++) {
+               unsigned long final_start, final_end;
+               unsigned long common_start, common_end;
+
+               if (!range[i].end)
+                       continue;
+
+               common_start = max(range[i].start, start);
+               common_end = min(range[i].end, end);
+               if (common_start > common_end + 1)
+                       continue;
+
+               final_start = min(range[i].start, start);
+               final_end = max(range[i].end, end);
+
+               range[i].start = final_start;
+               range[i].end =  final_end;
+               return nr_range;
+       }
+
+       /* need to add that */
+       return add_range(range, nr_range, start, end);
+}
+
+static void __init
+subtract_range(struct res_range *range, unsigned long start, unsigned long end)
+{
+       int i, j;
+
+       for (j = 0; j < RANGE_NUM; j++) {
+               if (!range[j].end)
+                       continue;
+
+               if (start <= range[j].start && end >= range[j].end) {
+                       range[j].start = 0;
+                       range[j].end = 0;
+                       continue;
+               }
+
+               if (start <= range[j].start && end < range[j].end &&
+                   range[j].start < end + 1) {
+                       range[j].start = end + 1;
+                       continue;
+               }
+
+
+               if (start > range[j].start && end >= range[j].end &&
+                   range[j].end > start - 1) {
+                       range[j].end = start - 1;
+                       continue;
+               }
+
+               if (start > range[j].start && end < range[j].end) {
+                       /* find the new spare */
+                       for (i = 0; i < RANGE_NUM; i++) {
+                               if (range[i].end == 0)
+                                       break;
+                       }
+                       if (i < RANGE_NUM) {
+                               range[i].end = range[j].end;
+                               range[i].start = end + 1;
+                       } else {
+                               printk(KERN_ERR "run of slot in ranges\n");
+                       }
+                       range[j].end = start - 1;
+                       continue;
+               }
+       }
+}
+
+static int __init cmp_range(const void *x1, const void *x2)
+{
+       const struct res_range *r1 = x1;
+       const struct res_range *r2 = x2;
+       long start1, start2;
+
+       start1 = r1->start;
+       start2 = r2->start;
+
+       return start1 - start2;
+}
+
+struct var_mtrr_range_state {
+       unsigned long base_pfn;
+       unsigned long size_pfn;
+       mtrr_type type;
+};
+
+static struct var_mtrr_range_state __initdata range_state[RANGE_NUM];
+static int __initdata debug_print;
+
+static int __init
+x86_get_mtrr_mem_range(struct res_range *range, int nr_range,
+                      unsigned long extra_remove_base,
+                      unsigned long extra_remove_size)
+{
+       unsigned long i, base, size;
+       mtrr_type type;
+
+       for (i = 0; i < num_var_ranges; i++) {
+               type = range_state[i].type;
+               if (type != MTRR_TYPE_WRBACK)
+                       continue;
+               base = range_state[i].base_pfn;
+               size = range_state[i].size_pfn;
+               nr_range = add_range_with_merge(range, nr_range, base,
+                                               base + size - 1);
+       }
+       if (debug_print) {
+               printk(KERN_DEBUG "After WB checking\n");
+               for (i = 0; i < nr_range; i++)
+                       printk(KERN_DEBUG "MTRR MAP PFN: %016lx - %016lx\n",
+                                range[i].start, range[i].end + 1);
+       }
+
+       /* take out UC ranges */
+       for (i = 0; i < num_var_ranges; i++) {
+               type = range_state[i].type;
+               if (type != MTRR_TYPE_UNCACHABLE &&
+                   type != MTRR_TYPE_WRPROT)
+                       continue;
+               size = range_state[i].size_pfn;
+               if (!size)
+                       continue;
+               base = range_state[i].base_pfn;
+               subtract_range(range, base, base + size - 1);
+       }
+       if (extra_remove_size)
+               subtract_range(range, extra_remove_base,
+                                extra_remove_base + extra_remove_size  - 1);
+
+       /* get new range num */
+       nr_range = 0;
+       for (i = 0; i < RANGE_NUM; i++) {
+               if (!range[i].end)
+                       continue;
+               nr_range++;
+       }
+       if  (debug_print) {
+               printk(KERN_DEBUG "After UC checking\n");
+               for (i = 0; i < nr_range; i++)
+                       printk(KERN_DEBUG "MTRR MAP PFN: %016lx - %016lx\n",
+                                range[i].start, range[i].end + 1);
+       }
+
+       /* sort the ranges */
+       sort(range, nr_range, sizeof(struct res_range), cmp_range, NULL);
+       if  (debug_print) {
+               printk(KERN_DEBUG "After sorting\n");
+               for (i = 0; i < nr_range; i++)
+                       printk(KERN_DEBUG "MTRR MAP PFN: %016lx - %016lx\n",
+                                range[i].start, range[i].end + 1);
+       }
+
+       /* clear those is not used */
+       for (i = nr_range; i < RANGE_NUM; i++)
+               memset(&range[i], 0, sizeof(range[i]));
+
+       return nr_range;
+}
+
+static struct res_range __initdata range[RANGE_NUM];
+static int __initdata nr_range;
+
+#ifdef CONFIG_MTRR_SANITIZER
+
+static unsigned long __init sum_ranges(struct res_range *range, int nr_range)
+{
+       unsigned long sum;
+       int i;
+
+       sum = 0;
+       for (i = 0; i < nr_range; i++)
+               sum += range[i].end + 1 - range[i].start;
+
+       return sum;
+}
+
+static int enable_mtrr_cleanup __initdata =
+       CONFIG_MTRR_SANITIZER_ENABLE_DEFAULT;
+
+static int __init disable_mtrr_cleanup_setup(char *str)
+{
+       enable_mtrr_cleanup = 0;
+       return 0;
+}
+early_param("disable_mtrr_cleanup", disable_mtrr_cleanup_setup);
+
+static int __init enable_mtrr_cleanup_setup(char *str)
+{
+       enable_mtrr_cleanup = 1;
+       return 0;
+}
+early_param("enable_mtrr_cleanup", enable_mtrr_cleanup_setup);
+
+static int __init mtrr_cleanup_debug_setup(char *str)
+{
+       debug_print = 1;
+       return 0;
+}
+early_param("mtrr_cleanup_debug", mtrr_cleanup_debug_setup);
+
+struct var_mtrr_state {
+       unsigned long   range_startk;
+       unsigned long   range_sizek;
+       unsigned long   chunk_sizek;
+       unsigned long   gran_sizek;
+       unsigned int    reg;
+};
+
+static void __init
+set_var_mtrr(unsigned int reg, unsigned long basek, unsigned long sizek,
+               unsigned char type, unsigned int address_bits)
+{
+       u32 base_lo, base_hi, mask_lo, mask_hi;
+       u64 base, mask;
+
+       if (!sizek) {
+               fill_mtrr_var_range(reg, 0, 0, 0, 0);
+               return;
+       }
+
+       mask = (1ULL << address_bits) - 1;
+       mask &= ~((((u64)sizek) << 10) - 1);
+
+       base  = ((u64)basek) << 10;
+
+       base |= type;
+       mask |= 0x800;
+
+       base_lo = base & ((1ULL<<32) - 1);
+       base_hi = base >> 32;
+
+       mask_lo = mask & ((1ULL<<32) - 1);
+       mask_hi = mask >> 32;
+
+       fill_mtrr_var_range(reg, base_lo, base_hi, mask_lo, mask_hi);
+}
+
+static void __init
+save_var_mtrr(unsigned int reg, unsigned long basek, unsigned long sizek,
+               unsigned char type)
+{
+       range_state[reg].base_pfn = basek >> (PAGE_SHIFT - 10);
+       range_state[reg].size_pfn = sizek >> (PAGE_SHIFT - 10);
+       range_state[reg].type = type;
+}
+
+static void __init
+set_var_mtrr_all(unsigned int address_bits)
+{
+       unsigned long basek, sizek;
+       unsigned char type;
+       unsigned int reg;
+
+       for (reg = 0; reg < num_var_ranges; reg++) {
+               basek = range_state[reg].base_pfn << (PAGE_SHIFT - 10);
+               sizek = range_state[reg].size_pfn << (PAGE_SHIFT - 10);
+               type = range_state[reg].type;
+
+               set_var_mtrr(reg, basek, sizek, type, address_bits);
+       }
+}
+
+static unsigned long to_size_factor(unsigned long sizek, char *factorp)
+{
+       char factor;
+       unsigned long base = sizek;
+
+       if (base & ((1<<10) - 1)) {
+               /* not MB alignment */
+               factor = 'K';
+       } else if (base & ((1<<20) - 1)) {
+               factor = 'M';
+               base >>= 10;
+       } else {
+               factor = 'G';
+               base >>= 20;
+       }
+
+       *factorp = factor;
+
+       return base;
+}
+
+static unsigned int __init
+range_to_mtrr(unsigned int reg, unsigned long range_startk,
+             unsigned long range_sizek, unsigned char type)
+{
+       if (!range_sizek || (reg >= num_var_ranges))
+               return reg;
+
+       while (range_sizek) {
+               unsigned long max_align, align;
+               unsigned long sizek;
+
+               /* Compute the maximum size I can make a range */
+               if (range_startk)
+                       max_align = ffs(range_startk) - 1;
+               else
+                       max_align = 32;
+               align = fls(range_sizek) - 1;
+               if (align > max_align)
+                       align = max_align;
+
+               sizek = 1 << align;
+               if (debug_print) {
+                       char start_factor = 'K', size_factor = 'K';
+                       unsigned long start_base, size_base;
+
+                       start_base = to_size_factor(range_startk,
+                                                        &start_factor),
+                       size_base = to_size_factor(sizek, &size_factor),
+
+                       printk(KERN_DEBUG "Setting variable MTRR %d, "
+                               "base: %ld%cB, range: %ld%cB, type %s\n",
+                               reg, start_base, start_factor,
+                               size_base, size_factor,
+                               (type == MTRR_TYPE_UNCACHABLE) ? "UC" :
+                                  ((type == MTRR_TYPE_WRBACK) ? "WB" : "Other")
+                               );
+               }
+               save_var_mtrr(reg++, range_startk, sizek, type);
+               range_startk += sizek;
+               range_sizek -= sizek;
+               if (reg >= num_var_ranges)
+                       break;
+       }
+       return reg;
+}
+
+static unsigned __init
+range_to_mtrr_with_hole(struct var_mtrr_state *state, unsigned long basek,
+                       unsigned long sizek)
+{
+       unsigned long hole_basek, hole_sizek;
+       unsigned long second_basek, second_sizek;
+       unsigned long range0_basek, range0_sizek;
+       unsigned long range_basek, range_sizek;
+       unsigned long chunk_sizek;
+       unsigned long gran_sizek;
+
+       hole_basek = 0;
+       hole_sizek = 0;
+       second_basek = 0;
+       second_sizek = 0;
+       chunk_sizek = state->chunk_sizek;
+       gran_sizek = state->gran_sizek;
+
+       /* align with gran size, prevent small block used up MTRRs */
+       range_basek = ALIGN(state->range_startk, gran_sizek);
+       if ((range_basek > basek) && basek)
+               return second_sizek;
+       state->range_sizek -= (range_basek - state->range_startk);
+       range_sizek = ALIGN(state->range_sizek, gran_sizek);
+
+       while (range_sizek > state->range_sizek) {
+               range_sizek -= gran_sizek;
+               if (!range_sizek)
+                       return 0;
+       }
+       state->range_sizek = range_sizek;
+
+       /* try to append some small hole */
+       range0_basek = state->range_startk;
+       range0_sizek = ALIGN(state->range_sizek, chunk_sizek);
+
+       /* no increase */
+       if (range0_sizek == state->range_sizek) {
+               if (debug_print)
+                       printk(KERN_DEBUG "rangeX: %016lx - %016lx\n",
+                               range0_basek<<10,
+                               (range0_basek + state->range_sizek)<<10);
+               state->reg = range_to_mtrr(state->reg, range0_basek,
+                               state->range_sizek, MTRR_TYPE_WRBACK);
+               return 0;
+       }
+
+       /* only cut back, when it is not the last */
+       if (sizek) {
+               while (range0_basek + range0_sizek > (basek + sizek)) {
+                       if (range0_sizek >= chunk_sizek)
+                               range0_sizek -= chunk_sizek;
+                       else
+                               range0_sizek = 0;
+
+                       if (!range0_sizek)
+                               break;
+               }
+       }
+
+second_try:
+       range_basek = range0_basek + range0_sizek;
+
+       /* one hole in the middle */
+       if (range_basek > basek && range_basek <= (basek + sizek))
+               second_sizek = range_basek - basek;
+
+       if (range0_sizek > state->range_sizek) {
+
+               /* one hole in middle or at end */
+               hole_sizek = range0_sizek - state->range_sizek - second_sizek;
+
+               /* hole size should be less than half of range0 size */
+               if (hole_sizek >= (range0_sizek >> 1) &&
+                   range0_sizek >= chunk_sizek) {
+                       range0_sizek -= chunk_sizek;
+                       second_sizek = 0;
+                       hole_sizek = 0;
+
+                       goto second_try;
+               }
+       }
+
+       if (range0_sizek) {
+               if (debug_print)
+                       printk(KERN_DEBUG "range0: %016lx - %016lx\n",
+                               range0_basek<<10,
+                               (range0_basek + range0_sizek)<<10);
+               state->reg = range_to_mtrr(state->reg, range0_basek,
+                               range0_sizek, MTRR_TYPE_WRBACK);
+       }
+
+       if (range0_sizek < state->range_sizek) {
+               /* need to handle left over */
+               range_sizek = state->range_sizek - range0_sizek;
+
+               if (debug_print)
+                       printk(KERN_DEBUG "range: %016lx - %016lx\n",
+                                range_basek<<10,
+                                (range_basek + range_sizek)<<10);
+               state->reg = range_to_mtrr(state->reg, range_basek,
+                                range_sizek, MTRR_TYPE_WRBACK);
+       }
+
+       if (hole_sizek) {
+               hole_basek = range_basek - hole_sizek - second_sizek;
+               if (debug_print)
+                       printk(KERN_DEBUG "hole: %016lx - %016lx\n",
+                                hole_basek<<10,
+                                (hole_basek + hole_sizek)<<10);
+               state->reg = range_to_mtrr(state->reg, hole_basek,
+                                hole_sizek, MTRR_TYPE_UNCACHABLE);
+       }
+
+       return second_sizek;
+}
+
+static void __init
+set_var_mtrr_range(struct var_mtrr_state *state, unsigned long base_pfn,
+                  unsigned long size_pfn)
+{
+       unsigned long basek, sizek;
+       unsigned long second_sizek = 0;
+
+       if (state->reg >= num_var_ranges)
+               return;
+
+       basek = base_pfn << (PAGE_SHIFT - 10);
+       sizek = size_pfn << (PAGE_SHIFT - 10);
+
+       /* See if I can merge with the last range */
+       if ((basek <= 1024) ||
+           (state->range_startk + state->range_sizek == basek)) {
+               unsigned long endk = basek + sizek;
+               state->range_sizek = endk - state->range_startk;
+               return;
+       }
+       /* Write the range mtrrs */
+       if (state->range_sizek != 0)
+               second_sizek = range_to_mtrr_with_hole(state, basek, sizek);
+
+       /* Allocate an msr */
+       state->range_startk = basek + second_sizek;
+       state->range_sizek  = sizek - second_sizek;
+}
+
+/* mininum size of mtrr block that can take hole */
+static u64 mtrr_chunk_size __initdata = (256ULL<<20);
+
+static int __init parse_mtrr_chunk_size_opt(char *p)
+{
+       if (!p)
+               return -EINVAL;
+       mtrr_chunk_size = memparse(p, &p);
+       return 0;
+}
+early_param("mtrr_chunk_size", parse_mtrr_chunk_size_opt);
+
+/* granity of mtrr of block */
+static u64 mtrr_gran_size __initdata;
+
+static int __init parse_mtrr_gran_size_opt(char *p)
+{
+       if (!p)
+               return -EINVAL;
+       mtrr_gran_size = memparse(p, &p);
+       return 0;
+}
+early_param("mtrr_gran_size", parse_mtrr_gran_size_opt);
+
+static int nr_mtrr_spare_reg __initdata =
+                                CONFIG_MTRR_SANITIZER_SPARE_REG_NR_DEFAULT;
+
+static int __init parse_mtrr_spare_reg(char *arg)
+{
+       if (arg)
+               nr_mtrr_spare_reg = simple_strtoul(arg, NULL, 0);
+       return 0;
+}
+
+early_param("mtrr_spare_reg_nr", parse_mtrr_spare_reg);
+
+static int __init
+x86_setup_var_mtrrs(struct res_range *range, int nr_range,
+                   u64 chunk_size, u64 gran_size)
+{
+       struct var_mtrr_state var_state;
+       int i;
+       int num_reg;
+
+       var_state.range_startk  = 0;
+       var_state.range_sizek   = 0;
+       var_state.reg           = 0;
+       var_state.chunk_sizek   = chunk_size >> 10;
+       var_state.gran_sizek    = gran_size >> 10;
+
+       memset(range_state, 0, sizeof(range_state));
+
+       /* Write the range etc */
+       for (i = 0; i < nr_range; i++)
+               set_var_mtrr_range(&var_state, range[i].start,
+                                  range[i].end - range[i].start + 1);
+
+       /* Write the last range */
+       if (var_state.range_sizek != 0)
+               range_to_mtrr_with_hole(&var_state, 0, 0);
+
+       num_reg = var_state.reg;
+       /* Clear out the extra MTRR's */
+       while (var_state.reg < num_var_ranges) {
+               save_var_mtrr(var_state.reg, 0, 0, 0);
+               var_state.reg++;
+       }
+
+       return num_reg;
+}
+
+struct mtrr_cleanup_result {
+       unsigned long gran_sizek;
+       unsigned long chunk_sizek;
+       unsigned long lose_cover_sizek;
+       unsigned int num_reg;
+       int bad;
+};
+
+/*
+ * gran_size: 64K, 128K, 256K, 512K, 1M, 2M, ..., 2G
+ * chunk size: gran_size, ..., 2G
+ * so we need (1+16)*8
+ */
+#define NUM_RESULT     136
+#define PSHIFT         (PAGE_SHIFT - 10)
+
+static struct mtrr_cleanup_result __initdata result[NUM_RESULT];
+static unsigned long __initdata min_loss_pfn[RANGE_NUM];
+
+static void __init print_out_mtrr_range_state(void)
+{
+       int i;
+       char start_factor = 'K', size_factor = 'K';
+       unsigned long start_base, size_base;
+       mtrr_type type;
+
+       for (i = 0; i < num_var_ranges; i++) {
+
+               size_base = range_state[i].size_pfn << (PAGE_SHIFT - 10);
+               if (!size_base)
+                       continue;
+
+               size_base = to_size_factor(size_base, &size_factor),
+               start_base = range_state[i].base_pfn << (PAGE_SHIFT - 10);
+               start_base = to_size_factor(start_base, &start_factor),
+               type = range_state[i].type;
+
+               printk(KERN_DEBUG "reg %d, base: %ld%cB, range: %ld%cB, type %s\n",
+                       i, start_base, start_factor,
+                       size_base, size_factor,
+                       (type == MTRR_TYPE_UNCACHABLE) ? "UC" :
+                           ((type == MTRR_TYPE_WRPROT) ? "WP" :
+                            ((type == MTRR_TYPE_WRBACK) ? "WB" : "Other"))
+                       );
+       }
+}
+
+static int __init mtrr_need_cleanup(void)
+{
+       int i;
+       mtrr_type type;
+       unsigned long size;
+       /* extra one for all 0 */
+       int num[MTRR_NUM_TYPES + 1];
+
+       /* check entries number */
+       memset(num, 0, sizeof(num));
+       for (i = 0; i < num_var_ranges; i++) {
+               type = range_state[i].type;
+               size = range_state[i].size_pfn;
+               if (type >= MTRR_NUM_TYPES)
+                       continue;
+               if (!size)
+                       type = MTRR_NUM_TYPES;
+               if (type == MTRR_TYPE_WRPROT)
+                       type = MTRR_TYPE_UNCACHABLE;
+               num[type]++;
+       }
+
+       /* check if we got UC entries */
+       if (!num[MTRR_TYPE_UNCACHABLE])
+               return 0;
+
+       /* check if we only had WB and UC */
+       if (num[MTRR_TYPE_WRBACK] + num[MTRR_TYPE_UNCACHABLE] !=
+               num_var_ranges - num[MTRR_NUM_TYPES])
+               return 0;
+
+       return 1;
+}
+
+static unsigned long __initdata range_sums;
+static void __init mtrr_calc_range_state(u64 chunk_size, u64 gran_size,
+                                        unsigned long extra_remove_base,
+                                        unsigned long extra_remove_size,
+                                        int i)
+{
+       int num_reg;
+       static struct res_range range_new[RANGE_NUM];
+       static int nr_range_new;
+       unsigned long range_sums_new;
+
+       /* convert ranges to var ranges state */
+       num_reg = x86_setup_var_mtrrs(range, nr_range,
+                                               chunk_size, gran_size);
+
+       /* we got new setting in range_state, check it */
+       memset(range_new, 0, sizeof(range_new));
+       nr_range_new = x86_get_mtrr_mem_range(range_new, 0,
+                               extra_remove_base, extra_remove_size);
+       range_sums_new = sum_ranges(range_new, nr_range_new);
+
+       result[i].chunk_sizek = chunk_size >> 10;
+       result[i].gran_sizek = gran_size >> 10;
+       result[i].num_reg = num_reg;
+       if (range_sums < range_sums_new) {
+               result[i].lose_cover_sizek =
+                       (range_sums_new - range_sums) << PSHIFT;
+               result[i].bad = 1;
+       } else
+               result[i].lose_cover_sizek =
+                       (range_sums - range_sums_new) << PSHIFT;
+
+       /* double check it */
+       if (!result[i].bad && !result[i].lose_cover_sizek) {
+               if (nr_range_new != nr_range ||
+                       memcmp(range, range_new, sizeof(range)))
+                               result[i].bad = 1;
+       }
+
+       if (!result[i].bad && (range_sums - range_sums_new <
+                               min_loss_pfn[num_reg])) {
+               min_loss_pfn[num_reg] =
+                       range_sums - range_sums_new;
+       }
+}
+
+static void __init mtrr_print_out_one_result(int i)
+{
+       char gran_factor, chunk_factor, lose_factor;
+       unsigned long gran_base, chunk_base, lose_base;
+
+       gran_base = to_size_factor(result[i].gran_sizek, &gran_factor),
+       chunk_base = to_size_factor(result[i].chunk_sizek, &chunk_factor),
+       lose_base = to_size_factor(result[i].lose_cover_sizek, &lose_factor),
+       printk(KERN_INFO "%sgran_size: %ld%c \tchunk_size: %ld%c \t",
+                       result[i].bad ? "*BAD*" : " ",
+                       gran_base, gran_factor, chunk_base, chunk_factor);
+       printk(KERN_CONT "num_reg: %d  \tlose cover RAM: %s%ld%c\n",
+                       result[i].num_reg, result[i].bad ? "-" : "",
+                       lose_base, lose_factor);
+}
+
+static int __init mtrr_search_optimal_index(void)
+{
+       int i;
+       int num_reg_good;
+       int index_good;
+
+       if (nr_mtrr_spare_reg >= num_var_ranges)
+               nr_mtrr_spare_reg = num_var_ranges - 1;
+       num_reg_good = -1;
+       for (i = num_var_ranges - nr_mtrr_spare_reg; i > 0; i--) {
+               if (!min_loss_pfn[i])
+                       num_reg_good = i;
+       }
+
+       index_good = -1;
+       if (num_reg_good != -1) {
+               for (i = 0; i < NUM_RESULT; i++) {
+                       if (!result[i].bad &&
+                           result[i].num_reg == num_reg_good &&
+                           !result[i].lose_cover_sizek) {
+                               index_good = i;
+                               break;
+                       }
+               }
+       }
+
+       return index_good;
+}
+
+
+int __init mtrr_cleanup(unsigned address_bits)
+{
+       unsigned long extra_remove_base, extra_remove_size;
+       unsigned long base, size, def, dummy;
+       mtrr_type type;
+       u64 chunk_size, gran_size;
+       int index_good;
+       int i;
+
+       if (!is_cpu(INTEL) || enable_mtrr_cleanup < 1)
+               return 0;
+       rdmsr(MTRRdefType_MSR, def, dummy);
+       def &= 0xff;
+       if (def != MTRR_TYPE_UNCACHABLE)
+               return 0;
+
+       /* get it and store it aside */
+       memset(range_state, 0, sizeof(range_state));
+       for (i = 0; i < num_var_ranges; i++) {
+               mtrr_if->get(i, &base, &size, &type);
+               range_state[i].base_pfn = base;
+               range_state[i].size_pfn = size;
+               range_state[i].type = type;
+       }
+
+       /* check if we need handle it and can handle it */
+       if (!mtrr_need_cleanup())
+               return 0;
+
+       /* print original var MTRRs at first, for debugging: */
+       printk(KERN_DEBUG "original variable MTRRs\n");
+       print_out_mtrr_range_state();
+
+       memset(range, 0, sizeof(range));
+       extra_remove_size = 0;
+       extra_remove_base = 1 << (32 - PAGE_SHIFT);
+       if (mtrr_tom2)
+               extra_remove_size =
+                       (mtrr_tom2 >> PAGE_SHIFT) - extra_remove_base;
+       nr_range = x86_get_mtrr_mem_range(range, 0, extra_remove_base,
+                                         extra_remove_size);
+       /*
+        * [0, 1M) should always be coverred by var mtrr with WB
+        * and fixed mtrrs should take effective before var mtrr for it
+        */
+       nr_range = add_range_with_merge(range, nr_range, 0,
+                                       (1ULL<<(20 - PAGE_SHIFT)) - 1);
+       /* sort the ranges */
+       sort(range, nr_range, sizeof(struct res_range), cmp_range, NULL);
+
+       range_sums = sum_ranges(range, nr_range);
+       printk(KERN_INFO "total RAM coverred: %ldM\n",
+              range_sums >> (20 - PAGE_SHIFT));
+
+       if (mtrr_chunk_size && mtrr_gran_size) {
+               i = 0;
+               mtrr_calc_range_state(mtrr_chunk_size, mtrr_gran_size,
+                                     extra_remove_base, extra_remove_size, i);
+
+               mtrr_print_out_one_result(i);
+
+               if (!result[i].bad) {
+                       set_var_mtrr_all(address_bits);
+                       printk(KERN_DEBUG "New variable MTRRs\n");
+                       print_out_mtrr_range_state();
+                       return 1;
+               }
+               printk(KERN_INFO "invalid mtrr_gran_size or mtrr_chunk_size, "
+                      "will find optimal one\n");
+       }
+
+       i = 0;
+       memset(min_loss_pfn, 0xff, sizeof(min_loss_pfn));
+       memset(result, 0, sizeof(result));
+       for (gran_size = (1ULL<<16); gran_size < (1ULL<<32); gran_size <<= 1) {
+
+               for (chunk_size = gran_size; chunk_size < (1ULL<<32);
+                    chunk_size <<= 1) {
+
+                       if (i >= NUM_RESULT)
+                               continue;
+
+                       mtrr_calc_range_state(chunk_size, gran_size,
+                                     extra_remove_base, extra_remove_size, i);
+                       if (debug_print) {
+                               mtrr_print_out_one_result(i);
+                               printk(KERN_INFO "\n");
+                       }
+
+                       i++;
+               }
+       }
+
+       /* try to find the optimal index */
+       index_good = mtrr_search_optimal_index();
+
+       if (index_good != -1) {
+               printk(KERN_INFO "Found optimal setting for mtrr clean up\n");
+               i = index_good;
+               mtrr_print_out_one_result(i);
+
+               /* convert ranges to var ranges state */
+               chunk_size = result[i].chunk_sizek;
+               chunk_size <<= 10;
+               gran_size = result[i].gran_sizek;
+               gran_size <<= 10;
+               x86_setup_var_mtrrs(range, nr_range, chunk_size, gran_size);
+               set_var_mtrr_all(address_bits);
+               printk(KERN_DEBUG "New variable MTRRs\n");
+               print_out_mtrr_range_state();
+               return 1;
+       } else {
+               /* print out all */
+               for (i = 0; i < NUM_RESULT; i++)
+                       mtrr_print_out_one_result(i);
+       }
+
+       printk(KERN_INFO "mtrr_cleanup: can not find optimal value\n");
+       printk(KERN_INFO "please specify mtrr_gran_size/mtrr_chunk_size\n");
+
+       return 0;
+}
+#else
+int __init mtrr_cleanup(unsigned address_bits)
+{
+       return 0;
+}
+#endif
+
+static int disable_mtrr_trim;
+
+static int __init disable_mtrr_trim_setup(char *str)
+{
+       disable_mtrr_trim = 1;
+       return 0;
+}
+early_param("disable_mtrr_trim", disable_mtrr_trim_setup);
+
+/*
+ * Newer AMD K8s and later CPUs have a special magic MSR way to force WB
+ * for memory >4GB. Check for that here.
+ * Note this won't check if the MTRRs < 4GB where the magic bit doesn't
+ * apply to are wrong, but so far we don't know of any such case in the wild.
+ */
+#define Tom2Enabled (1U << 21)
+#define Tom2ForceMemTypeWB (1U << 22)
+
+int __init amd_special_default_mtrr(void)
+{
+       u32 l, h;
+
+       if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD)
+               return 0;
+       if (boot_cpu_data.x86 < 0xf || boot_cpu_data.x86 > 0x11)
+               return 0;
+       /* In case some hypervisor doesn't pass SYSCFG through */
+       if (rdmsr_safe(MSR_K8_SYSCFG, &l, &h) < 0)
+               return 0;
+       /*
+        * Memory between 4GB and top of mem is forced WB by this magic bit.
+        * Reserved before K8RevF, but should be zero there.
+        */
+       if ((l & (Tom2Enabled | Tom2ForceMemTypeWB)) ==
+                (Tom2Enabled | Tom2ForceMemTypeWB))
+               return 1;
+       return 0;
+}
+
+static u64 __init real_trim_memory(unsigned long start_pfn,
+                                  unsigned long limit_pfn)
+{
+       u64 trim_start, trim_size;
+       trim_start = start_pfn;
+       trim_start <<= PAGE_SHIFT;
+       trim_size = limit_pfn;
+       trim_size <<= PAGE_SHIFT;
+       trim_size -= trim_start;
+
+       return e820_update_range(trim_start, trim_size, E820_RAM,
+                               E820_RESERVED);
+}
+/**
+ * mtrr_trim_uncached_memory - trim RAM not covered by MTRRs
+ * @end_pfn: ending page frame number
+ *
+ * Some buggy BIOSes don't setup the MTRRs properly for systems with certain
+ * memory configurations.  This routine checks that the highest MTRR matches
+ * the end of memory, to make sure the MTRRs having a write back type cover
+ * all of the memory the kernel is intending to use. If not, it'll trim any
+ * memory off the end by adjusting end_pfn, removing it from the kernel's
+ * allocation pools, warning the user with an obnoxious message.
+ */
+int __init mtrr_trim_uncached_memory(unsigned long end_pfn)
+{
+       unsigned long i, base, size, highest_pfn = 0, def, dummy;
+       mtrr_type type;
+       u64 total_trim_size;
+
+       /* extra one for all 0 */
+       int num[MTRR_NUM_TYPES + 1];
+       /*
+        * Make sure we only trim uncachable memory on machines that
+        * support the Intel MTRR architecture:
+        */
+       if (!is_cpu(INTEL) || disable_mtrr_trim)
+               return 0;
+       rdmsr(MTRRdefType_MSR, def, dummy);
+       def &= 0xff;
+       if (def != MTRR_TYPE_UNCACHABLE)
+               return 0;
+
+       /* get it and store it aside */
+       memset(range_state, 0, sizeof(range_state));
+       for (i = 0; i < num_var_ranges; i++) {
+               mtrr_if->get(i, &base, &size, &type);
+               range_state[i].base_pfn = base;
+               range_state[i].size_pfn = size;
+               range_state[i].type = type;
+       }
+
+       /* Find highest cached pfn */
+       for (i = 0; i < num_var_ranges; i++) {
+               type = range_state[i].type;
+               if (type != MTRR_TYPE_WRBACK)
+                       continue;
+               base = range_state[i].base_pfn;
+               size = range_state[i].size_pfn;
+               if (highest_pfn < base + size)
+                       highest_pfn = base + size;
+       }
+
+       /* kvm/qemu doesn't have mtrr set right, don't trim them all */
+       if (!highest_pfn) {
+               printk(KERN_INFO "CPU MTRRs all blank - virtualized system.\n");
+               return 0;
+       }
+
+       /* check entries number */
+       memset(num, 0, sizeof(num));
+       for (i = 0; i < num_var_ranges; i++) {
+               type = range_state[i].type;
+               if (type >= MTRR_NUM_TYPES)
+                       continue;
+               size = range_state[i].size_pfn;
+               if (!size)
+                       type = MTRR_NUM_TYPES;
+               num[type]++;
+       }
+
+       /* no entry for WB? */
+       if (!num[MTRR_TYPE_WRBACK])
+               return 0;
+
+       /* check if we only had WB and UC */
+       if (num[MTRR_TYPE_WRBACK] + num[MTRR_TYPE_UNCACHABLE] !=
+               num_var_ranges - num[MTRR_NUM_TYPES])
+               return 0;
+
+       memset(range, 0, sizeof(range));
+       nr_range = 0;
+       if (mtrr_tom2) {
+               range[nr_range].start = (1ULL<<(32 - PAGE_SHIFT));
+               range[nr_range].end = (mtrr_tom2 >> PAGE_SHIFT) - 1;
+               if (highest_pfn < range[nr_range].end + 1)
+                       highest_pfn = range[nr_range].end + 1;
+               nr_range++;
+       }
+       nr_range = x86_get_mtrr_mem_range(range, nr_range, 0, 0);
+
+       total_trim_size = 0;
+       /* check the head */
+       if (range[0].start)
+               total_trim_size += real_trim_memory(0, range[0].start);
+       /* check the holes */
+       for (i = 0; i < nr_range - 1; i++) {
+               if (range[i].end + 1 < range[i+1].start)
+                       total_trim_size += real_trim_memory(range[i].end + 1,
+                                                           range[i+1].start);
+       }
+       /* check the top */
+       i = nr_range - 1;
+       if (range[i].end + 1 < end_pfn)
+               total_trim_size += real_trim_memory(range[i].end + 1,
+                                                        end_pfn);
+
+       if (total_trim_size) {
+               printk(KERN_WARNING "WARNING: BIOS bug: CPU MTRRs don't cover"
+                       " all of memory, losing %lluMB of RAM.\n",
+                       total_trim_size >> 20);
+
+               if (!changed_by_mtrr_cleanup)
+                       WARN_ON(1);
+
+               printk(KERN_INFO "update e820 for mtrr\n");
+               update_e820();
+
+               return 1;
+       }
+
+       return 0;
+}
+
index 311a473..5c2e266 100644 (file)
@@ -610,1060 +610,7 @@ static struct sysdev_driver mtrr_sysdev_driver = {
        .resume         = mtrr_restore,
 };
 
-/* should be related to MTRR_VAR_RANGES nums */
-#define RANGE_NUM 256
-
-struct res_range {
-       unsigned long start;
-       unsigned long end;
-};
-
-static int __init
-add_range(struct res_range *range, int nr_range, unsigned long start,
-                             unsigned long end)
-{
-       /* out of slots */
-       if (nr_range >= RANGE_NUM)
-               return nr_range;
-
-       range[nr_range].start = start;
-       range[nr_range].end = end;
-
-       nr_range++;
-
-       return nr_range;
-}
-
-static int __init
-add_range_with_merge(struct res_range *range, int nr_range, unsigned long start,
-                             unsigned long end)
-{
-       int i;
-
-       /* try to merge it with old one */
-       for (i = 0; i < nr_range; i++) {
-               unsigned long final_start, final_end;
-               unsigned long common_start, common_end;
-
-               if (!range[i].end)
-                       continue;
-
-               common_start = max(range[i].start, start);
-               common_end = min(range[i].end, end);
-               if (common_start > common_end + 1)
-                       continue;
-
-               final_start = min(range[i].start, start);
-               final_end = max(range[i].end, end);
-
-               range[i].start = final_start;
-               range[i].end =  final_end;
-               return nr_range;
-       }
-
-       /* need to add that */
-       return add_range(range, nr_range, start, end);
-}
-
-static void __init
-subtract_range(struct res_range *range, unsigned long start, unsigned long end)
-{
-       int i, j;
-
-       for (j = 0; j < RANGE_NUM; j++) {
-               if (!range[j].end)
-                       continue;
-
-               if (start <= range[j].start && end >= range[j].end) {
-                       range[j].start = 0;
-                       range[j].end = 0;
-                       continue;
-               }
-
-               if (start <= range[j].start && end < range[j].end &&
-                   range[j].start < end + 1) {
-                       range[j].start = end + 1;
-                       continue;
-               }
-
-
-               if (start > range[j].start && end >= range[j].end &&
-                   range[j].end > start - 1) {
-                       range[j].end = start - 1;
-                       continue;
-               }
-
-               if (start > range[j].start && end < range[j].end) {
-                       /* find the new spare */
-                       for (i = 0; i < RANGE_NUM; i++) {
-                               if (range[i].end == 0)
-                                       break;
-                       }
-                       if (i < RANGE_NUM) {
-                               range[i].end = range[j].end;
-                               range[i].start = end + 1;
-                       } else {
-                               printk(KERN_ERR "run of slot in ranges\n");
-                       }
-                       range[j].end = start - 1;
-                       continue;
-               }
-       }
-}
-
-static int __init cmp_range(const void *x1, const void *x2)
-{
-       const struct res_range *r1 = x1;
-       const struct res_range *r2 = x2;
-       long start1, start2;
-
-       start1 = r1->start;
-       start2 = r2->start;
-
-       return start1 - start2;
-}
-
-struct var_mtrr_range_state {
-       unsigned long base_pfn;
-       unsigned long size_pfn;
-       mtrr_type type;
-};
-
-static struct var_mtrr_range_state __initdata range_state[RANGE_NUM];
-static int __initdata debug_print;
-
-static int __init
-x86_get_mtrr_mem_range(struct res_range *range, int nr_range,
-                      unsigned long extra_remove_base,
-                      unsigned long extra_remove_size)
-{
-       unsigned long i, base, size;
-       mtrr_type type;
-
-       for (i = 0; i < num_var_ranges; i++) {
-               type = range_state[i].type;
-               if (type != MTRR_TYPE_WRBACK)
-                       continue;
-               base = range_state[i].base_pfn;
-               size = range_state[i].size_pfn;
-               nr_range = add_range_with_merge(range, nr_range, base,
-                                               base + size - 1);
-       }
-       if (debug_print) {
-               printk(KERN_DEBUG "After WB checking\n");
-               for (i = 0; i < nr_range; i++)
-                       printk(KERN_DEBUG "MTRR MAP PFN: %016lx - %016lx\n",
-                                range[i].start, range[i].end + 1);
-       }
-
-       /* take out UC ranges */
-       for (i = 0; i < num_var_ranges; i++) {
-               type = range_state[i].type;
-               if (type != MTRR_TYPE_UNCACHABLE &&
-                   type != MTRR_TYPE_WRPROT)
-                       continue;
-               size = range_state[i].size_pfn;
-               if (!size)
-                       continue;
-               base = range_state[i].base_pfn;
-               subtract_range(range, base, base + size - 1);
-       }
-       if (extra_remove_size)
-               subtract_range(range, extra_remove_base,
-                                extra_remove_base + extra_remove_size  - 1);
-
-       /* get new range num */
-       nr_range = 0;
-       for (i = 0; i < RANGE_NUM; i++) {
-               if (!range[i].end)
-                       continue;
-               nr_range++;
-       }
-       if  (debug_print) {
-               printk(KERN_DEBUG "After UC checking\n");
-               for (i = 0; i < nr_range; i++)
-                       printk(KERN_DEBUG "MTRR MAP PFN: %016lx - %016lx\n",
-                                range[i].start, range[i].end + 1);
-       }
-
-       /* sort the ranges */
-       sort(range, nr_range, sizeof(struct res_range), cmp_range, NULL);
-       if  (debug_print) {
-               printk(KERN_DEBUG "After sorting\n");
-               for (i = 0; i < nr_range; i++)
-                       printk(KERN_DEBUG "MTRR MAP PFN: %016lx - %016lx\n",
-                                range[i].start, range[i].end + 1);
-       }
-
-       /* clear those is not used */
-       for (i = nr_range; i < RANGE_NUM; i++)
-               memset(&range[i], 0, sizeof(range[i]));
-
-       return nr_range;
-}
-
-static struct res_range __initdata range[RANGE_NUM];
-static int __initdata nr_range;
-
-#ifdef CONFIG_MTRR_SANITIZER
-
-static unsigned long __init sum_ranges(struct res_range *range, int nr_range)
-{
-       unsigned long sum;
-       int i;
-
-       sum = 0;
-       for (i = 0; i < nr_range; i++)
-               sum += range[i].end + 1 - range[i].start;
-
-       return sum;
-}
-
-static int enable_mtrr_cleanup __initdata =
-       CONFIG_MTRR_SANITIZER_ENABLE_DEFAULT;
-
-static int __init disable_mtrr_cleanup_setup(char *str)
-{
-       enable_mtrr_cleanup = 0;
-       return 0;
-}
-early_param("disable_mtrr_cleanup", disable_mtrr_cleanup_setup);
-
-static int __init enable_mtrr_cleanup_setup(char *str)
-{
-       enable_mtrr_cleanup = 1;
-       return 0;
-}
-early_param("enable_mtrr_cleanup", enable_mtrr_cleanup_setup);
-
-static int __init mtrr_cleanup_debug_setup(char *str)
-{
-       debug_print = 1;
-       return 0;
-}
-early_param("mtrr_cleanup_debug", mtrr_cleanup_debug_setup);
-
-struct var_mtrr_state {
-       unsigned long   range_startk;
-       unsigned long   range_sizek;
-       unsigned long   chunk_sizek;
-       unsigned long   gran_sizek;
-       unsigned int    reg;
-};
-
-static void __init
-set_var_mtrr(unsigned int reg, unsigned long basek, unsigned long sizek,
-               unsigned char type, unsigned int address_bits)
-{
-       u32 base_lo, base_hi, mask_lo, mask_hi;
-       u64 base, mask;
-
-       if (!sizek) {
-               fill_mtrr_var_range(reg, 0, 0, 0, 0);
-               return;
-       }
-
-       mask = (1ULL << address_bits) - 1;
-       mask &= ~((((u64)sizek) << 10) - 1);
-
-       base  = ((u64)basek) << 10;
-
-       base |= type;
-       mask |= 0x800;
-
-       base_lo = base & ((1ULL<<32) - 1);
-       base_hi = base >> 32;
-
-       mask_lo = mask & ((1ULL<<32) - 1);
-       mask_hi = mask >> 32;
-
-       fill_mtrr_var_range(reg, base_lo, base_hi, mask_lo, mask_hi);
-}
-
-static void __init
-save_var_mtrr(unsigned int reg, unsigned long basek, unsigned long sizek,
-               unsigned char type)
-{
-       range_state[reg].base_pfn = basek >> (PAGE_SHIFT - 10);
-       range_state[reg].size_pfn = sizek >> (PAGE_SHIFT - 10);
-       range_state[reg].type = type;
-}
-
-static void __init
-set_var_mtrr_all(unsigned int address_bits)
-{
-       unsigned long basek, sizek;
-       unsigned char type;
-       unsigned int reg;
-
-       for (reg = 0; reg < num_var_ranges; reg++) {
-               basek = range_state[reg].base_pfn << (PAGE_SHIFT - 10);
-               sizek = range_state[reg].size_pfn << (PAGE_SHIFT - 10);
-               type = range_state[reg].type;
-
-               set_var_mtrr(reg, basek, sizek, type, address_bits);
-       }
-}
-
-static unsigned long to_size_factor(unsigned long sizek, char *factorp)
-{
-       char factor;
-       unsigned long base = sizek;
-
-       if (base & ((1<<10) - 1)) {
-               /* not MB alignment */
-               factor = 'K';
-       } else if (base & ((1<<20) - 1)){
-               factor = 'M';
-               base >>= 10;
-       } else {
-               factor = 'G';
-               base >>= 20;
-       }
-
-       *factorp = factor;
-
-       return base;
-}
-
-static unsigned int __init
-range_to_mtrr(unsigned int reg, unsigned long range_startk,
-             unsigned long range_sizek, unsigned char type)
-{
-       if (!range_sizek || (reg >= num_var_ranges))
-               return reg;
-
-       while (range_sizek) {
-               unsigned long max_align, align;
-               unsigned long sizek;
-
-               /* Compute the maximum size I can make a range */
-               if (range_startk)
-                       max_align = ffs(range_startk) - 1;
-               else
-                       max_align = 32;
-               align = fls(range_sizek) - 1;
-               if (align > max_align)
-                       align = max_align;
-
-               sizek = 1 << align;
-               if (debug_print) {
-                       char start_factor = 'K', size_factor = 'K';
-                       unsigned long start_base, size_base;
-
-                       start_base = to_size_factor(range_startk, &start_factor),
-                       size_base = to_size_factor(sizek, &size_factor),
-
-                       printk(KERN_DEBUG "Setting variable MTRR %d, "
-                               "base: %ld%cB, range: %ld%cB, type %s\n",
-                               reg, start_base, start_factor,
-                               size_base, size_factor,
-                               (type == MTRR_TYPE_UNCACHABLE)?"UC":
-                                   ((type == MTRR_TYPE_WRBACK)?"WB":"Other")
-                               );
-               }
-               save_var_mtrr(reg++, range_startk, sizek, type);
-               range_startk += sizek;
-               range_sizek -= sizek;
-               if (reg >= num_var_ranges)
-                       break;
-       }
-       return reg;
-}
-
-static unsigned __init
-range_to_mtrr_with_hole(struct var_mtrr_state *state, unsigned long basek,
-                       unsigned long sizek)
-{
-       unsigned long hole_basek, hole_sizek;
-       unsigned long second_basek, second_sizek;
-       unsigned long range0_basek, range0_sizek;
-       unsigned long range_basek, range_sizek;
-       unsigned long chunk_sizek;
-       unsigned long gran_sizek;
-
-       hole_basek = 0;
-       hole_sizek = 0;
-       second_basek = 0;
-       second_sizek = 0;
-       chunk_sizek = state->chunk_sizek;
-       gran_sizek = state->gran_sizek;
-
-       /* align with gran size, prevent small block used up MTRRs */
-       range_basek = ALIGN(state->range_startk, gran_sizek);
-       if ((range_basek > basek) && basek)
-               return second_sizek;
-       state->range_sizek -= (range_basek - state->range_startk);
-       range_sizek = ALIGN(state->range_sizek, gran_sizek);
-
-       while (range_sizek > state->range_sizek) {
-               range_sizek -= gran_sizek;
-               if (!range_sizek)
-                       return 0;
-       }
-       state->range_sizek = range_sizek;
-
-       /* try to append some small hole */
-       range0_basek = state->range_startk;
-       range0_sizek = ALIGN(state->range_sizek, chunk_sizek);
-
-       /* no increase */
-       if (range0_sizek == state->range_sizek) {
-               if (debug_print)
-                       printk(KERN_DEBUG "rangeX: %016lx - %016lx\n",
-                               range0_basek<<10,
-                               (range0_basek + state->range_sizek)<<10);
-               state->reg = range_to_mtrr(state->reg, range0_basek,
-                               state->range_sizek, MTRR_TYPE_WRBACK);
-               return 0;
-       }
-
-       /* only cut back, when it is not the last */
-       if (sizek) {
-               while (range0_basek + range0_sizek > (basek + sizek)) {
-                       if (range0_sizek >= chunk_sizek)
-                               range0_sizek -= chunk_sizek;
-                       else
-                               range0_sizek = 0;
-
-                       if (!range0_sizek)
-                               break;
-               }
-       }
-
-second_try:
-       range_basek = range0_basek + range0_sizek;
-
-       /* one hole in the middle */
-       if (range_basek > basek && range_basek <= (basek + sizek))
-               second_sizek = range_basek - basek;
-
-       if (range0_sizek > state->range_sizek) {
-
-               /* one hole in middle or at end */
-               hole_sizek = range0_sizek - state->range_sizek - second_sizek;
-
-               /* hole size should be less than half of range0 size */
-               if (hole_sizek >= (range0_sizek >> 1) &&
-                   range0_sizek >= chunk_sizek) {
-                       range0_sizek -= chunk_sizek;
-                       second_sizek = 0;
-                       hole_sizek = 0;
-
-                       goto second_try;
-               }
-       }
-
-       if (range0_sizek) {
-               if (debug_print)
-                       printk(KERN_DEBUG "range0: %016lx - %016lx\n",
-                               range0_basek<<10,
-                               (range0_basek + range0_sizek)<<10);
-               state->reg = range_to_mtrr(state->reg, range0_basek,
-                               range0_sizek, MTRR_TYPE_WRBACK);
-       }
-
-       if (range0_sizek < state->range_sizek) {
-               /* need to handle left over */
-               range_sizek = state->range_sizek - range0_sizek;
-
-               if (debug_print)
-                       printk(KERN_DEBUG "range: %016lx - %016lx\n",
-                                range_basek<<10,
-                                (range_basek + range_sizek)<<10);
-               state->reg = range_to_mtrr(state->reg, range_basek,
-                                range_sizek, MTRR_TYPE_WRBACK);
-       }
-
-       if (hole_sizek) {
-               hole_basek = range_basek - hole_sizek - second_sizek;
-               if (debug_print)
-                       printk(KERN_DEBUG "hole: %016lx - %016lx\n",
-                                hole_basek<<10,
-                                (hole_basek + hole_sizek)<<10);
-               state->reg = range_to_mtrr(state->reg, hole_basek,
-                                hole_sizek, MTRR_TYPE_UNCACHABLE);
-       }
-
-       return second_sizek;
-}
-
-static void __init
-set_var_mtrr_range(struct var_mtrr_state *state, unsigned long base_pfn,
-                  unsigned long size_pfn)
-{
-       unsigned long basek, sizek;
-       unsigned long second_sizek = 0;
-
-       if (state->reg >= num_var_ranges)
-               return;
-
-       basek = base_pfn << (PAGE_SHIFT - 10);
-       sizek = size_pfn << (PAGE_SHIFT - 10);
-
-       /* See if I can merge with the last range */
-       if ((basek <= 1024) ||
-           (state->range_startk + state->range_sizek == basek)) {
-               unsigned long endk = basek + sizek;
-               state->range_sizek = endk - state->range_startk;
-               return;
-       }
-       /* Write the range mtrrs */
-       if (state->range_sizek != 0)
-               second_sizek = range_to_mtrr_with_hole(state, basek, sizek);
-
-       /* Allocate an msr */
-       state->range_startk = basek + second_sizek;
-       state->range_sizek  = sizek - second_sizek;
-}
-
-/* mininum size of mtrr block that can take hole */
-static u64 mtrr_chunk_size __initdata = (256ULL<<20);
-
-static int __init parse_mtrr_chunk_size_opt(char *p)
-{
-       if (!p)
-               return -EINVAL;
-       mtrr_chunk_size = memparse(p, &p);
-       return 0;
-}
-early_param("mtrr_chunk_size", parse_mtrr_chunk_size_opt);
-
-/* granity of mtrr of block */
-static u64 mtrr_gran_size __initdata;
-
-static int __init parse_mtrr_gran_size_opt(char *p)
-{
-       if (!p)
-               return -EINVAL;
-       mtrr_gran_size = memparse(p, &p);
-       return 0;
-}
-early_param("mtrr_gran_size", parse_mtrr_gran_size_opt);
-
-static int nr_mtrr_spare_reg __initdata =
-                                CONFIG_MTRR_SANITIZER_SPARE_REG_NR_DEFAULT;
-
-static int __init parse_mtrr_spare_reg(char *arg)
-{
-       if (arg)
-               nr_mtrr_spare_reg = simple_strtoul(arg, NULL, 0);
-       return 0;
-}
-
-early_param("mtrr_spare_reg_nr", parse_mtrr_spare_reg);
-
-static int __init
-x86_setup_var_mtrrs(struct res_range *range, int nr_range,
-                   u64 chunk_size, u64 gran_size)
-{
-       struct var_mtrr_state var_state;
-       int i;
-       int num_reg;
-
-       var_state.range_startk  = 0;
-       var_state.range_sizek   = 0;
-       var_state.reg           = 0;
-       var_state.chunk_sizek   = chunk_size >> 10;
-       var_state.gran_sizek    = gran_size >> 10;
-
-       memset(range_state, 0, sizeof(range_state));
-
-       /* Write the range etc */
-       for (i = 0; i < nr_range; i++)
-               set_var_mtrr_range(&var_state, range[i].start,
-                                  range[i].end - range[i].start + 1);
-
-       /* Write the last range */
-       if (var_state.range_sizek != 0)
-               range_to_mtrr_with_hole(&var_state, 0, 0);
-
-       num_reg = var_state.reg;
-       /* Clear out the extra MTRR's */
-       while (var_state.reg < num_var_ranges) {
-               save_var_mtrr(var_state.reg, 0, 0, 0);
-               var_state.reg++;
-       }
-
-       return num_reg;
-}
-
-struct mtrr_cleanup_result {
-       unsigned long gran_sizek;
-       unsigned long chunk_sizek;
-       unsigned long lose_cover_sizek;
-       unsigned int num_reg;
-       int bad;
-};
-
-/*
- * gran_size: 64K, 128K, 256K, 512K, 1M, 2M, ..., 2G
- * chunk size: gran_size, ..., 2G
- * so we need (1+16)*8
- */
-#define NUM_RESULT     136
-#define PSHIFT         (PAGE_SHIFT - 10)
-
-static struct mtrr_cleanup_result __initdata result[NUM_RESULT];
-static unsigned long __initdata min_loss_pfn[RANGE_NUM];
-
-static void __init print_out_mtrr_range_state(void)
-{
-       int i;
-       char start_factor = 'K', size_factor = 'K';
-       unsigned long start_base, size_base;
-       mtrr_type type;
-
-       for (i = 0; i < num_var_ranges; i++) {
-
-               size_base = range_state[i].size_pfn << (PAGE_SHIFT - 10);
-               if (!size_base)
-                       continue;
-
-               size_base = to_size_factor(size_base, &size_factor),
-               start_base = range_state[i].base_pfn << (PAGE_SHIFT - 10);
-               start_base = to_size_factor(start_base, &start_factor),
-               type = range_state[i].type;
-
-               printk(KERN_DEBUG "reg %d, base: %ld%cB, range: %ld%cB, type %s\n",
-                       i, start_base, start_factor,
-                       size_base, size_factor,
-                       (type == MTRR_TYPE_UNCACHABLE) ? "UC" :
-                           ((type == MTRR_TYPE_WRPROT) ? "WP" :
-                            ((type == MTRR_TYPE_WRBACK) ? "WB" : "Other"))
-                       );
-       }
-}
-
-static int __init mtrr_need_cleanup(void)
-{
-       int i;
-       mtrr_type type;
-       unsigned long size;
-       /* extra one for all 0 */
-       int num[MTRR_NUM_TYPES + 1];
-
-       /* check entries number */
-       memset(num, 0, sizeof(num));
-       for (i = 0; i < num_var_ranges; i++) {
-               type = range_state[i].type;
-               size = range_state[i].size_pfn;
-               if (type >= MTRR_NUM_TYPES)
-                       continue;
-               if (!size)
-                       type = MTRR_NUM_TYPES;
-               if (type == MTRR_TYPE_WRPROT)
-                       type = MTRR_TYPE_UNCACHABLE;
-               num[type]++;
-       }
-
-       /* check if we got UC entries */
-       if (!num[MTRR_TYPE_UNCACHABLE])
-               return 0;
-
-       /* check if we only had WB and UC */
-       if (num[MTRR_TYPE_WRBACK] + num[MTRR_TYPE_UNCACHABLE] !=
-               num_var_ranges - num[MTRR_NUM_TYPES])
-               return 0;
-
-       return 1;
-}
-
-static unsigned long __initdata range_sums;
-static void __init mtrr_calc_range_state(u64 chunk_size, u64 gran_size,
-                                        unsigned long extra_remove_base,
-                                        unsigned long extra_remove_size,
-                                        int i)
-{
-       int num_reg;
-       static struct res_range range_new[RANGE_NUM];
-       static int nr_range_new;
-       unsigned long range_sums_new;
-
-       /* convert ranges to var ranges state */
-       num_reg = x86_setup_var_mtrrs(range, nr_range,
-                                               chunk_size, gran_size);
-
-       /* we got new setting in range_state, check it */
-       memset(range_new, 0, sizeof(range_new));
-       nr_range_new = x86_get_mtrr_mem_range(range_new, 0,
-                               extra_remove_base, extra_remove_size);
-       range_sums_new = sum_ranges(range_new, nr_range_new);
-
-       result[i].chunk_sizek = chunk_size >> 10;
-       result[i].gran_sizek = gran_size >> 10;
-       result[i].num_reg = num_reg;
-       if (range_sums < range_sums_new) {
-               result[i].lose_cover_sizek =
-                       (range_sums_new - range_sums) << PSHIFT;
-               result[i].bad = 1;
-       } else
-               result[i].lose_cover_sizek =
-                       (range_sums - range_sums_new) << PSHIFT;
-
-       /* double check it */
-       if (!result[i].bad && !result[i].lose_cover_sizek) {
-               if (nr_range_new != nr_range ||
-                       memcmp(range, range_new, sizeof(range)))
-                               result[i].bad = 1;
-       }
-
-       if (!result[i].bad && (range_sums - range_sums_new <
-                               min_loss_pfn[num_reg])) {
-               min_loss_pfn[num_reg] =
-                       range_sums - range_sums_new;
-       }
-}
-
-static void __init mtrr_print_out_one_result(int i)
-{
-       char gran_factor, chunk_factor, lose_factor;
-       unsigned long gran_base, chunk_base, lose_base;
-
-       gran_base = to_size_factor(result[i].gran_sizek, &gran_factor),
-       chunk_base = to_size_factor(result[i].chunk_sizek, &chunk_factor),
-       lose_base = to_size_factor(result[i].lose_cover_sizek, &lose_factor),
-       printk(KERN_INFO "%sgran_size: %ld%c \tchunk_size: %ld%c \t",
-                       result[i].bad ? "*BAD*" : " ",
-                       gran_base, gran_factor, chunk_base, chunk_factor);
-       printk(KERN_CONT "num_reg: %d  \tlose cover RAM: %s%ld%c\n",
-                       result[i].num_reg, result[i].bad ? "-" : "",
-                       lose_base, lose_factor);
-}
-
-static int __init mtrr_search_optimal_index(void)
-{
-       int i;
-       int num_reg_good;
-       int index_good;
-
-       if (nr_mtrr_spare_reg >= num_var_ranges)
-               nr_mtrr_spare_reg = num_var_ranges - 1;
-       num_reg_good = -1;
-       for (i = num_var_ranges - nr_mtrr_spare_reg; i > 0; i--) {
-               if (!min_loss_pfn[i])
-                       num_reg_good = i;
-       }
-
-       index_good = -1;
-       if (num_reg_good != -1) {
-               for (i = 0; i < NUM_RESULT; i++) {
-                       if (!result[i].bad &&
-                           result[i].num_reg == num_reg_good &&
-                           !result[i].lose_cover_sizek) {
-                               index_good = i;
-                               break;
-                       }
-               }
-       }
-
-       return index_good;
-}
-
-
-static int __init mtrr_cleanup(unsigned address_bits)
-{
-       unsigned long extra_remove_base, extra_remove_size;
-       unsigned long base, size, def, dummy;
-       mtrr_type type;
-       u64 chunk_size, gran_size;
-       int index_good;
-       int i;
-
-       if (!is_cpu(INTEL) || enable_mtrr_cleanup < 1)
-               return 0;
-       rdmsr(MTRRdefType_MSR, def, dummy);
-       def &= 0xff;
-       if (def != MTRR_TYPE_UNCACHABLE)
-               return 0;
-
-       /* get it and store it aside */
-       memset(range_state, 0, sizeof(range_state));
-       for (i = 0; i < num_var_ranges; i++) {
-               mtrr_if->get(i, &base, &size, &type);
-               range_state[i].base_pfn = base;
-               range_state[i].size_pfn = size;
-               range_state[i].type = type;
-       }
-
-       /* check if we need handle it and can handle it */
-       if (!mtrr_need_cleanup())
-               return 0;
-
-       /* print original var MTRRs at first, for debugging: */
-       printk(KERN_DEBUG "original variable MTRRs\n");
-       print_out_mtrr_range_state();
-
-       memset(range, 0, sizeof(range));
-       extra_remove_size = 0;
-       extra_remove_base = 1 << (32 - PAGE_SHIFT);
-       if (mtrr_tom2)
-               extra_remove_size =
-                       (mtrr_tom2 >> PAGE_SHIFT) - extra_remove_base;
-       nr_range = x86_get_mtrr_mem_range(range, 0, extra_remove_base,
-                                         extra_remove_size);
-       /*
-        * [0, 1M) should always be coverred by var mtrr with WB
-        * and fixed mtrrs should take effective before var mtrr for it
-        */
-       nr_range = add_range_with_merge(range, nr_range, 0,
-                                       (1ULL<<(20 - PAGE_SHIFT)) - 1);
-       /* sort the ranges */
-       sort(range, nr_range, sizeof(struct res_range), cmp_range, NULL);
-
-       range_sums = sum_ranges(range, nr_range);
-       printk(KERN_INFO "total RAM coverred: %ldM\n",
-              range_sums >> (20 - PAGE_SHIFT));
-
-       if (mtrr_chunk_size && mtrr_gran_size) {
-               i = 0;
-               mtrr_calc_range_state(mtrr_chunk_size, mtrr_gran_size,
-                                     extra_remove_base, extra_remove_size, i);
-
-               mtrr_print_out_one_result(i);
-
-               if (!result[i].bad) {
-                       set_var_mtrr_all(address_bits);
-                       printk(KERN_DEBUG "New variable MTRRs\n");
-                       print_out_mtrr_range_state();
-                       return 1;
-               }
-               printk(KERN_INFO "invalid mtrr_gran_size or mtrr_chunk_size, "
-                      "will find optimal one\n");
-       }
-
-       i = 0;
-       memset(min_loss_pfn, 0xff, sizeof(min_loss_pfn));
-       memset(result, 0, sizeof(result));
-       for (gran_size = (1ULL<<16); gran_size < (1ULL<<32); gran_size <<= 1) {
-
-               for (chunk_size = gran_size; chunk_size < (1ULL<<32);
-                    chunk_size <<= 1) {
-
-                       if (i >= NUM_RESULT)
-                               continue;
-
-                       mtrr_calc_range_state(chunk_size, gran_size,
-                                     extra_remove_base, extra_remove_size, i);
-                       if (debug_print) {
-                               mtrr_print_out_one_result(i);
-                               printk(KERN_INFO "\n");
-                       }
-
-                       i++;
-               }
-       }
-
-       /* try to find the optimal index */
-       index_good = mtrr_search_optimal_index();
-
-       if (index_good != -1) {
-               printk(KERN_INFO "Found optimal setting for mtrr clean up\n");
-               i = index_good;
-               mtrr_print_out_one_result(i);
-
-               /* convert ranges to var ranges state */
-               chunk_size = result[i].chunk_sizek;
-               chunk_size <<= 10;
-               gran_size = result[i].gran_sizek;
-               gran_size <<= 10;
-               x86_setup_var_mtrrs(range, nr_range, chunk_size, gran_size);
-               set_var_mtrr_all(address_bits);
-               printk(KERN_DEBUG "New variable MTRRs\n");
-               print_out_mtrr_range_state();
-               return 1;
-       } else {
-               /* print out all */
-               for (i = 0; i < NUM_RESULT; i++)
-                       mtrr_print_out_one_result(i);
-       }
-
-       printk(KERN_INFO "mtrr_cleanup: can not find optimal value\n");
-       printk(KERN_INFO "please specify mtrr_gran_size/mtrr_chunk_size\n");
-
-       return 0;
-}
-#else
-static int __init mtrr_cleanup(unsigned address_bits)
-{
-       return 0;
-}
-#endif
-
-static int __initdata changed_by_mtrr_cleanup;
-
-static int disable_mtrr_trim;
-
-static int __init disable_mtrr_trim_setup(char *str)
-{
-       disable_mtrr_trim = 1;
-       return 0;
-}
-early_param("disable_mtrr_trim", disable_mtrr_trim_setup);
-
-/*
- * Newer AMD K8s and later CPUs have a special magic MSR way to force WB
- * for memory >4GB. Check for that here.
- * Note this won't check if the MTRRs < 4GB where the magic bit doesn't
- * apply to are wrong, but so far we don't know of any such case in the wild.
- */
-#define Tom2Enabled (1U << 21)
-#define Tom2ForceMemTypeWB (1U << 22)
-
-int __init amd_special_default_mtrr(void)
-{
-       u32 l, h;
-
-       if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD)
-               return 0;
-       if (boot_cpu_data.x86 < 0xf || boot_cpu_data.x86 > 0x11)
-               return 0;
-       /* In case some hypervisor doesn't pass SYSCFG through */
-       if (rdmsr_safe(MSR_K8_SYSCFG, &l, &h) < 0)
-               return 0;
-       /*
-        * Memory between 4GB and top of mem is forced WB by this magic bit.
-        * Reserved before K8RevF, but should be zero there.
-        */
-       if ((l & (Tom2Enabled | Tom2ForceMemTypeWB)) ==
-                (Tom2Enabled | Tom2ForceMemTypeWB))
-               return 1;
-       return 0;
-}
-
-static u64 __init real_trim_memory(unsigned long start_pfn,
-                                  unsigned long limit_pfn)
-{
-       u64 trim_start, trim_size;
-       trim_start = start_pfn;
-       trim_start <<= PAGE_SHIFT;
-       trim_size = limit_pfn;
-       trim_size <<= PAGE_SHIFT;
-       trim_size -= trim_start;
-
-       return e820_update_range(trim_start, trim_size, E820_RAM,
-                               E820_RESERVED);
-}
-/**
- * mtrr_trim_uncached_memory - trim RAM not covered by MTRRs
- * @end_pfn: ending page frame number
- *
- * Some buggy BIOSes don't setup the MTRRs properly for systems with certain
- * memory configurations.  This routine checks that the highest MTRR matches
- * the end of memory, to make sure the MTRRs having a write back type cover
- * all of the memory the kernel is intending to use. If not, it'll trim any
- * memory off the end by adjusting end_pfn, removing it from the kernel's
- * allocation pools, warning the user with an obnoxious message.
- */
-int __init mtrr_trim_uncached_memory(unsigned long end_pfn)
-{
-       unsigned long i, base, size, highest_pfn = 0, def, dummy;
-       mtrr_type type;
-       u64 total_trim_size;
-
-       /* extra one for all 0 */
-       int num[MTRR_NUM_TYPES + 1];
-       /*
-        * Make sure we only trim uncachable memory on machines that
-        * support the Intel MTRR architecture:
-        */
-       if (!is_cpu(INTEL) || disable_mtrr_trim)
-               return 0;
-       rdmsr(MTRRdefType_MSR, def, dummy);
-       def &= 0xff;
-       if (def != MTRR_TYPE_UNCACHABLE)
-               return 0;
-
-       /* get it and store it aside */
-       memset(range_state, 0, sizeof(range_state));
-       for (i = 0; i < num_var_ranges; i++) {
-               mtrr_if->get(i, &base, &size, &type);
-               range_state[i].base_pfn = base;
-               range_state[i].size_pfn = size;
-               range_state[i].type = type;
-       }
-
-       /* Find highest cached pfn */
-       for (i = 0; i < num_var_ranges; i++) {
-               type = range_state[i].type;
-               if (type != MTRR_TYPE_WRBACK)
-                       continue;
-               base = range_state[i].base_pfn;
-               size = range_state[i].size_pfn;
-               if (highest_pfn < base + size)
-                       highest_pfn = base + size;
-       }
-
-       /* kvm/qemu doesn't have mtrr set right, don't trim them all */
-       if (!highest_pfn) {
-               printk(KERN_INFO "CPU MTRRs all blank - virtualized system.\n");
-               return 0;
-       }
-
-       /* check entries number */
-       memset(num, 0, sizeof(num));
-       for (i = 0; i < num_var_ranges; i++) {
-               type = range_state[i].type;
-               if (type >= MTRR_NUM_TYPES)
-                       continue;
-               size = range_state[i].size_pfn;
-               if (!size)
-                       type = MTRR_NUM_TYPES;
-               num[type]++;
-       }
-
-       /* no entry for WB? */
-       if (!num[MTRR_TYPE_WRBACK])
-               return 0;
-
-       /* check if we only had WB and UC */
-       if (num[MTRR_TYPE_WRBACK] + num[MTRR_TYPE_UNCACHABLE] !=
-               num_var_ranges - num[MTRR_NUM_TYPES])
-               return 0;
-
-       memset(range, 0, sizeof(range));
-       nr_range = 0;
-       if (mtrr_tom2) {
-               range[nr_range].start = (1ULL<<(32 - PAGE_SHIFT));
-               range[nr_range].end = (mtrr_tom2 >> PAGE_SHIFT) - 1;
-               if (highest_pfn < range[nr_range].end + 1)
-                       highest_pfn = range[nr_range].end + 1;
-               nr_range++;
-       }
-       nr_range = x86_get_mtrr_mem_range(range, nr_range, 0, 0);
-
-       total_trim_size = 0;
-       /* check the head */
-       if (range[0].start)
-               total_trim_size += real_trim_memory(0, range[0].start);
-       /* check the holes */
-       for (i = 0; i < nr_range - 1; i++) {
-               if (range[i].end + 1 < range[i+1].start)
-                       total_trim_size += real_trim_memory(range[i].end + 1,
-                                                           range[i+1].start);
-       }
-       /* check the top */
-       i = nr_range - 1;
-       if (range[i].end + 1 < end_pfn)
-               total_trim_size += real_trim_memory(range[i].end + 1,
-                                                        end_pfn);
-
-       if (total_trim_size) {
-               printk(KERN_WARNING "WARNING: BIOS bug: CPU MTRRs don't cover"
-                       " all of memory, losing %lluMB of RAM.\n",
-                       total_trim_size >> 20);
-
-               if (!changed_by_mtrr_cleanup)
-                       WARN_ON(1);
-
-               printk(KERN_INFO "update e820 for mtrr\n");
-               update_e820();
-
-               return 1;
-       }
-
-       return 0;
-}
+int __initdata changed_by_mtrr_cleanup;
 
 /**
  * mtrr_bp_init - initialize mtrrs on the boot CPU
index ffd6040..6710e93 100644 (file)
@@ -88,3 +88,6 @@ void mtrr_wrmsr(unsigned, unsigned, unsigned);
 int amd_init_mtrr(void);
 int cyrix_init_mtrr(void);
 int centaur_init_mtrr(void);
+
+extern int changed_by_mtrr_cleanup;
+extern int mtrr_cleanup(unsigned address_bits);