Message ID | 1334404333-24592-2-git-send-email-prathyush.k@samsung.com |
---|---|
State | New |
Headers | show |
Hi Prathyush. First of all, thanks for your patch but your patch set isn't considered for latest exynos dmabuf. we already updated dmabuf support for exynos drm and this is also considered for non-continuous memory region. you can refer to git repository below: http://git.infradead.org/users/kmpark/linux-2.6-samsung/shortlog/refs/heads/ exynos-drm-prime and this repository has already been tested by me and Tomasz. for this, please refer to link below: http://www.spinics.net/lists/linux-media/msg46292.html last week, we had posted exynos-drm-fixes update and it has been merged to drm-fixes last week. so we are just waiting for drm-next update to post latest exynos-drm-prime. sorry but please, re-sync your patch set with latest Dave's drm-next after latest exynos-drm-prime is posted so your patch set can't be reviewed yet. Thanks, Inki Dae. > -----Original Message----- > From: Prathyush [mailto:prathyush.k@samsung.com] > Sent: Saturday, April 14, 2012 8:52 PM > To: dri-devel@lists.freedesktop.org; linaro-mm-sig@lists.linaro.org > Cc: inki.dae@samsung.com; subash.rp@samsung.com; prashanth.g@samsung.com; > sunilm@samsung.com; prathyush.k@samsung.com > Subject: [PATCH 1/4] [RFC] drm/exynos: DMABUF: Added support for exporting > non-contig buffers > > With this change, the exynos drm dmabuf module can export and > import dmabuf of gem objects with non-continuous memory. > > The exynos_map_dmabuf function can create SGT of a non-contiguous > buffer by calling dma_get_pages to retrieve the allocated pages > and then maps the SGT to the caller's address space. > > Signed-off-by: Prathyush K <prathyush.k@samsung.com> > --- > drivers/gpu/drm/exynos/exynos_drm_dmabuf.c | 98 +++++++++++++++++++++++- > ---- > 1 files changed, 81 insertions(+), 17 deletions(-) > > diff --git a/drivers/gpu/drm/exynos/exynos_drm_dmabuf.c > b/drivers/gpu/drm/exynos/exynos_drm_dmabuf.c > index cbb6ad4..54b88bd 100644 > --- a/drivers/gpu/drm/exynos/exynos_drm_dmabuf.c > +++ b/drivers/gpu/drm/exynos/exynos_drm_dmabuf.c > @@ -56,6 +56,59 @@ static void exynos_dmabuf_detach(struct dma_buf *dmabuf, > dma_buf_put(dmabuf); > } > > + > +static struct sg_table *drm_dc_pages_to_sgt(struct page **pages, > + unsigned long n_pages, size_t offset, size_t offset2, dma_addr_t > daddr) > +{ > + struct sg_table *sgt; > + struct scatterlist *s; > + int i, j, cur_page, chunks, ret; > + > + sgt = kzalloc(sizeof *sgt, GFP_KERNEL); > + if (!sgt) > + return ERR_PTR(-ENOMEM); > + > + /* compute number of chunks */ > + chunks = 1; > + for (i = 1; i < n_pages; ++i) > + if (pages[i] != pages[i - 1] + 1) > + ++chunks; > + > + ret = sg_alloc_table(sgt, chunks, GFP_KERNEL); > + if (ret) { > + kfree(sgt); > + return ERR_PTR(-ENOMEM); > + } > + > + /* merging chunks and putting them into the scatterlist */ > + cur_page = 0; > + for_each_sg(sgt->sgl, s, sgt->orig_nents, i) { > + size_t size = PAGE_SIZE; > + > + for (j = cur_page + 1; j < n_pages; ++j) { > + if (pages[j] != pages[j - 1] + 1) > + break; > + size += PAGE_SIZE; > + } > + > + /* cut offset if chunk starts at the first page */ > + if (cur_page == 0) > + size -= offset; > + /* cut offset2 if chunk ends at the last page */ > + if (j == n_pages) > + size -= offset2; > + > + sg_set_page(s, pages[cur_page], size, offset); > + s->dma_address = daddr; > + daddr += size; > + offset = 0; > + cur_page = j; > + } > + > + return sgt; > +} > + > + > static struct sg_table *exynos_map_dmabuf(struct dma_buf_attachment > *attach, > enum dma_data_direction direction) > { > @@ -64,6 +117,8 @@ static struct sg_table *exynos_map_dmabuf(struct > dma_buf_attachment *attach, > struct exynos_drm_gem_buf *buffer; > struct sg_table *sgt; > int ret; > + int size, n_pages; > + struct page **pages = NULL; > > DRM_DEBUG_KMS("%s\n", __FILE__); > > @@ -71,27 +126,37 @@ static struct sg_table *exynos_map_dmabuf(struct > dma_buf_attachment *attach, > > buffer = exynos_gem_obj->buffer; > > - /* TODO. consider physically non-continuous memory with IOMMU. */ > + size = buffer->size; > + n_pages = PAGE_ALIGN(size) >> PAGE_SHIFT; > > - sgt = kzalloc(sizeof(*sgt), GFP_KERNEL); > - if (!sgt) { > - DRM_DEBUG_KMS("failed to allocate sg table.\n"); > - return ERR_PTR(-ENOMEM); > + pages = kmalloc(n_pages * sizeof pages[0], GFP_KERNEL); > + if (!pages) { > + DRM_DEBUG_KMS("failed to alloc page table\n"); > + return NULL; > } > > - ret = sg_alloc_table(sgt, 1, GFP_KERNEL); > + ret = dma_get_pages(attach->dev, buffer->kvaddr, > + buffer->dma_addr, pages, n_pages); > if (ret < 0) { > - DRM_DEBUG_KMS("failed to allocate scatter list.\n"); > - kfree(sgt); > - sgt = NULL; > - return ERR_PTR(-ENOMEM); > + DRM_DEBUG_KMS("failed to get buffer pages from DMA API\n"); > + return NULL; > } > + if (ret != n_pages) { > + DRM_DEBUG_KMS("failed to get all pages from DMA API\n"); > + return NULL; > + } > + > + sgt = drm_dc_pages_to_sgt(pages, n_pages, 0, 0, buffer->dma_addr); > + if (IS_ERR(sgt)) { > + DRM_DEBUG_KMS("failed to prepare sg table\n"); > + return NULL; > + } > + > + sgt->nents = dma_map_sg(attach->dev, sgt->sgl, > + sgt->orig_nents, DMA_BIDIRECTIONAL); > > - sg_init_table(sgt->sgl, 1); > - sg_dma_len(sgt->sgl) = buffer->size; > - sg_set_page(sgt->sgl, pfn_to_page(PFN_DOWN(buffer->dma_addr)), > - buffer->size, 0); > - sg_dma_address(sgt->sgl) = buffer->dma_addr; > + /* pages are no longer needed */ > + kfree(pages); > > /* > * increase reference count of this buffer. > @@ -303,8 +368,6 @@ int exynos_dmabuf_prime_fd_to_handle(struct drm_device > *drm_dev, > if (ret < 0) > goto fail_handle; > > - /* consider physically non-continuous memory with IOMMU. */ > - > buffer->dma_addr = sg_dma_address(sgt->sgl); > buffer->size = sg_dma_len(sgt->sgl); > > @@ -316,6 +379,7 @@ int exynos_dmabuf_prime_fd_to_handle(struct drm_device > *drm_dev, > atomic_set(&buffer->shared_refcount, 1); > > exynos_gem_obj->base.import_attach = attach; > + exynos_gem_obj->buffer = buffer; > > ret = drm_prime_insert_fd_handle_mapping(&file_priv->prime, > dmabuf, *handle); > -- > 1.7.0.4
diff --git a/drivers/gpu/drm/exynos/exynos_drm_dmabuf.c b/drivers/gpu/drm/exynos/exynos_drm_dmabuf.c index cbb6ad4..54b88bd 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_dmabuf.c +++ b/drivers/gpu/drm/exynos/exynos_drm_dmabuf.c @@ -56,6 +56,59 @@ static void exynos_dmabuf_detach(struct dma_buf *dmabuf, dma_buf_put(dmabuf); } + +static struct sg_table *drm_dc_pages_to_sgt(struct page **pages, + unsigned long n_pages, size_t offset, size_t offset2, dma_addr_t daddr) +{ + struct sg_table *sgt; + struct scatterlist *s; + int i, j, cur_page, chunks, ret; + + sgt = kzalloc(sizeof *sgt, GFP_KERNEL); + if (!sgt) + return ERR_PTR(-ENOMEM); + + /* compute number of chunks */ + chunks = 1; + for (i = 1; i < n_pages; ++i) + if (pages[i] != pages[i - 1] + 1) + ++chunks; + + ret = sg_alloc_table(sgt, chunks, GFP_KERNEL); + if (ret) { + kfree(sgt); + return ERR_PTR(-ENOMEM); + } + + /* merging chunks and putting them into the scatterlist */ + cur_page = 0; + for_each_sg(sgt->sgl, s, sgt->orig_nents, i) { + size_t size = PAGE_SIZE; + + for (j = cur_page + 1; j < n_pages; ++j) { + if (pages[j] != pages[j - 1] + 1) + break; + size += PAGE_SIZE; + } + + /* cut offset if chunk starts at the first page */ + if (cur_page == 0) + size -= offset; + /* cut offset2 if chunk ends at the last page */ + if (j == n_pages) + size -= offset2; + + sg_set_page(s, pages[cur_page], size, offset); + s->dma_address = daddr; + daddr += size; + offset = 0; + cur_page = j; + } + + return sgt; +} + + static struct sg_table *exynos_map_dmabuf(struct dma_buf_attachment *attach, enum dma_data_direction direction) { @@ -64,6 +117,8 @@ static struct sg_table *exynos_map_dmabuf(struct dma_buf_attachment *attach, struct exynos_drm_gem_buf *buffer; struct sg_table *sgt; int ret; + int size, n_pages; + struct page **pages = NULL; DRM_DEBUG_KMS("%s\n", __FILE__); @@ -71,27 +126,37 @@ static struct sg_table *exynos_map_dmabuf(struct dma_buf_attachment *attach, buffer = exynos_gem_obj->buffer; - /* TODO. consider physically non-continuous memory with IOMMU. */ + size = buffer->size; + n_pages = PAGE_ALIGN(size) >> PAGE_SHIFT; - sgt = kzalloc(sizeof(*sgt), GFP_KERNEL); - if (!sgt) { - DRM_DEBUG_KMS("failed to allocate sg table.\n"); - return ERR_PTR(-ENOMEM); + pages = kmalloc(n_pages * sizeof pages[0], GFP_KERNEL); + if (!pages) { + DRM_DEBUG_KMS("failed to alloc page table\n"); + return NULL; } - ret = sg_alloc_table(sgt, 1, GFP_KERNEL); + ret = dma_get_pages(attach->dev, buffer->kvaddr, + buffer->dma_addr, pages, n_pages); if (ret < 0) { - DRM_DEBUG_KMS("failed to allocate scatter list.\n"); - kfree(sgt); - sgt = NULL; - return ERR_PTR(-ENOMEM); + DRM_DEBUG_KMS("failed to get buffer pages from DMA API\n"); + return NULL; } + if (ret != n_pages) { + DRM_DEBUG_KMS("failed to get all pages from DMA API\n"); + return NULL; + } + + sgt = drm_dc_pages_to_sgt(pages, n_pages, 0, 0, buffer->dma_addr); + if (IS_ERR(sgt)) { + DRM_DEBUG_KMS("failed to prepare sg table\n"); + return NULL; + } + + sgt->nents = dma_map_sg(attach->dev, sgt->sgl, + sgt->orig_nents, DMA_BIDIRECTIONAL); - sg_init_table(sgt->sgl, 1); - sg_dma_len(sgt->sgl) = buffer->size; - sg_set_page(sgt->sgl, pfn_to_page(PFN_DOWN(buffer->dma_addr)), - buffer->size, 0); - sg_dma_address(sgt->sgl) = buffer->dma_addr; + /* pages are no longer needed */ + kfree(pages); /* * increase reference count of this buffer. @@ -303,8 +368,6 @@ int exynos_dmabuf_prime_fd_to_handle(struct drm_device *drm_dev, if (ret < 0) goto fail_handle; - /* consider physically non-continuous memory with IOMMU. */ - buffer->dma_addr = sg_dma_address(sgt->sgl); buffer->size = sg_dma_len(sgt->sgl); @@ -316,6 +379,7 @@ int exynos_dmabuf_prime_fd_to_handle(struct drm_device *drm_dev, atomic_set(&buffer->shared_refcount, 1); exynos_gem_obj->base.import_attach = attach; + exynos_gem_obj->buffer = buffer; ret = drm_prime_insert_fd_handle_mapping(&file_priv->prime, dmabuf, *handle);
With this change, the exynos drm dmabuf module can export and import dmabuf of gem objects with non-continuous memory. The exynos_map_dmabuf function can create SGT of a non-contiguous buffer by calling dma_get_pages to retrieve the allocated pages and then maps the SGT to the caller's address space. Signed-off-by: Prathyush K <prathyush.k@samsung.com> --- drivers/gpu/drm/exynos/exynos_drm_dmabuf.c | 98 +++++++++++++++++++++++----- 1 files changed, 81 insertions(+), 17 deletions(-)