[PATCH 1/4] [RFC] drm/exynos: DMABUF: Added support for exporting non-contig buffers

Kyungmin Park kmpark at infradead.org
Sun Apr 15 18:38:02 PDT 2012


Hi,

I saw your description but please generate the patches against the
latest codes at next time.

On 4/14/12, Prathyush <prathyush.k at samsung.com> wrote:
> 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 at 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);
>  }
>
> +
Useless newline.
> +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;
> +}
This function is almost same as Tomasz one at v4l2.
To Tomasz,
Can you make it common helper function at common place?
> +
> +
Useless newline too.
>  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);
kcalloc?

Thank you,
Kyungmin Park
> +	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
>
> _______________________________________________
> dri-devel mailing list
> dri-devel at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel
>


More information about the dri-devel mailing list