diff mbox series

[v9,04/32] drm: armada: fix common struct sg_table related issues

Message ID 20200826063316.23486-5-m.szyprowski@samsung.com
State New
Headers show
Series DRM: fix struct sg_table nents vs. orig_nents misuse | expand

Commit Message

Marek Szyprowski Aug. 26, 2020, 6:32 a.m. UTC
The Documentation/DMA-API-HOWTO.txt states that the dma_map_sg() function
returns the number of the created entries in the DMA address space.
However the subsequent calls to the dma_sync_sg_for_{device,cpu}() and
dma_unmap_sg must be called with the original number of the entries
passed to the dma_map_sg().

struct sg_table is a common structure used for describing a non-contiguous
memory buffer, used commonly in the DRM and graphics subsystems. It
consists of a scatterlist with memory pages and DMA addresses (sgl entry),
as well as the number of scatterlist entries: CPU pages (orig_nents entry)
and DMA mapped pages (nents entry).

It turned out that it was a common mistake to misuse nents and orig_nents
entries, calling DMA-mapping functions with a wrong number of entries or
ignoring the number of mapped entries returned by the dma_map_sg()
function.

To avoid such issues, lets use a common dma-mapping wrappers operating
directly on the struct sg_table objects and use scatterlist page
iterators where possible. This, almost always, hides references to the
nents and orig_nents entries, making the code robust, easier to follow
and copy/paste safe.

Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>

---
 drivers/gpu/drm/armada/armada_gem.c | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

-- 
2.17.1

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

Comments

Robin Murphy Sept. 1, 2020, 6:26 p.m. UTC | #1
On 2020-08-26 07:32, Marek Szyprowski wrote:
> The Documentation/DMA-API-HOWTO.txt states that the dma_map_sg() function

> returns the number of the created entries in the DMA address space.

> However the subsequent calls to the dma_sync_sg_for_{device,cpu}() and

> dma_unmap_sg must be called with the original number of the entries

> passed to the dma_map_sg().

> 

> struct sg_table is a common structure used for describing a non-contiguous

> memory buffer, used commonly in the DRM and graphics subsystems. It

> consists of a scatterlist with memory pages and DMA addresses (sgl entry),

> as well as the number of scatterlist entries: CPU pages (orig_nents entry)

> and DMA mapped pages (nents entry).

> 

> It turned out that it was a common mistake to misuse nents and orig_nents

> entries, calling DMA-mapping functions with a wrong number of entries or

> ignoring the number of mapped entries returned by the dma_map_sg()

> function.

> 

> To avoid such issues, lets use a common dma-mapping wrappers operating

> directly on the struct sg_table objects and use scatterlist page

> iterators where possible. This, almost always, hides references to the

> nents and orig_nents entries, making the code robust, easier to follow

> and copy/paste safe.

> 

> Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>

> ---

>   drivers/gpu/drm/armada/armada_gem.c | 12 ++++++------

>   1 file changed, 6 insertions(+), 6 deletions(-)

> 

> diff --git a/drivers/gpu/drm/armada/armada_gem.c b/drivers/gpu/drm/armada/armada_gem.c

> index 8005614d2e6b..bedd8937d8a1 100644

> --- a/drivers/gpu/drm/armada/armada_gem.c

> +++ b/drivers/gpu/drm/armada/armada_gem.c

