linux/drivers/gpu/drm/lima/lima_object.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0 OR MIT
   2/* Copyright 2018-2019 Qiang Yu <yuq825@gmail.com> */
   3
   4#include <drm/drm_prime.h>
   5#include <linux/pagemap.h>
   6#include <linux/dma-mapping.h>
   7
   8#include "lima_object.h"
   9
  10void lima_bo_destroy(struct lima_bo *bo)
  11{
  12        if (bo->sgt) {
  13                kfree(bo->pages);
  14                drm_prime_gem_destroy(&bo->gem, bo->sgt);
  15        } else {
  16                if (bo->pages_dma_addr) {
  17                        int i, npages = bo->gem.size >> PAGE_SHIFT;
  18
  19                        for (i = 0; i < npages; i++) {
  20                                if (bo->pages_dma_addr[i])
  21                                        dma_unmap_page(bo->gem.dev->dev,
  22                                                       bo->pages_dma_addr[i],
  23                                                       PAGE_SIZE, DMA_BIDIRECTIONAL);
  24                        }
  25                }
  26
  27                if (bo->pages)
  28                        drm_gem_put_pages(&bo->gem, bo->pages, true, true);
  29        }
  30
  31        kfree(bo->pages_dma_addr);
  32        drm_gem_object_release(&bo->gem);
  33        kfree(bo);
  34}
  35
  36static struct lima_bo *lima_bo_create_struct(struct lima_device *dev, u32 size, u32 flags,
  37                                             struct reservation_object *resv)
  38{
  39        struct lima_bo *bo;
  40        int err;
  41
  42        size = PAGE_ALIGN(size);
  43
  44        bo = kzalloc(sizeof(*bo), GFP_KERNEL);
  45        if (!bo)
  46                return ERR_PTR(-ENOMEM);
  47
  48        mutex_init(&bo->lock);
  49        INIT_LIST_HEAD(&bo->va);
  50        bo->gem.resv = resv;
  51
  52        err = drm_gem_object_init(dev->ddev, &bo->gem, size);
  53        if (err) {
  54                kfree(bo);
  55                return ERR_PTR(err);
  56        }
  57
  58        return bo;
  59}
  60
  61struct lima_bo *lima_bo_create(struct lima_device *dev, u32 size,
  62                               u32 flags, struct sg_table *sgt,
  63                               struct reservation_object *resv)
  64{
  65        int i, err;
  66        size_t npages;
  67        struct lima_bo *bo, *ret;
  68
  69        bo = lima_bo_create_struct(dev, size, flags, resv);
  70        if (IS_ERR(bo))
  71                return bo;
  72
  73        npages = bo->gem.size >> PAGE_SHIFT;
  74
  75        bo->pages_dma_addr = kcalloc(npages, sizeof(dma_addr_t), GFP_KERNEL);
  76        if (!bo->pages_dma_addr) {
  77                ret = ERR_PTR(-ENOMEM);
  78                goto err_out;
  79        }
  80
  81        if (sgt) {
  82                bo->sgt = sgt;
  83
  84                bo->pages = kcalloc(npages, sizeof(*bo->pages), GFP_KERNEL);
  85                if (!bo->pages) {
  86                        ret = ERR_PTR(-ENOMEM);
  87                        goto err_out;
  88                }
  89
  90                err = drm_prime_sg_to_page_addr_arrays(
  91                        sgt, bo->pages, bo->pages_dma_addr, npages);
  92                if (err) {
  93                        ret = ERR_PTR(err);
  94                        goto err_out;
  95                }
  96        } else {
  97                mapping_set_gfp_mask(bo->gem.filp->f_mapping, GFP_DMA32);
  98                bo->pages = drm_gem_get_pages(&bo->gem);
  99                if (IS_ERR(bo->pages)) {
 100                        ret = ERR_CAST(bo->pages);
 101                        bo->pages = NULL;
 102                        goto err_out;
 103                }
 104
 105                for (i = 0; i < npages; i++) {
 106                        dma_addr_t addr = dma_map_page(dev->dev, bo->pages[i], 0,
 107                                                       PAGE_SIZE, DMA_BIDIRECTIONAL);
 108                        if (dma_mapping_error(dev->dev, addr)) {
 109                                ret = ERR_PTR(-EFAULT);
 110                                goto err_out;
 111                        }
 112                        bo->pages_dma_addr[i] = addr;
 113                }
 114
 115        }
 116
 117        return bo;
 118
 119err_out:
 120        lima_bo_destroy(bo);
 121        return ret;
 122}
 123