linux/drivers/gpu/drm/mediatek/mtk_drm_gem.c
<<
>>
Prefs
   1/*
   2 * 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 */
  13
  14#include <drm/drmP.h>
  15#include <drm/drm_gem.h>
  16#include <linux/dma-buf.h>
  17
  18#include "mtk_drm_drv.h"
  19#include "mtk_drm_gem.h"
  20
  21static struct mtk_drm_gem_obj *mtk_drm_gem_init(struct drm_device *dev,
  22                                                unsigned long size)
  23{
  24        struct mtk_drm_gem_obj *mtk_gem_obj;
  25        int ret;
  26
  27        size = round_up(size, PAGE_SIZE);
  28
  29        mtk_gem_obj = kzalloc(sizeof(*mtk_gem_obj), GFP_KERNEL);
  30        if (!mtk_gem_obj)
  31                return ERR_PTR(-ENOMEM);
  32
  33        ret = drm_gem_object_init(dev, &mtk_gem_obj->base, size);
  34        if (ret < 0) {
  35                DRM_ERROR("failed to initialize gem object\n");
  36                kfree(mtk_gem_obj);
  37                return ERR_PTR(ret);
  38        }
  39
  40        return mtk_gem_obj;
  41}
  42
  43struct mtk_drm_gem_obj *mtk_drm_gem_create(struct drm_device *dev,
  44                                           size_t size, bool alloc_kmap)
  45{
  46        struct mtk_drm_private *priv = dev->dev_private;
  47        struct mtk_drm_gem_obj *mtk_gem;
  48        struct drm_gem_object *obj;
  49        int ret;
  50
  51        mtk_gem = mtk_drm_gem_init(dev, size);
  52        if (IS_ERR(mtk_gem))
  53                return ERR_CAST(mtk_gem);
  54
  55        obj = &mtk_gem->base;
  56
  57        mtk_gem->dma_attrs = DMA_ATTR_WRITE_COMBINE;
  58
  59        if (!alloc_kmap)
  60                mtk_gem->dma_attrs |= DMA_ATTR_NO_KERNEL_MAPPING;
  61
  62        mtk_gem->cookie = dma_alloc_attrs(priv->dma_dev, obj->size,
  63                                          &mtk_gem->dma_addr, GFP_KERNEL,
  64                                          mtk_gem->dma_attrs);
  65        if (!mtk_gem->cookie) {
  66                DRM_ERROR("failed to allocate %zx byte dma buffer", obj->size);
  67                ret = -ENOMEM;
  68                goto err_gem_free;
  69        }
  70
  71        if (alloc_kmap)
  72                mtk_gem->kvaddr = mtk_gem->cookie;
  73
  74        DRM_DEBUG_DRIVER("cookie = %p dma_addr = %pad size = %zu\n",
  75                         mtk_gem->cookie, &mtk_gem->dma_addr,
  76                         size);
  77
  78        return mtk_gem;
  79
  80err_gem_free:
  81        drm_gem_object_release(obj);
  82        kfree(mtk_gem);
  83        return ERR_PTR(ret);
  84}
  85
  86void mtk_drm_gem_free_object(struct drm_gem_object *obj)
  87{
  88        struct mtk_drm_gem_obj *mtk_gem = to_mtk_gem_obj(obj);
  89        struct mtk_drm_private *priv = obj->dev->dev_private;
  90
  91        if (mtk_gem->sg)
  92                drm_prime_gem_destroy(obj, mtk_gem->sg);
  93        else
  94                dma_free_attrs(priv->dma_dev, obj->size, mtk_gem->cookie,
  95                               mtk_gem->dma_addr, mtk_gem->dma_attrs);
  96
  97        /* release file pointer to gem object. */
  98        drm_gem_object_release(obj);
  99
 100        kfree(mtk_gem);
 101}
 102
 103int mtk_drm_gem_dumb_create(struct drm_file *file_priv, struct drm_device *dev,
 104                            struct drm_mode_create_dumb *args)
 105{
 106        struct mtk_drm_gem_obj *mtk_gem;
 107        int ret;
 108
 109        args->pitch = DIV_ROUND_UP(args->width * args->bpp, 8);
 110        args->size = args->pitch * args->height;
 111
 112        mtk_gem = mtk_drm_gem_create(dev, args->size, false);
 113        if (IS_ERR(mtk_gem))
 114                return PTR_ERR(mtk_gem);
 115
 116        /*
 117         * allocate a id of idr table where the obj is registered
 118         * and handle has the id what user can see.
 119         */
 120        ret = drm_gem_handle_create(file_priv, &mtk_gem->base, &args->handle);
 121        if (ret)
 122                goto err_handle_create;
 123
 124        /* drop reference from allocate - handle holds it now. */
 125        drm_gem_object_unreference_unlocked(&mtk_gem->base);
 126
 127        return 0;
 128
 129err_handle_create:
 130        mtk_drm_gem_free_object(&mtk_gem->base);
 131        return ret;
 132}
 133
 134int mtk_drm_gem_dumb_map_offset(struct drm_file *file_priv,
 135                                struct drm_device *dev, uint32_t handle,
 136                                uint64_t *offset)
 137{
 138        struct drm_gem_object *obj;
 139        int ret;
 140
 141        obj = drm_gem_object_lookup(file_priv, handle);
 142        if (!obj) {
 143                DRM_ERROR("failed to lookup gem object.\n");
 144                return -EINVAL;
 145        }
 146
 147        ret = drm_gem_create_mmap_offset(obj);
 148        if (ret)
 149                goto out;
 150
 151        *offset = drm_vma_node_offset_addr(&obj->vma_node);
 152        DRM_DEBUG_KMS("offset = 0x%llx\n", *offset);
 153
 154out:
 155        drm_gem_object_unreference_unlocked(obj);
 156        return ret;
 157}
 158
 159static int mtk_drm_gem_object_mmap(struct drm_gem_object *obj,
 160                                   struct vm_area_struct *vma)
 161
 162{
 163        int ret;
 164        struct mtk_drm_gem_obj *mtk_gem = to_mtk_gem_obj(obj);
 165        struct mtk_drm_private *priv = obj->dev->dev_private;
 166
 167        /*
 168         * dma_alloc_attrs() allocated a struct page table for mtk_gem, so clear
 169         * VM_PFNMAP flag that was set by drm_gem_mmap_obj()/drm_gem_mmap().
 170         */
 171        vma->vm_flags &= ~VM_PFNMAP;
 172        vma->vm_pgoff = 0;
 173
 174        ret = dma_mmap_attrs(priv->dma_dev, vma, mtk_gem->cookie,
 175                             mtk_gem->dma_addr, obj->size, mtk_gem->dma_attrs);
 176        if (ret)
 177                drm_gem_vm_close(vma);
 178
 179        return ret;
 180}
 181
 182int mtk_drm_gem_mmap_buf(struct drm_gem_object *obj, struct vm_area_struct *vma)
 183{
 184        int ret;
 185
 186        ret = drm_gem_mmap_obj(obj, obj->size, vma);
 187        if (ret)
 188                return ret;
 189
 190        return mtk_drm_gem_object_mmap(obj, vma);
 191}
 192
 193int mtk_drm_gem_mmap(struct file *filp, struct vm_area_struct *vma)
 194{
 195        struct drm_gem_object *obj;
 196        int ret;
 197
 198        ret = drm_gem_mmap(filp, vma);
 199        if (ret)
 200                return ret;
 201
 202        obj = vma->vm_private_data;
 203
 204        return mtk_drm_gem_object_mmap(obj, vma);
 205}
 206
 207/*
 208 * Allocate a sg_table for this GEM object.
 209 * Note: Both the table's contents, and the sg_table itself must be freed by
 210 *       the caller.
 211 * Returns a pointer to the newly allocated sg_table, or an ERR_PTR() error.
 212 */
 213struct sg_table *mtk_gem_prime_get_sg_table(struct drm_gem_object *obj)
 214{
 215        struct mtk_drm_gem_obj *mtk_gem = to_mtk_gem_obj(obj);
 216        struct mtk_drm_private *priv = obj->dev->dev_private;
 217        struct sg_table *sgt;
 218        int ret;
 219
 220        sgt = kzalloc(sizeof(*sgt), GFP_KERNEL);
 221        if (!sgt)
 222                return ERR_PTR(-ENOMEM);
 223
 224        ret = dma_get_sgtable_attrs(priv->dma_dev, sgt, mtk_gem->cookie,
 225                                    mtk_gem->dma_addr, obj->size,
 226                                    mtk_gem->dma_attrs);
 227        if (ret) {
 228                DRM_ERROR("failed to allocate sgt, %d\n", ret);
 229                kfree(sgt);
 230                return ERR_PTR(ret);
 231        }
 232
 233        return sgt;
 234}
 235
 236struct drm_gem_object *mtk_gem_prime_import_sg_table(struct drm_device *dev,
 237                        struct dma_buf_attachment *attach, struct sg_table *sg)
 238{
 239        struct mtk_drm_gem_obj *mtk_gem;
 240        int ret;
 241        struct scatterlist *s;
 242        unsigned int i;
 243        dma_addr_t expected;
 244
 245        mtk_gem = mtk_drm_gem_init(dev, attach->dmabuf->size);
 246
 247        if (IS_ERR(mtk_gem))
 248                return ERR_PTR(PTR_ERR(mtk_gem));
 249
 250        expected = sg_dma_address(sg->sgl);
 251        for_each_sg(sg->sgl, s, sg->nents, i) {
 252                if (sg_dma_address(s) != expected) {
 253                        DRM_ERROR("sg_table is not contiguous");
 254                        ret = -EINVAL;
 255                        goto err_gem_free;
 256                }
 257                expected = sg_dma_address(s) + sg_dma_len(s);
 258        }
 259
 260        mtk_gem->dma_addr = sg_dma_address(sg->sgl);
 261        mtk_gem->sg = sg;
 262
 263        return &mtk_gem->base;
 264
 265err_gem_free:
 266        kfree(mtk_gem);
 267        return ERR_PTR(ret);
 268}
 269