drm/exynos: fix DMA_ATTR_NO_KERNEL_MAPPING usage
authorCarlo Caione <carlo@caione.org>
Wed, 4 Feb 2015 09:23:19 +0000 (10:23 +0100)
committerInki Dae <inki.dae@samsung.com>
Sat, 7 Feb 2015 07:38:41 +0000 (16:38 +0900)
The Exynos DRM driver doesn't follow the correct API when dealing with
dma_{alloc, mmap, free}_attrs functions and the
DMA_ATTR_NO_KERNEL_MAPPING attribute.

When a IOMMU is not available and the DMA_ATTR_NO_KERNEL_MAPPING is
used, the driver should use the pointer returned by dma_alloc_attr() as
a cookie.

The Exynos DRM driver directly uses the non-requested virtual kernel
address returned by the DMA mapping subsystem. This just works now
because the non-IOMMU codepath doesn't obey DMA_ATTR_NO_KERNEL_MAPPING
but we need to fix it before fixing the DMA layer.

Signed-off-by: Carlo Caione <carlo@caione.org>
Acked-by: Marek Szyprowski <m.szyprowski@samsung.com>
Acked-by: Joonyoung Shim <jy0922.shim@samsung.com>
Signed-off-by: Inki Dae <inki.dae@samsung.com>
drivers/gpu/drm/exynos/exynos_drm_buf.c
drivers/gpu/drm/exynos/exynos_drm_fbdev.c
drivers/gpu/drm/exynos/exynos_drm_gem.h

index 9c8088462c26f970d42b2fb40dae86490e51d3f6..24994ba10e28af4dfc46d14c544edc36bd6f94bf 100644 (file)
@@ -63,11 +63,11 @@ static int lowlevel_buffer_allocate(struct drm_device *dev,
                        return -ENOMEM;
                }
 
-               buf->kvaddr = (void __iomem *)dma_alloc_attrs(dev->dev,
+               buf->cookie = dma_alloc_attrs(dev->dev,
                                        buf->size,
                                        &buf->dma_addr, GFP_KERNEL,
                                        &buf->dma_attrs);
-               if (!buf->kvaddr) {
+               if (!buf->cookie) {
                        DRM_ERROR("failed to allocate buffer.\n");
                        ret = -ENOMEM;
                        goto err_free;
@@ -132,7 +132,7 @@ static void lowlevel_buffer_deallocate(struct drm_device *dev,
        buf->sgt = NULL;
 
        if (!is_drm_iommu_supported(dev)) {
-               dma_free_attrs(dev->dev, buf->size, buf->kvaddr,
+               dma_free_attrs(dev->dev, buf->size, buf->cookie,
                                (dma_addr_t)buf->dma_addr, &buf->dma_attrs);
                drm_free_large(buf->pages);
        } else
index e12ea90c62371e6212fba19623c1b2034545c2f4..84f8dfe1c5ec02ec383b0d74cf615b7906388d9a 100644 (file)
@@ -79,9 +79,9 @@ static int exynos_drm_fbdev_update(struct drm_fb_helper *helper,
                                     struct drm_framebuffer *fb)
 {
        struct fb_info *fbi = helper->fbdev;
-       struct drm_device *dev = helper->dev;
        struct exynos_drm_gem_buf *buffer;
        unsigned int size = fb->width * fb->height * (fb->bits_per_pixel >> 3);
+       unsigned int nr_pages;
        unsigned long offset;
 
        drm_fb_helper_fill_fix(fbi, fb->pitches[0], fb->depth);
@@ -94,25 +94,14 @@ static int exynos_drm_fbdev_update(struct drm_fb_helper *helper,
                return -EFAULT;
        }
 
-       /* map pages with kernel virtual space. */
+       nr_pages = buffer->size >> PAGE_SHIFT;
+
+       buffer->kvaddr = (void __iomem *) vmap(buffer->pages,
+                       nr_pages, VM_MAP,
+                       pgprot_writecombine(PAGE_KERNEL));
        if (!buffer->kvaddr) {
-               if (is_drm_iommu_supported(dev)) {
-                       unsigned int nr_pages = buffer->size >> PAGE_SHIFT;
-
-                       buffer->kvaddr = (void __iomem *) vmap(buffer->pages,
-                                       nr_pages, VM_MAP,
-                                       pgprot_writecombine(PAGE_KERNEL));
-               } else {
-                       phys_addr_t dma_addr = buffer->dma_addr;
-                       if (dma_addr)
-                               buffer->kvaddr = (void __iomem *)phys_to_virt(dma_addr);
-                       else
-                               buffer->kvaddr = (void __iomem *)NULL;
-               }
-               if (!buffer->kvaddr) {
-                       DRM_ERROR("failed to map pages to kernel space.\n");
-                       return -EIO;
-               }
+               DRM_ERROR("failed to map pages to kernel space.\n");
+               return -EIO;
        }
 
        /* buffer count to framebuffer always is 1 at booting time. */
@@ -313,7 +302,7 @@ static void exynos_drm_fbdev_destroy(struct drm_device *dev,
        struct exynos_drm_gem_obj *exynos_gem_obj = exynos_fbd->exynos_gem_obj;
        struct drm_framebuffer *fb;
 
-       if (is_drm_iommu_supported(dev) && exynos_gem_obj->buffer->kvaddr)
+       if (exynos_gem_obj->buffer->kvaddr)
                vunmap(exynos_gem_obj->buffer->kvaddr);
 
        /* release drm framebuffer and real buffer */
index ec58fe9c40df5814da0e10ebc95d6186bf6fbb2e..308173cb4f0a0dc3bd8ceb9492d85ba890f155cf 100644 (file)
@@ -22,6 +22,7 @@
 /*
  * exynos drm gem buffer structure.
  *
+ * @cookie: cookie returned by dma_alloc_attrs
  * @kvaddr: kernel virtual address to allocated memory region.
  * *userptr: user space address.
  * @dma_addr: bus address(accessed by dma) to allocated memory region.
@@ -35,6 +36,7 @@
  *     VM_PFNMAP or not.
  */
 struct exynos_drm_gem_buf {
+       void                    *cookie;
        void __iomem            *kvaddr;
        unsigned long           userptr;
        dma_addr_t              dma_addr;