[PATCH] drm/exynos: use DMA_ATTR_NO_KERNEL_MAPPING attribute

Inki Dae inki.dae at samsung.com
Fri Dec 7 01:34:58 PST 2012


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 |   16 ++++++++++++++++
 drivers/gpu/drm/exynos/exynos_drm_gem.c   |    2 +-
 drivers/gpu/drm/exynos/exynos_drm_gem.h   |    2 ++
 4 files changed, 29 insertions(+), 19 deletions(-)

diff --git a/drivers/gpu/drm/exynos/exynos_drm_buf.c b/drivers/gpu/drm/exynos/exynos_drm_buf.c
index 72bf97b..ad18299 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..00797a9 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c
@@ -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