Login
[x]
Log in using an account from:
Fedora Account System
Red Hat Associate
Red Hat Customer
Or login using a Red Hat Bugzilla account
Forgot Password
Login:
Hide Forgot
Create an Account
Red Hat Bugzilla – Attachment 299365 Details for
Bug 438960
G965 chipset box grinds to a halt on boot with 6GiB ram
[?]
New
Simple Search
Advanced Search
My Links
Browse
Requests
Reports
Current State
Search
Tabular reports
Graphical reports
Duplicates
Other Reports
User Changes
Plotly Reports
Bug Status
Bug Severity
Non-Defaults
|
Product Dashboard
Help
Page Help!
Bug Writing Guidelines
What's new
Browser Support Policy
5.0.4.rh83 Release notes
FAQ
Guides index
User guide
Web Services
Contact
Legal
This site requires JavaScript to be enabled to function correctly, please enable it.
[patch]
fixes. take 2.
mtrr2.diff (text/plain), 54.11 KB, created by
Dave Jones
on 2008-03-27 17:20:34 UTC
(
hide
)
Description:
fixes. take 2.
Filename:
MIME Type:
Creator:
Dave Jones
Created:
2008-03-27 17:20:34 UTC
Size:
54.11 KB
patch
obsolete
>commit 2d2ee8de5f6d26ef2942e0b449aa68d9236d5777 >Author: Paul Jimenez <pj@place.org> >Date: Wed Jan 30 13:30:31 2008 +0100 > > x86: mtrr use type bool [RESEND AGAIN] > > This is a janitorish patch to 1) remove private TRUE/FALSE #def's in > favor of using the standard enum from linux/stddef.h and 2) switch the > variables holding those values to type 'bool' (from linux/types.h) > since it both seems more appropriate and allows for potentially better > optimization. > > As a truly minor aside, I removed a couple of comments documenting > a 'do_safe' parameter that seems to no longer exist. > > Signed-off-by: Paul Jimenez <pj@place.org> > Signed-off-by: Thomas Gleixner <tglx@linutronix.de> > Signed-off-by: Ingo Molnar <mingo@elte.hu> > Signed-off-by: Thomas Gleixner <tglx@linutronix.de> > >diff --git a/arch/x86/kernel/cpu/mtrr/amd.c b/arch/x86/kernel/cpu/mtrr/amd.c >index 0949cdb..ee2331b 100644 >--- a/arch/x86/kernel/cpu/mtrr/amd.c >+++ b/arch/x86/kernel/cpu/mtrr/amd.c >@@ -53,8 +53,6 @@ static void amd_set_mtrr(unsigned int reg, unsigned long base, > <base> The base address of the region. > <size> The size of the region. If this is 0 the region is disabled. > <type> The type of the region. >- <do_safe> If TRUE, do the change safely. If FALSE, safety measures should >- be done externally. > [RETURNS] Nothing. > */ > { >diff --git a/arch/x86/kernel/cpu/mtrr/generic.c b/arch/x86/kernel/cpu/mtrr/generic.c >index 992f08d..1c331c3 100644 >--- a/arch/x86/kernel/cpu/mtrr/generic.c >+++ b/arch/x86/kernel/cpu/mtrr/generic.c >@@ -188,7 +188,7 @@ static inline void k8_enable_fixed_iorrs(void) > * \param changed pointer which indicates whether the MTRR needed to be changed > * \param msrwords pointer to the MSR values which the MSR should have > */ >-static void set_fixed_range(int msr, int * changed, unsigned int * msrwords) >+static void set_fixed_range(int msr, bool *changed, unsigned int *msrwords) > { > unsigned lo, hi; > >@@ -200,7 +200,7 @@ static void set_fixed_range(int msr, int * changed, unsigned int * msrwords) > ((msrwords[0] | msrwords[1]) & K8_MTRR_RDMEM_WRMEM_MASK)) > k8_enable_fixed_iorrs(); > mtrr_wrmsr(msr, msrwords[0], msrwords[1]); >- *changed = TRUE; >+ *changed = true; > } > } > >@@ -260,7 +260,7 @@ static void generic_get_mtrr(unsigned int reg, unsigned long *base, > static int set_fixed_ranges(mtrr_type * frs) > { > unsigned long long *saved = (unsigned long long *) frs; >- int changed = FALSE; >+ bool changed = false; > int block=-1, range; > > while (fixed_range_blocks[++block].ranges) >@@ -273,17 +273,17 @@ static int set_fixed_ranges(mtrr_type * frs) > > /* Set the MSR pair relating to a var range. Returns TRUE if > changes are made */ >-static int set_mtrr_var_ranges(unsigned int index, struct mtrr_var_range *vr) >+static bool set_mtrr_var_ranges(unsigned int index, struct mtrr_var_range *vr) > { > unsigned int lo, hi; >- int changed = FALSE; >+ bool changed = false; > > rdmsr(MTRRphysBase_MSR(index), lo, hi); > if ((vr->base_lo & 0xfffff0ffUL) != (lo & 0xfffff0ffUL) > || (vr->base_hi & (size_and_mask >> (32 - PAGE_SHIFT))) != > (hi & (size_and_mask >> (32 - PAGE_SHIFT)))) { > mtrr_wrmsr(MTRRphysBase_MSR(index), vr->base_lo, vr->base_hi); >- changed = TRUE; >+ changed = true; > } > > rdmsr(MTRRphysMask_MSR(index), lo, hi); >@@ -292,7 +292,7 @@ static int set_mtrr_var_ranges(unsigned int index, struct mtrr_var_range *vr) > || (vr->mask_hi & (size_and_mask >> (32 - PAGE_SHIFT))) != > (hi & (size_and_mask >> (32 - PAGE_SHIFT)))) { > mtrr_wrmsr(MTRRphysMask_MSR(index), vr->mask_lo, vr->mask_hi); >- changed = TRUE; >+ changed = true; > } > return changed; > } >@@ -417,8 +417,6 @@ static void generic_set_mtrr(unsigned int reg, unsigned long base, > <base> The base address of the region. > <size> The size of the region. If this is 0 the region is disabled. > <type> The type of the region. >- <do_safe> If TRUE, do the change safely. If FALSE, safety measures should >- be done externally. > [RETURNS] Nothing. > */ > { >diff --git a/arch/x86/kernel/cpu/mtrr/if.c b/arch/x86/kernel/cpu/mtrr/if.c >index c7d8f17..1453568 100644 >--- a/arch/x86/kernel/cpu/mtrr/if.c >+++ b/arch/x86/kernel/cpu/mtrr/if.c >@@ -37,7 +37,7 @@ const char *mtrr_attrib_to_str(int x) > > static int > mtrr_file_add(unsigned long base, unsigned long size, >- unsigned int type, char increment, struct file *file, int page) >+ unsigned int type, bool increment, struct file *file, int page) > { > int reg, max; > unsigned int *fcount = FILE_FCOUNT(file); >@@ -55,7 +55,7 @@ mtrr_file_add(unsigned long base, unsigned long size, > base >>= PAGE_SHIFT; > size >>= PAGE_SHIFT; > } >- reg = mtrr_add_page(base, size, type, 1); >+ reg = mtrr_add_page(base, size, type, true); > if (reg >= 0) > ++fcount[reg]; > return reg; >@@ -141,7 +141,7 @@ mtrr_write(struct file *file, const char __user *buf, size_t len, loff_t * ppos) > size >>= PAGE_SHIFT; > err = > mtrr_add_page((unsigned long) base, (unsigned long) size, i, >- 1); >+ true); > if (err < 0) > return err; > return len; >@@ -217,7 +217,7 @@ mtrr_ioctl(struct file *file, unsigned int cmd, unsigned long __arg) > if (!capable(CAP_SYS_ADMIN)) > return -EPERM; > err = >- mtrr_file_add(sentry.base, sentry.size, sentry.type, 1, >+ mtrr_file_add(sentry.base, sentry.size, sentry.type, true, > file, 0); > break; > case MTRRIOC_SET_ENTRY: >@@ -226,7 +226,7 @@ mtrr_ioctl(struct file *file, unsigned int cmd, unsigned long __arg) > #endif > if (!capable(CAP_SYS_ADMIN)) > return -EPERM; >- err = mtrr_add(sentry.base, sentry.size, sentry.type, 0); >+ err = mtrr_add(sentry.base, sentry.size, sentry.type, false); > break; > case MTRRIOC_DEL_ENTRY: > #ifdef CONFIG_COMPAT >@@ -270,7 +270,7 @@ mtrr_ioctl(struct file *file, unsigned int cmd, unsigned long __arg) > if (!capable(CAP_SYS_ADMIN)) > return -EPERM; > err = >- mtrr_file_add(sentry.base, sentry.size, sentry.type, 1, >+ mtrr_file_add(sentry.base, sentry.size, sentry.type, true, > file, 1); > break; > case MTRRIOC_SET_PAGE_ENTRY: >@@ -279,7 +279,8 @@ mtrr_ioctl(struct file *file, unsigned int cmd, unsigned long __arg) > #endif > if (!capable(CAP_SYS_ADMIN)) > return -EPERM; >- err = mtrr_add_page(sentry.base, sentry.size, sentry.type, 0); >+ err = >+ mtrr_add_page(sentry.base, sentry.size, sentry.type, false); > break; > case MTRRIOC_DEL_PAGE_ENTRY: > #ifdef CONFIG_COMPAT >diff --git a/arch/x86/kernel/cpu/mtrr/main.c b/arch/x86/kernel/cpu/mtrr/main.c >index beb45c9..60af5ed 100644 >--- a/arch/x86/kernel/cpu/mtrr/main.c >+++ b/arch/x86/kernel/cpu/mtrr/main.c >@@ -311,7 +311,7 @@ static void set_mtrr(unsigned int reg, unsigned long base, > */ > > int mtrr_add_page(unsigned long base, unsigned long size, >- unsigned int type, char increment) >+ unsigned int type, bool increment) > { > int i, replace, error; > mtrr_type ltype; >@@ -394,7 +394,9 @@ int mtrr_add_page(unsigned long base, unsigned long size, > if (likely(replace < 0)) > usage_table[i] = 1; > else { >- usage_table[i] = usage_table[replace] + !!increment; >+ usage_table[i] = usage_table[replace]; >+ if (increment) >+ usage_table[i]++; > if (unlikely(replace != i)) { > set_mtrr(replace, 0, 0, 0); > usage_table[replace] = 0; >@@ -460,7 +462,7 @@ static int mtrr_check(unsigned long base, unsigned long size) > > int > mtrr_add(unsigned long base, unsigned long size, unsigned int type, >- char increment) >+ bool increment) > { > if (mtrr_check(base, size)) > return -EINVAL; >diff --git a/arch/x86/kernel/cpu/mtrr/mtrr.h b/arch/x86/kernel/cpu/mtrr/mtrr.h >index 289dfe6..54347e9 100644 >--- a/arch/x86/kernel/cpu/mtrr/mtrr.h >+++ b/arch/x86/kernel/cpu/mtrr/mtrr.h >@@ -2,10 +2,8 @@ > * local mtrr defines. > */ > >-#ifndef TRUE >-#define TRUE 1 >-#define FALSE 0 >-#endif >+#include <linux/types.h> >+#include <linux/stddef.h> > > #define MTRRcap_MSR 0x0fe > #define MTRRdefType_MSR 0x2ff >diff --git a/include/asm-x86/mtrr.h b/include/asm-x86/mtrr.h >index e8320e4..262670e 100644 >--- a/include/asm-x86/mtrr.h >+++ b/include/asm-x86/mtrr.h >@@ -89,9 +89,9 @@ struct mtrr_gentry > extern void mtrr_save_fixed_ranges(void *); > extern void mtrr_save_state(void); > extern int mtrr_add (unsigned long base, unsigned long size, >- unsigned int type, char increment); >+ unsigned int type, bool increment); > extern int mtrr_add_page (unsigned long base, unsigned long size, >- unsigned int type, char increment); >+ unsigned int type, bool increment); > extern int mtrr_del (int reg, unsigned long base, unsigned long size); > extern int mtrr_del_page (int reg, unsigned long base, unsigned long size); > extern void mtrr_centaur_report_mcr(int mcr, u32 lo, u32 hi); >@@ -101,12 +101,12 @@ extern void mtrr_bp_init(void); > #define mtrr_save_fixed_ranges(arg) do {} while (0) > #define mtrr_save_state() do {} while (0) > static __inline__ int mtrr_add (unsigned long base, unsigned long size, >- unsigned int type, char increment) >+ unsigned int type, bool increment) > { > return -ENODEV; > } > static __inline__ int mtrr_add_page (unsigned long base, unsigned long size, >- unsigned int type, char increment) >+ unsigned int type, bool increment) > { > return -ENODEV; > } >commit 99fc8d424bc5d803fe92cad56c068fe64e73747a >Author: Jesse Barnes <jesse.barnes@intel.com> >Date: Wed Jan 30 13:33:18 2008 +0100 > > x86, 32-bit: trim memory not covered by wb mtrrs > > On some machines, buggy BIOSes don't properly setup WB MTRRs to cover all > available RAM, meaning the last few megs (or even gigs) of memory will be > marked uncached. Since Linux tends to allocate from high memory addresses > first, this causes the machine to be unusably slow as soon as the kernel > starts really using memory (i.e. right around init time). > > This patch works around the problem by scanning the MTRRs at boot and > figuring out whether the current end_pfn value (setup by early e820 code) > goes beyond the highest WB MTRR range, and if so, trimming it to match. A > fairly obnoxious KERN_WARNING is printed too, letting the user know that > not all of their memory is available due to a likely BIOS bug. > > Something similar could be done on i386 if needed, but the boot ordering > would be slightly different, since the MTRR code on i386 depends on the > boot_cpu_data structure being setup. > > This patch fixes a bug in the last patch that caused the code to run on > non-Intel machines (AMD machines apparently don't need it and it's untested > on other non-Intel machines, so best keep it off). > > Further enhancements and fixes from: > > Yinghai Lu <Yinghai.Lu@Sun.COM> > Andi Kleen <ak@suse.de> > > Signed-off-by: Jesse Barnes <jesse.barnes@intel.com> > Tested-by: Justin Piszcz <jpiszcz@lucidpixels.com> > Cc: Andi Kleen <andi@firstfloor.org> > Cc: "Eric W. Biederman" <ebiederm@xmission.com> > Cc: Yinghai Lu <yhlu.kernel@gmail.com> > Signed-off-by: Andrew Morton <akpm@linux-foundation.org> > Signed-off-by: Ingo Molnar <mingo@elte.hu> > Signed-off-by: Thomas Gleixner <tglx@linutronix.de> > >diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt >index 860a908..b8fadf5 100644 >--- a/Documentation/kernel-parameters.txt >+++ b/Documentation/kernel-parameters.txt >@@ -570,6 +570,12 @@ and is between 256 and 4096 characters. It is defined in the file > See drivers/char/README.epca and > Documentation/digiepca.txt. > >+ disable_mtrr_trim [X86-64, Intel only] >+ By default the kernel will trim any uncacheable >+ memory out of your available memory pool based on >+ MTRR settings. This parameter disables that behavior, >+ possibly causing your machine to run very slowly. >+ > dmasound= [HW,OSS] Sound subsystem buffers > > dscc4.setup= [NET] >diff --git a/arch/x86/kernel/bugs_64.c b/arch/x86/kernel/bugs_64.c >index 9a189ce..8f520f9 100644 >--- a/arch/x86/kernel/bugs_64.c >+++ b/arch/x86/kernel/bugs_64.c >@@ -13,7 +13,6 @@ > void __init check_bugs(void) > { > identify_cpu(&boot_cpu_data); >- mtrr_bp_init(); > #if !defined(CONFIG_SMP) > printk("CPU: "); > print_cpu_info(&boot_cpu_data); >diff --git a/arch/x86/kernel/cpu/mtrr/generic.c b/arch/x86/kernel/cpu/mtrr/generic.c >index 55d31ff..103d61a 100644 >--- a/arch/x86/kernel/cpu/mtrr/generic.c >+++ b/arch/x86/kernel/cpu/mtrr/generic.c >@@ -14,7 +14,7 @@ > #include "mtrr.h" > > struct mtrr_state { >- struct mtrr_var_range *var_ranges; >+ struct mtrr_var_range var_ranges[MAX_VAR_RANGES]; > mtrr_type fixed_ranges[NUM_FIXED_RANGES]; > unsigned char enabled; > unsigned char have_fixed; >@@ -86,12 +86,6 @@ void __init get_mtrr_state(void) > struct mtrr_var_range *vrs; > unsigned lo, dummy; > >- if (!mtrr_state.var_ranges) { >- mtrr_state.var_ranges = kmalloc(num_var_ranges * sizeof (struct mtrr_var_range), >- GFP_KERNEL); >- if (!mtrr_state.var_ranges) >- return; >- } > vrs = mtrr_state.var_ranges; > > rdmsr(MTRRcap_MSR, lo, dummy); >diff --git a/arch/x86/kernel/cpu/mtrr/if.c b/arch/x86/kernel/cpu/mtrr/if.c >index 1453568..91e150a 100644 >--- a/arch/x86/kernel/cpu/mtrr/if.c >+++ b/arch/x86/kernel/cpu/mtrr/if.c >@@ -11,10 +11,6 @@ > #include <asm/mtrr.h> > #include "mtrr.h" > >-/* RED-PEN: this is accessed without any locking */ >-extern unsigned int *usage_table; >- >- > #define FILE_FCOUNT(f) (((struct seq_file *)((f)->private_data))->private) > > static const char *const mtrr_strings[MTRR_NUM_TYPES] = >@@ -397,7 +393,7 @@ static int mtrr_seq_show(struct seq_file *seq, void *offset) > for (i = 0; i < max; i++) { > mtrr_if->get(i, &base, &size, &type); > if (size == 0) >- usage_table[i] = 0; >+ mtrr_usage_table[i] = 0; > else { > if (size < (0x100000 >> PAGE_SHIFT)) { > /* less than 1MB */ >@@ -411,7 +407,7 @@ static int mtrr_seq_show(struct seq_file *seq, void *offset) > len += seq_printf(seq, > "reg%02i: base=0x%05lx000 (%4luMB), size=%4lu%cB: %s, count=%d\n", > i, base, base >> (20 - PAGE_SHIFT), size, factor, >- mtrr_attrib_to_str(type), usage_table[i]); >+ mtrr_attrib_to_str(type), mtrr_usage_table[i]); > } > } > return 0; >diff --git a/arch/x86/kernel/cpu/mtrr/main.c b/arch/x86/kernel/cpu/mtrr/main.c >index 60af5ed..ccd36ed 100644 >--- a/arch/x86/kernel/cpu/mtrr/main.c >+++ b/arch/x86/kernel/cpu/mtrr/main.c >@@ -38,8 +38,8 @@ > #include <linux/cpu.h> > #include <linux/mutex.h> > >+#include <asm/e820.h> > #include <asm/mtrr.h> >- > #include <asm/uaccess.h> > #include <asm/processor.h> > #include <asm/msr.h> >@@ -47,7 +47,7 @@ > > u32 num_var_ranges = 0; > >-unsigned int *usage_table; >+unsigned int mtrr_usage_table[MAX_VAR_RANGES]; > static DEFINE_MUTEX(mtrr_mutex); > > u64 size_or_mask, size_and_mask; >@@ -121,13 +121,8 @@ static void __init init_table(void) > int i, max; > > max = num_var_ranges; >- if ((usage_table = kmalloc(max * sizeof *usage_table, GFP_KERNEL)) >- == NULL) { >- printk(KERN_ERR "mtrr: could not allocate\n"); >- return; >- } > for (i = 0; i < max; i++) >- usage_table[i] = 1; >+ mtrr_usage_table[i] = 1; > } > > struct set_mtrr_data { >@@ -383,7 +378,7 @@ int mtrr_add_page(unsigned long base, unsigned long size, > goto out; > } > if (increment) >- ++usage_table[i]; >+ ++mtrr_usage_table[i]; > error = i; > goto out; > } >@@ -391,15 +386,15 @@ int mtrr_add_page(unsigned long base, unsigned long size, > i = mtrr_if->get_free_region(base, size, replace); > if (i >= 0) { > set_mtrr(i, base, size, type); >- if (likely(replace < 0)) >- usage_table[i] = 1; >- else { >- usage_table[i] = usage_table[replace]; >+ if (likely(replace < 0)) { >+ mtrr_usage_table[i] = 1; >+ } else { >+ mtrr_usage_table[i] = mtrr_usage_table[replace]; > if (increment) >- usage_table[i]++; >+ mtrr_usage_table[i]++; > if (unlikely(replace != i)) { > set_mtrr(replace, 0, 0, 0); >- usage_table[replace] = 0; >+ mtrr_usage_table[replace] = 0; > } > } > } else >@@ -529,11 +524,11 @@ int mtrr_del_page(int reg, unsigned long base, unsigned long size) > printk(KERN_WARNING "mtrr: MTRR %d not used\n", reg); > goto out; > } >- if (usage_table[reg] < 1) { >+ if (mtrr_usage_table[reg] < 1) { > printk(KERN_WARNING "mtrr: reg: %d has count=0\n", reg); > goto out; > } >- if (--usage_table[reg] < 1) >+ if (--mtrr_usage_table[reg] < 1) > set_mtrr(reg, 0, 0, 0); > error = reg; > out: >@@ -593,16 +588,11 @@ struct mtrr_value { > unsigned long lsize; > }; > >-static struct mtrr_value * mtrr_state; >+static struct mtrr_value mtrr_state[MAX_VAR_RANGES]; > > static int mtrr_save(struct sys_device * sysdev, pm_message_t state) > { > int i; >- int size = num_var_ranges * sizeof(struct mtrr_value); >- >- mtrr_state = kzalloc(size,GFP_ATOMIC); >- if (!mtrr_state) >- return -ENOMEM; > > for (i = 0; i < num_var_ranges; i++) { > mtrr_if->get(i, >@@ -624,7 +614,6 @@ static int mtrr_restore(struct sys_device * sysdev) > mtrr_state[i].lsize, > mtrr_state[i].ltype); > } >- kfree(mtrr_state); > return 0; > } > >@@ -635,6 +624,109 @@ static struct sysdev_driver mtrr_sysdev_driver = { > .resume = mtrr_restore, > }; > >+#ifdef CONFIG_X86_64 >+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) >+ >+static __init int amd_special_default_mtrr(unsigned long end_pfn) >+{ >+ u32 l, h; >+ >+ /* Doesn't apply to memory < 4GB */ >+ if (end_pfn <= (0xffffffff >> PAGE_SHIFT)) >+ return 0; >+ 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; >+} >+ >+/** >+ * mtrr_trim_uncached_memory - trim RAM not covered by MTRRs >+ * >+ * 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_addr = 0, def, dummy; >+ mtrr_type type; >+ u64 trim_start, trim_size; >+ >+ /* >+ * Make sure we only trim uncachable memory on machines that >+ * support the Intel MTRR architecture: >+ */ >+ rdmsr(MTRRdefType_MSR, def, dummy); >+ def &= 0xff; >+ if (!is_cpu(INTEL) || disable_mtrr_trim || def != MTRR_TYPE_UNCACHABLE) >+ return 0; >+ >+ /* Find highest cached pfn */ >+ for (i = 0; i < num_var_ranges; i++) { >+ mtrr_if->get(i, &base, &size, &type); >+ if (type != MTRR_TYPE_WRBACK) >+ continue; >+ base <<= PAGE_SHIFT; >+ size <<= PAGE_SHIFT; >+ if (highest_addr < base + size) >+ highest_addr = base + size; >+ } >+ >+ if (amd_special_default_mtrr(end_pfn)) >+ return 0; >+ >+ if ((highest_addr >> PAGE_SHIFT) < end_pfn) { >+ printk(KERN_WARNING "***************\n"); >+ printk(KERN_WARNING "**** WARNING: likely BIOS bug\n"); >+ printk(KERN_WARNING "**** MTRRs don't cover all of " >+ "memory, trimmed %ld pages\n", end_pfn - >+ (highest_addr >> PAGE_SHIFT)); >+ printk(KERN_WARNING "***************\n"); >+ >+ printk(KERN_INFO "update e820 for mtrr\n"); >+ trim_start = highest_addr; >+ trim_size = end_pfn; >+ trim_size <<= PAGE_SHIFT; >+ trim_size -= trim_start; >+ add_memory_region(trim_start, trim_size, E820_RESERVED); >+ update_e820(); >+ return 1; >+ } >+ >+ return 0; >+} >+#endif > > /** > * mtrr_bp_init - initialize mtrrs on the boot CPU >diff --git a/arch/x86/kernel/cpu/mtrr/mtrr.h b/arch/x86/kernel/cpu/mtrr/mtrr.h >index 54347e9..fb74a2c 100644 >--- a/arch/x86/kernel/cpu/mtrr/mtrr.h >+++ b/arch/x86/kernel/cpu/mtrr/mtrr.h >@@ -12,6 +12,7 @@ > #define MTRRphysMask_MSR(reg) (0x200 + 2 * (reg) + 1) > > #define NUM_FIXED_RANGES 88 >+#define MAX_VAR_RANGES 256 > #define MTRRfix64K_00000_MSR 0x250 > #define MTRRfix16K_80000_MSR 0x258 > #define MTRRfix16K_A0000_MSR 0x259 >@@ -32,6 +33,8 @@ > an 8 bit field: */ > typedef u8 mtrr_type; > >+extern unsigned int mtrr_usage_table[MAX_VAR_RANGES]; >+ > struct mtrr_ops { > u32 vendor; > u32 use_intel_if; >diff --git a/arch/x86/kernel/setup_64.c b/arch/x86/kernel/setup_64.c >index 6cbd156..1294831 100644 >--- a/arch/x86/kernel/setup_64.c >+++ b/arch/x86/kernel/setup_64.c >@@ -310,6 +310,13 @@ void __init setup_arch(char **cmdline_p) > * we are rounding upwards: > */ > end_pfn = e820_end_of_ram(); >+ /* update e820 for memory not covered by WB MTRRs */ >+ mtrr_bp_init(); >+ if (mtrr_trim_uncached_memory(end_pfn)) { >+ e820_register_active_regions(0, 0, -1UL); >+ end_pfn = e820_end_of_ram(); >+ } >+ > num_physpages = end_pfn; > > check_efer(); >diff --git a/include/asm-x86/mtrr.h b/include/asm-x86/mtrr.h >index 262670e..319d065 100644 >--- a/include/asm-x86/mtrr.h >+++ b/include/asm-x86/mtrr.h >@@ -97,6 +97,7 @@ extern int mtrr_del_page (int reg, unsigned long base, unsigned long size); > extern void mtrr_centaur_report_mcr(int mcr, u32 lo, u32 hi); > extern void mtrr_ap_init(void); > extern void mtrr_bp_init(void); >+extern int mtrr_trim_uncached_memory(unsigned long end_pfn); > # else > #define mtrr_save_fixed_ranges(arg) do {} while (0) > #define mtrr_save_state() do {} while (0) >@@ -120,7 +121,10 @@ static __inline__ int mtrr_del_page (int reg, unsigned long base, > { > return -ENODEV; > } >- >+static inline int mtrr_trim_uncached_memory(unsigned long end_pfn) >+{ >+ return 0; >+} > static __inline__ void mtrr_centaur_report_mcr(int mcr, u32 lo, u32 hi) {;} > > #define mtrr_ap_init() do {} while (0) >commit 093af8d7f0ba3c6be1485973508584ef081e9f93 >Author: Yinghai Lu <Yinghai.Lu@Sun.COM> >Date: Wed Jan 30 13:33:32 2008 +0100 > > x86_32: trim memory by updating e820 > > when MTRRs are not covering the whole e820 table, we need to trim the > RAM and need to update e820. > > reuse some code on 64-bit as well. > > here need to add early_get_cap and use it in early_cpu_detect, and move > mtrr_bp_init early. > > The code successfully trimmed the memory map on Justin's system: > > from: > > [ 0.000000] BIOS-e820: 0000000100000000 - 000000022c000000 (usable) > > to: > > [ 0.000000] modified: 0000000100000000 - 0000000228000000 (usable) > [ 0.000000] modified: 0000000228000000 - 000000022c000000 (reserved) > > According to Justin it makes quite a difference: > > | When I boot the box without any trimming it acts like a 286 or 386, > | takes about 10 minutes to boot (using raptor disks). > > Signed-off-by: Yinghai Lu <yinghai.lu@sun.com> > Tested-by: Justin Piszcz <jpiszcz@lucidpixels.com> > Signed-off-by: Ingo Molnar <mingo@elte.hu> > Signed-off-by: Thomas Gleixner <tglx@linutronix.de> > >diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt >index 50d564d..fe3031d 100644 >--- a/Documentation/kernel-parameters.txt >+++ b/Documentation/kernel-parameters.txt >@@ -583,7 +583,7 @@ and is between 256 and 4096 characters. It is defined in the file > See drivers/char/README.epca and > Documentation/digiepca.txt. > >- disable_mtrr_trim [X86-64, Intel only] >+ disable_mtrr_trim [X86, Intel and AMD only] > By default the kernel will trim any uncacheable > memory out of your available memory pool based on > MTRR settings. This parameter disables that behavior, >diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c >index 56cc341..bba850b 100644 >--- a/arch/x86/kernel/cpu/common.c >+++ b/arch/x86/kernel/cpu/common.c >@@ -278,6 +278,33 @@ void __init cpu_detect(struct cpuinfo_x86 *c) > c->x86_cache_alignment = ((misc >> 8) & 0xff) * 8; > } > } >+static void __cpuinit early_get_cap(struct cpuinfo_x86 *c) >+{ >+ u32 tfms, xlvl; >+ int ebx; >+ >+ memset(&c->x86_capability, 0, sizeof c->x86_capability); >+ if (have_cpuid_p()) { >+ /* Intel-defined flags: level 0x00000001 */ >+ if (c->cpuid_level >= 0x00000001) { >+ u32 capability, excap; >+ cpuid(0x00000001, &tfms, &ebx, &excap, &capability); >+ c->x86_capability[0] = capability; >+ c->x86_capability[4] = excap; >+ } >+ >+ /* AMD-defined flags: level 0x80000001 */ >+ xlvl = cpuid_eax(0x80000000); >+ if ((xlvl & 0xffff0000) == 0x80000000) { >+ if (xlvl >= 0x80000001) { >+ c->x86_capability[1] = cpuid_edx(0x80000001); >+ c->x86_capability[6] = cpuid_ecx(0x80000001); >+ } >+ } >+ >+ } >+ >+} > > /* Do minimum CPU detection early. > Fields really needed: vendor, cpuid_level, family, model, mask, cache alignment. >@@ -306,6 +333,8 @@ static void __init early_cpu_detect(void) > early_init_intel(c); > break; > } >+ >+ early_get_cap(c); > } > > static void __cpuinit generic_identify(struct cpuinfo_x86 * c) >@@ -485,7 +514,6 @@ void __init identify_boot_cpu(void) > identify_cpu(&boot_cpu_data); > sysenter_setup(); > enable_sep_cpu(); >- mtrr_bp_init(); > } > > void __cpuinit identify_secondary_cpu(struct cpuinfo_x86 *c) >diff --git a/arch/x86/kernel/cpu/mtrr/main.c b/arch/x86/kernel/cpu/mtrr/main.c >index ccd36ed..ac4b633 100644 >--- a/arch/x86/kernel/cpu/mtrr/main.c >+++ b/arch/x86/kernel/cpu/mtrr/main.c >@@ -624,7 +624,6 @@ static struct sysdev_driver mtrr_sysdev_driver = { > .resume = mtrr_restore, > }; > >-#ifdef CONFIG_X86_64 > static int disable_mtrr_trim; > > static int __init disable_mtrr_trim_setup(char *str) >@@ -643,13 +642,10 @@ early_param("disable_mtrr_trim", disable_mtrr_trim_setup); > #define Tom2Enabled (1U << 21) > #define Tom2ForceMemTypeWB (1U << 22) > >-static __init int amd_special_default_mtrr(unsigned long end_pfn) >+static __init int amd_special_default_mtrr(void) > { > u32 l, h; > >- /* Doesn't apply to memory < 4GB */ >- if (end_pfn <= (0xffffffff >> PAGE_SHIFT)) >- return 0; > if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD) > return 0; > if (boot_cpu_data.x86 < 0xf || boot_cpu_data.x86 > 0x11) >@@ -687,9 +683,14 @@ int __init mtrr_trim_uncached_memory(unsigned long end_pfn) > * 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 (!is_cpu(INTEL) || disable_mtrr_trim || def != MTRR_TYPE_UNCACHABLE) >+ if (def != MTRR_TYPE_UNCACHABLE) >+ return 0; >+ >+ if (amd_special_default_mtrr()) > return 0; > > /* Find highest cached pfn */ >@@ -703,8 +704,14 @@ int __init mtrr_trim_uncached_memory(unsigned long end_pfn) > highest_addr = base + size; > } > >- if (amd_special_default_mtrr(end_pfn)) >+ /* kvm/qemu doesn't have mtrr set right, don't trim them all */ >+ if (!highest_addr) { >+ printk(KERN_WARNING "***************\n"); >+ printk(KERN_WARNING "**** WARNING: likely strange cpu\n"); >+ printk(KERN_WARNING "**** MTRRs all blank, cpu in qemu?\n"); >+ printk(KERN_WARNING "***************\n"); > return 0; >+ } > > if ((highest_addr >> PAGE_SHIFT) < end_pfn) { > printk(KERN_WARNING "***************\n"); >@@ -726,7 +733,6 @@ int __init mtrr_trim_uncached_memory(unsigned long end_pfn) > > return 0; > } >-#endif > > /** > * mtrr_bp_init - initialize mtrrs on the boot CPU >diff --git a/arch/x86/kernel/e820_32.c b/arch/x86/kernel/e820_32.c >index 931934a..4e16ef4 100644 >--- a/arch/x86/kernel/e820_32.c >+++ b/arch/x86/kernel/e820_32.c >@@ -749,3 +749,14 @@ static int __init parse_memmap(char *arg) > return 0; > } > early_param("memmap", parse_memmap); >+void __init update_e820(void) >+{ >+ u8 nr_map; >+ >+ nr_map = e820.nr_map; >+ if (sanitize_e820_map(e820.map, &nr_map)) >+ return; >+ e820.nr_map = nr_map; >+ printk(KERN_INFO "modified physical RAM map:\n"); >+ print_memory_map("modified"); >+} >diff --git a/arch/x86/kernel/setup_32.c b/arch/x86/kernel/setup_32.c >index 26a56f7..83ba3ca 100644 >--- a/arch/x86/kernel/setup_32.c >+++ b/arch/x86/kernel/setup_32.c >@@ -48,6 +48,7 @@ > > #include <video/edid.h> > >+#include <asm/mtrr.h> > #include <asm/apic.h> > #include <asm/e820.h> > #include <asm/mpspec.h> >@@ -758,6 +759,11 @@ void __init setup_arch(char **cmdline_p) > > max_low_pfn = setup_memory(); > >+ /* update e820 for memory not covered by WB MTRRs */ >+ mtrr_bp_init(); >+ if (mtrr_trim_uncached_memory(max_pfn)) >+ max_low_pfn = setup_memory(); >+ > #ifdef CONFIG_VMI > /* > * Must be after max_low_pfn is determined, and before kernel >diff --git a/include/asm-x86/e820_32.h b/include/asm-x86/e820_32.h >index e2faf5f..f1da7eb 100644 >--- a/include/asm-x86/e820_32.h >+++ b/include/asm-x86/e820_32.h >@@ -19,12 +19,15 @@ > #ifndef __ASSEMBLY__ > > extern struct e820map e820; >+extern void update_e820(void); > > extern int e820_all_mapped(unsigned long start, unsigned long end, > unsigned type); > extern int e820_any_mapped(u64 start, u64 end, unsigned type); > extern void find_max_pfn(void); > extern void register_bootmem_low_pages(unsigned long max_low_pfn); >+extern void add_memory_region(unsigned long long start, >+ unsigned long long size, int type); > extern void e820_register_memory(void); > extern void limit_regions(unsigned long long size); > extern void print_memory_map(char *who); >commit cd7d72bb27a8c7502a602bdc299f1bb0a9357975 >Author: Ingo Molnar <mingo@elte.hu> >Date: Wed Jan 30 13:33:35 2008 +0100 > > x86: improve MTRR trimming messages > > improve the MTTR trimming messages and also trigger a WARN_ON() > so that kerneloops.org can pick it up and categorize it. > > Signed-off-by: Ingo Molnar <mingo@elte.hu> > Signed-off-by: Thomas Gleixner <tglx@linutronix.de> > >diff --git a/arch/x86/kernel/cpu/mtrr/main.c b/arch/x86/kernel/cpu/mtrr/main.c >index ac4b633..7159195 100644 >--- a/arch/x86/kernel/cpu/mtrr/main.c >+++ b/arch/x86/kernel/cpu/mtrr/main.c >@@ -706,20 +706,17 @@ int __init mtrr_trim_uncached_memory(unsigned long end_pfn) > > /* kvm/qemu doesn't have mtrr set right, don't trim them all */ > if (!highest_addr) { >- printk(KERN_WARNING "***************\n"); >- printk(KERN_WARNING "**** WARNING: likely strange cpu\n"); >- printk(KERN_WARNING "**** MTRRs all blank, cpu in qemu?\n"); >- printk(KERN_WARNING "***************\n"); >+ printk(KERN_WARNING "WARNING: strange, CPU MTRRs all blank?\n"); >+ WARN_ON(1); > return 0; > } > > if ((highest_addr >> PAGE_SHIFT) < end_pfn) { >- printk(KERN_WARNING "***************\n"); >- printk(KERN_WARNING "**** WARNING: likely BIOS bug\n"); >- printk(KERN_WARNING "**** MTRRs don't cover all of " >- "memory, trimmed %ld pages\n", end_pfn - >- (highest_addr >> PAGE_SHIFT)); >- printk(KERN_WARNING "***************\n"); >+ printk(KERN_WARNING "WARNING: BIOS bug: CPU MTRRs don't cover" >+ " all of memory, losing %LdMB of RAM.\n", >+ (((u64)end_pfn << PAGE_SHIFT) - highest_addr) >> 20); >+ >+ WARN_ON(1); > > printk(KERN_INFO "update e820 for mtrr\n"); > trim_start = highest_addr; >commit 9a6b344ea967efa0bb5ca4cb5405f840652b66c4 >Author: Harvey Harrison <harvey.harrison@gmail.com> >Date: Mon Feb 4 16:48:01 2008 +0100 > > x86: remove long dead cyrix mtrr code > > cyrix_arr_init was #if 0 all the way back to at least v2.6.12. > > This was the only place where arr3_protected was set to anything > but zero. Eliminate this variable. > > Signed-off-by: Harvey Harrison <harvey.harrison@gmail.com> > Signed-off-by: Ingo Molnar <mingo@elte.hu> > Signed-off-by: Thomas Gleixner <tglx@linutronix.de> > >diff --git a/arch/x86/kernel/cpu/mtrr/cyrix.c b/arch/x86/kernel/cpu/mtrr/cyrix.c >index 8e139c7..ff14c32 100644 >--- a/arch/x86/kernel/cpu/mtrr/cyrix.c >+++ b/arch/x86/kernel/cpu/mtrr/cyrix.c >@@ -7,8 +7,6 @@ > #include <asm/processor-flags.h> > #include "mtrr.h" > >-int arr3_protected; >- > static void > cyrix_get_arr(unsigned int reg, unsigned long *base, > unsigned long *size, mtrr_type * type) >@@ -99,8 +97,6 @@ cyrix_get_free_region(unsigned long base, unsigned long size, int replace_reg) > case 4: > return replace_reg; > case 3: >- if (arr3_protected) >- break; > case 2: > case 1: > case 0: >@@ -115,8 +111,6 @@ cyrix_get_free_region(unsigned long base, unsigned long size, int replace_reg) > } else { > for (i = 0; i < 7; i++) { > cyrix_get_arr(i, &lbase, &lsize, <ype); >- if ((i == 3) && arr3_protected) >- continue; > if (lsize == 0) > return i; > } >@@ -260,107 +254,6 @@ static void cyrix_set_all(void) > post_set(); > } > >-#if 0 >-/* >- * On Cyrix 6x86(MX) and M II the ARR3 is special: it has connection >- * with the SMM (System Management Mode) mode. So we need the following: >- * Check whether SMI_LOCK (CCR3 bit 0) is set >- * if it is set, write a warning message: ARR3 cannot be changed! >- * (it cannot be changed until the next processor reset) >- * if it is reset, then we can change it, set all the needed bits: >- * - disable access to SMM memory through ARR3 range (CCR1 bit 7 reset) >- * - disable access to SMM memory (CCR1 bit 2 reset) >- * - disable SMM mode (CCR1 bit 1 reset) >- * - disable write protection of ARR3 (CCR6 bit 1 reset) >- * - (maybe) disable ARR3 >- * Just to be sure, we enable ARR usage by the processor (CCR5 bit 5 set) >- */ >-static void __init >-cyrix_arr_init(void) >-{ >- struct set_mtrr_context ctxt; >- unsigned char ccr[7]; >- int ccrc[7] = { 0, 0, 0, 0, 0, 0, 0 }; >-#ifdef CONFIG_SMP >- int i; >-#endif >- >- /* flush cache and enable MAPEN */ >- set_mtrr_prepare_save(&ctxt); >- set_mtrr_cache_disable(&ctxt); >- >- /* Save all CCRs locally */ >- ccr[0] = getCx86(CX86_CCR0); >- ccr[1] = getCx86(CX86_CCR1); >- ccr[2] = getCx86(CX86_CCR2); >- ccr[3] = ctxt.ccr3; >- ccr[4] = getCx86(CX86_CCR4); >- ccr[5] = getCx86(CX86_CCR5); >- ccr[6] = getCx86(CX86_CCR6); >- >- if (ccr[3] & 1) { >- ccrc[3] = 1; >- arr3_protected = 1; >- } else { >- /* Disable SMM mode (bit 1), access to SMM memory (bit 2) and >- * access to SMM memory through ARR3 (bit 7). >- */ >- if (ccr[1] & 0x80) { >- ccr[1] &= 0x7f; >- ccrc[1] |= 0x80; >- } >- if (ccr[1] & 0x04) { >- ccr[1] &= 0xfb; >- ccrc[1] |= 0x04; >- } >- if (ccr[1] & 0x02) { >- ccr[1] &= 0xfd; >- ccrc[1] |= 0x02; >- } >- arr3_protected = 0; >- if (ccr[6] & 0x02) { >- ccr[6] &= 0xfd; >- ccrc[6] = 1; /* Disable write protection of ARR3 */ >- setCx86(CX86_CCR6, ccr[6]); >- } >- /* Disable ARR3. This is safe now that we disabled SMM. */ >- /* cyrix_set_arr_up (3, 0, 0, 0, FALSE); */ >- } >- /* If we changed CCR1 in memory, change it in the processor, too. */ >- if (ccrc[1]) >- setCx86(CX86_CCR1, ccr[1]); >- >- /* Enable ARR usage by the processor */ >- if (!(ccr[5] & 0x20)) { >- ccr[5] |= 0x20; >- ccrc[5] = 1; >- setCx86(CX86_CCR5, ccr[5]); >- } >-#ifdef CONFIG_SMP >- for (i = 0; i < 7; i++) >- ccr_state[i] = ccr[i]; >- for (i = 0; i < 8; i++) >- cyrix_get_arr(i, >- &arr_state[i].base, &arr_state[i].size, >- &arr_state[i].type); >-#endif >- >- set_mtrr_done(&ctxt); /* flush cache and disable MAPEN */ >- >- if (ccrc[5]) >- printk(KERN_INFO "mtrr: ARR usage was not enabled, enabled manually\n"); >- if (ccrc[3]) >- printk(KERN_INFO "mtrr: ARR3 cannot be changed\n"); >-/* >- if ( ccrc[1] & 0x80) printk ("mtrr: SMM memory access through ARR3 disabled\n"); >- if ( ccrc[1] & 0x04) printk ("mtrr: SMM memory access disabled\n"); >- if ( ccrc[1] & 0x02) printk ("mtrr: SMM mode disabled\n"); >-*/ >- if (ccrc[6]) >- printk(KERN_INFO "mtrr: ARR3 was write protected, unprotected\n"); >-} >-#endif >- > static struct mtrr_ops cyrix_mtrr_ops = { > .vendor = X86_VENDOR_CYRIX, > // .init = cyrix_arr_init, >diff --git a/arch/x86/kernel/cpu/mtrr/main.c b/arch/x86/kernel/cpu/mtrr/main.c >index 7159195..822d8f9 100644 >--- a/arch/x86/kernel/cpu/mtrr/main.c >+++ b/arch/x86/kernel/cpu/mtrr/main.c >@@ -59,12 +59,6 @@ struct mtrr_ops * mtrr_if = NULL; > static void set_mtrr(unsigned int reg, unsigned long base, > unsigned long size, mtrr_type type); > >-#ifndef CONFIG_X86_64 >-extern int arr3_protected; >-#else >-#define arr3_protected 0 >-#endif >- > void set_mtrr_ops(struct mtrr_ops * ops) > { > if (ops->vendor && ops->vendor < X86_VENDOR_NUM) >@@ -513,12 +507,6 @@ int mtrr_del_page(int reg, unsigned long base, unsigned long size) > printk(KERN_WARNING "mtrr: register: %d too big\n", reg); > goto out; > } >- if (is_cpu(CYRIX) && !use_intel()) { >- if ((reg == 3) && arr3_protected) { >- printk(KERN_WARNING "mtrr: ARR3 cannot be changed\n"); >- goto out; >- } >- } > mtrr_if->get(reg, &lbase, &lsize, <ype); > if (lsize < 1) { > printk(KERN_WARNING "mtrr: MTRR %d not used\n", reg); >commit 16c02ed74361433a4fc5d8bd5f67abbac6e1c5ca >Author: Harvey Harrison <harvey.harrison@gmail.com> >Date: Mon Feb 4 16:48:05 2008 +0100 > > x86: add cpu mtrr init function definitions to mtrr.h > > mtrr.h was included everywhere needed. Fixes the following sparse > warnings. Also, the return types in the extern definitions were > incorrect. > > arch/x86/kernel/cpu/mtrr/amd.c:113:12: warning: symbol 'amd_init_mtrr' was not declared. Should it be static? > arch/x86/kernel/cpu/mtrr/cyrix.c:268:12: warning: symbol 'cyrix_init_mtrr' was not declared. Should it be static? > arch/x86/kernel/cpu/mtrr/centaur.c:218:12: warning: symbol 'centaur_init_mtrr' was not declared. Should it be static? > > Signed-off-by: Harvey Harrison <harvey.harrison@gmail.com> > Signed-off-by: Ingo Molnar <mingo@elte.hu> > Signed-off-by: Thomas Gleixner <tglx@linutronix.de> > >diff --git a/arch/x86/kernel/cpu/mtrr/main.c b/arch/x86/kernel/cpu/mtrr/main.c >index 822d8f9..1e27b69 100644 >--- a/arch/x86/kernel/cpu/mtrr/main.c >+++ b/arch/x86/kernel/cpu/mtrr/main.c >@@ -554,10 +554,6 @@ EXPORT_SYMBOL(mtrr_del); > * These should be called implicitly, but we can't yet until all the initcall > * stuff is done... > */ >-extern void amd_init_mtrr(void); >-extern void cyrix_init_mtrr(void); >-extern void centaur_init_mtrr(void); >- > static void __init init_ifs(void) > { > #ifndef CONFIG_X86_64 >diff --git a/arch/x86/kernel/cpu/mtrr/mtrr.h b/arch/x86/kernel/cpu/mtrr/mtrr.h >index fb74a2c..2cc77eb 100644 >--- a/arch/x86/kernel/cpu/mtrr/mtrr.h >+++ b/arch/x86/kernel/cpu/mtrr/mtrr.h >@@ -97,3 +97,7 @@ void mtrr_state_warn(void); > const char *mtrr_attrib_to_str(int x); > void mtrr_wrmsr(unsigned, unsigned, unsigned); > >+/* CPU specific mtrr init functions */ >+int amd_init_mtrr(void); >+int cyrix_init_mtrr(void); >+int centaur_init_mtrr(void); >commit 20651af9ac60fd6e31360688ad44861a7d05256a >Author: Yinghai Lu <yinghai.lu@sun.com> >Date: Wed Feb 6 22:39:45 2008 +0100 > > x86: fix mttr trimming > > Pavel Emelyanov reported that his networking card did not work > and bisected it down to: > > " > The commit > > 093af8d7f0ba3c6be1485973508584ef081e9f93 > x86_32: trim memory by updating e820 > > broke my e1000 card: on loading driver says that > > e1000: probe of 0000:04:03.0 failed with error -5 > > and the interface doesn't appear. > " > > on a 32-bit kernel, base will overflow when try to do PAGE_SHIFT, > and highest_addr will always less 4G. > > So use pfn instead of address to avoid the overflow when more than > 4g RAM is installed on a 32-bit kernel. > > Many thanks to Pavel Emelyanov for reporting and testing it. > > Bisected-by: Pavel Emelyanov <xemul@openvz.org> > Signed-off-by: Yinghai Lu <yinghai.lu@sun.com> > Tested-by: Pavel Emelyanov <xemul@openvz.org> > Signed-off-by: Ingo Molnar <mingo@elte.hu> > >diff --git a/arch/x86/kernel/cpu/mtrr/main.c b/arch/x86/kernel/cpu/mtrr/main.c >index 1e27b69..b6e136f 100644 >--- a/arch/x86/kernel/cpu/mtrr/main.c >+++ b/arch/x86/kernel/cpu/mtrr/main.c >@@ -659,7 +659,7 @@ static __init int amd_special_default_mtrr(void) > */ > int __init mtrr_trim_uncached_memory(unsigned long end_pfn) > { >- unsigned long i, base, size, highest_addr = 0, def, dummy; >+ unsigned long i, base, size, highest_pfn = 0, def, dummy; > mtrr_type type; > u64 trim_start, trim_size; > >@@ -682,28 +682,27 @@ int __init mtrr_trim_uncached_memory(unsigned long end_pfn) > mtrr_if->get(i, &base, &size, &type); > if (type != MTRR_TYPE_WRBACK) > continue; >- base <<= PAGE_SHIFT; >- size <<= PAGE_SHIFT; >- if (highest_addr < base + size) >- highest_addr = base + size; >+ if (highest_pfn < base + size) >+ highest_pfn = base + size; > } > > /* kvm/qemu doesn't have mtrr set right, don't trim them all */ >- if (!highest_addr) { >+ if (!highest_pfn) { > printk(KERN_WARNING "WARNING: strange, CPU MTRRs all blank?\n"); > WARN_ON(1); > return 0; > } > >- if ((highest_addr >> PAGE_SHIFT) < end_pfn) { >+ if (highest_pfn < end_pfn) { > printk(KERN_WARNING "WARNING: BIOS bug: CPU MTRRs don't cover" >- " all of memory, losing %LdMB of RAM.\n", >- (((u64)end_pfn << PAGE_SHIFT) - highest_addr) >> 20); >+ " all of memory, losing %luMB of RAM.\n", >+ (end_pfn - highest_pfn) >> (20 - PAGE_SHIFT)); > > WARN_ON(1); > > printk(KERN_INFO "update e820 for mtrr\n"); >- trim_start = highest_addr; >+ trim_start = highest_pfn; >+ trim_start <<= PAGE_SHIFT; > trim_size = end_pfn; > trim_size <<= PAGE_SHIFT; > trim_size -= trim_start; >commit f5106d91f2bf9153d6420f9ebb8114f73f9ce66a >Author: Randy Dunlap <randy.dunlap@oracle.com> >Date: Mon Feb 18 13:10:44 2008 -0800 > > x86/mtrr: fix kernel-doc missing notation > > Fix mtrr kernel-doc warning: > Warning(linux-2.6.24-git12//arch/x86/kernel/cpu/mtrr/main.c:677): No description found for parameter 'end_pfn' > > Signed-off-by: Randy Dunlap <randy.dunlap@oracle.com> > Signed-off-by: Ingo Molnar <mingo@elte.hu> > >diff --git a/arch/x86/kernel/cpu/mtrr/main.c b/arch/x86/kernel/cpu/mtrr/main.c >index b6e136f..c8fda3e 100644 >--- a/arch/x86/kernel/cpu/mtrr/main.c >+++ b/arch/x86/kernel/cpu/mtrr/main.c >@@ -649,6 +649,7 @@ static __init int amd_special_default_mtrr(void) > > /** > * 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 > >commit aaf230424204864e2833dcc1da23e2cb0b9f39cd >Author: Yinghai Lu <Yinghai.Lu@Sun.COM> >Date: Wed Jan 30 13:33:09 2008 +0100 > > x86: disable the GART early, 64-bit > > For K8 system: 4G RAM with memory hole remapping enabled, or more than > 4G RAM installed. > > when try to use kexec second kernel, and the first doesn't include > gart_shutdown. the second kernel could have different aper position than > the first kernel. and second kernel could use that hole as RAM that is > still used by GART set by the first kernel. esp. when try to kexec > 2.6.24 with sparse mem enable from previous kernel (from RHEL 5 or SLES > 10). the new kernel will use aper by GART (set by first kernel) for > vmemmap. and after new kernel setting one new GART. the position will be > real RAM. the _mapcount set is lost. > > Bad page state in process 'swapper' > page:ffffe2000e600020 flags:0x0000000000000000 mapping:0000000000000000 mapcount:1 count:0 > Trying to fix it up, but a reboot is needed > Backtrace: > Pid: 0, comm: swapper Not tainted 2.6.24-rc7-smp-gcdf71a10-dirty #13 > > Call Trace: > [<ffffffff8026401f>] bad_page+0x63/0x8d > [<ffffffff80264169>] __free_pages_ok+0x7c/0x2a5 > [<ffffffff80ba75d1>] free_all_bootmem_core+0xd0/0x198 > [<ffffffff80ba3a42>] numa_free_all_bootmem+0x3b/0x76 > [<ffffffff80ba3461>] mem_init+0x3b/0x152 > [<ffffffff80b959d3>] start_kernel+0x236/0x2c2 > [<ffffffff80b9511a>] _sinittext+0x11a/0x121 > > and > [ffffe2000e600000-ffffe2000e7fffff] PMD ->ffff81001c200000 on node 0 > phys addr is : 0x1c200000 > > RHEL 5.1 kernel -53 said: > PCI-DMA: aperture base @ 1c000000 size 65536 KB > > new kernel said: > Mapping aperture over 65536 KB of RAM @ 3c000000 > > So could try to disable that GART if possible. > > According to Ingo > > > hm, i'm wondering, instead of modifying the GART, why dont we simply > > _detect_ whatever GART settings we have inherited, and propagate that > > into our e820 maps? I.e. if there's inconsistency, then punch that out > > from the memory maps and just dont use that memory. > > > > that way it would not matter whether the GART settings came from a [old > > or crashing] Linux kernel that has not called gart_iommu_shutdown(), or > > whether it's a BIOS that has set up an aperture hole inconsistent with > > the memory map it passed. (or the memory map we _think_ i tried to pass > > us) > > > > it would also be more robust to only read and do a memory map quirk > > based on that, than actively trying to change the GART so early in the > > bootup. Later on we have to re-enable the GART _anyway_ and have to > > punch a hole for it. > > > > and as a bonus, we would have shored up our defenses against crappy > > BIOSes as well. > > add e820 modification for gart inconsistent setting. > > gart_fix_e820=off could be used to disable e820 fix. > > Signed-off-by: Yinghai Lu <yinghai.lu@sun.com> > Signed-off-by: Ingo Molnar <mingo@elte.hu> > Signed-off-by: Thomas Gleixner <tglx@linutronix.de> > >diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt >index 40db7dd..860a908 100644 >--- a/Documentation/kernel-parameters.txt >+++ b/Documentation/kernel-parameters.txt >@@ -660,6 +660,10 @@ and is between 256 and 4096 characters. It is defined in the file > > gamma= [HW,DRM] > >+ gart_fix_e820= [X86_64] disable the fix e820 for K8 GART >+ Format: off | on >+ default: on >+ > gdth= [HW,SCSI] > See header of drivers/scsi/gdth.c. > >diff --git a/arch/x86/kernel/aperture_64.c b/arch/x86/kernel/aperture_64.c >index 52d2bea..bf1b469 100644 >--- a/arch/x86/kernel/aperture_64.c >+++ b/arch/x86/kernel/aperture_64.c >@@ -218,6 +218,95 @@ static __u32 __init search_agp_bridge(u32 *order, int *valid_agp) > return 0; > } > >+static int gart_fix_e820 __initdata = 1; >+ >+static int __init parse_gart_mem(char *p) >+{ >+ if (!p) >+ return -EINVAL; >+ >+ if (!strncmp(p, "off", 3)) >+ gart_fix_e820 = 0; >+ else if (!strncmp(p, "on", 2)) >+ gart_fix_e820 = 1; >+ >+ return 0; >+} >+early_param("gart_fix_e820", parse_gart_mem); >+ >+void __init early_gart_iommu_check(void) >+{ >+ /* >+ * in case it is enabled before, esp for kexec/kdump, >+ * previous kernel already enable that. memset called >+ * by allocate_aperture/__alloc_bootmem_nopanic cause restart. >+ * or second kernel have different position for GART hole. and new >+ * kernel could use hole as RAM that is still used by GART set by >+ * first kernel >+ * or BIOS forget to put that in reserved. >+ * try to update e820 to make that region as reserved. >+ */ >+ int fix, num; >+ u32 ctl; >+ u32 aper_size = 0, aper_order = 0, last_aper_order = 0; >+ u64 aper_base = 0, last_aper_base = 0; >+ int aper_enabled = 0, last_aper_enabled = 0; >+ >+ if (!early_pci_allowed()) >+ return; >+ >+ fix = 0; >+ for (num = 24; num < 32; num++) { >+ if (!early_is_k8_nb(read_pci_config(0, num, 3, 0x00))) >+ continue; >+ >+ ctl = read_pci_config(0, num, 3, 0x90); >+ aper_enabled = ctl & 1; >+ aper_order = (ctl >> 1) & 7; >+ aper_size = (32 * 1024 * 1024) << aper_order; >+ aper_base = read_pci_config(0, num, 3, 0x94) & 0x7fff; >+ aper_base <<= 25; >+ >+ if ((last_aper_order && aper_order != last_aper_order) || >+ (last_aper_base && aper_base != last_aper_base) || >+ (last_aper_enabled && aper_enabled != last_aper_enabled)) { >+ fix = 1; >+ break; >+ } >+ last_aper_order = aper_order; >+ last_aper_base = aper_base; >+ last_aper_enabled = aper_enabled; >+ } >+ >+ if (!fix && !aper_enabled) >+ return; >+ >+ if (!aper_base || !aper_size || aper_base + aper_size > 0x100000000UL) >+ fix = 1; >+ >+ if (gart_fix_e820 && !fix && aper_enabled) { >+ if (e820_any_mapped(aper_base, aper_base + aper_size, >+ E820_RAM)) { >+ /* reserved it, so we can resuse it in second kernel */ >+ printk(KERN_INFO "update e820 for GART\n"); >+ add_memory_region(aper_base, aper_size, E820_RESERVED); >+ update_e820(); >+ } >+ return; >+ } >+ >+ /* different nodes have different setting, disable them all at first*/ >+ for (num = 24; num < 32; num++) { >+ if (!early_is_k8_nb(read_pci_config(0, num, 3, 0x00))) >+ continue; >+ >+ ctl = read_pci_config(0, num, 3, 0x90); >+ ctl &= ~1; >+ write_pci_config(0, num, 3, 0x90, ctl); >+ } >+ >+} >+ > void __init gart_iommu_hole_init(void) > { > u32 aper_size, aper_alloc = 0, aper_order = 0, last_aper_order = 0; >diff --git a/arch/x86/kernel/e820_64.c b/arch/x86/kernel/e820_64.c >index abc473b..07cfaae 100644 >--- a/arch/x86/kernel/e820_64.c >+++ b/arch/x86/kernel/e820_64.c >@@ -728,6 +728,18 @@ void __init finish_e820_parsing(void) > } > } > >+void __init update_e820(void) >+{ >+ u8 nr_map; >+ >+ nr_map = e820.nr_map; >+ if (sanitize_e820_map(e820.map, &nr_map)) >+ return; >+ e820.nr_map = nr_map; >+ printk(KERN_INFO "modified physical RAM map:\n"); >+ e820_print_map("modified"); >+} >+ > unsigned long pci_mem_start = 0xaeedbabe; > EXPORT_SYMBOL(pci_mem_start); > >diff --git a/arch/x86/kernel/setup_64.c b/arch/x86/kernel/setup_64.c >index 07547fe..12bad27 100644 >--- a/arch/x86/kernel/setup_64.c >+++ b/arch/x86/kernel/setup_64.c >@@ -53,6 +53,7 @@ > #include <video/edid.h> > #include <asm/e820.h> > #include <asm/dma.h> >+#include <asm/gart.h> > #include <asm/mpspec.h> > #include <asm/mmu_context.h> > #include <asm/proto.h> >@@ -335,6 +336,8 @@ void __init setup_arch(char **cmdline_p) > > finish_e820_parsing(); > >+ early_gart_iommu_check(); >+ > e820_register_active_regions(0, 0, -1UL); > /* > * partially used pages are not usable - thus >diff --git a/include/asm-x86/e820_64.h b/include/asm-x86/e820_64.h >index 8cba49d..ff36f43 100644 >--- a/include/asm-x86/e820_64.h >+++ b/include/asm-x86/e820_64.h >@@ -39,6 +39,7 @@ extern void e820_register_active_regions(int nid, > extern void finish_e820_parsing(void); > > extern struct e820map e820; >+extern void update_e820(void); > > extern unsigned ebda_addr, ebda_size; > extern unsigned long nodemap_addr, nodemap_size; >diff --git a/include/asm-x86/gart.h b/include/asm-x86/gart.h >index f704c50..90958ed 100644 >--- a/include/asm-x86/gart.h >+++ b/include/asm-x86/gart.h >@@ -9,6 +9,7 @@ extern int iommu_detected; > extern void gart_iommu_init(void); > extern void gart_iommu_shutdown(void); > extern void __init gart_parse_options(char *); >+extern void early_gart_iommu_check(void); > extern void gart_iommu_hole_init(void); > extern int fallback_aper_order; > extern int fallback_aper_force; >@@ -20,6 +21,10 @@ extern int fix_aperture; > #define gart_iommu_aperture 0 > #define gart_iommu_aperture_allowed 0 > >+static inline void early_gart_iommu_check(void) >+{ >+} >+ > static inline void gart_iommu_shutdown(void) > { > } >commit 5dca6a1bb014875a17289fdaae8c31e0a3641c99 >Author: Yinghai Lu <yhlu.kernel.send@gmail.com> >Date: Tue Mar 18 16:44:19 2008 -0700 > > x86: trim mtrr don't close gap for resource allocation. > > fix the bug reported here: > > http://bugzilla.kernel.org/show_bug.cgi?id=10232 > > use update_memory_range() instead of add_memory_range() directly > to avoid closing the gap. > > ( the new code only affects and runs on systems where the MTRR > workaround triggers. ) > > Signed-off-by: Yinghai Lu <yhlu.kernel@gmail.com> > Signed-off-by: Ingo Molnar <mingo@elte.hu> > Signed-off-by: Thomas Gleixner <tglx@linutronix.de> > >diff --git a/arch/x86/kernel/cpu/mtrr/main.c b/arch/x86/kernel/cpu/mtrr/main.c >index be83336..a6450b3 100644 >--- a/arch/x86/kernel/cpu/mtrr/main.c >+++ b/arch/x86/kernel/cpu/mtrr/main.c >@@ -711,7 +711,8 @@ int __init mtrr_trim_uncached_memory(unsigned long end_pfn) > trim_size = end_pfn; > trim_size <<= PAGE_SHIFT; > trim_size -= trim_start; >- add_memory_region(trim_start, trim_size, E820_RESERVED); >+ update_memory_range(trim_start, trim_size, E820_RAM, >+ E820_RESERVED); > update_e820(); > return 1; > } >diff --git a/arch/x86/kernel/e820_32.c b/arch/x86/kernel/e820_32.c >index 4e16ef4..80444c5 100644 >--- a/arch/x86/kernel/e820_32.c >+++ b/arch/x86/kernel/e820_32.c >@@ -749,6 +749,32 @@ static int __init parse_memmap(char *arg) > return 0; > } > early_param("memmap", parse_memmap); >+void __init update_memory_range(u64 start, u64 size, unsigned old_type, >+ unsigned new_type) >+{ >+ int i; >+ >+ BUG_ON(old_type == new_type); >+ >+ for (i = 0; i < e820.nr_map; i++) { >+ struct e820entry *ei = &e820.map[i]; >+ u64 final_start, final_end; >+ if (ei->type != old_type) >+ continue; >+ /* totally covered? */ >+ if (ei->addr >= start && ei->size <= size) { >+ ei->type = new_type; >+ continue; >+ } >+ /* partially covered */ >+ final_start = max(start, ei->addr); >+ final_end = min(start + size, ei->addr + ei->size); >+ if (final_start >= final_end) >+ continue; >+ add_memory_region(final_start, final_end - final_start, >+ new_type); >+ } >+} > void __init update_e820(void) > { > u8 nr_map; >diff --git a/arch/x86/kernel/e820_64.c b/arch/x86/kernel/e820_64.c >index 9f65b4c..9be6971 100644 >--- a/arch/x86/kernel/e820_64.c >+++ b/arch/x86/kernel/e820_64.c >@@ -744,6 +744,33 @@ void __init finish_e820_parsing(void) > } > } > >+void __init update_memory_range(u64 start, u64 size, unsigned old_type, >+ unsigned new_type) >+{ >+ int i; >+ >+ BUG_ON(old_type == new_type); >+ >+ for (i = 0; i < e820.nr_map; i++) { >+ struct e820entry *ei = &e820.map[i]; >+ u64 final_start, final_end; >+ if (ei->type != old_type) >+ continue; >+ /* totally covered? */ >+ if (ei->addr >= start && ei->size <= size) { >+ ei->type = new_type; >+ continue; >+ } >+ /* partially covered */ >+ final_start = max(start, ei->addr); >+ final_end = min(start + size, ei->addr + ei->size); >+ if (final_start >= final_end) >+ continue; >+ add_memory_region(final_start, final_end - final_start, >+ new_type); >+ } >+} >+ > void __init update_e820(void) > { > u8 nr_map; >diff --git a/include/asm-x86/e820_32.h b/include/asm-x86/e820_32.h >index f1da7eb..e7207a6 100644 >--- a/include/asm-x86/e820_32.h >+++ b/include/asm-x86/e820_32.h >@@ -28,6 +28,8 @@ extern void find_max_pfn(void); > extern void register_bootmem_low_pages(unsigned long max_low_pfn); > extern void add_memory_region(unsigned long long start, > unsigned long long size, int type); >+extern void update_memory_range(u64 start, u64 size, unsigned old_type, >+ unsigned new_type); > extern void e820_register_memory(void); > extern void limit_regions(unsigned long long size); > extern void print_memory_map(char *who); >diff --git a/include/asm-x86/e820_64.h b/include/asm-x86/e820_64.h >index a560c4f..22ede73 100644 >--- a/include/asm-x86/e820_64.h >+++ b/include/asm-x86/e820_64.h >@@ -18,6 +18,8 @@ extern unsigned long find_e820_area(unsigned long start, unsigned long end, > unsigned size, unsigned long align); > extern void add_memory_region(unsigned long start, unsigned long size, > int type); >+extern void update_memory_range(u64 start, u64 size, unsigned old_type, >+ unsigned new_type); > extern void setup_memory_region(void); > extern void contig_e820_setup(void); > extern unsigned long e820_end_of_ram(void);
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 438960
:
299355
| 299365