1f51b7662SDaniel Vetter /* 2f51b7662SDaniel Vetter * Intel GTT (Graphics Translation Table) routines 3f51b7662SDaniel Vetter * 4f51b7662SDaniel Vetter * Caveat: This driver implements the linux agp interface, but this is far from 5f51b7662SDaniel Vetter * a agp driver! GTT support ended up here for purely historical reasons: The 6f51b7662SDaniel Vetter * old userspace intel graphics drivers needed an interface to map memory into 7f51b7662SDaniel Vetter * the GTT. And the drm provides a default interface for graphic devices sitting 8f51b7662SDaniel Vetter * on an agp port. So it made sense to fake the GTT support as an agp port to 9f51b7662SDaniel Vetter * avoid having to create a new api. 10f51b7662SDaniel Vetter * 11f51b7662SDaniel Vetter * With gem this does not make much sense anymore, just needlessly complicates 12f51b7662SDaniel Vetter * the code. But as long as the old graphics stack is still support, it's stuck 13f51b7662SDaniel Vetter * here. 14f51b7662SDaniel Vetter * 15f51b7662SDaniel Vetter * /fairy-tale-mode off 16f51b7662SDaniel Vetter */ 17f51b7662SDaniel Vetter 18e2404e7cSDaniel Vetter #include <linux/module.h> 19e2404e7cSDaniel Vetter #include <linux/pci.h> 20e2404e7cSDaniel Vetter #include <linux/init.h> 21e2404e7cSDaniel Vetter #include <linux/kernel.h> 22e2404e7cSDaniel Vetter #include <linux/pagemap.h> 23e2404e7cSDaniel Vetter #include <linux/agp_backend.h> 24e2404e7cSDaniel Vetter #include <asm/smp.h> 25e2404e7cSDaniel Vetter #include "agp.h" 26e2404e7cSDaniel Vetter #include "intel-agp.h" 27e2404e7cSDaniel Vetter #include <linux/intel-gtt.h> 280ade6386SDaniel Vetter #include <drm/intel-gtt.h> 29e2404e7cSDaniel Vetter 30f51b7662SDaniel Vetter /* 31f51b7662SDaniel Vetter * If we have Intel graphics, we're not going to have anything other than 32f51b7662SDaniel Vetter * an Intel IOMMU. So make the correct use of the PCI DMA API contingent 33f51b7662SDaniel Vetter * on the Intel IOMMU support (CONFIG_DMAR). 34f51b7662SDaniel Vetter * Only newer chipsets need to bother with this, of course. 35f51b7662SDaniel Vetter */ 36f51b7662SDaniel Vetter #ifdef CONFIG_DMAR 37f51b7662SDaniel Vetter #define USE_PCI_DMA_API 1 380e87d2b0SDaniel Vetter #else 390e87d2b0SDaniel Vetter #define USE_PCI_DMA_API 0 40f51b7662SDaniel Vetter #endif 41f51b7662SDaniel Vetter 42f51b7662SDaniel Vetter static const struct aper_size_info_fixed intel_i810_sizes[] = 43f51b7662SDaniel Vetter { 44f51b7662SDaniel Vetter {64, 16384, 4}, 45f51b7662SDaniel Vetter /* The 32M mode still requires a 64k gatt */ 46f51b7662SDaniel Vetter {32, 8192, 4} 47f51b7662SDaniel Vetter }; 48f51b7662SDaniel Vetter 49f51b7662SDaniel Vetter #define AGP_DCACHE_MEMORY 1 50f51b7662SDaniel Vetter #define AGP_PHYS_MEMORY 2 51f51b7662SDaniel Vetter #define INTEL_AGP_CACHED_MEMORY 3 52f51b7662SDaniel Vetter 53f51b7662SDaniel Vetter static struct gatt_mask intel_i810_masks[] = 54f51b7662SDaniel Vetter { 55f51b7662SDaniel Vetter {.mask = I810_PTE_VALID, .type = 0}, 56f51b7662SDaniel Vetter {.mask = (I810_PTE_VALID | I810_PTE_LOCAL), .type = AGP_DCACHE_MEMORY}, 57f51b7662SDaniel Vetter {.mask = I810_PTE_VALID, .type = 0}, 58f51b7662SDaniel Vetter {.mask = I810_PTE_VALID | I830_PTE_SYSTEM_CACHED, 59f51b7662SDaniel Vetter .type = INTEL_AGP_CACHED_MEMORY} 60f51b7662SDaniel Vetter }; 61f51b7662SDaniel Vetter 62f8f235e5SZhenyu Wang #define INTEL_AGP_UNCACHED_MEMORY 0 63f8f235e5SZhenyu Wang #define INTEL_AGP_CACHED_MEMORY_LLC 1 64f8f235e5SZhenyu Wang #define INTEL_AGP_CACHED_MEMORY_LLC_GFDT 2 65f8f235e5SZhenyu Wang #define INTEL_AGP_CACHED_MEMORY_LLC_MLC 3 66f8f235e5SZhenyu Wang #define INTEL_AGP_CACHED_MEMORY_LLC_MLC_GFDT 4 67f8f235e5SZhenyu Wang 681a997ff2SDaniel Vetter struct intel_gtt_driver { 691a997ff2SDaniel Vetter unsigned int gen : 8; 701a997ff2SDaniel Vetter unsigned int is_g33 : 1; 711a997ff2SDaniel Vetter unsigned int is_pineview : 1; 721a997ff2SDaniel Vetter unsigned int is_ironlake : 1; 73100519e2SChris Wilson unsigned int has_pgtbl_enable : 1; 7422533b49SDaniel Vetter unsigned int dma_mask_size : 8; 7573800422SDaniel Vetter /* Chipset specific GTT setup */ 7673800422SDaniel Vetter int (*setup)(void); 77ae83dd5cSDaniel Vetter /* This should undo anything done in ->setup() save the unmapping 78ae83dd5cSDaniel Vetter * of the mmio register file, that's done in the generic code. */ 79ae83dd5cSDaniel Vetter void (*cleanup)(void); 80351bb278SDaniel Vetter void (*write_entry)(dma_addr_t addr, unsigned int entry, unsigned int flags); 81351bb278SDaniel Vetter /* Flags is a more or less chipset specific opaque value. 82351bb278SDaniel Vetter * For chipsets that need to support old ums (non-gem) code, this 83351bb278SDaniel Vetter * needs to be identical to the various supported agp memory types! */ 845cbecafcSDaniel Vetter bool (*check_flags)(unsigned int flags); 851b263f24SDaniel Vetter void (*chipset_flush)(void); 861a997ff2SDaniel Vetter }; 871a997ff2SDaniel Vetter 88f51b7662SDaniel Vetter static struct _intel_private { 890ade6386SDaniel Vetter struct intel_gtt base; 901a997ff2SDaniel Vetter const struct intel_gtt_driver *driver; 91f51b7662SDaniel Vetter struct pci_dev *pcidev; /* device one */ 92d7cca2f7SDaniel Vetter struct pci_dev *bridge_dev; 93f51b7662SDaniel Vetter u8 __iomem *registers; 94f67eab66SDaniel Vetter phys_addr_t gtt_bus_addr; 9573800422SDaniel Vetter phys_addr_t gma_bus_addr; 96b3eafc5aSDaniel Vetter u32 PGETBL_save; 97f51b7662SDaniel Vetter u32 __iomem *gtt; /* I915G */ 98f51b7662SDaniel Vetter int num_dcache_entries; 99f51b7662SDaniel Vetter union { 100f51b7662SDaniel Vetter void __iomem *i9xx_flush_page; 101f51b7662SDaniel Vetter void *i8xx_flush_page; 102f51b7662SDaniel Vetter }; 103f51b7662SDaniel Vetter struct page *i8xx_page; 104f51b7662SDaniel Vetter struct resource ifp_resource; 105f51b7662SDaniel Vetter int resource_valid; 1060e87d2b0SDaniel Vetter struct page *scratch_page; 1070e87d2b0SDaniel Vetter dma_addr_t scratch_page_dma; 108f51b7662SDaniel Vetter } intel_private; 109f51b7662SDaniel Vetter 1101a997ff2SDaniel Vetter #define INTEL_GTT_GEN intel_private.driver->gen 1111a997ff2SDaniel Vetter #define IS_G33 intel_private.driver->is_g33 1121a997ff2SDaniel Vetter #define IS_PINEVIEW intel_private.driver->is_pineview 1131a997ff2SDaniel Vetter #define IS_IRONLAKE intel_private.driver->is_ironlake 114100519e2SChris Wilson #define HAS_PGTBL_EN intel_private.driver->has_pgtbl_enable 1151a997ff2SDaniel Vetter 116f51b7662SDaniel Vetter static void intel_agp_free_sglist(struct agp_memory *mem) 117f51b7662SDaniel Vetter { 118f51b7662SDaniel Vetter struct sg_table st; 119f51b7662SDaniel Vetter 120f51b7662SDaniel Vetter st.sgl = mem->sg_list; 121f51b7662SDaniel Vetter st.orig_nents = st.nents = mem->page_count; 122f51b7662SDaniel Vetter 123f51b7662SDaniel Vetter sg_free_table(&st); 124f51b7662SDaniel Vetter 125f51b7662SDaniel Vetter mem->sg_list = NULL; 126f51b7662SDaniel Vetter mem->num_sg = 0; 127f51b7662SDaniel Vetter } 128f51b7662SDaniel Vetter 129f51b7662SDaniel Vetter static int intel_agp_map_memory(struct agp_memory *mem) 130f51b7662SDaniel Vetter { 131f51b7662SDaniel Vetter struct sg_table st; 132f51b7662SDaniel Vetter struct scatterlist *sg; 133f51b7662SDaniel Vetter int i; 134f51b7662SDaniel Vetter 135fefaa70fSDaniel Vetter if (mem->sg_list) 136fefaa70fSDaniel Vetter return 0; /* already mapped (for e.g. resume */ 137fefaa70fSDaniel Vetter 138f51b7662SDaniel Vetter DBG("try mapping %lu pages\n", (unsigned long)mem->page_count); 139f51b7662SDaniel Vetter 140f51b7662SDaniel Vetter if (sg_alloc_table(&st, mem->page_count, GFP_KERNEL)) 141831cd445SChris Wilson goto err; 142f51b7662SDaniel Vetter 143f51b7662SDaniel Vetter mem->sg_list = sg = st.sgl; 144f51b7662SDaniel Vetter 145f51b7662SDaniel Vetter for (i = 0 ; i < mem->page_count; i++, sg = sg_next(sg)) 146f51b7662SDaniel Vetter sg_set_page(sg, mem->pages[i], PAGE_SIZE, 0); 147f51b7662SDaniel Vetter 148f51b7662SDaniel Vetter mem->num_sg = pci_map_sg(intel_private.pcidev, mem->sg_list, 149f51b7662SDaniel Vetter mem->page_count, PCI_DMA_BIDIRECTIONAL); 150831cd445SChris Wilson if (unlikely(!mem->num_sg)) 151831cd445SChris Wilson goto err; 152831cd445SChris Wilson 153f51b7662SDaniel Vetter return 0; 154831cd445SChris Wilson 155831cd445SChris Wilson err: 156831cd445SChris Wilson sg_free_table(&st); 157831cd445SChris Wilson return -ENOMEM; 158f51b7662SDaniel Vetter } 159f51b7662SDaniel Vetter 160f51b7662SDaniel Vetter static void intel_agp_unmap_memory(struct agp_memory *mem) 161f51b7662SDaniel Vetter { 162f51b7662SDaniel Vetter DBG("try unmapping %lu pages\n", (unsigned long)mem->page_count); 163f51b7662SDaniel Vetter 164f51b7662SDaniel Vetter pci_unmap_sg(intel_private.pcidev, mem->sg_list, 165f51b7662SDaniel Vetter mem->page_count, PCI_DMA_BIDIRECTIONAL); 166f51b7662SDaniel Vetter intel_agp_free_sglist(mem); 167f51b7662SDaniel Vetter } 168f51b7662SDaniel Vetter 169f51b7662SDaniel Vetter static int intel_i810_fetch_size(void) 170f51b7662SDaniel Vetter { 171f51b7662SDaniel Vetter u32 smram_miscc; 172f51b7662SDaniel Vetter struct aper_size_info_fixed *values; 173f51b7662SDaniel Vetter 174d7cca2f7SDaniel Vetter pci_read_config_dword(intel_private.bridge_dev, 175d7cca2f7SDaniel Vetter I810_SMRAM_MISCC, &smram_miscc); 176f51b7662SDaniel Vetter values = A_SIZE_FIX(agp_bridge->driver->aperture_sizes); 177f51b7662SDaniel Vetter 178f51b7662SDaniel Vetter if ((smram_miscc & I810_GMS) == I810_GMS_DISABLE) { 179d7cca2f7SDaniel Vetter dev_warn(&intel_private.bridge_dev->dev, "i810 is disabled\n"); 180f51b7662SDaniel Vetter return 0; 181f51b7662SDaniel Vetter } 182f51b7662SDaniel Vetter if ((smram_miscc & I810_GFX_MEM_WIN_SIZE) == I810_GFX_MEM_WIN_32M) { 183f51b7662SDaniel Vetter agp_bridge->current_size = (void *) (values + 1); 184f51b7662SDaniel Vetter agp_bridge->aperture_size_idx = 1; 185f51b7662SDaniel Vetter return values[1].size; 186f51b7662SDaniel Vetter } else { 187f51b7662SDaniel Vetter agp_bridge->current_size = (void *) (values); 188f51b7662SDaniel Vetter agp_bridge->aperture_size_idx = 0; 189f51b7662SDaniel Vetter return values[0].size; 190f51b7662SDaniel Vetter } 191f51b7662SDaniel Vetter 192f51b7662SDaniel Vetter return 0; 193f51b7662SDaniel Vetter } 194f51b7662SDaniel Vetter 195f51b7662SDaniel Vetter static int intel_i810_configure(void) 196f51b7662SDaniel Vetter { 197f51b7662SDaniel Vetter struct aper_size_info_fixed *current_size; 198f51b7662SDaniel Vetter u32 temp; 199f51b7662SDaniel Vetter int i; 200f51b7662SDaniel Vetter 201f51b7662SDaniel Vetter current_size = A_SIZE_FIX(agp_bridge->current_size); 202f51b7662SDaniel Vetter 203f51b7662SDaniel Vetter if (!intel_private.registers) { 204f51b7662SDaniel Vetter pci_read_config_dword(intel_private.pcidev, I810_MMADDR, &temp); 205f51b7662SDaniel Vetter temp &= 0xfff80000; 206f51b7662SDaniel Vetter 207f51b7662SDaniel Vetter intel_private.registers = ioremap(temp, 128 * 4096); 208f51b7662SDaniel Vetter if (!intel_private.registers) { 209f51b7662SDaniel Vetter dev_err(&intel_private.pcidev->dev, 210f51b7662SDaniel Vetter "can't remap memory\n"); 211f51b7662SDaniel Vetter return -ENOMEM; 212f51b7662SDaniel Vetter } 213f51b7662SDaniel Vetter } 214f51b7662SDaniel Vetter 215f51b7662SDaniel Vetter if ((readl(intel_private.registers+I810_DRAM_CTL) 216f51b7662SDaniel Vetter & I810_DRAM_ROW_0) == I810_DRAM_ROW_0_SDRAM) { 217f51b7662SDaniel Vetter /* This will need to be dynamically assigned */ 218f51b7662SDaniel Vetter dev_info(&intel_private.pcidev->dev, 219f51b7662SDaniel Vetter "detected 4MB dedicated video ram\n"); 220f51b7662SDaniel Vetter intel_private.num_dcache_entries = 1024; 221f51b7662SDaniel Vetter } 222f51b7662SDaniel Vetter pci_read_config_dword(intel_private.pcidev, I810_GMADDR, &temp); 223f51b7662SDaniel Vetter agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); 224f51b7662SDaniel Vetter writel(agp_bridge->gatt_bus_addr | I810_PGETBL_ENABLED, intel_private.registers+I810_PGETBL_CTL); 225f51b7662SDaniel Vetter readl(intel_private.registers+I810_PGETBL_CTL); /* PCI Posting. */ 226f51b7662SDaniel Vetter 227f51b7662SDaniel Vetter if (agp_bridge->driver->needs_scratch_page) { 228f51b7662SDaniel Vetter for (i = 0; i < current_size->num_entries; i++) { 229f51b7662SDaniel Vetter writel(agp_bridge->scratch_page, intel_private.registers+I810_PTE_BASE+(i*4)); 230f51b7662SDaniel Vetter } 231f51b7662SDaniel Vetter readl(intel_private.registers+I810_PTE_BASE+((i-1)*4)); /* PCI posting. */ 232f51b7662SDaniel Vetter } 233f51b7662SDaniel Vetter global_cache_flush(); 234f51b7662SDaniel Vetter return 0; 235f51b7662SDaniel Vetter } 236f51b7662SDaniel Vetter 237f51b7662SDaniel Vetter static void intel_i810_cleanup(void) 238f51b7662SDaniel Vetter { 239f51b7662SDaniel Vetter writel(0, intel_private.registers+I810_PGETBL_CTL); 240f51b7662SDaniel Vetter readl(intel_private.registers); /* PCI Posting. */ 241f51b7662SDaniel Vetter iounmap(intel_private.registers); 242f51b7662SDaniel Vetter } 243f51b7662SDaniel Vetter 244ffdd7510SDaniel Vetter static void intel_fake_agp_enable(struct agp_bridge_data *bridge, u32 mode) 245f51b7662SDaniel Vetter { 246f51b7662SDaniel Vetter return; 247f51b7662SDaniel Vetter } 248f51b7662SDaniel Vetter 249f51b7662SDaniel Vetter /* Exists to support ARGB cursors */ 250f51b7662SDaniel Vetter static struct page *i8xx_alloc_pages(void) 251f51b7662SDaniel Vetter { 252f51b7662SDaniel Vetter struct page *page; 253f51b7662SDaniel Vetter 254f51b7662SDaniel Vetter page = alloc_pages(GFP_KERNEL | GFP_DMA32, 2); 255f51b7662SDaniel Vetter if (page == NULL) 256f51b7662SDaniel Vetter return NULL; 257f51b7662SDaniel Vetter 258f51b7662SDaniel Vetter if (set_pages_uc(page, 4) < 0) { 259f51b7662SDaniel Vetter set_pages_wb(page, 4); 260f51b7662SDaniel Vetter __free_pages(page, 2); 261f51b7662SDaniel Vetter return NULL; 262f51b7662SDaniel Vetter } 263f51b7662SDaniel Vetter get_page(page); 264f51b7662SDaniel Vetter atomic_inc(&agp_bridge->current_memory_agp); 265f51b7662SDaniel Vetter return page; 266f51b7662SDaniel Vetter } 267f51b7662SDaniel Vetter 268f51b7662SDaniel Vetter static void i8xx_destroy_pages(struct page *page) 269f51b7662SDaniel Vetter { 270f51b7662SDaniel Vetter if (page == NULL) 271f51b7662SDaniel Vetter return; 272f51b7662SDaniel Vetter 273f51b7662SDaniel Vetter set_pages_wb(page, 4); 274f51b7662SDaniel Vetter put_page(page); 275f51b7662SDaniel Vetter __free_pages(page, 2); 276f51b7662SDaniel Vetter atomic_dec(&agp_bridge->current_memory_agp); 277f51b7662SDaniel Vetter } 278f51b7662SDaniel Vetter 279f51b7662SDaniel Vetter static int intel_i810_insert_entries(struct agp_memory *mem, off_t pg_start, 280f51b7662SDaniel Vetter int type) 281f51b7662SDaniel Vetter { 282f51b7662SDaniel Vetter int i, j, num_entries; 283f51b7662SDaniel Vetter void *temp; 284f51b7662SDaniel Vetter int ret = -EINVAL; 285f51b7662SDaniel Vetter int mask_type; 286f51b7662SDaniel Vetter 287f51b7662SDaniel Vetter if (mem->page_count == 0) 288f51b7662SDaniel Vetter goto out; 289f51b7662SDaniel Vetter 290f51b7662SDaniel Vetter temp = agp_bridge->current_size; 291f51b7662SDaniel Vetter num_entries = A_SIZE_FIX(temp)->num_entries; 292f51b7662SDaniel Vetter 293f51b7662SDaniel Vetter if ((pg_start + mem->page_count) > num_entries) 294f51b7662SDaniel Vetter goto out_err; 295f51b7662SDaniel Vetter 296f51b7662SDaniel Vetter 297f51b7662SDaniel Vetter for (j = pg_start; j < (pg_start + mem->page_count); j++) { 298f51b7662SDaniel Vetter if (!PGE_EMPTY(agp_bridge, readl(agp_bridge->gatt_table+j))) { 299f51b7662SDaniel Vetter ret = -EBUSY; 300f51b7662SDaniel Vetter goto out_err; 301f51b7662SDaniel Vetter } 302f51b7662SDaniel Vetter } 303f51b7662SDaniel Vetter 304f51b7662SDaniel Vetter if (type != mem->type) 305f51b7662SDaniel Vetter goto out_err; 306f51b7662SDaniel Vetter 307f51b7662SDaniel Vetter mask_type = agp_bridge->driver->agp_type_to_mask_type(agp_bridge, type); 308f51b7662SDaniel Vetter 309f51b7662SDaniel Vetter switch (mask_type) { 310f51b7662SDaniel Vetter case AGP_DCACHE_MEMORY: 311f51b7662SDaniel Vetter if (!mem->is_flushed) 312f51b7662SDaniel Vetter global_cache_flush(); 313f51b7662SDaniel Vetter for (i = pg_start; i < (pg_start + mem->page_count); i++) { 314f51b7662SDaniel Vetter writel((i*4096)|I810_PTE_LOCAL|I810_PTE_VALID, 315f51b7662SDaniel Vetter intel_private.registers+I810_PTE_BASE+(i*4)); 316f51b7662SDaniel Vetter } 317f51b7662SDaniel Vetter readl(intel_private.registers+I810_PTE_BASE+((i-1)*4)); 318f51b7662SDaniel Vetter break; 319f51b7662SDaniel Vetter case AGP_PHYS_MEMORY: 320f51b7662SDaniel Vetter case AGP_NORMAL_MEMORY: 321f51b7662SDaniel Vetter if (!mem->is_flushed) 322f51b7662SDaniel Vetter global_cache_flush(); 323f51b7662SDaniel Vetter for (i = 0, j = pg_start; i < mem->page_count; i++, j++) { 324f51b7662SDaniel Vetter writel(agp_bridge->driver->mask_memory(agp_bridge, 325f51b7662SDaniel Vetter page_to_phys(mem->pages[i]), mask_type), 326f51b7662SDaniel Vetter intel_private.registers+I810_PTE_BASE+(j*4)); 327f51b7662SDaniel Vetter } 328f51b7662SDaniel Vetter readl(intel_private.registers+I810_PTE_BASE+((j-1)*4)); 329f51b7662SDaniel Vetter break; 330f51b7662SDaniel Vetter default: 331f51b7662SDaniel Vetter goto out_err; 332f51b7662SDaniel Vetter } 333f51b7662SDaniel Vetter 334f51b7662SDaniel Vetter out: 335f51b7662SDaniel Vetter ret = 0; 336f51b7662SDaniel Vetter out_err: 337f51b7662SDaniel Vetter mem->is_flushed = true; 338f51b7662SDaniel Vetter return ret; 339f51b7662SDaniel Vetter } 340f51b7662SDaniel Vetter 341f51b7662SDaniel Vetter static int intel_i810_remove_entries(struct agp_memory *mem, off_t pg_start, 342f51b7662SDaniel Vetter int type) 343f51b7662SDaniel Vetter { 344f51b7662SDaniel Vetter int i; 345f51b7662SDaniel Vetter 346f51b7662SDaniel Vetter if (mem->page_count == 0) 347f51b7662SDaniel Vetter return 0; 348f51b7662SDaniel Vetter 349f51b7662SDaniel Vetter for (i = pg_start; i < (mem->page_count + pg_start); i++) { 350f51b7662SDaniel Vetter writel(agp_bridge->scratch_page, intel_private.registers+I810_PTE_BASE+(i*4)); 351f51b7662SDaniel Vetter } 352f51b7662SDaniel Vetter readl(intel_private.registers+I810_PTE_BASE+((i-1)*4)); 353f51b7662SDaniel Vetter 354f51b7662SDaniel Vetter return 0; 355f51b7662SDaniel Vetter } 356f51b7662SDaniel Vetter 357f51b7662SDaniel Vetter /* 358f51b7662SDaniel Vetter * The i810/i830 requires a physical address to program its mouse 359f51b7662SDaniel Vetter * pointer into hardware. 360f51b7662SDaniel Vetter * However the Xserver still writes to it through the agp aperture. 361f51b7662SDaniel Vetter */ 362f51b7662SDaniel Vetter static struct agp_memory *alloc_agpphysmem_i8xx(size_t pg_count, int type) 363f51b7662SDaniel Vetter { 364f51b7662SDaniel Vetter struct agp_memory *new; 365f51b7662SDaniel Vetter struct page *page; 366f51b7662SDaniel Vetter 367f51b7662SDaniel Vetter switch (pg_count) { 368f51b7662SDaniel Vetter case 1: page = agp_bridge->driver->agp_alloc_page(agp_bridge); 369f51b7662SDaniel Vetter break; 370f51b7662SDaniel Vetter case 4: 371f51b7662SDaniel Vetter /* kludge to get 4 physical pages for ARGB cursor */ 372f51b7662SDaniel Vetter page = i8xx_alloc_pages(); 373f51b7662SDaniel Vetter break; 374f51b7662SDaniel Vetter default: 375f51b7662SDaniel Vetter return NULL; 376f51b7662SDaniel Vetter } 377f51b7662SDaniel Vetter 378f51b7662SDaniel Vetter if (page == NULL) 379f51b7662SDaniel Vetter return NULL; 380f51b7662SDaniel Vetter 381f51b7662SDaniel Vetter new = agp_create_memory(pg_count); 382f51b7662SDaniel Vetter if (new == NULL) 383f51b7662SDaniel Vetter return NULL; 384f51b7662SDaniel Vetter 385f51b7662SDaniel Vetter new->pages[0] = page; 386f51b7662SDaniel Vetter if (pg_count == 4) { 387f51b7662SDaniel Vetter /* kludge to get 4 physical pages for ARGB cursor */ 388f51b7662SDaniel Vetter new->pages[1] = new->pages[0] + 1; 389f51b7662SDaniel Vetter new->pages[2] = new->pages[1] + 1; 390f51b7662SDaniel Vetter new->pages[3] = new->pages[2] + 1; 391f51b7662SDaniel Vetter } 392f51b7662SDaniel Vetter new->page_count = pg_count; 393f51b7662SDaniel Vetter new->num_scratch_pages = pg_count; 394f51b7662SDaniel Vetter new->type = AGP_PHYS_MEMORY; 395f51b7662SDaniel Vetter new->physical = page_to_phys(new->pages[0]); 396f51b7662SDaniel Vetter return new; 397f51b7662SDaniel Vetter } 398f51b7662SDaniel Vetter 399f51b7662SDaniel Vetter static struct agp_memory *intel_i810_alloc_by_type(size_t pg_count, int type) 400f51b7662SDaniel Vetter { 401f51b7662SDaniel Vetter struct agp_memory *new; 402f51b7662SDaniel Vetter 403f51b7662SDaniel Vetter if (type == AGP_DCACHE_MEMORY) { 404f51b7662SDaniel Vetter if (pg_count != intel_private.num_dcache_entries) 405f51b7662SDaniel Vetter return NULL; 406f51b7662SDaniel Vetter 407f51b7662SDaniel Vetter new = agp_create_memory(1); 408f51b7662SDaniel Vetter if (new == NULL) 409f51b7662SDaniel Vetter return NULL; 410f51b7662SDaniel Vetter 411f51b7662SDaniel Vetter new->type = AGP_DCACHE_MEMORY; 412f51b7662SDaniel Vetter new->page_count = pg_count; 413f51b7662SDaniel Vetter new->num_scratch_pages = 0; 414f51b7662SDaniel Vetter agp_free_page_array(new); 415f51b7662SDaniel Vetter return new; 416f51b7662SDaniel Vetter } 417f51b7662SDaniel Vetter if (type == AGP_PHYS_MEMORY) 418f51b7662SDaniel Vetter return alloc_agpphysmem_i8xx(pg_count, type); 419f51b7662SDaniel Vetter return NULL; 420f51b7662SDaniel Vetter } 421f51b7662SDaniel Vetter 422f51b7662SDaniel Vetter static void intel_i810_free_by_type(struct agp_memory *curr) 423f51b7662SDaniel Vetter { 424f51b7662SDaniel Vetter agp_free_key(curr->key); 425f51b7662SDaniel Vetter if (curr->type == AGP_PHYS_MEMORY) { 426f51b7662SDaniel Vetter if (curr->page_count == 4) 427f51b7662SDaniel Vetter i8xx_destroy_pages(curr->pages[0]); 428f51b7662SDaniel Vetter else { 429f51b7662SDaniel Vetter agp_bridge->driver->agp_destroy_page(curr->pages[0], 430f51b7662SDaniel Vetter AGP_PAGE_DESTROY_UNMAP); 431f51b7662SDaniel Vetter agp_bridge->driver->agp_destroy_page(curr->pages[0], 432f51b7662SDaniel Vetter AGP_PAGE_DESTROY_FREE); 433f51b7662SDaniel Vetter } 434f51b7662SDaniel Vetter agp_free_page_array(curr); 435f51b7662SDaniel Vetter } 436f51b7662SDaniel Vetter kfree(curr); 437f51b7662SDaniel Vetter } 438f51b7662SDaniel Vetter 439f51b7662SDaniel Vetter static unsigned long intel_i810_mask_memory(struct agp_bridge_data *bridge, 440f51b7662SDaniel Vetter dma_addr_t addr, int type) 441f51b7662SDaniel Vetter { 442f51b7662SDaniel Vetter /* Type checking must be done elsewhere */ 443f51b7662SDaniel Vetter return addr | bridge->driver->masks[type].mask; 444f51b7662SDaniel Vetter } 445f51b7662SDaniel Vetter 4460e87d2b0SDaniel Vetter static int intel_gtt_setup_scratch_page(void) 4470e87d2b0SDaniel Vetter { 4480e87d2b0SDaniel Vetter struct page *page; 4490e87d2b0SDaniel Vetter dma_addr_t dma_addr; 4500e87d2b0SDaniel Vetter 4510e87d2b0SDaniel Vetter page = alloc_page(GFP_KERNEL | GFP_DMA32 | __GFP_ZERO); 4520e87d2b0SDaniel Vetter if (page == NULL) 4530e87d2b0SDaniel Vetter return -ENOMEM; 4540e87d2b0SDaniel Vetter get_page(page); 4550e87d2b0SDaniel Vetter set_pages_uc(page, 1); 4560e87d2b0SDaniel Vetter 4570e87d2b0SDaniel Vetter if (USE_PCI_DMA_API && INTEL_GTT_GEN > 2) { 4580e87d2b0SDaniel Vetter dma_addr = pci_map_page(intel_private.pcidev, page, 0, 4590e87d2b0SDaniel Vetter PAGE_SIZE, PCI_DMA_BIDIRECTIONAL); 4600e87d2b0SDaniel Vetter if (pci_dma_mapping_error(intel_private.pcidev, dma_addr)) 4610e87d2b0SDaniel Vetter return -EINVAL; 4620e87d2b0SDaniel Vetter 4630e87d2b0SDaniel Vetter intel_private.scratch_page_dma = dma_addr; 4640e87d2b0SDaniel Vetter } else 4650e87d2b0SDaniel Vetter intel_private.scratch_page_dma = page_to_phys(page); 4660e87d2b0SDaniel Vetter 4670e87d2b0SDaniel Vetter intel_private.scratch_page = page; 4680e87d2b0SDaniel Vetter 4690e87d2b0SDaniel Vetter return 0; 4700e87d2b0SDaniel Vetter } 4710e87d2b0SDaniel Vetter 4729e76e7b8SChris Wilson static const struct aper_size_info_fixed const intel_fake_agp_sizes[] = { 473f51b7662SDaniel Vetter {128, 32768, 5}, 474f51b7662SDaniel Vetter /* The 64M mode still requires a 128k gatt */ 475f51b7662SDaniel Vetter {64, 16384, 5}, 476f51b7662SDaniel Vetter {256, 65536, 6}, 477f51b7662SDaniel Vetter {512, 131072, 7}, 478f51b7662SDaniel Vetter }; 479f51b7662SDaniel Vetter 480bfde067bSDaniel Vetter static unsigned int intel_gtt_stolen_entries(void) 481f51b7662SDaniel Vetter { 482f51b7662SDaniel Vetter u16 gmch_ctrl; 483f51b7662SDaniel Vetter u8 rdct; 484f51b7662SDaniel Vetter int local = 0; 485f51b7662SDaniel Vetter static const int ddt[4] = { 0, 16, 32, 64 }; 4861b6064d7SChris Wilson unsigned int overhead_entries; 487d8d9abcdSDaniel Vetter unsigned int stolen_size = 0; 488f51b7662SDaniel Vetter 489d7cca2f7SDaniel Vetter pci_read_config_word(intel_private.bridge_dev, 490d7cca2f7SDaniel Vetter I830_GMCH_CTRL, &gmch_ctrl); 491f51b7662SDaniel Vetter 4921a997ff2SDaniel Vetter if (INTEL_GTT_GEN > 4 || IS_PINEVIEW) 493fbe40783SDaniel Vetter overhead_entries = 0; 494fbe40783SDaniel Vetter else 495fbe40783SDaniel Vetter overhead_entries = intel_private.base.gtt_mappable_entries 496fbe40783SDaniel Vetter / 1024; 497f51b7662SDaniel Vetter 498fbe40783SDaniel Vetter overhead_entries += 1; /* BIOS popup */ 499d8d9abcdSDaniel Vetter 500d7cca2f7SDaniel Vetter if (intel_private.bridge_dev->device == PCI_DEVICE_ID_INTEL_82830_HB || 501d7cca2f7SDaniel Vetter intel_private.bridge_dev->device == PCI_DEVICE_ID_INTEL_82845G_HB) { 502f51b7662SDaniel Vetter switch (gmch_ctrl & I830_GMCH_GMS_MASK) { 503f51b7662SDaniel Vetter case I830_GMCH_GMS_STOLEN_512: 504d8d9abcdSDaniel Vetter stolen_size = KB(512); 505f51b7662SDaniel Vetter break; 506f51b7662SDaniel Vetter case I830_GMCH_GMS_STOLEN_1024: 507d8d9abcdSDaniel Vetter stolen_size = MB(1); 508f51b7662SDaniel Vetter break; 509f51b7662SDaniel Vetter case I830_GMCH_GMS_STOLEN_8192: 510d8d9abcdSDaniel Vetter stolen_size = MB(8); 511f51b7662SDaniel Vetter break; 512f51b7662SDaniel Vetter case I830_GMCH_GMS_LOCAL: 513f51b7662SDaniel Vetter rdct = readb(intel_private.registers+I830_RDRAM_CHANNEL_TYPE); 514d8d9abcdSDaniel Vetter stolen_size = (I830_RDRAM_ND(rdct) + 1) * 515f51b7662SDaniel Vetter MB(ddt[I830_RDRAM_DDT(rdct)]); 516f51b7662SDaniel Vetter local = 1; 517f51b7662SDaniel Vetter break; 518f51b7662SDaniel Vetter default: 519d8d9abcdSDaniel Vetter stolen_size = 0; 520f51b7662SDaniel Vetter break; 521f51b7662SDaniel Vetter } 5221a997ff2SDaniel Vetter } else if (INTEL_GTT_GEN == 6) { 523f51b7662SDaniel Vetter /* 524f51b7662SDaniel Vetter * SandyBridge has new memory control reg at 0x50.w 525f51b7662SDaniel Vetter */ 526f51b7662SDaniel Vetter u16 snb_gmch_ctl; 527f51b7662SDaniel Vetter pci_read_config_word(intel_private.pcidev, SNB_GMCH_CTRL, &snb_gmch_ctl); 528f51b7662SDaniel Vetter switch (snb_gmch_ctl & SNB_GMCH_GMS_STOLEN_MASK) { 529f51b7662SDaniel Vetter case SNB_GMCH_GMS_STOLEN_32M: 530d8d9abcdSDaniel Vetter stolen_size = MB(32); 531f51b7662SDaniel Vetter break; 532f51b7662SDaniel Vetter case SNB_GMCH_GMS_STOLEN_64M: 533d8d9abcdSDaniel Vetter stolen_size = MB(64); 534f51b7662SDaniel Vetter break; 535f51b7662SDaniel Vetter case SNB_GMCH_GMS_STOLEN_96M: 536d8d9abcdSDaniel Vetter stolen_size = MB(96); 537f51b7662SDaniel Vetter break; 538f51b7662SDaniel Vetter case SNB_GMCH_GMS_STOLEN_128M: 539d8d9abcdSDaniel Vetter stolen_size = MB(128); 540f51b7662SDaniel Vetter break; 541f51b7662SDaniel Vetter case SNB_GMCH_GMS_STOLEN_160M: 542d8d9abcdSDaniel Vetter stolen_size = MB(160); 543f51b7662SDaniel Vetter break; 544f51b7662SDaniel Vetter case SNB_GMCH_GMS_STOLEN_192M: 545d8d9abcdSDaniel Vetter stolen_size = MB(192); 546f51b7662SDaniel Vetter break; 547f51b7662SDaniel Vetter case SNB_GMCH_GMS_STOLEN_224M: 548d8d9abcdSDaniel Vetter stolen_size = MB(224); 549f51b7662SDaniel Vetter break; 550f51b7662SDaniel Vetter case SNB_GMCH_GMS_STOLEN_256M: 551d8d9abcdSDaniel Vetter stolen_size = MB(256); 552f51b7662SDaniel Vetter break; 553f51b7662SDaniel Vetter case SNB_GMCH_GMS_STOLEN_288M: 554d8d9abcdSDaniel Vetter stolen_size = MB(288); 555f51b7662SDaniel Vetter break; 556f51b7662SDaniel Vetter case SNB_GMCH_GMS_STOLEN_320M: 557d8d9abcdSDaniel Vetter stolen_size = MB(320); 558f51b7662SDaniel Vetter break; 559f51b7662SDaniel Vetter case SNB_GMCH_GMS_STOLEN_352M: 560d8d9abcdSDaniel Vetter stolen_size = MB(352); 561f51b7662SDaniel Vetter break; 562f51b7662SDaniel Vetter case SNB_GMCH_GMS_STOLEN_384M: 563d8d9abcdSDaniel Vetter stolen_size = MB(384); 564f51b7662SDaniel Vetter break; 565f51b7662SDaniel Vetter case SNB_GMCH_GMS_STOLEN_416M: 566d8d9abcdSDaniel Vetter stolen_size = MB(416); 567f51b7662SDaniel Vetter break; 568f51b7662SDaniel Vetter case SNB_GMCH_GMS_STOLEN_448M: 569d8d9abcdSDaniel Vetter stolen_size = MB(448); 570f51b7662SDaniel Vetter break; 571f51b7662SDaniel Vetter case SNB_GMCH_GMS_STOLEN_480M: 572d8d9abcdSDaniel Vetter stolen_size = MB(480); 573f51b7662SDaniel Vetter break; 574f51b7662SDaniel Vetter case SNB_GMCH_GMS_STOLEN_512M: 575d8d9abcdSDaniel Vetter stolen_size = MB(512); 576f51b7662SDaniel Vetter break; 577f51b7662SDaniel Vetter } 578f51b7662SDaniel Vetter } else { 579f51b7662SDaniel Vetter switch (gmch_ctrl & I855_GMCH_GMS_MASK) { 580f51b7662SDaniel Vetter case I855_GMCH_GMS_STOLEN_1M: 581d8d9abcdSDaniel Vetter stolen_size = MB(1); 582f51b7662SDaniel Vetter break; 583f51b7662SDaniel Vetter case I855_GMCH_GMS_STOLEN_4M: 584d8d9abcdSDaniel Vetter stolen_size = MB(4); 585f51b7662SDaniel Vetter break; 586f51b7662SDaniel Vetter case I855_GMCH_GMS_STOLEN_8M: 587d8d9abcdSDaniel Vetter stolen_size = MB(8); 588f51b7662SDaniel Vetter break; 589f51b7662SDaniel Vetter case I855_GMCH_GMS_STOLEN_16M: 590d8d9abcdSDaniel Vetter stolen_size = MB(16); 591f51b7662SDaniel Vetter break; 592f51b7662SDaniel Vetter case I855_GMCH_GMS_STOLEN_32M: 593d8d9abcdSDaniel Vetter stolen_size = MB(32); 594f51b7662SDaniel Vetter break; 595f51b7662SDaniel Vetter case I915_GMCH_GMS_STOLEN_48M: 596d8d9abcdSDaniel Vetter stolen_size = MB(48); 597f51b7662SDaniel Vetter break; 598f51b7662SDaniel Vetter case I915_GMCH_GMS_STOLEN_64M: 599d8d9abcdSDaniel Vetter stolen_size = MB(64); 600f51b7662SDaniel Vetter break; 601f51b7662SDaniel Vetter case G33_GMCH_GMS_STOLEN_128M: 602d8d9abcdSDaniel Vetter stolen_size = MB(128); 603f51b7662SDaniel Vetter break; 604f51b7662SDaniel Vetter case G33_GMCH_GMS_STOLEN_256M: 605d8d9abcdSDaniel Vetter stolen_size = MB(256); 606f51b7662SDaniel Vetter break; 607f51b7662SDaniel Vetter case INTEL_GMCH_GMS_STOLEN_96M: 608d8d9abcdSDaniel Vetter stolen_size = MB(96); 609f51b7662SDaniel Vetter break; 610f51b7662SDaniel Vetter case INTEL_GMCH_GMS_STOLEN_160M: 611d8d9abcdSDaniel Vetter stolen_size = MB(160); 612f51b7662SDaniel Vetter break; 613f51b7662SDaniel Vetter case INTEL_GMCH_GMS_STOLEN_224M: 614d8d9abcdSDaniel Vetter stolen_size = MB(224); 615f51b7662SDaniel Vetter break; 616f51b7662SDaniel Vetter case INTEL_GMCH_GMS_STOLEN_352M: 617d8d9abcdSDaniel Vetter stolen_size = MB(352); 618f51b7662SDaniel Vetter break; 619f51b7662SDaniel Vetter default: 620d8d9abcdSDaniel Vetter stolen_size = 0; 621f51b7662SDaniel Vetter break; 622f51b7662SDaniel Vetter } 623f51b7662SDaniel Vetter } 6241784a5fbSDaniel Vetter 6251b6064d7SChris Wilson if (stolen_size > 0) { 626d7cca2f7SDaniel Vetter dev_info(&intel_private.bridge_dev->dev, "detected %dK %s memory\n", 627d8d9abcdSDaniel Vetter stolen_size / KB(1), local ? "local" : "stolen"); 628f51b7662SDaniel Vetter } else { 629d7cca2f7SDaniel Vetter dev_info(&intel_private.bridge_dev->dev, 630f51b7662SDaniel Vetter "no pre-allocated video memory detected\n"); 631d8d9abcdSDaniel Vetter stolen_size = 0; 632f51b7662SDaniel Vetter } 633f51b7662SDaniel Vetter 6341b6064d7SChris Wilson return stolen_size/KB(4) - overhead_entries; 635f51b7662SDaniel Vetter } 636f51b7662SDaniel Vetter 63720172842SDaniel Vetter static void i965_adjust_pgetbl_size(unsigned int size_flag) 63820172842SDaniel Vetter { 63920172842SDaniel Vetter u32 pgetbl_ctl, pgetbl_ctl2; 64020172842SDaniel Vetter 64120172842SDaniel Vetter /* ensure that ppgtt is disabled */ 64220172842SDaniel Vetter pgetbl_ctl2 = readl(intel_private.registers+I965_PGETBL_CTL2); 64320172842SDaniel Vetter pgetbl_ctl2 &= ~I810_PGETBL_ENABLED; 64420172842SDaniel Vetter writel(pgetbl_ctl2, intel_private.registers+I965_PGETBL_CTL2); 64520172842SDaniel Vetter 64620172842SDaniel Vetter /* write the new ggtt size */ 64720172842SDaniel Vetter pgetbl_ctl = readl(intel_private.registers+I810_PGETBL_CTL); 64820172842SDaniel Vetter pgetbl_ctl &= ~I965_PGETBL_SIZE_MASK; 64920172842SDaniel Vetter pgetbl_ctl |= size_flag; 65020172842SDaniel Vetter writel(pgetbl_ctl, intel_private.registers+I810_PGETBL_CTL); 65120172842SDaniel Vetter } 65220172842SDaniel Vetter 65320172842SDaniel Vetter static unsigned int i965_gtt_total_entries(void) 654fbe40783SDaniel Vetter { 655fbe40783SDaniel Vetter int size; 656fbe40783SDaniel Vetter u32 pgetbl_ctl; 65720172842SDaniel Vetter u16 gmch_ctl; 65820172842SDaniel Vetter 65920172842SDaniel Vetter pci_read_config_word(intel_private.bridge_dev, 66020172842SDaniel Vetter I830_GMCH_CTRL, &gmch_ctl); 66120172842SDaniel Vetter 66220172842SDaniel Vetter if (INTEL_GTT_GEN == 5) { 66320172842SDaniel Vetter switch (gmch_ctl & G4x_GMCH_SIZE_MASK) { 66420172842SDaniel Vetter case G4x_GMCH_SIZE_1M: 66520172842SDaniel Vetter case G4x_GMCH_SIZE_VT_1M: 66620172842SDaniel Vetter i965_adjust_pgetbl_size(I965_PGETBL_SIZE_1MB); 66720172842SDaniel Vetter break; 66820172842SDaniel Vetter case G4x_GMCH_SIZE_VT_1_5M: 66920172842SDaniel Vetter i965_adjust_pgetbl_size(I965_PGETBL_SIZE_1_5MB); 67020172842SDaniel Vetter break; 67120172842SDaniel Vetter case G4x_GMCH_SIZE_2M: 67220172842SDaniel Vetter case G4x_GMCH_SIZE_VT_2M: 67320172842SDaniel Vetter i965_adjust_pgetbl_size(I965_PGETBL_SIZE_2MB); 67420172842SDaniel Vetter break; 67520172842SDaniel Vetter } 67620172842SDaniel Vetter } 67720172842SDaniel Vetter 678fbe40783SDaniel Vetter pgetbl_ctl = readl(intel_private.registers+I810_PGETBL_CTL); 679fbe40783SDaniel Vetter 680fbe40783SDaniel Vetter switch (pgetbl_ctl & I965_PGETBL_SIZE_MASK) { 681fbe40783SDaniel Vetter case I965_PGETBL_SIZE_128KB: 682e5e408fcSDaniel Vetter size = KB(128); 683fbe40783SDaniel Vetter break; 684fbe40783SDaniel Vetter case I965_PGETBL_SIZE_256KB: 685e5e408fcSDaniel Vetter size = KB(256); 686fbe40783SDaniel Vetter break; 687fbe40783SDaniel Vetter case I965_PGETBL_SIZE_512KB: 688e5e408fcSDaniel Vetter size = KB(512); 689fbe40783SDaniel Vetter break; 69020172842SDaniel Vetter /* GTT pagetable sizes bigger than 512KB are not possible on G33! */ 691fbe40783SDaniel Vetter case I965_PGETBL_SIZE_1MB: 692e5e408fcSDaniel Vetter size = KB(1024); 693fbe40783SDaniel Vetter break; 694fbe40783SDaniel Vetter case I965_PGETBL_SIZE_2MB: 695e5e408fcSDaniel Vetter size = KB(2048); 696fbe40783SDaniel Vetter break; 697fbe40783SDaniel Vetter case I965_PGETBL_SIZE_1_5MB: 698e5e408fcSDaniel Vetter size = KB(1024 + 512); 699fbe40783SDaniel Vetter break; 700fbe40783SDaniel Vetter default: 701fbe40783SDaniel Vetter dev_info(&intel_private.pcidev->dev, 702fbe40783SDaniel Vetter "unknown page table size, assuming 512KB\n"); 703e5e408fcSDaniel Vetter size = KB(512); 704fbe40783SDaniel Vetter } 705e5e408fcSDaniel Vetter 706e5e408fcSDaniel Vetter return size/4; 70720172842SDaniel Vetter } 70820172842SDaniel Vetter 70920172842SDaniel Vetter static unsigned int intel_gtt_total_entries(void) 71020172842SDaniel Vetter { 71120172842SDaniel Vetter int size; 71220172842SDaniel Vetter 71320172842SDaniel Vetter if (IS_G33 || INTEL_GTT_GEN == 4 || INTEL_GTT_GEN == 5) 71420172842SDaniel Vetter return i965_gtt_total_entries(); 71520172842SDaniel Vetter else if (INTEL_GTT_GEN == 6) { 716210b23c2SDaniel Vetter u16 snb_gmch_ctl; 717210b23c2SDaniel Vetter 718210b23c2SDaniel Vetter pci_read_config_word(intel_private.pcidev, SNB_GMCH_CTRL, &snb_gmch_ctl); 719210b23c2SDaniel Vetter switch (snb_gmch_ctl & SNB_GTT_SIZE_MASK) { 720210b23c2SDaniel Vetter default: 721210b23c2SDaniel Vetter case SNB_GTT_SIZE_0M: 722210b23c2SDaniel Vetter printk(KERN_ERR "Bad GTT size mask: 0x%04x.\n", snb_gmch_ctl); 723210b23c2SDaniel Vetter size = MB(0); 724210b23c2SDaniel Vetter break; 725210b23c2SDaniel Vetter case SNB_GTT_SIZE_1M: 726210b23c2SDaniel Vetter size = MB(1); 727210b23c2SDaniel Vetter break; 728210b23c2SDaniel Vetter case SNB_GTT_SIZE_2M: 729210b23c2SDaniel Vetter size = MB(2); 730210b23c2SDaniel Vetter break; 731210b23c2SDaniel Vetter } 732210b23c2SDaniel Vetter return size/4; 733fbe40783SDaniel Vetter } else { 734fbe40783SDaniel Vetter /* On previous hardware, the GTT size was just what was 735fbe40783SDaniel Vetter * required to map the aperture. 736fbe40783SDaniel Vetter */ 737e5e408fcSDaniel Vetter return intel_private.base.gtt_mappable_entries; 738fbe40783SDaniel Vetter } 739fbe40783SDaniel Vetter } 740fbe40783SDaniel Vetter 7411784a5fbSDaniel Vetter static unsigned int intel_gtt_mappable_entries(void) 7421784a5fbSDaniel Vetter { 7431784a5fbSDaniel Vetter unsigned int aperture_size; 7441784a5fbSDaniel Vetter 745b1c5b0f8SChris Wilson if (INTEL_GTT_GEN == 2) { 746b1c5b0f8SChris Wilson u16 gmch_ctrl; 7471784a5fbSDaniel Vetter 7481784a5fbSDaniel Vetter pci_read_config_word(intel_private.bridge_dev, 7491784a5fbSDaniel Vetter I830_GMCH_CTRL, &gmch_ctrl); 7501784a5fbSDaniel Vetter 7511784a5fbSDaniel Vetter if ((gmch_ctrl & I830_GMCH_MEM_MASK) == I830_GMCH_MEM_64M) 752b1c5b0f8SChris Wilson aperture_size = MB(64); 7531784a5fbSDaniel Vetter else 754b1c5b0f8SChris Wilson aperture_size = MB(128); 755239918f7SDaniel Vetter } else { 7561784a5fbSDaniel Vetter /* 9xx supports large sizes, just look at the length */ 7571784a5fbSDaniel Vetter aperture_size = pci_resource_len(intel_private.pcidev, 2); 7581784a5fbSDaniel Vetter } 7591784a5fbSDaniel Vetter 7601784a5fbSDaniel Vetter return aperture_size >> PAGE_SHIFT; 7611784a5fbSDaniel Vetter } 7621784a5fbSDaniel Vetter 7630e87d2b0SDaniel Vetter static void intel_gtt_teardown_scratch_page(void) 7640e87d2b0SDaniel Vetter { 7650e87d2b0SDaniel Vetter set_pages_wb(intel_private.scratch_page, 1); 7660e87d2b0SDaniel Vetter pci_unmap_page(intel_private.pcidev, intel_private.scratch_page_dma, 7670e87d2b0SDaniel Vetter PAGE_SIZE, PCI_DMA_BIDIRECTIONAL); 7680e87d2b0SDaniel Vetter put_page(intel_private.scratch_page); 7690e87d2b0SDaniel Vetter __free_page(intel_private.scratch_page); 7700e87d2b0SDaniel Vetter } 7710e87d2b0SDaniel Vetter 7720e87d2b0SDaniel Vetter static void intel_gtt_cleanup(void) 7730e87d2b0SDaniel Vetter { 774ae83dd5cSDaniel Vetter intel_private.driver->cleanup(); 775ae83dd5cSDaniel Vetter 7760e87d2b0SDaniel Vetter iounmap(intel_private.gtt); 7770e87d2b0SDaniel Vetter iounmap(intel_private.registers); 7780e87d2b0SDaniel Vetter 7790e87d2b0SDaniel Vetter intel_gtt_teardown_scratch_page(); 7800e87d2b0SDaniel Vetter } 7810e87d2b0SDaniel Vetter 7821784a5fbSDaniel Vetter static int intel_gtt_init(void) 7831784a5fbSDaniel Vetter { 784f67eab66SDaniel Vetter u32 gtt_map_size; 7853b15a9d7SDaniel Vetter int ret; 7863b15a9d7SDaniel Vetter 7873b15a9d7SDaniel Vetter ret = intel_private.driver->setup(); 7883b15a9d7SDaniel Vetter if (ret != 0) 7893b15a9d7SDaniel Vetter return ret; 790f67eab66SDaniel Vetter 791f67eab66SDaniel Vetter intel_private.base.gtt_mappable_entries = intel_gtt_mappable_entries(); 792f67eab66SDaniel Vetter intel_private.base.gtt_total_entries = intel_gtt_total_entries(); 793f67eab66SDaniel Vetter 794b3eafc5aSDaniel Vetter /* save the PGETBL reg for resume */ 795b3eafc5aSDaniel Vetter intel_private.PGETBL_save = 796b3eafc5aSDaniel Vetter readl(intel_private.registers+I810_PGETBL_CTL) 797b3eafc5aSDaniel Vetter & ~I810_PGETBL_ENABLED; 798100519e2SChris Wilson /* we only ever restore the register when enabling the PGTBL... */ 799100519e2SChris Wilson if (HAS_PGTBL_EN) 800100519e2SChris Wilson intel_private.PGETBL_save |= I810_PGETBL_ENABLED; 801b3eafc5aSDaniel Vetter 8020af9e92eSDaniel Vetter dev_info(&intel_private.bridge_dev->dev, 8030af9e92eSDaniel Vetter "detected gtt size: %dK total, %dK mappable\n", 8040af9e92eSDaniel Vetter intel_private.base.gtt_total_entries * 4, 8050af9e92eSDaniel Vetter intel_private.base.gtt_mappable_entries * 4); 8060af9e92eSDaniel Vetter 807f67eab66SDaniel Vetter gtt_map_size = intel_private.base.gtt_total_entries * 4; 808f67eab66SDaniel Vetter 809f67eab66SDaniel Vetter intel_private.gtt = ioremap(intel_private.gtt_bus_addr, 810f67eab66SDaniel Vetter gtt_map_size); 811f67eab66SDaniel Vetter if (!intel_private.gtt) { 812ae83dd5cSDaniel Vetter intel_private.driver->cleanup(); 813f67eab66SDaniel Vetter iounmap(intel_private.registers); 814f67eab66SDaniel Vetter return -ENOMEM; 815f67eab66SDaniel Vetter } 816f67eab66SDaniel Vetter 817f67eab66SDaniel Vetter global_cache_flush(); /* FIXME: ? */ 818f67eab66SDaniel Vetter 8191784a5fbSDaniel Vetter /* we have to call this as early as possible after the MMIO base address is known */ 8201784a5fbSDaniel Vetter intel_private.base.gtt_stolen_entries = intel_gtt_stolen_entries(); 8211784a5fbSDaniel Vetter if (intel_private.base.gtt_stolen_entries == 0) { 822ae83dd5cSDaniel Vetter intel_private.driver->cleanup(); 8231784a5fbSDaniel Vetter iounmap(intel_private.registers); 824f67eab66SDaniel Vetter iounmap(intel_private.gtt); 8251784a5fbSDaniel Vetter return -ENOMEM; 8261784a5fbSDaniel Vetter } 8271784a5fbSDaniel Vetter 8280e87d2b0SDaniel Vetter ret = intel_gtt_setup_scratch_page(); 8290e87d2b0SDaniel Vetter if (ret != 0) { 8300e87d2b0SDaniel Vetter intel_gtt_cleanup(); 8310e87d2b0SDaniel Vetter return ret; 8320e87d2b0SDaniel Vetter } 8330e87d2b0SDaniel Vetter 8341784a5fbSDaniel Vetter return 0; 8351784a5fbSDaniel Vetter } 8361784a5fbSDaniel Vetter 8373e921f98SDaniel Vetter static int intel_fake_agp_fetch_size(void) 8383e921f98SDaniel Vetter { 8399e76e7b8SChris Wilson int num_sizes = ARRAY_SIZE(intel_fake_agp_sizes); 8403e921f98SDaniel Vetter unsigned int aper_size; 8413e921f98SDaniel Vetter int i; 8423e921f98SDaniel Vetter 8433e921f98SDaniel Vetter aper_size = (intel_private.base.gtt_mappable_entries << PAGE_SHIFT) 8443e921f98SDaniel Vetter / MB(1); 8453e921f98SDaniel Vetter 8463e921f98SDaniel Vetter for (i = 0; i < num_sizes; i++) { 847ffdd7510SDaniel Vetter if (aper_size == intel_fake_agp_sizes[i].size) { 8489e76e7b8SChris Wilson agp_bridge->current_size = 8499e76e7b8SChris Wilson (void *) (intel_fake_agp_sizes + i); 8503e921f98SDaniel Vetter return aper_size; 8513e921f98SDaniel Vetter } 8523e921f98SDaniel Vetter } 8533e921f98SDaniel Vetter 8543e921f98SDaniel Vetter return 0; 8553e921f98SDaniel Vetter } 8563e921f98SDaniel Vetter 857ae83dd5cSDaniel Vetter static void i830_cleanup(void) 858f51b7662SDaniel Vetter { 859f51b7662SDaniel Vetter kunmap(intel_private.i8xx_page); 860f51b7662SDaniel Vetter intel_private.i8xx_flush_page = NULL; 861f51b7662SDaniel Vetter 862f51b7662SDaniel Vetter __free_page(intel_private.i8xx_page); 863f51b7662SDaniel Vetter intel_private.i8xx_page = NULL; 864f51b7662SDaniel Vetter } 865f51b7662SDaniel Vetter 866f51b7662SDaniel Vetter static void intel_i830_setup_flush(void) 867f51b7662SDaniel Vetter { 868f51b7662SDaniel Vetter /* return if we've already set the flush mechanism up */ 869f51b7662SDaniel Vetter if (intel_private.i8xx_page) 870f51b7662SDaniel Vetter return; 871f51b7662SDaniel Vetter 872e61cb0d5SJan Beulich intel_private.i8xx_page = alloc_page(GFP_KERNEL); 873f51b7662SDaniel Vetter if (!intel_private.i8xx_page) 874f51b7662SDaniel Vetter return; 875f51b7662SDaniel Vetter 876f51b7662SDaniel Vetter intel_private.i8xx_flush_page = kmap(intel_private.i8xx_page); 877f51b7662SDaniel Vetter if (!intel_private.i8xx_flush_page) 878ae83dd5cSDaniel Vetter i830_cleanup(); 879f51b7662SDaniel Vetter } 880f51b7662SDaniel Vetter 881f51b7662SDaniel Vetter /* The chipset_flush interface needs to get data that has already been 882f51b7662SDaniel Vetter * flushed out of the CPU all the way out to main memory, because the GPU 883f51b7662SDaniel Vetter * doesn't snoop those buffers. 884f51b7662SDaniel Vetter * 885f51b7662SDaniel Vetter * The 8xx series doesn't have the same lovely interface for flushing the 886f51b7662SDaniel Vetter * chipset write buffers that the later chips do. According to the 865 887f51b7662SDaniel Vetter * specs, it's 64 octwords, or 1KB. So, to get those previous things in 888f51b7662SDaniel Vetter * that buffer out, we just fill 1KB and clflush it out, on the assumption 889f51b7662SDaniel Vetter * that it'll push whatever was in there out. It appears to work. 890f51b7662SDaniel Vetter */ 8911b263f24SDaniel Vetter static void i830_chipset_flush(void) 892f51b7662SDaniel Vetter { 893f51b7662SDaniel Vetter unsigned int *pg = intel_private.i8xx_flush_page; 894f51b7662SDaniel Vetter 895f51b7662SDaniel Vetter memset(pg, 0, 1024); 896f51b7662SDaniel Vetter 897f51b7662SDaniel Vetter if (cpu_has_clflush) 898f51b7662SDaniel Vetter clflush_cache_range(pg, 1024); 899f51b7662SDaniel Vetter else if (wbinvd_on_all_cpus() != 0) 900f51b7662SDaniel Vetter printk(KERN_ERR "Timed out waiting for cache flush.\n"); 901f51b7662SDaniel Vetter } 902f51b7662SDaniel Vetter 903351bb278SDaniel Vetter static void i830_write_entry(dma_addr_t addr, unsigned int entry, 904351bb278SDaniel Vetter unsigned int flags) 905351bb278SDaniel Vetter { 906351bb278SDaniel Vetter u32 pte_flags = I810_PTE_VALID; 907351bb278SDaniel Vetter 908351bb278SDaniel Vetter switch (flags) { 909351bb278SDaniel Vetter case AGP_DCACHE_MEMORY: 910351bb278SDaniel Vetter pte_flags |= I810_PTE_LOCAL; 911351bb278SDaniel Vetter break; 912351bb278SDaniel Vetter case AGP_USER_CACHED_MEMORY: 913351bb278SDaniel Vetter pte_flags |= I830_PTE_SYSTEM_CACHED; 914351bb278SDaniel Vetter break; 915351bb278SDaniel Vetter } 916351bb278SDaniel Vetter 917351bb278SDaniel Vetter writel(addr | pte_flags, intel_private.gtt + entry); 918351bb278SDaniel Vetter } 919351bb278SDaniel Vetter 920e380f60bSChris Wilson static bool intel_enable_gtt(void) 92173800422SDaniel Vetter { 9223f08e4efSChris Wilson u32 gma_addr; 923e380f60bSChris Wilson u8 __iomem *reg; 92473800422SDaniel Vetter 9252d2430cfSDaniel Vetter if (INTEL_GTT_GEN == 2) 9262d2430cfSDaniel Vetter pci_read_config_dword(intel_private.pcidev, I810_GMADDR, 9272d2430cfSDaniel Vetter &gma_addr); 9282d2430cfSDaniel Vetter else 9292d2430cfSDaniel Vetter pci_read_config_dword(intel_private.pcidev, I915_GMADDR, 9302d2430cfSDaniel Vetter &gma_addr); 9312d2430cfSDaniel Vetter 93273800422SDaniel Vetter intel_private.gma_bus_addr = (gma_addr & PCI_BASE_ADDRESS_MEM_MASK); 93373800422SDaniel Vetter 934e380f60bSChris Wilson if (INTEL_GTT_GEN >= 6) 935e380f60bSChris Wilson return true; 93673800422SDaniel Vetter 937100519e2SChris Wilson if (INTEL_GTT_GEN == 2) { 938100519e2SChris Wilson u16 gmch_ctrl; 939100519e2SChris Wilson 940e380f60bSChris Wilson pci_read_config_word(intel_private.bridge_dev, 941e380f60bSChris Wilson I830_GMCH_CTRL, &gmch_ctrl); 942e380f60bSChris Wilson gmch_ctrl |= I830_GMCH_ENABLED; 943e380f60bSChris Wilson pci_write_config_word(intel_private.bridge_dev, 944e380f60bSChris Wilson I830_GMCH_CTRL, gmch_ctrl); 945e380f60bSChris Wilson 946e380f60bSChris Wilson pci_read_config_word(intel_private.bridge_dev, 947e380f60bSChris Wilson I830_GMCH_CTRL, &gmch_ctrl); 948e380f60bSChris Wilson if ((gmch_ctrl & I830_GMCH_ENABLED) == 0) { 949e380f60bSChris Wilson dev_err(&intel_private.pcidev->dev, 950e380f60bSChris Wilson "failed to enable the GTT: GMCH_CTRL=%x\n", 951e380f60bSChris Wilson gmch_ctrl); 952e380f60bSChris Wilson return false; 953e380f60bSChris Wilson } 954100519e2SChris Wilson } 955e380f60bSChris Wilson 956e380f60bSChris Wilson reg = intel_private.registers+I810_PGETBL_CTL; 957100519e2SChris Wilson writel(intel_private.PGETBL_save, reg); 958100519e2SChris Wilson if (HAS_PGTBL_EN && (readl(reg) & I810_PGETBL_ENABLED) == 0) { 959e380f60bSChris Wilson dev_err(&intel_private.pcidev->dev, 960100519e2SChris Wilson "failed to enable the GTT: PGETBL=%x [expected %x]\n", 961e380f60bSChris Wilson readl(reg), intel_private.PGETBL_save); 962e380f60bSChris Wilson return false; 963e380f60bSChris Wilson } 964e380f60bSChris Wilson 965e380f60bSChris Wilson return true; 96673800422SDaniel Vetter } 96773800422SDaniel Vetter 96873800422SDaniel Vetter static int i830_setup(void) 96973800422SDaniel Vetter { 97073800422SDaniel Vetter u32 reg_addr; 97173800422SDaniel Vetter 97273800422SDaniel Vetter pci_read_config_dword(intel_private.pcidev, I810_MMADDR, ®_addr); 97373800422SDaniel Vetter reg_addr &= 0xfff80000; 97473800422SDaniel Vetter 97573800422SDaniel Vetter intel_private.registers = ioremap(reg_addr, KB(64)); 97673800422SDaniel Vetter if (!intel_private.registers) 97773800422SDaniel Vetter return -ENOMEM; 97873800422SDaniel Vetter 97973800422SDaniel Vetter intel_private.gtt_bus_addr = reg_addr + I810_PTE_BASE; 98073800422SDaniel Vetter 98173800422SDaniel Vetter intel_i830_setup_flush(); 98273800422SDaniel Vetter 98373800422SDaniel Vetter return 0; 98473800422SDaniel Vetter } 98573800422SDaniel Vetter 9863b15a9d7SDaniel Vetter static int intel_fake_agp_create_gatt_table(struct agp_bridge_data *bridge) 987f51b7662SDaniel Vetter { 98873800422SDaniel Vetter agp_bridge->gatt_table_real = NULL; 989f51b7662SDaniel Vetter agp_bridge->gatt_table = NULL; 99073800422SDaniel Vetter agp_bridge->gatt_bus_addr = 0; 991f51b7662SDaniel Vetter 992f51b7662SDaniel Vetter return 0; 993f51b7662SDaniel Vetter } 994f51b7662SDaniel Vetter 995ffdd7510SDaniel Vetter static int intel_fake_agp_free_gatt_table(struct agp_bridge_data *bridge) 996f51b7662SDaniel Vetter { 997f51b7662SDaniel Vetter return 0; 998f51b7662SDaniel Vetter } 999f51b7662SDaniel Vetter 1000351bb278SDaniel Vetter static int intel_fake_agp_configure(void) 1001f51b7662SDaniel Vetter { 1002f51b7662SDaniel Vetter int i; 1003f51b7662SDaniel Vetter 1004e380f60bSChris Wilson if (!intel_enable_gtt()) 1005e380f60bSChris Wilson return -EIO; 1006f51b7662SDaniel Vetter 100773800422SDaniel Vetter agp_bridge->gart_bus_addr = intel_private.gma_bus_addr; 1008f51b7662SDaniel Vetter 100973800422SDaniel Vetter for (i = intel_private.base.gtt_stolen_entries; 101073800422SDaniel Vetter i < intel_private.base.gtt_total_entries; i++) { 1011351bb278SDaniel Vetter intel_private.driver->write_entry(intel_private.scratch_page_dma, 1012351bb278SDaniel Vetter i, 0); 1013f51b7662SDaniel Vetter } 1014fdfb58a9SDaniel Vetter readl(intel_private.gtt+i-1); /* PCI Posting. */ 1015f51b7662SDaniel Vetter 1016f51b7662SDaniel Vetter global_cache_flush(); 1017f51b7662SDaniel Vetter 1018f51b7662SDaniel Vetter return 0; 1019f51b7662SDaniel Vetter } 1020f51b7662SDaniel Vetter 10215cbecafcSDaniel Vetter static bool i830_check_flags(unsigned int flags) 1022f51b7662SDaniel Vetter { 10235cbecafcSDaniel Vetter switch (flags) { 10245cbecafcSDaniel Vetter case 0: 10255cbecafcSDaniel Vetter case AGP_PHYS_MEMORY: 10265cbecafcSDaniel Vetter case AGP_USER_CACHED_MEMORY: 10275cbecafcSDaniel Vetter case AGP_USER_MEMORY: 10285cbecafcSDaniel Vetter return true; 10295cbecafcSDaniel Vetter } 10305cbecafcSDaniel Vetter 10315cbecafcSDaniel Vetter return false; 10325cbecafcSDaniel Vetter } 10335cbecafcSDaniel Vetter 1034fefaa70fSDaniel Vetter static void intel_gtt_insert_sg_entries(struct scatterlist *sg_list, 1035fefaa70fSDaniel Vetter unsigned int sg_len, 1036fefaa70fSDaniel Vetter unsigned int pg_start, 1037fefaa70fSDaniel Vetter unsigned int flags) 1038fefaa70fSDaniel Vetter { 1039fefaa70fSDaniel Vetter struct scatterlist *sg; 1040fefaa70fSDaniel Vetter unsigned int len, m; 1041fefaa70fSDaniel Vetter int i, j; 1042fefaa70fSDaniel Vetter 1043fefaa70fSDaniel Vetter j = pg_start; 1044fefaa70fSDaniel Vetter 1045fefaa70fSDaniel Vetter /* sg may merge pages, but we have to separate 1046fefaa70fSDaniel Vetter * per-page addr for GTT */ 1047fefaa70fSDaniel Vetter for_each_sg(sg_list, sg, sg_len, i) { 1048fefaa70fSDaniel Vetter len = sg_dma_len(sg) >> PAGE_SHIFT; 1049fefaa70fSDaniel Vetter for (m = 0; m < len; m++) { 1050fefaa70fSDaniel Vetter dma_addr_t addr = sg_dma_address(sg) + (m << PAGE_SHIFT); 1051fefaa70fSDaniel Vetter intel_private.driver->write_entry(addr, 1052fefaa70fSDaniel Vetter j, flags); 1053fefaa70fSDaniel Vetter j++; 1054fefaa70fSDaniel Vetter } 1055fefaa70fSDaniel Vetter } 1056fefaa70fSDaniel Vetter readl(intel_private.gtt+j-1); 1057fefaa70fSDaniel Vetter } 1058fefaa70fSDaniel Vetter 10595cbecafcSDaniel Vetter static int intel_fake_agp_insert_entries(struct agp_memory *mem, 10605cbecafcSDaniel Vetter off_t pg_start, int type) 10615cbecafcSDaniel Vetter { 10625cbecafcSDaniel Vetter int i, j; 1063f51b7662SDaniel Vetter int ret = -EINVAL; 1064f51b7662SDaniel Vetter 1065f51b7662SDaniel Vetter if (mem->page_count == 0) 1066f51b7662SDaniel Vetter goto out; 1067f51b7662SDaniel Vetter 10680ade6386SDaniel Vetter if (pg_start < intel_private.base.gtt_stolen_entries) { 1069f51b7662SDaniel Vetter dev_printk(KERN_DEBUG, &intel_private.pcidev->dev, 10700ade6386SDaniel Vetter "pg_start == 0x%.8lx, gtt_stolen_entries == 0x%.8x\n", 10710ade6386SDaniel Vetter pg_start, intel_private.base.gtt_stolen_entries); 1072f51b7662SDaniel Vetter 1073f51b7662SDaniel Vetter dev_info(&intel_private.pcidev->dev, 1074f51b7662SDaniel Vetter "trying to insert into local/stolen memory\n"); 1075f51b7662SDaniel Vetter goto out_err; 1076f51b7662SDaniel Vetter } 1077f51b7662SDaniel Vetter 10785cbecafcSDaniel Vetter if ((pg_start + mem->page_count) > intel_private.base.gtt_total_entries) 1079f51b7662SDaniel Vetter goto out_err; 1080f51b7662SDaniel Vetter 1081f51b7662SDaniel Vetter if (type != mem->type) 1082f51b7662SDaniel Vetter goto out_err; 1083f51b7662SDaniel Vetter 10845cbecafcSDaniel Vetter if (!intel_private.driver->check_flags(type)) 1085f51b7662SDaniel Vetter goto out_err; 1086f51b7662SDaniel Vetter 1087f51b7662SDaniel Vetter if (!mem->is_flushed) 1088f51b7662SDaniel Vetter global_cache_flush(); 1089f51b7662SDaniel Vetter 1090fefaa70fSDaniel Vetter if (USE_PCI_DMA_API && INTEL_GTT_GEN > 2) { 1091fefaa70fSDaniel Vetter ret = intel_agp_map_memory(mem); 1092fefaa70fSDaniel Vetter if (ret != 0) 1093fefaa70fSDaniel Vetter return ret; 1094fefaa70fSDaniel Vetter 1095fefaa70fSDaniel Vetter intel_gtt_insert_sg_entries(mem->sg_list, mem->num_sg, 1096fefaa70fSDaniel Vetter pg_start, type); 1097fefaa70fSDaniel Vetter } else { 1098f51b7662SDaniel Vetter for (i = 0, j = pg_start; i < mem->page_count; i++, j++) { 1099fefaa70fSDaniel Vetter dma_addr_t addr = page_to_phys(mem->pages[i]); 1100fefaa70fSDaniel Vetter intel_private.driver->write_entry(addr, 11015cbecafcSDaniel Vetter j, type); 1102f51b7662SDaniel Vetter } 1103fdfb58a9SDaniel Vetter readl(intel_private.gtt+j-1); 1104fefaa70fSDaniel Vetter } 1105f51b7662SDaniel Vetter 1106f51b7662SDaniel Vetter out: 1107f51b7662SDaniel Vetter ret = 0; 1108f51b7662SDaniel Vetter out_err: 1109f51b7662SDaniel Vetter mem->is_flushed = true; 1110f51b7662SDaniel Vetter return ret; 1111f51b7662SDaniel Vetter } 1112f51b7662SDaniel Vetter 11135cbecafcSDaniel Vetter static int intel_fake_agp_remove_entries(struct agp_memory *mem, 11145cbecafcSDaniel Vetter off_t pg_start, int type) 1115f51b7662SDaniel Vetter { 1116f51b7662SDaniel Vetter int i; 1117f51b7662SDaniel Vetter 1118f51b7662SDaniel Vetter if (mem->page_count == 0) 1119f51b7662SDaniel Vetter return 0; 1120f51b7662SDaniel Vetter 11210ade6386SDaniel Vetter if (pg_start < intel_private.base.gtt_stolen_entries) { 1122f51b7662SDaniel Vetter dev_info(&intel_private.pcidev->dev, 1123f51b7662SDaniel Vetter "trying to disable local/stolen memory\n"); 1124f51b7662SDaniel Vetter return -EINVAL; 1125f51b7662SDaniel Vetter } 1126f51b7662SDaniel Vetter 1127fefaa70fSDaniel Vetter if (USE_PCI_DMA_API && INTEL_GTT_GEN > 2) 1128fefaa70fSDaniel Vetter intel_agp_unmap_memory(mem); 1129fefaa70fSDaniel Vetter 1130f51b7662SDaniel Vetter for (i = pg_start; i < (mem->page_count + pg_start); i++) { 11315cbecafcSDaniel Vetter intel_private.driver->write_entry(intel_private.scratch_page_dma, 11325cbecafcSDaniel Vetter i, 0); 1133f51b7662SDaniel Vetter } 1134fdfb58a9SDaniel Vetter readl(intel_private.gtt+i-1); 1135f51b7662SDaniel Vetter 1136f51b7662SDaniel Vetter return 0; 1137f51b7662SDaniel Vetter } 1138f51b7662SDaniel Vetter 11391b263f24SDaniel Vetter static void intel_fake_agp_chipset_flush(struct agp_bridge_data *bridge) 11401b263f24SDaniel Vetter { 11411b263f24SDaniel Vetter intel_private.driver->chipset_flush(); 11421b263f24SDaniel Vetter } 11431b263f24SDaniel Vetter 1144ffdd7510SDaniel Vetter static struct agp_memory *intel_fake_agp_alloc_by_type(size_t pg_count, 1145ffdd7510SDaniel Vetter int type) 1146f51b7662SDaniel Vetter { 1147f51b7662SDaniel Vetter if (type == AGP_PHYS_MEMORY) 1148f51b7662SDaniel Vetter return alloc_agpphysmem_i8xx(pg_count, type); 1149f51b7662SDaniel Vetter /* always return NULL for other allocation types for now */ 1150f51b7662SDaniel Vetter return NULL; 1151f51b7662SDaniel Vetter } 1152f51b7662SDaniel Vetter 1153f51b7662SDaniel Vetter static int intel_alloc_chipset_flush_resource(void) 1154f51b7662SDaniel Vetter { 1155f51b7662SDaniel Vetter int ret; 1156d7cca2f7SDaniel Vetter ret = pci_bus_alloc_resource(intel_private.bridge_dev->bus, &intel_private.ifp_resource, PAGE_SIZE, 1157f51b7662SDaniel Vetter PAGE_SIZE, PCIBIOS_MIN_MEM, 0, 1158d7cca2f7SDaniel Vetter pcibios_align_resource, intel_private.bridge_dev); 1159f51b7662SDaniel Vetter 1160f51b7662SDaniel Vetter return ret; 1161f51b7662SDaniel Vetter } 1162f51b7662SDaniel Vetter 1163f51b7662SDaniel Vetter static void intel_i915_setup_chipset_flush(void) 1164f51b7662SDaniel Vetter { 1165f51b7662SDaniel Vetter int ret; 1166f51b7662SDaniel Vetter u32 temp; 1167f51b7662SDaniel Vetter 1168d7cca2f7SDaniel Vetter pci_read_config_dword(intel_private.bridge_dev, I915_IFPADDR, &temp); 1169f51b7662SDaniel Vetter if (!(temp & 0x1)) { 1170f51b7662SDaniel Vetter intel_alloc_chipset_flush_resource(); 1171f51b7662SDaniel Vetter intel_private.resource_valid = 1; 1172d7cca2f7SDaniel Vetter pci_write_config_dword(intel_private.bridge_dev, I915_IFPADDR, (intel_private.ifp_resource.start & 0xffffffff) | 0x1); 1173f51b7662SDaniel Vetter } else { 1174f51b7662SDaniel Vetter temp &= ~1; 1175f51b7662SDaniel Vetter 1176f51b7662SDaniel Vetter intel_private.resource_valid = 1; 1177f51b7662SDaniel Vetter intel_private.ifp_resource.start = temp; 1178f51b7662SDaniel Vetter intel_private.ifp_resource.end = temp + PAGE_SIZE; 1179f51b7662SDaniel Vetter ret = request_resource(&iomem_resource, &intel_private.ifp_resource); 1180f51b7662SDaniel Vetter /* some BIOSes reserve this area in a pnp some don't */ 1181f51b7662SDaniel Vetter if (ret) 1182f51b7662SDaniel Vetter intel_private.resource_valid = 0; 1183f51b7662SDaniel Vetter } 1184f51b7662SDaniel Vetter } 1185f51b7662SDaniel Vetter 1186f51b7662SDaniel Vetter static void intel_i965_g33_setup_chipset_flush(void) 1187f51b7662SDaniel Vetter { 1188f51b7662SDaniel Vetter u32 temp_hi, temp_lo; 1189f51b7662SDaniel Vetter int ret; 1190f51b7662SDaniel Vetter 1191d7cca2f7SDaniel Vetter pci_read_config_dword(intel_private.bridge_dev, I965_IFPADDR + 4, &temp_hi); 1192d7cca2f7SDaniel Vetter pci_read_config_dword(intel_private.bridge_dev, I965_IFPADDR, &temp_lo); 1193f51b7662SDaniel Vetter 1194f51b7662SDaniel Vetter if (!(temp_lo & 0x1)) { 1195f51b7662SDaniel Vetter 1196f51b7662SDaniel Vetter intel_alloc_chipset_flush_resource(); 1197f51b7662SDaniel Vetter 1198f51b7662SDaniel Vetter intel_private.resource_valid = 1; 1199d7cca2f7SDaniel Vetter pci_write_config_dword(intel_private.bridge_dev, I965_IFPADDR + 4, 1200f51b7662SDaniel Vetter upper_32_bits(intel_private.ifp_resource.start)); 1201d7cca2f7SDaniel Vetter pci_write_config_dword(intel_private.bridge_dev, I965_IFPADDR, (intel_private.ifp_resource.start & 0xffffffff) | 0x1); 1202f51b7662SDaniel Vetter } else { 1203f51b7662SDaniel Vetter u64 l64; 1204f51b7662SDaniel Vetter 1205f51b7662SDaniel Vetter temp_lo &= ~0x1; 1206f51b7662SDaniel Vetter l64 = ((u64)temp_hi << 32) | temp_lo; 1207f51b7662SDaniel Vetter 1208f51b7662SDaniel Vetter intel_private.resource_valid = 1; 1209f51b7662SDaniel Vetter intel_private.ifp_resource.start = l64; 1210f51b7662SDaniel Vetter intel_private.ifp_resource.end = l64 + PAGE_SIZE; 1211f51b7662SDaniel Vetter ret = request_resource(&iomem_resource, &intel_private.ifp_resource); 1212f51b7662SDaniel Vetter /* some BIOSes reserve this area in a pnp some don't */ 1213f51b7662SDaniel Vetter if (ret) 1214f51b7662SDaniel Vetter intel_private.resource_valid = 0; 1215f51b7662SDaniel Vetter } 1216f51b7662SDaniel Vetter } 1217f51b7662SDaniel Vetter 1218f51b7662SDaniel Vetter static void intel_i9xx_setup_flush(void) 1219f51b7662SDaniel Vetter { 1220f51b7662SDaniel Vetter /* return if already configured */ 1221f51b7662SDaniel Vetter if (intel_private.ifp_resource.start) 1222f51b7662SDaniel Vetter return; 1223f51b7662SDaniel Vetter 12241a997ff2SDaniel Vetter if (INTEL_GTT_GEN == 6) 1225f51b7662SDaniel Vetter return; 1226f51b7662SDaniel Vetter 1227f51b7662SDaniel Vetter /* setup a resource for this object */ 1228f51b7662SDaniel Vetter intel_private.ifp_resource.name = "Intel Flush Page"; 1229f51b7662SDaniel Vetter intel_private.ifp_resource.flags = IORESOURCE_MEM; 1230f51b7662SDaniel Vetter 1231f51b7662SDaniel Vetter /* Setup chipset flush for 915 */ 12321a997ff2SDaniel Vetter if (IS_G33 || INTEL_GTT_GEN >= 4) { 1233f51b7662SDaniel Vetter intel_i965_g33_setup_chipset_flush(); 1234f51b7662SDaniel Vetter } else { 1235f51b7662SDaniel Vetter intel_i915_setup_chipset_flush(); 1236f51b7662SDaniel Vetter } 1237f51b7662SDaniel Vetter 1238df51e7aaSChris Wilson if (intel_private.ifp_resource.start) 1239f51b7662SDaniel Vetter intel_private.i9xx_flush_page = ioremap_nocache(intel_private.ifp_resource.start, PAGE_SIZE); 1240f51b7662SDaniel Vetter if (!intel_private.i9xx_flush_page) 1241df51e7aaSChris Wilson dev_err(&intel_private.pcidev->dev, 1242df51e7aaSChris Wilson "can't ioremap flush page - no chipset flushing\n"); 1243f51b7662SDaniel Vetter } 1244f51b7662SDaniel Vetter 1245ae83dd5cSDaniel Vetter static void i9xx_cleanup(void) 1246ae83dd5cSDaniel Vetter { 1247ae83dd5cSDaniel Vetter if (intel_private.i9xx_flush_page) 1248ae83dd5cSDaniel Vetter iounmap(intel_private.i9xx_flush_page); 1249ae83dd5cSDaniel Vetter if (intel_private.resource_valid) 1250ae83dd5cSDaniel Vetter release_resource(&intel_private.ifp_resource); 1251ae83dd5cSDaniel Vetter intel_private.ifp_resource.start = 0; 1252ae83dd5cSDaniel Vetter intel_private.resource_valid = 0; 1253ae83dd5cSDaniel Vetter } 1254ae83dd5cSDaniel Vetter 12551b263f24SDaniel Vetter static void i9xx_chipset_flush(void) 1256f51b7662SDaniel Vetter { 1257f51b7662SDaniel Vetter if (intel_private.i9xx_flush_page) 1258f51b7662SDaniel Vetter writel(1, intel_private.i9xx_flush_page); 1259f51b7662SDaniel Vetter } 1260f51b7662SDaniel Vetter 1261a6963596SDaniel Vetter static void i965_write_entry(dma_addr_t addr, unsigned int entry, 1262a6963596SDaniel Vetter unsigned int flags) 1263a6963596SDaniel Vetter { 1264a6963596SDaniel Vetter /* Shift high bits down */ 1265a6963596SDaniel Vetter addr |= (addr >> 28) & 0xf0; 1266a6963596SDaniel Vetter writel(addr | I810_PTE_VALID, intel_private.gtt + entry); 1267a6963596SDaniel Vetter } 1268a6963596SDaniel Vetter 126990cb149eSDaniel Vetter static bool gen6_check_flags(unsigned int flags) 127090cb149eSDaniel Vetter { 127190cb149eSDaniel Vetter return true; 127290cb149eSDaniel Vetter } 127390cb149eSDaniel Vetter 127497ef1bddSDaniel Vetter static void gen6_write_entry(dma_addr_t addr, unsigned int entry, 127597ef1bddSDaniel Vetter unsigned int flags) 127697ef1bddSDaniel Vetter { 127797ef1bddSDaniel Vetter unsigned int type_mask = flags & ~AGP_USER_CACHED_MEMORY_GFDT; 127897ef1bddSDaniel Vetter unsigned int gfdt = flags & AGP_USER_CACHED_MEMORY_GFDT; 127997ef1bddSDaniel Vetter u32 pte_flags; 128097ef1bddSDaniel Vetter 1281897ef192SZhenyu Wang if (type_mask == AGP_USER_MEMORY) 128285ccc35bSChris Wilson pte_flags = GEN6_PTE_UNCACHED | I810_PTE_VALID; 128397ef1bddSDaniel Vetter else if (type_mask == AGP_USER_CACHED_MEMORY_LLC_MLC) { 1284d1108525SZhenyu Wang pte_flags = GEN6_PTE_LLC_MLC | I810_PTE_VALID; 128597ef1bddSDaniel Vetter if (gfdt) 128697ef1bddSDaniel Vetter pte_flags |= GEN6_PTE_GFDT; 128797ef1bddSDaniel Vetter } else { /* set 'normal'/'cached' to LLC by default */ 1288d1108525SZhenyu Wang pte_flags = GEN6_PTE_LLC | I810_PTE_VALID; 128997ef1bddSDaniel Vetter if (gfdt) 129097ef1bddSDaniel Vetter pte_flags |= GEN6_PTE_GFDT; 129197ef1bddSDaniel Vetter } 129297ef1bddSDaniel Vetter 129397ef1bddSDaniel Vetter /* gen6 has bit11-4 for physical addr bit39-32 */ 129497ef1bddSDaniel Vetter addr |= (addr >> 28) & 0xff0; 129597ef1bddSDaniel Vetter writel(addr | pte_flags, intel_private.gtt + entry); 129697ef1bddSDaniel Vetter } 129797ef1bddSDaniel Vetter 1298ae83dd5cSDaniel Vetter static void gen6_cleanup(void) 1299ae83dd5cSDaniel Vetter { 1300ae83dd5cSDaniel Vetter } 1301ae83dd5cSDaniel Vetter 13022d2430cfSDaniel Vetter static int i9xx_setup(void) 13032d2430cfSDaniel Vetter { 13042d2430cfSDaniel Vetter u32 reg_addr; 13052d2430cfSDaniel Vetter 13062d2430cfSDaniel Vetter pci_read_config_dword(intel_private.pcidev, I915_MMADDR, ®_addr); 13072d2430cfSDaniel Vetter 13082d2430cfSDaniel Vetter reg_addr &= 0xfff80000; 13092d2430cfSDaniel Vetter 13102d2430cfSDaniel Vetter intel_private.registers = ioremap(reg_addr, 128 * 4096); 13112d2430cfSDaniel Vetter if (!intel_private.registers) 13122d2430cfSDaniel Vetter return -ENOMEM; 13132d2430cfSDaniel Vetter 13142d2430cfSDaniel Vetter if (INTEL_GTT_GEN == 3) { 13152d2430cfSDaniel Vetter u32 gtt_addr; 13163f08e4efSChris Wilson 13172d2430cfSDaniel Vetter pci_read_config_dword(intel_private.pcidev, 13182d2430cfSDaniel Vetter I915_PTEADDR, >t_addr); 13192d2430cfSDaniel Vetter intel_private.gtt_bus_addr = gtt_addr; 13202d2430cfSDaniel Vetter } else { 13212d2430cfSDaniel Vetter u32 gtt_offset; 13222d2430cfSDaniel Vetter 13232d2430cfSDaniel Vetter switch (INTEL_GTT_GEN) { 13242d2430cfSDaniel Vetter case 5: 13252d2430cfSDaniel Vetter case 6: 13262d2430cfSDaniel Vetter gtt_offset = MB(2); 13272d2430cfSDaniel Vetter break; 13282d2430cfSDaniel Vetter case 4: 13292d2430cfSDaniel Vetter default: 13302d2430cfSDaniel Vetter gtt_offset = KB(512); 13312d2430cfSDaniel Vetter break; 13322d2430cfSDaniel Vetter } 13332d2430cfSDaniel Vetter intel_private.gtt_bus_addr = reg_addr + gtt_offset; 13342d2430cfSDaniel Vetter } 13352d2430cfSDaniel Vetter 13362d2430cfSDaniel Vetter intel_i9xx_setup_flush(); 13372d2430cfSDaniel Vetter 13382d2430cfSDaniel Vetter return 0; 13392d2430cfSDaniel Vetter } 13402d2430cfSDaniel Vetter 1341f51b7662SDaniel Vetter static const struct agp_bridge_driver intel_810_driver = { 1342f51b7662SDaniel Vetter .owner = THIS_MODULE, 1343f51b7662SDaniel Vetter .aperture_sizes = intel_i810_sizes, 1344f51b7662SDaniel Vetter .size_type = FIXED_APER_SIZE, 1345f51b7662SDaniel Vetter .num_aperture_sizes = 2, 1346f51b7662SDaniel Vetter .needs_scratch_page = true, 1347f51b7662SDaniel Vetter .configure = intel_i810_configure, 1348f51b7662SDaniel Vetter .fetch_size = intel_i810_fetch_size, 1349f51b7662SDaniel Vetter .cleanup = intel_i810_cleanup, 1350f51b7662SDaniel Vetter .mask_memory = intel_i810_mask_memory, 1351f51b7662SDaniel Vetter .masks = intel_i810_masks, 1352ffdd7510SDaniel Vetter .agp_enable = intel_fake_agp_enable, 1353f51b7662SDaniel Vetter .cache_flush = global_cache_flush, 1354f51b7662SDaniel Vetter .create_gatt_table = agp_generic_create_gatt_table, 1355f51b7662SDaniel Vetter .free_gatt_table = agp_generic_free_gatt_table, 1356f51b7662SDaniel Vetter .insert_memory = intel_i810_insert_entries, 1357f51b7662SDaniel Vetter .remove_memory = intel_i810_remove_entries, 1358f51b7662SDaniel Vetter .alloc_by_type = intel_i810_alloc_by_type, 1359f51b7662SDaniel Vetter .free_by_type = intel_i810_free_by_type, 1360f51b7662SDaniel Vetter .agp_alloc_page = agp_generic_alloc_page, 1361f51b7662SDaniel Vetter .agp_alloc_pages = agp_generic_alloc_pages, 1362f51b7662SDaniel Vetter .agp_destroy_page = agp_generic_destroy_page, 1363f51b7662SDaniel Vetter .agp_destroy_pages = agp_generic_destroy_pages, 1364f51b7662SDaniel Vetter .agp_type_to_mask_type = agp_generic_type_to_mask_type, 1365f51b7662SDaniel Vetter }; 1366f51b7662SDaniel Vetter 1367e9b1cc81SDaniel Vetter static const struct agp_bridge_driver intel_fake_agp_driver = { 1368f51b7662SDaniel Vetter .owner = THIS_MODULE, 1369f51b7662SDaniel Vetter .size_type = FIXED_APER_SIZE, 13709e76e7b8SChris Wilson .aperture_sizes = intel_fake_agp_sizes, 13719e76e7b8SChris Wilson .num_aperture_sizes = ARRAY_SIZE(intel_fake_agp_sizes), 1372a6963596SDaniel Vetter .configure = intel_fake_agp_configure, 13733e921f98SDaniel Vetter .fetch_size = intel_fake_agp_fetch_size, 1374fdfb58a9SDaniel Vetter .cleanup = intel_gtt_cleanup, 1375ffdd7510SDaniel Vetter .agp_enable = intel_fake_agp_enable, 1376f51b7662SDaniel Vetter .cache_flush = global_cache_flush, 13773b15a9d7SDaniel Vetter .create_gatt_table = intel_fake_agp_create_gatt_table, 1378ffdd7510SDaniel Vetter .free_gatt_table = intel_fake_agp_free_gatt_table, 1379450f2b3dSDaniel Vetter .insert_memory = intel_fake_agp_insert_entries, 1380450f2b3dSDaniel Vetter .remove_memory = intel_fake_agp_remove_entries, 1381ffdd7510SDaniel Vetter .alloc_by_type = intel_fake_agp_alloc_by_type, 1382f51b7662SDaniel Vetter .free_by_type = intel_i810_free_by_type, 1383f51b7662SDaniel Vetter .agp_alloc_page = agp_generic_alloc_page, 1384f51b7662SDaniel Vetter .agp_alloc_pages = agp_generic_alloc_pages, 1385f51b7662SDaniel Vetter .agp_destroy_page = agp_generic_destroy_page, 1386f51b7662SDaniel Vetter .agp_destroy_pages = agp_generic_destroy_pages, 13871b263f24SDaniel Vetter .chipset_flush = intel_fake_agp_chipset_flush, 1388f51b7662SDaniel Vetter }; 138902c026ceSDaniel Vetter 1390bdd30729SDaniel Vetter static const struct intel_gtt_driver i81x_gtt_driver = { 1391bdd30729SDaniel Vetter .gen = 1, 139222533b49SDaniel Vetter .dma_mask_size = 32, 1393bdd30729SDaniel Vetter }; 13941a997ff2SDaniel Vetter static const struct intel_gtt_driver i8xx_gtt_driver = { 13951a997ff2SDaniel Vetter .gen = 2, 1396100519e2SChris Wilson .has_pgtbl_enable = 1, 139773800422SDaniel Vetter .setup = i830_setup, 1398ae83dd5cSDaniel Vetter .cleanup = i830_cleanup, 1399351bb278SDaniel Vetter .write_entry = i830_write_entry, 140022533b49SDaniel Vetter .dma_mask_size = 32, 14015cbecafcSDaniel Vetter .check_flags = i830_check_flags, 14021b263f24SDaniel Vetter .chipset_flush = i830_chipset_flush, 14031a997ff2SDaniel Vetter }; 14041a997ff2SDaniel Vetter static const struct intel_gtt_driver i915_gtt_driver = { 14051a997ff2SDaniel Vetter .gen = 3, 1406100519e2SChris Wilson .has_pgtbl_enable = 1, 14072d2430cfSDaniel Vetter .setup = i9xx_setup, 1408ae83dd5cSDaniel Vetter .cleanup = i9xx_cleanup, 1409351bb278SDaniel Vetter /* i945 is the last gpu to need phys mem (for overlay and cursors). */ 1410351bb278SDaniel Vetter .write_entry = i830_write_entry, 141122533b49SDaniel Vetter .dma_mask_size = 32, 1412fefaa70fSDaniel Vetter .check_flags = i830_check_flags, 14131b263f24SDaniel Vetter .chipset_flush = i9xx_chipset_flush, 14141a997ff2SDaniel Vetter }; 14151a997ff2SDaniel Vetter static const struct intel_gtt_driver g33_gtt_driver = { 14161a997ff2SDaniel Vetter .gen = 3, 14171a997ff2SDaniel Vetter .is_g33 = 1, 14182d2430cfSDaniel Vetter .setup = i9xx_setup, 1419ae83dd5cSDaniel Vetter .cleanup = i9xx_cleanup, 1420a6963596SDaniel Vetter .write_entry = i965_write_entry, 142122533b49SDaniel Vetter .dma_mask_size = 36, 1422450f2b3dSDaniel Vetter .check_flags = i830_check_flags, 14231b263f24SDaniel Vetter .chipset_flush = i9xx_chipset_flush, 14241a997ff2SDaniel Vetter }; 14251a997ff2SDaniel Vetter static const struct intel_gtt_driver pineview_gtt_driver = { 14261a997ff2SDaniel Vetter .gen = 3, 14271a997ff2SDaniel Vetter .is_pineview = 1, .is_g33 = 1, 14282d2430cfSDaniel Vetter .setup = i9xx_setup, 1429ae83dd5cSDaniel Vetter .cleanup = i9xx_cleanup, 1430a6963596SDaniel Vetter .write_entry = i965_write_entry, 143122533b49SDaniel Vetter .dma_mask_size = 36, 1432450f2b3dSDaniel Vetter .check_flags = i830_check_flags, 14331b263f24SDaniel Vetter .chipset_flush = i9xx_chipset_flush, 14341a997ff2SDaniel Vetter }; 14351a997ff2SDaniel Vetter static const struct intel_gtt_driver i965_gtt_driver = { 14361a997ff2SDaniel Vetter .gen = 4, 1437100519e2SChris Wilson .has_pgtbl_enable = 1, 14382d2430cfSDaniel Vetter .setup = i9xx_setup, 1439ae83dd5cSDaniel Vetter .cleanup = i9xx_cleanup, 1440a6963596SDaniel Vetter .write_entry = i965_write_entry, 144122533b49SDaniel Vetter .dma_mask_size = 36, 1442450f2b3dSDaniel Vetter .check_flags = i830_check_flags, 14431b263f24SDaniel Vetter .chipset_flush = i9xx_chipset_flush, 14441a997ff2SDaniel Vetter }; 14451a997ff2SDaniel Vetter static const struct intel_gtt_driver g4x_gtt_driver = { 14461a997ff2SDaniel Vetter .gen = 5, 14472d2430cfSDaniel Vetter .setup = i9xx_setup, 1448ae83dd5cSDaniel Vetter .cleanup = i9xx_cleanup, 1449a6963596SDaniel Vetter .write_entry = i965_write_entry, 145022533b49SDaniel Vetter .dma_mask_size = 36, 1451450f2b3dSDaniel Vetter .check_flags = i830_check_flags, 14521b263f24SDaniel Vetter .chipset_flush = i9xx_chipset_flush, 14531a997ff2SDaniel Vetter }; 14541a997ff2SDaniel Vetter static const struct intel_gtt_driver ironlake_gtt_driver = { 14551a997ff2SDaniel Vetter .gen = 5, 14561a997ff2SDaniel Vetter .is_ironlake = 1, 14572d2430cfSDaniel Vetter .setup = i9xx_setup, 1458ae83dd5cSDaniel Vetter .cleanup = i9xx_cleanup, 1459a6963596SDaniel Vetter .write_entry = i965_write_entry, 146022533b49SDaniel Vetter .dma_mask_size = 36, 1461450f2b3dSDaniel Vetter .check_flags = i830_check_flags, 14621b263f24SDaniel Vetter .chipset_flush = i9xx_chipset_flush, 14631a997ff2SDaniel Vetter }; 14641a997ff2SDaniel Vetter static const struct intel_gtt_driver sandybridge_gtt_driver = { 14651a997ff2SDaniel Vetter .gen = 6, 14662d2430cfSDaniel Vetter .setup = i9xx_setup, 1467ae83dd5cSDaniel Vetter .cleanup = gen6_cleanup, 146897ef1bddSDaniel Vetter .write_entry = gen6_write_entry, 146922533b49SDaniel Vetter .dma_mask_size = 40, 147090cb149eSDaniel Vetter .check_flags = gen6_check_flags, 14711b263f24SDaniel Vetter .chipset_flush = i9xx_chipset_flush, 14721a997ff2SDaniel Vetter }; 14731a997ff2SDaniel Vetter 147402c026ceSDaniel Vetter /* Table to describe Intel GMCH and AGP/PCIE GART drivers. At least one of 147502c026ceSDaniel Vetter * driver and gmch_driver must be non-null, and find_gmch will determine 147602c026ceSDaniel Vetter * which one should be used if a gmch_chip_id is present. 147702c026ceSDaniel Vetter */ 147802c026ceSDaniel Vetter static const struct intel_gtt_driver_description { 147902c026ceSDaniel Vetter unsigned int gmch_chip_id; 148002c026ceSDaniel Vetter char *name; 148102c026ceSDaniel Vetter const struct agp_bridge_driver *gmch_driver; 14821a997ff2SDaniel Vetter const struct intel_gtt_driver *gtt_driver; 148302c026ceSDaniel Vetter } intel_gtt_chipsets[] = { 1484bdd30729SDaniel Vetter { PCI_DEVICE_ID_INTEL_82810_IG1, "i810", &intel_810_driver, 1485bdd30729SDaniel Vetter &i81x_gtt_driver}, 1486bdd30729SDaniel Vetter { PCI_DEVICE_ID_INTEL_82810_IG3, "i810", &intel_810_driver, 1487bdd30729SDaniel Vetter &i81x_gtt_driver}, 1488bdd30729SDaniel Vetter { PCI_DEVICE_ID_INTEL_82810E_IG, "i810", &intel_810_driver, 1489bdd30729SDaniel Vetter &i81x_gtt_driver}, 1490bdd30729SDaniel Vetter { PCI_DEVICE_ID_INTEL_82815_CGC, "i815", &intel_810_driver, 1491bdd30729SDaniel Vetter &i81x_gtt_driver}, 14921a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_82830_CGC, "830M", 1493e9b1cc81SDaniel Vetter &intel_fake_agp_driver, &i8xx_gtt_driver}, 14941a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_82845G_IG, "830M", 1495e9b1cc81SDaniel Vetter &intel_fake_agp_driver, &i8xx_gtt_driver}, 14961a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_82854_IG, "854", 1497e9b1cc81SDaniel Vetter &intel_fake_agp_driver, &i8xx_gtt_driver}, 14981a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_82855GM_IG, "855GM", 1499e9b1cc81SDaniel Vetter &intel_fake_agp_driver, &i8xx_gtt_driver}, 15001a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_82865_IG, "865", 1501e9b1cc81SDaniel Vetter &intel_fake_agp_driver, &i8xx_gtt_driver}, 15021a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_E7221_IG, "E7221 (i915)", 1503e9b1cc81SDaniel Vetter &intel_fake_agp_driver, &i915_gtt_driver }, 15041a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_82915G_IG, "915G", 1505e9b1cc81SDaniel Vetter &intel_fake_agp_driver, &i915_gtt_driver }, 15061a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_82915GM_IG, "915GM", 1507e9b1cc81SDaniel Vetter &intel_fake_agp_driver, &i915_gtt_driver }, 15081a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_82945G_IG, "945G", 1509e9b1cc81SDaniel Vetter &intel_fake_agp_driver, &i915_gtt_driver }, 15101a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_82945GM_IG, "945GM", 1511e9b1cc81SDaniel Vetter &intel_fake_agp_driver, &i915_gtt_driver }, 15121a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_82945GME_IG, "945GME", 1513e9b1cc81SDaniel Vetter &intel_fake_agp_driver, &i915_gtt_driver }, 15141a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_82946GZ_IG, "946GZ", 1515e9b1cc81SDaniel Vetter &intel_fake_agp_driver, &i965_gtt_driver }, 15161a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_82G35_IG, "G35", 1517e9b1cc81SDaniel Vetter &intel_fake_agp_driver, &i965_gtt_driver }, 15181a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_82965Q_IG, "965Q", 1519e9b1cc81SDaniel Vetter &intel_fake_agp_driver, &i965_gtt_driver }, 15201a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_82965G_IG, "965G", 1521e9b1cc81SDaniel Vetter &intel_fake_agp_driver, &i965_gtt_driver }, 15221a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_82965GM_IG, "965GM", 1523e9b1cc81SDaniel Vetter &intel_fake_agp_driver, &i965_gtt_driver }, 15241a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_82965GME_IG, "965GME/GLE", 1525e9b1cc81SDaniel Vetter &intel_fake_agp_driver, &i965_gtt_driver }, 15261a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_G33_IG, "G33", 1527e9b1cc81SDaniel Vetter &intel_fake_agp_driver, &g33_gtt_driver }, 15281a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_Q35_IG, "Q35", 1529e9b1cc81SDaniel Vetter &intel_fake_agp_driver, &g33_gtt_driver }, 15301a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_Q33_IG, "Q33", 1531e9b1cc81SDaniel Vetter &intel_fake_agp_driver, &g33_gtt_driver }, 15321a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_PINEVIEW_M_IG, "GMA3150", 1533e9b1cc81SDaniel Vetter &intel_fake_agp_driver, &pineview_gtt_driver }, 15341a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_PINEVIEW_IG, "GMA3150", 1535e9b1cc81SDaniel Vetter &intel_fake_agp_driver, &pineview_gtt_driver }, 15361a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_GM45_IG, "GM45", 1537e9b1cc81SDaniel Vetter &intel_fake_agp_driver, &g4x_gtt_driver }, 15381a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_EAGLELAKE_IG, "Eaglelake", 1539e9b1cc81SDaniel Vetter &intel_fake_agp_driver, &g4x_gtt_driver }, 15401a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_Q45_IG, "Q45/Q43", 1541e9b1cc81SDaniel Vetter &intel_fake_agp_driver, &g4x_gtt_driver }, 15421a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_G45_IG, "G45/G43", 1543e9b1cc81SDaniel Vetter &intel_fake_agp_driver, &g4x_gtt_driver }, 15441a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_B43_IG, "B43", 1545e9b1cc81SDaniel Vetter &intel_fake_agp_driver, &g4x_gtt_driver }, 1546e9e5f8e8SChris Wilson { PCI_DEVICE_ID_INTEL_B43_1_IG, "B43", 1547e9b1cc81SDaniel Vetter &intel_fake_agp_driver, &g4x_gtt_driver }, 15481a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_G41_IG, "G41", 1549e9b1cc81SDaniel Vetter &intel_fake_agp_driver, &g4x_gtt_driver }, 155002c026ceSDaniel Vetter { PCI_DEVICE_ID_INTEL_IRONLAKE_D_IG, 1551e9b1cc81SDaniel Vetter "HD Graphics", &intel_fake_agp_driver, &ironlake_gtt_driver }, 155202c026ceSDaniel Vetter { PCI_DEVICE_ID_INTEL_IRONLAKE_M_IG, 1553e9b1cc81SDaniel Vetter "HD Graphics", &intel_fake_agp_driver, &ironlake_gtt_driver }, 155402c026ceSDaniel Vetter { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_GT1_IG, 1555e9b1cc81SDaniel Vetter "Sandybridge", &intel_fake_agp_driver, &sandybridge_gtt_driver }, 155602c026ceSDaniel Vetter { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_GT2_IG, 1557e9b1cc81SDaniel Vetter "Sandybridge", &intel_fake_agp_driver, &sandybridge_gtt_driver }, 155802c026ceSDaniel Vetter { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_GT2_PLUS_IG, 1559e9b1cc81SDaniel Vetter "Sandybridge", &intel_fake_agp_driver, &sandybridge_gtt_driver }, 156002c026ceSDaniel Vetter { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_GT1_IG, 1561e9b1cc81SDaniel Vetter "Sandybridge", &intel_fake_agp_driver, &sandybridge_gtt_driver }, 156202c026ceSDaniel Vetter { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_GT2_IG, 1563e9b1cc81SDaniel Vetter "Sandybridge", &intel_fake_agp_driver, &sandybridge_gtt_driver }, 156402c026ceSDaniel Vetter { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_GT2_PLUS_IG, 1565e9b1cc81SDaniel Vetter "Sandybridge", &intel_fake_agp_driver, &sandybridge_gtt_driver }, 156602c026ceSDaniel Vetter { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_S_IG, 1567e9b1cc81SDaniel Vetter "Sandybridge", &intel_fake_agp_driver, &sandybridge_gtt_driver }, 156802c026ceSDaniel Vetter { 0, NULL, NULL } 156902c026ceSDaniel Vetter }; 157002c026ceSDaniel Vetter 157102c026ceSDaniel Vetter static int find_gmch(u16 device) 157202c026ceSDaniel Vetter { 157302c026ceSDaniel Vetter struct pci_dev *gmch_device; 157402c026ceSDaniel Vetter 157502c026ceSDaniel Vetter gmch_device = pci_get_device(PCI_VENDOR_ID_INTEL, device, NULL); 157602c026ceSDaniel Vetter if (gmch_device && PCI_FUNC(gmch_device->devfn) != 0) { 157702c026ceSDaniel Vetter gmch_device = pci_get_device(PCI_VENDOR_ID_INTEL, 157802c026ceSDaniel Vetter device, gmch_device); 157902c026ceSDaniel Vetter } 158002c026ceSDaniel Vetter 158102c026ceSDaniel Vetter if (!gmch_device) 158202c026ceSDaniel Vetter return 0; 158302c026ceSDaniel Vetter 158402c026ceSDaniel Vetter intel_private.pcidev = gmch_device; 158502c026ceSDaniel Vetter return 1; 158602c026ceSDaniel Vetter } 158702c026ceSDaniel Vetter 1588e2404e7cSDaniel Vetter int intel_gmch_probe(struct pci_dev *pdev, 158902c026ceSDaniel Vetter struct agp_bridge_data *bridge) 159002c026ceSDaniel Vetter { 159102c026ceSDaniel Vetter int i, mask; 159202c026ceSDaniel Vetter bridge->driver = NULL; 159302c026ceSDaniel Vetter 159402c026ceSDaniel Vetter for (i = 0; intel_gtt_chipsets[i].name != NULL; i++) { 159502c026ceSDaniel Vetter if (find_gmch(intel_gtt_chipsets[i].gmch_chip_id)) { 159602c026ceSDaniel Vetter bridge->driver = 159702c026ceSDaniel Vetter intel_gtt_chipsets[i].gmch_driver; 15981a997ff2SDaniel Vetter intel_private.driver = 15991a997ff2SDaniel Vetter intel_gtt_chipsets[i].gtt_driver; 160002c026ceSDaniel Vetter break; 160102c026ceSDaniel Vetter } 160202c026ceSDaniel Vetter } 160302c026ceSDaniel Vetter 160402c026ceSDaniel Vetter if (!bridge->driver) 160502c026ceSDaniel Vetter return 0; 160602c026ceSDaniel Vetter 160702c026ceSDaniel Vetter bridge->dev_private_data = &intel_private; 160802c026ceSDaniel Vetter bridge->dev = pdev; 160902c026ceSDaniel Vetter 1610d7cca2f7SDaniel Vetter intel_private.bridge_dev = pci_dev_get(pdev); 1611d7cca2f7SDaniel Vetter 161202c026ceSDaniel Vetter dev_info(&pdev->dev, "Intel %s Chipset\n", intel_gtt_chipsets[i].name); 161302c026ceSDaniel Vetter 161422533b49SDaniel Vetter mask = intel_private.driver->dma_mask_size; 161502c026ceSDaniel Vetter if (pci_set_dma_mask(intel_private.pcidev, DMA_BIT_MASK(mask))) 161602c026ceSDaniel Vetter dev_err(&intel_private.pcidev->dev, 161702c026ceSDaniel Vetter "set gfx device dma mask %d-bit failed!\n", mask); 161802c026ceSDaniel Vetter else 161902c026ceSDaniel Vetter pci_set_consistent_dma_mask(intel_private.pcidev, 162002c026ceSDaniel Vetter DMA_BIT_MASK(mask)); 162102c026ceSDaniel Vetter 16221784a5fbSDaniel Vetter if (bridge->driver == &intel_810_driver) 16231784a5fbSDaniel Vetter return 1; 16241784a5fbSDaniel Vetter 16253b15a9d7SDaniel Vetter if (intel_gtt_init() != 0) 16263b15a9d7SDaniel Vetter return 0; 16271784a5fbSDaniel Vetter 162802c026ceSDaniel Vetter return 1; 162902c026ceSDaniel Vetter } 1630e2404e7cSDaniel Vetter EXPORT_SYMBOL(intel_gmch_probe); 163102c026ceSDaniel Vetter 163219966754SDaniel Vetter struct intel_gtt *intel_gtt_get(void) 163319966754SDaniel Vetter { 163419966754SDaniel Vetter return &intel_private.base; 163519966754SDaniel Vetter } 163619966754SDaniel Vetter EXPORT_SYMBOL(intel_gtt_get); 163719966754SDaniel Vetter 1638e2404e7cSDaniel Vetter void intel_gmch_remove(struct pci_dev *pdev) 163902c026ceSDaniel Vetter { 164002c026ceSDaniel Vetter if (intel_private.pcidev) 164102c026ceSDaniel Vetter pci_dev_put(intel_private.pcidev); 1642d7cca2f7SDaniel Vetter if (intel_private.bridge_dev) 1643d7cca2f7SDaniel Vetter pci_dev_put(intel_private.bridge_dev); 164402c026ceSDaniel Vetter } 1645e2404e7cSDaniel Vetter EXPORT_SYMBOL(intel_gmch_remove); 1646e2404e7cSDaniel Vetter 1647e2404e7cSDaniel Vetter MODULE_AUTHOR("Dave Jones <davej@redhat.com>"); 1648e2404e7cSDaniel Vetter MODULE_LICENSE("GPL and additional rights"); 1649