aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric Anholt <eric@anholt.net>2009-09-10 20:48:48 -0400
committerEric Anholt <eric@anholt.net>2009-09-11 14:39:23 -0400
commite517a5e97080bbe52857bd0d7df9b66602d53c4d (patch)
tree814e9345a91dba619f1c1ea4da9944e313490442
parent8082400327d8d2ca54254b593644942bed0edd25 (diff)
agp/intel: Fix the pre-9xx chipset flush.
Ever since we enabled GEM, the pre-9xx chipsets (particularly 865) have had serious stability issues. Back in May a wbinvd was added to the DRM to work around much of the problem. Some failure remained -- easily visible by dragging a window around on an X -retro desktop, or by looking at bugzilla. The chipset flush was on the right track -- hitting the right amount of memory, and it appears to be the only way to flush on these chipsets, but the flush page was mapped uncached. As a result, the writes trying to clear the writeback cache ended up bypassing the cache, and not flushing anything! The wbinvd would flush out other writeback data and often cause the data we wanted to get flushed, but not always. By removing the setting of the page to UC and instead just clflushing the data we write to try to flush it, we get the desired behavior with no wbinvd. This exports clflush_cache_range(), which was laying around and happened to basically match the code I was otherwise going to copy from the DRM. Signed-off-by: Eric Anholt <eric@anholt.net> Signed-off-by: Brice Goglin <Brice.Goglin@ens-lyon.org> Cc: stable@kernel.org
-rw-r--r--arch/x86/mm/pageattr.c1
-rw-r--r--drivers/char/agp/intel-agp.c30
-rw-r--r--drivers/gpu/drm/i915/i915_gem.c10
3 files changed, 24 insertions, 17 deletions
diff --git a/arch/x86/mm/pageattr.c b/arch/x86/mm/pageattr.c
index 7e600c1962db..5866b28eede1 100644
--- a/arch/x86/mm/pageattr.c
+++ b/arch/x86/mm/pageattr.c
@@ -143,6 +143,7 @@ void clflush_cache_range(void *vaddr, unsigned int size)
143 143
144 mb(); 144 mb();
145} 145}
146EXPORT_SYMBOL_GPL(clflush_cache_range);
146 147
147static void __cpa_flush_all(void *arg) 148static void __cpa_flush_all(void *arg)
148{ 149{
diff --git a/drivers/char/agp/intel-agp.c b/drivers/char/agp/intel-agp.c
index c17291715031..e8dc75fc33cc 100644
--- a/drivers/char/agp/intel-agp.c
+++ b/drivers/char/agp/intel-agp.c
@@ -682,23 +682,39 @@ static void intel_i830_setup_flush(void)
682 if (!intel_private.i8xx_page) 682 if (!intel_private.i8xx_page)
683 return; 683 return;
684 684
685 /* make page uncached */
686 map_page_into_agp(intel_private.i8xx_page);
687
688 intel_private.i8xx_flush_page = kmap(intel_private.i8xx_page); 685 intel_private.i8xx_flush_page = kmap(intel_private.i8xx_page);
689 if (!intel_private.i8xx_flush_page) 686 if (!intel_private.i8xx_flush_page)
690 intel_i830_fini_flush(); 687 intel_i830_fini_flush();
691} 688}
692 689
690static void
691do_wbinvd(void *null)
692{
693 wbinvd();
694}
695
696/* The chipset_flush interface needs to get data that has already been
697 * flushed out of the CPU all the way out to main memory, because the GPU
698 * doesn't snoop those buffers.
699 *
700 * The 8xx series doesn't have the same lovely interface for flushing the
701 * chipset write buffers that the later chips do. According to the 865
702 * specs, it's 64 octwords, or 1KB. So, to get those previous things in
703 * that buffer out, we just fill 1KB and clflush it out, on the assumption
704 * that it'll push whatever was in there out. It appears to work.
705 */
693static void intel_i830_chipset_flush(struct agp_bridge_data *bridge) 706static void intel_i830_chipset_flush(struct agp_bridge_data *bridge)
694{ 707{
695 unsigned int *pg = intel_private.i8xx_flush_page; 708 unsigned int *pg = intel_private.i8xx_flush_page;
696 int i;
697 709
698 for (i = 0; i < 256; i += 2) 710 memset(pg, 0, 1024);
699 *(pg + i) = i;
700 711
701 wmb(); 712 if (cpu_has_clflush) {
713 clflush_cache_range(pg, 1024);
714 } else {
715 if (on_each_cpu(do_wbinvd, NULL, 1) != 0)
716 printk(KERN_ERR "Timed out waiting for cache flush.\n");
717 }
702} 718}
703 719
704/* The intel i830 automatically initializes the agp aperture during POST. 720/* The intel i830 automatically initializes the agp aperture during POST.
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index f3758f9fc979..30ea4b6b0219 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -2511,16 +2511,6 @@ i915_gem_clflush_object(struct drm_gem_object *obj)
2511 if (obj_priv->pages == NULL) 2511 if (obj_priv->pages == NULL)
2512 return; 2512 return;
2513 2513
2514 /* XXX: The 865 in particular appears to be weird in how it handles
2515 * cache flushing. We haven't figured it out, but the
2516 * clflush+agp_chipset_flush doesn't appear to successfully get the
2517 * data visible to the PGU, while wbinvd + agp_chipset_flush does.
2518 */
2519 if (IS_I865G(obj->dev)) {
2520 wbinvd();
2521 return;
2522 }
2523
2524 drm_clflush_pages(obj_priv->pages, obj->size / PAGE_SIZE); 2514 drm_clflush_pages(obj_priv->pages, obj->size / PAGE_SIZE);
2525} 2515}
2526 2516