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 42d1d6ca73SJesse Barnes /* Max amount of stolen space, anything above will be returned to Linux */ 43d1d6ca73SJesse Barnes int intel_max_stolen = 32 * 1024 * 1024; 44d1d6ca73SJesse Barnes 45f51b7662SDaniel Vetter static const struct aper_size_info_fixed intel_i810_sizes[] = 46f51b7662SDaniel Vetter { 47f51b7662SDaniel Vetter {64, 16384, 4}, 48f51b7662SDaniel Vetter /* The 32M mode still requires a 64k gatt */ 49f51b7662SDaniel Vetter {32, 8192, 4} 50f51b7662SDaniel Vetter }; 51f51b7662SDaniel Vetter 52f51b7662SDaniel Vetter #define AGP_DCACHE_MEMORY 1 53f51b7662SDaniel Vetter #define AGP_PHYS_MEMORY 2 54f51b7662SDaniel Vetter #define INTEL_AGP_CACHED_MEMORY 3 55f51b7662SDaniel Vetter 56f51b7662SDaniel Vetter static struct gatt_mask intel_i810_masks[] = 57f51b7662SDaniel Vetter { 58f51b7662SDaniel Vetter {.mask = I810_PTE_VALID, .type = 0}, 59f51b7662SDaniel Vetter {.mask = (I810_PTE_VALID | I810_PTE_LOCAL), .type = AGP_DCACHE_MEMORY}, 60f51b7662SDaniel Vetter {.mask = I810_PTE_VALID, .type = 0}, 61f51b7662SDaniel Vetter {.mask = I810_PTE_VALID | I830_PTE_SYSTEM_CACHED, 62f51b7662SDaniel Vetter .type = INTEL_AGP_CACHED_MEMORY} 63f51b7662SDaniel Vetter }; 64f51b7662SDaniel Vetter 65f8f235e5SZhenyu Wang #define INTEL_AGP_UNCACHED_MEMORY 0 66f8f235e5SZhenyu Wang #define INTEL_AGP_CACHED_MEMORY_LLC 1 67f8f235e5SZhenyu Wang #define INTEL_AGP_CACHED_MEMORY_LLC_GFDT 2 68f8f235e5SZhenyu Wang #define INTEL_AGP_CACHED_MEMORY_LLC_MLC 3 69f8f235e5SZhenyu Wang #define INTEL_AGP_CACHED_MEMORY_LLC_MLC_GFDT 4 70f8f235e5SZhenyu Wang 711a997ff2SDaniel Vetter struct intel_gtt_driver { 721a997ff2SDaniel Vetter unsigned int gen : 8; 731a997ff2SDaniel Vetter unsigned int is_g33 : 1; 741a997ff2SDaniel Vetter unsigned int is_pineview : 1; 751a997ff2SDaniel Vetter unsigned int is_ironlake : 1; 7622533b49SDaniel Vetter unsigned int dma_mask_size : 8; 7773800422SDaniel Vetter /* Chipset specific GTT setup */ 7873800422SDaniel Vetter int (*setup)(void); 79ae83dd5cSDaniel Vetter /* This should undo anything done in ->setup() save the unmapping 80ae83dd5cSDaniel Vetter * of the mmio register file, that's done in the generic code. */ 81ae83dd5cSDaniel Vetter void (*cleanup)(void); 82351bb278SDaniel Vetter void (*write_entry)(dma_addr_t addr, unsigned int entry, unsigned int flags); 83351bb278SDaniel Vetter /* Flags is a more or less chipset specific opaque value. 84351bb278SDaniel Vetter * For chipsets that need to support old ums (non-gem) code, this 85351bb278SDaniel Vetter * needs to be identical to the various supported agp memory types! */ 865cbecafcSDaniel Vetter bool (*check_flags)(unsigned int flags); 871b263f24SDaniel Vetter void (*chipset_flush)(void); 881a997ff2SDaniel Vetter }; 891a997ff2SDaniel Vetter 90f51b7662SDaniel Vetter static struct _intel_private { 910ade6386SDaniel Vetter struct intel_gtt base; 921a997ff2SDaniel Vetter const struct intel_gtt_driver *driver; 93f51b7662SDaniel Vetter struct pci_dev *pcidev; /* device one */ 94d7cca2f7SDaniel Vetter struct pci_dev *bridge_dev; 95f51b7662SDaniel Vetter u8 __iomem *registers; 96f67eab66SDaniel Vetter phys_addr_t gtt_bus_addr; 9773800422SDaniel Vetter phys_addr_t gma_bus_addr; 98b3eafc5aSDaniel Vetter u32 PGETBL_save; 99f51b7662SDaniel Vetter u32 __iomem *gtt; /* I915G */ 100f51b7662SDaniel Vetter int num_dcache_entries; 101f51b7662SDaniel Vetter union { 102f51b7662SDaniel Vetter void __iomem *i9xx_flush_page; 103f51b7662SDaniel Vetter void *i8xx_flush_page; 104f51b7662SDaniel Vetter }; 105f51b7662SDaniel Vetter struct page *i8xx_page; 106f51b7662SDaniel Vetter struct resource ifp_resource; 107f51b7662SDaniel Vetter int resource_valid; 1080e87d2b0SDaniel Vetter struct page *scratch_page; 1090e87d2b0SDaniel Vetter dma_addr_t scratch_page_dma; 110f51b7662SDaniel Vetter } intel_private; 111f51b7662SDaniel Vetter 1121a997ff2SDaniel Vetter #define INTEL_GTT_GEN intel_private.driver->gen 1131a997ff2SDaniel Vetter #define IS_G33 intel_private.driver->is_g33 1141a997ff2SDaniel Vetter #define IS_PINEVIEW intel_private.driver->is_pineview 1151a997ff2SDaniel Vetter #define IS_IRONLAKE intel_private.driver->is_ironlake 1161a997ff2SDaniel Vetter 117f51b7662SDaniel Vetter static void intel_agp_free_sglist(struct agp_memory *mem) 118f51b7662SDaniel Vetter { 119f51b7662SDaniel Vetter struct sg_table st; 120f51b7662SDaniel Vetter 121f51b7662SDaniel Vetter st.sgl = mem->sg_list; 122f51b7662SDaniel Vetter st.orig_nents = st.nents = mem->page_count; 123f51b7662SDaniel Vetter 124f51b7662SDaniel Vetter sg_free_table(&st); 125f51b7662SDaniel Vetter 126f51b7662SDaniel Vetter mem->sg_list = NULL; 127f51b7662SDaniel Vetter mem->num_sg = 0; 128f51b7662SDaniel Vetter } 129f51b7662SDaniel Vetter 130f51b7662SDaniel Vetter static int intel_agp_map_memory(struct agp_memory *mem) 131f51b7662SDaniel Vetter { 132f51b7662SDaniel Vetter struct sg_table st; 133f51b7662SDaniel Vetter struct scatterlist *sg; 134f51b7662SDaniel Vetter int i; 135f51b7662SDaniel Vetter 136fefaa70fSDaniel Vetter if (mem->sg_list) 137fefaa70fSDaniel Vetter return 0; /* already mapped (for e.g. resume */ 138fefaa70fSDaniel Vetter 139f51b7662SDaniel Vetter DBG("try mapping %lu pages\n", (unsigned long)mem->page_count); 140f51b7662SDaniel Vetter 141f51b7662SDaniel Vetter if (sg_alloc_table(&st, mem->page_count, GFP_KERNEL)) 142831cd445SChris Wilson goto err; 143f51b7662SDaniel Vetter 144f51b7662SDaniel Vetter mem->sg_list = sg = st.sgl; 145f51b7662SDaniel Vetter 146f51b7662SDaniel Vetter for (i = 0 ; i < mem->page_count; i++, sg = sg_next(sg)) 147f51b7662SDaniel Vetter sg_set_page(sg, mem->pages[i], PAGE_SIZE, 0); 148f51b7662SDaniel Vetter 149f51b7662SDaniel Vetter mem->num_sg = pci_map_sg(intel_private.pcidev, mem->sg_list, 150f51b7662SDaniel Vetter mem->page_count, PCI_DMA_BIDIRECTIONAL); 151831cd445SChris Wilson if (unlikely(!mem->num_sg)) 152831cd445SChris Wilson goto err; 153831cd445SChris Wilson 154f51b7662SDaniel Vetter return 0; 155831cd445SChris Wilson 156831cd445SChris Wilson err: 157831cd445SChris Wilson sg_free_table(&st); 158831cd445SChris Wilson return -ENOMEM; 159f51b7662SDaniel Vetter } 160f51b7662SDaniel Vetter 161f51b7662SDaniel Vetter static void intel_agp_unmap_memory(struct agp_memory *mem) 162f51b7662SDaniel Vetter { 163f51b7662SDaniel Vetter DBG("try unmapping %lu pages\n", (unsigned long)mem->page_count); 164f51b7662SDaniel Vetter 165f51b7662SDaniel Vetter pci_unmap_sg(intel_private.pcidev, mem->sg_list, 166f51b7662SDaniel Vetter mem->page_count, PCI_DMA_BIDIRECTIONAL); 167f51b7662SDaniel Vetter intel_agp_free_sglist(mem); 168f51b7662SDaniel Vetter } 169f51b7662SDaniel Vetter 170f51b7662SDaniel Vetter static int intel_i810_fetch_size(void) 171f51b7662SDaniel Vetter { 172f51b7662SDaniel Vetter u32 smram_miscc; 173f51b7662SDaniel Vetter struct aper_size_info_fixed *values; 174f51b7662SDaniel Vetter 175d7cca2f7SDaniel Vetter pci_read_config_dword(intel_private.bridge_dev, 176d7cca2f7SDaniel Vetter I810_SMRAM_MISCC, &smram_miscc); 177f51b7662SDaniel Vetter values = A_SIZE_FIX(agp_bridge->driver->aperture_sizes); 178f51b7662SDaniel Vetter 179f51b7662SDaniel Vetter if ((smram_miscc & I810_GMS) == I810_GMS_DISABLE) { 180d7cca2f7SDaniel Vetter dev_warn(&intel_private.bridge_dev->dev, "i810 is disabled\n"); 181f51b7662SDaniel Vetter return 0; 182f51b7662SDaniel Vetter } 183f51b7662SDaniel Vetter if ((smram_miscc & I810_GFX_MEM_WIN_SIZE) == I810_GFX_MEM_WIN_32M) { 184f51b7662SDaniel Vetter agp_bridge->current_size = (void *) (values + 1); 185f51b7662SDaniel Vetter agp_bridge->aperture_size_idx = 1; 186f51b7662SDaniel Vetter return values[1].size; 187f51b7662SDaniel Vetter } else { 188f51b7662SDaniel Vetter agp_bridge->current_size = (void *) (values); 189f51b7662SDaniel Vetter agp_bridge->aperture_size_idx = 0; 190f51b7662SDaniel Vetter return values[0].size; 191f51b7662SDaniel Vetter } 192f51b7662SDaniel Vetter 193f51b7662SDaniel Vetter return 0; 194f51b7662SDaniel Vetter } 195f51b7662SDaniel Vetter 196f51b7662SDaniel Vetter static int intel_i810_configure(void) 197f51b7662SDaniel Vetter { 198f51b7662SDaniel Vetter struct aper_size_info_fixed *current_size; 199f51b7662SDaniel Vetter u32 temp; 200f51b7662SDaniel Vetter int i; 201f51b7662SDaniel Vetter 202f51b7662SDaniel Vetter current_size = A_SIZE_FIX(agp_bridge->current_size); 203f51b7662SDaniel Vetter 204f51b7662SDaniel Vetter if (!intel_private.registers) { 205f51b7662SDaniel Vetter pci_read_config_dword(intel_private.pcidev, I810_MMADDR, &temp); 206f51b7662SDaniel Vetter temp &= 0xfff80000; 207f51b7662SDaniel Vetter 208f51b7662SDaniel Vetter intel_private.registers = ioremap(temp, 128 * 4096); 209f51b7662SDaniel Vetter if (!intel_private.registers) { 210f51b7662SDaniel Vetter dev_err(&intel_private.pcidev->dev, 211f51b7662SDaniel Vetter "can't remap memory\n"); 212f51b7662SDaniel Vetter return -ENOMEM; 213f51b7662SDaniel Vetter } 214f51b7662SDaniel Vetter } 215f51b7662SDaniel Vetter 216f51b7662SDaniel Vetter if ((readl(intel_private.registers+I810_DRAM_CTL) 217f51b7662SDaniel Vetter & I810_DRAM_ROW_0) == I810_DRAM_ROW_0_SDRAM) { 218f51b7662SDaniel Vetter /* This will need to be dynamically assigned */ 219f51b7662SDaniel Vetter dev_info(&intel_private.pcidev->dev, 220f51b7662SDaniel Vetter "detected 4MB dedicated video ram\n"); 221f51b7662SDaniel Vetter intel_private.num_dcache_entries = 1024; 222f51b7662SDaniel Vetter } 223f51b7662SDaniel Vetter pci_read_config_dword(intel_private.pcidev, I810_GMADDR, &temp); 224f51b7662SDaniel Vetter agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); 225f51b7662SDaniel Vetter writel(agp_bridge->gatt_bus_addr | I810_PGETBL_ENABLED, intel_private.registers+I810_PGETBL_CTL); 226f51b7662SDaniel Vetter readl(intel_private.registers+I810_PGETBL_CTL); /* PCI Posting. */ 227f51b7662SDaniel Vetter 228f51b7662SDaniel Vetter if (agp_bridge->driver->needs_scratch_page) { 229f51b7662SDaniel Vetter for (i = 0; i < current_size->num_entries; i++) { 230f51b7662SDaniel Vetter writel(agp_bridge->scratch_page, intel_private.registers+I810_PTE_BASE+(i*4)); 231f51b7662SDaniel Vetter } 232f51b7662SDaniel Vetter readl(intel_private.registers+I810_PTE_BASE+((i-1)*4)); /* PCI posting. */ 233f51b7662SDaniel Vetter } 234f51b7662SDaniel Vetter global_cache_flush(); 235f51b7662SDaniel Vetter return 0; 236f51b7662SDaniel Vetter } 237f51b7662SDaniel Vetter 238f51b7662SDaniel Vetter static void intel_i810_cleanup(void) 239f51b7662SDaniel Vetter { 240f51b7662SDaniel Vetter writel(0, intel_private.registers+I810_PGETBL_CTL); 241f51b7662SDaniel Vetter readl(intel_private.registers); /* PCI Posting. */ 242f51b7662SDaniel Vetter iounmap(intel_private.registers); 243f51b7662SDaniel Vetter } 244f51b7662SDaniel Vetter 245ffdd7510SDaniel Vetter static void intel_fake_agp_enable(struct agp_bridge_data *bridge, u32 mode) 246f51b7662SDaniel Vetter { 247f51b7662SDaniel Vetter return; 248f51b7662SDaniel Vetter } 249f51b7662SDaniel Vetter 250f51b7662SDaniel Vetter /* Exists to support ARGB cursors */ 251f51b7662SDaniel Vetter static struct page *i8xx_alloc_pages(void) 252f51b7662SDaniel Vetter { 253f51b7662SDaniel Vetter struct page *page; 254f51b7662SDaniel Vetter 255f51b7662SDaniel Vetter page = alloc_pages(GFP_KERNEL | GFP_DMA32, 2); 256f51b7662SDaniel Vetter if (page == NULL) 257f51b7662SDaniel Vetter return NULL; 258f51b7662SDaniel Vetter 259f51b7662SDaniel Vetter if (set_pages_uc(page, 4) < 0) { 260f51b7662SDaniel Vetter set_pages_wb(page, 4); 261f51b7662SDaniel Vetter __free_pages(page, 2); 262f51b7662SDaniel Vetter return NULL; 263f51b7662SDaniel Vetter } 264f51b7662SDaniel Vetter get_page(page); 265f51b7662SDaniel Vetter atomic_inc(&agp_bridge->current_memory_agp); 266f51b7662SDaniel Vetter return page; 267f51b7662SDaniel Vetter } 268f51b7662SDaniel Vetter 269f51b7662SDaniel Vetter static void i8xx_destroy_pages(struct page *page) 270f51b7662SDaniel Vetter { 271f51b7662SDaniel Vetter if (page == NULL) 272f51b7662SDaniel Vetter return; 273f51b7662SDaniel Vetter 274f51b7662SDaniel Vetter set_pages_wb(page, 4); 275f51b7662SDaniel Vetter put_page(page); 276f51b7662SDaniel Vetter __free_pages(page, 2); 277f51b7662SDaniel Vetter atomic_dec(&agp_bridge->current_memory_agp); 278f51b7662SDaniel Vetter } 279f51b7662SDaniel Vetter 280f51b7662SDaniel Vetter static int intel_i810_insert_entries(struct agp_memory *mem, off_t pg_start, 281f51b7662SDaniel Vetter int type) 282f51b7662SDaniel Vetter { 283f51b7662SDaniel Vetter int i, j, num_entries; 284f51b7662SDaniel Vetter void *temp; 285f51b7662SDaniel Vetter int ret = -EINVAL; 286f51b7662SDaniel Vetter int mask_type; 287f51b7662SDaniel Vetter 288f51b7662SDaniel Vetter if (mem->page_count == 0) 289f51b7662SDaniel Vetter goto out; 290f51b7662SDaniel Vetter 291f51b7662SDaniel Vetter temp = agp_bridge->current_size; 292f51b7662SDaniel Vetter num_entries = A_SIZE_FIX(temp)->num_entries; 293f51b7662SDaniel Vetter 294f51b7662SDaniel Vetter if ((pg_start + mem->page_count) > num_entries) 295f51b7662SDaniel Vetter goto out_err; 296f51b7662SDaniel Vetter 297f51b7662SDaniel Vetter 298f51b7662SDaniel Vetter for (j = pg_start; j < (pg_start + mem->page_count); j++) { 299f51b7662SDaniel Vetter if (!PGE_EMPTY(agp_bridge, readl(agp_bridge->gatt_table+j))) { 300f51b7662SDaniel Vetter ret = -EBUSY; 301f51b7662SDaniel Vetter goto out_err; 302f51b7662SDaniel Vetter } 303f51b7662SDaniel Vetter } 304f51b7662SDaniel Vetter 305f51b7662SDaniel Vetter if (type != mem->type) 306f51b7662SDaniel Vetter goto out_err; 307f51b7662SDaniel Vetter 308f51b7662SDaniel Vetter mask_type = agp_bridge->driver->agp_type_to_mask_type(agp_bridge, type); 309f51b7662SDaniel Vetter 310f51b7662SDaniel Vetter switch (mask_type) { 311f51b7662SDaniel Vetter case AGP_DCACHE_MEMORY: 312f51b7662SDaniel Vetter if (!mem->is_flushed) 313f51b7662SDaniel Vetter global_cache_flush(); 314f51b7662SDaniel Vetter for (i = pg_start; i < (pg_start + mem->page_count); i++) { 315f51b7662SDaniel Vetter writel((i*4096)|I810_PTE_LOCAL|I810_PTE_VALID, 316f51b7662SDaniel Vetter intel_private.registers+I810_PTE_BASE+(i*4)); 317f51b7662SDaniel Vetter } 318f51b7662SDaniel Vetter readl(intel_private.registers+I810_PTE_BASE+((i-1)*4)); 319f51b7662SDaniel Vetter break; 320f51b7662SDaniel Vetter case AGP_PHYS_MEMORY: 321f51b7662SDaniel Vetter case AGP_NORMAL_MEMORY: 322f51b7662SDaniel Vetter if (!mem->is_flushed) 323f51b7662SDaniel Vetter global_cache_flush(); 324f51b7662SDaniel Vetter for (i = 0, j = pg_start; i < mem->page_count; i++, j++) { 325f51b7662SDaniel Vetter writel(agp_bridge->driver->mask_memory(agp_bridge, 326f51b7662SDaniel Vetter page_to_phys(mem->pages[i]), mask_type), 327f51b7662SDaniel Vetter intel_private.registers+I810_PTE_BASE+(j*4)); 328f51b7662SDaniel Vetter } 329f51b7662SDaniel Vetter readl(intel_private.registers+I810_PTE_BASE+((j-1)*4)); 330f51b7662SDaniel Vetter break; 331f51b7662SDaniel Vetter default: 332f51b7662SDaniel Vetter goto out_err; 333f51b7662SDaniel Vetter } 334f51b7662SDaniel Vetter 335f51b7662SDaniel Vetter out: 336f51b7662SDaniel Vetter ret = 0; 337f51b7662SDaniel Vetter out_err: 338f51b7662SDaniel Vetter mem->is_flushed = true; 339f51b7662SDaniel Vetter return ret; 340f51b7662SDaniel Vetter } 341f51b7662SDaniel Vetter 342f51b7662SDaniel Vetter static int intel_i810_remove_entries(struct agp_memory *mem, off_t pg_start, 343f51b7662SDaniel Vetter int type) 344f51b7662SDaniel Vetter { 345f51b7662SDaniel Vetter int i; 346f51b7662SDaniel Vetter 347f51b7662SDaniel Vetter if (mem->page_count == 0) 348f51b7662SDaniel Vetter return 0; 349f51b7662SDaniel Vetter 350f51b7662SDaniel Vetter for (i = pg_start; i < (mem->page_count + pg_start); i++) { 351f51b7662SDaniel Vetter writel(agp_bridge->scratch_page, intel_private.registers+I810_PTE_BASE+(i*4)); 352f51b7662SDaniel Vetter } 353f51b7662SDaniel Vetter readl(intel_private.registers+I810_PTE_BASE+((i-1)*4)); 354f51b7662SDaniel Vetter 355f51b7662SDaniel Vetter return 0; 356f51b7662SDaniel Vetter } 357f51b7662SDaniel Vetter 358f51b7662SDaniel Vetter /* 359f51b7662SDaniel Vetter * The i810/i830 requires a physical address to program its mouse 360f51b7662SDaniel Vetter * pointer into hardware. 361f51b7662SDaniel Vetter * However the Xserver still writes to it through the agp aperture. 362f51b7662SDaniel Vetter */ 363f51b7662SDaniel Vetter static struct agp_memory *alloc_agpphysmem_i8xx(size_t pg_count, int type) 364f51b7662SDaniel Vetter { 365f51b7662SDaniel Vetter struct agp_memory *new; 366f51b7662SDaniel Vetter struct page *page; 367f51b7662SDaniel Vetter 368f51b7662SDaniel Vetter switch (pg_count) { 369f51b7662SDaniel Vetter case 1: page = agp_bridge->driver->agp_alloc_page(agp_bridge); 370f51b7662SDaniel Vetter break; 371f51b7662SDaniel Vetter case 4: 372f51b7662SDaniel Vetter /* kludge to get 4 physical pages for ARGB cursor */ 373f51b7662SDaniel Vetter page = i8xx_alloc_pages(); 374f51b7662SDaniel Vetter break; 375f51b7662SDaniel Vetter default: 376f51b7662SDaniel Vetter return NULL; 377f51b7662SDaniel Vetter } 378f51b7662SDaniel Vetter 379f51b7662SDaniel Vetter if (page == NULL) 380f51b7662SDaniel Vetter return NULL; 381f51b7662SDaniel Vetter 382f51b7662SDaniel Vetter new = agp_create_memory(pg_count); 383f51b7662SDaniel Vetter if (new == NULL) 384f51b7662SDaniel Vetter return NULL; 385f51b7662SDaniel Vetter 386f51b7662SDaniel Vetter new->pages[0] = page; 387f51b7662SDaniel Vetter if (pg_count == 4) { 388f51b7662SDaniel Vetter /* kludge to get 4 physical pages for ARGB cursor */ 389f51b7662SDaniel Vetter new->pages[1] = new->pages[0] + 1; 390f51b7662SDaniel Vetter new->pages[2] = new->pages[1] + 1; 391f51b7662SDaniel Vetter new->pages[3] = new->pages[2] + 1; 392f51b7662SDaniel Vetter } 393f51b7662SDaniel Vetter new->page_count = pg_count; 394f51b7662SDaniel Vetter new->num_scratch_pages = pg_count; 395f51b7662SDaniel Vetter new->type = AGP_PHYS_MEMORY; 396f51b7662SDaniel Vetter new->physical = page_to_phys(new->pages[0]); 397f51b7662SDaniel Vetter return new; 398f51b7662SDaniel Vetter } 399f51b7662SDaniel Vetter 400f51b7662SDaniel Vetter static struct agp_memory *intel_i810_alloc_by_type(size_t pg_count, int type) 401f51b7662SDaniel Vetter { 402f51b7662SDaniel Vetter struct agp_memory *new; 403f51b7662SDaniel Vetter 404f51b7662SDaniel Vetter if (type == AGP_DCACHE_MEMORY) { 405f51b7662SDaniel Vetter if (pg_count != intel_private.num_dcache_entries) 406f51b7662SDaniel Vetter return NULL; 407f51b7662SDaniel Vetter 408f51b7662SDaniel Vetter new = agp_create_memory(1); 409f51b7662SDaniel Vetter if (new == NULL) 410f51b7662SDaniel Vetter return NULL; 411f51b7662SDaniel Vetter 412f51b7662SDaniel Vetter new->type = AGP_DCACHE_MEMORY; 413f51b7662SDaniel Vetter new->page_count = pg_count; 414f51b7662SDaniel Vetter new->num_scratch_pages = 0; 415f51b7662SDaniel Vetter agp_free_page_array(new); 416f51b7662SDaniel Vetter return new; 417f51b7662SDaniel Vetter } 418f51b7662SDaniel Vetter if (type == AGP_PHYS_MEMORY) 419f51b7662SDaniel Vetter return alloc_agpphysmem_i8xx(pg_count, type); 420f51b7662SDaniel Vetter return NULL; 421f51b7662SDaniel Vetter } 422f51b7662SDaniel Vetter 423f51b7662SDaniel Vetter static void intel_i810_free_by_type(struct agp_memory *curr) 424f51b7662SDaniel Vetter { 425f51b7662SDaniel Vetter agp_free_key(curr->key); 426f51b7662SDaniel Vetter if (curr->type == AGP_PHYS_MEMORY) { 427f51b7662SDaniel Vetter if (curr->page_count == 4) 428f51b7662SDaniel Vetter i8xx_destroy_pages(curr->pages[0]); 429f51b7662SDaniel Vetter else { 430f51b7662SDaniel Vetter agp_bridge->driver->agp_destroy_page(curr->pages[0], 431f51b7662SDaniel Vetter AGP_PAGE_DESTROY_UNMAP); 432f51b7662SDaniel Vetter agp_bridge->driver->agp_destroy_page(curr->pages[0], 433f51b7662SDaniel Vetter AGP_PAGE_DESTROY_FREE); 434f51b7662SDaniel Vetter } 435f51b7662SDaniel Vetter agp_free_page_array(curr); 436f51b7662SDaniel Vetter } 437f51b7662SDaniel Vetter kfree(curr); 438f51b7662SDaniel Vetter } 439f51b7662SDaniel Vetter 440f51b7662SDaniel Vetter static unsigned long intel_i810_mask_memory(struct agp_bridge_data *bridge, 441f51b7662SDaniel Vetter dma_addr_t addr, int type) 442f51b7662SDaniel Vetter { 443f51b7662SDaniel Vetter /* Type checking must be done elsewhere */ 444f51b7662SDaniel Vetter return addr | bridge->driver->masks[type].mask; 445f51b7662SDaniel Vetter } 446f51b7662SDaniel Vetter 4470e87d2b0SDaniel Vetter static int intel_gtt_setup_scratch_page(void) 4480e87d2b0SDaniel Vetter { 4490e87d2b0SDaniel Vetter struct page *page; 4500e87d2b0SDaniel Vetter dma_addr_t dma_addr; 4510e87d2b0SDaniel Vetter 4520e87d2b0SDaniel Vetter page = alloc_page(GFP_KERNEL | GFP_DMA32 | __GFP_ZERO); 4530e87d2b0SDaniel Vetter if (page == NULL) 4540e87d2b0SDaniel Vetter return -ENOMEM; 4550e87d2b0SDaniel Vetter get_page(page); 4560e87d2b0SDaniel Vetter set_pages_uc(page, 1); 4570e87d2b0SDaniel Vetter 4580e87d2b0SDaniel Vetter if (USE_PCI_DMA_API && INTEL_GTT_GEN > 2) { 4590e87d2b0SDaniel Vetter dma_addr = pci_map_page(intel_private.pcidev, page, 0, 4600e87d2b0SDaniel Vetter PAGE_SIZE, PCI_DMA_BIDIRECTIONAL); 4610e87d2b0SDaniel Vetter if (pci_dma_mapping_error(intel_private.pcidev, dma_addr)) 4620e87d2b0SDaniel Vetter return -EINVAL; 4630e87d2b0SDaniel Vetter 4640e87d2b0SDaniel Vetter intel_private.scratch_page_dma = dma_addr; 4650e87d2b0SDaniel Vetter } else 4660e87d2b0SDaniel Vetter intel_private.scratch_page_dma = page_to_phys(page); 4670e87d2b0SDaniel Vetter 4680e87d2b0SDaniel Vetter intel_private.scratch_page = page; 4690e87d2b0SDaniel Vetter 4700e87d2b0SDaniel Vetter return 0; 4710e87d2b0SDaniel Vetter } 4720e87d2b0SDaniel Vetter 4739e76e7b8SChris Wilson static const struct aper_size_info_fixed const intel_fake_agp_sizes[] = { 474f51b7662SDaniel Vetter {128, 32768, 5}, 475f51b7662SDaniel Vetter /* The 64M mode still requires a 128k gatt */ 476f51b7662SDaniel Vetter {64, 16384, 5}, 477f51b7662SDaniel Vetter {256, 65536, 6}, 478f51b7662SDaniel Vetter {512, 131072, 7}, 479f51b7662SDaniel Vetter }; 480f51b7662SDaniel Vetter 481bfde067bSDaniel Vetter static unsigned int intel_gtt_stolen_entries(void) 482f51b7662SDaniel Vetter { 483f51b7662SDaniel Vetter u16 gmch_ctrl; 484f51b7662SDaniel Vetter u8 rdct; 485f51b7662SDaniel Vetter int local = 0; 486f51b7662SDaniel Vetter static const int ddt[4] = { 0, 16, 32, 64 }; 487d8d9abcdSDaniel Vetter unsigned int overhead_entries, stolen_entries; 488d8d9abcdSDaniel Vetter unsigned int stolen_size = 0; 489f51b7662SDaniel Vetter 490d7cca2f7SDaniel Vetter pci_read_config_word(intel_private.bridge_dev, 491d7cca2f7SDaniel Vetter I830_GMCH_CTRL, &gmch_ctrl); 492f51b7662SDaniel Vetter 4931a997ff2SDaniel Vetter if (INTEL_GTT_GEN > 4 || IS_PINEVIEW) 494fbe40783SDaniel Vetter overhead_entries = 0; 495fbe40783SDaniel Vetter else 496fbe40783SDaniel Vetter overhead_entries = intel_private.base.gtt_mappable_entries 497fbe40783SDaniel Vetter / 1024; 498f51b7662SDaniel Vetter 499fbe40783SDaniel Vetter overhead_entries += 1; /* BIOS popup */ 500d8d9abcdSDaniel Vetter 501d7cca2f7SDaniel Vetter if (intel_private.bridge_dev->device == PCI_DEVICE_ID_INTEL_82830_HB || 502d7cca2f7SDaniel Vetter intel_private.bridge_dev->device == PCI_DEVICE_ID_INTEL_82845G_HB) { 503f51b7662SDaniel Vetter switch (gmch_ctrl & I830_GMCH_GMS_MASK) { 504f51b7662SDaniel Vetter case I830_GMCH_GMS_STOLEN_512: 505d8d9abcdSDaniel Vetter stolen_size = KB(512); 506f51b7662SDaniel Vetter break; 507f51b7662SDaniel Vetter case I830_GMCH_GMS_STOLEN_1024: 508d8d9abcdSDaniel Vetter stolen_size = MB(1); 509f51b7662SDaniel Vetter break; 510f51b7662SDaniel Vetter case I830_GMCH_GMS_STOLEN_8192: 511d8d9abcdSDaniel Vetter stolen_size = MB(8); 512f51b7662SDaniel Vetter break; 513f51b7662SDaniel Vetter case I830_GMCH_GMS_LOCAL: 514f51b7662SDaniel Vetter rdct = readb(intel_private.registers+I830_RDRAM_CHANNEL_TYPE); 515d8d9abcdSDaniel Vetter stolen_size = (I830_RDRAM_ND(rdct) + 1) * 516f51b7662SDaniel Vetter MB(ddt[I830_RDRAM_DDT(rdct)]); 517f51b7662SDaniel Vetter local = 1; 518f51b7662SDaniel Vetter break; 519f51b7662SDaniel Vetter default: 520d8d9abcdSDaniel Vetter stolen_size = 0; 521f51b7662SDaniel Vetter break; 522f51b7662SDaniel Vetter } 5231a997ff2SDaniel Vetter } else if (INTEL_GTT_GEN == 6) { 524f51b7662SDaniel Vetter /* 525f51b7662SDaniel Vetter * SandyBridge has new memory control reg at 0x50.w 526f51b7662SDaniel Vetter */ 527f51b7662SDaniel Vetter u16 snb_gmch_ctl; 528f51b7662SDaniel Vetter pci_read_config_word(intel_private.pcidev, SNB_GMCH_CTRL, &snb_gmch_ctl); 529f51b7662SDaniel Vetter switch (snb_gmch_ctl & SNB_GMCH_GMS_STOLEN_MASK) { 530f51b7662SDaniel Vetter case SNB_GMCH_GMS_STOLEN_32M: 531d8d9abcdSDaniel Vetter stolen_size = MB(32); 532f51b7662SDaniel Vetter break; 533f51b7662SDaniel Vetter case SNB_GMCH_GMS_STOLEN_64M: 534d8d9abcdSDaniel Vetter stolen_size = MB(64); 535f51b7662SDaniel Vetter break; 536f51b7662SDaniel Vetter case SNB_GMCH_GMS_STOLEN_96M: 537d8d9abcdSDaniel Vetter stolen_size = MB(96); 538f51b7662SDaniel Vetter break; 539f51b7662SDaniel Vetter case SNB_GMCH_GMS_STOLEN_128M: 540d8d9abcdSDaniel Vetter stolen_size = MB(128); 541f51b7662SDaniel Vetter break; 542f51b7662SDaniel Vetter case SNB_GMCH_GMS_STOLEN_160M: 543d8d9abcdSDaniel Vetter stolen_size = MB(160); 544f51b7662SDaniel Vetter break; 545f51b7662SDaniel Vetter case SNB_GMCH_GMS_STOLEN_192M: 546d8d9abcdSDaniel Vetter stolen_size = MB(192); 547f51b7662SDaniel Vetter break; 548f51b7662SDaniel Vetter case SNB_GMCH_GMS_STOLEN_224M: 549d8d9abcdSDaniel Vetter stolen_size = MB(224); 550f51b7662SDaniel Vetter break; 551f51b7662SDaniel Vetter case SNB_GMCH_GMS_STOLEN_256M: 552d8d9abcdSDaniel Vetter stolen_size = MB(256); 553f51b7662SDaniel Vetter break; 554f51b7662SDaniel Vetter case SNB_GMCH_GMS_STOLEN_288M: 555d8d9abcdSDaniel Vetter stolen_size = MB(288); 556f51b7662SDaniel Vetter break; 557f51b7662SDaniel Vetter case SNB_GMCH_GMS_STOLEN_320M: 558d8d9abcdSDaniel Vetter stolen_size = MB(320); 559f51b7662SDaniel Vetter break; 560f51b7662SDaniel Vetter case SNB_GMCH_GMS_STOLEN_352M: 561d8d9abcdSDaniel Vetter stolen_size = MB(352); 562f51b7662SDaniel Vetter break; 563f51b7662SDaniel Vetter case SNB_GMCH_GMS_STOLEN_384M: 564d8d9abcdSDaniel Vetter stolen_size = MB(384); 565f51b7662SDaniel Vetter break; 566f51b7662SDaniel Vetter case SNB_GMCH_GMS_STOLEN_416M: 567d8d9abcdSDaniel Vetter stolen_size = MB(416); 568f51b7662SDaniel Vetter break; 569f51b7662SDaniel Vetter case SNB_GMCH_GMS_STOLEN_448M: 570d8d9abcdSDaniel Vetter stolen_size = MB(448); 571f51b7662SDaniel Vetter break; 572f51b7662SDaniel Vetter case SNB_GMCH_GMS_STOLEN_480M: 573d8d9abcdSDaniel Vetter stolen_size = MB(480); 574f51b7662SDaniel Vetter break; 575f51b7662SDaniel Vetter case SNB_GMCH_GMS_STOLEN_512M: 576d8d9abcdSDaniel Vetter stolen_size = MB(512); 577f51b7662SDaniel Vetter break; 578f51b7662SDaniel Vetter } 579f51b7662SDaniel Vetter } else { 580f51b7662SDaniel Vetter switch (gmch_ctrl & I855_GMCH_GMS_MASK) { 581f51b7662SDaniel Vetter case I855_GMCH_GMS_STOLEN_1M: 582d8d9abcdSDaniel Vetter stolen_size = MB(1); 583f51b7662SDaniel Vetter break; 584f51b7662SDaniel Vetter case I855_GMCH_GMS_STOLEN_4M: 585d8d9abcdSDaniel Vetter stolen_size = MB(4); 586f51b7662SDaniel Vetter break; 587f51b7662SDaniel Vetter case I855_GMCH_GMS_STOLEN_8M: 588d8d9abcdSDaniel Vetter stolen_size = MB(8); 589f51b7662SDaniel Vetter break; 590f51b7662SDaniel Vetter case I855_GMCH_GMS_STOLEN_16M: 591d8d9abcdSDaniel Vetter stolen_size = MB(16); 592f51b7662SDaniel Vetter break; 593f51b7662SDaniel Vetter case I855_GMCH_GMS_STOLEN_32M: 594d8d9abcdSDaniel Vetter stolen_size = MB(32); 595f51b7662SDaniel Vetter break; 596f51b7662SDaniel Vetter case I915_GMCH_GMS_STOLEN_48M: 597d8d9abcdSDaniel Vetter stolen_size = MB(48); 598f51b7662SDaniel Vetter break; 599f51b7662SDaniel Vetter case I915_GMCH_GMS_STOLEN_64M: 600d8d9abcdSDaniel Vetter stolen_size = MB(64); 601f51b7662SDaniel Vetter break; 602f51b7662SDaniel Vetter case G33_GMCH_GMS_STOLEN_128M: 603d8d9abcdSDaniel Vetter stolen_size = MB(128); 604f51b7662SDaniel Vetter break; 605f51b7662SDaniel Vetter case G33_GMCH_GMS_STOLEN_256M: 606d8d9abcdSDaniel Vetter stolen_size = MB(256); 607f51b7662SDaniel Vetter break; 608f51b7662SDaniel Vetter case INTEL_GMCH_GMS_STOLEN_96M: 609d8d9abcdSDaniel Vetter stolen_size = MB(96); 610f51b7662SDaniel Vetter break; 611f51b7662SDaniel Vetter case INTEL_GMCH_GMS_STOLEN_160M: 612d8d9abcdSDaniel Vetter stolen_size = MB(160); 613f51b7662SDaniel Vetter break; 614f51b7662SDaniel Vetter case INTEL_GMCH_GMS_STOLEN_224M: 615d8d9abcdSDaniel Vetter stolen_size = MB(224); 616f51b7662SDaniel Vetter break; 617f51b7662SDaniel Vetter case INTEL_GMCH_GMS_STOLEN_352M: 618d8d9abcdSDaniel Vetter stolen_size = MB(352); 619f51b7662SDaniel Vetter break; 620f51b7662SDaniel Vetter default: 621d8d9abcdSDaniel Vetter stolen_size = 0; 622f51b7662SDaniel Vetter break; 623f51b7662SDaniel Vetter } 624f51b7662SDaniel Vetter } 6251784a5fbSDaniel Vetter 626d8d9abcdSDaniel Vetter if (!local && stolen_size > intel_max_stolen) { 627d7cca2f7SDaniel Vetter dev_info(&intel_private.bridge_dev->dev, 628d1d6ca73SJesse Barnes "detected %dK stolen memory, trimming to %dK\n", 629d8d9abcdSDaniel Vetter stolen_size / KB(1), intel_max_stolen / KB(1)); 630d8d9abcdSDaniel Vetter stolen_size = intel_max_stolen; 631d8d9abcdSDaniel Vetter } else if (stolen_size > 0) { 632d7cca2f7SDaniel Vetter dev_info(&intel_private.bridge_dev->dev, "detected %dK %s memory\n", 633d8d9abcdSDaniel Vetter stolen_size / KB(1), local ? "local" : "stolen"); 634f51b7662SDaniel Vetter } else { 635d7cca2f7SDaniel Vetter dev_info(&intel_private.bridge_dev->dev, 636f51b7662SDaniel Vetter "no pre-allocated video memory detected\n"); 637d8d9abcdSDaniel Vetter stolen_size = 0; 638f51b7662SDaniel Vetter } 639f51b7662SDaniel Vetter 640d8d9abcdSDaniel Vetter stolen_entries = stolen_size/KB(4) - overhead_entries; 641d8d9abcdSDaniel Vetter 642d8d9abcdSDaniel Vetter return stolen_entries; 643f51b7662SDaniel Vetter } 644f51b7662SDaniel Vetter 64520172842SDaniel Vetter static void i965_adjust_pgetbl_size(unsigned int size_flag) 64620172842SDaniel Vetter { 64720172842SDaniel Vetter u32 pgetbl_ctl, pgetbl_ctl2; 64820172842SDaniel Vetter 64920172842SDaniel Vetter /* ensure that ppgtt is disabled */ 65020172842SDaniel Vetter pgetbl_ctl2 = readl(intel_private.registers+I965_PGETBL_CTL2); 65120172842SDaniel Vetter pgetbl_ctl2 &= ~I810_PGETBL_ENABLED; 65220172842SDaniel Vetter writel(pgetbl_ctl2, intel_private.registers+I965_PGETBL_CTL2); 65320172842SDaniel Vetter 65420172842SDaniel Vetter /* write the new ggtt size */ 65520172842SDaniel Vetter pgetbl_ctl = readl(intel_private.registers+I810_PGETBL_CTL); 65620172842SDaniel Vetter pgetbl_ctl &= ~I965_PGETBL_SIZE_MASK; 65720172842SDaniel Vetter pgetbl_ctl |= size_flag; 65820172842SDaniel Vetter writel(pgetbl_ctl, intel_private.registers+I810_PGETBL_CTL); 65920172842SDaniel Vetter } 66020172842SDaniel Vetter 66120172842SDaniel Vetter static unsigned int i965_gtt_total_entries(void) 662fbe40783SDaniel Vetter { 663fbe40783SDaniel Vetter int size; 664fbe40783SDaniel Vetter u32 pgetbl_ctl; 66520172842SDaniel Vetter u16 gmch_ctl; 66620172842SDaniel Vetter 66720172842SDaniel Vetter pci_read_config_word(intel_private.bridge_dev, 66820172842SDaniel Vetter I830_GMCH_CTRL, &gmch_ctl); 66920172842SDaniel Vetter 67020172842SDaniel Vetter if (INTEL_GTT_GEN == 5) { 67120172842SDaniel Vetter switch (gmch_ctl & G4x_GMCH_SIZE_MASK) { 67220172842SDaniel Vetter case G4x_GMCH_SIZE_1M: 67320172842SDaniel Vetter case G4x_GMCH_SIZE_VT_1M: 67420172842SDaniel Vetter i965_adjust_pgetbl_size(I965_PGETBL_SIZE_1MB); 67520172842SDaniel Vetter break; 67620172842SDaniel Vetter case G4x_GMCH_SIZE_VT_1_5M: 67720172842SDaniel Vetter i965_adjust_pgetbl_size(I965_PGETBL_SIZE_1_5MB); 67820172842SDaniel Vetter break; 67920172842SDaniel Vetter case G4x_GMCH_SIZE_2M: 68020172842SDaniel Vetter case G4x_GMCH_SIZE_VT_2M: 68120172842SDaniel Vetter i965_adjust_pgetbl_size(I965_PGETBL_SIZE_2MB); 68220172842SDaniel Vetter break; 68320172842SDaniel Vetter } 68420172842SDaniel Vetter } 68520172842SDaniel Vetter 686fbe40783SDaniel Vetter pgetbl_ctl = readl(intel_private.registers+I810_PGETBL_CTL); 687fbe40783SDaniel Vetter 688fbe40783SDaniel Vetter switch (pgetbl_ctl & I965_PGETBL_SIZE_MASK) { 689fbe40783SDaniel Vetter case I965_PGETBL_SIZE_128KB: 690e5e408fcSDaniel Vetter size = KB(128); 691fbe40783SDaniel Vetter break; 692fbe40783SDaniel Vetter case I965_PGETBL_SIZE_256KB: 693e5e408fcSDaniel Vetter size = KB(256); 694fbe40783SDaniel Vetter break; 695fbe40783SDaniel Vetter case I965_PGETBL_SIZE_512KB: 696e5e408fcSDaniel Vetter size = KB(512); 697fbe40783SDaniel Vetter break; 69820172842SDaniel Vetter /* GTT pagetable sizes bigger than 512KB are not possible on G33! */ 699fbe40783SDaniel Vetter case I965_PGETBL_SIZE_1MB: 700e5e408fcSDaniel Vetter size = KB(1024); 701fbe40783SDaniel Vetter break; 702fbe40783SDaniel Vetter case I965_PGETBL_SIZE_2MB: 703e5e408fcSDaniel Vetter size = KB(2048); 704fbe40783SDaniel Vetter break; 705fbe40783SDaniel Vetter case I965_PGETBL_SIZE_1_5MB: 706e5e408fcSDaniel Vetter size = KB(1024 + 512); 707fbe40783SDaniel Vetter break; 708fbe40783SDaniel Vetter default: 709fbe40783SDaniel Vetter dev_info(&intel_private.pcidev->dev, 710fbe40783SDaniel Vetter "unknown page table size, assuming 512KB\n"); 711e5e408fcSDaniel Vetter size = KB(512); 712fbe40783SDaniel Vetter } 713e5e408fcSDaniel Vetter 714e5e408fcSDaniel Vetter return size/4; 71520172842SDaniel Vetter } 71620172842SDaniel Vetter 71720172842SDaniel Vetter static unsigned int intel_gtt_total_entries(void) 71820172842SDaniel Vetter { 71920172842SDaniel Vetter int size; 72020172842SDaniel Vetter 72120172842SDaniel Vetter if (IS_G33 || INTEL_GTT_GEN == 4 || INTEL_GTT_GEN == 5) 72220172842SDaniel Vetter return i965_gtt_total_entries(); 72320172842SDaniel Vetter else if (INTEL_GTT_GEN == 6) { 724210b23c2SDaniel Vetter u16 snb_gmch_ctl; 725210b23c2SDaniel Vetter 726210b23c2SDaniel Vetter pci_read_config_word(intel_private.pcidev, SNB_GMCH_CTRL, &snb_gmch_ctl); 727210b23c2SDaniel Vetter switch (snb_gmch_ctl & SNB_GTT_SIZE_MASK) { 728210b23c2SDaniel Vetter default: 729210b23c2SDaniel Vetter case SNB_GTT_SIZE_0M: 730210b23c2SDaniel Vetter printk(KERN_ERR "Bad GTT size mask: 0x%04x.\n", snb_gmch_ctl); 731210b23c2SDaniel Vetter size = MB(0); 732210b23c2SDaniel Vetter break; 733210b23c2SDaniel Vetter case SNB_GTT_SIZE_1M: 734210b23c2SDaniel Vetter size = MB(1); 735210b23c2SDaniel Vetter break; 736210b23c2SDaniel Vetter case SNB_GTT_SIZE_2M: 737210b23c2SDaniel Vetter size = MB(2); 738210b23c2SDaniel Vetter break; 739210b23c2SDaniel Vetter } 740210b23c2SDaniel Vetter return size/4; 741fbe40783SDaniel Vetter } else { 742fbe40783SDaniel Vetter /* On previous hardware, the GTT size was just what was 743fbe40783SDaniel Vetter * required to map the aperture. 744fbe40783SDaniel Vetter */ 745e5e408fcSDaniel Vetter return intel_private.base.gtt_mappable_entries; 746fbe40783SDaniel Vetter } 747fbe40783SDaniel Vetter } 748fbe40783SDaniel Vetter 7491784a5fbSDaniel Vetter static unsigned int intel_gtt_mappable_entries(void) 7501784a5fbSDaniel Vetter { 7511784a5fbSDaniel Vetter unsigned int aperture_size; 7521784a5fbSDaniel Vetter 753b1c5b0f8SChris Wilson if (INTEL_GTT_GEN == 2) { 754b1c5b0f8SChris Wilson u16 gmch_ctrl; 7551784a5fbSDaniel Vetter 7561784a5fbSDaniel Vetter pci_read_config_word(intel_private.bridge_dev, 7571784a5fbSDaniel Vetter I830_GMCH_CTRL, &gmch_ctrl); 7581784a5fbSDaniel Vetter 7591784a5fbSDaniel Vetter if ((gmch_ctrl & I830_GMCH_MEM_MASK) == I830_GMCH_MEM_64M) 760b1c5b0f8SChris Wilson aperture_size = MB(64); 7611784a5fbSDaniel Vetter else 762b1c5b0f8SChris Wilson aperture_size = MB(128); 763239918f7SDaniel Vetter } else { 7641784a5fbSDaniel Vetter /* 9xx supports large sizes, just look at the length */ 7651784a5fbSDaniel Vetter aperture_size = pci_resource_len(intel_private.pcidev, 2); 7661784a5fbSDaniel Vetter } 7671784a5fbSDaniel Vetter 7681784a5fbSDaniel Vetter return aperture_size >> PAGE_SHIFT; 7691784a5fbSDaniel Vetter } 7701784a5fbSDaniel Vetter 7710e87d2b0SDaniel Vetter static void intel_gtt_teardown_scratch_page(void) 7720e87d2b0SDaniel Vetter { 7730e87d2b0SDaniel Vetter set_pages_wb(intel_private.scratch_page, 1); 7740e87d2b0SDaniel Vetter pci_unmap_page(intel_private.pcidev, intel_private.scratch_page_dma, 7750e87d2b0SDaniel Vetter PAGE_SIZE, PCI_DMA_BIDIRECTIONAL); 7760e87d2b0SDaniel Vetter put_page(intel_private.scratch_page); 7770e87d2b0SDaniel Vetter __free_page(intel_private.scratch_page); 7780e87d2b0SDaniel Vetter } 7790e87d2b0SDaniel Vetter 7800e87d2b0SDaniel Vetter static void intel_gtt_cleanup(void) 7810e87d2b0SDaniel Vetter { 782ae83dd5cSDaniel Vetter intel_private.driver->cleanup(); 783ae83dd5cSDaniel Vetter 7840e87d2b0SDaniel Vetter iounmap(intel_private.gtt); 7850e87d2b0SDaniel Vetter iounmap(intel_private.registers); 7860e87d2b0SDaniel Vetter 7870e87d2b0SDaniel Vetter intel_gtt_teardown_scratch_page(); 7880e87d2b0SDaniel Vetter } 7890e87d2b0SDaniel Vetter 7901784a5fbSDaniel Vetter static int intel_gtt_init(void) 7911784a5fbSDaniel Vetter { 792f67eab66SDaniel Vetter u32 gtt_map_size; 7933b15a9d7SDaniel Vetter int ret; 7943b15a9d7SDaniel Vetter 7953b15a9d7SDaniel Vetter ret = intel_private.driver->setup(); 7963b15a9d7SDaniel Vetter if (ret != 0) 7973b15a9d7SDaniel Vetter return ret; 798f67eab66SDaniel Vetter 799f67eab66SDaniel Vetter intel_private.base.gtt_mappable_entries = intel_gtt_mappable_entries(); 800f67eab66SDaniel Vetter intel_private.base.gtt_total_entries = intel_gtt_total_entries(); 801f67eab66SDaniel Vetter 802b3eafc5aSDaniel Vetter /* save the PGETBL reg for resume */ 803b3eafc5aSDaniel Vetter intel_private.PGETBL_save = 804b3eafc5aSDaniel Vetter readl(intel_private.registers+I810_PGETBL_CTL) 805b3eafc5aSDaniel Vetter & ~I810_PGETBL_ENABLED; 806b3eafc5aSDaniel Vetter 8070af9e92eSDaniel Vetter dev_info(&intel_private.bridge_dev->dev, 8080af9e92eSDaniel Vetter "detected gtt size: %dK total, %dK mappable\n", 8090af9e92eSDaniel Vetter intel_private.base.gtt_total_entries * 4, 8100af9e92eSDaniel Vetter intel_private.base.gtt_mappable_entries * 4); 8110af9e92eSDaniel Vetter 812f67eab66SDaniel Vetter gtt_map_size = intel_private.base.gtt_total_entries * 4; 813f67eab66SDaniel Vetter 814f67eab66SDaniel Vetter intel_private.gtt = ioremap(intel_private.gtt_bus_addr, 815f67eab66SDaniel Vetter gtt_map_size); 816f67eab66SDaniel Vetter if (!intel_private.gtt) { 817ae83dd5cSDaniel Vetter intel_private.driver->cleanup(); 818f67eab66SDaniel Vetter iounmap(intel_private.registers); 819f67eab66SDaniel Vetter return -ENOMEM; 820f67eab66SDaniel Vetter } 821f67eab66SDaniel Vetter 822f67eab66SDaniel Vetter global_cache_flush(); /* FIXME: ? */ 823f67eab66SDaniel Vetter 8241784a5fbSDaniel Vetter /* we have to call this as early as possible after the MMIO base address is known */ 8251784a5fbSDaniel Vetter intel_private.base.gtt_stolen_entries = intel_gtt_stolen_entries(); 8261784a5fbSDaniel Vetter if (intel_private.base.gtt_stolen_entries == 0) { 827ae83dd5cSDaniel Vetter intel_private.driver->cleanup(); 8281784a5fbSDaniel Vetter iounmap(intel_private.registers); 829f67eab66SDaniel Vetter iounmap(intel_private.gtt); 8301784a5fbSDaniel Vetter return -ENOMEM; 8311784a5fbSDaniel Vetter } 8321784a5fbSDaniel Vetter 8330e87d2b0SDaniel Vetter ret = intel_gtt_setup_scratch_page(); 8340e87d2b0SDaniel Vetter if (ret != 0) { 8350e87d2b0SDaniel Vetter intel_gtt_cleanup(); 8360e87d2b0SDaniel Vetter return ret; 8370e87d2b0SDaniel Vetter } 8380e87d2b0SDaniel Vetter 8391784a5fbSDaniel Vetter return 0; 8401784a5fbSDaniel Vetter } 8411784a5fbSDaniel Vetter 8423e921f98SDaniel Vetter static int intel_fake_agp_fetch_size(void) 8433e921f98SDaniel Vetter { 8449e76e7b8SChris Wilson int num_sizes = ARRAY_SIZE(intel_fake_agp_sizes); 8453e921f98SDaniel Vetter unsigned int aper_size; 8463e921f98SDaniel Vetter int i; 8473e921f98SDaniel Vetter 8483e921f98SDaniel Vetter aper_size = (intel_private.base.gtt_mappable_entries << PAGE_SHIFT) 8493e921f98SDaniel Vetter / MB(1); 8503e921f98SDaniel Vetter 8513e921f98SDaniel Vetter for (i = 0; i < num_sizes; i++) { 852ffdd7510SDaniel Vetter if (aper_size == intel_fake_agp_sizes[i].size) { 8539e76e7b8SChris Wilson agp_bridge->current_size = 8549e76e7b8SChris Wilson (void *) (intel_fake_agp_sizes + i); 8553e921f98SDaniel Vetter return aper_size; 8563e921f98SDaniel Vetter } 8573e921f98SDaniel Vetter } 8583e921f98SDaniel Vetter 8593e921f98SDaniel Vetter return 0; 8603e921f98SDaniel Vetter } 8613e921f98SDaniel Vetter 862ae83dd5cSDaniel Vetter static void i830_cleanup(void) 863f51b7662SDaniel Vetter { 864f51b7662SDaniel Vetter kunmap(intel_private.i8xx_page); 865f51b7662SDaniel Vetter intel_private.i8xx_flush_page = NULL; 866f51b7662SDaniel Vetter 867f51b7662SDaniel Vetter __free_page(intel_private.i8xx_page); 868f51b7662SDaniel Vetter intel_private.i8xx_page = NULL; 869f51b7662SDaniel Vetter } 870f51b7662SDaniel Vetter 871f51b7662SDaniel Vetter static void intel_i830_setup_flush(void) 872f51b7662SDaniel Vetter { 873f51b7662SDaniel Vetter /* return if we've already set the flush mechanism up */ 874f51b7662SDaniel Vetter if (intel_private.i8xx_page) 875f51b7662SDaniel Vetter return; 876f51b7662SDaniel Vetter 877e61cb0d5SJan Beulich intel_private.i8xx_page = alloc_page(GFP_KERNEL); 878f51b7662SDaniel Vetter if (!intel_private.i8xx_page) 879f51b7662SDaniel Vetter return; 880f51b7662SDaniel Vetter 881f51b7662SDaniel Vetter intel_private.i8xx_flush_page = kmap(intel_private.i8xx_page); 882f51b7662SDaniel Vetter if (!intel_private.i8xx_flush_page) 883ae83dd5cSDaniel Vetter i830_cleanup(); 884f51b7662SDaniel Vetter } 885f51b7662SDaniel Vetter 886f51b7662SDaniel Vetter /* The chipset_flush interface needs to get data that has already been 887f51b7662SDaniel Vetter * flushed out of the CPU all the way out to main memory, because the GPU 888f51b7662SDaniel Vetter * doesn't snoop those buffers. 889f51b7662SDaniel Vetter * 890f51b7662SDaniel Vetter * The 8xx series doesn't have the same lovely interface for flushing the 891f51b7662SDaniel Vetter * chipset write buffers that the later chips do. According to the 865 892f51b7662SDaniel Vetter * specs, it's 64 octwords, or 1KB. So, to get those previous things in 893f51b7662SDaniel Vetter * that buffer out, we just fill 1KB and clflush it out, on the assumption 894f51b7662SDaniel Vetter * that it'll push whatever was in there out. It appears to work. 895f51b7662SDaniel Vetter */ 8961b263f24SDaniel Vetter static void i830_chipset_flush(void) 897f51b7662SDaniel Vetter { 898f51b7662SDaniel Vetter unsigned int *pg = intel_private.i8xx_flush_page; 899f51b7662SDaniel Vetter 900f51b7662SDaniel Vetter memset(pg, 0, 1024); 901f51b7662SDaniel Vetter 902f51b7662SDaniel Vetter if (cpu_has_clflush) 903f51b7662SDaniel Vetter clflush_cache_range(pg, 1024); 904f51b7662SDaniel Vetter else if (wbinvd_on_all_cpus() != 0) 905f51b7662SDaniel Vetter printk(KERN_ERR "Timed out waiting for cache flush.\n"); 906f51b7662SDaniel Vetter } 907f51b7662SDaniel Vetter 908351bb278SDaniel Vetter static void i830_write_entry(dma_addr_t addr, unsigned int entry, 909351bb278SDaniel Vetter unsigned int flags) 910351bb278SDaniel Vetter { 911351bb278SDaniel Vetter u32 pte_flags = I810_PTE_VALID; 912351bb278SDaniel Vetter 913351bb278SDaniel Vetter switch (flags) { 914351bb278SDaniel Vetter case AGP_DCACHE_MEMORY: 915351bb278SDaniel Vetter pte_flags |= I810_PTE_LOCAL; 916351bb278SDaniel Vetter break; 917351bb278SDaniel Vetter case AGP_USER_CACHED_MEMORY: 918351bb278SDaniel Vetter pte_flags |= I830_PTE_SYSTEM_CACHED; 919351bb278SDaniel Vetter break; 920351bb278SDaniel Vetter } 921351bb278SDaniel Vetter 922351bb278SDaniel Vetter writel(addr | pte_flags, intel_private.gtt + entry); 923351bb278SDaniel Vetter } 924351bb278SDaniel Vetter 925e380f60bSChris Wilson static bool intel_enable_gtt(void) 92673800422SDaniel Vetter { 9273f08e4efSChris Wilson u32 gma_addr; 92873800422SDaniel Vetter u16 gmch_ctrl; 929e380f60bSChris Wilson u8 __iomem *reg; 93073800422SDaniel Vetter 9312d2430cfSDaniel Vetter if (INTEL_GTT_GEN == 2) 9322d2430cfSDaniel Vetter pci_read_config_dword(intel_private.pcidev, I810_GMADDR, 9332d2430cfSDaniel Vetter &gma_addr); 9342d2430cfSDaniel Vetter else 9352d2430cfSDaniel Vetter pci_read_config_dword(intel_private.pcidev, I915_GMADDR, 9362d2430cfSDaniel Vetter &gma_addr); 9372d2430cfSDaniel Vetter 93873800422SDaniel Vetter intel_private.gma_bus_addr = (gma_addr & PCI_BASE_ADDRESS_MEM_MASK); 93973800422SDaniel Vetter 940e380f60bSChris Wilson if (INTEL_GTT_GEN >= 6) 941e380f60bSChris Wilson return true; 94273800422SDaniel Vetter 943e380f60bSChris Wilson pci_read_config_word(intel_private.bridge_dev, 944e380f60bSChris Wilson I830_GMCH_CTRL, &gmch_ctrl); 945e380f60bSChris Wilson gmch_ctrl |= I830_GMCH_ENABLED; 946e380f60bSChris Wilson pci_write_config_word(intel_private.bridge_dev, 947e380f60bSChris Wilson I830_GMCH_CTRL, gmch_ctrl); 948e380f60bSChris Wilson 949e380f60bSChris Wilson pci_read_config_word(intel_private.bridge_dev, 950e380f60bSChris Wilson I830_GMCH_CTRL, &gmch_ctrl); 951e380f60bSChris Wilson if ((gmch_ctrl & I830_GMCH_ENABLED) == 0) { 952e380f60bSChris Wilson dev_err(&intel_private.pcidev->dev, 953e380f60bSChris Wilson "failed to enable the GTT: GMCH_CTRL=%x\n", 954e380f60bSChris Wilson gmch_ctrl); 955e380f60bSChris Wilson return false; 956e380f60bSChris Wilson } 957e380f60bSChris Wilson 958e380f60bSChris Wilson reg = intel_private.registers+I810_PGETBL_CTL; 959e380f60bSChris Wilson writel(intel_private.PGETBL_save|I810_PGETBL_ENABLED, reg); 960e380f60bSChris Wilson if ((readl(reg) & I810_PGETBL_ENABLED) == 0) { 961e380f60bSChris Wilson dev_err(&intel_private.pcidev->dev, 962e380f60bSChris Wilson "failed to enable the GTT: PGETBL=%x [expected %x|1]\n", 963e380f60bSChris Wilson readl(reg), intel_private.PGETBL_save); 964e380f60bSChris Wilson return false; 965e380f60bSChris Wilson } 966e380f60bSChris Wilson 967e380f60bSChris Wilson return true; 96873800422SDaniel Vetter } 96973800422SDaniel Vetter 97073800422SDaniel Vetter static int i830_setup(void) 97173800422SDaniel Vetter { 97273800422SDaniel Vetter u32 reg_addr; 97373800422SDaniel Vetter 97473800422SDaniel Vetter pci_read_config_dword(intel_private.pcidev, I810_MMADDR, ®_addr); 97573800422SDaniel Vetter reg_addr &= 0xfff80000; 97673800422SDaniel Vetter 97773800422SDaniel Vetter intel_private.registers = ioremap(reg_addr, KB(64)); 97873800422SDaniel Vetter if (!intel_private.registers) 97973800422SDaniel Vetter return -ENOMEM; 98073800422SDaniel Vetter 98173800422SDaniel Vetter intel_private.gtt_bus_addr = reg_addr + I810_PTE_BASE; 98273800422SDaniel Vetter 98373800422SDaniel Vetter intel_i830_setup_flush(); 98473800422SDaniel Vetter 98573800422SDaniel Vetter return 0; 98673800422SDaniel Vetter } 98773800422SDaniel Vetter 9883b15a9d7SDaniel Vetter static int intel_fake_agp_create_gatt_table(struct agp_bridge_data *bridge) 989f51b7662SDaniel Vetter { 99073800422SDaniel Vetter agp_bridge->gatt_table_real = NULL; 991f51b7662SDaniel Vetter agp_bridge->gatt_table = NULL; 99273800422SDaniel Vetter agp_bridge->gatt_bus_addr = 0; 993f51b7662SDaniel Vetter 994f51b7662SDaniel Vetter return 0; 995f51b7662SDaniel Vetter } 996f51b7662SDaniel Vetter 997ffdd7510SDaniel Vetter static int intel_fake_agp_free_gatt_table(struct agp_bridge_data *bridge) 998f51b7662SDaniel Vetter { 999f51b7662SDaniel Vetter return 0; 1000f51b7662SDaniel Vetter } 1001f51b7662SDaniel Vetter 1002351bb278SDaniel Vetter static int intel_fake_agp_configure(void) 1003f51b7662SDaniel Vetter { 1004f51b7662SDaniel Vetter int i; 1005f51b7662SDaniel Vetter 1006e380f60bSChris Wilson if (!intel_enable_gtt()) 1007e380f60bSChris Wilson return -EIO; 1008f51b7662SDaniel Vetter 100973800422SDaniel Vetter agp_bridge->gart_bus_addr = intel_private.gma_bus_addr; 1010f51b7662SDaniel Vetter 101173800422SDaniel Vetter for (i = intel_private.base.gtt_stolen_entries; 101273800422SDaniel Vetter i < intel_private.base.gtt_total_entries; i++) { 1013351bb278SDaniel Vetter intel_private.driver->write_entry(intel_private.scratch_page_dma, 1014351bb278SDaniel Vetter i, 0); 1015f51b7662SDaniel Vetter } 1016fdfb58a9SDaniel Vetter readl(intel_private.gtt+i-1); /* PCI Posting. */ 1017f51b7662SDaniel Vetter 1018f51b7662SDaniel Vetter global_cache_flush(); 1019f51b7662SDaniel Vetter 1020f51b7662SDaniel Vetter return 0; 1021f51b7662SDaniel Vetter } 1022f51b7662SDaniel Vetter 10235cbecafcSDaniel Vetter static bool i830_check_flags(unsigned int flags) 1024f51b7662SDaniel Vetter { 10255cbecafcSDaniel Vetter switch (flags) { 10265cbecafcSDaniel Vetter case 0: 10275cbecafcSDaniel Vetter case AGP_PHYS_MEMORY: 10285cbecafcSDaniel Vetter case AGP_USER_CACHED_MEMORY: 10295cbecafcSDaniel Vetter case AGP_USER_MEMORY: 10305cbecafcSDaniel Vetter return true; 10315cbecafcSDaniel Vetter } 10325cbecafcSDaniel Vetter 10335cbecafcSDaniel Vetter return false; 10345cbecafcSDaniel Vetter } 10355cbecafcSDaniel Vetter 1036fefaa70fSDaniel Vetter static void intel_gtt_insert_sg_entries(struct scatterlist *sg_list, 1037fefaa70fSDaniel Vetter unsigned int sg_len, 1038fefaa70fSDaniel Vetter unsigned int pg_start, 1039fefaa70fSDaniel Vetter unsigned int flags) 1040fefaa70fSDaniel Vetter { 1041fefaa70fSDaniel Vetter struct scatterlist *sg; 1042fefaa70fSDaniel Vetter unsigned int len, m; 1043fefaa70fSDaniel Vetter int i, j; 1044fefaa70fSDaniel Vetter 1045fefaa70fSDaniel Vetter j = pg_start; 1046fefaa70fSDaniel Vetter 1047fefaa70fSDaniel Vetter /* sg may merge pages, but we have to separate 1048fefaa70fSDaniel Vetter * per-page addr for GTT */ 1049fefaa70fSDaniel Vetter for_each_sg(sg_list, sg, sg_len, i) { 1050fefaa70fSDaniel Vetter len = sg_dma_len(sg) >> PAGE_SHIFT; 1051fefaa70fSDaniel Vetter for (m = 0; m < len; m++) { 1052fefaa70fSDaniel Vetter dma_addr_t addr = sg_dma_address(sg) + (m << PAGE_SHIFT); 1053fefaa70fSDaniel Vetter intel_private.driver->write_entry(addr, 1054fefaa70fSDaniel Vetter j, flags); 1055fefaa70fSDaniel Vetter j++; 1056fefaa70fSDaniel Vetter } 1057fefaa70fSDaniel Vetter } 1058fefaa70fSDaniel Vetter readl(intel_private.gtt+j-1); 1059fefaa70fSDaniel Vetter } 1060fefaa70fSDaniel Vetter 10615cbecafcSDaniel Vetter static int intel_fake_agp_insert_entries(struct agp_memory *mem, 10625cbecafcSDaniel Vetter off_t pg_start, int type) 10635cbecafcSDaniel Vetter { 10645cbecafcSDaniel Vetter int i, j; 1065f51b7662SDaniel Vetter int ret = -EINVAL; 1066f51b7662SDaniel Vetter 1067f51b7662SDaniel Vetter if (mem->page_count == 0) 1068f51b7662SDaniel Vetter goto out; 1069f51b7662SDaniel Vetter 10700ade6386SDaniel Vetter if (pg_start < intel_private.base.gtt_stolen_entries) { 1071f51b7662SDaniel Vetter dev_printk(KERN_DEBUG, &intel_private.pcidev->dev, 10720ade6386SDaniel Vetter "pg_start == 0x%.8lx, gtt_stolen_entries == 0x%.8x\n", 10730ade6386SDaniel Vetter pg_start, intel_private.base.gtt_stolen_entries); 1074f51b7662SDaniel Vetter 1075f51b7662SDaniel Vetter dev_info(&intel_private.pcidev->dev, 1076f51b7662SDaniel Vetter "trying to insert into local/stolen memory\n"); 1077f51b7662SDaniel Vetter goto out_err; 1078f51b7662SDaniel Vetter } 1079f51b7662SDaniel Vetter 10805cbecafcSDaniel Vetter if ((pg_start + mem->page_count) > intel_private.base.gtt_total_entries) 1081f51b7662SDaniel Vetter goto out_err; 1082f51b7662SDaniel Vetter 1083f51b7662SDaniel Vetter if (type != mem->type) 1084f51b7662SDaniel Vetter goto out_err; 1085f51b7662SDaniel Vetter 10865cbecafcSDaniel Vetter if (!intel_private.driver->check_flags(type)) 1087f51b7662SDaniel Vetter goto out_err; 1088f51b7662SDaniel Vetter 1089f51b7662SDaniel Vetter if (!mem->is_flushed) 1090f51b7662SDaniel Vetter global_cache_flush(); 1091f51b7662SDaniel Vetter 1092fefaa70fSDaniel Vetter if (USE_PCI_DMA_API && INTEL_GTT_GEN > 2) { 1093fefaa70fSDaniel Vetter ret = intel_agp_map_memory(mem); 1094fefaa70fSDaniel Vetter if (ret != 0) 1095fefaa70fSDaniel Vetter return ret; 1096fefaa70fSDaniel Vetter 1097fefaa70fSDaniel Vetter intel_gtt_insert_sg_entries(mem->sg_list, mem->num_sg, 1098fefaa70fSDaniel Vetter pg_start, type); 1099fefaa70fSDaniel Vetter } else { 1100f51b7662SDaniel Vetter for (i = 0, j = pg_start; i < mem->page_count; i++, j++) { 1101fefaa70fSDaniel Vetter dma_addr_t addr = page_to_phys(mem->pages[i]); 1102fefaa70fSDaniel Vetter intel_private.driver->write_entry(addr, 11035cbecafcSDaniel Vetter j, type); 1104f51b7662SDaniel Vetter } 1105fdfb58a9SDaniel Vetter readl(intel_private.gtt+j-1); 1106fefaa70fSDaniel Vetter } 1107f51b7662SDaniel Vetter 1108f51b7662SDaniel Vetter out: 1109f51b7662SDaniel Vetter ret = 0; 1110f51b7662SDaniel Vetter out_err: 1111f51b7662SDaniel Vetter mem->is_flushed = true; 1112f51b7662SDaniel Vetter return ret; 1113f51b7662SDaniel Vetter } 1114f51b7662SDaniel Vetter 11155cbecafcSDaniel Vetter static int intel_fake_agp_remove_entries(struct agp_memory *mem, 11165cbecafcSDaniel Vetter off_t pg_start, int type) 1117f51b7662SDaniel Vetter { 1118f51b7662SDaniel Vetter int i; 1119f51b7662SDaniel Vetter 1120f51b7662SDaniel Vetter if (mem->page_count == 0) 1121f51b7662SDaniel Vetter return 0; 1122f51b7662SDaniel Vetter 11230ade6386SDaniel Vetter if (pg_start < intel_private.base.gtt_stolen_entries) { 1124f51b7662SDaniel Vetter dev_info(&intel_private.pcidev->dev, 1125f51b7662SDaniel Vetter "trying to disable local/stolen memory\n"); 1126f51b7662SDaniel Vetter return -EINVAL; 1127f51b7662SDaniel Vetter } 1128f51b7662SDaniel Vetter 1129fefaa70fSDaniel Vetter if (USE_PCI_DMA_API && INTEL_GTT_GEN > 2) 1130fefaa70fSDaniel Vetter intel_agp_unmap_memory(mem); 1131fefaa70fSDaniel Vetter 1132f51b7662SDaniel Vetter for (i = pg_start; i < (mem->page_count + pg_start); i++) { 11335cbecafcSDaniel Vetter intel_private.driver->write_entry(intel_private.scratch_page_dma, 11345cbecafcSDaniel Vetter i, 0); 1135f51b7662SDaniel Vetter } 1136fdfb58a9SDaniel Vetter readl(intel_private.gtt+i-1); 1137f51b7662SDaniel Vetter 1138f51b7662SDaniel Vetter return 0; 1139f51b7662SDaniel Vetter } 1140f51b7662SDaniel Vetter 11411b263f24SDaniel Vetter static void intel_fake_agp_chipset_flush(struct agp_bridge_data *bridge) 11421b263f24SDaniel Vetter { 11431b263f24SDaniel Vetter intel_private.driver->chipset_flush(); 11441b263f24SDaniel Vetter } 11451b263f24SDaniel Vetter 1146ffdd7510SDaniel Vetter static struct agp_memory *intel_fake_agp_alloc_by_type(size_t pg_count, 1147ffdd7510SDaniel Vetter int type) 1148f51b7662SDaniel Vetter { 1149f51b7662SDaniel Vetter if (type == AGP_PHYS_MEMORY) 1150f51b7662SDaniel Vetter return alloc_agpphysmem_i8xx(pg_count, type); 1151f51b7662SDaniel Vetter /* always return NULL for other allocation types for now */ 1152f51b7662SDaniel Vetter return NULL; 1153f51b7662SDaniel Vetter } 1154f51b7662SDaniel Vetter 1155f51b7662SDaniel Vetter static int intel_alloc_chipset_flush_resource(void) 1156f51b7662SDaniel Vetter { 1157f51b7662SDaniel Vetter int ret; 1158d7cca2f7SDaniel Vetter ret = pci_bus_alloc_resource(intel_private.bridge_dev->bus, &intel_private.ifp_resource, PAGE_SIZE, 1159f51b7662SDaniel Vetter PAGE_SIZE, PCIBIOS_MIN_MEM, 0, 1160d7cca2f7SDaniel Vetter pcibios_align_resource, intel_private.bridge_dev); 1161f51b7662SDaniel Vetter 1162f51b7662SDaniel Vetter return ret; 1163f51b7662SDaniel Vetter } 1164f51b7662SDaniel Vetter 1165f51b7662SDaniel Vetter static void intel_i915_setup_chipset_flush(void) 1166f51b7662SDaniel Vetter { 1167f51b7662SDaniel Vetter int ret; 1168f51b7662SDaniel Vetter u32 temp; 1169f51b7662SDaniel Vetter 1170d7cca2f7SDaniel Vetter pci_read_config_dword(intel_private.bridge_dev, I915_IFPADDR, &temp); 1171f51b7662SDaniel Vetter if (!(temp & 0x1)) { 1172f51b7662SDaniel Vetter intel_alloc_chipset_flush_resource(); 1173f51b7662SDaniel Vetter intel_private.resource_valid = 1; 1174d7cca2f7SDaniel Vetter pci_write_config_dword(intel_private.bridge_dev, I915_IFPADDR, (intel_private.ifp_resource.start & 0xffffffff) | 0x1); 1175f51b7662SDaniel Vetter } else { 1176f51b7662SDaniel Vetter temp &= ~1; 1177f51b7662SDaniel Vetter 1178f51b7662SDaniel Vetter intel_private.resource_valid = 1; 1179f51b7662SDaniel Vetter intel_private.ifp_resource.start = temp; 1180f51b7662SDaniel Vetter intel_private.ifp_resource.end = temp + PAGE_SIZE; 1181f51b7662SDaniel Vetter ret = request_resource(&iomem_resource, &intel_private.ifp_resource); 1182f51b7662SDaniel Vetter /* some BIOSes reserve this area in a pnp some don't */ 1183f51b7662SDaniel Vetter if (ret) 1184f51b7662SDaniel Vetter intel_private.resource_valid = 0; 1185f51b7662SDaniel Vetter } 1186f51b7662SDaniel Vetter } 1187f51b7662SDaniel Vetter 1188f51b7662SDaniel Vetter static void intel_i965_g33_setup_chipset_flush(void) 1189f51b7662SDaniel Vetter { 1190f51b7662SDaniel Vetter u32 temp_hi, temp_lo; 1191f51b7662SDaniel Vetter int ret; 1192f51b7662SDaniel Vetter 1193d7cca2f7SDaniel Vetter pci_read_config_dword(intel_private.bridge_dev, I965_IFPADDR + 4, &temp_hi); 1194d7cca2f7SDaniel Vetter pci_read_config_dword(intel_private.bridge_dev, I965_IFPADDR, &temp_lo); 1195f51b7662SDaniel Vetter 1196f51b7662SDaniel Vetter if (!(temp_lo & 0x1)) { 1197f51b7662SDaniel Vetter 1198f51b7662SDaniel Vetter intel_alloc_chipset_flush_resource(); 1199f51b7662SDaniel Vetter 1200f51b7662SDaniel Vetter intel_private.resource_valid = 1; 1201d7cca2f7SDaniel Vetter pci_write_config_dword(intel_private.bridge_dev, I965_IFPADDR + 4, 1202f51b7662SDaniel Vetter upper_32_bits(intel_private.ifp_resource.start)); 1203d7cca2f7SDaniel Vetter pci_write_config_dword(intel_private.bridge_dev, I965_IFPADDR, (intel_private.ifp_resource.start & 0xffffffff) | 0x1); 1204f51b7662SDaniel Vetter } else { 1205f51b7662SDaniel Vetter u64 l64; 1206f51b7662SDaniel Vetter 1207f51b7662SDaniel Vetter temp_lo &= ~0x1; 1208f51b7662SDaniel Vetter l64 = ((u64)temp_hi << 32) | temp_lo; 1209f51b7662SDaniel Vetter 1210f51b7662SDaniel Vetter intel_private.resource_valid = 1; 1211f51b7662SDaniel Vetter intel_private.ifp_resource.start = l64; 1212f51b7662SDaniel Vetter intel_private.ifp_resource.end = l64 + PAGE_SIZE; 1213f51b7662SDaniel Vetter ret = request_resource(&iomem_resource, &intel_private.ifp_resource); 1214f51b7662SDaniel Vetter /* some BIOSes reserve this area in a pnp some don't */ 1215f51b7662SDaniel Vetter if (ret) 1216f51b7662SDaniel Vetter intel_private.resource_valid = 0; 1217f51b7662SDaniel Vetter } 1218f51b7662SDaniel Vetter } 1219f51b7662SDaniel Vetter 1220f51b7662SDaniel Vetter static void intel_i9xx_setup_flush(void) 1221f51b7662SDaniel Vetter { 1222f51b7662SDaniel Vetter /* return if already configured */ 1223f51b7662SDaniel Vetter if (intel_private.ifp_resource.start) 1224f51b7662SDaniel Vetter return; 1225f51b7662SDaniel Vetter 12261a997ff2SDaniel Vetter if (INTEL_GTT_GEN == 6) 1227f51b7662SDaniel Vetter return; 1228f51b7662SDaniel Vetter 1229f51b7662SDaniel Vetter /* setup a resource for this object */ 1230f51b7662SDaniel Vetter intel_private.ifp_resource.name = "Intel Flush Page"; 1231f51b7662SDaniel Vetter intel_private.ifp_resource.flags = IORESOURCE_MEM; 1232f51b7662SDaniel Vetter 1233f51b7662SDaniel Vetter /* Setup chipset flush for 915 */ 12341a997ff2SDaniel Vetter if (IS_G33 || INTEL_GTT_GEN >= 4) { 1235f51b7662SDaniel Vetter intel_i965_g33_setup_chipset_flush(); 1236f51b7662SDaniel Vetter } else { 1237f51b7662SDaniel Vetter intel_i915_setup_chipset_flush(); 1238f51b7662SDaniel Vetter } 1239f51b7662SDaniel Vetter 1240df51e7aaSChris Wilson if (intel_private.ifp_resource.start) 1241f51b7662SDaniel Vetter intel_private.i9xx_flush_page = ioremap_nocache(intel_private.ifp_resource.start, PAGE_SIZE); 1242f51b7662SDaniel Vetter if (!intel_private.i9xx_flush_page) 1243df51e7aaSChris Wilson dev_err(&intel_private.pcidev->dev, 1244df51e7aaSChris Wilson "can't ioremap flush page - no chipset flushing\n"); 1245f51b7662SDaniel Vetter } 1246f51b7662SDaniel Vetter 1247ae83dd5cSDaniel Vetter static void i9xx_cleanup(void) 1248ae83dd5cSDaniel Vetter { 1249ae83dd5cSDaniel Vetter if (intel_private.i9xx_flush_page) 1250ae83dd5cSDaniel Vetter iounmap(intel_private.i9xx_flush_page); 1251ae83dd5cSDaniel Vetter if (intel_private.resource_valid) 1252ae83dd5cSDaniel Vetter release_resource(&intel_private.ifp_resource); 1253ae83dd5cSDaniel Vetter intel_private.ifp_resource.start = 0; 1254ae83dd5cSDaniel Vetter intel_private.resource_valid = 0; 1255ae83dd5cSDaniel Vetter } 1256ae83dd5cSDaniel Vetter 12571b263f24SDaniel Vetter static void i9xx_chipset_flush(void) 1258f51b7662SDaniel Vetter { 1259f51b7662SDaniel Vetter if (intel_private.i9xx_flush_page) 1260f51b7662SDaniel Vetter writel(1, intel_private.i9xx_flush_page); 1261f51b7662SDaniel Vetter } 1262f51b7662SDaniel Vetter 1263a6963596SDaniel Vetter static void i965_write_entry(dma_addr_t addr, unsigned int entry, 1264a6963596SDaniel Vetter unsigned int flags) 1265a6963596SDaniel Vetter { 1266a6963596SDaniel Vetter /* Shift high bits down */ 1267a6963596SDaniel Vetter addr |= (addr >> 28) & 0xf0; 1268a6963596SDaniel Vetter writel(addr | I810_PTE_VALID, intel_private.gtt + entry); 1269a6963596SDaniel Vetter } 1270a6963596SDaniel Vetter 127190cb149eSDaniel Vetter static bool gen6_check_flags(unsigned int flags) 127290cb149eSDaniel Vetter { 127390cb149eSDaniel Vetter return true; 127490cb149eSDaniel Vetter } 127590cb149eSDaniel Vetter 127697ef1bddSDaniel Vetter static void gen6_write_entry(dma_addr_t addr, unsigned int entry, 127797ef1bddSDaniel Vetter unsigned int flags) 127897ef1bddSDaniel Vetter { 127997ef1bddSDaniel Vetter unsigned int type_mask = flags & ~AGP_USER_CACHED_MEMORY_GFDT; 128097ef1bddSDaniel Vetter unsigned int gfdt = flags & AGP_USER_CACHED_MEMORY_GFDT; 128197ef1bddSDaniel Vetter u32 pte_flags; 128297ef1bddSDaniel Vetter 128397ef1bddSDaniel Vetter if (type_mask == AGP_USER_UNCACHED_MEMORY) 128485ccc35bSChris Wilson pte_flags = GEN6_PTE_UNCACHED | I810_PTE_VALID; 128597ef1bddSDaniel Vetter else if (type_mask == AGP_USER_CACHED_MEMORY_LLC_MLC) { 128685ccc35bSChris Wilson pte_flags = GEN6_PTE_LLC | I810_PTE_VALID; 128797ef1bddSDaniel Vetter if (gfdt) 128897ef1bddSDaniel Vetter pte_flags |= GEN6_PTE_GFDT; 128997ef1bddSDaniel Vetter } else { /* set 'normal'/'cached' to LLC by default */ 129085ccc35bSChris Wilson pte_flags = GEN6_PTE_LLC_MLC | I810_PTE_VALID; 129197ef1bddSDaniel Vetter if (gfdt) 129297ef1bddSDaniel Vetter pte_flags |= GEN6_PTE_GFDT; 129397ef1bddSDaniel Vetter } 129497ef1bddSDaniel Vetter 129597ef1bddSDaniel Vetter /* gen6 has bit11-4 for physical addr bit39-32 */ 129697ef1bddSDaniel Vetter addr |= (addr >> 28) & 0xff0; 129797ef1bddSDaniel Vetter writel(addr | pte_flags, intel_private.gtt + entry); 129897ef1bddSDaniel Vetter } 129997ef1bddSDaniel Vetter 1300ae83dd5cSDaniel Vetter static void gen6_cleanup(void) 1301ae83dd5cSDaniel Vetter { 1302ae83dd5cSDaniel Vetter } 1303ae83dd5cSDaniel Vetter 13042d2430cfSDaniel Vetter static int i9xx_setup(void) 13052d2430cfSDaniel Vetter { 13062d2430cfSDaniel Vetter u32 reg_addr; 13072d2430cfSDaniel Vetter 13082d2430cfSDaniel Vetter pci_read_config_dword(intel_private.pcidev, I915_MMADDR, ®_addr); 13092d2430cfSDaniel Vetter 13102d2430cfSDaniel Vetter reg_addr &= 0xfff80000; 13112d2430cfSDaniel Vetter 13122d2430cfSDaniel Vetter intel_private.registers = ioremap(reg_addr, 128 * 4096); 13132d2430cfSDaniel Vetter if (!intel_private.registers) 13142d2430cfSDaniel Vetter return -ENOMEM; 13152d2430cfSDaniel Vetter 13162d2430cfSDaniel Vetter if (INTEL_GTT_GEN == 3) { 13172d2430cfSDaniel Vetter u32 gtt_addr; 13183f08e4efSChris Wilson 13192d2430cfSDaniel Vetter pci_read_config_dword(intel_private.pcidev, 13202d2430cfSDaniel Vetter I915_PTEADDR, >t_addr); 13212d2430cfSDaniel Vetter intel_private.gtt_bus_addr = gtt_addr; 13222d2430cfSDaniel Vetter } else { 13232d2430cfSDaniel Vetter u32 gtt_offset; 13242d2430cfSDaniel Vetter 13252d2430cfSDaniel Vetter switch (INTEL_GTT_GEN) { 13262d2430cfSDaniel Vetter case 5: 13272d2430cfSDaniel Vetter case 6: 13282d2430cfSDaniel Vetter gtt_offset = MB(2); 13292d2430cfSDaniel Vetter break; 13302d2430cfSDaniel Vetter case 4: 13312d2430cfSDaniel Vetter default: 13322d2430cfSDaniel Vetter gtt_offset = KB(512); 13332d2430cfSDaniel Vetter break; 13342d2430cfSDaniel Vetter } 13352d2430cfSDaniel Vetter intel_private.gtt_bus_addr = reg_addr + gtt_offset; 13362d2430cfSDaniel Vetter } 13372d2430cfSDaniel Vetter 13382d2430cfSDaniel Vetter intel_i9xx_setup_flush(); 13392d2430cfSDaniel Vetter 13402d2430cfSDaniel Vetter return 0; 13412d2430cfSDaniel Vetter } 13422d2430cfSDaniel Vetter 1343f51b7662SDaniel Vetter static const struct agp_bridge_driver intel_810_driver = { 1344f51b7662SDaniel Vetter .owner = THIS_MODULE, 1345f51b7662SDaniel Vetter .aperture_sizes = intel_i810_sizes, 1346f51b7662SDaniel Vetter .size_type = FIXED_APER_SIZE, 1347f51b7662SDaniel Vetter .num_aperture_sizes = 2, 1348f51b7662SDaniel Vetter .needs_scratch_page = true, 1349f51b7662SDaniel Vetter .configure = intel_i810_configure, 1350f51b7662SDaniel Vetter .fetch_size = intel_i810_fetch_size, 1351f51b7662SDaniel Vetter .cleanup = intel_i810_cleanup, 1352f51b7662SDaniel Vetter .mask_memory = intel_i810_mask_memory, 1353f51b7662SDaniel Vetter .masks = intel_i810_masks, 1354ffdd7510SDaniel Vetter .agp_enable = intel_fake_agp_enable, 1355f51b7662SDaniel Vetter .cache_flush = global_cache_flush, 1356f51b7662SDaniel Vetter .create_gatt_table = agp_generic_create_gatt_table, 1357f51b7662SDaniel Vetter .free_gatt_table = agp_generic_free_gatt_table, 1358f51b7662SDaniel Vetter .insert_memory = intel_i810_insert_entries, 1359f51b7662SDaniel Vetter .remove_memory = intel_i810_remove_entries, 1360f51b7662SDaniel Vetter .alloc_by_type = intel_i810_alloc_by_type, 1361f51b7662SDaniel Vetter .free_by_type = intel_i810_free_by_type, 1362f51b7662SDaniel Vetter .agp_alloc_page = agp_generic_alloc_page, 1363f51b7662SDaniel Vetter .agp_alloc_pages = agp_generic_alloc_pages, 1364f51b7662SDaniel Vetter .agp_destroy_page = agp_generic_destroy_page, 1365f51b7662SDaniel Vetter .agp_destroy_pages = agp_generic_destroy_pages, 1366f51b7662SDaniel Vetter .agp_type_to_mask_type = agp_generic_type_to_mask_type, 1367f51b7662SDaniel Vetter }; 1368f51b7662SDaniel Vetter 1369e9b1cc81SDaniel Vetter static const struct agp_bridge_driver intel_fake_agp_driver = { 1370f51b7662SDaniel Vetter .owner = THIS_MODULE, 1371f51b7662SDaniel Vetter .size_type = FIXED_APER_SIZE, 13729e76e7b8SChris Wilson .aperture_sizes = intel_fake_agp_sizes, 13739e76e7b8SChris Wilson .num_aperture_sizes = ARRAY_SIZE(intel_fake_agp_sizes), 1374a6963596SDaniel Vetter .configure = intel_fake_agp_configure, 13753e921f98SDaniel Vetter .fetch_size = intel_fake_agp_fetch_size, 1376fdfb58a9SDaniel Vetter .cleanup = intel_gtt_cleanup, 1377ffdd7510SDaniel Vetter .agp_enable = intel_fake_agp_enable, 1378f51b7662SDaniel Vetter .cache_flush = global_cache_flush, 13793b15a9d7SDaniel Vetter .create_gatt_table = intel_fake_agp_create_gatt_table, 1380ffdd7510SDaniel Vetter .free_gatt_table = intel_fake_agp_free_gatt_table, 1381450f2b3dSDaniel Vetter .insert_memory = intel_fake_agp_insert_entries, 1382450f2b3dSDaniel Vetter .remove_memory = intel_fake_agp_remove_entries, 1383ffdd7510SDaniel Vetter .alloc_by_type = intel_fake_agp_alloc_by_type, 1384f51b7662SDaniel Vetter .free_by_type = intel_i810_free_by_type, 1385f51b7662SDaniel Vetter .agp_alloc_page = agp_generic_alloc_page, 1386f51b7662SDaniel Vetter .agp_alloc_pages = agp_generic_alloc_pages, 1387f51b7662SDaniel Vetter .agp_destroy_page = agp_generic_destroy_page, 1388f51b7662SDaniel Vetter .agp_destroy_pages = agp_generic_destroy_pages, 13891b263f24SDaniel Vetter .chipset_flush = intel_fake_agp_chipset_flush, 1390f51b7662SDaniel Vetter }; 139102c026ceSDaniel Vetter 1392bdd30729SDaniel Vetter static const struct intel_gtt_driver i81x_gtt_driver = { 1393bdd30729SDaniel Vetter .gen = 1, 139422533b49SDaniel Vetter .dma_mask_size = 32, 1395bdd30729SDaniel Vetter }; 13961a997ff2SDaniel Vetter static const struct intel_gtt_driver i8xx_gtt_driver = { 13971a997ff2SDaniel Vetter .gen = 2, 139873800422SDaniel Vetter .setup = i830_setup, 1399ae83dd5cSDaniel Vetter .cleanup = i830_cleanup, 1400351bb278SDaniel Vetter .write_entry = i830_write_entry, 140122533b49SDaniel Vetter .dma_mask_size = 32, 14025cbecafcSDaniel Vetter .check_flags = i830_check_flags, 14031b263f24SDaniel Vetter .chipset_flush = i830_chipset_flush, 14041a997ff2SDaniel Vetter }; 14051a997ff2SDaniel Vetter static const struct intel_gtt_driver i915_gtt_driver = { 14061a997ff2SDaniel Vetter .gen = 3, 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, 14372d2430cfSDaniel Vetter .setup = i9xx_setup, 1438ae83dd5cSDaniel Vetter .cleanup = i9xx_cleanup, 1439a6963596SDaniel Vetter .write_entry = i965_write_entry, 144022533b49SDaniel Vetter .dma_mask_size = 36, 1441450f2b3dSDaniel Vetter .check_flags = i830_check_flags, 14421b263f24SDaniel Vetter .chipset_flush = i9xx_chipset_flush, 14431a997ff2SDaniel Vetter }; 14441a997ff2SDaniel Vetter static const struct intel_gtt_driver g4x_gtt_driver = { 14451a997ff2SDaniel Vetter .gen = 5, 14462d2430cfSDaniel Vetter .setup = i9xx_setup, 1447ae83dd5cSDaniel Vetter .cleanup = i9xx_cleanup, 1448a6963596SDaniel Vetter .write_entry = i965_write_entry, 144922533b49SDaniel Vetter .dma_mask_size = 36, 1450450f2b3dSDaniel Vetter .check_flags = i830_check_flags, 14511b263f24SDaniel Vetter .chipset_flush = i9xx_chipset_flush, 14521a997ff2SDaniel Vetter }; 14531a997ff2SDaniel Vetter static const struct intel_gtt_driver ironlake_gtt_driver = { 14541a997ff2SDaniel Vetter .gen = 5, 14551a997ff2SDaniel Vetter .is_ironlake = 1, 14562d2430cfSDaniel Vetter .setup = i9xx_setup, 1457ae83dd5cSDaniel Vetter .cleanup = i9xx_cleanup, 1458a6963596SDaniel Vetter .write_entry = i965_write_entry, 145922533b49SDaniel Vetter .dma_mask_size = 36, 1460450f2b3dSDaniel Vetter .check_flags = i830_check_flags, 14611b263f24SDaniel Vetter .chipset_flush = i9xx_chipset_flush, 14621a997ff2SDaniel Vetter }; 14631a997ff2SDaniel Vetter static const struct intel_gtt_driver sandybridge_gtt_driver = { 14641a997ff2SDaniel Vetter .gen = 6, 14652d2430cfSDaniel Vetter .setup = i9xx_setup, 1466ae83dd5cSDaniel Vetter .cleanup = gen6_cleanup, 146797ef1bddSDaniel Vetter .write_entry = gen6_write_entry, 146822533b49SDaniel Vetter .dma_mask_size = 40, 146990cb149eSDaniel Vetter .check_flags = gen6_check_flags, 14701b263f24SDaniel Vetter .chipset_flush = i9xx_chipset_flush, 14711a997ff2SDaniel Vetter }; 14721a997ff2SDaniel Vetter 147302c026ceSDaniel Vetter /* Table to describe Intel GMCH and AGP/PCIE GART drivers. At least one of 147402c026ceSDaniel Vetter * driver and gmch_driver must be non-null, and find_gmch will determine 147502c026ceSDaniel Vetter * which one should be used if a gmch_chip_id is present. 147602c026ceSDaniel Vetter */ 147702c026ceSDaniel Vetter static const struct intel_gtt_driver_description { 147802c026ceSDaniel Vetter unsigned int gmch_chip_id; 147902c026ceSDaniel Vetter char *name; 148002c026ceSDaniel Vetter const struct agp_bridge_driver *gmch_driver; 14811a997ff2SDaniel Vetter const struct intel_gtt_driver *gtt_driver; 148202c026ceSDaniel Vetter } intel_gtt_chipsets[] = { 1483bdd30729SDaniel Vetter { PCI_DEVICE_ID_INTEL_82810_IG1, "i810", &intel_810_driver, 1484bdd30729SDaniel Vetter &i81x_gtt_driver}, 1485bdd30729SDaniel Vetter { PCI_DEVICE_ID_INTEL_82810_IG3, "i810", &intel_810_driver, 1486bdd30729SDaniel Vetter &i81x_gtt_driver}, 1487bdd30729SDaniel Vetter { PCI_DEVICE_ID_INTEL_82810E_IG, "i810", &intel_810_driver, 1488bdd30729SDaniel Vetter &i81x_gtt_driver}, 1489bdd30729SDaniel Vetter { PCI_DEVICE_ID_INTEL_82815_CGC, "i815", &intel_810_driver, 1490bdd30729SDaniel Vetter &i81x_gtt_driver}, 14911a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_82830_CGC, "830M", 1492e9b1cc81SDaniel Vetter &intel_fake_agp_driver, &i8xx_gtt_driver}, 14931a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_82845G_IG, "830M", 1494e9b1cc81SDaniel Vetter &intel_fake_agp_driver, &i8xx_gtt_driver}, 14951a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_82854_IG, "854", 1496e9b1cc81SDaniel Vetter &intel_fake_agp_driver, &i8xx_gtt_driver}, 14971a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_82855GM_IG, "855GM", 1498e9b1cc81SDaniel Vetter &intel_fake_agp_driver, &i8xx_gtt_driver}, 14991a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_82865_IG, "865", 1500e9b1cc81SDaniel Vetter &intel_fake_agp_driver, &i8xx_gtt_driver}, 15011a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_E7221_IG, "E7221 (i915)", 1502e9b1cc81SDaniel Vetter &intel_fake_agp_driver, &i915_gtt_driver }, 15031a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_82915G_IG, "915G", 1504e9b1cc81SDaniel Vetter &intel_fake_agp_driver, &i915_gtt_driver }, 15051a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_82915GM_IG, "915GM", 1506e9b1cc81SDaniel Vetter &intel_fake_agp_driver, &i915_gtt_driver }, 15071a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_82945G_IG, "945G", 1508e9b1cc81SDaniel Vetter &intel_fake_agp_driver, &i915_gtt_driver }, 15091a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_82945GM_IG, "945GM", 1510e9b1cc81SDaniel Vetter &intel_fake_agp_driver, &i915_gtt_driver }, 15111a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_82945GME_IG, "945GME", 1512e9b1cc81SDaniel Vetter &intel_fake_agp_driver, &i915_gtt_driver }, 15131a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_82946GZ_IG, "946GZ", 1514e9b1cc81SDaniel Vetter &intel_fake_agp_driver, &i965_gtt_driver }, 15151a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_82G35_IG, "G35", 1516e9b1cc81SDaniel Vetter &intel_fake_agp_driver, &i965_gtt_driver }, 15171a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_82965Q_IG, "965Q", 1518e9b1cc81SDaniel Vetter &intel_fake_agp_driver, &i965_gtt_driver }, 15191a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_82965G_IG, "965G", 1520e9b1cc81SDaniel Vetter &intel_fake_agp_driver, &i965_gtt_driver }, 15211a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_82965GM_IG, "965GM", 1522e9b1cc81SDaniel Vetter &intel_fake_agp_driver, &i965_gtt_driver }, 15231a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_82965GME_IG, "965GME/GLE", 1524e9b1cc81SDaniel Vetter &intel_fake_agp_driver, &i965_gtt_driver }, 15251a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_G33_IG, "G33", 1526e9b1cc81SDaniel Vetter &intel_fake_agp_driver, &g33_gtt_driver }, 15271a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_Q35_IG, "Q35", 1528e9b1cc81SDaniel Vetter &intel_fake_agp_driver, &g33_gtt_driver }, 15291a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_Q33_IG, "Q33", 1530e9b1cc81SDaniel Vetter &intel_fake_agp_driver, &g33_gtt_driver }, 15311a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_PINEVIEW_M_IG, "GMA3150", 1532e9b1cc81SDaniel Vetter &intel_fake_agp_driver, &pineview_gtt_driver }, 15331a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_PINEVIEW_IG, "GMA3150", 1534e9b1cc81SDaniel Vetter &intel_fake_agp_driver, &pineview_gtt_driver }, 15351a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_GM45_IG, "GM45", 1536e9b1cc81SDaniel Vetter &intel_fake_agp_driver, &g4x_gtt_driver }, 15371a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_EAGLELAKE_IG, "Eaglelake", 1538e9b1cc81SDaniel Vetter &intel_fake_agp_driver, &g4x_gtt_driver }, 15391a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_Q45_IG, "Q45/Q43", 1540e9b1cc81SDaniel Vetter &intel_fake_agp_driver, &g4x_gtt_driver }, 15411a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_G45_IG, "G45/G43", 1542e9b1cc81SDaniel Vetter &intel_fake_agp_driver, &g4x_gtt_driver }, 15431a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_B43_IG, "B43", 1544e9b1cc81SDaniel Vetter &intel_fake_agp_driver, &g4x_gtt_driver }, 1545e9e5f8e8SChris Wilson { PCI_DEVICE_ID_INTEL_B43_1_IG, "B43", 1546e9b1cc81SDaniel Vetter &intel_fake_agp_driver, &g4x_gtt_driver }, 15471a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_G41_IG, "G41", 1548e9b1cc81SDaniel Vetter &intel_fake_agp_driver, &g4x_gtt_driver }, 154902c026ceSDaniel Vetter { PCI_DEVICE_ID_INTEL_IRONLAKE_D_IG, 1550e9b1cc81SDaniel Vetter "HD Graphics", &intel_fake_agp_driver, &ironlake_gtt_driver }, 155102c026ceSDaniel Vetter { PCI_DEVICE_ID_INTEL_IRONLAKE_M_IG, 1552e9b1cc81SDaniel Vetter "HD Graphics", &intel_fake_agp_driver, &ironlake_gtt_driver }, 155302c026ceSDaniel Vetter { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_GT1_IG, 1554e9b1cc81SDaniel Vetter "Sandybridge", &intel_fake_agp_driver, &sandybridge_gtt_driver }, 155502c026ceSDaniel Vetter { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_GT2_IG, 1556e9b1cc81SDaniel Vetter "Sandybridge", &intel_fake_agp_driver, &sandybridge_gtt_driver }, 155702c026ceSDaniel Vetter { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_GT2_PLUS_IG, 1558e9b1cc81SDaniel Vetter "Sandybridge", &intel_fake_agp_driver, &sandybridge_gtt_driver }, 155902c026ceSDaniel Vetter { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_GT1_IG, 1560e9b1cc81SDaniel Vetter "Sandybridge", &intel_fake_agp_driver, &sandybridge_gtt_driver }, 156102c026ceSDaniel Vetter { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_GT2_IG, 1562e9b1cc81SDaniel Vetter "Sandybridge", &intel_fake_agp_driver, &sandybridge_gtt_driver }, 156302c026ceSDaniel Vetter { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_GT2_PLUS_IG, 1564e9b1cc81SDaniel Vetter "Sandybridge", &intel_fake_agp_driver, &sandybridge_gtt_driver }, 156502c026ceSDaniel Vetter { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_S_IG, 1566e9b1cc81SDaniel Vetter "Sandybridge", &intel_fake_agp_driver, &sandybridge_gtt_driver }, 156702c026ceSDaniel Vetter { 0, NULL, NULL } 156802c026ceSDaniel Vetter }; 156902c026ceSDaniel Vetter 157002c026ceSDaniel Vetter static int find_gmch(u16 device) 157102c026ceSDaniel Vetter { 157202c026ceSDaniel Vetter struct pci_dev *gmch_device; 157302c026ceSDaniel Vetter 157402c026ceSDaniel Vetter gmch_device = pci_get_device(PCI_VENDOR_ID_INTEL, device, NULL); 157502c026ceSDaniel Vetter if (gmch_device && PCI_FUNC(gmch_device->devfn) != 0) { 157602c026ceSDaniel Vetter gmch_device = pci_get_device(PCI_VENDOR_ID_INTEL, 157702c026ceSDaniel Vetter device, gmch_device); 157802c026ceSDaniel Vetter } 157902c026ceSDaniel Vetter 158002c026ceSDaniel Vetter if (!gmch_device) 158102c026ceSDaniel Vetter return 0; 158202c026ceSDaniel Vetter 158302c026ceSDaniel Vetter intel_private.pcidev = gmch_device; 158402c026ceSDaniel Vetter return 1; 158502c026ceSDaniel Vetter } 158602c026ceSDaniel Vetter 1587e2404e7cSDaniel Vetter int intel_gmch_probe(struct pci_dev *pdev, 158802c026ceSDaniel Vetter struct agp_bridge_data *bridge) 158902c026ceSDaniel Vetter { 159002c026ceSDaniel Vetter int i, mask; 159102c026ceSDaniel Vetter bridge->driver = NULL; 159202c026ceSDaniel Vetter 159302c026ceSDaniel Vetter for (i = 0; intel_gtt_chipsets[i].name != NULL; i++) { 159402c026ceSDaniel Vetter if (find_gmch(intel_gtt_chipsets[i].gmch_chip_id)) { 159502c026ceSDaniel Vetter bridge->driver = 159602c026ceSDaniel Vetter intel_gtt_chipsets[i].gmch_driver; 15971a997ff2SDaniel Vetter intel_private.driver = 15981a997ff2SDaniel Vetter intel_gtt_chipsets[i].gtt_driver; 159902c026ceSDaniel Vetter break; 160002c026ceSDaniel Vetter } 160102c026ceSDaniel Vetter } 160202c026ceSDaniel Vetter 160302c026ceSDaniel Vetter if (!bridge->driver) 160402c026ceSDaniel Vetter return 0; 160502c026ceSDaniel Vetter 160602c026ceSDaniel Vetter bridge->dev_private_data = &intel_private; 160702c026ceSDaniel Vetter bridge->dev = pdev; 160802c026ceSDaniel Vetter 1609d7cca2f7SDaniel Vetter intel_private.bridge_dev = pci_dev_get(pdev); 1610d7cca2f7SDaniel Vetter 161102c026ceSDaniel Vetter dev_info(&pdev->dev, "Intel %s Chipset\n", intel_gtt_chipsets[i].name); 161202c026ceSDaniel Vetter 161322533b49SDaniel Vetter mask = intel_private.driver->dma_mask_size; 161402c026ceSDaniel Vetter if (pci_set_dma_mask(intel_private.pcidev, DMA_BIT_MASK(mask))) 161502c026ceSDaniel Vetter dev_err(&intel_private.pcidev->dev, 161602c026ceSDaniel Vetter "set gfx device dma mask %d-bit failed!\n", mask); 161702c026ceSDaniel Vetter else 161802c026ceSDaniel Vetter pci_set_consistent_dma_mask(intel_private.pcidev, 161902c026ceSDaniel Vetter DMA_BIT_MASK(mask)); 162002c026ceSDaniel Vetter 16211784a5fbSDaniel Vetter if (bridge->driver == &intel_810_driver) 16221784a5fbSDaniel Vetter return 1; 16231784a5fbSDaniel Vetter 16243b15a9d7SDaniel Vetter if (intel_gtt_init() != 0) 16253b15a9d7SDaniel Vetter return 0; 16261784a5fbSDaniel Vetter 162702c026ceSDaniel Vetter return 1; 162802c026ceSDaniel Vetter } 1629e2404e7cSDaniel Vetter EXPORT_SYMBOL(intel_gmch_probe); 163002c026ceSDaniel Vetter 163119966754SDaniel Vetter struct intel_gtt *intel_gtt_get(void) 163219966754SDaniel Vetter { 163319966754SDaniel Vetter return &intel_private.base; 163419966754SDaniel Vetter } 163519966754SDaniel Vetter EXPORT_SYMBOL(intel_gtt_get); 163619966754SDaniel Vetter 1637e2404e7cSDaniel Vetter void intel_gmch_remove(struct pci_dev *pdev) 163802c026ceSDaniel Vetter { 163902c026ceSDaniel Vetter if (intel_private.pcidev) 164002c026ceSDaniel Vetter pci_dev_put(intel_private.pcidev); 1641d7cca2f7SDaniel Vetter if (intel_private.bridge_dev) 1642d7cca2f7SDaniel Vetter pci_dev_put(intel_private.bridge_dev); 164302c026ceSDaniel Vetter } 1644e2404e7cSDaniel Vetter EXPORT_SYMBOL(intel_gmch_remove); 1645e2404e7cSDaniel Vetter 1646e2404e7cSDaniel Vetter MODULE_AUTHOR("Dave Jones <davej@redhat.com>"); 1647e2404e7cSDaniel Vetter MODULE_LICENSE("GPL and additional rights"); 1648