> @@ -395,7 +395,7 @@ armada_gem_prime_map_dma_buf(struct dma_buf_attachment *attach,

>   

>   		mapping = dobj->obj.filp->f_mapping;

>   

> -		for_each_sg(sgt->sgl, sg, count, i) {

> +		for_each_sgtable_sg(sgt, sg, i) {

>   			struct page *page;

>   

>   			page = shmem_read_mapping_page(mapping, i);

> @@ -407,8 +407,8 @@ armada_gem_prime_map_dma_buf(struct dma_buf_attachment *attach,

>   			sg_set_page(sg, page, PAGE_SIZE, 0);

>   		}

>   

> -		if (dma_map_sg(attach->dev, sgt->sgl, sgt->nents, dir) == 0) {

> -			num = sgt->nents;

> +		if (dma_map_sgtable(attach->dev, sgt, dir, 0)) {

> +			num = count;


I think it might be even nicer to get rid of "num" entirely and convert 
the cleanup path to for_each_sgtable_sg() for completeness - AFAICS it 
should only need an extra "if (sg_page(sg))..." check in that loop. Then 
"count" could possibly be squashed into its one remaining use as well, 
but maybe it's worth keeping for readability.

Robin.

>   			goto release;

>   		}

>   	} else if (dobj->page) {

> @@ -418,7 +418,7 @@ armada_gem_prime_map_dma_buf(struct dma_buf_attachment *attach,

>   

>   		sg_set_page(sgt->sgl, dobj->page, dobj->obj.size, 0);

>   

> -		if (dma_map_sg(attach->dev, sgt->sgl, sgt->nents, dir) == 0)

> +		if (dma_map_sgtable(attach->dev, sgt, dir, 0))

>   			goto free_table;

>   	} else if (dobj->linear) {

>   		/* Single contiguous physical region - no struct page */

> @@ -449,11 +449,11 @@ static void armada_gem_prime_unmap_dma_buf(struct dma_buf_attachment *attach,

>   	int i;

>   

>   	if (!dobj->linear)

> -		dma_unmap_sg(attach->dev, sgt->sgl, sgt->nents, dir);

> +		dma_unmap_sgtable(attach->dev, sgt, dir, 0);

>   

>   	if (dobj->obj.filp) {

>   		struct scatterlist *sg;

> -		for_each_sg(sgt->sgl, sg, sgt->nents, i)

> +		for_each_sgtable_sg(sgt, sg, i)

>   			put_page(sg_page(sg));

>   	}

>   

> 

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel
diff mbox series

Patch

diff --git a/drivers/gpu/drm/armada/armada_gem.c b/drivers/gpu/drm/armada/armada_gem.c
index 8005614d2e6b..bedd8937d8a1 100644
--- a/drivers/gpu/drm/armada/armada_gem.c
+++ b/drivers/gpu/drm/armada/armada_gem.c
@@ -395,7 +395,7 @@  armada_gem_prime_map_dma_buf(struct dma_buf_attachment *attach,
 
 		mapping = dobj->obj.filp->f_mapping;
 
-		for_each_sg(sgt->sgl, sg, count, i) {
+		for_each_sgtable_sg(sgt, sg, i) {
 			struct page *page;
 
 			page = shmem_read_mapping_page(mapping, i);
@@ -407,8 +407,8 @@  armada_gem_prime_map_dma_buf(struct dma_buf_attachment *attach,
 			sg_set_page(sg, page, PAGE_SIZE, 0);
 		}
 
-		if (dma_map_sg(attach->dev, sgt->sgl, sgt->nents, dir) == 0) {
-			num = sgt->nents;
+		if (dma_map_sgtable(attach->dev, sgt, dir, 0)) {
+			num = count;
 			goto release;
 		}
 	} else if (dobj->page) {
@@ -418,7 +418,7 @@  armada_gem_prime_map_dma_buf(struct dma_buf_attachment *attach,
 
 		sg_set_page(sgt->sgl, dobj->page, dobj->obj.size, 0);
 
-		if (dma_map_sg(attach->dev, sgt->sgl, sgt->nents, dir) == 0)
+		if (dma_map_sgtable(attach->dev, sgt, dir, 0))
 			goto free_table;
 	} else if (dobj->linear) {
 		/* Single contiguous physical region - no struct page */
@@ -449,11 +449,11 @@  static void armada_gem_prime_unmap_dma_buf(struct dma_buf_attachment *attach,
 	int i;
 
 	if (!dobj->linear)
-		dma_unmap_sg(attach->dev, sgt->sgl, sgt->nents, dir);
+		dma_unmap_sgtable(attach->dev, sgt, dir, 0);
 
 	if (dobj->obj.filp) {
 		struct scatterlist *sg;
-		for_each_sg(sgt->sgl, sg, sgt->nents, i)
+		for_each_sgtable_sg(sgt, sg, i)
 			put_page(sg_page(sg));
 	}