linux/drivers/gpu/drm/exynos/exynos_drm_buf.c
<<
>>
Prefs
   1/* exynos_drm_buf.c
   2 *
   3 * Copyright (c) 2011 Samsung Electronics Co., Ltd.
   4 * Author: Inki Dae <inki.dae@samsung.com>
   5 *
   6 * This program is free software; you can redistribute  it and/or modify it
   7 * under  the terms of  the GNU General  Public License as published by the
   8 * Free Software Foundation;  either version 2 of the  License, or (at your
   9 * option) any later version.
  10 */
  11
  12#include <drm/drmP.h>
  13#include <drm/exynos_drm.h>
  14
  15#include "exynos_drm_drv.h"
  16#include "exynos_drm_gem.h"
  17#include "exynos_drm_buf.h"
  18#include "exynos_drm_iommu.h"
  19
  20static int lowlevel_buffer_allocate(struct drm_device *dev,
  21                unsigned int flags, struct exynos_drm_gem_buf *buf)
  22{
  23        int ret = 0;
  24        enum dma_attr attr;
  25        unsigned int nr_pages;
  26
  27        if (buf->dma_addr) {
  28                DRM_DEBUG_KMS("already allocated.\n");
  29                return 0;
  30        }
  31
  32        init_dma_attrs(&buf->dma_attrs);
  33
  34        /*
  35         * if EXYNOS_BO_CONTIG, fully physically contiguous memory
  36         * region will be allocated else physically contiguous
  37         * as possible.
  38         */
  39        if (!(flags & EXYNOS_BO_NONCONTIG))
  40                dma_set_attr(DMA_ATTR_FORCE_CONTIGUOUS, &buf->dma_attrs);
  41
  42        /*
  43         * if EXYNOS_BO_WC or EXYNOS_BO_NONCACHABLE, writecombine mapping
  44         * else cachable mapping.
  45         */
  46        if (flags & EXYNOS_BO_WC || !(flags & EXYNOS_BO_CACHABLE))
  47                attr = DMA_ATTR_WRITE_COMBINE;
  48        else
  49                attr = DMA_ATTR_NON_CONSISTENT;
  50
  51        dma_set_attr(attr, &buf->dma_attrs);
  52        dma_set_attr(DMA_ATTR_NO_KERNEL_MAPPING, &buf->dma_attrs);
  53
  54        nr_pages = buf->size >> PAGE_SHIFT;
  55
  56        if (!is_drm_iommu_supported(dev)) {
  57                dma_addr_t start_addr;
  58                unsigned int i = 0;
  59
  60                buf->pages = drm_calloc_large(nr_pages, sizeof(struct page *));
  61                if (!buf->pages) {
  62                        DRM_ERROR("failed to allocate pages.\n");
  63                        return -ENOMEM;
  64                }
  65
  66                buf->kvaddr = (void __iomem *)dma_alloc_attrs(dev->dev,
  67                                        buf->size,
  68                                        &buf->dma_addr, GFP_KERNEL,
  69                                        &buf->dma_attrs);
  70                if (!buf->kvaddr) {
  71                        DRM_ERROR("failed to allocate buffer.\n");
  72                        ret = -ENOMEM;
  73                        goto err_free;
  74                }
  75
  76                start_addr = buf->dma_addr;
  77                while (i < nr_pages) {
  78                        buf->pages[i] = phys_to_page(start_addr);
  79                        start_addr += PAGE_SIZE;
  80                        i++;
  81                }
  82        } else {
  83
  84                buf->pages = dma_alloc_attrs(dev->dev, buf->size,
  85                                        &buf->dma_addr, GFP_KERNEL,
  86                                        &buf->dma_attrs);
  87                if (!buf->pages) {
  88                        DRM_ERROR("failed to allocate buffer.\n");
  89                        return -ENOMEM;
  90                }
  91        }
  92
  93        buf->sgt = drm_prime_pages_to_sg(buf->pages, nr_pages);
  94        if (IS_ERR(buf->sgt)) {
  95                DRM_ERROR("failed to get sg table.\n");
  96                ret = PTR_ERR(buf->sgt);
  97                goto err_free_attrs;
  98        }
  99
 100        DRM_DEBUG_KMS("dma_addr(0x%lx), size(0x%lx)\n",
 101                        (unsigned long)buf->dma_addr,
 102                        buf->size);
 103
 104        return ret;
 105
 106err_free_attrs:
 107        dma_free_attrs(dev->dev, buf->size, buf->pages,
 108                        (dma_addr_t)buf->dma_addr, &buf->dma_attrs);
 109        buf->dma_addr = (dma_addr_t)NULL;
 110err_free:
 111        if (!is_drm_iommu_supported(dev))
 112                drm_free_large(buf->pages);
 113
 114        return ret;
 115}
 116
 117static void lowlevel_buffer_deallocate(struct drm_device *dev,
 118                unsigned int flags, struct exynos_drm_gem_buf *buf)
 119{
 120        if (!buf->dma_addr) {
 121                DRM_DEBUG_KMS("dma_addr is invalid.\n");
 122                return;
 123        }
 124
 125        DRM_DEBUG_KMS("dma_addr(0x%lx), size(0x%lx)\n",
 126                        (unsigned long)buf->dma_addr,
 127                        buf->size);
 128
 129        sg_free_table(buf->sgt);
 130
 131        kfree(buf->sgt);
 132        buf->sgt = NULL;
 133
 134        if (!is_drm_iommu_supported(dev)) {
 135                dma_free_attrs(dev->dev, buf->size, buf->kvaddr,
 136                                (dma_addr_t)buf->dma_addr, &buf->dma_attrs);
 137                drm_free_large(buf->pages);
 138        } else
 139                dma_free_attrs(dev->dev, buf->size, buf->pages,
 140                                (dma_addr_t)buf->dma_addr, &buf->dma_attrs);
 141
 142        buf->dma_addr = (dma_addr_t)NULL;
 143}
 144
 145struct exynos_drm_gem_buf *exynos_drm_init_buf(struct drm_device *dev,
 146                                                unsigned int size)
 147{
 148        struct exynos_drm_gem_buf *buffer;
 149
 150        DRM_DEBUG_KMS("desired size = 0x%x\n", size);
 151
 152        buffer = kzalloc(sizeof(*buffer), GFP_KERNEL);
 153        if (!buffer)
 154                return NULL;
 155
 156        buffer->size = size;
 157        return buffer;
 158}
 159
 160void exynos_drm_fini_buf(struct drm_device *dev,
 161                                struct exynos_drm_gem_buf *buffer)
 162{
 163        kfree(buffer);
 164        buffer = NULL;
 165}
 166
 167int exynos_drm_alloc_buf(struct drm_device *dev,
 168                struct exynos_drm_gem_buf *buf, unsigned int flags)
 169{
 170
 171        /*
 172         * allocate memory region and set the memory information
 173         * to vaddr and dma_addr of a buffer object.
 174         */
 175        if (lowlevel_buffer_allocate(dev, flags, buf) < 0)
 176                return -ENOMEM;
 177
 178        return 0;
 179}
 180
 181void exynos_drm_free_buf(struct drm_device *dev,
 182                unsigned int flags, struct exynos_drm_gem_buf *buffer)
 183{
 184
 185        lowlevel_buffer_deallocate(dev, flags, buffer);
 186}
 187