[Intel-gfx] [PATCH 3/4] drm/cache: Return what type of cache flush occurred

Ben Widawsky benjamin.widawsky at intel.com
Sat Dec 13 19:08:23 PST 2014


The caller of the cache flush APIs can sometimes do useful things with the
information of how the cache was flushed. For instance, when giving buffers to
the GPU to read, we need to make sure all of them have properly invalidated the
caches (when not using LLC). If we can determine a wbinvd() occurred though, we
can skip trying to clflush all remaining objects.

There is a further optimization to be made here in the driver specific code
where it can try to flush the largest object first in hopes of it needing a
wbinvd(). I haven't implemented that yet.

The enum parts of this were very minimally considered for the sake of getting
the data for the profile.

Cc: Intel GFX <intel-gfx at lists.freedesktop.org>
Signed-off-by: Ben Widawsky <ben at bwidawsk.net>
---
 drivers/gpu/drm/drm_cache.c | 34 +++++++++++++++++++++++++---------
 include/drm/drmP.h          | 13 ++++++++++---
 2 files changed, 35 insertions(+), 12 deletions(-)

diff --git a/drivers/gpu/drm/drm_cache.c b/drivers/gpu/drm/drm_cache.c
index 6009c2d..433b15d 100644
--- a/drivers/gpu/drm/drm_cache.c
+++ b/drivers/gpu/drm/drm_cache.c
@@ -80,21 +80,25 @@ drm_cache_should_clflush(unsigned long num_pages)
 }
 #endif
 
-void
+int
 drm_clflush_pages(struct page *pages[], unsigned long num_pages)
 {
 
 #if defined(CONFIG_X86)
 	if (cpu_has_clflush && drm_cache_should_clflush(num_pages)) {
 		drm_cache_flush_clflush(pages, num_pages);
-		return;
+		return DRM_CACHE_FLUSH_CL;
 	}
 
-	if (wbinvd_on_all_cpus())
+	if (wbinvd_on_all_cpus()) {
 		printk(KERN_ERR "Timed out waiting for cache flush.\n");
+		return DRM_CACHE_FLUSH_ERROR;
+	} else
+		return DRM_CACHE_FLUSH_WBINVD;
 
 #elif defined(__powerpc__)
 	unsigned long i;
+	int ret = DRM_CACHE_FLUSH_NONE;
 	for (i = 0; i < num_pages; i++) {
 		struct page *page = pages[i];
 		void *page_virtual;
@@ -106,15 +110,19 @@ drm_clflush_pages(struct page *pages[], unsigned long num_pages)
 		flush_dcache_range((unsigned long)page_virtual,
 				   (unsigned long)page_virtual + PAGE_SIZE);
 		kunmap_atomic(page_virtual);
+		ret = DRM_CACHE_FLUSH_DCACHE;
 	}
+	WARN_ON(ret == DRM_CACHE_FLUSH_NONE);
+	return ret;
 #else
 	printk(KERN_ERR "Architecture has no drm_cache.c support\n");
 	WARN_ON_ONCE(1);
+	return DRM_CACHE_FLUSH_NONE;
 #endif
 }
 EXPORT_SYMBOL(drm_clflush_pages);
 
-void
+int
 drm_clflush_sg(struct sg_table *st)
 {
 #if defined(CONFIG_X86)
@@ -126,19 +134,23 @@ drm_clflush_sg(struct sg_table *st)
 			drm_clflush_page(sg_page_iter_page(&sg_iter));
 		mb();
 
-		return;
+		return DRM_CACHE_FLUSH_CL;
 	}
 
-	if (wbinvd_on_all_cpus())
+	if (wbinvd_on_all_cpus()) {
 		printk(KERN_ERR "Timed out waiting for cache flush.\n");
+		return DRM_CACHE_FLUSH_ERROR;
+	} else
+		return DRM_CACHE_FLUSH_WBINVD;
 #else
 	printk(KERN_ERR "Architecture has no drm_cache.c support\n");
 	WARN_ON_ONCE(1);
+	return DRM_CACHE_FLUSH_NONE;
 #endif
 }
 EXPORT_SYMBOL(drm_clflush_sg);
 
-void
+int
 drm_clflush_virt_range(void *addr, unsigned long length)
 {
 #if defined(CONFIG_X86)
@@ -149,14 +161,18 @@ drm_clflush_virt_range(void *addr, unsigned long length)
 			clflushopt(addr);
 		clflushopt(end - 1);
 		mb();
-		return;
+		return DRM_CACHE_FLUSH_CL;
 	}
 
-	if (wbinvd_on_all_cpus())
+	if (wbinvd_on_all_cpus()) {
 		printk(KERN_ERR "Timed out waiting for cache flush.\n");
+		return DRM_CACHE_FLUSH_ERROR;
+	} else
+		return DRM_CACHE_FLUSH_WBINVD;
 #else
 	printk(KERN_ERR "Architecture has no drm_cache.c support\n");
 	WARN_ON_ONCE(1);
+	return DRM_CACHE_FLUSH_NONE;
 #endif
 }
 EXPORT_SYMBOL(drm_clflush_virt_range);
diff --git a/include/drm/drmP.h b/include/drm/drmP.h
index 8ba35c6..09ebe46 100644
--- a/include/drm/drmP.h
+++ b/include/drm/drmP.h
@@ -884,9 +884,16 @@ int drm_noop(struct drm_device *dev, void *data,
 	     struct drm_file *file_priv);
 
 /* Cache management (drm_cache.c) */
-void drm_clflush_pages(struct page *pages[], unsigned long num_pages);
-void drm_clflush_sg(struct sg_table *st);
-void drm_clflush_virt_range(void *addr, unsigned long length);
+enum drm_cache_flush {
+	DRM_CACHE_FLUSH_NONE=0,
+	DRM_CACHE_FLUSH_ERROR,
+	DRM_CACHE_FLUSH_CL,
+	DRM_CACHE_FLUSH_WBINVD,
+	DRM_CACHE_FLUSH_DCACHE,
+};
+int drm_clflush_pages(struct page *pages[], unsigned long num_pages);
+int drm_clflush_sg(struct sg_table *st);
+int drm_clflush_virt_range(void *addr, unsigned long length);
 
 /*
  * These are exported to drivers so that they can implement fencing using
-- 
2.1.3



More information about the Intel-gfx mailing list