1 #include <linux/spinlock.h>
2 #include <linux/list.h>
3 #include <linux/slab.h>
8 * VM region handling support.
10 * This should become something generic, handling VM region allocations for
11 * vmalloc and similar (ioremap, module space, etc).
13 * I envisage vmalloc()'s supporting vm_struct becoming:
16 * struct vmregion region;
17 * unsigned long flags;
18 * struct page **pages;
19 * unsigned int nr_pages;
20 * unsigned long phys_addr;
23 * get_vm_area() would then call vmregion_alloc with an appropriate
24 * struct vmregion head (eg):
26 * struct vmregion vmalloc_head = {
27 * .vm_list = LIST_HEAD_INIT(vmalloc_head.vm_list),
28 * .vm_start = VMALLOC_START,
29 * .vm_end = VMALLOC_END,
32 * However, vmalloc_head.vm_start is variable (typically, it is dependent on
33 * the amount of RAM found at boot time.) I would imagine that get_vm_area()
34 * would have to initialise this each time prior to calling vmregion_alloc().
38 arm_vmregion_alloc(struct arm_vmregion_head
*head
, size_t align
,
39 size_t size
, gfp_t gfp
)
41 unsigned long addr
= head
->vm_start
, end
= head
->vm_end
- size
;
43 struct arm_vmregion
*c
, *new;
45 if (head
->vm_end
- head
->vm_start
< size
) {
46 printk(KERN_WARNING
"%s: allocation too big (requested %#x)\n",
51 new = kmalloc(sizeof(struct arm_vmregion
), gfp
);
55 spin_lock_irqsave(&head
->vm_lock
, flags
);
57 list_for_each_entry(c
, &head
->vm_list
, vm_list
) {
58 if ((addr
+ size
) < addr
)
60 if ((addr
+ size
) <= c
->vm_start
)
62 addr
= ALIGN(c
->vm_end
, align
);
69 * Insert this entry _before_ the one we found.
71 list_add_tail(&new->vm_list
, &c
->vm_list
);
73 new->vm_end
= addr
+ size
;
76 spin_unlock_irqrestore(&head
->vm_lock
, flags
);
80 spin_unlock_irqrestore(&head
->vm_lock
, flags
);
86 static struct arm_vmregion
*__arm_vmregion_find(struct arm_vmregion_head
*head
, unsigned long addr
)
88 struct arm_vmregion
*c
;
90 list_for_each_entry(c
, &head
->vm_list
, vm_list
) {
91 if (c
->vm_active
&& c
->vm_start
== addr
)
99 struct arm_vmregion
*arm_vmregion_find(struct arm_vmregion_head
*head
, unsigned long addr
)
101 struct arm_vmregion
*c
;
104 spin_lock_irqsave(&head
->vm_lock
, flags
);
105 c
= __arm_vmregion_find(head
, addr
);
106 spin_unlock_irqrestore(&head
->vm_lock
, flags
);
110 struct arm_vmregion
*arm_vmregion_find_remove(struct arm_vmregion_head
*head
, unsigned long addr
)
112 struct arm_vmregion
*c
;
115 spin_lock_irqsave(&head
->vm_lock
, flags
);
116 c
= __arm_vmregion_find(head
, addr
);
119 spin_unlock_irqrestore(&head
->vm_lock
, flags
);
123 void arm_vmregion_free(struct arm_vmregion_head
*head
, struct arm_vmregion
*c
)
127 spin_lock_irqsave(&head
->vm_lock
, flags
);
128 list_del(&c
->vm_list
);
129 spin_unlock_irqrestore(&head
->vm_lock
, flags
);