diff mbox

drm/omap: GEM, deal with cache

Message ID 1324421668-18056-1-git-send-email-rob.clark@linaro.org
State Accepted
Commit f3bc9d24cb4a221bd3530c445fa08e33775e7707
Headers show

Commit Message

Rob Clark Dec. 20, 2011, 10:54 p.m. UTC
From: Rob Clark <rob@ti.com>

Uncached/writecombine buffers need to be clean before creating uc/wc
userspace mappings, lest dirty cache lines fall down and corrupt the
contents of the buffer.

Signed-off-by: Rob Clark <rob@ti.com>
---
 drivers/staging/omapdrm/omap_gem.c |   30 ++++++++++++++++++++++++++++++
 1 files changed, 30 insertions(+), 0 deletions(-)
diff mbox

Patch

diff --git a/drivers/staging/omapdrm/omap_gem.c b/drivers/staging/omapdrm/omap_gem.c
index 63490f7..e0ebd1d 100644
--- a/drivers/staging/omapdrm/omap_gem.c
+++ b/drivers/staging/omapdrm/omap_gem.c
@@ -84,6 +84,9 @@  struct omap_gem_object {
 	 */
 	struct page **pages;
 
+	/** addresses corresponding to pages in above array */
+	dma_addr_t *addrs;
+
 	/**
 	 * Virtual address, if mapped.
 	 */
@@ -208,6 +211,19 @@  static int omap_gem_attach_pages(struct drm_gem_object *obj)
 		return PTR_ERR(pages);
 	}
 
+	/* for non-cached buffers, ensure the new pages are clean because
+	 * DSS, GPU, etc. are not cache coherent:
+	 */
+	if (omap_obj->flags & (OMAP_BO_WC|OMAP_BO_UNCACHED)) {
+		int i, npages = obj->size >> PAGE_SHIFT;
+		dma_addr_t *addrs = kmalloc(npages * sizeof(addrs), GFP_KERNEL);
+		for (i = 0; i < npages; i++) {
+			addrs[i] = dma_map_page(obj->dev->dev, pages[i],
+					0, PAGE_SIZE, DMA_BIDIRECTIONAL);
+		}
+		omap_obj->addrs = addrs;
+	}
+
 	omap_obj->pages = pages;
 	return 0;
 }
@@ -216,6 +232,20 @@  static int omap_gem_attach_pages(struct drm_gem_object *obj)
 static void omap_gem_detach_pages(struct drm_gem_object *obj)
 {
 	struct omap_gem_object *omap_obj = to_omap_bo(obj);
+
+	/* for non-cached buffers, ensure the new pages are clean because
+	 * DSS, GPU, etc. are not cache coherent:
+	 */
+	if (omap_obj->flags & (OMAP_BO_WC|OMAP_BO_UNCACHED)) {
+		int i, npages = obj->size >> PAGE_SHIFT;
+		for (i = 0; i < npages; i++) {
+			dma_unmap_page(obj->dev->dev, omap_obj->addrs[i],
+					PAGE_SIZE, DMA_BIDIRECTIONAL);
+		}
+		kfree(omap_obj->addrs);
+		omap_obj->addrs = NULL;
+	}
+
 	_drm_gem_put_pages(obj, omap_obj->pages, true, false);
 	omap_obj->pages = NULL;
 }