From 17f8b65e5c239ff3f095462d7b5de5e5985453bc Mon Sep 17 00:00:00 2001 From: Mark Yao Date: Fri, 24 Mar 2017 14:31:22 +0800 Subject: [PATCH] staging: ion: dup sg_table when map_dma_buffer Change-Id: Ib57df4e7f972a8e46b6c8e8c82e314e04cc3b349 Signed-off-by: Mark Yao --- drivers/staging/android/ion/ion.c | 52 +++++++++++++++++++++++++++++-- 1 file changed, 49 insertions(+), 3 deletions(-) diff --git a/drivers/staging/android/ion/ion.c b/drivers/staging/android/ion/ion.c index 13c0972669c0..5083289504ab 100644 --- a/drivers/staging/android/ion/ion.c +++ b/drivers/staging/android/ion/ion.c @@ -1178,13 +1178,57 @@ static struct sg_table *ion_map_dma_buf(struct dma_buf_attachment *attachment, { struct dma_buf *dmabuf = attachment->dmabuf; struct ion_buffer *buffer = dmabuf->priv; + int nr_pages = PAGE_ALIGN(buffer->size) / PAGE_SIZE; + struct sg_table *table = buffer->sg_table; + struct scatterlist *sg; + struct sg_table *sgt; + int ret, i; ion_buffer_sync_for_device(buffer, attachment->dev, direction); - if (!dma_map_sg(attachment->dev, buffer->sg_table->sgl, - buffer->sg_table->nents, direction)) + sgt = kmalloc(sizeof(*sgt), GFP_KERNEL); + if (!sgt) return ERR_PTR(-ENOMEM); - return buffer->sg_table; + if (!buffer->pages) { + int j, k = 0; + + buffer->pages = vmalloc(sizeof(struct page *) * nr_pages); + if (!buffer->pages) { + ret = -ENOMEM; + goto err_free_sgt; + } + + for_each_sg(table->sgl, sg, table->nents, i) { + struct page *page = sg_page(sg); + + for (j = 0; j < sg->length / PAGE_SIZE; j++) + buffer->pages[k++] = page++; + } + } + + ret = sg_alloc_table_from_pages(sgt, buffer->pages, nr_pages, 0, + nr_pages << PAGE_SHIFT, GFP_KERNEL); + if (ret) + goto err_free_sgt; + + for_each_sg(sgt->sgl, sg, sgt->nents, i) { + sg_dma_address(sg) = sg_phys(sg); + sg_dma_len(sg) = sg->length; + } + + if (!dma_map_sg(attachment->dev, sgt->sgl, + sgt->nents, direction)) { + ret = -ENOMEM; + goto err_free_sg_table; + } + + return sgt; + +err_free_sg_table: + sg_free_table(sgt); +err_free_sgt: + kfree(sgt); + return ERR_PTR(ret); } static void ion_unmap_dma_buf(struct dma_buf_attachment *attachment, @@ -1192,6 +1236,8 @@ static void ion_unmap_dma_buf(struct dma_buf_attachment *attachment, enum dma_data_direction direction) { dma_unmap_sg(attachment->dev, table->sgl, table->nents, direction); + sg_free_table(table); + kfree(table); } void ion_pages_sync_for_device(struct device *dev, struct page *page, -- 2.34.1