[PATCH v2] drm/exynos: use DMA_ATTR_NO_KERNEL_MAPPING attribute

Inki Dae inki.dae at samsung.com
Sun Dec 9 17:55:54 PST 2012


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 at samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park at samsung.com>
---
 drivers/gpu/drm/exynos/exynos_drm_buf.c   |   28 ++++++++++------------------
 drivers/gpu/drm/exynos/exynos_drm_fbdev.c |   18 +++++++++++++++++-
 drivers/gpu/drm/exynos/exynos_drm_gem.c   |    2 +-
 drivers/gpu/drm/exynos/exynos_drm_gem.h   |    2 ++
 4 files changed, 30 insertions(+), 20 deletions(-)

diff --git a/drivers/gpu/drm/exynos/exynos_drm_buf.c b/drivers/gpu/drm/exynos/exynos_drm_buf.c
index 72bf97b..2774e9b 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_buf.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_buf.c
@@ -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;
 
@@ -109,7 +101,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;
 }
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c
index 885ef23..f433eb7 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c
@@ -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;
diff --git a/drivers/gpu/drm/exynos/exynos_drm_gem.c b/drivers/gpu/drm/exynos/exynos_drm_gem.c
index 9922724..d48183e 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_gem.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_gem.c
@@ -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) {
diff --git a/drivers/gpu/drm/exynos/exynos_drm_gem.h b/drivers/gpu/drm/exynos/exynos_drm_gem.h
index d3ea106..f11f2af 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_gem.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_gem.h
@@ -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;
-- 
1.7.4.1



More information about the dri-devel mailing list