.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;
- 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) {
if ((addr + size) < addr)
- goto out;
+ goto nospc;
if ((addr + size) <= c->vm_start)
goto found;
addr = c->vm_end;
if (addr > end)
- goto out;
+ goto nospc;
}
found:
new->vm_start = addr;
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:
- return -ENOMEM;
+ return NULL;
}
static struct vm_region *vm_region_find(struct vm_region *head, unsigned long addr)
}
/*
- * Our housekeeping doesn't need to come from DMA,
- * but it must not come from highmem.
- */
- c = kmalloc(sizeof(struct vm_region),
- gfp & ~(__GFP_DMA | __GFP_HIGHMEM));
- if (!c)
- goto no_remap;
-
- /*
- * Attempt to allocate a virtual address in the
- * consistent mapping region.
+ * 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) {
+ c = vm_region_alloc(&consistent_head, size,
+ gfp & ~(__GFP_DMA | __GFP_HIGHMEM));
+ if (c) {
pte_t *pte = consistent_pte + CONSISTENT_OFFSET(c->vm_start);
struct page *end = page + (1 << order);
pgprot_t prot = __pgprot(L_PTE_PRESENT | L_PTE_YOUNG |
page++;
}
- ret = (void *)c->vm_start;
+ return (void *)c->vm_start;
}
- no_remap:
- if (ret == NULL) {
- kfree(c);
+ if (page)
__free_pages(page, order);
- }
no_page:
- return ret;
+ return NULL;
}
EXPORT_SYMBOL(consistent_alloc);