diff options
Diffstat (limited to 'drivers/gpu/drm/tegra/gem.c')
-rw-r--r-- | drivers/gpu/drm/tegra/gem.c | 180 |
1 files changed, 179 insertions, 1 deletions
diff --git a/drivers/gpu/drm/tegra/gem.c b/drivers/gpu/drm/tegra/gem.c index 7741e3355c98..ef853e558036 100644 --- a/drivers/gpu/drm/tegra/gem.c +++ b/drivers/gpu/drm/tegra/gem.c | |||
@@ -18,6 +18,7 @@ | |||
18 | * GNU General Public License for more details. | 18 | * GNU General Public License for more details. |
19 | */ | 19 | */ |
20 | 20 | ||
21 | #include <linux/dma-buf.h> | ||
21 | #include <drm/tegra_drm.h> | 22 | #include <drm/tegra_drm.h> |
22 | 23 | ||
23 | #include "gem.h" | 24 | #include "gem.h" |
@@ -173,13 +174,87 @@ err: | |||
173 | return ERR_PTR(ret); | 174 | return ERR_PTR(ret); |
174 | } | 175 | } |
175 | 176 | ||
177 | struct tegra_bo *tegra_bo_import(struct drm_device *drm, struct dma_buf *buf) | ||
178 | { | ||
179 | struct dma_buf_attachment *attach; | ||
180 | struct tegra_bo *bo; | ||
181 | ssize_t size; | ||
182 | int err; | ||
183 | |||
184 | bo = kzalloc(sizeof(*bo), GFP_KERNEL); | ||
185 | if (!bo) | ||
186 | return ERR_PTR(-ENOMEM); | ||
187 | |||
188 | host1x_bo_init(&bo->base, &tegra_bo_ops); | ||
189 | size = round_up(buf->size, PAGE_SIZE); | ||
190 | |||
191 | err = drm_gem_object_init(drm, &bo->gem, size); | ||
192 | if (err < 0) | ||
193 | goto free; | ||
194 | |||
195 | err = drm_gem_create_mmap_offset(&bo->gem); | ||
196 | if (err < 0) | ||
197 | goto release; | ||
198 | |||
199 | attach = dma_buf_attach(buf, drm->dev); | ||
200 | if (IS_ERR(attach)) { | ||
201 | err = PTR_ERR(attach); | ||
202 | goto free_mmap; | ||
203 | } | ||
204 | |||
205 | get_dma_buf(buf); | ||
206 | |||
207 | bo->sgt = dma_buf_map_attachment(attach, DMA_TO_DEVICE); | ||
208 | if (!bo->sgt) { | ||
209 | err = -ENOMEM; | ||
210 | goto detach; | ||
211 | } | ||
212 | |||
213 | if (IS_ERR(bo->sgt)) { | ||
214 | err = PTR_ERR(bo->sgt); | ||
215 | goto detach; | ||
216 | } | ||
217 | |||
218 | if (bo->sgt->nents > 1) { | ||
219 | err = -EINVAL; | ||
220 | goto detach; | ||
221 | } | ||
222 | |||
223 | bo->paddr = sg_dma_address(bo->sgt->sgl); | ||
224 | bo->gem.import_attach = attach; | ||
225 | |||
226 | return bo; | ||
227 | |||
228 | detach: | ||
229 | if (!IS_ERR_OR_NULL(bo->sgt)) | ||
230 | dma_buf_unmap_attachment(attach, bo->sgt, DMA_TO_DEVICE); | ||
231 | |||
232 | dma_buf_detach(buf, attach); | ||
233 | dma_buf_put(buf); | ||
234 | free_mmap: | ||
235 | drm_gem_free_mmap_offset(&bo->gem); | ||
236 | release: | ||
237 | drm_gem_object_release(&bo->gem); | ||
238 | free: | ||
239 | kfree(bo); | ||
240 | |||
241 | return ERR_PTR(err); | ||
242 | } | ||
243 | |||
176 | void tegra_bo_free_object(struct drm_gem_object *gem) | 244 | void tegra_bo_free_object(struct drm_gem_object *gem) |
177 | { | 245 | { |
178 | struct tegra_bo *bo = to_tegra_bo(gem); | 246 | struct tegra_bo *bo = to_tegra_bo(gem); |
179 | 247 | ||
248 | if (gem->import_attach) { | ||
249 | dma_buf_unmap_attachment(gem->import_attach, bo->sgt, | ||
250 | DMA_TO_DEVICE); | ||
251 | drm_prime_gem_destroy(gem, NULL); | ||
252 | } else { | ||
253 | tegra_bo_destroy(gem->dev, bo); | ||
254 | } | ||
255 | |||
180 | drm_gem_free_mmap_offset(gem); | 256 | drm_gem_free_mmap_offset(gem); |
181 | drm_gem_object_release(gem); | 257 | drm_gem_object_release(gem); |
182 | tegra_bo_destroy(gem->dev, bo); | ||
183 | 258 | ||
184 | kfree(bo); | 259 | kfree(bo); |
185 | } | 260 | } |
@@ -255,3 +330,106 @@ int tegra_drm_mmap(struct file *file, struct vm_area_struct *vma) | |||
255 | 330 | ||
256 | return ret; | 331 | return ret; |
257 | } | 332 | } |
333 | |||
334 | static struct sg_table * | ||
335 | tegra_gem_prime_map_dma_buf(struct dma_buf_attachment *attach, | ||
336 | enum dma_data_direction dir) | ||
337 | { | ||
338 | struct drm_gem_object *gem = attach->dmabuf->priv; | ||
339 | struct tegra_bo *bo = to_tegra_bo(gem); | ||
340 | struct sg_table *sgt; | ||
341 | |||
342 | sgt = kmalloc(sizeof(*sgt), GFP_KERNEL); | ||
343 | if (!sgt) | ||
344 | return NULL; | ||
345 | |||
346 | if (sg_alloc_table(sgt, 1, GFP_KERNEL)) { | ||
347 | kfree(sgt); | ||
348 | return NULL; | ||
349 | } | ||
350 | |||
351 | sg_dma_address(sgt->sgl) = bo->paddr; | ||
352 | sg_dma_len(sgt->sgl) = gem->size; | ||
353 | |||
354 | return sgt; | ||
355 | } | ||
356 | |||
357 | static void tegra_gem_prime_unmap_dma_buf(struct dma_buf_attachment *attach, | ||
358 | struct sg_table *sgt, | ||
359 | enum dma_data_direction dir) | ||
360 | { | ||
361 | sg_free_table(sgt); | ||
362 | kfree(sgt); | ||
363 | } | ||
364 | |||
365 | static void tegra_gem_prime_release(struct dma_buf *buf) | ||
366 | { | ||
367 | drm_gem_dmabuf_release(buf); | ||
368 | } | ||
369 | |||
370 | static void *tegra_gem_prime_kmap_atomic(struct dma_buf *buf, | ||
371 | unsigned long page) | ||
372 | { | ||
373 | return NULL; | ||
374 | } | ||
375 | |||
376 | static void tegra_gem_prime_kunmap_atomic(struct dma_buf *buf, | ||
377 | unsigned long page, | ||
378 | void *addr) | ||
379 | { | ||
380 | } | ||
381 | |||
382 | static void *tegra_gem_prime_kmap(struct dma_buf *buf, unsigned long page) | ||
383 | { | ||
384 | return NULL; | ||
385 | } | ||
386 | |||
387 | static void tegra_gem_prime_kunmap(struct dma_buf *buf, unsigned long page, | ||
388 | void *addr) | ||
389 | { | ||
390 | } | ||
391 | |||
392 | static int tegra_gem_prime_mmap(struct dma_buf *buf, struct vm_area_struct *vma) | ||
393 | { | ||
394 | return -EINVAL; | ||
395 | } | ||
396 | |||
397 | static const struct dma_buf_ops tegra_gem_prime_dmabuf_ops = { | ||
398 | .map_dma_buf = tegra_gem_prime_map_dma_buf, | ||
399 | .unmap_dma_buf = tegra_gem_prime_unmap_dma_buf, | ||
400 | .release = tegra_gem_prime_release, | ||
401 | .kmap_atomic = tegra_gem_prime_kmap_atomic, | ||
402 | .kunmap_atomic = tegra_gem_prime_kunmap_atomic, | ||
403 | .kmap = tegra_gem_prime_kmap, | ||
404 | .kunmap = tegra_gem_prime_kunmap, | ||
405 | .mmap = tegra_gem_prime_mmap, | ||
406 | }; | ||
407 | |||
408 | struct dma_buf *tegra_gem_prime_export(struct drm_device *drm, | ||
409 | struct drm_gem_object *gem, | ||
410 | int flags) | ||
411 | { | ||
412 | return dma_buf_export(gem, &tegra_gem_prime_dmabuf_ops, gem->size, | ||
413 | flags); | ||
414 | } | ||
415 | |||
416 | struct drm_gem_object *tegra_gem_prime_import(struct drm_device *drm, | ||
417 | struct dma_buf *buf) | ||
418 | { | ||
419 | struct tegra_bo *bo; | ||
420 | |||
421 | if (buf->ops == &tegra_gem_prime_dmabuf_ops) { | ||
422 | struct drm_gem_object *gem = buf->priv; | ||
423 | |||
424 | if (gem->dev == drm) { | ||
425 | drm_gem_object_reference(gem); | ||
426 | return gem; | ||
427 | } | ||
428 | } | ||
429 | |||
430 | bo = tegra_bo_import(drm, buf); | ||
431 | if (IS_ERR(bo)) | ||
432 | return ERR_CAST(bo); | ||
433 | |||
434 | return &bo->gem; | ||
435 | } | ||