| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * Copyright (c) 2015 MediaTek Inc. |
|---|
| 3 | | - * |
|---|
| 4 | | - * This program is free software; you can redistribute it and/or modify |
|---|
| 5 | | - * it under the terms of the GNU General Public License version 2 as |
|---|
| 6 | | - * published by the Free Software Foundation. |
|---|
| 7 | | - * |
|---|
| 8 | | - * This program is distributed in the hope that it will be useful, |
|---|
| 9 | | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 10 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|---|
| 11 | | - * GNU General Public License for more details. |
|---|
| 12 | 4 | */ |
|---|
| 13 | 5 | |
|---|
| 14 | | -#include <drm/drmP.h> |
|---|
| 15 | | -#include <drm/drm_gem.h> |
|---|
| 16 | 6 | #include <linux/dma-buf.h> |
|---|
| 7 | + |
|---|
| 8 | +#include <drm/drm.h> |
|---|
| 9 | +#include <drm/drm_device.h> |
|---|
| 10 | +#include <drm/drm_gem.h> |
|---|
| 11 | +#include <drm/drm_prime.h> |
|---|
| 17 | 12 | |
|---|
| 18 | 13 | #include "mtk_drm_drv.h" |
|---|
| 19 | 14 | #include "mtk_drm_gem.h" |
|---|
| .. | .. |
|---|
| 122 | 117 | goto err_handle_create; |
|---|
| 123 | 118 | |
|---|
| 124 | 119 | /* drop reference from allocate - handle holds it now. */ |
|---|
| 125 | | - drm_gem_object_put_unlocked(&mtk_gem->base); |
|---|
| 120 | + drm_gem_object_put(&mtk_gem->base); |
|---|
| 126 | 121 | |
|---|
| 127 | 122 | return 0; |
|---|
| 128 | 123 | |
|---|
| .. | .. |
|---|
| 144 | 139 | * VM_PFNMAP flag that was set by drm_gem_mmap_obj()/drm_gem_mmap(). |
|---|
| 145 | 140 | */ |
|---|
| 146 | 141 | vma->vm_flags &= ~VM_PFNMAP; |
|---|
| 147 | | - vma->vm_pgoff = 0; |
|---|
| 148 | 142 | |
|---|
| 149 | 143 | ret = dma_mmap_attrs(priv->dma_dev, vma, mtk_gem->cookie, |
|---|
| 150 | 144 | mtk_gem->dma_addr, obj->size, mtk_gem->dma_attrs); |
|---|
| .. | .. |
|---|
| 175 | 169 | return ret; |
|---|
| 176 | 170 | |
|---|
| 177 | 171 | obj = vma->vm_private_data; |
|---|
| 172 | + |
|---|
| 173 | + /* |
|---|
| 174 | + * Set vm_pgoff (used as a fake buffer offset by DRM) to 0 and map the |
|---|
| 175 | + * whole buffer from the start. |
|---|
| 176 | + */ |
|---|
| 177 | + vma->vm_pgoff = 0; |
|---|
| 178 | 178 | |
|---|
| 179 | 179 | return mtk_drm_gem_object_mmap(obj, vma); |
|---|
| 180 | 180 | } |
|---|
| .. | .. |
|---|
| 212 | 212 | struct dma_buf_attachment *attach, struct sg_table *sg) |
|---|
| 213 | 213 | { |
|---|
| 214 | 214 | struct mtk_drm_gem_obj *mtk_gem; |
|---|
| 215 | | - int ret; |
|---|
| 216 | | - struct scatterlist *s; |
|---|
| 217 | | - unsigned int i; |
|---|
| 218 | | - dma_addr_t expected; |
|---|
| 215 | + |
|---|
| 216 | + /* check if the entries in the sg_table are contiguous */ |
|---|
| 217 | + if (drm_prime_get_contiguous_size(sg) < attach->dmabuf->size) { |
|---|
| 218 | + DRM_ERROR("sg_table is not contiguous"); |
|---|
| 219 | + return ERR_PTR(-EINVAL); |
|---|
| 220 | + } |
|---|
| 219 | 221 | |
|---|
| 220 | 222 | mtk_gem = mtk_drm_gem_init(dev, attach->dmabuf->size); |
|---|
| 221 | | - |
|---|
| 222 | 223 | if (IS_ERR(mtk_gem)) |
|---|
| 223 | 224 | return ERR_CAST(mtk_gem); |
|---|
| 224 | | - |
|---|
| 225 | | - expected = sg_dma_address(sg->sgl); |
|---|
| 226 | | - for_each_sg(sg->sgl, s, sg->nents, i) { |
|---|
| 227 | | - if (sg_dma_address(s) != expected) { |
|---|
| 228 | | - DRM_ERROR("sg_table is not contiguous"); |
|---|
| 229 | | - ret = -EINVAL; |
|---|
| 230 | | - goto err_gem_free; |
|---|
| 231 | | - } |
|---|
| 232 | | - expected = sg_dma_address(s) + sg_dma_len(s); |
|---|
| 233 | | - } |
|---|
| 234 | 225 | |
|---|
| 235 | 226 | mtk_gem->dma_addr = sg_dma_address(sg->sgl); |
|---|
| 236 | 227 | mtk_gem->sg = sg; |
|---|
| 237 | 228 | |
|---|
| 238 | 229 | return &mtk_gem->base; |
|---|
| 230 | +} |
|---|
| 239 | 231 | |
|---|
| 240 | | -err_gem_free: |
|---|
| 241 | | - kfree(mtk_gem); |
|---|
| 242 | | - return ERR_PTR(ret); |
|---|
| 232 | +void *mtk_drm_gem_prime_vmap(struct drm_gem_object *obj) |
|---|
| 233 | +{ |
|---|
| 234 | + struct mtk_drm_gem_obj *mtk_gem = to_mtk_gem_obj(obj); |
|---|
| 235 | + struct sg_table *sgt; |
|---|
| 236 | + unsigned int npages; |
|---|
| 237 | + |
|---|
| 238 | + if (mtk_gem->kvaddr) |
|---|
| 239 | + return mtk_gem->kvaddr; |
|---|
| 240 | + |
|---|
| 241 | + sgt = mtk_gem_prime_get_sg_table(obj); |
|---|
| 242 | + if (IS_ERR(sgt)) |
|---|
| 243 | + return NULL; |
|---|
| 244 | + |
|---|
| 245 | + npages = obj->size >> PAGE_SHIFT; |
|---|
| 246 | + mtk_gem->pages = kcalloc(npages, sizeof(*mtk_gem->pages), GFP_KERNEL); |
|---|
| 247 | + if (!mtk_gem->pages) |
|---|
| 248 | + goto out; |
|---|
| 249 | + |
|---|
| 250 | + drm_prime_sg_to_page_addr_arrays(sgt, mtk_gem->pages, NULL, npages); |
|---|
| 251 | + |
|---|
| 252 | + mtk_gem->kvaddr = vmap(mtk_gem->pages, npages, VM_MAP, |
|---|
| 253 | + pgprot_writecombine(PAGE_KERNEL)); |
|---|
| 254 | + |
|---|
| 255 | +out: |
|---|
| 256 | + kfree(sgt); |
|---|
| 257 | + |
|---|
| 258 | + return mtk_gem->kvaddr; |
|---|
| 259 | +} |
|---|
| 260 | + |
|---|
| 261 | +void mtk_drm_gem_prime_vunmap(struct drm_gem_object *obj, void *vaddr) |
|---|
| 262 | +{ |
|---|
| 263 | + struct mtk_drm_gem_obj *mtk_gem = to_mtk_gem_obj(obj); |
|---|
| 264 | + |
|---|
| 265 | + if (!mtk_gem->pages) |
|---|
| 266 | + return; |
|---|
| 267 | + |
|---|
| 268 | + vunmap(vaddr); |
|---|
| 269 | + mtk_gem->kvaddr = 0; |
|---|
| 270 | + kfree(mtk_gem->pages); |
|---|
| 243 | 271 | } |
|---|