diff options
author | David Woodhouse <David.Woodhouse@intel.com> | 2008-07-11 09:36:25 -0400 |
---|---|---|
committer | David Woodhouse <David.Woodhouse@intel.com> | 2008-07-11 09:36:25 -0400 |
commit | a8931ef380c92d121ae74ecfb03b2d63f72eea6f (patch) | |
tree | 980fb6b019e11e6cb1ece55b7faff184721a8053 /arch/x86/mm/pat.c | |
parent | 90574d0a4d4b73308ae54a2a57a4f3f1fa98e984 (diff) | |
parent | e5a5816f7875207cb0a0a7032e39a4686c5e10a4 (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.c | 103 |
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 | ||
28 | int pat_wc_enabled = 1; | 28 | #ifdef CONFIG_X86_PAT |
29 | int __read_mostly pat_wc_enabled = 1; | ||
29 | 30 | ||
30 | static u64 __read_mostly boot_pat_state; | 31 | void __cpuinit pat_disable(char *reason) |
31 | |||
32 | static 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 | } |
39 | early_param("nopat", nopat); | ||
40 | 36 | ||
41 | static int pat_known_cpu(void) | 37 | static 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 | } |
42 | early_param("nopat", nopat); | ||
43 | #endif | ||
44 | |||
45 | static u64 __read_mostly boot_pat_state; | ||
53 | 46 | ||
54 | enum { | 47 | enum { |
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 | } |