aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char/agp/intel-gtt.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/char/agp/intel-gtt.c')
-rw-r--r--drivers/char/agp/intel-gtt.c75
1 files changed, 30 insertions, 45 deletions
diff --git a/drivers/char/agp/intel-gtt.c b/drivers/char/agp/intel-gtt.c
index 826ab0939a12..0d09b537bb9a 100644
--- a/drivers/char/agp/intel-gtt.c
+++ b/drivers/char/agp/intel-gtt.c
@@ -21,6 +21,7 @@
21#include <linux/kernel.h> 21#include <linux/kernel.h>
22#include <linux/pagemap.h> 22#include <linux/pagemap.h>
23#include <linux/agp_backend.h> 23#include <linux/agp_backend.h>
24#include <linux/delay.h>
24#include <asm/smp.h> 25#include <asm/smp.h>
25#include "agp.h" 26#include "agp.h"
26#include "intel-agp.h" 27#include "intel-agp.h"
@@ -68,13 +69,10 @@ static struct _intel_private {
68 phys_addr_t gma_bus_addr; 69 phys_addr_t gma_bus_addr;
69 u32 PGETBL_save; 70 u32 PGETBL_save;
70 u32 __iomem *gtt; /* I915G */ 71 u32 __iomem *gtt; /* I915G */
72 bool clear_fake_agp; /* on first access via agp, fill with scratch */
71 int num_dcache_entries; 73 int num_dcache_entries;
72 union { 74 void __iomem *i9xx_flush_page;
73 void __iomem *i9xx_flush_page;
74 void *i8xx_flush_page;
75 };
76 char *i81x_gtt_table; 75 char *i81x_gtt_table;
77 struct page *i8xx_page;
78 struct resource ifp_resource; 76 struct resource ifp_resource;
79 int resource_valid; 77 int resource_valid;
80 struct page *scratch_page; 78 struct page *scratch_page;
@@ -721,28 +719,6 @@ static int intel_fake_agp_fetch_size(void)
721 719
722static void i830_cleanup(void) 720static void i830_cleanup(void)
723{ 721{
724 if (intel_private.i8xx_flush_page) {
725 kunmap(intel_private.i8xx_flush_page);
726 intel_private.i8xx_flush_page = NULL;
727 }
728
729 __free_page(intel_private.i8xx_page);
730 intel_private.i8xx_page = NULL;
731}
732
733static void intel_i830_setup_flush(void)
734{
735 /* return if we've already set the flush mechanism up */
736 if (intel_private.i8xx_page)
737 return;
738
739 intel_private.i8xx_page = alloc_page(GFP_KERNEL);
740 if (!intel_private.i8xx_page)
741 return;
742
743 intel_private.i8xx_flush_page = kmap(intel_private.i8xx_page);
744 if (!intel_private.i8xx_flush_page)
745 i830_cleanup();
746} 722}
747 723
748/* The chipset_flush interface needs to get data that has already been 724/* The chipset_flush interface needs to get data that has already been
@@ -757,14 +733,27 @@ static void intel_i830_setup_flush(void)
757 */ 733 */
758static void i830_chipset_flush(void) 734static void i830_chipset_flush(void)
759{ 735{
760 unsigned int *pg = intel_private.i8xx_flush_page; 736 unsigned long timeout = jiffies + msecs_to_jiffies(1000);
737
738 /* Forcibly evict everything from the CPU write buffers.
739 * clflush appears to be insufficient.
740 */
741 wbinvd_on_all_cpus();
761 742
762 memset(pg, 0, 1024); 743 /* Now we've only seen documents for this magic bit on 855GM,
744 * we hope it exists for the other gen2 chipsets...
745 *
746 * Also works as advertised on my 845G.
747 */
748 writel(readl(intel_private.registers+I830_HIC) | (1<<31),
749 intel_private.registers+I830_HIC);
763 750
764 if (cpu_has_clflush) 751 while (readl(intel_private.registers+I830_HIC) & (1<<31)) {
765 clflush_cache_range(pg, 1024); 752 if (time_after(jiffies, timeout))
766 else if (wbinvd_on_all_cpus() != 0) 753 break;
767 printk(KERN_ERR "Timed out waiting for cache flush.\n"); 754
755 udelay(50);
756 }
768} 757}
769 758
770static void i830_write_entry(dma_addr_t addr, unsigned int entry, 759static void i830_write_entry(dma_addr_t addr, unsigned int entry,
@@ -848,8 +837,6 @@ static int i830_setup(void)
848 837
849 intel_private.gtt_bus_addr = reg_addr + I810_PTE_BASE; 838 intel_private.gtt_bus_addr = reg_addr + I810_PTE_BASE;
850 839
851 intel_i830_setup_flush();
852
853 return 0; 840 return 0;
854} 841}
855 842
@@ -869,21 +856,12 @@ static int intel_fake_agp_free_gatt_table(struct agp_bridge_data *bridge)
869 856
870static int intel_fake_agp_configure(void) 857static int intel_fake_agp_configure(void)
871{ 858{
872 int i;
873
874 if (!intel_enable_gtt()) 859 if (!intel_enable_gtt())
875 return -EIO; 860 return -EIO;
876 861
862 intel_private.clear_fake_agp = true;
877 agp_bridge->gart_bus_addr = intel_private.gma_bus_addr; 863 agp_bridge->gart_bus_addr = intel_private.gma_bus_addr;
878 864
879 for (i = 0; i < intel_private.base.gtt_total_entries; i++) {
880 intel_private.driver->write_entry(intel_private.scratch_page_dma,
881 i, 0);
882 }
883 readl(intel_private.gtt+i-1); /* PCI Posting. */
884
885 global_cache_flush();
886
887 return 0; 865 return 0;
888} 866}
889 867
@@ -945,6 +923,13 @@ static int intel_fake_agp_insert_entries(struct agp_memory *mem,
945{ 923{
946 int ret = -EINVAL; 924 int ret = -EINVAL;
947 925
926 if (intel_private.clear_fake_agp) {
927 int start = intel_private.base.stolen_size / PAGE_SIZE;
928 int end = intel_private.base.gtt_mappable_entries;
929 intel_gtt_clear_range(start, end - start);
930 intel_private.clear_fake_agp = false;
931 }
932
948 if (INTEL_GTT_GEN == 1 && type == AGP_DCACHE_MEMORY) 933 if (INTEL_GTT_GEN == 1 && type == AGP_DCACHE_MEMORY)
949 return i810_insert_dcache_entries(mem, pg_start, type); 934 return i810_insert_dcache_entries(mem, pg_start, type);
950 935