diff mbox

[RFC,072/111] staging: etnaviv: "better" DMA API usage

Message ID 1427988653-754-73-git-send-email-l.stach@pengutronix.de (mailing list archive)
State New, archived
Headers show

Commit Message

Lucas Stach April 2, 2015, 3:30 p.m. UTC
From: Russell King <rmk+kernel@arm.linux.org.uk>

The DMA API usage by etnaviv is really not up to scratch.  It does not
respect the buffer ownership rules, which are vitally necessary when
using DMA_BIDIRECTIONAL, as mapping /only/ cleans the cache lines,
causing dirty data to be written back to RAM and an unmap /only/
invalidates them, causing any data in the cache to be discarded.  Given
the length of time which these objects remain mapped, we can't hold
them in the mapped state while hoping that no other CPU accesses to the
buffer occur.

This has lead to visible pixmap corruption in the X server.  Work around
this by mapping and then immediately unmapping the buffers.  This causes
data in the buffers to be written back and then purged from the caches.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/staging/etnaviv/etnaviv_gem.c | 14 ++++++++------
 1 file changed, 8 insertions(+), 6 deletions(-)
diff mbox

Patch

diff --git a/drivers/staging/etnaviv/etnaviv_gem.c b/drivers/staging/etnaviv/etnaviv_gem.c
index 8eeafcafb4e9..56e4ff5dd048 100644
--- a/drivers/staging/etnaviv/etnaviv_gem.c
+++ b/drivers/staging/etnaviv/etnaviv_gem.c
@@ -26,14 +26,15 @@ 
 static void etnaviv_gem_scatter_map(struct etnaviv_gem_object *etnaviv_obj)
 {
 	struct drm_device *dev = etnaviv_obj->base.dev;
+	struct sg_table *sgt = etnaviv_obj->sgt;
 
 	/*
 	 * For non-cached buffers, ensure the new pages are clean
 	 * because display controller, GPU, etc. are not coherent.
 	 */
 	if (etnaviv_obj->flags & (ETNA_BO_WC|ETNA_BO_CACHED)) {
-		dma_map_sg(dev->dev, etnaviv_obj->sgt->sgl,
-			   etnaviv_obj->sgt->nents, DMA_BIDIRECTIONAL);
+		dma_map_sg(dev->dev, sgt->sgl, sgt->nents, DMA_BIDIRECTIONAL);
+		dma_unmap_sg(dev->dev, sgt->sgl, sgt->nents, DMA_BIDIRECTIONAL);
 	} else {
 		struct scatterlist *sg;
 		unsigned int i;
@@ -50,6 +51,7 @@  static void etnaviv_gem_scatter_map(struct etnaviv_gem_object *etnaviv_obj)
 static void etnaviv_gem_scatterlist_unmap(struct etnaviv_gem_object *etnaviv_obj)
 {
 	struct drm_device *dev = etnaviv_obj->base.dev;
+	struct sg_table *sgt = etnaviv_obj->sgt;
 
 	/*
 	 * For non-cached buffers, ensure the new pages are clean
@@ -66,10 +68,10 @@  static void etnaviv_gem_scatterlist_unmap(struct etnaviv_gem_object *etnaviv_obj
 	 * written into the remainder of the region, this can
 	 * discard those writes.
 	 */
-	if (etnaviv_obj->flags & (ETNA_BO_WC|ETNA_BO_CACHED))
-		dma_unmap_sg(dev->dev, etnaviv_obj->sgt->sgl,
-			     etnaviv_obj->sgt->nents,
-			     DMA_BIDIRECTIONAL);
+	if (etnaviv_obj->flags & (ETNA_BO_WC|ETNA_BO_CACHED)) {
+		dma_map_sg(dev->dev, sgt->sgl, sgt->nents, DMA_BIDIRECTIONAL);
+		dma_unmap_sg(dev->dev, sgt->sgl, sgt->nents, DMA_BIDIRECTIONAL);
+	}
 }
 
 /* called with dev->struct_mutex held */