summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Hellstrom <thomas-at-tungstengraphics-dot-com>2006-10-21 14:17:51 +0200
committerThomas Hellstrom <thomas-at-tungstengraphics-dot-com>2006-10-21 14:17:51 +0200
commit9ed4656799043f24f4d64615ebb8128bedc99799 (patch)
treef05a24b66be6ba71bee752b5c63630dc4f1f5aae
parent9321592149c031694c459bb05e7a31d1197fe5cb (diff)
The CPU cache must be flushed _before_ we start modifying the kernel map ptes,
otherwise data will be missing, which becomes apparent when the kernel evicts batch buffers which are likely to be written into in the evicted state, and then rebound to the AGP aperture. This means we cannot rely on the AGP module to flush the cache for us.
-rw-r--r--linux-core/drm_agpsupport.c2
-rw-r--r--linux-core/drm_ttm.c15
2 files changed, 16 insertions, 1 deletions
diff --git a/linux-core/drm_agpsupport.c b/linux-core/drm_agpsupport.c
index 13a3ced3..a5f1f9ee 100644
--- a/linux-core/drm_agpsupport.c
+++ b/linux-core/drm_agpsupport.c
@@ -610,7 +610,7 @@ static int drm_agp_bind_ttm(drm_ttm_backend_t *backend,
DRM_DEBUG("drm_agp_bind_ttm\n");
DRM_MASK_VAL(backend->flags, DRM_BE_FLAG_BOUND_CACHED,
(cached) ? DRM_BE_FLAG_BOUND_CACHED : 0);
- mem->is_flushed = FALSE;
+ mem->is_flushed = TRUE;
mem->type = (cached) ? agp_priv->cached_type : agp_priv->uncached_type;
ret = drm_agp_bind_memory(mem, offset);
if (ret) {
diff --git a/linux-core/drm_ttm.c b/linux-core/drm_ttm.c
index 599589fc..7344acce 100644
--- a/linux-core/drm_ttm.c
+++ b/linux-core/drm_ttm.c
@@ -28,6 +28,18 @@
#include "drmP.h"
+static void drm_ttm_ipi_handler(void *null)
+{
+ wbinvd();
+}
+
+static void drm_ttm_cache_flush(void)
+{
+ if (on_each_cpu(drm_ttm_ipi_handler, NULL, 1, 1) != 0)
+ DRM_ERROR("Timed out waiting for drm cache flush.\n");
+}
+
+
/*
* Use kmalloc if possible. Otherwise fall back to vmalloc.
*/
@@ -99,6 +111,9 @@ static int drm_set_caching(drm_ttm_t * ttm, int noncached)
if ((ttm->page_flags & DRM_TTM_PAGE_UNCACHED) == noncached)
return 0;
+ if (noncached)
+ drm_ttm_cache_flush();
+
for (i = 0; i < ttm->num_pages; ++i) {
cur_page = ttm->pages + i;
if (*cur_page) {