drm/exynos: use DMA_ATTR_NO_KERNEL_MAPPING attribute
authorInki Dae <inki.dae@samsung.com>
Fri, 7 Dec 2012 08:51:27 +0000 (17:51 +0900)
committerInki Dae <daeinki@gmail.com>
Thu, 13 Dec 2012 14:05:45 +0000 (06:05 -0800)
Changelog v3:
just code cleanup.

Changelog v2:
fix argument to dma_mmap_attr function.
- use pages instead of kvaddr because kvaddr is 0 with
  DMA_ATTR_NO_KERNEL_MAPPING.

Changelog v1:
When gem allocation is requested, kernel space mapping isn't needed.
But if need, such as console framebuffer, the physical pages would be
mapped with kernel space though vmap function.

Signed-off-by: Inki Dae <inki.dae@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
drivers/gpu/drm/exynos/exynos_drm_buf.c
drivers/gpu/drm/exynos/exynos_drm_fb.c
drivers/gpu/drm/exynos/exynos_drm_fbdev.c
drivers/gpu/drm/exynos/exynos_drm_gem.c
drivers/gpu/drm/exynos/exynos_drm_gem.h

index 72bf97b96ba0a676ceeea99dc0e72cfb472afbc6..9732043d91ec39d351d57922848b5b3373d80c24 100644 (file)
@@ -35,6 +35,7 @@ static int lowlevel_buffer_allocate(struct drm_device *dev,
 {
        int ret = 0;
        enum dma_attr attr = DMA_ATTR_FORCE_CONTIGUOUS;
+       unsigned int nr_pages;
 
        DRM_DEBUG_KMS("%s\n", __FILE__);
 
@@ -49,40 +50,31 @@ static int lowlevel_buffer_allocate(struct drm_device *dev,
                attr = DMA_ATTR_WRITE_COMBINE;
 
        dma_set_attr(attr, &buf->dma_attrs);
+       dma_set_attr(DMA_ATTR_NO_KERNEL_MAPPING, &buf->dma_attrs);
 
-       buf->kvaddr = dma_alloc_attrs(dev->dev, buf->size,
+       buf->pages = dma_alloc_attrs(dev->dev, buf->size,
                        &buf->dma_addr, GFP_KERNEL, &buf->dma_attrs);
-       if (!buf->kvaddr) {
+       if (!buf->pages) {
                DRM_ERROR("failed to allocate buffer.\n");
                return -ENOMEM;
        }
 
-       buf->sgt = kzalloc(sizeof(struct sg_table), GFP_KERNEL);
+       nr_pages = buf->size >> PAGE_SHIFT;
+       buf->sgt = drm_prime_pages_to_sg(buf->pages, nr_pages);
        if (!buf->sgt) {
-               DRM_ERROR("failed to allocate sg table.\n");
+               DRM_ERROR("failed to get sg table.\n");
                ret = -ENOMEM;
                goto err_free_attrs;
        }
 
-       ret = dma_get_sgtable(dev->dev, buf->sgt, buf->kvaddr, buf->dma_addr,
-                       buf->size);
-       if (ret < 0) {
-               DRM_ERROR("failed to get sgtable.\n");
-               goto err_free_sgt;
-       }
-
-       DRM_DEBUG_KMS("vaddr(0x%lx), dma_addr(0x%lx), size(0x%lx)\n",
-                       (unsigned long)buf->kvaddr,
+       DRM_DEBUG_KMS("dma_addr(0x%lx), size(0x%lx)\n",
                        (unsigned long)buf->dma_addr,
                        buf->size);
 
        return ret;
 
-err_free_sgt:
-       kfree(buf->sgt);
-       buf->sgt = NULL;
 err_free_attrs:
-       dma_free_attrs(dev->dev, buf->size, buf->kvaddr,
+       dma_free_attrs(dev->dev, buf->size, buf->pages,
                        (dma_addr_t)buf->dma_addr, &buf->dma_attrs);
        buf->dma_addr = (dma_addr_t)NULL;
 
@@ -99,8 +91,7 @@ static void lowlevel_buffer_deallocate(struct drm_device *dev,
                return;
        }
 
-       DRM_DEBUG_KMS("vaddr(0x%lx), dma_addr(0x%lx), size(0x%lx)\n",
-                       (unsigned long)buf->kvaddr,
+       DRM_DEBUG_KMS("dma_addr(0x%lx), size(0x%lx)\n",
                        (unsigned long)buf->dma_addr,
                        buf->size);
 
@@ -109,7 +100,7 @@ static void lowlevel_buffer_deallocate(struct drm_device *dev,
        kfree(buf->sgt);
        buf->sgt = NULL;
 
-       dma_free_attrs(dev->dev, buf->size, buf->kvaddr,
+       dma_free_attrs(dev->dev, buf->size, buf->pages,
                                (dma_addr_t)buf->dma_addr, &buf->dma_attrs);
        buf->dma_addr = (dma_addr_t)NULL;
 }
index 7413f4b729b07e5455a1dfc8ae7085eabd026bcd..764571c9625a211e453e0d4cc39455f171c1053a 100644 (file)
@@ -297,9 +297,7 @@ struct exynos_drm_gem_buf *exynos_drm_fb_buffer(struct drm_framebuffer *fb,
        if (!buffer)
                return NULL;
 
-       DRM_DEBUG_KMS("vaddr = 0x%lx, dma_addr = 0x%lx\n",
-                       (unsigned long)buffer->kvaddr,
-                       (unsigned long)buffer->dma_addr);
+       DRM_DEBUG_KMS("dma_addr = 0x%lx\n", (unsigned long)buffer->dma_addr);
 
        return buffer;
 }
index 885ef235d59ce56d278139ca92b74c325c9311c1..f433eb7533a97e9550f86f2f94c4f5fa173d0427 100644 (file)
@@ -65,7 +65,7 @@ static int exynos_drm_fb_mmap(struct fb_info *info,
        if (vm_size > buffer->size)
                return -EINVAL;
 
-       ret = dma_mmap_attrs(helper->dev->dev, vma, buffer->kvaddr,
+       ret = dma_mmap_attrs(helper->dev->dev, vma, buffer->pages,
                buffer->dma_addr, buffer->size, &buffer->dma_attrs);
        if (ret < 0) {
                DRM_ERROR("failed to mmap.\n");
@@ -109,6 +109,17 @@ static int exynos_drm_fbdev_update(struct drm_fb_helper *helper,
                return -EFAULT;
        }
 
+       /* map pages with kernel virtual space. */
+       if (!buffer->kvaddr) {
+               unsigned int nr_pages = buffer->size >> PAGE_SHIFT;
+               buffer->kvaddr = vmap(buffer->pages, nr_pages, VM_MAP,
+                                       pgprot_writecombine(PAGE_KERNEL));
+               if (!buffer->kvaddr) {
+                       DRM_ERROR("failed to map pages to kernel space.\n");
+                       return -EIO;
+               }
+       }
+
        /* buffer count to framebuffer always is 1 at booting time. */
        exynos_drm_fb_set_buf_cnt(fb, 1);
 
@@ -305,8 +316,13 @@ err_init:
 static void exynos_drm_fbdev_destroy(struct drm_device *dev,
                                      struct drm_fb_helper *fb_helper)
 {
+       struct exynos_drm_fbdev *exynos_fbd = to_exynos_fbdev(fb_helper);
+       struct exynos_drm_gem_obj *exynos_gem_obj = exynos_fbd->exynos_gem_obj;
        struct drm_framebuffer *fb;
 
+       if (exynos_gem_obj->buffer->kvaddr)
+               vunmap(exynos_gem_obj->buffer->kvaddr);
+
        /* release drm framebuffer and real buffer */
        if (fb_helper->fb && fb_helper->fb->funcs) {
                fb = fb_helper->fb;
index 99227246ce82b9e0471ee0d2669bd3508d43b2bb..d48183e7e056d56a8932ae06baf1bc172ce02893 100644 (file)
@@ -400,7 +400,7 @@ static int exynos_drm_gem_mmap_buffer(struct file *filp,
        if (vm_size > buffer->size)
                return -EINVAL;
 
-       ret = dma_mmap_attrs(drm_dev->dev, vma, buffer->kvaddr,
+       ret = dma_mmap_attrs(drm_dev->dev, vma, buffer->pages,
                                buffer->dma_addr, buffer->size,
                                &buffer->dma_attrs);
        if (ret < 0) {
index d3ea106a9a77a2bbb9f034eb6dc55d948faac1c3..f11f2afd5bfc58254eb0b064535ae4b8131b91c3 100644 (file)
@@ -40,6 +40,7 @@
  *     - this address could be physical address without IOMMU and
  *     device address with IOMMU.
  * @write: whether pages will be written to by the caller.
+ * @pages: Array of backing pages.
  * @sgt: sg table to transfer page data.
  * @size: size of allocated memory region.
  * @pfnmap: indicate whether memory region from userptr is mmaped with
@@ -51,6 +52,7 @@ struct exynos_drm_gem_buf {
        dma_addr_t              dma_addr;
        struct dma_attrs        dma_attrs;
        unsigned int            write;
+       struct page             **pages;
        struct sg_table         *sgt;
        unsigned long           size;
        bool                    pfnmap;