Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 191545
b: refs/heads/master
c: 9e41a49
h: refs/heads/master
i:
  191543: 6f2103b
v: v3
  • Loading branch information
Pallipadi, Venkatesh authored and H. Peter Anvin committed Feb 18, 2010
1 parent d23d0ad commit 1a18bd2
Show file tree
Hide file tree
Showing 5 changed files with 297 additions and 206 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: be5a0c126ad1dea2128dc5aef12c87083518d1ab
refs/heads/master: 9e41a49aab88a5a6c8f4875bf10a5543bc321f2d
1 change: 1 addition & 0 deletions trunk/arch/x86/mm/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ nostackp := $(call cc-option, -fno-stack-protector)
CFLAGS_physaddr.o := $(nostackp)
CFLAGS_setup_nx.o := $(nostackp)

obj-$(CONFIG_X86_PAT) += pat_rbtree.o
obj-$(CONFIG_SMP) += tlb.o

obj-$(CONFIG_X86_32) += pgtable_32.o iomap_32.o
Expand Down
209 changes: 5 additions & 204 deletions trunk/arch/x86/mm/pat.c
Original file line number Diff line number Diff line change
Expand Up @@ -130,65 +130,7 @@ void pat_init(void)

#undef PAT

/*
* The global memtype list keeps track of memory type for specific
* physical memory areas. Conflicting memory types in different
* mappings can cause CPU cache corruption. To avoid this we keep track.
*
* The list is sorted based on starting address and can contain multiple
* entries for each address (this allows reference counting for overlapping
* areas). All the aliases have the same cache attributes of course.
* Zero attributes are represented as holes.
*
* The data structure is a list that is also organized as an rbtree
* sorted on the start address of memtype range.
*
* memtype_lock protects both the linear list and rbtree.
*/

static struct rb_root memtype_rbroot = RB_ROOT;
static LIST_HEAD(memtype_list);
static DEFINE_SPINLOCK(memtype_lock); /* protects memtype list */

static struct memtype *memtype_rb_search(struct rb_root *root, u64 start)
{
struct rb_node *node = root->rb_node;
struct memtype *last_lower = NULL;

while (node) {
struct memtype *data = container_of(node, struct memtype, rb);

if (data->start < start) {
last_lower = data;
node = node->rb_right;
} else if (data->start > start) {
node = node->rb_left;
} else
return data;
}

/* Will return NULL if there is no entry with its start <= start */
return last_lower;
}

static void memtype_rb_insert(struct rb_root *root, struct memtype *data)
{
struct rb_node **new = &(root->rb_node);
struct rb_node *parent = NULL;

while (*new) {
struct memtype *this = container_of(*new, struct memtype, rb);

parent = *new;
if (data->start <= this->start)
new = &((*new)->rb_left);
else if (data->start > this->start)
new = &((*new)->rb_right);
}

rb_link_node(&data->rb, parent, new);
rb_insert_color(&data->rb, root);
}
static DEFINE_SPINLOCK(memtype_lock); /* protects memtype accesses */

/*
* Does intersection of PAT memory type and MTRR memory type and returns
Expand Down Expand Up @@ -216,33 +158,6 @@ 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;
}

static int pat_pagerange_is_ram(unsigned long start, unsigned long end)
{
int ram_page = 0, not_rampage = 0;
Expand Down Expand Up @@ -328,64 +243,6 @@ static int free_ram_pages_type(u64 start, u64 end)
return 0;
}

static int memtype_check_insert(struct memtype *new, unsigned long *new_type)
{
struct memtype *entry;
u64 start, end;
unsigned long actual_type;
struct list_head *where;
int err = 0;

start = new->start;
end = new->end;
actual_type = new->type;

/* Search for existing mapping that overlaps the current range */
where = NULL;
list_for_each_entry(entry, &memtype_list, nd) {
if (end <= entry->start) {
where = entry->nd.prev;
break;
} else if (start <= entry->start) { /* end > entry->start */
err = chk_conflict(new, entry, new_type);
if (!err) {
dprintk("Overlap at 0x%Lx-0x%Lx\n",
entry->start, entry->end);
where = entry->nd.prev;
}
break;
} else if (start < entry->end) { /* start > entry->start */
err = chk_conflict(new, entry, new_type);
if (!err) {
dprintk("Overlap at 0x%Lx-0x%Lx\n",
entry->start, entry->end);

/*
* Move to right position in the linked
* list to add this new entry
*/
list_for_each_entry_continue(entry,
&memtype_list, nd) {
if (start <= entry->start) {
where = entry->nd.prev;
break;
}
}
}
break;
}
}
if (!err) {
if (where)
list_add(&new->nd, where);
else
list_add_tail(&new->nd, &memtype_list);

memtype_rb_insert(&memtype_rbroot, new);
}
return err;
}

