upload tizen1.0 source
[kernel/linux-2.6.36.git] / drivers / media / video / videobuf2-cma.c
1 /*
2  * videobuf2-cma.c - CMA memory allocator for videobuf2
3  *
4  * Copyright (C) 2010 Samsung Electronics
5  *
6  * Author: Pawel Osciak <p.osciak@samsung.com>
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation.
11  */
12
13 #include <linux/module.h>
14 #include <linux/slab.h>
15 #include <linux/cma.h>
16 #include <linux/mm.h>
17 #include <linux/sched.h>
18 #include <linux/file.h>
19
20 #include <media/videobuf2-core.h>
21 #include <media/videobuf2-memops.h>
22
23 #include <asm/io.h>
24
25 struct vb2_cma_conf {
26         struct device           *dev;
27         const char              *type;
28         unsigned long           alignment;
29 };
30
31 struct vb2_cma_buf {
32         struct vb2_cma_conf             *conf;
33         dma_addr_t                      paddr;
34         unsigned long                   size;
35         struct vm_area_struct           *vma;
36         atomic_t                        refcount;
37         struct vb2_vmarea_handler       handler;
38 };
39
40 static void vb2_cma_put(void *buf_priv);
41
42 static void *vb2_cma_alloc(void *alloc_ctx, unsigned long size)
43 {
44         struct vb2_cma_conf *conf = alloc_ctx;
45         struct vb2_cma_buf *buf;
46
47         buf = kzalloc(sizeof *buf, GFP_KERNEL);
48         if (!buf)
49                 return ERR_PTR(-ENOMEM);
50
51         buf->paddr = cma_alloc(conf->dev, conf->type, size, conf->alignment);
52         if (IS_ERR((void *)buf->paddr)) {
53                 printk(KERN_ERR "cma_alloc of size %ld failed\n", size);
54                 kfree(buf);
55                 return ERR_PTR(-ENOMEM);
56         }
57
58         buf->conf = conf;
59         buf->size = size;
60
61         buf->handler.refcount = &buf->refcount;
62         buf->handler.put = vb2_cma_put;
63         buf->handler.arg = buf;
64
65         atomic_inc(&buf->refcount);
66
67         return buf;
68 }
69
70 static void vb2_cma_put(void *buf_priv)
71 {
72         struct vb2_cma_buf *buf = buf_priv;
73
74         if (atomic_dec_and_test(&buf->refcount)) {
75                 cma_free(buf->paddr);
76                 kfree(buf);
77         }
78 }
79
80 static void *vb2_cma_cookie(void *buf_priv)
81 {
82         struct vb2_cma_buf *buf = buf_priv;
83
84         return (void *)buf->paddr;
85 }
86
87 static unsigned int vb2_cma_num_users(void *buf_priv)
88 {
89         struct vb2_cma_buf *buf = buf_priv;
90
91         return atomic_read(&buf->refcount);
92 }
93
94 static int vb2_cma_mmap(void *buf_priv, struct vm_area_struct *vma)
95 {
96         struct vb2_cma_buf *buf = buf_priv;
97
98         if (!buf) {
99                 printk(KERN_ERR "No buffer to map\n");
100                 return -EINVAL;
101         }
102
103         return vb2_mmap_pfn_range(vma, buf->paddr, buf->size,
104                                   &vb2_common_vm_ops, &buf->handler);
105 }
106
107 static void *vb2_cma_get_userptr(void *alloc_ctx, unsigned long vaddr,
108                                  unsigned long size, int write)
109 {
110         struct vb2_cma_buf *buf;
111         struct vm_area_struct *vma;
112         dma_addr_t paddr = 0;
113         int ret;
114
115         buf = kzalloc(sizeof *buf, GFP_KERNEL);
116         if (!buf)
117                 return ERR_PTR(-ENOMEM);
118
119         ret = vb2_get_contig_userptr(vaddr, size, &vma, &paddr);
120         if (ret) {
121                 printk(KERN_ERR "Failed acquiring VMA for vaddr 0x%08lx\n",
122                                 vaddr);
123                 kfree(buf);
124                 return ERR_PTR(ret);
125         }
126
127         buf->size = size;
128         buf->paddr = paddr;
129         buf->vma = vma;
130
131         return buf;
132 }
133
134 static void vb2_cma_put_userptr(void *mem_priv)
135 {
136         struct vb2_cma_buf *buf = mem_priv;
137
138         if (!buf)
139                 return;
140
141         vb2_put_vma(buf->vma);
142         kfree(buf);
143 }
144
145 static void *vb2_cma_vaddr(void *mem_priv)
146 {
147         struct vb2_cma_buf *buf = mem_priv;
148         if (!buf)
149                 return 0;
150
151         return phys_to_virt(buf->paddr);
152 }
153
154 const struct vb2_mem_ops vb2_cma_memops = {
155         .alloc          = vb2_cma_alloc,
156         .put            = vb2_cma_put,
157         .cookie         = vb2_cma_cookie,
158         .mmap           = vb2_cma_mmap,
159         .get_userptr    = vb2_cma_get_userptr,
160         .put_userptr    = vb2_cma_put_userptr,
161         .num_users      = vb2_cma_num_users,
162         .vaddr          = vb2_cma_vaddr,
163 };
164 EXPORT_SYMBOL_GPL(vb2_cma_memops);
165
166 void *vb2_cma_init(struct device *dev, const char *type,
167                                         unsigned long alignment)
168 {
169         struct vb2_cma_conf *conf;
170
171         conf = kzalloc(sizeof *conf, GFP_KERNEL);
172         if (!conf)
173                 return ERR_PTR(-ENOMEM);
174
175         conf->dev = dev;
176         conf->type = type;
177         conf->alignment = alignment;
178
179         return conf;
180 }
181 EXPORT_SYMBOL_GPL(vb2_cma_init);
182
183 void vb2_cma_cleanup(void *conf)
184 {
185         kfree(conf);
186 }
187 EXPORT_SYMBOL_GPL(vb2_cma_cleanup);
188
189 void **vb2_cma_init_multi(struct device *dev,
190                                           unsigned int num_planes,
191                                           const char *types[],
192                                           unsigned long alignments[])
193 {
194         struct vb2_cma_conf *cma_conf;
195         void **alloc_ctxes;
196         unsigned int i;
197
198         alloc_ctxes = kzalloc((sizeof *alloc_ctxes + sizeof *cma_conf)
199                                 * num_planes, GFP_KERNEL);
200         if (!alloc_ctxes)
201                 return ERR_PTR(-ENOMEM);
202
203         cma_conf = (void *)(alloc_ctxes + num_planes);
204
205         for (i = 0; i < num_planes; ++i, ++cma_conf) {
206                 alloc_ctxes[i] = cma_conf;
207                 cma_conf->dev = dev;
208                 cma_conf->type = types[i];
209                 cma_conf->alignment = alignments[i];
210         }
211
212         return alloc_ctxes;
213 }
214 EXPORT_SYMBOL_GPL(vb2_cma_init_multi);
215
216 void vb2_cma_cleanup_multi(void **alloc_ctxes)
217 {
218         kfree(alloc_ctxes);
219 }
220 EXPORT_SYMBOL_GPL(vb2_cma_cleanup_multi);
221
222 MODULE_DESCRIPTION("CMA allocator handling routines for videobuf2");
223 MODULE_AUTHOR("Pawel Osciak");
224 MODULE_LICENSE("GPL");