Commit 2ccb567a authored by Russell King's avatar Russell King

[ARM] Move kmalloc() and spinlocks into vm_region_alloc()

parent 8e645822
...@@ -76,19 +76,27 @@ static struct vm_region consistent_head = { ...@@ -76,19 +76,27 @@ static struct vm_region consistent_head = {
.vm_end = CONSISTENT_END, .vm_end = CONSISTENT_END,
}; };
static int vm_region_alloc(struct vm_region *head, struct vm_region *new, size_t size) static struct vm_region *
vm_region_alloc(struct vm_region *head, size_t size, int gfp)
{ {
unsigned long addr = head->vm_start, end = head->vm_end - size; unsigned long addr = head->vm_start, end = head->vm_end - size;
struct vm_region *c; unsigned long flags;
struct vm_region *c, *new;
new = kmalloc(sizeof(struct vm_region), gfp);
if (!new)
goto out;
spin_lock_irqsave(&consistent_lock, flags);
list_for_each_entry(c, &head->vm_list, vm_list) { list_for_each_entry(c, &head->vm_list, vm_list) {
if ((addr + size) < addr) if ((addr + size) < addr)
goto out; goto nospc;
if ((addr + size) <= c->vm_start) if ((addr + size) <= c->vm_start)
goto found; goto found;
addr = c->vm_end; addr = c->vm_end;
if (addr > end) if (addr > end)
goto out; goto nospc;
} }
found: found:
...@@ -99,10 +107,14 @@ static int vm_region_alloc(struct vm_region *head, struct vm_region *new, size_t ...@@ -99,10 +107,14 @@ static int vm_region_alloc(struct vm_region *head, struct vm_region *new, size_t
new->vm_start = addr; new->vm_start = addr;
new->vm_end = addr + size; new->vm_end = addr + size;
return 0; spin_unlock_irqrestore(&consistent_lock, flags);
return new;
nospc:
spin_unlock_irqrestore(&consistent_lock, flags);
kfree(new);
out: out:
return -ENOMEM; return NULL;
} }
static struct vm_region *vm_region_find(struct vm_region *head, unsigned long addr) static struct vm_region *vm_region_find(struct vm_region *head, unsigned long addr)
...@@ -154,25 +166,11 @@ void *consistent_alloc(int gfp, size_t size, dma_addr_t *handle, ...@@ -154,25 +166,11 @@ void *consistent_alloc(int gfp, size_t size, dma_addr_t *handle,
} }
/* /*
* Our housekeeping doesn't need to come from DMA, * Allocate a virtual address in the consistent mapping region.
* but it must not come from highmem.
*/ */
c = kmalloc(sizeof(struct vm_region), c = vm_region_alloc(&consistent_head, size,
gfp & ~(__GFP_DMA | __GFP_HIGHMEM)); gfp & ~(__GFP_DMA | __GFP_HIGHMEM));
if (!c) if (c) {
goto no_remap;
/*
* Attempt to allocate a virtual address in the
* consistent mapping region.
*/
spin_lock_irqsave(&consistent_lock, flags);
res = vm_region_alloc(&consistent_head, c, size);
spin_unlock_irqrestore(&consistent_lock, flags);
if (!res) {
pte_t *pte = consistent_pte + CONSISTENT_OFFSET(c->vm_start); pte_t *pte = consistent_pte + CONSISTENT_OFFSET(c->vm_start);
struct page *end = page + (1 << order); struct page *end = page + (1 << order);
pgprot_t prot = __pgprot(L_PTE_PRESENT | L_PTE_YOUNG | pgprot_t prot = __pgprot(L_PTE_PRESENT | L_PTE_YOUNG |
...@@ -203,16 +201,13 @@ void *consistent_alloc(int gfp, size_t size, dma_addr_t *handle, ...@@ -203,16 +201,13 @@ void *consistent_alloc(int gfp, size_t size, dma_addr_t *handle,
page++; page++;
} }
ret = (void *)c->vm_start; return (void *)c->vm_start;
} }
no_remap: if (page)
if (ret == NULL) {
kfree(c);
__free_pages(page, order); __free_pages(page, order);
}
no_page: no_page:
return ret; return NULL;
} }
EXPORT_SYMBOL(consistent_alloc); EXPORT_SYMBOL(consistent_alloc);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment