2 #include <linux/spinlock.h>
3 #include <linux/list.h>
4 #include <linux/proc_fs.h>
5 #include <linux/seq_file.h>
6 #include <linux/slab.h>
11 * VM region handling support.
13 * This should become something generic, handling VM region allocations for
14 * vmalloc and similar (ioremap, module space, etc).
16 * I envisage vmalloc()'s supporting vm_struct becoming:
19 * struct vmregion region;
20 * unsigned long flags;
21 * struct page **pages;
22 * unsigned int nr_pages;
23 * unsigned long phys_addr;
26 * get_vm_area() would then call vmregion_alloc with an appropriate
27 * struct vmregion head (eg):
29 * struct vmregion vmalloc_head = {
30 * .vm_list = LIST_HEAD_INIT(vmalloc_head.vm_list),
31 * .vm_start = VMALLOC_START,
32 * .vm_end = VMALLOC_END,
35 * However, vmalloc_head.vm_start is variable (typically, it is dependent on
36 * the amount of RAM found at boot time.) I would imagine that get_vm_area()
37 * would have to initialise this each time prior to calling vmregion_alloc().
41 arm_vmregion_alloc(struct arm_vmregion_head
*head
, size_t align
,
42 size_t size
, gfp_t gfp
, const void *caller
)
44 unsigned long start
= head
->vm_start
, addr
= head
->vm_end
;
46 struct arm_vmregion
*c
, *new;
48 if (head
->vm_end
- head
->vm_start
< size
) {
49 printk(KERN_WARNING
"%s: allocation too big (requested %#x)\n",
54 new = kmalloc(sizeof(struct arm_vmregion
), gfp
);
60 spin_lock_irqsave(&head
->vm_lock
, flags
);
62 addr
= rounddown(addr
- size
, align
);
63 list_for_each_entry_reverse(c
, &head
->vm_list
, vm_list
) {
64 if (addr
>= c
->vm_end
)
66 addr
= rounddown(c
->vm_start
- size
, align
);
73 * Insert this entry after the one we found.
75 list_add(&new->vm_list
, &c
->vm_list
);
77 new->vm_end
= addr
+ size
;
80 spin_unlock_irqrestore(&head
->vm_lock
, flags
);
84 spin_unlock_irqrestore(&head
->vm_lock
, flags
);
90 static struct arm_vmregion
*__arm_vmregion_find(struct arm_vmregion_head
*head
, unsigned long addr
)
92 struct arm_vmregion
*c
;
94 list_for_each_entry(c
, &head
->vm_list
, vm_list
) {
95 if (c
->vm_active
&& c
->vm_start
== addr
)
103 struct arm_vmregion
*arm_vmregion_find(struct arm_vmregion_head
*head
, unsigned long addr
)
105 struct arm_vmregion
*c
;
108 spin_lock_irqsave(&head
->vm_lock
, flags
);
109 c
= __arm_vmregion_find(head
, addr
);
110 spin_unlock_irqrestore(&head
->vm_lock
, flags
);
114 struct arm_vmregion
*arm_vmregion_find_remove(struct arm_vmregion_head
*head
, unsigned long addr
)
116 struct arm_vmregion
*c
;
119 spin_lock_irqsave(&head
->vm_lock
, flags
);
120 c
= __arm_vmregion_find(head
, addr
);
123 spin_unlock_irqrestore(&head
->vm_lock
, flags
);
127 void arm_vmregion_free(struct arm_vmregion_head
*head
, struct arm_vmregion
*c
)
131 spin_lock_irqsave(&head
->vm_lock
, flags
);
132 list_del(&c
->vm_list
);
133 spin_unlock_irqrestore(&head
->vm_lock
, flags
);
138 #ifdef CONFIG_PROC_FS
139 static int arm_vmregion_show(struct seq_file
*m
, void *p
)
141 struct arm_vmregion
*c
= list_entry(p
, struct arm_vmregion
, vm_list
);
143 seq_printf(m
, "0x%08lx-0x%08lx %7lu", c
->vm_start
, c
->vm_end
,
144 c
->vm_end
- c
->vm_start
);
146 seq_printf(m
, " %pS", (void *)c
->caller
);
151 static void *arm_vmregion_start(struct seq_file
*m
, loff_t
*pos
)
153 struct arm_vmregion_head
*h
= m
->private;
154 spin_lock_irq(&h
->vm_lock
);
155 return seq_list_start(&h
->vm_list
, *pos
);
158 static void *arm_vmregion_next(struct seq_file
*m
, void *p
, loff_t
*pos
)
160 struct arm_vmregion_head
*h
= m
->private;
161 return seq_list_next(p
, &h
->vm_list
, pos
);
164 static void arm_vmregion_stop(struct seq_file
*m
, void *p
)
166 struct arm_vmregion_head
*h
= m
->private;
167 spin_unlock_irq(&h
->vm_lock
);
170 static const struct seq_operations arm_vmregion_ops
= {
171 .start
= arm_vmregion_start
,
172 .stop
= arm_vmregion_stop
,
173 .next
= arm_vmregion_next
,
174 .show
= arm_vmregion_show
,
177 static int arm_vmregion_open(struct inode
*inode
, struct file
*file
)
179 struct arm_vmregion_head
*h
= PDE(inode
)->data
;
180 int ret
= seq_open(file
, &arm_vmregion_ops
);
182 struct seq_file
*m
= file
->private_data
;
188 static const struct file_operations arm_vmregion_fops
= {
189 .open
= arm_vmregion_open
,
192 .release
= seq_release
,
195 int arm_vmregion_create_proc(const char *path
, struct arm_vmregion_head
*h
)
197 proc_create_data(path
, S_IRUSR
, NULL
, &arm_vmregion_fops
, h
);
201 int arm_vmregion_create_proc(const char *path
, struct arm_vmregion_head
*h
)