diff options
author | Pawel Osciak <p.osciak@samsung.com> | 2010-10-11 09:59:36 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2011-03-21 19:31:34 -0400 |
commit | 1a758d4e847f7743ac1b5aa79fde3ba2d8b5132b (patch) | |
tree | b5f37565157d7dd16af460b00b19cafa1b01c966 /drivers/media/video/videobuf2-dma-contig.c | |
parent | 3c18ff06d811f743d380e6436fac0143ffcf1266 (diff) |
[media] v4l: videobuf2: add DMA coherent allocator
Add an implementation of DMA coherent memory allocator and handling
routines for videobuf2, implemented on top of dma_alloc_coherent() call.
Signed-off-by: Pawel Osciak <p.osciak@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
CC: Pawel Osciak <pawel@osciak.com>
Reviewed-by: Hans Verkuil <hverkuil@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/video/videobuf2-dma-contig.c')
-rw-r--r-- | drivers/media/video/videobuf2-dma-contig.c | 185 |
1 files changed, 185 insertions, 0 deletions
diff --git a/drivers/media/video/videobuf2-dma-contig.c b/drivers/media/video/videobuf2-dma-contig.c new file mode 100644 index 000000000000..bb6a5602cf94 --- /dev/null +++ b/drivers/media/video/videobuf2-dma-contig.c | |||
@@ -0,0 +1,185 @@ | |||
1 | /* | ||
2 | * videobuf2-dma-contig.c - DMA contig 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/dma-mapping.h> | ||
16 | |||
17 | #include <media/videobuf2-core.h> | ||
18 | #include <media/videobuf2-memops.h> | ||
19 | |||
20 | struct vb2_dc_conf { | ||
21 | struct device *dev; | ||
22 | }; | ||
23 | |||
24 | struct vb2_dc_buf { | ||
25 | struct vb2_dc_conf *conf; | ||
26 | void *vaddr; | ||
27 | dma_addr_t paddr; | ||
28 | unsigned long size; | ||
29 | struct vm_area_struct *vma; | ||
30 | atomic_t refcount; | ||
31 | struct vb2_vmarea_handler handler; | ||
32 | }; | ||
33 | |||
34 | static void vb2_dma_contig_put(void *buf_priv); | ||
35 | |||
36 | static void *vb2_dma_contig_alloc(void *alloc_ctx, unsigned long size) | ||
37 | { | ||
38 | struct vb2_dc_conf *conf = alloc_ctx; | ||
39 | struct vb2_dc_buf *buf; | ||
40 | |||
41 | buf = kzalloc(sizeof *buf, GFP_KERNEL); | ||
42 | if (!buf) | ||
43 | return ERR_PTR(-ENOMEM); | ||
44 | |||
45 | buf->vaddr = dma_alloc_coherent(conf->dev, size, &buf->paddr, | ||
46 | GFP_KERNEL); | ||
47 | if (!buf->vaddr) { | ||
48 | dev_err(conf->dev, "dma_alloc_coherent of size %ld failed\n", | ||
49 | buf->size); | ||
50 | kfree(buf); | ||
51 | return ERR_PTR(-ENOMEM); | ||
52 | } | ||
53 | |||
54 | buf->conf = conf; | ||
55 | buf->size = size; | ||
56 | |||
57 | buf->handler.refcount = &buf->refcount; | ||
58 | buf->handler.put = vb2_dma_contig_put; | ||
59 | buf->handler.arg = buf; | ||
60 | |||
61 | atomic_inc(&buf->refcount); | ||
62 | |||
63 | return buf; | ||
64 | } | ||
65 | |||
66 | static void vb2_dma_contig_put(void *buf_priv) | ||
67 | { | ||
68 | struct vb2_dc_buf *buf = buf_priv; | ||
69 | |||
70 | if (atomic_dec_and_test(&buf->refcount)) { | ||
71 | dma_free_coherent(buf->conf->dev, buf->size, buf->vaddr, | ||
72 | buf->paddr); | ||
73 | kfree(buf); | ||
74 | } | ||
75 | } | ||
76 | |||
77 | static void *vb2_dma_contig_cookie(void *buf_priv) | ||
78 | { | ||
79 | struct vb2_dc_buf *buf = buf_priv; | ||
80 | |||
81 | return (void *)buf->paddr; | ||
82 | } | ||
83 | |||
84 | static void *vb2_dma_contig_vaddr(void *buf_priv) | ||
85 | { | ||
86 | struct vb2_dc_buf *buf = buf_priv; | ||
87 | if (!buf) | ||
88 | return 0; | ||
89 | |||
90 | return buf->vaddr; | ||
91 | } | ||
92 | |||
93 | static unsigned int vb2_dma_contig_num_users(void *buf_priv) | ||
94 | { | ||
95 | struct vb2_dc_buf *buf = buf_priv; | ||
96 | |||
97 | return atomic_read(&buf->refcount); | ||
98 | } | ||
99 | |||
100 | static int vb2_dma_contig_mmap(void *buf_priv, struct vm_area_struct *vma) | ||
101 | { | ||
102 | struct vb2_dc_buf *buf = buf_priv; | ||
103 | |||
104 | if (!buf) { | ||
105 | printk(KERN_ERR "No buffer to map\n"); | ||
106 | return -EINVAL; | ||
107 | } | ||
108 | |||
109 | return vb2_mmap_pfn_range(vma, buf->paddr, buf->size, | ||
110 | &vb2_common_vm_ops, &buf->handler); | ||
111 | } | ||
112 | |||
113 | static void *vb2_dma_contig_get_userptr(void *alloc_ctx, unsigned long vaddr, | ||
114 | unsigned long size, int write) | ||
115 | { | ||
116 | struct vb2_dc_buf *buf; | ||
117 | struct vm_area_struct *vma; | ||
118 | dma_addr_t paddr = 0; | ||
119 | int ret; | ||
120 | |||
121 | buf = kzalloc(sizeof *buf, GFP_KERNEL); | ||
122 | if (!buf) | ||
123 | return ERR_PTR(-ENOMEM); | ||
124 | |||
125 | ret = vb2_get_contig_userptr(vaddr, size, &vma, &paddr); | ||
126 | if (ret) { | ||
127 | printk(KERN_ERR "Failed acquiring VMA for vaddr 0x%08lx\n", | ||
128 | vaddr); | ||
129 | kfree(buf); | ||
130 | return ERR_PTR(ret); | ||
131 | } | ||
132 | |||
133 | buf->size = size; | ||
134 | buf->paddr = paddr; | ||
135 | buf->vma = vma; | ||
136 | |||
137 | return buf; | ||
138 | } | ||
139 | |||
140 | static void vb2_dma_contig_put_userptr(void *mem_priv) | ||
141 | { | ||
142 | struct vb2_dc_buf *buf = mem_priv; | ||
143 | |||
144 | if (!buf) | ||
145 | return; | ||
146 | |||
147 | vb2_put_vma(buf->vma); | ||
148 | kfree(buf); | ||
149 | } | ||
150 | |||
151 | const struct vb2_mem_ops vb2_dma_contig_memops = { | ||
152 | .alloc = vb2_dma_contig_alloc, | ||
153 | .put = vb2_dma_contig_put, | ||
154 | .cookie = vb2_dma_contig_cookie, | ||
155 | .vaddr = vb2_dma_contig_vaddr, | ||
156 | .mmap = vb2_dma_contig_mmap, | ||
157 | .get_userptr = vb2_dma_contig_get_userptr, | ||
158 | .put_userptr = vb2_dma_contig_put_userptr, | ||
159 | .num_users = vb2_dma_contig_num_users, | ||
160 | }; | ||
161 | EXPORT_SYMBOL_GPL(vb2_dma_contig_memops); | ||
162 | |||
163 | void *vb2_dma_contig_init_ctx(struct device *dev) | ||
164 | { | ||
165 | struct vb2_dc_conf *conf; | ||
166 | |||
167 | conf = kzalloc(sizeof *conf, GFP_KERNEL); | ||
168 | if (!conf) | ||
169 | return ERR_PTR(-ENOMEM); | ||
170 | |||
171 | conf->dev = dev; | ||
172 | |||
173 | return conf; | ||
174 | } | ||
175 | EXPORT_SYMBOL_GPL(vb2_dma_contig_init_ctx); | ||
176 | |||
177 | void vb2_dma_contig_cleanup_ctx(void *alloc_ctx) | ||
178 | { | ||
179 | kfree(alloc_ctx); | ||
180 | } | ||
181 | EXPORT_SYMBOL_GPL(vb2_dma_contig_cleanup_ctx); | ||
182 | |||
183 | MODULE_DESCRIPTION("DMA-contig memory handling routines for videobuf2"); | ||
184 | MODULE_AUTHOR("Pawel Osciak"); | ||
185 | MODULE_LICENSE("GPL"); | ||