]>
Commit | Line | Data |
---|---|---|
6ad11bc3 | 1 | /* |
8bb0daff | 2 | * drivers/gpu/drm/omapdrm/omap_gem_dmabuf.c |
6ad11bc3 RC |
3 | * |
4 | * Copyright (C) 2011 Texas Instruments | |
5 | * Author: Rob Clark <rob.clark@linaro.org> | |
6 | * | |
7 | * This program is free software; you can redistribute it and/or modify it | |
8 | * under the terms of the GNU General Public License version 2 as published by | |
9 | * the Free Software Foundation. | |
10 | * | |
11 | * This program is distributed in the hope that it will be useful, but WITHOUT | |
12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
14 | * more details. | |
15 | * | |
16 | * You should have received a copy of the GNU General Public License along with | |
17 | * this program. If not, see <http://www.gnu.org/licenses/>. | |
18 | */ | |
19 | ||
6ad11bc3 RC |
20 | #include <linux/dma-buf.h> |
21 | ||
2d278f54 LP |
22 | #include "omap_drv.h" |
23 | ||
b22e6690 LP |
24 | /* ----------------------------------------------------------------------------- |
25 | * DMABUF Export | |
26 | */ | |
27 | ||
6ad11bc3 RC |
28 | static struct sg_table *omap_gem_map_dma_buf( |
29 | struct dma_buf_attachment *attachment, | |
30 | enum dma_data_direction dir) | |
31 | { | |
32 | struct drm_gem_object *obj = attachment->dmabuf->priv; | |
33 | struct sg_table *sg; | |
34 | dma_addr_t paddr; | |
35 | int ret; | |
36 | ||
37 | sg = kzalloc(sizeof(*sg), GFP_KERNEL); | |
38 | if (!sg) | |
39 | return ERR_PTR(-ENOMEM); | |
40 | ||
41 | /* camera, etc, need physically contiguous.. but we need a | |
42 | * better way to know this.. | |
43 | */ | |
44 | ret = omap_gem_get_paddr(obj, &paddr, true); | |
45 | if (ret) | |
46 | goto out; | |
47 | ||
48 | ret = sg_alloc_table(sg, 1, GFP_KERNEL); | |
49 | if (ret) | |
50 | goto out; | |
51 | ||
52 | sg_init_table(sg->sgl, 1); | |
53 | sg_dma_len(sg->sgl) = obj->size; | |
54 | sg_set_page(sg->sgl, pfn_to_page(PFN_DOWN(paddr)), obj->size, 0); | |
55 | sg_dma_address(sg->sgl) = paddr; | |
56 | ||
8b6b569e RC |
57 | /* this should be after _get_paddr() to ensure we have pages attached */ |
58 | omap_gem_dma_sync(obj, dir); | |
59 | ||
6ad11bc3 | 60 | return sg; |
32ac1a52 CD |
61 | out: |
62 | kfree(sg); | |
63 | return ERR_PTR(ret); | |
6ad11bc3 RC |
64 | } |
65 | ||
66 | static void omap_gem_unmap_dma_buf(struct dma_buf_attachment *attachment, | |
67 | struct sg_table *sg, enum dma_data_direction dir) | |
68 | { | |
69 | struct drm_gem_object *obj = attachment->dmabuf->priv; | |
70 | omap_gem_put_paddr(obj); | |
71 | sg_free_table(sg); | |
72 | kfree(sg); | |
73 | } | |
74 | ||
75 | static void omap_gem_dmabuf_release(struct dma_buf *buffer) | |
76 | { | |
77 | struct drm_gem_object *obj = buffer->priv; | |
78 | /* release reference that was taken when dmabuf was exported | |
79 | * in omap_gem_prime_set().. | |
80 | */ | |
81 | drm_gem_object_unreference_unlocked(obj); | |
82 | } | |
83 | ||
84 | ||
85 | static int omap_gem_dmabuf_begin_cpu_access(struct dma_buf *buffer, | |
831e9da7 | 86 | enum dma_data_direction dir) |
6ad11bc3 RC |
87 | { |
88 | struct drm_gem_object *obj = buffer->priv; | |
89 | struct page **pages; | |
90 | if (omap_gem_flags(obj) & OMAP_BO_TILED) { | |
91 | /* TODO we would need to pin at least part of the buffer to | |
92 | * get de-tiled view. For now just reject it. | |
93 | */ | |
94 | return -ENOMEM; | |
95 | } | |
96 | /* make sure we have the pages: */ | |
97 | return omap_gem_get_pages(obj, &pages, true); | |
98 | } | |
99 | ||
18b862dc CW |
100 | static int omap_gem_dmabuf_end_cpu_access(struct dma_buf *buffer, |
101 | enum dma_data_direction dir) | |
6ad11bc3 RC |
102 | { |
103 | struct drm_gem_object *obj = buffer->priv; | |
104 | omap_gem_put_pages(obj); | |
18b862dc | 105 | return 0; |
6ad11bc3 RC |
106 | } |
107 | ||
108 | ||
109 | static void *omap_gem_dmabuf_kmap_atomic(struct dma_buf *buffer, | |
110 | unsigned long page_num) | |
111 | { | |
112 | struct drm_gem_object *obj = buffer->priv; | |
113 | struct page **pages; | |
114 | omap_gem_get_pages(obj, &pages, false); | |
8b6b569e | 115 | omap_gem_cpu_sync(obj, page_num); |
6ad11bc3 RC |
116 | return kmap_atomic(pages[page_num]); |
117 | } | |
118 | ||
119 | static void omap_gem_dmabuf_kunmap_atomic(struct dma_buf *buffer, | |
120 | unsigned long page_num, void *addr) | |
121 | { | |
122 | kunmap_atomic(addr); | |
123 | } | |
124 | ||
125 | static void *omap_gem_dmabuf_kmap(struct dma_buf *buffer, | |
126 | unsigned long page_num) | |
127 | { | |
128 | struct drm_gem_object *obj = buffer->priv; | |
129 | struct page **pages; | |
130 | omap_gem_get_pages(obj, &pages, false); | |
8b6b569e | 131 | omap_gem_cpu_sync(obj, page_num); |
6ad11bc3 RC |
132 | return kmap(pages[page_num]); |
133 | } | |
134 | ||
135 | static void omap_gem_dmabuf_kunmap(struct dma_buf *buffer, | |
136 | unsigned long page_num, void *addr) | |
137 | { | |
138 | struct drm_gem_object *obj = buffer->priv; | |
139 | struct page **pages; | |
140 | omap_gem_get_pages(obj, &pages, false); | |
141 | kunmap(pages[page_num]); | |
142 | } | |
143 | ||
8b6b569e RC |
144 | static int omap_gem_dmabuf_mmap(struct dma_buf *buffer, |
145 | struct vm_area_struct *vma) | |
146 | { | |
147 | struct drm_gem_object *obj = buffer->priv; | |
148 | int ret = 0; | |
149 | ||
bda3fdaa LP |
150 | ret = drm_gem_mmap_obj(obj, omap_gem_mmap_size(obj), vma); |
151 | if (ret < 0) | |
152 | return ret; | |
8b6b569e RC |
153 | |
154 | return omap_gem_mmap_obj(obj, vma); | |
155 | } | |
156 | ||
6717cd29 | 157 | static struct dma_buf_ops omap_dmabuf_ops = { |
222025e4 LP |
158 | .map_dma_buf = omap_gem_map_dma_buf, |
159 | .unmap_dma_buf = omap_gem_unmap_dma_buf, | |
160 | .release = omap_gem_dmabuf_release, | |
161 | .begin_cpu_access = omap_gem_dmabuf_begin_cpu_access, | |
162 | .end_cpu_access = omap_gem_dmabuf_end_cpu_access, | |
163 | .kmap_atomic = omap_gem_dmabuf_kmap_atomic, | |
164 | .kunmap_atomic = omap_gem_dmabuf_kunmap_atomic, | |
165 | .kmap = omap_gem_dmabuf_kmap, | |
166 | .kunmap = omap_gem_dmabuf_kunmap, | |
167 | .mmap = omap_gem_dmabuf_mmap, | |
6ad11bc3 RC |
168 | }; |
169 | ||
11d3d27b | 170 | struct dma_buf *omap_gem_prime_export(struct drm_device *dev, |
6ad11bc3 RC |
171 | struct drm_gem_object *obj, int flags) |
172 | { | |
d8fbe341 SS |
173 | DEFINE_DMA_BUF_EXPORT_INFO(exp_info); |
174 | ||
175 | exp_info.ops = &omap_dmabuf_ops; | |
176 | exp_info.size = obj->size; | |
177 | exp_info.flags = flags; | |
178 | exp_info.priv = obj; | |
179 | ||
180 | return dma_buf_export(&exp_info); | |
6ad11bc3 | 181 | } |
3080b838 | 182 | |
b22e6690 LP |
183 | /* ----------------------------------------------------------------------------- |
184 | * DMABUF Import | |
185 | */ | |
186 | ||
11d3d27b | 187 | struct drm_gem_object *omap_gem_prime_import(struct drm_device *dev, |
b22e6690 | 188 | struct dma_buf *dma_buf) |
3080b838 | 189 | { |
b22e6690 | 190 | struct dma_buf_attachment *attach; |
3080b838 | 191 | struct drm_gem_object *obj; |
b22e6690 LP |
192 | struct sg_table *sgt; |
193 | int ret; | |
3080b838 | 194 | |
b22e6690 LP |
195 | if (dma_buf->ops == &omap_dmabuf_ops) { |
196 | obj = dma_buf->priv; | |
3080b838 | 197 | if (obj->dev == dev) { |
be8a42ae SWK |
198 | /* |
199 | * Importing dmabuf exported from out own gem increases | |
200 | * refcount on gem itself instead of f_count of dmabuf. | |
201 | */ | |
3080b838 RC |
202 | drm_gem_object_reference(obj); |
203 | return obj; | |
204 | } | |
205 | } | |
206 | ||
b22e6690 LP |
207 | attach = dma_buf_attach(dma_buf, dev->dev); |
208 | if (IS_ERR(attach)) | |
209 | return ERR_CAST(attach); | |
210 | ||
211 | get_dma_buf(dma_buf); | |
212 | ||
213 | sgt = dma_buf_map_attachment(attach, DMA_BIDIRECTIONAL); | |
214 | if (IS_ERR(sgt)) { | |
215 | ret = PTR_ERR(sgt); | |
216 | goto fail_detach; | |
217 | } | |
218 | ||
219 | obj = omap_gem_new_dmabuf(dev, dma_buf->size, sgt); | |
220 | if (IS_ERR(obj)) { | |
221 | ret = PTR_ERR(obj); | |
222 | goto fail_unmap; | |
223 | } | |
224 | ||
225 | obj->import_attach = attach; | |
226 | ||
227 | return obj; | |
228 | ||
229 | fail_unmap: | |
230 | dma_buf_unmap_attachment(attach, sgt, DMA_BIDIRECTIONAL); | |
231 | fail_detach: | |
232 | dma_buf_detach(dma_buf, attach); | |
233 | dma_buf_put(dma_buf); | |
234 | ||
235 | return ERR_PTR(ret); | |
3080b838 | 236 | } |