aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
Diffstat (limited to 'arch')
-rw-r--r--arch/x86/mm/pat.c170
-rw-r--r--arch/x86/mm/pat_internal.h28
2 files changed, 116 insertions, 82 deletions
diff --git a/arch/x86/mm/pat.c b/arch/x86/mm/pat.c
index ae9648eb1c7f..628e507b7936 100644
--- a/arch/x86/mm/pat.c
+++ b/arch/x86/mm/pat.c
@@ -30,6 +30,8 @@
30#include <asm/pat.h> 30#include <asm/pat.h>
31#include <asm/io.h> 31#include <asm/io.h>
32 32
33#include "pat_internal.h"
34
33#ifdef CONFIG_X86_PAT 35#ifdef CONFIG_X86_PAT
34int __read_mostly pat_enabled = 1; 36int __read_mostly pat_enabled = 1;
35 37
@@ -53,19 +55,15 @@ static inline void pat_disable(const char *reason)
53#endif 55#endif
54 56
55 57
56static int debug_enable; 58int pat_debug_enable;
57 59
58static int __init pat_debug_setup(char *str) 60static int __init pat_debug_setup(char *str)
59{ 61{
60 debug_enable = 1; 62 pat_debug_enable = 1;
61 return 0; 63 return 0;
62} 64}
63__setup("debugpat", pat_debug_setup); 65__setup("debugpat", pat_debug_setup);
64 66
65#define dprintk(fmt, arg...) \
66 do { if (debug_enable) printk(KERN_INFO fmt, ##arg); } while (0)
67
68
69static u64 __read_mostly boot_pat_state; 67static u64 __read_mostly boot_pat_state;
70 68
71enum { 69enum {
@@ -132,17 +130,6 @@ void pat_init(void)
132 130
133#undef PAT 131#undef PAT
134 132
135static char *cattr_name(unsigned long flags)
136{
137 switch (flags & _PAGE_CACHE_MASK) {
138 case _PAGE_CACHE_UC: return "uncached";
139 case _PAGE_CACHE_UC_MINUS: return "uncached-minus";
140 case _PAGE_CACHE_WB: return "write-back";
141 case _PAGE_CACHE_WC: return "write-combining";
142 default: return "broken";
143 }
144}
145
146/* 133/*
147 * The global memtype list keeps track of memory type for specific 134 * The global memtype list keeps track of memory type for specific
148 * physical memory areas. Conflicting memory types in different 135 * physical memory areas. Conflicting memory types in different
@@ -159,14 +146,6 @@ static char *cattr_name(unsigned long flags)
159 * memtype_lock protects both the linear list and rbtree. 146 * memtype_lock protects both the linear list and rbtree.
160 */ 147 */
161 148
162struct memtype {
163 u64 start;
164 u64 end;
165 unsigned long type;
166 struct list_head nd;
167 struct rb_node rb;
168};
169
170static struct rb_root memtype_rbroot = RB_ROOT; 149static struct rb_root memtype_rbroot = RB_ROOT;
171static LIST_HEAD(memtype_list); 150static LIST_HEAD(memtype_list);
172static DEFINE_SPINLOCK(memtype_lock); /* protects memtype list */ 151static DEFINE_SPINLOCK(memtype_lock); /* protects memtype list */
@@ -349,6 +328,64 @@ static int free_ram_pages_type(u64 start, u64 end)
349 return 0; 328 return 0;
350} 329}
351 330
331static int memtype_check_insert(struct memtype *new, unsigned long *new_type)
332{
333 struct memtype *entry;
334 u64 start, end;
335 unsigned long actual_type;
336 struct list_head *where;
337 int err = 0;
338
339 start = new->start;
340 end = new->end;
341 actual_type = new->type;
342
343 /* Search for existing mapping that overlaps the current range */
344 where = NULL;
345 list_for_each_entry(entry, &memtype_list, nd) {
346 if (end <= entry->start) {
347 where = entry->nd.prev;
348 break;
349 } else if (start <= entry->start) { /* end > entry->start */
350 err = chk_conflict(new, entry, new_type);
351 if (!err) {
352 dprintk("Overlap at 0x%Lx-0x%Lx\n",
353 entry->start, entry->end);
354 where = entry->nd.prev;
355 }
356 break;
357 } else if (start < entry->end) { /* start > entry->start */
358 err = chk_conflict(new, entry, new_type);
359 if (!err) {
360 dprintk("Overlap at 0x%Lx-0x%Lx\n",
361 entry->start, entry->end);
362
363 /*
364 * Move to right position in the linked
365 * list to add this new entry
366 */
367 list_for_each_entry_continue(entry,
368 &memtype_list, nd) {
369 if (start <= entry->start) {
370 where = entry->nd.prev;
371 break;
372 }
373 }
374 }
375 break;
376 }
377 }
378 if (!err) {
379 if (where)
380 list_add(&new->nd, where);
381 else
382 list_add_tail(&new->nd, &memtype_list);
383
384 memtype_rb_insert(&memtype_rbroot, new);
385 }
386 return err;
387}
388
352/* 389/*
353 * req_type typically has one of the: 390 * req_type typically has one of the:
354 * - _PAGE_CACHE_WB 391 * - _PAGE_CACHE_WB
@@ -364,9 +401,8 @@ static int free_ram_pages_type(u64 start, u64 end)
364int reserve_memtype(u64 start, u64 end, unsigned long req_type, 401int reserve_memtype(u64 start, u64 end, unsigned long req_type,
365 unsigned long *new_type) 402 unsigned long *new_type)
366{ 403{
367 struct memtype *new, *entry; 404 struct memtype *new;
368 unsigned long actual_type; 405 unsigned long actual_type;
369 struct list_head *where;
370 int is_range_ram; 406 int is_range_ram;
371 int err = 0; 407 int err = 0;
372 408
@@ -423,42 +459,7 @@ int reserve_memtype(u64 start, u64 end, unsigned long req_type,
423 459
424 spin_lock(&memtype_lock); 460 spin_lock(&memtype_lock);
425 461
426 /* Search for existing mapping that overlaps the current range */ 462 err = memtype_check_insert(new, new_type);
427 where = NULL;
428 list_for_each_entry(entry, &memtype_list, nd) {
429 if (end <= entry->start) {
430 where = entry->nd.prev;
431 break;
432 } else if (start <= entry->start) { /* end > entry->start */
433 err = chk_conflict(new, entry, new_type);
434 if (!err) {
435 dprintk("Overlap at 0x%Lx-0x%Lx\n",
436 entry->start, entry->end);
437 where = entry->nd.prev;
438 }
439 break;
440 } else if (start < entry->end) { /* start > entry->start */
441 err = chk_conflict(new, entry, new_type);
442 if (!err) {
443 dprintk("Overlap at 0x%Lx-0x%Lx\n",
444 entry->start, entry->end);
445
446 /*
447 * Move to right position in the linked
448 * list to add this new entry
449 */
450 list_for_each_entry_continue(entry,
451 &memtype_list, nd) {
452 if (start <= entry->start) {
453 where = entry->nd.prev;
454 break;
455 }
456 }
457 }
458 break;
459 }
460 }
461
462 if (err) { 463 if (err) {
463 printk(KERN_INFO "reserve_memtype failed 0x%Lx-0x%Lx, " 464 printk(KERN_INFO "reserve_memtype failed 0x%Lx-0x%Lx, "
464 "track %s, req %s\n", 465 "track %s, req %s\n",
@@ -469,13 +470,6 @@ int reserve_memtype(u64 start, u64 end, unsigned long req_type,
469 return err; 470 return err;
470 } 471 }
471 472
472 if (where)
473 list_add(&new->nd, where);
474 else
475 list_add_tail(&new->nd, &memtype_list);
476
477 memtype_rb_insert(&memtype_rbroot, new);
478
479 spin_unlock(&memtype_lock); 473 spin_unlock(&memtype_lock);
480 474
481 dprintk("reserve_memtype added 0x%Lx-0x%Lx, track %s, req %s, ret %s\n", 475 dprintk("reserve_memtype added 0x%Lx-0x%Lx, track %s, req %s, ret %s\n",
@@ -937,28 +931,40 @@ EXPORT_SYMBOL_GPL(pgprot_writecombine);
937#if defined(CONFIG_DEBUG_FS) && defined(CONFIG_X86_PAT) 931#if defined(CONFIG_DEBUG_FS) && defined(CONFIG_X86_PAT)
938 932
939/* get Nth element of the linked list */ 933/* get Nth element of the linked list */
940static struct memtype *memtype_get_idx(loff_t pos) 934static int copy_memtype_nth_element(struct memtype *out, loff_t pos)
941{ 935{
942 struct memtype *list_node, *print_entry; 936 struct memtype *list_node;
943 int i = 1; 937 int i = 1;
944 938
945 print_entry = kmalloc(sizeof(struct memtype), GFP_KERNEL);
946 if (!print_entry)
947 return NULL;
948
949 spin_lock(&memtype_lock);
950 list_for_each_entry(list_node, &memtype_list, nd) { 939 list_for_each_entry(list_node, &memtype_list, nd) {
951 if (pos == i) { 940 if (pos == i) {
952 *print_entry = *list_node; 941 *out = *list_node;
953 spin_unlock(&memtype_lock); 942 return 0;
954 return print_entry;
955 } 943 }
956 ++i; 944 ++i;
957 } 945 }
946 return 1;
947}
948
949static struct memtype *memtype_get_idx(loff_t pos)
950{
951 struct memtype *print_entry;
952 int ret;
953
954 print_entry = kzalloc(sizeof(struct memtype), GFP_KERNEL);
955 if (!print_entry)
956 return NULL;
957
958 spin_lock(&memtype_lock);
959 ret = copy_memtype_nth_element(print_entry, pos);
958 spin_unlock(&memtype_lock); 960 spin_unlock(&memtype_lock);
959 kfree(print_entry);
960 961
961 return NULL; 962 if (!ret) {
963 return print_entry;
964 } else {
965 kfree(print_entry);
966 return NULL;
967 }
962} 968}
963 969
964static void *memtype_seq_start(struct seq_file *seq, loff_t *pos) 970static void *memtype_seq_start(struct seq_file *seq, loff_t *pos)
diff --git a/arch/x86/mm/pat_internal.h b/arch/x86/mm/pat_internal.h
new file mode 100644
index 000000000000..6c98780eb731
--- /dev/null
+++ b/arch/x86/mm/pat_internal.h
@@ -0,0 +1,28 @@
1#ifndef __PAT_INTERNAL_H_
2#define __PAT_INTERNAL_H_
3
4extern int pat_debug_enable;
5
6#define dprintk(fmt, arg...) \
7 do { if (pat_debug_enable) printk(KERN_INFO fmt, ##arg); } while (0)
8
9struct memtype {
10 u64 start;
11 u64 end;
12 unsigned long type;
13 struct list_head nd;
14 struct rb_node rb;
15};
16
17static inline char *cattr_name(unsigned long flags)
18{
19 switch (flags & _PAGE_CACHE_MASK) {
20 case _PAGE_CACHE_UC: return "uncached";
21 case _PAGE_CACHE_UC_MINUS: return "uncached-minus";
22 case _PAGE_CACHE_WB: return "write-back";
23 case _PAGE_CACHE_WC: return "write-combining";
24 default: return "broken";
25 }
26}
27
28#endif /* __PAT_INTERNAL_H_ */