/*
* req_type typically has one of the:
* - _PAGE_CACHE_WB
Expand Down Expand Up @@ -459,7 +316,7 @@ int reserve_memtype(u64 start, u64 end, unsigned long req_type,

spin_lock(&memtype_lock);

err = memtype_check_insert(new, new_type);
err = rbt_memtype_check_insert(new, new_type);
if (err) {
printk(KERN_INFO "reserve_memtype failed 0x%Lx-0x%Lx, "
"track %s, req %s\n",
Expand All @@ -481,7 +338,6 @@ int reserve_memtype(u64 start, u64 end, unsigned long req_type,

int free_memtype(u64 start, u64 end)
{
struct memtype *entry, *saved_entry;
int err = -EINVAL;
int is_range_ram;

Expand All @@ -505,46 +361,7 @@ int free_memtype(u64 start, u64 end)
}

spin_lock(&memtype_lock);

entry = memtype_rb_search(&memtype_rbroot, start);
if (unlikely(entry == NULL))
goto unlock_ret;

/*
* Saved entry points to an entry with start same or less than what
* we searched for. Now go through the list in both directions to look
* for the entry that matches with both start and end, with list stored
* in sorted start address
*/
saved_entry = entry;
list_for_each_entry_from(entry, &memtype_list, nd) {
if (entry->start == start && entry->end == end) {
rb_erase(&entry->rb, &memtype_rbroot);
list_del(&entry->nd);
kfree(entry);
err = 0;
break;
} else if (entry->start > start) {
break;
}
}

if (!err)
goto unlock_ret;

entry = saved_entry;
list_for_each_entry_reverse(entry, &memtype_list, nd) {
if (entry->start == start && entry->end == end) {
rb_erase(&entry->rb, &memtype_rbroot);
list_del(&entry->nd);
kfree(entry);
err = 0;
break;
} else if (entry->start < start) {
break;
}
}
unlock_ret:
err = rbt_memtype_erase(start, end);
spin_unlock(&memtype_lock);

if (err) {
Expand Down Expand Up @@ -593,7 +410,7 @@ static unsigned long lookup_memtype(u64 paddr)

spin_lock(&memtype_lock);

entry = memtype_rb_search(&memtype_rbroot, paddr);
entry = rbt_memtype_lookup(paddr);
if (entry != NULL)
rettype = entry->type;
else
Expand Down Expand Up @@ -930,22 +747,6 @@ EXPORT_SYMBOL_GPL(pgprot_writecombine);

#if defined(CONFIG_DEBUG_FS) && defined(CONFIG_X86_PAT)

/* get Nth element of the linked list */
static int copy_memtype_nth_element(struct memtype *out, loff_t pos)
{
struct memtype *list_node;
int i = 1;

list_for_each_entry(list_node, &memtype_list, nd) {
if (pos == i) {
*out = *list_node;
return 0;
}
++i;
}
return 1;
}

static struct memtype *memtype_get_idx(loff_t pos)
{
struct memtype *print_entry;
Expand All @@ -956,7 +757,7 @@ static struct memtype *memtype_get_idx(loff_t pos)
return NULL;

spin_lock(&memtype_lock);
ret = copy_memtype_nth_element(print_entry, pos);
ret = rbt_memtype_copy_nth_element(print_entry, pos);
spin_unlock(&memtype_lock);

if (!ret) {
Expand Down
20 changes: 19 additions & 1 deletion trunk/arch/x86/mm/pat_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ extern int pat_debug_enable;
struct memtype {
u64 start;
u64 end;
u64 subtree_max_end;
unsigned long type;
struct list_head nd;
struct rb_node rb;
};

Expand All @@ -25,4 +25,22 @@ static inline char *cattr_name(unsigned long flags)
}
}

#ifdef CONFIG_X86_PAT
extern int rbt_memtype_check_insert(struct memtype *new,
unsigned long *new_type);
extern int rbt_memtype_erase(u64 start, u64 end);
extern struct memtype *rbt_memtype_lookup(u64 addr);
extern int rbt_memtype_copy_nth_element(struct memtype *out, loff_t pos);
#else
static inline int rbt_memtype_check_insert(struct memtype *new,
unsigned long *new_type)
{ return 0; }
static inline int rbt_memtype_erase(u64 start, u64 end)
{ return 0; }
static inline struct memtype *rbt_memtype_lookup(u64 addr)
{ return NULL; }
static inline int rbt_memtype_copy_nth_element(struct memtype *out, loff_t pos)
{ return 0; }
#endif

#endif /* __PAT_INTERNAL_H_ */
Loading

0 comments on commit 1a18bd2

Please sign in to comment.