aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mm/vmregion.c
diff options
context:
space:
mode:
authorRussell King <rmk+kernel@arm.linux.org.uk>2012-01-12 18:08:07 -0500
committerRussell King <rmk+kernel@arm.linux.org.uk>2012-01-23 05:23:57 -0500
commit45cd5290bfd358e9885c0bf47a8c46671a92f716 (patch)
treea1831403d646336b022b973fd48427263d349e8b /arch/arm/mm/vmregion.c
parent6bebb572404f96d367170fb263603cda7251f932 (diff)
ARM: add dma coherent region reporting via procfs
Add a new seqfile for reporting coherent DMA allocations. This contains the address range, size and the function which was used to allocate each region, allowing these allocations to be viewed in much the same way as /proc/vmallocinfo. The DMA coherent region has limited space, so this allows allocation failures to be viewed, as well as finding out how much space is being used. Make sure this file is only readable by root - same as vmallocinfo - to prevent information leakage. Acked-by: Nicolas Pitre <nico@linaro.org> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'arch/arm/mm/vmregion.c')
-rw-r--r--arch/arm/mm/vmregion.c76
1 files changed, 75 insertions, 1 deletions
diff --git a/arch/arm/mm/vmregion.c b/arch/arm/mm/vmregion.c
index 036fdbfdd62f..a631016e1f8f 100644
--- a/arch/arm/mm/vmregion.c
+++ b/arch/arm/mm/vmregion.c
@@ -1,5 +1,8 @@
1#include <linux/fs.h>
1#include <linux/spinlock.h> 2#include <linux/spinlock.h>
2#include <linux/list.h> 3#include <linux/list.h>
4#include <linux/proc_fs.h>
5#include <linux/seq_file.h>
3#include <linux/slab.h> 6#include <linux/slab.h>
4 7
5#include "vmregion.h" 8#include "vmregion.h"
@@ -36,7 +39,7 @@
36 39
37struct arm_vmregion * 40struct arm_vmregion *
38arm_vmregion_alloc(struct arm_vmregion_head *head, size_t align, 41arm_vmregion_alloc(struct arm_vmregion_head *head, size_t align,
39 size_t size, gfp_t gfp) 42 size_t size, gfp_t gfp, const void *caller)
40{ 43{
41 unsigned long start = head->vm_start, addr = head->vm_end; 44 unsigned long start = head->vm_start, addr = head->vm_end;
42 unsigned long flags; 45 unsigned long flags;
@@ -52,6 +55,8 @@ arm_vmregion_alloc(struct arm_vmregion_head *head, size_t align,
52 if (!new) 55 if (!new)
53 goto out; 56 goto out;
54 57
58 new->caller = caller;
59
55 spin_lock_irqsave(&head->vm_lock, flags); 60 spin_lock_irqsave(&head->vm_lock, flags);
56 61
57 addr = rounddown(addr - size, align); 62 addr = rounddown(addr - size, align);
@@ -129,3 +134,72 @@ void arm_vmregion_free(struct arm_vmregion_head *head, struct arm_vmregion *c)
129 134
130 kfree(c); 135 kfree(c);
131} 136}
137
138#ifdef CONFIG_PROC_FS
139static int arm_vmregion_show(struct seq_file *m, void *p)
140{
141 struct arm_vmregion *c = list_entry(p, struct arm_vmregion, vm_list);
142
143 seq_printf(m, "0x%08lx-0x%08lx %7lu", c->vm_start, c->vm_end,
144 c->vm_end - c->vm_start);
145 if (c->caller)
146 seq_printf(m, " %pS", (void *)c->caller);
147 seq_putc(m, '\n');
148 return 0;
149}
150
151static void *arm_vmregion_start(struct seq_file *m, loff_t *pos)
152{
153 struct arm_vmregion_head *h = m->private;
154 spin_lock_irq(&h->vm_lock);
155 return seq_list_start(&h->vm_list, *pos);
156}
157
158static void *arm_vmregion_next(struct seq_file *m, void *p, loff_t *pos)
159{
160 struct arm_vmregion_head *h = m->private;
161 return seq_list_next(p, &h->vm_list, pos);
162}
163
164static void arm_vmregion_stop(struct seq_file *m, void *p)
165{
166 struct arm_vmregion_head *h = m->private;
167 spin_unlock_irq(&h->vm_lock);
168}
169
170static 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,
175};
176
177static int arm_vmregion_open(struct inode *inode, struct file *file)
178{
179 struct arm_vmregion_head *h = PDE(inode)->data;
180 int ret = seq_open(file, &arm_vmregion_ops);
181 if (!ret) {
182 struct seq_file *m = file->private_data;
183 m->private = h;
184 }
185 return ret;
186}
187
188static const struct file_operations arm_vmregion_fops = {
189 .open = arm_vmregion_open,
190 .read = seq_read,
191 .llseek = seq_lseek,
192 .release = seq_release,
193};
194
195int arm_vmregion_create_proc(const char *path, struct arm_vmregion_head *h)
196{
197 proc_create_data(path, S_IRUSR, NULL, &arm_vmregion_fops, h);
198 return 0;
199}
200#else
201int arm_vmregion_create_proc(const char *path, struct arm_vmregion_head *h)
202{
203 return 0;
204}
205#endif