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 <linux/dma-buf.h> 21 22 #include "omap_drv.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 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 int omap_gem_dmabuf_end_cpu_access(struct dma_buf *buffer, 97 enum dma_data_direction dir) 98 { 99 struct drm_gem_object *obj = buffer->priv; 100 omap_gem_put_pages(obj); 101 return 0; 102 } 103 104 105 static void *omap_gem_dmabuf_kmap_atomic(struct dma_buf *buffer, 106 unsigned long page_num) 107 { 108 struct drm_gem_object *obj = buffer->priv; 109 struct page **pages; 110 omap_gem_get_pages(obj, &pages, false); 111 omap_gem_cpu_sync(obj, page_num); 112 return kmap_atomic(pages[page_num]); 113 } 114 115 static void omap_gem_dmabuf_kunmap_atomic(struct dma_buf *buffer, 116 unsigned long page_num, void *addr) 117 { 118 kunmap_atomic(addr); 119 } 120 121 static void *omap_gem_dmabuf_kmap(struct dma_buf *buffer, 122 unsigned long page_num) 123 { 124 struct drm_gem_object *obj = buffer->priv; 125 struct page **pages; 126 omap_gem_get_pages(obj, &pages, false); 127 omap_gem_cpu_sync(obj, page_num); 128 return kmap(pages[page_num]); 129 } 130 131 static void omap_gem_dmabuf_kunmap(struct dma_buf *buffer, 132 unsigned long page_num, void *addr) 133 { 134 struct drm_gem_object *obj = buffer->priv; 135 struct page **pages; 136 omap_gem_get_pages(obj, &pages, false); 137 kunmap(pages[page_num]); 138 } 139 140 static int omap_gem_dmabuf_mmap(struct dma_buf *buffer, 141 struct vm_area_struct *vma) 142 { 143 struct drm_gem_object *obj = buffer->priv; 144 int ret = 0; 145 146 if (WARN_ON(!obj->filp)) 147 return -EINVAL; 148 149 ret = drm_gem_mmap_obj(obj, omap_gem_mmap_size(obj), vma); 150 if (ret < 0) 151 return ret; 152 153 return omap_gem_mmap_obj(obj, vma); 154 } 155 156 static struct dma_buf_ops omap_dmabuf_ops = { 157 .map_dma_buf = omap_gem_map_dma_buf, 158 .unmap_dma_buf = omap_gem_unmap_dma_buf, 159 .release = omap_gem_dmabuf_release, 160 .begin_cpu_access = omap_gem_dmabuf_begin_cpu_access, 161 .end_cpu_access = omap_gem_dmabuf_end_cpu_access, 162 .kmap_atomic = omap_gem_dmabuf_kmap_atomic, 163 .kunmap_atomic = omap_gem_dmabuf_kunmap_atomic, 164 .kmap = omap_gem_dmabuf_kmap, 165 .kunmap = omap_gem_dmabuf_kunmap, 166 .mmap = omap_gem_dmabuf_mmap, 167 }; 168 169 struct dma_buf *omap_gem_prime_export(struct drm_device *dev, 170 struct drm_gem_object *obj, int flags) 171 { 172 DEFINE_DMA_BUF_EXPORT_INFO(exp_info); 173 174 exp_info.ops = &omap_dmabuf_ops; 175 exp_info.size = obj->size; 176 exp_info.flags = flags; 177 exp_info.priv = obj; 178 179 return dma_buf_export(&exp_info); 180 } 181 182 struct drm_gem_object *omap_gem_prime_import(struct drm_device *dev, 183 struct dma_buf *buffer) 184 { 185 struct drm_gem_object *obj; 186 187 /* is this one of own objects? */ 188 if (buffer->ops == &omap_dmabuf_ops) { 189 obj = buffer->priv; 190 /* is it from our device? */ 191 if (obj->dev == dev) { 192 /* 193 * Importing dmabuf exported from out own gem increases 194 * refcount on gem itself instead of f_count of dmabuf. 195 */ 196 drm_gem_object_reference(obj); 197 return obj; 198 } 199 } 200 201 /* 202 * TODO add support for importing buffers from other devices.. 203 * for now we don't need this but would be nice to add eventually 204 */ 205 return ERR_PTR(-EINVAL); 206 } 207