1 /* 2 * drivers/gpu/drm/omapdrm/omap_gem_dmabuf.c 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 20 #include "omap_drv.h" 21 22 #include <linux/dma-buf.h> 23 24 static struct sg_table *omap_gem_map_dma_buf( 25 struct dma_buf_attachment *attachment, 26 enum dma_data_direction dir) 27 { 28 struct drm_gem_object *obj = attachment->dmabuf->priv; 29 struct sg_table *sg; 30 dma_addr_t paddr; 31 int ret; 32 33 sg = kzalloc(sizeof(*sg), GFP_KERNEL); 34 if (!sg) 35 return ERR_PTR(-ENOMEM); 36 37 /* camera, etc, need physically contiguous.. but we need a 38 * better way to know this.. 39 */ 40 ret = omap_gem_get_paddr(obj, &paddr, true); 41 if (ret) 42 goto out; 43 44 ret = sg_alloc_table(sg, 1, GFP_KERNEL); 45 if (ret) 46 goto out; 47 48 sg_init_table(sg->sgl, 1); 49 sg_dma_len(sg->sgl) = obj->size; 50 sg_set_page(sg->sgl, pfn_to_page(PFN_DOWN(paddr)), obj->size, 0); 51 sg_dma_address(sg->sgl) = paddr; 52 53 /* this should be after _get_paddr() to ensure we have pages attached */ 54 omap_gem_dma_sync(obj, dir); 55 56 return sg; 57 out: 58 kfree(sg); 59 return ERR_PTR(ret); 60 } 61 62 static void omap_gem_unmap_dma_buf(struct dma_buf_attachment *attachment, 63 struct sg_table *sg, enum dma_data_direction dir) 64 { 65 struct drm_gem_object *obj = attachment->dmabuf->priv; 66 omap_gem_put_paddr(obj); 67 sg_free_table(sg); 68 kfree(sg); 69 } 70 71 static void omap_gem_dmabuf_release(struct dma_buf *buffer) 72 { 73 struct drm_gem_object *obj = buffer->priv; 74 /* release reference that was taken when dmabuf was exported 75 * in omap_gem_prime_set().. 76 */ 77 drm_gem_object_unreference_unlocked(obj); 78 } 79 80 81 static int omap_gem_dmabuf_begin_cpu_access(struct dma_buf *buffer, 82 size_t start, size_t len, enum dma_data_direction dir) 83 { 84 struct drm_gem_object *obj = buffer->priv; 85 struct page **pages; 86 if (omap_gem_flags(obj) & OMAP_BO_TILED) { 87 /* TODO we would need to pin at least part of the buffer to 88 * get de-tiled view. For now just reject it. 89 */ 90 return -ENOMEM; 91 } 92 /* make sure we have the pages: */ 93 return omap_gem_get_pages(obj, &pages, true); 94 } 95 96 static void omap_gem_dmabuf_end_cpu_access(struct dma_buf *buffer, 97 size_t start, size_t len, enum dma_data_direction dir) 98 { 99 struct drm_gem_object *obj = buffer->priv; 100 omap_gem_put_pages(obj); 101 } 102 103 104 static void *omap_gem_dmabuf_kmap_atomic(struct dma_buf *buffer, 105 unsigned long page_num) 106 { 107 struct drm_gem_object *obj = buffer->priv; 108 struct page **pages; 109 omap_gem_get_pages(obj, &pages, false); 110 omap_gem_cpu_sync(obj, page_num); 111 return kmap_atomic(pages[page_num]); 112 } 113 114 static void omap_gem_dmabuf_kunmap_atomic(struct dma_buf *buffer, 115 unsigned long page_num, void *addr) 116 { 117 kunmap_atomic(addr); 118 } 119 120 static void *omap_gem_dmabuf_kmap(struct dma_buf *buffer, 121 unsigned long page_num) 122 { 123 struct drm_gem_object *obj = buffer->priv; 124 struct page **pages; 125 omap_gem_get_pages(obj, &pages, false); 126 omap_gem_cpu_sync(obj, page_num); 127 return kmap(pages[page_num]); 128 } 129 130 static void omap_gem_dmabuf_kunmap(struct dma_buf *buffer, 131 unsigned long page_num, void *addr) 132 { 133 struct drm_gem_object *obj = buffer->priv; 134 struct page **pages; 135 omap_gem_get_pages(obj, &pages, false); 136 kunmap(pages[page_num]); 137 } 138 139 static int omap_gem_dmabuf_mmap(struct dma_buf *buffer, 140 struct vm_area_struct *vma) 141 { 142 struct drm_gem_object *obj = buffer->priv; 143 struct drm_device *dev = obj->dev; 144 int ret = 0; 145 146 if (WARN_ON(!obj->filp)) 147 return -EINVAL; 148 149 mutex_lock(&dev->struct_mutex); 150 ret = drm_gem_mmap_obj(obj, omap_gem_mmap_size(obj), vma); 151 mutex_unlock(&dev->struct_mutex); 152 if (ret < 0) 153 return ret; 154 155 return omap_gem_mmap_obj(obj, vma); 156 } 157 158 static struct dma_buf_ops omap_dmabuf_ops = { 159 .map_dma_buf = omap_gem_map_dma_buf, 160 .unmap_dma_buf = omap_gem_unmap_dma_buf, 161 .release = omap_gem_dmabuf_release, 162 .begin_cpu_access = omap_gem_dmabuf_begin_cpu_access, 163 .end_cpu_access = omap_gem_dmabuf_end_cpu_access, 164 .kmap_atomic = omap_gem_dmabuf_kmap_atomic, 165 .kunmap_atomic = omap_gem_dmabuf_kunmap_atomic, 166 .kmap = omap_gem_dmabuf_kmap, 167 .kunmap = omap_gem_dmabuf_kunmap, 168 .mmap = omap_gem_dmabuf_mmap, 169 }; 170 171 struct dma_buf *omap_gem_prime_export(struct drm_device *dev, 172 struct drm_gem_object *obj, int flags) 173 { 174 DEFINE_DMA_BUF_EXPORT_INFO(exp_info); 175 176 exp_info.ops = &omap_dmabuf_ops; 177 exp_info.size = obj->size; 178 exp_info.flags = flags; 179 exp_info.priv = obj; 180 181 return dma_buf_export(&exp_info); 182 } 183 184 struct drm_gem_object *omap_gem_prime_import(struct drm_device *dev, 185 struct dma_buf *buffer) 186 { 187 struct drm_gem_object *obj; 188 189 /* is this one of own objects? */ 190 if (buffer->ops == &omap_dmabuf_ops) { 191 obj = buffer->priv; 192 /* is it from our device? */ 193 if (obj->dev == dev) { 194 /* 195 * Importing dmabuf exported from out own gem increases 196 * refcount on gem itself instead of f_count of dmabuf. 197 */ 198 drm_gem_object_reference(obj); 199 return obj; 200 } 201 } 202 203 /* 204 * TODO add support for importing buffers from other devices.. 205 * for now we don't need this but would be nice to add eventually 206 */ 207 return ERR_PTR(-EINVAL); 208 } 209