drm/nv50: fix iommu errors caused by device reading from address 0
[safe/jmp/linux-2.6] / drivers / gpu / drm / drm_cache.c
index 0e994a0..0e3bd5b 100644 (file)
@@ -45,6 +45,23 @@ drm_clflush_page(struct page *page)
                clflush(page_virtual + i);
        kunmap_atomic(page_virtual, KM_USER0);
 }
+
+static void drm_cache_flush_clflush(struct page *pages[],
+                                   unsigned long num_pages)
+{
+       unsigned long i;
+
+       mb();
+       for (i = 0; i < num_pages; i++)
+               drm_clflush_page(*pages++);
+       mb();
+}
+
+static void
+drm_clflush_ipi_handler(void *null)
+{
+       wbinvd();
+}
 #endif
 
 void
@@ -53,17 +70,30 @@ drm_clflush_pages(struct page *pages[], unsigned long num_pages)
 
 #if defined(CONFIG_X86)
        if (cpu_has_clflush) {
-               unsigned long i;
-
-               mb();
-               for (i = 0; i < num_pages; ++i)
-                       drm_clflush_page(*pages++);
-               mb();
-
+               drm_cache_flush_clflush(pages, num_pages);
                return;
        }
 
-       wbinvd();
+       if (on_each_cpu(drm_clflush_ipi_handler, NULL, 1) != 0)
+               printk(KERN_ERR "Timed out waiting for cache flush.\n");
+
+#elif defined(__powerpc__)
+       unsigned long i;
+       for (i = 0; i < num_pages; i++) {
+               struct page *page = pages[i];
+               void *page_virtual;
+
+               if (unlikely(page == NULL))
+                       continue;
+
+               page_virtual = kmap_atomic(page, KM_USER0);
+               flush_dcache_range((unsigned long)page_virtual,
+                                  (unsigned long)page_virtual + PAGE_SIZE);
+               kunmap_atomic(page_virtual, KM_USER0);
+       }
+#else
+       printk(KERN_ERR "Architecture has no drm_cache.c support\n");
+       WARN_ON_ONCE(1);
 #endif
 }
 EXPORT_SYMBOL(drm_clflush_pages);