Loading drivers/gpu/drm/tegra/drm.c +7 −1 Original line number Diff line number Diff line Loading @@ -580,7 +580,7 @@ static void tegra_debugfs_cleanup(struct drm_minor *minor) #endif static struct drm_driver tegra_drm_driver = { .driver_features = DRIVER_MODESET | DRIVER_GEM, .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME, .load = tegra_drm_load, .unload = tegra_drm_unload, .open = tegra_drm_open, Loading @@ -598,6 +598,12 @@ static struct drm_driver tegra_drm_driver = { .gem_free_object = tegra_bo_free_object, .gem_vm_ops = &tegra_bo_vm_ops, .prime_handle_to_fd = drm_gem_prime_handle_to_fd, .prime_fd_to_handle = drm_gem_prime_fd_to_handle, .gem_prime_export = tegra_gem_prime_export, .gem_prime_import = tegra_gem_prime_import, .dumb_create = tegra_bo_dumb_create, .dumb_map_offset = tegra_bo_dumb_map_offset, .dumb_destroy = drm_gem_dumb_destroy, Loading drivers/gpu/drm/tegra/gem.c +179 −1 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ * GNU General Public License for more details. */ #include <linux/dma-buf.h> #include <drm/tegra_drm.h> #include "gem.h" Loading Loading @@ -173,13 +174,87 @@ struct tegra_bo *tegra_bo_create_with_handle(struct drm_file *file, return ERR_PTR(ret); } struct tegra_bo *tegra_bo_import(struct drm_device *drm, struct dma_buf *buf) { struct dma_buf_attachment *attach; struct tegra_bo *bo; ssize_t size; int err; bo = kzalloc(sizeof(*bo), GFP_KERNEL); if (!bo) return ERR_PTR(-ENOMEM); host1x_bo_init(&bo->base, &tegra_bo_ops); size = round_up(buf->size, PAGE_SIZE); err = drm_gem_object_init(drm, &bo->gem, size); if (err < 0) goto free; err = drm_gem_create_mmap_offset(&bo->gem); if (err < 0) goto release; attach = dma_buf_attach(buf, drm->dev); if (IS_ERR(attach)) { err = PTR_ERR(attach); goto free_mmap; } get_dma_buf(buf); bo->sgt = dma_buf_map_attachment(attach, DMA_TO_DEVICE); if (!bo->sgt) { err = -ENOMEM; goto detach; } if (IS_ERR(bo->sgt)) { err = PTR_ERR(bo->sgt); goto detach; } if (bo->sgt->nents > 1) { err = -EINVAL; goto detach; } bo->paddr = sg_dma_address(bo->sgt->sgl); bo->gem.import_attach = attach; return bo; detach: if (!IS_ERR_OR_NULL(bo->sgt)) dma_buf_unmap_attachment(attach, bo->sgt, DMA_TO_DEVICE); dma_buf_detach(buf, attach); dma_buf_put(buf); free_mmap: drm_gem_free_mmap_offset(&bo->gem); release: drm_gem_object_release(&bo->gem); free: kfree(bo); return ERR_PTR(err); } void tegra_bo_free_object(struct drm_gem_object *gem) { struct tegra_bo *bo = to_tegra_bo(gem); if (gem->import_attach) { dma_buf_unmap_attachment(gem->import_attach, bo->sgt, DMA_TO_DEVICE); drm_prime_gem_destroy(gem, NULL); } else { tegra_bo_destroy(gem->dev, bo); } drm_gem_free_mmap_offset(gem); drm_gem_object_release(gem); tegra_bo_destroy(gem->dev, bo); kfree(bo); } Loading Loading @@ -255,3 +330,106 @@ int tegra_drm_mmap(struct file *file, struct vm_area_struct *vma) return ret; } static struct sg_table * tegra_gem_prime_map_dma_buf(struct dma_buf_attachment *attach, enum dma_data_direction dir) { struct drm_gem_object *gem = attach->dmabuf->priv; struct tegra_bo *bo = to_tegra_bo(gem); struct sg_table *sgt; sgt = kmalloc(sizeof(*sgt), GFP_KERNEL); if (!sgt) return NULL; if (sg_alloc_table(sgt, 1, GFP_KERNEL)) { kfree(sgt); return NULL; } sg_dma_address(sgt->sgl) = bo->paddr; sg_dma_len(sgt->sgl) = gem->size; return sgt; } static void tegra_gem_prime_unmap_dma_buf(struct dma_buf_attachment *attach, struct sg_table *sgt, enum dma_data_direction dir) { sg_free_table(sgt); kfree(sgt); } static void tegra_gem_prime_release(struct dma_buf *buf) { drm_gem_dmabuf_release(buf); } static void *tegra_gem_prime_kmap_atomic(struct dma_buf *buf, unsigned long page) { return NULL; } static void tegra_gem_prime_kunmap_atomic(struct dma_buf *buf, unsigned long page, void *addr) { } static void *tegra_gem_prime_kmap(struct dma_buf *buf, unsigned long page) { return NULL; } static void tegra_gem_prime_kunmap(struct dma_buf *buf, unsigned long page, void *addr) { } static int tegra_gem_prime_mmap(struct dma_buf *buf, struct vm_area_struct *vma) { return -EINVAL; } static const struct dma_buf_ops tegra_gem_prime_dmabuf_ops = { .map_dma_buf = tegra_gem_prime_map_dma_buf, .unmap_dma_buf = tegra_gem_prime_unmap_dma_buf, .release = tegra_gem_prime_release, .kmap_atomic = tegra_gem_prime_kmap_atomic, .kunmap_atomic = tegra_gem_prime_kunmap_atomic, .kmap = tegra_gem_prime_kmap, .kunmap = tegra_gem_prime_kunmap, .mmap = tegra_gem_prime_mmap, }; struct dma_buf *tegra_gem_prime_export(struct drm_device *drm, struct drm_gem_object *gem, int flags) { return dma_buf_export(gem, &tegra_gem_prime_dmabuf_ops, gem->size, flags); } struct drm_gem_object *tegra_gem_prime_import(struct drm_device *drm, struct dma_buf *buf) { struct tegra_bo *bo; if (buf->ops == &tegra_gem_prime_dmabuf_ops) { struct drm_gem_object *gem = buf->priv; if (gem->dev == drm) { drm_gem_object_reference(gem); return gem; } } bo = tegra_bo_import(drm, buf); if (IS_ERR(bo)) return ERR_CAST(bo); return &bo->gem; } drivers/gpu/drm/tegra/gem.h +7 −0 Original line number Diff line number Diff line Loading @@ -31,6 +31,7 @@ struct tegra_bo { struct drm_gem_object gem; struct host1x_bo base; unsigned long flags; struct sg_table *sgt; dma_addr_t paddr; void *vaddr; }; Loading @@ -57,4 +58,10 @@ int tegra_drm_mmap(struct file *file, struct vm_area_struct *vma); extern const struct vm_operations_struct tegra_bo_vm_ops; struct dma_buf *tegra_gem_prime_export(struct drm_device *drm, struct drm_gem_object *gem, int flags); struct drm_gem_object *tegra_gem_prime_import(struct drm_device *drm, struct dma_buf *buf); #endif Loading
drivers/gpu/drm/tegra/drm.c +7 −1 Original line number Diff line number Diff line Loading @@ -580,7 +580,7 @@ static void tegra_debugfs_cleanup(struct drm_minor *minor) #endif static struct drm_driver tegra_drm_driver = { .driver_features = DRIVER_MODESET | DRIVER_GEM, .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME, .load = tegra_drm_load, .unload = tegra_drm_unload, .open = tegra_drm_open, Loading @@ -598,6 +598,12 @@ static struct drm_driver tegra_drm_driver = { .gem_free_object = tegra_bo_free_object, .gem_vm_ops = &tegra_bo_vm_ops, .prime_handle_to_fd = drm_gem_prime_handle_to_fd, .prime_fd_to_handle = drm_gem_prime_fd_to_handle, .gem_prime_export = tegra_gem_prime_export, .gem_prime_import = tegra_gem_prime_import, .dumb_create = tegra_bo_dumb_create, .dumb_map_offset = tegra_bo_dumb_map_offset, .dumb_destroy = drm_gem_dumb_destroy, Loading
drivers/gpu/drm/tegra/gem.c +179 −1 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ * GNU General Public License for more details. */ #include <linux/dma-buf.h> #include <drm/tegra_drm.h> #include "gem.h" Loading Loading @@ -173,13 +174,87 @@ struct tegra_bo *tegra_bo_create_with_handle(struct drm_file *file, return ERR_PTR(ret); } struct tegra_bo *tegra_bo_import(struct drm_device *drm, struct dma_buf *buf) { struct dma_buf_attachment *attach; struct tegra_bo *bo; ssize_t size; int err; bo = kzalloc(sizeof(*bo), GFP_KERNEL); if (!bo) return ERR_PTR(-ENOMEM); host1x_bo_init(&bo->base, &tegra_bo_ops); size = round_up(buf->size, PAGE_SIZE); err = drm_gem_object_init(drm, &bo->gem, size); if (err < 0) goto free; err = drm_gem_create_mmap_offset(&bo->gem); if (err < 0) goto release; attach = dma_buf_attach(buf, drm->dev); if (IS_ERR(attach)) { err = PTR_ERR(attach); goto free_mmap; } get_dma_buf(buf); bo->sgt = dma_buf_map_attachment(attach, DMA_TO_DEVICE); if (!bo->sgt) { err = -ENOMEM; goto detach; } if (IS_ERR(bo->sgt)) { err = PTR_ERR(bo->sgt); goto detach; } if (bo->sgt->nents > 1) { err = -EINVAL; goto detach; } bo->paddr = sg_dma_address(bo->sgt->sgl); bo->gem.import_attach = attach; return bo; detach: if (!IS_ERR_OR_NULL(bo->sgt)) dma_buf_unmap_attachment(attach, bo->sgt, DMA_TO_DEVICE); dma_buf_detach(buf, attach); dma_buf_put(buf); free_mmap: drm_gem_free_mmap_offset(&bo->gem); release: drm_gem_object_release(&bo->gem); free: kfree(bo); return ERR_PTR(err); } void tegra_bo_free_object(struct drm_gem_object *gem) { struct tegra_bo *bo = to_tegra_bo(gem); if (gem->import_attach) { dma_buf_unmap_attachment(gem->import_attach, bo->sgt, DMA_TO_DEVICE); drm_prime_gem_destroy(gem, NULL); } else { tegra_bo_destroy(gem->dev, bo); } drm_gem_free_mmap_offset(gem); drm_gem_object_release(gem); tegra_bo_destroy(gem->dev, bo); kfree(bo); } Loading Loading @@ -255,3 +330,106 @@ int tegra_drm_mmap(struct file *file, struct vm_area_struct *vma) return ret; } static struct sg_table * tegra_gem_prime_map_dma_buf(struct dma_buf_attachment *attach, enum dma_data_direction dir) { struct drm_gem_object *gem = attach->dmabuf->priv; struct tegra_bo *bo = to_tegra_bo(gem); struct sg_table *sgt; sgt = kmalloc(sizeof(*sgt), GFP_KERNEL); if (!sgt) return NULL; if (sg_alloc_table(sgt, 1, GFP_KERNEL)) { kfree(sgt); return NULL; } sg_dma_address(sgt->sgl) = bo->paddr; sg_dma_len(sgt->sgl) = gem->size; return sgt; } static void tegra_gem_prime_unmap_dma_buf(struct dma_buf_attachment *attach, struct sg_table *sgt, enum dma_data_direction dir) { sg_free_table(sgt); kfree(sgt); } static void tegra_gem_prime_release(struct dma_buf *buf) { drm_gem_dmabuf_release(buf); } static void *tegra_gem_prime_kmap_atomic(struct dma_buf *buf, unsigned long page) { return NULL; } static void tegra_gem_prime_kunmap_atomic(struct dma_buf *buf, unsigned long page, void *addr) { } static void *tegra_gem_prime_kmap(struct dma_buf *buf, unsigned long page) { return NULL; } static void tegra_gem_prime_kunmap(struct dma_buf *buf, unsigned long page, void *addr) { } static int tegra_gem_prime_mmap(struct dma_buf *buf, struct vm_area_struct *vma) { return -EINVAL; } static const struct dma_buf_ops tegra_gem_prime_dmabuf_ops = { .map_dma_buf = tegra_gem_prime_map_dma_buf, .unmap_dma_buf = tegra_gem_prime_unmap_dma_buf, .release = tegra_gem_prime_release, .kmap_atomic = tegra_gem_prime_kmap_atomic, .kunmap_atomic = tegra_gem_prime_kunmap_atomic, .kmap = tegra_gem_prime_kmap, .kunmap = tegra_gem_prime_kunmap, .mmap = tegra_gem_prime_mmap, }; struct dma_buf *tegra_gem_prime_export(struct drm_device *drm, struct drm_gem_object *gem, int flags) { return dma_buf_export(gem, &tegra_gem_prime_dmabuf_ops, gem->size, flags); } struct drm_gem_object *tegra_gem_prime_import(struct drm_device *drm, struct dma_buf *buf) { struct tegra_bo *bo; if (buf->ops == &tegra_gem_prime_dmabuf_ops) { struct drm_gem_object *gem = buf->priv; if (gem->dev == drm) { drm_gem_object_reference(gem); return gem; } } bo = tegra_bo_import(drm, buf); if (IS_ERR(bo)) return ERR_CAST(bo); return &bo->gem; }
drivers/gpu/drm/tegra/gem.h +7 −0 Original line number Diff line number Diff line Loading @@ -31,6 +31,7 @@ struct tegra_bo { struct drm_gem_object gem; struct host1x_bo base; unsigned long flags; struct sg_table *sgt; dma_addr_t paddr; void *vaddr; }; Loading @@ -57,4 +58,10 @@ int tegra_drm_mmap(struct file *file, struct vm_area_struct *vma); extern const struct vm_operations_struct tegra_bo_vm_ops; struct dma_buf *tegra_gem_prime_export(struct drm_device *drm, struct drm_gem_object *gem, int flags); struct drm_gem_object *tegra_gem_prime_import(struct drm_device *drm, struct dma_buf *buf); #endif