aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/mm/pat.c
diff options
context:
space:
mode:
authorDavid Woodhouse <David.Woodhouse@intel.com>2008-07-11 09:36:25 -0400
committerDavid Woodhouse <David.Woodhouse@intel.com>2008-07-11 09:36:25 -0400
commita8931ef380c92d121ae74ecfb03b2d63f72eea6f (patch)
tree980fb6b019e11e6cb1ece55b7faff184721a8053 /arch/x86/mm/pat.c
parent90574d0a4d4b73308ae54a2a57a4f3f1fa98e984 (diff)
parente5a5816f7875207cb0a0a7032e39a4686c5e10a4 (diff)
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6
Diffstat (limited to 'arch/x86/mm/pat.c')
-rw-r--r--arch/x86/mm/pat.c103
1 files changed, 48 insertions, 55 deletions
diff --git a/arch/x86/mm/pat.c b/arch/x86/mm/pat.c
index 277446cd30b6..06b7a1c90fb8 100644
--- a/arch/x86/mm/pat.c
+++ b/arch/x86/mm/pat.c
@@ -25,31 +25,24 @@
25#include <asm/mtrr.h> 25#include <asm/mtrr.h>
26#include <asm/io.h> 26#include <asm/io.h>
27 27
28int pat_wc_enabled = 1; 28#ifdef CONFIG_X86_PAT
29int __read_mostly pat_wc_enabled = 1;
29 30
30static u64 __read_mostly boot_pat_state; 31void __cpuinit pat_disable(char *reason)
31
32static int nopat(char *str)
33{ 32{
34 pat_wc_enabled = 0; 33 pat_wc_enabled = 0;
35 printk(KERN_INFO "x86: PAT support disabled.\n"); 34 printk(KERN_INFO "%s\n", reason);
36
37 return 0;
38} 35}
39early_param("nopat", nopat);
40 36
41static int pat_known_cpu(void) 37static int __init nopat(char *str)
42{ 38{
43 if (!pat_wc_enabled) 39 pat_disable("PAT support disabled.");
44 return 0;
45
46 if (cpu_has_pat)
47 return 1;
48
49 pat_wc_enabled = 0;
50 printk(KERN_INFO "CPU and/or kernel does not support PAT.\n");
51 return 0; 40 return 0;
52} 41}
42early_param("nopat", nopat);
43#endif
44
45static u64 __read_mostly boot_pat_state;
53 46
54enum { 47enum {
55 PAT_UC = 0, /* uncached */ 48 PAT_UC = 0, /* uncached */
@@ -66,17 +59,19 @@ void pat_init(void)
66{ 59{
67 u64 pat; 60 u64 pat;
68 61
69#ifndef CONFIG_X86_PAT 62 if (!pat_wc_enabled)
70 nopat(NULL);
71#endif
72
73 /* Boot CPU enables PAT based on CPU feature */
74 if (!smp_processor_id() && !pat_known_cpu())
75 return; 63 return;
76 64
77 /* APs enable PAT iff boot CPU has enabled it before */ 65 /* Paranoia check. */
78 if (smp_processor_id() && !pat_wc_enabled) 66 if (!cpu_has_pat) {
79 return; 67 printk(KERN_ERR "PAT enabled, but CPU feature cleared\n");
68 /*
69 * Panic if this happens on the secondary CPU, and we
70 * switched to PAT on the boot CPU. We have no way to
71 * undo PAT.
72 */
73 BUG_ON(boot_pat_state);
74 }
80 75
81 /* Set PWT to Write-Combining. All other bits stay the same */ 76 /* Set PWT to Write-Combining. All other bits stay the same */
82 /* 77 /*
@@ -95,9 +90,8 @@ void pat_init(void)
95 PAT(4,WB) | PAT(5,WC) | PAT(6,UC_MINUS) | PAT(7,UC); 90 PAT(4,WB) | PAT(5,WC) | PAT(6,UC_MINUS) | PAT(7,UC);
96 91
97 /* Boot CPU check */ 92 /* Boot CPU check */
98 if (!smp_processor_id()) { 93 if (!boot_pat_state)
99 rdmsrl(MSR_IA32_CR_PAT, boot_pat_state); 94 rdmsrl(MSR_IA32_CR_PAT, boot_pat_state);
100 }
101 95
102 wrmsrl(MSR_IA32_CR_PAT, pat); 96 wrmsrl(MSR_IA32_CR_PAT, pat);
103 printk(KERN_INFO "x86 PAT enabled: cpu %d, old 0x%Lx, new 0x%Lx\n", 97 printk(KERN_INFO "x86 PAT enabled: cpu %d, old 0x%Lx, new 0x%Lx\n",
@@ -157,32 +151,33 @@ static int pat_x_mtrr_type(u64 start, u64 end, unsigned long prot,
157 unsigned long pat_type; 151 unsigned long pat_type;
158 u8 mtrr_type; 152 u8 mtrr_type;
159 153
160 mtrr_type = mtrr_type_lookup(start, end);
161 if (mtrr_type == 0xFF) { /* MTRR not enabled */
162 *ret_prot = prot;
163 return 0;
164 }
165 if (mtrr_type == 0xFE) { /* MTRR match error */
166 *ret_prot = _PAGE_CACHE_UC;
167 return -1;
168 }
169 if (mtrr_type != MTRR_TYPE_UNCACHABLE &&
170 mtrr_type != MTRR_TYPE_WRBACK &&
171 mtrr_type != MTRR_TYPE_WRCOMB) { /* MTRR type unhandled */
172 *ret_prot = _PAGE_CACHE_UC;
173 return -1;
174 }
175
176 pat_type = prot & _PAGE_CACHE_MASK; 154 pat_type = prot & _PAGE_CACHE_MASK;
177 prot &= (~_PAGE_CACHE_MASK); 155 prot &= (~_PAGE_CACHE_MASK);
178 156
179 /* Currently doing intersection by hand. Optimize it later. */ 157 /*
158 * We return the PAT request directly for types where PAT takes
159 * precedence with respect to MTRR and for UC_MINUS.
160 * Consistency checks with other PAT requests is done later
161 * while going through memtype list.
162 */
180 if (pat_type == _PAGE_CACHE_WC) { 163 if (pat_type == _PAGE_CACHE_WC) {
181 *ret_prot = prot | _PAGE_CACHE_WC; 164 *ret_prot = prot | _PAGE_CACHE_WC;
165 return 0;
182 } else if (pat_type == _PAGE_CACHE_UC_MINUS) { 166 } else if (pat_type == _PAGE_CACHE_UC_MINUS) {
183 *ret_prot = prot | _PAGE_CACHE_UC_MINUS; 167 *ret_prot = prot | _PAGE_CACHE_UC_MINUS;
184 } else if (pat_type == _PAGE_CACHE_UC || 168 return 0;
185 mtrr_type == MTRR_TYPE_UNCACHABLE) { 169 } else if (pat_type == _PAGE_CACHE_UC) {
170 *ret_prot = prot | _PAGE_CACHE_UC;
171 return 0;
172 }
173
174 /*
175 * Look for MTRR hint to get the effective type in case where PAT
176 * request is for WB.
177 */
178 mtrr_type = mtrr_type_lookup(start, end);
179
180 if (mtrr_type == MTRR_TYPE_UNCACHABLE) {
186 *ret_prot = prot | _PAGE_CACHE_UC; 181 *ret_prot = prot | _PAGE_CACHE_UC;
187 } else if (mtrr_type == MTRR_TYPE_WRCOMB) { 182 } else if (mtrr_type == MTRR_TYPE_WRCOMB) {
188 *ret_prot = prot | _PAGE_CACHE_WC; 183 *ret_prot = prot | _PAGE_CACHE_WC;
@@ -239,14 +234,12 @@ int reserve_memtype(u64 start, u64 end, unsigned long req_type,
239 234
240 if (req_type == -1) { 235 if (req_type == -1) {
241 /* 236 /*
242 * Special case where caller wants to inherit from mtrr or 237 * Call mtrr_lookup to get the type hint. This is an
243 * existing pat mapping, defaulting to UC_MINUS in case of 238 * optimization for /dev/mem mmap'ers into WB memory (BIOS
244 * no match. 239 * tools and ACPI tools). Use WB request for WB memory and use
240 * UC_MINUS otherwise.
245 */ 241 */
246 u8 mtrr_type = mtrr_type_lookup(start, end); 242 u8 mtrr_type = mtrr_type_lookup(start, end);
247 if (mtrr_type == 0xFE) { /* MTRR match error */
248 err = -1;
249 }
250 243
251 if (mtrr_type == MTRR_TYPE_WRBACK) { 244 if (mtrr_type == MTRR_TYPE_WRBACK) {
252 req_type = _PAGE_CACHE_WB; 245 req_type = _PAGE_CACHE_WB;
@@ -561,7 +554,7 @@ int phys_mem_access_prot_allowed(struct file *file, unsigned long pfn,
561 "%s:%d /dev/mem ioremap_change_attr failed %s for %Lx-%Lx\n", 554 "%s:%d /dev/mem ioremap_change_attr failed %s for %Lx-%Lx\n",
562 current->comm, current->pid, 555 current->comm, current->pid,
563 cattr_name(flags), 556 cattr_name(flags),
564 offset, offset + size); 557 offset, (unsigned long long)(offset + size));
565 return 0; 558 return 0;
566 } 559 }
567 560
@@ -582,7 +575,7 @@ void map_devmem(unsigned long pfn, unsigned long size, pgprot_t vma_prot)
582 "%s:%d /dev/mem expected mapping type %s for %Lx-%Lx, got %s\n", 575 "%s:%d /dev/mem expected mapping type %s for %Lx-%Lx, got %s\n",
583 current->comm, current->pid, 576 current->comm, current->pid,
584 cattr_name(want_flags), 577 cattr_name(want_flags),
585 addr, addr + size, 578 addr, (unsigned long long)(addr + size),
586 cattr_name(flags)); 579 cattr_name(flags));
587 } 580 }
588} 581}