From 77b52b4c5c66175553ee59eb43f74366f1e54bde Mon Sep 17 00:00:00 2001 From: Venki Pallipadi Date: Mon, 5 May 2008 19:09:10 -0700 Subject: x86: add "debugpat" boot option enable debug messages by a boot option "debugpat". Signed-off-by: Venkatesh Pallipadi Signed-off-by: Ingo Molnar Signed-off-by: Thomas Gleixner --- arch/x86/mm/pat.c | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) (limited to 'arch/x86/mm/pat.c') diff --git a/arch/x86/mm/pat.c b/arch/x86/mm/pat.c index 60adbe22efa0..1a82f4db8a46 100644 --- a/arch/x86/mm/pat.c +++ b/arch/x86/mm/pat.c @@ -42,6 +42,19 @@ static int nopat(char *str) early_param("nopat", nopat); #endif + +static int debug_enable; +static int __init pat_debug_setup(char *str) +{ + debug_enable = 1; + return 0; +} +__setup("debugpat", pat_debug_setup); + +#define dprintk(fmt, arg...) \ + do { if (debug_enable) printk(KERN_INFO fmt, ##arg); } while (0) + + static u64 __read_mostly boot_pat_state; enum { @@ -279,7 +292,7 @@ int reserve_memtype(u64 start, u64 end, unsigned long req_type, struct memtype *saved_ptr; if (parse->start >= end) { - pr_debug("New Entry\n"); + dprintk("New Entry\n"); list_add(&new_entry->nd, parse->nd.prev); new_entry = NULL; break; @@ -329,7 +342,7 @@ int reserve_memtype(u64 start, u64 end, unsigned long req_type, break; } - pr_debug("Overlap at 0x%Lx-0x%Lx\n", + dprintk("Overlap at 0x%Lx-0x%Lx\n", saved_ptr->start, saved_ptr->end); /* No conflict. Go ahead and add this new entry */ list_add(&new_entry->nd, saved_ptr->nd.prev); @@ -381,7 +394,7 @@ int reserve_memtype(u64 start, u64 end, unsigned long req_type, break; } - pr_debug(KERN_INFO "Overlap at 0x%Lx-0x%Lx\n", + dprintk("Overlap at 0x%Lx-0x%Lx\n", saved_ptr->start, saved_ptr->end); /* No conflict. Go ahead and add this new entry */ list_add(&new_entry->nd, &saved_ptr->nd); @@ -403,16 +416,16 @@ int reserve_memtype(u64 start, u64 end, unsigned long req_type, if (new_entry) { /* No conflict. Not yet added to the list. Add to the tail */ list_add_tail(&new_entry->nd, &memtype_list); - pr_debug("New Entry\n"); + dprintk("New Entry\n"); } if (ret_type) { - pr_debug( + dprintk( "reserve_memtype added 0x%Lx-0x%Lx, track %s, req %s, ret %s\n", start, end, cattr_name(actual_type), cattr_name(req_type), cattr_name(*ret_type)); } else { - pr_debug( + dprintk( "reserve_memtype added 0x%Lx-0x%Lx, track %s, req %s\n", start, end, cattr_name(actual_type), cattr_name(req_type)); @@ -453,7 +466,7 @@ int free_memtype(u64 start, u64 end) current->comm, current->pid, start, end); } - pr_debug("free_memtype request 0x%Lx-0x%Lx\n", start, end); + dprintk("free_memtype request 0x%Lx-0x%Lx\n", start, end); return err; } -- cgit v1.2.3 From 46dd98a5c0b907f94742579ab605be1933a37abd Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Wed, 14 May 2008 16:10:39 -0700 Subject: arch/x86/mm/pat.c: use boot_cpu_has() arch/x86/mm/pat.c: In function 'phys_mem_access_prot_allowed': arch/x86/mm/pat.c:526: warning: passing argument 2 of 'constant_test_bit' from incompatible pointer type arch/x86/mm/pat.c:526: warning: passing argument 2 of 'variable_test_bit' from incompatible pointer type arch/x86/mm/pat.c:527: warning: passing argument 2 of 'constant_test_bit' from incompatible pointer type arch/x86/mm/pat.c:527: warning: passing argument 2 of 'variable_test_bit' from incompatible pointer type arch/x86/mm/pat.c:528: warning: passing argument 2 of 'constant_test_bit' from incompatible pointer type arch/x86/mm/pat.c:528: warning: passing argument 2 of 'variable_test_bit' from incompatible pointer type arch/x86/mm/pat.c:529: warning: passing argument 2 of 'constant_test_bit' from incompatible pointer type arch/x86/mm/pat.c:529: warning: passing argument 2 of 'variable_test_bit' from incompatible pointer type Don't open-code test_bit() on a __u32 Cc: Andrea Arcangeli Signed-off-by: Andrew Morton Signed-off-by: Ingo Molnar --- arch/x86/mm/pat.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'arch/x86/mm/pat.c') diff --git a/arch/x86/mm/pat.c b/arch/x86/mm/pat.c index a1cbea0b79b1..e83b770676d5 100644 --- a/arch/x86/mm/pat.c +++ b/arch/x86/mm/pat.c @@ -536,10 +536,10 @@ int phys_mem_access_prot_allowed(struct file *file, unsigned long pfn, * we maintain the tradition of paranoia in this code. */ if (!pat_wc_enabled && - ! ( test_bit(X86_FEATURE_MTRR, boot_cpu_data.x86_capability) || - test_bit(X86_FEATURE_K6_MTRR, boot_cpu_data.x86_capability) || - test_bit(X86_FEATURE_CYRIX_ARR, boot_cpu_data.x86_capability) || - test_bit(X86_FEATURE_CENTAUR_MCR, boot_cpu_data.x86_capability)) && + ! ( boot_cpu_has(X86_FEATURE_MTRR) || + boot_cpu_has(X86_FEATURE_K6_MTRR) || + boot_cpu_has(X86_FEATURE_CYRIX_ARR) || + boot_cpu_has(X86_FEATURE_CENTAUR_MCR)) && (pfn << PAGE_SHIFT) >= __pa(high_memory)) { flags = _PAGE_CACHE_UC; } -- cgit v1.2.3 From c26421d01986e1521043c8feb47256833df3bf31 Mon Sep 17 00:00:00 2001 From: Venki Pallipadi Date: Thu, 29 May 2008 12:01:44 -0700 Subject: x86: fix Xorg crash with xf86MapVidMem error Clarify the usage of mtrr_lookup() in PAT code, and to make PAT code resilient to mtrr lookup problems. Specifically, pat_x_mtrr_type() is restructured to highlight, under what conditions we look for mtrr hint. pat_x_mtrr_type() uses a default type when there are any errors in mtrr lookup (still maintaining the pat consistency). And, reserve_memtype() highlights its usage ot mtrr_lookup for request type of '-1' and also defaults in a sane way on any mtrr lookup failure. pat.c looks at mtrr type of a range to get a hint on what mapping type to request when user/API: (1) hasn't specified any type (/dev/mem mapping) and we do not want to take performance hit by always mapping UC_MINUS. This will be the case for /dev/mem mappings used to map BIOS area or ACPI region which are WB'able. In this case, as long as MTRR is not WB, PAT will request UC_MINUS for such mappings. (2) user/API requests WB mapping while in reality MTRR may have UC or WC. In this case, PAT can map as WB (without checking MTRR) and still effective type will be UC or WC. But, a subsequent request to map same region as UC or WC may fail, as the region will get trackked as WB in PAT list. Looking at MTRR hint helps us to track based on effective type rather than what user requested. Again, here mtrr_lookup is only used as hint and we fallback to WB mapping (as requested by user) as default. In both cases, after using the mtrr hint, we still go through the memtype list to make sure there are no inconsistencies among multiple users. Signed-off-by: Venkatesh Pallipadi Signed-off-by: Suresh Siddha Tested-by: Rufus & Azrael Signed-off-by: Ingo Molnar --- arch/x86/mm/pat.c | 49 ++++++++++++++++++++++++------------------------- 1 file changed, 24 insertions(+), 25 deletions(-) (limited to 'arch/x86/mm/pat.c') diff --git a/arch/x86/mm/pat.c b/arch/x86/mm/pat.c index e83b770676d5..320d644a8107 100644 --- a/arch/x86/mm/pat.c +++ b/arch/x86/mm/pat.c @@ -164,32 +164,33 @@ static int pat_x_mtrr_type(u64 start, u64 end, unsigned long prot, unsigned long pat_type; u8 mtrr_type; - mtrr_type = mtrr_type_lookup(start, end); - if (mtrr_type == 0xFF) { /* MTRR not enabled */ - *ret_prot = prot; - return 0; - } - if (mtrr_type == 0xFE) { /* MTRR match error */ - *ret_prot = _PAGE_CACHE_UC; - return -1; - } - if (mtrr_type != MTRR_TYPE_UNCACHABLE && - mtrr_type != MTRR_TYPE_WRBACK && - mtrr_type != MTRR_TYPE_WRCOMB) { /* MTRR type unhandled */ - *ret_prot = _PAGE_CACHE_UC; - return -1; - } - pat_type = prot & _PAGE_CACHE_MASK; prot &= (~_PAGE_CACHE_MASK); - /* Currently doing intersection by hand. Optimize it later. */ + /* + * We return the PAT request directly for types where PAT takes + * precedence with respect to MTRR and for UC_MINUS. + * Consistency checks with other PAT requests is done later + * while going through memtype list. + */ if (pat_type == _PAGE_CACHE_WC) { *ret_prot = prot | _PAGE_CACHE_WC; + return 0; } else if (pat_type == _PAGE_CACHE_UC_MINUS) { *ret_prot = prot | _PAGE_CACHE_UC_MINUS; - } else if (pat_type == _PAGE_CACHE_UC || - mtrr_type == MTRR_TYPE_UNCACHABLE) { + return 0; + } else if (pat_type == _PAGE_CACHE_UC) { + *ret_prot = prot | _PAGE_CACHE_UC; + return 0; + } + + /* + * Look for MTRR hint to get the effective type in case where PAT + * request is for WB. + */ + mtrr_type = mtrr_type_lookup(start, end); + + if (mtrr_type == MTRR_TYPE_UNCACHABLE) { *ret_prot = prot | _PAGE_CACHE_UC; } else if (mtrr_type == MTRR_TYPE_WRCOMB) { *ret_prot = prot | _PAGE_CACHE_WC; @@ -246,14 +247,12 @@ int reserve_memtype(u64 start, u64 end, unsigned long req_type, if (req_type == -1) { /* - * Special case where caller wants to inherit from mtrr or - * existing pat mapping, defaulting to UC_MINUS in case of - * no match. + * Call mtrr_lookup to get the type hint. This is an + * optimization for /dev/mem mmap'ers into WB memory (BIOS + * tools and ACPI tools). Use WB request for WB memory and use + * UC_MINUS otherwise. */ u8 mtrr_type = mtrr_type_lookup(start, end); - if (mtrr_type == 0xFE) { /* MTRR match error */ - err = -1; - } if (mtrr_type == MTRR_TYPE_WRBACK) { req_type = _PAGE_CACHE_WB; -- cgit v1.2.3 From 97cfab6ac4ddfda0d722393bbf46cc40bc332107 Mon Sep 17 00:00:00 2001 From: Andreas Herrmann Date: Tue, 10 Jun 2008 16:05:18 +0200 Subject: x86: PAT: fix ambiguous paranoia check in pat_init() Starting with commit 8d4a4300854f3971502e81dacd930704cb88f606 (x86: cleanup PAT cpu validation) the PAT CPU feature flag is not cleared anymore. Now the error message "PAT enabled, but CPU feature cleared" in pat_init() is misleading. Furthermore the current code does not check for existence of the PAT CPU feature flag if a CPU is whitelisted in validate_pat_support. This patch clears pat_wc_enabled if boot CPU has no PAT feature flag and adapts the paranoia check. Signed-off-by: Andreas Herrmann Signed-off-by: Ingo Molnar --- arch/x86/kernel/cpu/addon_cpuid_features.c | 7 ++++--- arch/x86/mm/pat.c | 11 ++++++----- 2 files changed, 10 insertions(+), 8 deletions(-) (limited to 'arch/x86/mm/pat.c') diff --git a/arch/x86/kernel/cpu/addon_cpuid_features.c b/arch/x86/kernel/cpu/addon_cpuid_features.c index 0fbd06241e07..2df461f06a52 100644 --- a/arch/x86/kernel/cpu/addon_cpuid_features.c +++ b/arch/x86/kernel/cpu/addon_cpuid_features.c @@ -53,6 +53,9 @@ void __cpuinit init_scattered_cpuid_features(struct cpuinfo_x86 *c) #ifdef CONFIG_X86_PAT void __cpuinit validate_pat_support(struct cpuinfo_x86 *c) { + if (!cpu_has_pat) + pat_disable("PAT not supported by CPU."); + switch (c->x86_vendor) { case X86_VENDOR_INTEL: if (c->x86 == 0xF || (c->x86 == 6 && c->x86_model >= 15)) @@ -64,8 +67,6 @@ void __cpuinit validate_pat_support(struct cpuinfo_x86 *c) return; } - pat_disable(cpu_has_pat ? - "PAT disabled. Not yet verified on this CPU type." : - "PAT not supported by CPU."); + pat_disable("PAT disabled. Not yet verified on this CPU type."); } #endif diff --git a/arch/x86/mm/pat.c b/arch/x86/mm/pat.c index 320d644a8107..65105b1195a3 100644 --- a/arch/x86/mm/pat.c +++ b/arch/x86/mm/pat.c @@ -76,14 +76,15 @@ void pat_init(void) return; /* Paranoia check. */ - if (!cpu_has_pat) { - printk(KERN_ERR "PAT enabled, but CPU feature cleared\n"); + if (!cpu_has_pat && boot_pat_state) { /* - * Panic if this happens on the secondary CPU, and we + * If this happens we are on a secondary CPU, but * switched to PAT on the boot CPU. We have no way to * undo PAT. - */ - BUG_ON(boot_pat_state); + */ + printk(KERN_ERR "PAT enabled, " + "but not supported by secondary CPU\n"); + BUG(); } /* Set PWT to Write-Combining. All other bits stay the same */ -- cgit v1.2.3 From cd7a4e936d345ab4cb49d68192d90bd4e4c58458 Mon Sep 17 00:00:00 2001 From: Andreas Herrmann Date: Tue, 10 Jun 2008 16:05:39 +0200 Subject: x86: PAT: fixed checkpatch errors (and whitespaces) x86: PAT: fixed checkpatch errors (and whitespaces) Signed-off-by: Andreas Herrmann Signed-off-by: Ingo Molnar --- arch/x86/kernel/cpu/addon_cpuid_features.c | 2 -- arch/x86/mm/pat.c | 29 ++++++++++++++--------------- include/asm-x86/pat.h | 6 ++---- 3 files changed, 16 insertions(+), 21 deletions(-) (limited to 'arch/x86/mm/pat.c') diff --git a/arch/x86/kernel/cpu/addon_cpuid_features.c b/arch/x86/kernel/cpu/addon_cpuid_features.c index 2df461f06a52..84a8220a6072 100644 --- a/arch/x86/kernel/cpu/addon_cpuid_features.c +++ b/arch/x86/kernel/cpu/addon_cpuid_features.c @@ -1,9 +1,7 @@ - /* * Routines to indentify additional cpu features that are scattered in * cpuid space. */ - #include #include diff --git a/arch/x86/mm/pat.c b/arch/x86/mm/pat.c index 65105b1195a3..a8b69bb26972 100644 --- a/arch/x86/mm/pat.c +++ b/arch/x86/mm/pat.c @@ -66,7 +66,7 @@ enum { PAT_UC_MINUS = 7, /* UC, but can be overriden by MTRR */ }; -#define PAT(x,y) ((u64)PAT_ ## y << ((x)*8)) +#define PAT(x, y) ((u64)PAT_ ## y << ((x)*8)) void pat_init(void) { @@ -100,8 +100,8 @@ void pat_init(void) * 011 UC _PAGE_CACHE_UC * PAT bit unused */ - pat = PAT(0,WB) | PAT(1,WC) | PAT(2,UC_MINUS) | PAT(3,UC) | - PAT(4,WB) | PAT(5,WC) | PAT(6,UC_MINUS) | PAT(7,UC); + pat = PAT(0, WB) | PAT(1, WC) | PAT(2, UC_MINUS) | PAT(3, UC) | + PAT(4, WB) | PAT(5, WC) | PAT(6, UC_MINUS) | PAT(7, UC); /* Boot CPU check */ if (!boot_pat_state) @@ -117,11 +117,11 @@ void pat_init(void) static char *cattr_name(unsigned long flags) { switch (flags & _PAGE_CACHE_MASK) { - case _PAGE_CACHE_UC: return "uncached"; - case _PAGE_CACHE_UC_MINUS: return "uncached-minus"; - case _PAGE_CACHE_WB: return "write-back"; - case _PAGE_CACHE_WC: return "write-combining"; - default: return "broken"; + case _PAGE_CACHE_UC: return "uncached"; + case _PAGE_CACHE_UC_MINUS: return "uncached-minus"; + case _PAGE_CACHE_WB: return "write-back"; + case _PAGE_CACHE_WC: return "write-combining"; + default: return "broken"; } } @@ -536,11 +536,11 @@ int phys_mem_access_prot_allowed(struct file *file, unsigned long pfn, * we maintain the tradition of paranoia in this code. */ if (!pat_wc_enabled && - ! ( boot_cpu_has(X86_FEATURE_MTRR) || - boot_cpu_has(X86_FEATURE_K6_MTRR) || - boot_cpu_has(X86_FEATURE_CYRIX_ARR) || - boot_cpu_has(X86_FEATURE_CENTAUR_MCR)) && - (pfn << PAGE_SHIFT) >= __pa(high_memory)) { + !(boot_cpu_has(X86_FEATURE_MTRR) || + boot_cpu_has(X86_FEATURE_K6_MTRR) || + boot_cpu_has(X86_FEATURE_CYRIX_ARR) || + boot_cpu_has(X86_FEATURE_CENTAUR_MCR)) && + (pfn << PAGE_SHIFT) >= __pa(high_memory)) { flags = _PAGE_CACHE_UC; } #endif @@ -562,7 +562,7 @@ int phys_mem_access_prot_allowed(struct file *file, unsigned long pfn, return 0; if (pfn <= max_pfn_mapped && - ioremap_change_attr((unsigned long)__va(offset), size, flags) < 0) { + ioremap_change_attr((unsigned long)__va(offset), size, flags) < 0) { free_memtype(offset, offset + size); printk(KERN_INFO "%s:%d /dev/mem ioremap_change_attr failed %s for %Lx-%Lx\n", @@ -600,4 +600,3 @@ void unmap_devmem(unsigned long pfn, unsigned long size, pgprot_t vma_prot) free_memtype(addr, addr + size); } - diff --git a/include/asm-x86/pat.h b/include/asm-x86/pat.h index 88f60cc6a227..6fa9710ae09a 100644 --- a/include/asm-x86/pat.h +++ b/include/asm-x86/pat.h @@ -1,6 +1,5 @@ - #ifndef _ASM_PAT_H -#define _ASM_PAT_H 1 +#define _ASM_PAT_H #include @@ -8,7 +7,7 @@ extern int pat_wc_enabled; extern void validate_pat_support(struct cpuinfo_x86 *c); #else -static const int pat_wc_enabled = 0; +static const int pat_wc_enabled; static inline void validate_pat_support(struct cpuinfo_x86 *c) { } #endif @@ -21,4 +20,3 @@ extern int free_memtype(u64 start, u64 end); extern void pat_disable(char *reason); #endif - -- cgit v1.2.3 From 499f8f84b8324ba27d756e03f373fa16eeed9ccc Mon Sep 17 00:00:00 2001 From: Andreas Herrmann Date: Tue, 10 Jun 2008 16:06:21 +0200 Subject: x86: rename pat_wc_enabled to pat_enabled BTW, what does pat_wc_enabled stand for? Does it mean "write-combining"? Currently it is used to globally switch on or off PAT support. Thus I renamed it to pat_enabled. I think this increases readability (and hope that I didn't miss something). Signed-off-by: Andreas Herrmann Signed-off-by: Ingo Molnar --- arch/x86/mm/ioremap.c | 4 ++-- arch/x86/mm/pageattr.c | 2 +- arch/x86/mm/pat.c | 16 ++++++++-------- arch/x86/pci/i386.c | 4 ++-- include/asm-x86/pat.h | 4 ++-- 5 files changed, 15 insertions(+), 15 deletions(-) (limited to 'arch/x86/mm/pat.c') diff --git a/arch/x86/mm/ioremap.c b/arch/x86/mm/ioremap.c index 71bb3159031a..ddeafed1171e 100644 --- a/arch/x86/mm/ioremap.c +++ b/arch/x86/mm/ioremap.c @@ -261,7 +261,7 @@ void __iomem *ioremap_nocache(resource_size_t phys_addr, unsigned long size) { /* * Ideally, this should be: - * pat_wc_enabled ? _PAGE_CACHE_UC : _PAGE_CACHE_UC_MINUS; + * pat_enabled ? _PAGE_CACHE_UC : _PAGE_CACHE_UC_MINUS; * * Till we fix all X drivers to use ioremap_wc(), we will use * UC MINUS. @@ -285,7 +285,7 @@ EXPORT_SYMBOL(ioremap_nocache); */ void __iomem *ioremap_wc(unsigned long phys_addr, unsigned long size) { - if (pat_wc_enabled) + if (pat_enabled) return __ioremap_caller(phys_addr, size, _PAGE_CACHE_WC, __builtin_return_address(0)); else diff --git a/arch/x86/mm/pageattr.c b/arch/x86/mm/pageattr.c index 60bcb5b6a37e..6916fe4bf0cb 100644 --- a/arch/x86/mm/pageattr.c +++ b/arch/x86/mm/pageattr.c @@ -805,7 +805,7 @@ int _set_memory_wc(unsigned long addr, int numpages) int set_memory_wc(unsigned long addr, int numpages) { - if (!pat_wc_enabled) + if (!pat_enabled) return set_memory_uc(addr, numpages); if (reserve_memtype(addr, addr + numpages * PAGE_SIZE, diff --git a/arch/x86/mm/pat.c b/arch/x86/mm/pat.c index a8b69bb26972..4beccea0897f 100644 --- a/arch/x86/mm/pat.c +++ b/arch/x86/mm/pat.c @@ -26,11 +26,11 @@ #include #ifdef CONFIG_X86_PAT -int __read_mostly pat_wc_enabled = 1; +int __read_mostly pat_enabled = 1; void __cpuinit pat_disable(char *reason) { - pat_wc_enabled = 0; + pat_enabled = 0; printk(KERN_INFO "%s\n", reason); } @@ -72,7 +72,7 @@ void pat_init(void) { u64 pat; - if (!pat_wc_enabled) + if (!pat_enabled) return; /* Paranoia check. */ @@ -225,8 +225,8 @@ int reserve_memtype(u64 start, u64 end, unsigned long req_type, unsigned long actual_type; int err = 0; - /* Only track when pat_wc_enabled */ - if (!pat_wc_enabled) { + /* Only track when pat_enabled */ + if (!pat_enabled) { /* This is identical to page table setting without PAT */ if (ret_type) { if (req_type == -1) { @@ -440,8 +440,8 @@ int free_memtype(u64 start, u64 end) struct memtype *ml; int err = -EINVAL; - /* Only track when pat_wc_enabled */ - if (!pat_wc_enabled) { + /* Only track when pat_enabled */ + if (!pat_enabled) { return 0; } @@ -535,7 +535,7 @@ int phys_mem_access_prot_allowed(struct file *file, unsigned long pfn, * caching for the high addresses through the KEN pin, but * we maintain the tradition of paranoia in this code. */ - if (!pat_wc_enabled && + if (!pat_enabled && !(boot_cpu_has(X86_FEATURE_MTRR) || boot_cpu_has(X86_FEATURE_K6_MTRR) || boot_cpu_has(X86_FEATURE_CYRIX_ARR) || diff --git a/arch/x86/pci/i386.c b/arch/x86/pci/i386.c index 10fb308fded8..6ccd7a108cd4 100644 --- a/arch/x86/pci/i386.c +++ b/arch/x86/pci/i386.c @@ -299,9 +299,9 @@ int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma, return -EINVAL; prot = pgprot_val(vma->vm_page_prot); - if (pat_wc_enabled && write_combine) + if (pat_enabled && write_combine) prot |= _PAGE_CACHE_WC; - else if (pat_wc_enabled || boot_cpu_data.x86 > 3) + else if (pat_enabled || boot_cpu_data.x86 > 3) /* * ioremap() and ioremap_nocache() defaults to UC MINUS for now. * To avoid attribute conflicts, request UC MINUS here diff --git a/include/asm-x86/pat.h b/include/asm-x86/pat.h index 6fa9710ae09a..7edc47307217 100644 --- a/include/asm-x86/pat.h +++ b/include/asm-x86/pat.h @@ -4,10 +4,10 @@ #include #ifdef CONFIG_X86_PAT -extern int pat_wc_enabled; +extern int pat_enabled; extern void validate_pat_support(struct cpuinfo_x86 *c); #else -static const int pat_wc_enabled; +static const int pat_enabled; static inline void validate_pat_support(struct cpuinfo_x86 *c) { } #endif -- cgit v1.2.3 From 6cf514fce18589ea1e0521c5f2d7c2bb280fefc7 Mon Sep 17 00:00:00 2001 From: Hugh Dickins Date: Mon, 16 Jun 2008 18:42:43 +0100 Subject: x86: PAT: make pat_x_mtrr_type() more readable Clean up over-complications in pat_x_mtrr_type(). And if reserve_memtype() ignores stray req_type bits when pat_enabled, it's better to mask them off when not also. Signed-off-by: Hugh Dickins Signed-off-by: Ingo Molnar --- arch/x86/mm/pat.c | 47 ++++++++++++----------------------------------- 1 file changed, 12 insertions(+), 35 deletions(-) (limited to 'arch/x86/mm/pat.c') diff --git a/arch/x86/mm/pat.c b/arch/x86/mm/pat.c index 7c21572bbdda..ac3a2b11eb38 100644 --- a/arch/x86/mm/pat.c +++ b/arch/x86/mm/pat.c @@ -159,47 +159,31 @@ static DEFINE_SPINLOCK(memtype_lock); /* protects memtype list */ * The intersection is based on "Effective Memory Type" tables in IA-32 * SDM vol 3a */ -static int pat_x_mtrr_type(u64 start, u64 end, unsigned long prot, - unsigned long *ret_prot) +static unsigned long pat_x_mtrr_type(u64 start, u64 end, unsigned long req_type) { - unsigned long pat_type; u8 mtrr_type; - pat_type = prot & _PAGE_CACHE_MASK; - prot &= (~_PAGE_CACHE_MASK); - /* * We return the PAT request directly for types where PAT takes * precedence with respect to MTRR and for UC_MINUS. * Consistency checks with other PAT requests is done later * while going through memtype list. */ - if (pat_type == _PAGE_CACHE_WC) { - *ret_prot = prot | _PAGE_CACHE_WC; - return 0; - } else if (pat_type == _PAGE_CACHE_UC_MINUS) { - *ret_prot = prot | _PAGE_CACHE_UC_MINUS; - return 0; - } else if (pat_type == _PAGE_CACHE_UC) { - *ret_prot = prot | _PAGE_CACHE_UC; - return 0; - } + if (req_type == _PAGE_CACHE_WC || + req_type == _PAGE_CACHE_UC_MINUS || + req_type == _PAGE_CACHE_UC) + return req_type; /* * Look for MTRR hint to get the effective type in case where PAT * request is for WB. */ mtrr_type = mtrr_type_lookup(start, end); - - if (mtrr_type == MTRR_TYPE_UNCACHABLE) { - *ret_prot = prot | _PAGE_CACHE_UC; - } else if (mtrr_type == MTRR_TYPE_WRCOMB) { - *ret_prot = prot | _PAGE_CACHE_WC; - } else { - *ret_prot = prot | _PAGE_CACHE_WB; - } - - return 0; + if (mtrr_type == MTRR_TYPE_UNCACHABLE) + return _PAGE_CACHE_UC; + if (mtrr_type == MTRR_TYPE_WRCOMB) + return _PAGE_CACHE_WC; + return _PAGE_CACHE_WB; } /* @@ -232,7 +216,7 @@ int reserve_memtype(u64 start, u64 end, unsigned long req_type, if (req_type == -1) { *ret_type = _PAGE_CACHE_WB; } else { - *ret_type = req_type; + *ret_type = req_type & _PAGE_CACHE_MASK; } } return 0; @@ -264,14 +248,7 @@ int reserve_memtype(u64 start, u64 end, unsigned long req_type, } } else { req_type &= _PAGE_CACHE_MASK; - err = pat_x_mtrr_type(start, end, req_type, &actual_type); - } - - if (err) { - if (ret_type) - *ret_type = actual_type; - - return -EINVAL; + actual_type = pat_x_mtrr_type(start, end, req_type); } new_entry = kmalloc(sizeof(struct memtype), GFP_KERNEL); -- cgit v1.2.3 From dd0c7c4903c29da9aa3bf33deecf064d190a0d81 Mon Sep 17 00:00:00 2001 From: Andreas Herrmann Date: Wed, 18 Jun 2008 15:38:57 +0200 Subject: x86: shrink pat_x_mtrr_type to its essentials Signed-off-by: Andreas Herrmann Cc: Venkatesh Pallipadi Cc: Suresh B Siddha Cc: Hugh Dickins Signed-off-by: Ingo Molnar --- arch/x86/mm/pat.c | 30 +++++++++++------------------- 1 file changed, 11 insertions(+), 19 deletions(-) (limited to 'arch/x86/mm/pat.c') diff --git a/arch/x86/mm/pat.c b/arch/x86/mm/pat.c index ac3a2b11eb38..227df3ca9bfd 100644 --- a/arch/x86/mm/pat.c +++ b/arch/x86/mm/pat.c @@ -161,29 +161,21 @@ static DEFINE_SPINLOCK(memtype_lock); /* protects memtype list */ */ static unsigned long pat_x_mtrr_type(u64 start, u64 end, unsigned long req_type) { - u8 mtrr_type; - - /* - * We return the PAT request directly for types where PAT takes - * precedence with respect to MTRR and for UC_MINUS. - * Consistency checks with other PAT requests is done later - * while going through memtype list. - */ - if (req_type == _PAGE_CACHE_WC || - req_type == _PAGE_CACHE_UC_MINUS || - req_type == _PAGE_CACHE_UC) - return req_type; - /* * Look for MTRR hint to get the effective type in case where PAT * request is for WB. */ - mtrr_type = mtrr_type_lookup(start, end); - if (mtrr_type == MTRR_TYPE_UNCACHABLE) - return _PAGE_CACHE_UC; - if (mtrr_type == MTRR_TYPE_WRCOMB) - return _PAGE_CACHE_WC; - return _PAGE_CACHE_WB; + if (req_type == _PAGE_CACHE_WB) { + u8 mtrr_type; + + mtrr_type = mtrr_type_lookup(start, end); + if (mtrr_type == MTRR_TYPE_UNCACHABLE) + return _PAGE_CACHE_UC; + if (mtrr_type == MTRR_TYPE_WRCOMB) + return _PAGE_CACHE_WC; + } + + return req_type; } /* -- cgit v1.2.3 From bcc643dc287cb732e96a1685ac130c3ae8b1c960 Mon Sep 17 00:00:00 2001 From: Andreas Herrmann Date: Fri, 20 Jun 2008 21:58:46 +0200 Subject: x86: introduce macro to check whether an address range is in the ISA range Signed-off-by: Andreas Herrmann Cc: Venkatesh Pallipadi Cc: Suresh B Siddha Signed-off-by: Ingo Molnar --- arch/x86/mm/ioremap.c | 2 +- arch/x86/mm/pat.c | 5 ++--- include/asm-x86/e820.h | 1 + 3 files changed, 4 insertions(+), 4 deletions(-) (limited to 'arch/x86/mm/pat.c') diff --git a/arch/x86/mm/ioremap.c b/arch/x86/mm/ioremap.c index 7452eb31ed12..6d9960dd6f35 100644 --- a/arch/x86/mm/ioremap.c +++ b/arch/x86/mm/ioremap.c @@ -142,7 +142,7 @@ static void __iomem *__ioremap_caller(resource_size_t phys_addr, /* * Don't remap the low PCI/ISA area, it's always mapped.. */ - if (phys_addr >= ISA_START_ADDRESS && last_addr < ISA_END_ADDRESS) + if (is_ISA_range(phys_addr, last_addr)) return (__force void __iomem *)phys_to_virt(phys_addr); /* diff --git a/arch/x86/mm/pat.c b/arch/x86/mm/pat.c index 227df3ca9bfd..5bbc22efe4e5 100644 --- a/arch/x86/mm/pat.c +++ b/arch/x86/mm/pat.c @@ -215,7 +215,7 @@ int reserve_memtype(u64 start, u64 end, unsigned long req_type, } /* Low ISA region is always mapped WB in page table. No need to track */ - if (start >= ISA_START_ADDRESS && (end - 1) <= ISA_END_ADDRESS) { + if (is_ISA_range(start, end - 1)) { if (ret_type) *ret_type = _PAGE_CACHE_WB; @@ -415,9 +415,8 @@ int free_memtype(u64 start, u64 end) } /* Low ISA region is always mapped WB. No need to track */ - if (start >= ISA_START_ADDRESS && end <= ISA_END_ADDRESS) { + if (is_ISA_range(start, end - 1)) return 0; - } spin_lock(&memtype_lock); list_for_each_entry(ml, &memtype_list, nd) { diff --git a/include/asm-x86/e820.h b/include/asm-x86/e820.h index 7004251fc66b..5103d0b2c46c 100644 --- a/include/asm-x86/e820.h +++ b/include/asm-x86/e820.h @@ -24,6 +24,7 @@ struct e820map { #define ISA_START_ADDRESS 0xa0000 #define ISA_END_ADDRESS 0x100000 +#define is_ISA_range(s, e) ((s) >= ISA_START_ADDRESS && (e) < ISA_END_ADDRESS) #define BIOS_BEGIN 0x000a0000 #define BIOS_END 0x00100000 -- cgit v1.2.3 From ac97991ec9e0a05c8860f4a04f8477227b1c03f2 Mon Sep 17 00:00:00 2001 From: Andreas Herrmann Date: Fri, 20 Jun 2008 22:01:49 +0200 Subject: x86: pat.c choose more crisp variable names - parse/ml => entry (within list_for_each and friends) - new_entry => new - ret_type => new_type (to avoid confusion with req_type) (... to make it more readable...) Signed-off-by: Andreas Herrmann Cc: Venkatesh Pallipadi Cc: Suresh B Siddha Signed-off-by: Ingo Molnar --- arch/x86/mm/pat.c | 127 ++++++++++++++++++++++++++---------------------------- 1 file changed, 62 insertions(+), 65 deletions(-) (limited to 'arch/x86/mm/pat.c') diff --git a/arch/x86/mm/pat.c b/arch/x86/mm/pat.c index 5bbc22efe4e5..a6507bfb12a7 100644 --- a/arch/x86/mm/pat.c +++ b/arch/x86/mm/pat.c @@ -188,37 +188,34 @@ static unsigned long pat_x_mtrr_type(u64 start, u64 end, unsigned long req_type) * req_type will have a special case value '-1', when requester want to inherit * the memory type from mtrr (if WB), existing PAT, defaulting to UC_MINUS. * - * If ret_type is NULL, function will return an error if it cannot reserve the - * region with req_type. If ret_type is non-null, function will return - * available type in ret_type in case of no error. In case of any error + * If new_type is NULL, function will return an error if it cannot reserve the + * region with req_type. If new_type is non-NULL, function will return + * available type in new_type in case of no error. In case of any error * it will return a negative return value. */ int reserve_memtype(u64 start, u64 end, unsigned long req_type, - unsigned long *ret_type) + unsigned long *new_type) { - struct memtype *new_entry = NULL; - struct memtype *parse; + struct memtype *new, *entry; unsigned long actual_type; int err = 0; /* Only track when pat_enabled */ if (!pat_enabled) { /* This is identical to page table setting without PAT */ - if (ret_type) { - if (req_type == -1) { - *ret_type = _PAGE_CACHE_WB; - } else { - *ret_type = req_type & _PAGE_CACHE_MASK; - } + if (new_type) { + if (req_type == -1) + *new_type = _PAGE_CACHE_WB; + else + *new_type = req_type & _PAGE_CACHE_MASK; } return 0; } /* Low ISA region is always mapped WB in page table. No need to track */ if (is_ISA_range(start, end - 1)) { - if (ret_type) - *ret_type = _PAGE_CACHE_WB; - + if (new_type) + *new_type = _PAGE_CACHE_WB; return 0; } @@ -243,65 +240,65 @@ int reserve_memtype(u64 start, u64 end, unsigned long req_type, actual_type = pat_x_mtrr_type(start, end, req_type); } - new_entry = kmalloc(sizeof(struct memtype), GFP_KERNEL); - if (!new_entry) + new = kmalloc(sizeof(struct memtype), GFP_KERNEL); + if (!new) return -ENOMEM; - new_entry->start = start; - new_entry->end = end; - new_entry->type = actual_type; + new->start = start; + new->end = end; + new->type = actual_type; - if (ret_type) - *ret_type = actual_type; + if (new_type) + *new_type = actual_type; spin_lock(&memtype_lock); /* Search for existing mapping that overlaps the current range */ - list_for_each_entry(parse, &memtype_list, nd) { + list_for_each_entry(entry, &memtype_list, nd) { struct memtype *saved_ptr; - if (parse->start >= end) { + if (entry->start >= end) { dprintk("New Entry\n"); - list_add(&new_entry->nd, parse->nd.prev); - new_entry = NULL; + list_add(&new->nd, entry->nd.prev); + new = NULL; break; } - if (start <= parse->start && end >= parse->start) { - if (actual_type != parse->type && ret_type) { - actual_type = parse->type; - *ret_type = actual_type; - new_entry->type = actual_type; + if (start <= entry->start && end >= entry->start) { + if (actual_type != entry->type && new_type) { + actual_type = entry->type; + *new_type = actual_type; + new->type = actual_type; } - if (actual_type != parse->type) { + if (actual_type != entry->type) { printk( KERN_INFO "%s:%d conflicting memory types %Lx-%Lx %s<->%s\n", current->comm, current->pid, start, end, cattr_name(actual_type), - cattr_name(parse->type)); + cattr_name(entry->type)); err = -EBUSY; break; } - saved_ptr = parse; + saved_ptr = entry; /* * Check to see whether the request overlaps more * than one entry in the list */ - list_for_each_entry_continue(parse, &memtype_list, nd) { - if (end <= parse->start) { + list_for_each_entry_continue(entry, &memtype_list, nd) { + if (end <= entry->start) { break; } - if (actual_type != parse->type) { + if (actual_type != entry->type) { printk( KERN_INFO "%s:%d conflicting memory types %Lx-%Lx %s<->%s\n", current->comm, current->pid, start, end, cattr_name(actual_type), - cattr_name(parse->type)); + cattr_name(entry->type)); err = -EBUSY; break; } @@ -314,46 +311,46 @@ int reserve_memtype(u64 start, u64 end, unsigned long req_type, dprintk("Overlap at 0x%Lx-0x%Lx\n", saved_ptr->start, saved_ptr->end); /* No conflict. Go ahead and add this new entry */ - list_add(&new_entry->nd, saved_ptr->nd.prev); - new_entry = NULL; + list_add(&new->nd, saved_ptr->nd.prev); + new = NULL; break; } - if (start < parse->end) { - if (actual_type != parse->type && ret_type) { - actual_type = parse->type; - *ret_type = actual_type; - new_entry->type = actual_type; + if (start < entry->end) { + if (actual_type != entry->type && new_type) { + actual_type = entry->type; + *new_type = actual_type; + new->type = actual_type; } - if (actual_type != parse->type) { + if (actual_type != entry->type) { printk( KERN_INFO "%s:%d conflicting memory types %Lx-%Lx %s<->%s\n", current->comm, current->pid, start, end, cattr_name(actual_type), - cattr_name(parse->type)); + cattr_name(entry->type)); err = -EBUSY; break; } - saved_ptr = parse; + saved_ptr = entry; /* * Check to see whether the request overlaps more * than one entry in the list */ - list_for_each_entry_continue(parse, &memtype_list, nd) { - if (end <= parse->start) { + list_for_each_entry_continue(entry, &memtype_list, nd) { + if (end <= entry->start) { break; } - if (actual_type != parse->type) { + if (actual_type != entry->type) { printk( KERN_INFO "%s:%d conflicting memory types %Lx-%Lx %s<->%s\n", current->comm, current->pid, start, end, cattr_name(actual_type), - cattr_name(parse->type)); + cattr_name(entry->type)); err = -EBUSY; break; } @@ -366,8 +363,8 @@ int reserve_memtype(u64 start, u64 end, unsigned long req_type, dprintk("Overlap at 0x%Lx-0x%Lx\n", saved_ptr->start, saved_ptr->end); /* No conflict. Go ahead and add this new entry */ - list_add(&new_entry->nd, &saved_ptr->nd); - new_entry = NULL; + list_add(&new->nd, &saved_ptr->nd); + new = NULL; break; } } @@ -375,24 +372,24 @@ int reserve_memtype(u64 start, u64 end, unsigned long req_type, if (err) { printk(KERN_INFO "reserve_memtype failed 0x%Lx-0x%Lx, track %s, req %s\n", - start, end, cattr_name(new_entry->type), + start, end, cattr_name(new->type), cattr_name(req_type)); - kfree(new_entry); + kfree(new); spin_unlock(&memtype_lock); return err; } - if (new_entry) { + if (new) { /* No conflict. Not yet added to the list. Add to the tail */ - list_add_tail(&new_entry->nd, &memtype_list); + list_add_tail(&new->nd, &memtype_list); dprintk("New Entry\n"); } - if (ret_type) { + if (new_type) { dprintk( "reserve_memtype added 0x%Lx-0x%Lx, track %s, req %s, ret %s\n", start, end, cattr_name(actual_type), - cattr_name(req_type), cattr_name(*ret_type)); + cattr_name(req_type), cattr_name(*new_type)); } else { dprintk( "reserve_memtype added 0x%Lx-0x%Lx, track %s, req %s\n", @@ -406,7 +403,7 @@ int reserve_memtype(u64 start, u64 end, unsigned long req_type, int free_memtype(u64 start, u64 end) { - struct memtype *ml; + struct memtype *entry; int err = -EINVAL; /* Only track when pat_enabled */ @@ -419,10 +416,10 @@ int free_memtype(u64 start, u64 end) return 0; spin_lock(&memtype_lock); - list_for_each_entry(ml, &memtype_list, nd) { - if (ml->start == start && ml->end == end) { - list_del(&ml->nd); - kfree(ml); + list_for_each_entry(entry, &memtype_list, nd) { + if (entry->start == start && entry->end == end) { + list_del(&entry->nd); + kfree(entry); err = 0; break; } -- cgit v1.2.3 From 69e26be9b1d0c83d3581475095ce2a1ccc578215 Mon Sep 17 00:00:00 2001 From: Andreas Herrmann Date: Fri, 20 Jun 2008 22:03:06 +0200 Subject: x86: pat.c more trivial changes - add BUG statement to catch invalid start and end parameters - No need to track the actual type in both req_type and actual_type -- keep req_type unchanged. - removed (IMHO) superfluous comments Signed-off-by: Andreas Herrmann Cc: Venkatesh Pallipadi Cc: Suresh B Siddha Signed-off-by: Ingo Molnar --- arch/x86/mm/pat.c | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) (limited to 'arch/x86/mm/pat.c') diff --git a/arch/x86/mm/pat.c b/arch/x86/mm/pat.c index a6507bfb12a7..c996a3641200 100644 --- a/arch/x86/mm/pat.c +++ b/arch/x86/mm/pat.c @@ -200,7 +200,8 @@ int reserve_memtype(u64 start, u64 end, unsigned long req_type, unsigned long actual_type; int err = 0; - /* Only track when pat_enabled */ + BUG_ON(start >= end); /* end is exclusive */ + if (!pat_enabled) { /* This is identical to page table setting without PAT */ if (new_type) { @@ -228,17 +229,13 @@ int reserve_memtype(u64 start, u64 end, unsigned long req_type, */ u8 mtrr_type = mtrr_type_lookup(start, end); - if (mtrr_type == MTRR_TYPE_WRBACK) { - req_type = _PAGE_CACHE_WB; + if (mtrr_type == MTRR_TYPE_WRBACK) actual_type = _PAGE_CACHE_WB; - } else { - req_type = _PAGE_CACHE_UC_MINUS; + else actual_type = _PAGE_CACHE_UC_MINUS; - } - } else { - req_type &= _PAGE_CACHE_MASK; - actual_type = pat_x_mtrr_type(start, end, req_type); - } + } else + actual_type = pat_x_mtrr_type(start, end, + req_type & _PAGE_CACHE_MASK); new = kmalloc(sizeof(struct memtype), GFP_KERNEL); if (!new) @@ -406,10 +403,8 @@ int free_memtype(u64 start, u64 end) struct memtype *entry; int err = -EINVAL; - /* Only track when pat_enabled */ - if (!pat_enabled) { + if (!pat_enabled) return 0; - } /* Low ISA region is always mapped WB. No need to track */ if (is_ISA_range(start, end - 1)) -- cgit v1.2.3 From 3e9c83b309fd7cbf1d9b801d0d5877c040e30420 Mon Sep 17 00:00:00 2001 From: Andreas Herrmann Date: Fri, 20 Jun 2008 22:04:02 +0200 Subject: x86: pat.c consolidate error/debug messages in reserve_memtype ... and move last debug message out of locked section. Signed-off-by: Andreas Herrmann Cc: Venkatesh Pallipadi Cc: Suresh B Siddha Signed-off-by: Ingo Molnar --- arch/x86/mm/pat.c | 51 +++++++++++---------------------------------------- 1 file changed, 11 insertions(+), 40 deletions(-) (limited to 'arch/x86/mm/pat.c') diff --git a/arch/x86/mm/pat.c b/arch/x86/mm/pat.c index c996a3641200..1118288f8fe2 100644 --- a/arch/x86/mm/pat.c +++ b/arch/x86/mm/pat.c @@ -269,12 +269,6 @@ int reserve_memtype(u64 start, u64 end, unsigned long req_type, } if (actual_type != entry->type) { - printk( - KERN_INFO "%s:%d conflicting memory types %Lx-%Lx %s<->%s\n", - current->comm, current->pid, - start, end, - cattr_name(actual_type), - cattr_name(entry->type)); err = -EBUSY; break; } @@ -290,12 +284,6 @@ int reserve_memtype(u64 start, u64 end, unsigned long req_type, } if (actual_type != entry->type) { - printk( - KERN_INFO "%s:%d conflicting memory types %Lx-%Lx %s<->%s\n", - current->comm, current->pid, - start, end, - cattr_name(actual_type), - cattr_name(entry->type)); err = -EBUSY; break; } @@ -321,12 +309,6 @@ int reserve_memtype(u64 start, u64 end, unsigned long req_type, } if (actual_type != entry->type) { - printk( - KERN_INFO "%s:%d conflicting memory types %Lx-%Lx %s<->%s\n", - current->comm, current->pid, - start, end, - cattr_name(actual_type), - cattr_name(entry->type)); err = -EBUSY; break; } @@ -342,12 +324,6 @@ int reserve_memtype(u64 start, u64 end, unsigned long req_type, } if (actual_type != entry->type) { - printk( - KERN_INFO "%s:%d conflicting memory types %Lx-%Lx %s<->%s\n", - current->comm, current->pid, - start, end, - cattr_name(actual_type), - cattr_name(entry->type)); err = -EBUSY; break; } @@ -367,10 +343,12 @@ int reserve_memtype(u64 start, u64 end, unsigned long req_type, } if (err) { - printk(KERN_INFO - "reserve_memtype failed 0x%Lx-0x%Lx, track %s, req %s\n", - start, end, cattr_name(new->type), - cattr_name(req_type)); + printk(KERN_INFO "%s:%d conflicting memory types " + "%Lx-%Lx %s<->%s\n", current->comm, current->pid, start, + end, cattr_name(new->type), cattr_name(entry->type)); + printk(KERN_INFO "reserve_memtype failed 0x%Lx-0x%Lx, " + "track %s, req %s\n", + start, end, cattr_name(new->type), cattr_name(req_type)); kfree(new); spin_unlock(&memtype_lock); return err; @@ -382,19 +360,12 @@ int reserve_memtype(u64 start, u64 end, unsigned long req_type, dprintk("New Entry\n"); } - if (new_type) { - dprintk( - "reserve_memtype added 0x%Lx-0x%Lx, track %s, req %s, ret %s\n", - start, end, cattr_name(actual_type), - cattr_name(req_type), cattr_name(*new_type)); - } else { - dprintk( - "reserve_memtype added 0x%Lx-0x%Lx, track %s, req %s\n", - start, end, cattr_name(actual_type), - cattr_name(req_type)); - } - spin_unlock(&memtype_lock); + + dprintk("reserve_memtype added 0x%Lx-0x%Lx, track %s, req %s, ret %s\n", + start, end, cattr_name(new->type), cattr_name(req_type), + new_type ? cattr_name(*new_type) : "-"); + return err; } -- cgit v1.2.3 From f6887264deba4cd991f0ca006918dcff4c939021 Mon Sep 17 00:00:00 2001 From: Andreas Herrmann Date: Fri, 20 Jun 2008 22:05:37 +0200 Subject: x86: pat.c consolidate list_add handling in reserve_memtype Signed-off-by: Andreas Herrmann Cc: Venkatesh Pallipadi Cc: Suresh B Siddha Signed-off-by: Ingo Molnar --- arch/x86/mm/pat.c | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) (limited to 'arch/x86/mm/pat.c') diff --git a/arch/x86/mm/pat.c b/arch/x86/mm/pat.c index 1118288f8fe2..49dcd9652ec8 100644 --- a/arch/x86/mm/pat.c +++ b/arch/x86/mm/pat.c @@ -198,6 +198,7 @@ int reserve_memtype(u64 start, u64 end, unsigned long req_type, { struct memtype *new, *entry; unsigned long actual_type; + struct list_head *where; int err = 0; BUG_ON(start >= end); /* end is exclusive */ @@ -251,13 +252,12 @@ int reserve_memtype(u64 start, u64 end, unsigned long req_type, spin_lock(&memtype_lock); /* Search for existing mapping that overlaps the current range */ + where = NULL; list_for_each_entry(entry, &memtype_list, nd) { struct memtype *saved_ptr; if (entry->start >= end) { - dprintk("New Entry\n"); - list_add(&new->nd, entry->nd.prev); - new = NULL; + where = entry->nd.prev; break; } @@ -295,9 +295,7 @@ int reserve_memtype(u64 start, u64 end, unsigned long req_type, dprintk("Overlap at 0x%Lx-0x%Lx\n", saved_ptr->start, saved_ptr->end); - /* No conflict. Go ahead and add this new entry */ - list_add(&new->nd, saved_ptr->nd.prev); - new = NULL; + where = saved_ptr->nd.prev; break; } @@ -335,9 +333,7 @@ int reserve_memtype(u64 start, u64 end, unsigned long req_type, dprintk("Overlap at 0x%Lx-0x%Lx\n", saved_ptr->start, saved_ptr->end); - /* No conflict. Go ahead and add this new entry */ - list_add(&new->nd, &saved_ptr->nd); - new = NULL; + where = &saved_ptr->nd; break; } } @@ -354,11 +350,10 @@ int reserve_memtype(u64 start, u64 end, unsigned long req_type, return err; } - if (new) { - /* No conflict. Not yet added to the list. Add to the tail */ + if (where) + list_add(&new->nd, where); + else list_add_tail(&new->nd, &memtype_list); - dprintk("New Entry\n"); - } spin_unlock(&memtype_lock); -- cgit v1.2.3 From 64fe44c38bbdfab4fe052029058ce5fe9804de68 Mon Sep 17 00:00:00 2001 From: Andreas Herrmann Date: Fri, 20 Jun 2008 22:07:09 +0200 Subject: x86: pat.c introduce function to check for conflicts with existing memtypes ... to strip down loop body in reserve_memtype. Signed-off-by: Andreas Herrmann Cc: Venkatesh Pallipadi Cc: Suresh B Siddha Signed-off-by: Ingo Molnar --- arch/x86/mm/pat.c | 96 +++++++++++++++++++------------------------------------ 1 file changed, 33 insertions(+), 63 deletions(-) (limited to 'arch/x86/mm/pat.c') diff --git a/arch/x86/mm/pat.c b/arch/x86/mm/pat.c index 49dcd9652ec8..281ac6489c08 100644 --- a/arch/x86/mm/pat.c +++ b/arch/x86/mm/pat.c @@ -178,6 +178,33 @@ static unsigned long pat_x_mtrr_type(u64 start, u64 end, unsigned long req_type) return req_type; } +static int chk_conflict(struct memtype *new, struct memtype *entry, + unsigned long *type) +{ + if (new->type != entry->type) { + if (type) { + new->type = entry->type; + *type = entry->type; + } else + goto conflict; + } + + /* check overlaps with more than one entry in the list */ + list_for_each_entry_continue(entry, &memtype_list, nd) { + if (new->end <= entry->start) + break; + else if (new->type != entry->type) + goto conflict; + } + return 0; + + conflict: + printk(KERN_INFO "%s:%d conflicting memory types " + "%Lx-%Lx %s<->%s\n", current->comm, current->pid, new->start, + new->end, cattr_name(new->type), cattr_name(entry->type)); + return -EBUSY; +} + /* * req_type typically has one of the: * - _PAGE_CACHE_WB @@ -254,94 +281,37 @@ int reserve_memtype(u64 start, u64 end, unsigned long req_type, /* Search for existing mapping that overlaps the current range */ where = NULL; list_for_each_entry(entry, &memtype_list, nd) { - struct memtype *saved_ptr; - if (entry->start >= end) { where = entry->nd.prev; break; } if (start <= entry->start && end >= entry->start) { - if (actual_type != entry->type && new_type) { - actual_type = entry->type; - *new_type = actual_type; - new->type = actual_type; - } - - if (actual_type != entry->type) { - err = -EBUSY; - break; - } - - saved_ptr = entry; - /* - * Check to see whether the request overlaps more - * than one entry in the list - */ - list_for_each_entry_continue(entry, &memtype_list, nd) { - if (end <= entry->start) { - break; - } - - if (actual_type != entry->type) { - err = -EBUSY; - break; - } - } - + err = chk_conflict(new, entry, new_type); if (err) { break; } dprintk("Overlap at 0x%Lx-0x%Lx\n", - saved_ptr->start, saved_ptr->end); - where = saved_ptr->nd.prev; + entry->start, entry->end); + where = entry->nd.prev; break; } if (start < entry->end) { - if (actual_type != entry->type && new_type) { - actual_type = entry->type; - *new_type = actual_type; - new->type = actual_type; - } - - if (actual_type != entry->type) { - err = -EBUSY; - break; - } - - saved_ptr = entry; - /* - * Check to see whether the request overlaps more - * than one entry in the list - */ - list_for_each_entry_continue(entry, &memtype_list, nd) { - if (end <= entry->start) { - break; - } - - if (actual_type != entry->type) { - err = -EBUSY; - break; - } - } - + err = chk_conflict(new, entry, new_type); if (err) { break; } dprintk("Overlap at 0x%Lx-0x%Lx\n", - saved_ptr->start, saved_ptr->end); - where = &saved_ptr->nd; + entry->start, entry->end); + where = &entry->nd; break; } } if (err) { - printk(KERN_INFO "%s:%d conflicting memory types " - "%Lx-%Lx %s<->%s\n", current->comm, current->pid, start, - end, cattr_name(new->type), cattr_name(entry->type)); printk(KERN_INFO "reserve_memtype failed 0x%Lx-0x%Lx, " "track %s, req %s\n", start, end, cattr_name(new->type), cattr_name(req_type)); -- cgit v1.2.3 From 33af9039cbf629041da2bfa0cf451208391a1ec3 Mon Sep 17 00:00:00 2001 From: Andreas Herrmann Date: Fri, 20 Jun 2008 22:08:37 +0200 Subject: x86: pat.c final cleanup of loop body in reserve_memtype Signed-off-by: Andreas Herrmann Cc: Venkatesh Pallipadi Cc: Suresh B Siddha Signed-off-by: Ingo Molnar --- arch/x86/mm/pat.c | 30 +++++++++++------------------- 1 file changed, 11 insertions(+), 19 deletions(-) (limited to 'arch/x86/mm/pat.c') diff --git a/arch/x86/mm/pat.c b/arch/x86/mm/pat.c index 281ac6489c08..a885a1019b8a 100644 --- a/arch/x86/mm/pat.c +++ b/arch/x86/mm/pat.c @@ -281,32 +281,24 @@ int reserve_memtype(u64 start, u64 end, unsigned long req_type, /* Search for existing mapping that overlaps the current range */ where = NULL; list_for_each_entry(entry, &memtype_list, nd) { - if (entry->start >= end) { + if (end <= entry->start) { where = entry->nd.prev; break; - } - - if (start <= entry->start && end >= entry->start) { + } else if (start <= entry->start) { /* end > entry->start */ err = chk_conflict(new, entry, new_type); - if (err) { - break; + if (!err) { + dprintk("Overlap at 0x%Lx-0x%Lx\n", + entry->start, entry->end); + where = entry->nd.prev; } - - dprintk("Overlap at 0x%Lx-0x%Lx\n", - entry->start, entry->end); - where = entry->nd.prev; break; - } - - if (start < entry->end) { + } else if (start < entry->end) { /* start > entry->start */ err = chk_conflict(new, entry, new_type); - if (err) { - break; + if (!err) { + dprintk("Overlap at 0x%Lx-0x%Lx\n", + entry->start, entry->end); + where = &entry->nd; } - - dprintk("Overlap at 0x%Lx-0x%Lx\n", - entry->start, entry->end); - where = &entry->nd; break; } } -- cgit v1.2.3 From f361a450bf1ad14e2b003217dbf3958638631265 Mon Sep 17 00:00:00 2001 From: Yinghai Lu Date: Thu, 10 Jul 2008 20:38:26 -0700 Subject: x86: introduce max_low_pfn_mapped for 64-bit when more than 4g memory is installed, don't map the big hole below 4g. Signed-off-by: Yinghai Lu Cc: Suresh Siddha Signed-off-by: Ingo Molnar --- arch/x86/kernel/acpi/boot.c | 2 +- arch/x86/kernel/cpu/amd_64.c | 10 +++++++--- arch/x86/kernel/e820.c | 23 ++++++++++++++++++++--- arch/x86/kernel/efi.c | 2 +- arch/x86/kernel/setup.c | 22 ++++++++++++++++++---- arch/x86/mm/init_32.c | 1 + arch/x86/mm/init_64.c | 1 + arch/x86/mm/pageattr.c | 19 +++++++++++++++++-- arch/x86/mm/pat.c | 3 ++- arch/x86/pci/i386.c | 4 +++- include/asm-x86/e820.h | 3 ++- include/asm-x86/page.h | 1 + 12 files changed, 74 insertions(+), 17 deletions(-) (limited to 'arch/x86/mm/pat.c') diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c index a31a579a47ca..9c981c4a3644 100644 --- a/arch/x86/kernel/acpi/boot.c +++ b/arch/x86/kernel/acpi/boot.c @@ -130,7 +130,7 @@ char *__init __acpi_map_table(unsigned long phys, unsigned long size) if (!phys || !size) return NULL; - if (phys+size <= (max_pfn_mapped << PAGE_SHIFT)) + if (phys+size <= (max_low_pfn_mapped << PAGE_SHIFT)) return __va(phys); offset = phys & (PAGE_SIZE - 1); diff --git a/arch/x86/kernel/cpu/amd_64.c b/arch/x86/kernel/cpu/amd_64.c index 958526d6a74a..bd182b7616ee 100644 --- a/arch/x86/kernel/cpu/amd_64.c +++ b/arch/x86/kernel/cpu/amd_64.c @@ -199,10 +199,14 @@ static void __cpuinit init_amd(struct cpuinfo_x86 *c) * Don't do it for gbpages because there seems very little * benefit in doing so. */ - if (!rdmsrl_safe(MSR_K8_TSEG_ADDR, &tseg) && - (tseg >> PMD_SHIFT) < - (max_pfn_mapped >> (PMD_SHIFT-PAGE_SHIFT))) + if (!rdmsrl_safe(MSR_K8_TSEG_ADDR, &tseg)) { + if ((tseg>>PMD_SHIFT) < + (max_low_pfn_mapped>>(PMD_SHIFT-PAGE_SHIFT)) || + ((tseg>>PMD_SHIFT) < + (max_pfn_mapped>>(PMD_SHIFT-PAGE_SHIFT)) && + (tseg>>PMD_SHIFT) >= (1ULL<<(32 - PMD_SHIFT)))) set_memory_4k((unsigned long)__va(tseg), 1); + } } } diff --git a/arch/x86/kernel/e820.c b/arch/x86/kernel/e820.c index 3451e0b3f324..9f5002e0b35c 100644 --- a/arch/x86/kernel/e820.c +++ b/arch/x86/kernel/e820.c @@ -1056,7 +1056,7 @@ unsigned long __initdata end_user_pfn = MAX_ARCH_PFN; /* * Find the highest page frame number we have available */ -unsigned long __init e820_end(void) +static unsigned long __init e820_end_pfn(unsigned long limit_pfn, unsigned type) { int i; unsigned long last_pfn = 0; @@ -1064,12 +1064,21 @@ unsigned long __init e820_end(void) for (i = 0; i < e820.nr_map; i++) { struct e820entry *ei = &e820.map[i]; + unsigned long start_pfn; unsigned long end_pfn; - if (ei->type != E820_RAM) + if (ei->type != type) continue; + start_pfn = ei->addr >> PAGE_SHIFT; end_pfn = (ei->addr + ei->size) >> PAGE_SHIFT; + + if (start_pfn >= limit_pfn) + continue; + if (end_pfn > limit_pfn) { + last_pfn = limit_pfn; + break; + } if (end_pfn > last_pfn) last_pfn = end_pfn; } @@ -1083,7 +1092,15 @@ unsigned long __init e820_end(void) last_pfn, max_arch_pfn); return last_pfn; } +unsigned long __init e820_end_of_ram_pfn(void) +{ + return e820_end_pfn(MAX_ARCH_PFN, E820_RAM); +} +unsigned long __init e820_end_of_low_ram_pfn(void) +{ + return e820_end_pfn(1UL<<(32 - PAGE_SHIFT), E820_RAM); +} /* * Finds an active region in the address range from start_pfn to last_pfn and * returns its range in ei_startpfn and ei_endpfn for the e820 entry. @@ -1206,7 +1223,7 @@ static int __init parse_memmap_opt(char *p) * the real mem size before original memory map is * reset. */ - saved_max_pfn = e820_end(); + saved_max_pfn = e820_end_of_ram_pfn(); #endif e820.nr_map = 0; userdef = 1; diff --git a/arch/x86/kernel/efi.c b/arch/x86/kernel/efi.c index 94382faeadb6..06cc8d4254b1 100644 --- a/arch/x86/kernel/efi.c +++ b/arch/x86/kernel/efi.c @@ -473,7 +473,7 @@ void __init efi_enter_virtual_mode(void) size = md->num_pages << EFI_PAGE_SHIFT; end = md->phys_addr + size; - if (PFN_UP(end) <= max_pfn_mapped) + if (PFN_UP(end) <= max_low_pfn_mapped) va = __va(md->phys_addr); else va = efi_ioremap(md->phys_addr, size); diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c index a7c3471ea17c..86fc2d624270 100644 --- a/arch/x86/kernel/setup.c +++ b/arch/x86/kernel/setup.c @@ -713,14 +713,14 @@ void __init setup_arch(char **cmdline_p) * partially used pages are not usable - thus * we are rounding upwards: */ - max_pfn = e820_end(); + max_pfn = e820_end_of_ram_pfn(); /* preallocate 4k for mptable mpc */ early_reserve_e820_mpc_new(); /* update e820 for memory not covered by WB MTRRs */ mtrr_bp_init(); if (mtrr_trim_uncached_memory(max_pfn)) - max_pfn = e820_end(); + max_pfn = e820_end_of_ram_pfn(); #ifdef CONFIG_X86_32 /* max_low_pfn get updated here */ @@ -732,12 +732,26 @@ void __init setup_arch(char **cmdline_p) /* How many end-of-memory variables you have, grandma! */ /* need this before calling reserve_initrd */ - max_low_pfn = max_pfn; + if (max_pfn > (1UL<<(32 - PAGE_SHIFT))) + max_low_pfn = e820_end_of_low_ram_pfn(); + else + max_low_pfn = max_pfn; + high_memory = (void *)__va(max_pfn * PAGE_SIZE - 1) + 1; #endif /* max_pfn_mapped is updated here */ - max_pfn_mapped = init_memory_mapping(0, (max_low_pfn << PAGE_SHIFT)); + max_low_pfn_mapped = init_memory_mapping(0, max_low_pfn< max_low_pfn) { + max_pfn_mapped = init_memory_mapping(1UL<<32, + max_pfn<= (unsigned long)__va(0) && + address < (unsigned long)__va(max_low_pfn_mapped << PAGE_SHIFT)) + split_page_count(level); + +#ifdef CONFIG_X86_64 + if (address >= (unsigned long)__va(1UL<<32) && address < (unsigned long)__va(max_pfn_mapped << PAGE_SHIFT)) split_page_count(level); +#endif /* * Install the new, split up pagetable. Important details here: @@ -655,12 +661,21 @@ static int cpa_process_alias(struct cpa_data *cpa) if (cpa->pfn > max_pfn_mapped) return 0; +#ifdef CONFIG_X86_64 + if (cpa->pfn > max_low_pfn_mapped && cpa->pfn < (1UL<<(32-PAGE_SHIFT))) + return 0; +#endif /* * No need to redo, when the primary call touched the direct * mapping already: */ - if (!within(cpa->vaddr, PAGE_OFFSET, - PAGE_OFFSET + (max_pfn_mapped << PAGE_SHIFT))) { + if (!(within(cpa->vaddr, PAGE_OFFSET, + PAGE_OFFSET + (max_low_pfn_mapped << PAGE_SHIFT)) +#ifdef CONFIG_X86_64 + || within(cpa->vaddr, PAGE_OFFSET + (1UL<<32), + PAGE_OFFSET + (max_pfn_mapped << PAGE_SHIFT)) +#endif + )) { alias_cpa = *cpa; alias_cpa.vaddr = (unsigned long) __va(cpa->pfn << PAGE_SHIFT); diff --git a/arch/x86/mm/pat.c b/arch/x86/mm/pat.c index a885a1019b8a..749766c3c5cd 100644 --- a/arch/x86/mm/pat.c +++ b/arch/x86/mm/pat.c @@ -449,7 +449,8 @@ int phys_mem_access_prot_allowed(struct file *file, unsigned long pfn, if (retval < 0) return 0; - if (pfn <= max_pfn_mapped && + if (((pfn <= max_low_pfn_mapped) || + (pfn >= (1UL<<(32 - PAGE_SHIFT)) && pfn <= max_pfn_mapped)) && ioremap_change_attr((unsigned long)__va(offset), size, flags) < 0) { free_memtype(offset, offset + size); printk(KERN_INFO diff --git a/arch/x86/pci/i386.c b/arch/x86/pci/i386.c index 6ccd7a108cd4..5281e343dd9f 100644 --- a/arch/x86/pci/i386.c +++ b/arch/x86/pci/i386.c @@ -334,7 +334,9 @@ int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma, flags = new_flags; } - if (vma->vm_pgoff <= max_pfn_mapped && + if (((vma->vm_pgoff <= max_low_pfn_mapped) || + (vma->vm_pgoff >= (1UL<<(32 - PAGE_SHIFT)) && + vma->vm_pgoff <= max_pfn_mapped)) && ioremap_change_attr((unsigned long)__va(addr), len, flags)) { free_memtype(addr, addr + len); return -EINVAL; diff --git a/include/asm-x86/e820.h b/include/asm-x86/e820.h index 78c03d7bf441..33e793e991d0 100644 --- a/include/asm-x86/e820.h +++ b/include/asm-x86/e820.h @@ -99,7 +99,8 @@ extern void free_early(u64 start, u64 end); extern void early_res_to_bootmem(u64 start, u64 end); extern u64 early_reserve_e820(u64 startt, u64 sizet, u64 align); -extern unsigned long e820_end(void); +extern unsigned long e820_end_of_ram_pfn(void); +extern unsigned long e820_end_of_low_ram_pfn(void); extern int e820_find_active_region(const struct e820entry *ei, unsigned long start_pfn, unsigned long last_pfn, diff --git a/include/asm-x86/page.h b/include/asm-x86/page.h index b52ed85f32f5..28d7b4533b1a 100644 --- a/include/asm-x86/page.h +++ b/include/asm-x86/page.h @@ -61,6 +61,7 @@ extern void map_devmem(unsigned long pfn, unsigned long size, extern void unmap_devmem(unsigned long pfn, unsigned long size, pgprot_t vma_prot); +extern unsigned long max_low_pfn_mapped; extern unsigned long max_pfn_mapped; struct page; -- cgit v1.2.3 From 965194c15dc9e4f3bc44432b39c441c86af7f11d Mon Sep 17 00:00:00 2001 From: Yinghai Lu Date: Sat, 12 Jul 2008 14:31:28 -0700 Subject: x86: max_low_pfn_mapped fix, #2 tighten the boundary checks around max_low_pfn_mapped - dont overmap nor undermap into holes. also print out tseg for AMD cpus, for diagnostic purposes. (this is an SMM area, and we split up any big mappings around that area) Signed-off-by: Yinghai Lu Cc: Suresh Siddha Signed-off-by: Ingo Molnar --- arch/x86/kernel/cpu/amd_64.c | 1 + arch/x86/mm/pageattr.c | 4 ++-- arch/x86/mm/pat.c | 4 ++-- arch/x86/pci/i386.c | 4 ++-- 4 files changed, 7 insertions(+), 6 deletions(-) (limited to 'arch/x86/mm/pat.c') diff --git a/arch/x86/kernel/cpu/amd_64.c b/arch/x86/kernel/cpu/amd_64.c index bd182b7616ee..7c36fb8a28d4 100644 --- a/arch/x86/kernel/cpu/amd_64.c +++ b/arch/x86/kernel/cpu/amd_64.c @@ -200,6 +200,7 @@ static void __cpuinit init_amd(struct cpuinfo_x86 *c) * benefit in doing so. */ if (!rdmsrl_safe(MSR_K8_TSEG_ADDR, &tseg)) { + printk(KERN_DEBUG "tseg: %010llx\n", tseg); if ((tseg>>PMD_SHIFT) < (max_low_pfn_mapped>>(PMD_SHIFT-PAGE_SHIFT)) || ((tseg>>PMD_SHIFT) < diff --git a/arch/x86/mm/pageattr.c b/arch/x86/mm/pageattr.c index 0389cb8f6b1a..fb6f2ab40dda 100644 --- a/arch/x86/mm/pageattr.c +++ b/arch/x86/mm/pageattr.c @@ -658,11 +658,11 @@ static int cpa_process_alias(struct cpa_data *cpa) struct cpa_data alias_cpa; int ret = 0; - if (cpa->pfn > max_pfn_mapped) + if (cpa->pfn >= max_pfn_mapped) return 0; #ifdef CONFIG_X86_64 - if (cpa->pfn > max_low_pfn_mapped && cpa->pfn < (1UL<<(32-PAGE_SHIFT))) + if (cpa->pfn >= max_low_pfn_mapped && cpa->pfn < (1UL<<(32-PAGE_SHIFT))) return 0; #endif /* diff --git a/arch/x86/mm/pat.c b/arch/x86/mm/pat.c index 749766c3c5cd..d4585077977a 100644 --- a/arch/x86/mm/pat.c +++ b/arch/x86/mm/pat.c @@ -449,8 +449,8 @@ int phys_mem_access_prot_allowed(struct file *file, unsigned long pfn, if (retval < 0) return 0; - if (((pfn <= max_low_pfn_mapped) || - (pfn >= (1UL<<(32 - PAGE_SHIFT)) && pfn <= max_pfn_mapped)) && + if (((pfn < max_low_pfn_mapped) || + (pfn >= (1UL<<(32 - PAGE_SHIFT)) && pfn < max_pfn_mapped)) && ioremap_change_attr((unsigned long)__va(offset), size, flags) < 0) { free_memtype(offset, offset + size); printk(KERN_INFO diff --git a/arch/x86/pci/i386.c b/arch/x86/pci/i386.c index 5281e343dd9f..2aafb67dc5f1 100644 --- a/arch/x86/pci/i386.c +++ b/arch/x86/pci/i386.c @@ -334,9 +334,9 @@ int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma, flags = new_flags; } - if (((vma->vm_pgoff <= max_low_pfn_mapped) || + if (((vma->vm_pgoff < max_low_pfn_mapped) || (vma->vm_pgoff >= (1UL<<(32 - PAGE_SHIFT)) && - vma->vm_pgoff <= max_pfn_mapped)) && + vma->vm_pgoff < max_pfn_mapped)) && ioremap_change_attr((unsigned long)__va(addr), len, flags)) { free_memtype(addr, addr + len); return -EINVAL; -- cgit v1.2.3