summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/exynos/exynos_drm_dmabuf.c
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2012-12-05 19:53:10 (GMT)
committerDave Airlie <airlied@redhat.com>2012-12-05 19:53:10 (GMT)
commit00f09afd1740c3b2a1434bf48a124b316aab19f2 (patch)
tree8e7d0c97f1ebecf326f19de32770f868c2994522 /drivers/gpu/drm/exynos/exynos_drm_dmabuf.c
parent7136470d4b37b46565b29b8b9425a8361421483b (diff)
parenta144c2e9f17b738ac47716f1fb033cbfcfcde934 (diff)
downloadlinux-fsl-qoriq-00f09afd1740c3b2a1434bf48a124b316aab19f2.tar.xz
Merge branch 'exynos-drm-next' of git://git.kernel.org/pub/scm/linux/kernel/git/daeinki/drm-exynos into drm-next
This patch set adds iommu support, userptr feature to g2d, minor fixups and code cleanups. And the iommu feature has dependency of the below patches related to dma mapping framework. This patch is used to allocate fully physically contiguous memory region. - add sending AVI and AVI info frames. . this adds some codes for composing AVI and AUI info frames and send them every VSYNC for HDMI Certification. - bug fix to previous pull request. - add some code cleanup * 'exynos-drm-next' of git://git.kernel.org/pub/scm/linux/kernel/git/daeinki/drm-exynos: (32 commits) drm/exynos: sending AVI and AUI info frames drm/exynos: Use devm_clk_get in exynos_drm_fimd.c drm/exynos: Use devm_* APIs in exynos_hdmi.c drm/exynos: Use devm_clk_get in exynos_mixer.c drm/exynos: Fix potential NULL pointer dereference drm/exynos: Use devm_clk_get in exynos_drm_g2d.c drm/exynos: use sgt instead of pages for framebuffer address drm: exynos: fix for loosing display mode header during mode adjustment drm/exynos: fix memory leak to EDID block drm/exynos: remove 'pages' and 'page_size' elements in exynos gem buffer drm/exynos: add exynos drm specific fb_mmap function drm/exynos: make sure that overlay data are updated drm/exynos: add vm_ops to specific gem mmaper drm/exynos: add userptr feature for g2d module drm/exynos: remove unnecessary sg_alloc_table call drm: exynos: fix for mapping of dma buffers drm/exynos: remove EXYNOS_BO_NONCONTIG type checking. drm/exynos: add iommu support for g2d drm/exynos: add iommu support for hdmi driver drm/exynos: add iommu support to fimd driver ...
Diffstat (limited to 'drivers/gpu/drm/exynos/exynos_drm_dmabuf.c')
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_dmabuf.c84
1 files changed, 32 insertions, 52 deletions
diff --git a/drivers/gpu/drm/exynos/exynos_drm_dmabuf.c b/drivers/gpu/drm/exynos/exynos_drm_dmabuf.c
index fae1f2e..539da9f 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_dmabuf.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_dmabuf.c
@@ -30,26 +30,22 @@
#include <linux/dma-buf.h>
-static struct sg_table *exynos_pages_to_sg(struct page **pages, int nr_pages,
- unsigned int page_size)
+static struct sg_table *exynos_get_sgt(struct drm_device *drm_dev,
+ struct exynos_drm_gem_buf *buf)
{
struct sg_table *sgt = NULL;
- struct scatterlist *sgl;
- int i, ret;
+ int ret;
sgt = kzalloc(sizeof(*sgt), GFP_KERNEL);
if (!sgt)
goto out;
- ret = sg_alloc_table(sgt, nr_pages, GFP_KERNEL);
- if (ret)
+ ret = dma_get_sgtable(drm_dev->dev, sgt, buf->kvaddr,
+ buf->dma_addr, buf->size);
+ if (ret < 0) {
+ DRM_ERROR("failed to get sgtable.\n");
goto err_free_sgt;
-
- if (page_size < PAGE_SIZE)
- page_size = PAGE_SIZE;
-
- for_each_sg(sgt->sgl, sgl, nr_pages, i)
- sg_set_page(sgl, pages[i], page_size, 0);
+ }
return sgt;
@@ -68,32 +64,30 @@ static struct sg_table *
struct drm_device *dev = gem_obj->base.dev;
struct exynos_drm_gem_buf *buf;
struct sg_table *sgt = NULL;
- unsigned int npages;
int nents;
DRM_DEBUG_PRIME("%s\n", __FILE__);
- mutex_lock(&dev->struct_mutex);
-
buf = gem_obj->buffer;
-
- /* there should always be pages allocated. */
- if (!buf->pages) {
- DRM_ERROR("pages is null.\n");
- goto err_unlock;
+ if (!buf) {
+ DRM_ERROR("buffer is null.\n");
+ return sgt;
}
- npages = buf->size / buf->page_size;
+ mutex_lock(&dev->struct_mutex);
- sgt = exynos_pages_to_sg(buf->pages, npages, buf->page_size);
- if (!sgt) {
- DRM_DEBUG_PRIME("exynos_pages_to_sg returned NULL!\n");
+ sgt = exynos_get_sgt(dev, buf);
+ if (!sgt)
goto err_unlock;
- }
+
nents = dma_map_sg(attach->dev, sgt->sgl, sgt->nents, dir);
+ if (!nents) {
+ DRM_ERROR("failed to map sgl with iommu.\n");
+ sgt = NULL;
+ goto err_unlock;
+ }
- DRM_DEBUG_PRIME("npages = %d buffer size = 0x%lx page_size = 0x%lx\n",
- npages, buf->size, buf->page_size);
+ DRM_DEBUG_PRIME("buffer size = 0x%lx\n", buf->size);
err_unlock:
mutex_unlock(&dev->struct_mutex);
@@ -105,6 +99,7 @@ static void exynos_gem_unmap_dma_buf(struct dma_buf_attachment *attach,
enum dma_data_direction dir)
{
dma_unmap_sg(attach->dev, sgt->sgl, sgt->nents, dir);
+
sg_free_table(sgt);
kfree(sgt);
sgt = NULL;
@@ -196,7 +191,6 @@ struct drm_gem_object *exynos_dmabuf_prime_import(struct drm_device *drm_dev,
struct scatterlist *sgl;
struct exynos_drm_gem_obj *exynos_gem_obj;
struct exynos_drm_gem_buf *buffer;
- struct page *page;
int ret;
DRM_DEBUG_PRIME("%s\n", __FILE__);
@@ -233,38 +227,27 @@ struct drm_gem_object *exynos_dmabuf_prime_import(struct drm_device *drm_dev,
goto err_unmap_attach;
}
- buffer->pages = kzalloc(sizeof(*page) * sgt->nents, GFP_KERNEL);
- if (!buffer->pages) {
- DRM_ERROR("failed to allocate pages.\n");
- ret = -ENOMEM;
- goto err_free_buffer;
- }
-
exynos_gem_obj = exynos_drm_gem_init(drm_dev, dma_buf->size);
if (!exynos_gem_obj) {
ret = -ENOMEM;
- goto err_free_pages;
+ goto err_free_buffer;
}
sgl = sgt->sgl;
- if (sgt->nents == 1) {
- buffer->dma_addr = sg_dma_address(sgt->sgl);
- buffer->size = sg_dma_len(sgt->sgl);
+ buffer->size = dma_buf->size;
+ buffer->dma_addr = sg_dma_address(sgl);
+ if (sgt->nents == 1) {
/* always physically continuous memory if sgt->nents is 1. */
exynos_gem_obj->flags |= EXYNOS_BO_CONTIG;
} else {
- unsigned int i = 0;
-
- buffer->dma_addr = sg_dma_address(sgl);
- while (i < sgt->nents) {
- buffer->pages[i] = sg_page(sgl);
- buffer->size += sg_dma_len(sgl);
- sgl = sg_next(sgl);
- i++;
- }
-
+ /*
+ * this case could be CONTIG or NONCONTIG type but for now
+ * sets NONCONTIG.
+ * TODO. we have to find a way that exporter can notify
+ * the type of its own buffer to importer.
+ */
exynos_gem_obj->flags |= EXYNOS_BO_NONCONTIG;
}
@@ -277,9 +260,6 @@ struct drm_gem_object *exynos_dmabuf_prime_import(struct drm_device *drm_dev,
return &exynos_gem_obj->base;
-err_free_pages:
- kfree(buffer->pages);
- buffer->pages = NULL;
err_free_buffer:
kfree(buffer);
buffer = NULL;