aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/mm/pat.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86/mm/pat.c')
-rw-r--r--arch/x86/mm/pat.c67
1 files changed, 32 insertions, 35 deletions
diff --git a/arch/x86/mm/pat.c b/arch/x86/mm/pat.c
index aceb6c7c6dba..738fd0f24958 100644
--- a/arch/x86/mm/pat.c
+++ b/arch/x86/mm/pat.c
@@ -7,24 +7,24 @@
7 * Loosely based on earlier PAT patchset from Eric Biederman and Andi Kleen. 7 * Loosely based on earlier PAT patchset from Eric Biederman and Andi Kleen.
8 */ 8 */
9 9
10#include <linux/mm.h> 10#include <linux/seq_file.h>
11#include <linux/bootmem.h>
12#include <linux/debugfs.h>
11#include <linux/kernel.h> 13#include <linux/kernel.h>
12#include <linux/gfp.h> 14#include <linux/gfp.h>
15#include <linux/mm.h>
13#include <linux/fs.h> 16#include <linux/fs.h>
14#include <linux/bootmem.h>
15#include <linux/debugfs.h>
16#include <linux/seq_file.h>
17 17
18#include <asm/msr.h> 18#include <asm/cacheflush.h>
19#include <asm/tlbflush.h>
20#include <asm/processor.h> 19#include <asm/processor.h>
21#include <asm/page.h> 20#include <asm/tlbflush.h>
22#include <asm/pgtable.h> 21#include <asm/pgtable.h>
23#include <asm/pat.h>
24#include <asm/e820.h>
25#include <asm/cacheflush.h>
26#include <asm/fcntl.h> 22#include <asm/fcntl.h>
23#include <asm/e820.h>
27#include <asm/mtrr.h> 24#include <asm/mtrr.h>
25#include <asm/page.h>
26#include <asm/msr.h>
27#include <asm/pat.h>
28#include <asm/io.h> 28#include <asm/io.h>
29 29
30#ifdef CONFIG_X86_PAT 30#ifdef CONFIG_X86_PAT
@@ -46,6 +46,7 @@ early_param("nopat", nopat);
46 46
47 47
48static int debug_enable; 48static int debug_enable;
49
49static int __init pat_debug_setup(char *str) 50static int __init pat_debug_setup(char *str)
50{ 51{
51 debug_enable = 1; 52 debug_enable = 1;
@@ -145,14 +146,14 @@ static char *cattr_name(unsigned long flags)
145 */ 146 */
146 147
147struct memtype { 148struct memtype {
148 u64 start; 149 u64 start;
149 u64 end; 150 u64 end;
150 unsigned long type; 151 unsigned long type;
151 struct list_head nd; 152 struct list_head nd;
152}; 153};
153 154
154static LIST_HEAD(memtype_list); 155static LIST_HEAD(memtype_list);
155static DEFINE_SPINLOCK(memtype_lock); /* protects memtype list */ 156static DEFINE_SPINLOCK(memtype_lock); /* protects memtype list */
156 157
157/* 158/*
158 * Does intersection of PAT memory type and MTRR memory type and returns 159 * Does intersection of PAT memory type and MTRR memory type and returns
@@ -180,8 +181,8 @@ static unsigned long pat_x_mtrr_type(u64 start, u64 end, unsigned long req_type)
180 return req_type; 181 return req_type;
181} 182}
182 183
183static int chk_conflict(struct memtype *new, struct memtype *entry, 184static int
184 unsigned long *type) 185chk_conflict(struct memtype *new, struct memtype *entry, unsigned long *type)
185{ 186{
186 if (new->type != entry->type) { 187 if (new->type != entry->type) {
187 if (type) { 188 if (type) {
@@ -211,15 +212,6 @@ static struct memtype *cached_entry;
211static u64 cached_start; 212static u64 cached_start;
212 213
213/* 214/*
214 * RED-PEN: TODO: Add PageReserved() check as well here,
215 * once we add SetPageReserved() to all the drivers using
216 * set_memory_* or set_pages_*.
217 *
218 * This will help prevent accidentally freeing pages
219 * before setting the attribute back to WB.
220 */
221
222/*
223 * For RAM pages, mark the pages as non WB memory type using 215 * For RAM pages, mark the pages as non WB memory type using
224 * PageNonWB (PG_arch_1). We allow only one set_memory_uc() or 216 * PageNonWB (PG_arch_1). We allow only one set_memory_uc() or
225 * set_memory_wc() on a RAM page at a time before marking it as WB again. 217 * set_memory_wc() on a RAM page at a time before marking it as WB again.
@@ -232,7 +224,7 @@ static u64 cached_start;
232 * UC and WC mapping. 224 * UC and WC mapping.
233 */ 225 */
234static int reserve_ram_pages_type(u64 start, u64 end, unsigned long req_type, 226static int reserve_ram_pages_type(u64 start, u64 end, unsigned long req_type,
235 unsigned long *new_type) 227 unsigned long *new_type)
236{ 228{
237 struct page *page; 229 struct page *page;
238 u64 pfn, end_pfn; 230 u64 pfn, end_pfn;
@@ -295,15 +287,15 @@ out:
295 * it will return a negative return value. 287 * it will return a negative return value.
296 */ 288 */
297int reserve_memtype(u64 start, u64 end, unsigned long req_type, 289int reserve_memtype(u64 start, u64 end, unsigned long req_type,
298 unsigned long *new_type) 290 unsigned long *new_type)
299{ 291{
300 struct memtype *new, *entry; 292 struct memtype *new, *entry;
301 unsigned long actual_type; 293 unsigned long actual_type;
302 struct list_head *where; 294 struct list_head *where;
303 int err = 0;
304 int is_range_ram; 295 int is_range_ram;
296 int err = 0;
305 297
306 BUG_ON(start >= end); /* end is exclusive */ 298 BUG_ON(start >= end); /* end is exclusive */
307 299
308 if (!pat_enabled) { 300 if (!pat_enabled) {
309 /* This is identical to page table setting without PAT */ 301 /* This is identical to page table setting without PAT */
@@ -336,9 +328,10 @@ int reserve_memtype(u64 start, u64 end, unsigned long req_type,
336 actual_type = _PAGE_CACHE_WB; 328 actual_type = _PAGE_CACHE_WB;
337 else 329 else
338 actual_type = _PAGE_CACHE_UC_MINUS; 330 actual_type = _PAGE_CACHE_UC_MINUS;
339 } else 331 } else {
340 actual_type = pat_x_mtrr_type(start, end, 332 actual_type = pat_x_mtrr_type(start, end,
341 req_type & _PAGE_CACHE_MASK); 333 req_type & _PAGE_CACHE_MASK);
334 }
342 335
343 is_range_ram = pagerange_is_ram(start, end); 336 is_range_ram = pagerange_is_ram(start, end);
344 if (is_range_ram == 1) 337 if (is_range_ram == 1)
@@ -350,9 +343,9 @@ int reserve_memtype(u64 start, u64 end, unsigned long req_type,
350 if (!new) 343 if (!new)
351 return -ENOMEM; 344 return -ENOMEM;
352 345
353 new->start = start; 346 new->start = start;
354 new->end = end; 347 new->end = end;
355 new->type = actual_type; 348 new->type = actual_type;
356 349
357 if (new_type) 350 if (new_type)
358 *new_type = actual_type; 351 *new_type = actual_type;
@@ -411,6 +404,7 @@ int reserve_memtype(u64 start, u64 end, unsigned long req_type,
411 start, end, cattr_name(new->type), cattr_name(req_type)); 404 start, end, cattr_name(new->type), cattr_name(req_type));
412 kfree(new); 405 kfree(new);
413 spin_unlock(&memtype_lock); 406 spin_unlock(&memtype_lock);
407
414 return err; 408 return err;
415 } 409 }
416 410
@@ -469,6 +463,7 @@ int free_memtype(u64 start, u64 end)
469 } 463 }
470 464
471 dprintk("free_memtype request 0x%Lx-0x%Lx\n", start, end); 465 dprintk("free_memtype request 0x%Lx-0x%Lx\n", start, end);
466
472 return err; 467 return err;
473} 468}
474 469
@@ -575,9 +570,9 @@ int phys_mem_access_prot_allowed(struct file *file, unsigned long pfn,
575 570
576void map_devmem(unsigned long pfn, unsigned long size, pgprot_t vma_prot) 571void map_devmem(unsigned long pfn, unsigned long size, pgprot_t vma_prot)
577{ 572{
573 unsigned long want_flags = (pgprot_val(vma_prot) & _PAGE_CACHE_MASK);
578 u64 addr = (u64)pfn << PAGE_SHIFT; 574 u64 addr = (u64)pfn << PAGE_SHIFT;
579 unsigned long flags; 575 unsigned long flags;
580 unsigned long want_flags = (pgprot_val(vma_prot) & _PAGE_CACHE_MASK);
581 576
582 reserve_memtype(addr, addr + size, want_flags, &flags); 577 reserve_memtype(addr, addr + size, want_flags, &flags);
583 if (flags != want_flags) { 578 if (flags != want_flags) {
@@ -620,6 +615,7 @@ static struct memtype *memtype_get_idx(loff_t pos)
620 } 615 }
621 spin_unlock(&memtype_lock); 616 spin_unlock(&memtype_lock);
622 kfree(print_entry); 617 kfree(print_entry);
618
623 return NULL; 619 return NULL;
624} 620}
625 621
@@ -650,6 +646,7 @@ static int memtype_seq_show(struct seq_file *seq, void *v)
650 seq_printf(seq, "%s @ 0x%Lx-0x%Lx\n", cattr_name(print_entry->type), 646 seq_printf(seq, "%s @ 0x%Lx-0x%Lx\n", cattr_name(print_entry->type),
651 print_entry->start, print_entry->end); 647 print_entry->start, print_entry->end);
652 kfree(print_entry); 648 kfree(print_entry);
649
653 return 0; 650 return 0;
654} 651}
655 652