@@ -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);
@@ -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
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@lists.freedesktop.org> Signed-off-by: Ben Widawsky <ben@bwidawsk.net> --- drivers/gpu/drm/drm_cache.c | 34 +++++++++++++++++++++++++--------- include/drm/drmP.h | 13 ++++++++++--- 2 files changed, 35 insertions(+), 12 deletions(-)