agp/intel: Add chipset flushing support for i8xx chipsets.

This is a bit of a large hammer but it makes sure the chipset is flushed
by writing out 1k of data to an uncached page. We may be able to get better
information in the future on how to this better.

Signed-off-by: Dave Airlie <airlied@redhat.com>

+78 -30
+78 -30
drivers/char/agp/intel-agp.c
··· 117 * popup and for the GTT. 118 */ 119 int gtt_entries; /* i830+ */ 120 - void __iomem *flush_page; 121 struct resource ifp_resource; 122 } intel_private; 123 ··· 583 intel_private.gtt_entries = gtt_entries; 584 } 585 586 /* The intel i830 automatically initializes the agp aperture during POST. 587 * Use the memory already set aside for in the GTT. 588 */ ··· 721 } 722 723 global_cache_flush(); 724 return 0; 725 } 726 ··· 822 ret = pci_bus_alloc_resource(agp_bridge->dev->bus, &intel_private.ifp_resource, PAGE_SIZE, 823 PAGE_SIZE, PCIBIOS_MIN_MEM, 0, 824 pcibios_align_resource, agp_bridge->dev); 825 - if (ret != 0) 826 - return ret; 827 828 - printk("intel priv bus start %08lx\n", intel_private.ifp_resource.start); 829 - return 0; 830 } 831 832 static void intel_i915_setup_chipset_flush(void) ··· 863 864 pci_write_config_dword(agp_bridge->dev, I965_IFPADDR + 4, (intel_private.ifp_resource.start >> 32)); 865 pci_write_config_dword(agp_bridge->dev, I965_IFPADDR, (intel_private.ifp_resource.start & 0xffffffff) | 0x1); 866 - intel_private.flush_page = ioremap_nocache(intel_private.ifp_resource.start, PAGE_SIZE); 867 } else { 868 u64 l64; 869 ··· 873 intel_private.ifp_resource.end = l64 + PAGE_SIZE; 874 ret = request_resource(&iomem_resource, &intel_private.ifp_resource); 875 if (!ret) { 876 - intel_private.ifp_resource.start = 0; 877 - printk("Failed inserting resource into tree\n"); 878 } 879 } 880 } 881 ··· 929 930 global_cache_flush(); 931 932 - /* setup a resource for this object */ 933 - memset(&intel_private.ifp_resource, 0, sizeof(intel_private.ifp_resource)); 934 - 935 - intel_private.ifp_resource.name = "Intel Flush Page"; 936 - intel_private.ifp_resource.flags = IORESOURCE_MEM; 937 - 938 - /* Setup chipset flush for 915 */ 939 - if (IS_I965 || IS_G33) { 940 - intel_i965_g33_setup_chipset_flush(); 941 - } else { 942 - intel_i915_setup_chipset_flush(); 943 - } 944 - 945 - if (intel_private.ifp_resource.start) { 946 - intel_private.flush_page = ioremap_nocache(intel_private.ifp_resource.start, PAGE_SIZE); 947 - if (!intel_private.flush_page) 948 - printk("unable to ioremap flush page - no chipset flushing"); 949 - } 950 951 return 0; 952 } 953 954 static void intel_i915_cleanup(void) 955 { 956 - if (intel_private.flush_page) 957 - iounmap(intel_private.flush_page); 958 iounmap(intel_private.gtt); 959 iounmap(intel_private.registers); 960 } 961 962 static void intel_i915_chipset_flush(struct agp_bridge_data *bridge) 963 { 964 - if (intel_private.flush_page) 965 - writel(1, intel_private.flush_page); 966 } 967 968 static int intel_i915_insert_entries(struct agp_memory *mem,off_t pg_start, ··· 1439 pci_write_config_byte(agp_bridge->dev, INTEL_I845_AGPM, temp2 | (1 << 1)); 1440 /* clear any possible error conditions */ 1441 pci_write_config_word(agp_bridge->dev, INTEL_I845_ERRSTS, 0x001c); 1442 return 0; 1443 } 1444 ··· 1697 .agp_alloc_page = agp_generic_alloc_page, 1698 .agp_destroy_page = agp_generic_destroy_page, 1699 .agp_type_to_mask_type = intel_i830_type_to_mask_type, 1700 }; 1701 1702 static const struct agp_bridge_driver intel_820_driver = { ··· 1794 .agp_alloc_page = agp_generic_alloc_page, 1795 .agp_destroy_page = agp_generic_destroy_page, 1796 .agp_type_to_mask_type = agp_generic_type_to_mask_type, 1797 }; 1798 1799 static const struct agp_bridge_driver intel_850_driver = {
··· 117 * popup and for the GTT. 118 */ 119 int gtt_entries; /* i830+ */ 120 + union { 121 + void __iomem *i9xx_flush_page; 122 + void *i8xx_flush_page; 123 + }; 124 + struct page *i8xx_page; 125 struct resource ifp_resource; 126 } intel_private; 127 ··· 579 intel_private.gtt_entries = gtt_entries; 580 } 581 582 + static void intel_i830_fini_flush(void) 583 + { 584 + kunmap(intel_private.i8xx_page); 585 + intel_private.i8xx_flush_page = NULL; 586 + unmap_page_from_agp(intel_private.i8xx_page); 587 + flush_agp_mappings(); 588 + 589 + __free_page(intel_private.i8xx_page); 590 + } 591 + 592 + static void intel_i830_setup_flush(void) 593 + { 594 + 595 + intel_private.i8xx_page = alloc_page(GFP_KERNEL | __GFP_ZERO | GFP_DMA32); 596 + if (!intel_private.i8xx_page) { 597 + return; 598 + } 599 + 600 + /* make page uncached */ 601 + map_page_into_agp(intel_private.i8xx_page); 602 + flush_agp_mappings(); 603 + 604 + intel_private.i8xx_flush_page = kmap(intel_private.i8xx_page); 605 + if (!intel_private.i8xx_flush_page) 606 + intel_i830_fini_flush(); 607 + } 608 + 609 + static void intel_i830_chipset_flush(struct agp_bridge_data *bridge) 610 + { 611 + unsigned int *pg = intel_private.i8xx_flush_page; 612 + int i; 613 + 614 + for (i = 0; i < 256; i+=2) 615 + *(pg + i) = i; 616 + 617 + wmb(); 618 + } 619 + 620 /* The intel i830 automatically initializes the agp aperture during POST. 621 * Use the memory already set aside for in the GTT. 622 */ ··· 679 } 680 681 global_cache_flush(); 682 + 683 + intel_i830_setup_flush(); 684 return 0; 685 } 686 ··· 778 ret = pci_bus_alloc_resource(agp_bridge->dev->bus, &intel_private.ifp_resource, PAGE_SIZE, 779 PAGE_SIZE, PCIBIOS_MIN_MEM, 0, 780 pcibios_align_resource, agp_bridge->dev); 781 782 + return ret; 783 } 784 785 static void intel_i915_setup_chipset_flush(void) ··· 822 823 pci_write_config_dword(agp_bridge->dev, I965_IFPADDR + 4, (intel_private.ifp_resource.start >> 32)); 824 pci_write_config_dword(agp_bridge->dev, I965_IFPADDR, (intel_private.ifp_resource.start & 0xffffffff) | 0x1); 825 } else { 826 u64 l64; 827 ··· 833 intel_private.ifp_resource.end = l64 + PAGE_SIZE; 834 ret = request_resource(&iomem_resource, &intel_private.ifp_resource); 835 if (!ret) { 836 + printk("Failed inserting resource into tree - continuing\n"); 837 } 838 + } 839 + } 840 + 841 + static void intel_i9xx_setup_flush(void) 842 + { 843 + /* setup a resource for this object */ 844 + memset(&intel_private.ifp_resource, 0, sizeof(intel_private.ifp_resource)); 845 + 846 + intel_private.ifp_resource.name = "Intel Flush Page"; 847 + intel_private.ifp_resource.flags = IORESOURCE_MEM; 848 + 849 + /* Setup chipset flush for 915 */ 850 + if (IS_I965 || IS_G33) { 851 + intel_i965_g33_setup_chipset_flush(); 852 + } else { 853 + intel_i915_setup_chipset_flush(); 854 + } 855 + 856 + if (intel_private.ifp_resource.start) { 857 + intel_private.i9xx_flush_page = ioremap_nocache(intel_private.ifp_resource.start, PAGE_SIZE); 858 + if (!intel_private.i9xx_flush_page) 859 + printk("unable to ioremap flush page - no chipset flushing"); 860 } 861 } 862 ··· 868 869 global_cache_flush(); 870 871 + intel_i9xx_setup_flush(); 872 873 return 0; 874 } 875 876 static void intel_i915_cleanup(void) 877 { 878 + if (intel_private.i9xx_flush_page) 879 + iounmap(intel_private.i9xx_flush_page); 880 iounmap(intel_private.gtt); 881 iounmap(intel_private.registers); 882 } 883 884 static void intel_i915_chipset_flush(struct agp_bridge_data *bridge) 885 { 886 + if (intel_private.i9xx_flush_page) 887 + writel(1, intel_private.i9xx_flush_page); 888 } 889 890 static int intel_i915_insert_entries(struct agp_memory *mem,off_t pg_start, ··· 1395 pci_write_config_byte(agp_bridge->dev, INTEL_I845_AGPM, temp2 | (1 << 1)); 1396 /* clear any possible error conditions */ 1397 pci_write_config_word(agp_bridge->dev, INTEL_I845_ERRSTS, 0x001c); 1398 + 1399 + intel_i830_setup_flush(); 1400 return 0; 1401 } 1402 ··· 1651 .agp_alloc_page = agp_generic_alloc_page, 1652 .agp_destroy_page = agp_generic_destroy_page, 1653 .agp_type_to_mask_type = intel_i830_type_to_mask_type, 1654 + .chipset_flush = intel_i830_chipset_flush, 1655 }; 1656 1657 static const struct agp_bridge_driver intel_820_driver = { ··· 1747 .agp_alloc_page = agp_generic_alloc_page, 1748 .agp_destroy_page = agp_generic_destroy_page, 1749 .agp_type_to_mask_type = agp_generic_type_to_mask_type, 1750 + .chipset_flush = intel_i830_chipset_flush, 1751 }; 1752 1753 static const struct agp_bridge_driver intel_850_driver = {