1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (C) 2013 Red Hat 4 * Author: Rob Clark <robdclark@gmail.com> 5 */ 6 7 #include <linux/dma-buf.h> 8 9 #include <drm/drm_drv.h> 10 #include <drm/drm_prime.h> 11 12 #include "msm_drv.h" 13 #include "msm_gem.h" 14 15 struct sg_table *msm_gem_prime_get_sg_table(struct drm_gem_object *obj) 16 { 17 struct msm_gem_object *msm_obj = to_msm_bo(obj); 18 int npages = obj->size >> PAGE_SHIFT; 19 20 if (msm_obj->flags & MSM_BO_NO_SHARE) 21 return ERR_PTR(-EINVAL); 22 23 if (WARN_ON(!msm_obj->pages)) /* should have already pinned! */ 24 return ERR_PTR(-ENOMEM); 25 26 return drm_prime_pages_to_sg(obj->dev, msm_obj->pages, npages); 27 } 28 29 int msm_gem_prime_vmap(struct drm_gem_object *obj, struct iosys_map *map) 30 { 31 void *vaddr; 32 33 vaddr = msm_gem_get_vaddr_locked(obj); 34 if (IS_ERR(vaddr)) 35 return PTR_ERR(vaddr); 36 iosys_map_set_vaddr(map, vaddr); 37 38 return 0; 39 } 40 41 void msm_gem_prime_vunmap(struct drm_gem_object *obj, struct iosys_map *map) 42 { 43 msm_gem_put_vaddr_locked(obj); 44 } 45 46 static void msm_gem_dmabuf_release(struct dma_buf *dma_buf) 47 { 48 struct drm_gem_object *obj = dma_buf->priv; 49 50 msm_gem_vma_put(obj); 51 drm_gem_dmabuf_release(dma_buf); 52 } 53 54 static const struct dma_buf_ops msm_gem_prime_dmabuf_ops = { 55 .attach = drm_gem_map_attach, 56 .detach = drm_gem_map_detach, 57 .map_dma_buf = drm_gem_map_dma_buf, 58 .unmap_dma_buf = drm_gem_unmap_dma_buf, 59 .release = msm_gem_dmabuf_release, 60 .mmap = drm_gem_dmabuf_mmap, 61 .vmap = drm_gem_dmabuf_vmap, 62 .vunmap = drm_gem_dmabuf_vunmap, 63 }; 64 65 struct drm_gem_object *msm_gem_prime_import(struct drm_device *dev, 66 struct dma_buf *buf) 67 { 68 if (buf->ops == &msm_gem_prime_dmabuf_ops) { 69 struct drm_gem_object *obj = buf->priv; 70 if (obj->dev == dev) { 71 /* 72 * Importing dmabuf exported from our own gem increases 73 * refcount on gem itself instead of f_count of dmabuf. 74 */ 75 drm_gem_object_get(obj); 76 return obj; 77 } 78 } 79 80 return drm_gem_prime_import(dev, buf); 81 } 82 83 struct drm_gem_object *msm_gem_prime_import_sg_table(struct drm_device *dev, 84 struct dma_buf_attachment *attach, struct sg_table *sg) 85 { 86 return msm_gem_import(dev, attach->dmabuf, sg); 87 } 88 89 struct dma_buf *msm_gem_prime_export(struct drm_gem_object *obj, int flags) 90 { 91 if (to_msm_bo(obj)->flags & MSM_BO_NO_SHARE) 92 return ERR_PTR(-EPERM); 93 94 msm_gem_vma_get(obj); 95 96 struct drm_device *dev = obj->dev; 97 struct dma_buf_export_info exp_info = { 98 .exp_name = KBUILD_MODNAME, /* white lie for debug */ 99 .owner = dev->driver->fops->owner, 100 .ops = &msm_gem_prime_dmabuf_ops, 101 .size = obj->size, 102 .flags = flags, 103 .priv = obj, 104 .resv = obj->resv, 105 }; 106 107 return drm_gem_dmabuf_export(dev, &exp_info); 108 } 109 110 int msm_gem_prime_pin(struct drm_gem_object *obj) 111 { 112 struct page **pages; 113 int ret = 0; 114 115 if (drm_gem_is_imported(obj)) 116 return 0; 117 118 if (to_msm_bo(obj)->flags & MSM_BO_NO_SHARE) 119 return -EINVAL; 120 121 pages = msm_gem_pin_pages_locked(obj); 122 if (IS_ERR(pages)) 123 ret = PTR_ERR(pages); 124 125 return ret; 126 } 127 128 void msm_gem_prime_unpin(struct drm_gem_object *obj) 129 { 130 if (drm_gem_is_imported(obj)) 131 return; 132 133 msm_gem_unpin_pages_locked(obj); 134 } 135