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> 24bdb8b975SChris Wilson #include <linux/delay.h> 25e2404e7cSDaniel Vetter #include <asm/smp.h> 26e2404e7cSDaniel Vetter #include "agp.h" 27e2404e7cSDaniel Vetter #include "intel-agp.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 33d3f13810SSuresh Siddha * on the Intel IOMMU support (CONFIG_INTEL_IOMMU). 34f51b7662SDaniel Vetter * Only newer chipsets need to bother with this, of course. 35f51b7662SDaniel Vetter */ 36d3f13810SSuresh Siddha #ifdef CONFIG_INTEL_IOMMU 37f51b7662SDaniel Vetter #define USE_PCI_DMA_API 1 380e87d2b0SDaniel Vetter #else 390e87d2b0SDaniel Vetter #define USE_PCI_DMA_API 0 40f51b7662SDaniel Vetter #endif 41f51b7662SDaniel Vetter 421a997ff2SDaniel Vetter struct intel_gtt_driver { 431a997ff2SDaniel Vetter unsigned int gen : 8; 441a997ff2SDaniel Vetter unsigned int is_g33 : 1; 451a997ff2SDaniel Vetter unsigned int is_pineview : 1; 461a997ff2SDaniel Vetter unsigned int is_ironlake : 1; 47100519e2SChris Wilson unsigned int has_pgtbl_enable : 1; 4822533b49SDaniel Vetter unsigned int dma_mask_size : 8; 4973800422SDaniel Vetter /* Chipset specific GTT setup */ 5073800422SDaniel Vetter int (*setup)(void); 51ae83dd5cSDaniel Vetter /* This should undo anything done in ->setup() save the unmapping 52ae83dd5cSDaniel Vetter * of the mmio register file, that's done in the generic code. */ 53ae83dd5cSDaniel Vetter void (*cleanup)(void); 54351bb278SDaniel Vetter void (*write_entry)(dma_addr_t addr, unsigned int entry, unsigned int flags); 55351bb278SDaniel Vetter /* Flags is a more or less chipset specific opaque value. 56351bb278SDaniel Vetter * For chipsets that need to support old ums (non-gem) code, this 57351bb278SDaniel Vetter * needs to be identical to the various supported agp memory types! */ 585cbecafcSDaniel Vetter bool (*check_flags)(unsigned int flags); 591b263f24SDaniel Vetter void (*chipset_flush)(void); 601a997ff2SDaniel Vetter }; 611a997ff2SDaniel Vetter 62f51b7662SDaniel Vetter static struct _intel_private { 630ade6386SDaniel Vetter struct intel_gtt base; 641a997ff2SDaniel Vetter const struct intel_gtt_driver *driver; 65f51b7662SDaniel Vetter struct pci_dev *pcidev; /* device one */ 66d7cca2f7SDaniel Vetter struct pci_dev *bridge_dev; 67f51b7662SDaniel Vetter u8 __iomem *registers; 68f67eab66SDaniel Vetter phys_addr_t gtt_bus_addr; 69b3eafc5aSDaniel Vetter u32 PGETBL_save; 70f51b7662SDaniel Vetter u32 __iomem *gtt; /* I915G */ 71bee4a186SChris Wilson bool clear_fake_agp; /* on first access via agp, fill with scratch */ 72f51b7662SDaniel Vetter int num_dcache_entries; 73f51b7662SDaniel Vetter void __iomem *i9xx_flush_page; 74820647b9SDaniel Vetter char *i81x_gtt_table; 75f51b7662SDaniel Vetter struct resource ifp_resource; 76f51b7662SDaniel Vetter int resource_valid; 770e87d2b0SDaniel Vetter struct page *scratch_page; 7814be93ddSDaniel Vetter int refcount; 79f51b7662SDaniel Vetter } intel_private; 80f51b7662SDaniel Vetter 811a997ff2SDaniel Vetter #define INTEL_GTT_GEN intel_private.driver->gen 821a997ff2SDaniel Vetter #define IS_G33 intel_private.driver->is_g33 831a997ff2SDaniel Vetter #define IS_PINEVIEW intel_private.driver->is_pineview 841a997ff2SDaniel Vetter #define IS_IRONLAKE intel_private.driver->is_ironlake 85100519e2SChris Wilson #define HAS_PGTBL_EN intel_private.driver->has_pgtbl_enable 861a997ff2SDaniel Vetter 874080775bSDaniel Vetter int intel_gtt_map_memory(struct page **pages, unsigned int num_entries, 884080775bSDaniel Vetter struct scatterlist **sg_list, int *num_sg) 89f51b7662SDaniel Vetter { 90f51b7662SDaniel Vetter struct sg_table st; 91f51b7662SDaniel Vetter struct scatterlist *sg; 92f51b7662SDaniel Vetter int i; 93f51b7662SDaniel Vetter 944080775bSDaniel Vetter if (*sg_list) 95fefaa70fSDaniel Vetter return 0; /* already mapped (for e.g. resume */ 96fefaa70fSDaniel Vetter 974080775bSDaniel Vetter DBG("try mapping %lu pages\n", (unsigned long)num_entries); 98f51b7662SDaniel Vetter 994080775bSDaniel Vetter if (sg_alloc_table(&st, num_entries, GFP_KERNEL)) 100831cd445SChris Wilson goto err; 101f51b7662SDaniel Vetter 1024080775bSDaniel Vetter *sg_list = sg = st.sgl; 103f51b7662SDaniel Vetter 1044080775bSDaniel Vetter for (i = 0 ; i < num_entries; i++, sg = sg_next(sg)) 1054080775bSDaniel Vetter sg_set_page(sg, pages[i], PAGE_SIZE, 0); 106f51b7662SDaniel Vetter 1074080775bSDaniel Vetter *num_sg = pci_map_sg(intel_private.pcidev, *sg_list, 1084080775bSDaniel Vetter num_entries, PCI_DMA_BIDIRECTIONAL); 1094080775bSDaniel Vetter if (unlikely(!*num_sg)) 110831cd445SChris Wilson goto err; 111831cd445SChris Wilson 112f51b7662SDaniel Vetter return 0; 113831cd445SChris Wilson 114831cd445SChris Wilson err: 115831cd445SChris Wilson sg_free_table(&st); 116831cd445SChris Wilson return -ENOMEM; 117f51b7662SDaniel Vetter } 1184080775bSDaniel Vetter EXPORT_SYMBOL(intel_gtt_map_memory); 119f51b7662SDaniel Vetter 1204080775bSDaniel Vetter void intel_gtt_unmap_memory(struct scatterlist *sg_list, int num_sg) 121f51b7662SDaniel Vetter { 1224080775bSDaniel Vetter struct sg_table st; 123f51b7662SDaniel Vetter DBG("try unmapping %lu pages\n", (unsigned long)mem->page_count); 124f51b7662SDaniel Vetter 1254080775bSDaniel Vetter pci_unmap_sg(intel_private.pcidev, sg_list, 1264080775bSDaniel Vetter num_sg, PCI_DMA_BIDIRECTIONAL); 1274080775bSDaniel Vetter 1284080775bSDaniel Vetter st.sgl = sg_list; 1294080775bSDaniel Vetter st.orig_nents = st.nents = num_sg; 1304080775bSDaniel Vetter 1314080775bSDaniel Vetter sg_free_table(&st); 132f51b7662SDaniel Vetter } 1334080775bSDaniel Vetter EXPORT_SYMBOL(intel_gtt_unmap_memory); 134f51b7662SDaniel Vetter 135ffdd7510SDaniel Vetter static void intel_fake_agp_enable(struct agp_bridge_data *bridge, u32 mode) 136f51b7662SDaniel Vetter { 137f51b7662SDaniel Vetter return; 138f51b7662SDaniel Vetter } 139f51b7662SDaniel Vetter 140f51b7662SDaniel Vetter /* Exists to support ARGB cursors */ 141f51b7662SDaniel Vetter static struct page *i8xx_alloc_pages(void) 142f51b7662SDaniel Vetter { 143f51b7662SDaniel Vetter struct page *page; 144f51b7662SDaniel Vetter 145f51b7662SDaniel Vetter page = alloc_pages(GFP_KERNEL | GFP_DMA32, 2); 146f51b7662SDaniel Vetter if (page == NULL) 147f51b7662SDaniel Vetter return NULL; 148f51b7662SDaniel Vetter 149f51b7662SDaniel Vetter if (set_pages_uc(page, 4) < 0) { 150f51b7662SDaniel Vetter set_pages_wb(page, 4); 151f51b7662SDaniel Vetter __free_pages(page, 2); 152f51b7662SDaniel Vetter return NULL; 153f51b7662SDaniel Vetter } 154f51b7662SDaniel Vetter get_page(page); 155f51b7662SDaniel Vetter atomic_inc(&agp_bridge->current_memory_agp); 156f51b7662SDaniel Vetter return page; 157f51b7662SDaniel Vetter } 158f51b7662SDaniel Vetter 159f51b7662SDaniel Vetter static void i8xx_destroy_pages(struct page *page) 160f51b7662SDaniel Vetter { 161f51b7662SDaniel Vetter if (page == NULL) 162f51b7662SDaniel Vetter return; 163f51b7662SDaniel Vetter 164f51b7662SDaniel Vetter set_pages_wb(page, 4); 165f51b7662SDaniel Vetter put_page(page); 166f51b7662SDaniel Vetter __free_pages(page, 2); 167f51b7662SDaniel Vetter atomic_dec(&agp_bridge->current_memory_agp); 168f51b7662SDaniel Vetter } 169f51b7662SDaniel Vetter 170820647b9SDaniel Vetter #define I810_GTT_ORDER 4 171820647b9SDaniel Vetter static int i810_setup(void) 172820647b9SDaniel Vetter { 173820647b9SDaniel Vetter u32 reg_addr; 174820647b9SDaniel Vetter char *gtt_table; 175820647b9SDaniel Vetter 176820647b9SDaniel Vetter /* i81x does not preallocate the gtt. It's always 64kb in size. */ 177820647b9SDaniel Vetter gtt_table = alloc_gatt_pages(I810_GTT_ORDER); 178820647b9SDaniel Vetter if (gtt_table == NULL) 179820647b9SDaniel Vetter return -ENOMEM; 180820647b9SDaniel Vetter intel_private.i81x_gtt_table = gtt_table; 181820647b9SDaniel Vetter 182820647b9SDaniel Vetter pci_read_config_dword(intel_private.pcidev, I810_MMADDR, ®_addr); 183820647b9SDaniel Vetter reg_addr &= 0xfff80000; 184820647b9SDaniel Vetter 185820647b9SDaniel Vetter intel_private.registers = ioremap(reg_addr, KB(64)); 186820647b9SDaniel Vetter if (!intel_private.registers) 187820647b9SDaniel Vetter return -ENOMEM; 188820647b9SDaniel Vetter 189820647b9SDaniel Vetter writel(virt_to_phys(gtt_table) | I810_PGETBL_ENABLED, 190820647b9SDaniel Vetter intel_private.registers+I810_PGETBL_CTL); 191820647b9SDaniel Vetter 192820647b9SDaniel Vetter intel_private.gtt_bus_addr = reg_addr + I810_PTE_BASE; 193820647b9SDaniel Vetter 194820647b9SDaniel Vetter if ((readl(intel_private.registers+I810_DRAM_CTL) 195820647b9SDaniel Vetter & I810_DRAM_ROW_0) == I810_DRAM_ROW_0_SDRAM) { 196820647b9SDaniel Vetter dev_info(&intel_private.pcidev->dev, 197820647b9SDaniel Vetter "detected 4MB dedicated video ram\n"); 198820647b9SDaniel Vetter intel_private.num_dcache_entries = 1024; 199820647b9SDaniel Vetter } 200820647b9SDaniel Vetter 201820647b9SDaniel Vetter return 0; 202820647b9SDaniel Vetter } 203820647b9SDaniel Vetter 204820647b9SDaniel Vetter static void i810_cleanup(void) 205820647b9SDaniel Vetter { 206820647b9SDaniel Vetter writel(0, intel_private.registers+I810_PGETBL_CTL); 207820647b9SDaniel Vetter free_gatt_pages(intel_private.i81x_gtt_table, I810_GTT_ORDER); 208820647b9SDaniel Vetter } 209820647b9SDaniel Vetter 210ff26860fSDaniel Vetter static int i810_insert_dcache_entries(struct agp_memory *mem, off_t pg_start, 211f51b7662SDaniel Vetter int type) 212f51b7662SDaniel Vetter { 213f51b7662SDaniel Vetter int i; 214f51b7662SDaniel Vetter 215625dd9d3SDaniel Vetter if ((pg_start + mem->page_count) 216625dd9d3SDaniel Vetter > intel_private.num_dcache_entries) 217625dd9d3SDaniel Vetter return -EINVAL; 218f51b7662SDaniel Vetter 219625dd9d3SDaniel Vetter if (!mem->is_flushed) 220625dd9d3SDaniel Vetter global_cache_flush(); 221625dd9d3SDaniel Vetter 222625dd9d3SDaniel Vetter for (i = pg_start; i < (pg_start + mem->page_count); i++) { 223625dd9d3SDaniel Vetter dma_addr_t addr = i << PAGE_SHIFT; 224625dd9d3SDaniel Vetter intel_private.driver->write_entry(addr, 225625dd9d3SDaniel Vetter i, type); 226f51b7662SDaniel Vetter } 227625dd9d3SDaniel Vetter readl(intel_private.gtt+i-1); 228f51b7662SDaniel Vetter 229f51b7662SDaniel Vetter return 0; 230f51b7662SDaniel Vetter } 231f51b7662SDaniel Vetter 232f51b7662SDaniel Vetter /* 233f51b7662SDaniel Vetter * The i810/i830 requires a physical address to program its mouse 234f51b7662SDaniel Vetter * pointer into hardware. 235f51b7662SDaniel Vetter * However the Xserver still writes to it through the agp aperture. 236f51b7662SDaniel Vetter */ 237f51b7662SDaniel Vetter static struct agp_memory *alloc_agpphysmem_i8xx(size_t pg_count, int type) 238f51b7662SDaniel Vetter { 239f51b7662SDaniel Vetter struct agp_memory *new; 240f51b7662SDaniel Vetter struct page *page; 241f51b7662SDaniel Vetter 242f51b7662SDaniel Vetter switch (pg_count) { 243f51b7662SDaniel Vetter case 1: page = agp_bridge->driver->agp_alloc_page(agp_bridge); 244f51b7662SDaniel Vetter break; 245f51b7662SDaniel Vetter case 4: 246f51b7662SDaniel Vetter /* kludge to get 4 physical pages for ARGB cursor */ 247f51b7662SDaniel Vetter page = i8xx_alloc_pages(); 248f51b7662SDaniel Vetter break; 249f51b7662SDaniel Vetter default: 250f51b7662SDaniel Vetter return NULL; 251f51b7662SDaniel Vetter } 252f51b7662SDaniel Vetter 253f51b7662SDaniel Vetter if (page == NULL) 254f51b7662SDaniel Vetter return NULL; 255f51b7662SDaniel Vetter 256f51b7662SDaniel Vetter new = agp_create_memory(pg_count); 257f51b7662SDaniel Vetter if (new == NULL) 258f51b7662SDaniel Vetter return NULL; 259f51b7662SDaniel Vetter 260f51b7662SDaniel Vetter new->pages[0] = page; 261f51b7662SDaniel Vetter if (pg_count == 4) { 262f51b7662SDaniel Vetter /* kludge to get 4 physical pages for ARGB cursor */ 263f51b7662SDaniel Vetter new->pages[1] = new->pages[0] + 1; 264f51b7662SDaniel Vetter new->pages[2] = new->pages[1] + 1; 265f51b7662SDaniel Vetter new->pages[3] = new->pages[2] + 1; 266f51b7662SDaniel Vetter } 267f51b7662SDaniel Vetter new->page_count = pg_count; 268f51b7662SDaniel Vetter new->num_scratch_pages = pg_count; 269f51b7662SDaniel Vetter new->type = AGP_PHYS_MEMORY; 270f51b7662SDaniel Vetter new->physical = page_to_phys(new->pages[0]); 271f51b7662SDaniel Vetter return new; 272f51b7662SDaniel Vetter } 273f51b7662SDaniel Vetter 274f51b7662SDaniel Vetter static void intel_i810_free_by_type(struct agp_memory *curr) 275f51b7662SDaniel Vetter { 276f51b7662SDaniel Vetter agp_free_key(curr->key); 277f51b7662SDaniel Vetter if (curr->type == AGP_PHYS_MEMORY) { 278f51b7662SDaniel Vetter if (curr->page_count == 4) 279f51b7662SDaniel Vetter i8xx_destroy_pages(curr->pages[0]); 280f51b7662SDaniel Vetter else { 281f51b7662SDaniel Vetter agp_bridge->driver->agp_destroy_page(curr->pages[0], 282f51b7662SDaniel Vetter AGP_PAGE_DESTROY_UNMAP); 283f51b7662SDaniel Vetter agp_bridge->driver->agp_destroy_page(curr->pages[0], 284f51b7662SDaniel Vetter AGP_PAGE_DESTROY_FREE); 285f51b7662SDaniel Vetter } 286f51b7662SDaniel Vetter agp_free_page_array(curr); 287f51b7662SDaniel Vetter } 288f51b7662SDaniel Vetter kfree(curr); 289f51b7662SDaniel Vetter } 290f51b7662SDaniel Vetter 2910e87d2b0SDaniel Vetter static int intel_gtt_setup_scratch_page(void) 2920e87d2b0SDaniel Vetter { 2930e87d2b0SDaniel Vetter struct page *page; 2940e87d2b0SDaniel Vetter dma_addr_t dma_addr; 2950e87d2b0SDaniel Vetter 2960e87d2b0SDaniel Vetter page = alloc_page(GFP_KERNEL | GFP_DMA32 | __GFP_ZERO); 2970e87d2b0SDaniel Vetter if (page == NULL) 2980e87d2b0SDaniel Vetter return -ENOMEM; 2990e87d2b0SDaniel Vetter get_page(page); 3000e87d2b0SDaniel Vetter set_pages_uc(page, 1); 3010e87d2b0SDaniel Vetter 3024080775bSDaniel Vetter if (intel_private.base.needs_dmar) { 3030e87d2b0SDaniel Vetter dma_addr = pci_map_page(intel_private.pcidev, page, 0, 3040e87d2b0SDaniel Vetter PAGE_SIZE, PCI_DMA_BIDIRECTIONAL); 3050e87d2b0SDaniel Vetter if (pci_dma_mapping_error(intel_private.pcidev, dma_addr)) 3060e87d2b0SDaniel Vetter return -EINVAL; 3070e87d2b0SDaniel Vetter 30850a4c4a9SDaniel Vetter intel_private.base.scratch_page_dma = dma_addr; 3090e87d2b0SDaniel Vetter } else 31050a4c4a9SDaniel Vetter intel_private.base.scratch_page_dma = page_to_phys(page); 3110e87d2b0SDaniel Vetter 3120e87d2b0SDaniel Vetter intel_private.scratch_page = page; 3130e87d2b0SDaniel Vetter 3140e87d2b0SDaniel Vetter return 0; 3150e87d2b0SDaniel Vetter } 3160e87d2b0SDaniel Vetter 317625dd9d3SDaniel Vetter static void i810_write_entry(dma_addr_t addr, unsigned int entry, 318625dd9d3SDaniel Vetter unsigned int flags) 319625dd9d3SDaniel Vetter { 320625dd9d3SDaniel Vetter u32 pte_flags = I810_PTE_VALID; 321625dd9d3SDaniel Vetter 322625dd9d3SDaniel Vetter switch (flags) { 323625dd9d3SDaniel Vetter case AGP_DCACHE_MEMORY: 324625dd9d3SDaniel Vetter pte_flags |= I810_PTE_LOCAL; 325625dd9d3SDaniel Vetter break; 326625dd9d3SDaniel Vetter case AGP_USER_CACHED_MEMORY: 327625dd9d3SDaniel Vetter pte_flags |= I830_PTE_SYSTEM_CACHED; 328625dd9d3SDaniel Vetter break; 329625dd9d3SDaniel Vetter } 330625dd9d3SDaniel Vetter 331625dd9d3SDaniel Vetter writel(addr | pte_flags, intel_private.gtt + entry); 332625dd9d3SDaniel Vetter } 333625dd9d3SDaniel Vetter 3347bdc9ab0SChris Wilson static const struct aper_size_info_fixed intel_fake_agp_sizes[] = { 335820647b9SDaniel Vetter {32, 8192, 3}, 336820647b9SDaniel Vetter {64, 16384, 4}, 337f51b7662SDaniel Vetter {128, 32768, 5}, 338f51b7662SDaniel Vetter {256, 65536, 6}, 339f51b7662SDaniel Vetter {512, 131072, 7}, 340f51b7662SDaniel Vetter }; 341f51b7662SDaniel Vetter 342c64f7ba5SChris Wilson static unsigned int intel_gtt_stolen_size(void) 343f51b7662SDaniel Vetter { 344f51b7662SDaniel Vetter u16 gmch_ctrl; 345f51b7662SDaniel Vetter u8 rdct; 346f51b7662SDaniel Vetter int local = 0; 347f51b7662SDaniel Vetter static const int ddt[4] = { 0, 16, 32, 64 }; 348d8d9abcdSDaniel Vetter unsigned int stolen_size = 0; 349f51b7662SDaniel Vetter 350820647b9SDaniel Vetter if (INTEL_GTT_GEN == 1) 351820647b9SDaniel Vetter return 0; /* no stolen mem on i81x */ 352820647b9SDaniel Vetter 353d7cca2f7SDaniel Vetter pci_read_config_word(intel_private.bridge_dev, 354d7cca2f7SDaniel Vetter I830_GMCH_CTRL, &gmch_ctrl); 355f51b7662SDaniel Vetter 356d7cca2f7SDaniel Vetter if (intel_private.bridge_dev->device == PCI_DEVICE_ID_INTEL_82830_HB || 357d7cca2f7SDaniel Vetter intel_private.bridge_dev->device == PCI_DEVICE_ID_INTEL_82845G_HB) { 358f51b7662SDaniel Vetter switch (gmch_ctrl & I830_GMCH_GMS_MASK) { 359f51b7662SDaniel Vetter case I830_GMCH_GMS_STOLEN_512: 360d8d9abcdSDaniel Vetter stolen_size = KB(512); 361f51b7662SDaniel Vetter break; 362f51b7662SDaniel Vetter case I830_GMCH_GMS_STOLEN_1024: 363d8d9abcdSDaniel Vetter stolen_size = MB(1); 364f51b7662SDaniel Vetter break; 365f51b7662SDaniel Vetter case I830_GMCH_GMS_STOLEN_8192: 366d8d9abcdSDaniel Vetter stolen_size = MB(8); 367f51b7662SDaniel Vetter break; 368f51b7662SDaniel Vetter case I830_GMCH_GMS_LOCAL: 369f51b7662SDaniel Vetter rdct = readb(intel_private.registers+I830_RDRAM_CHANNEL_TYPE); 370d8d9abcdSDaniel Vetter stolen_size = (I830_RDRAM_ND(rdct) + 1) * 371f51b7662SDaniel Vetter MB(ddt[I830_RDRAM_DDT(rdct)]); 372f51b7662SDaniel Vetter local = 1; 373f51b7662SDaniel Vetter break; 374f51b7662SDaniel Vetter default: 375d8d9abcdSDaniel Vetter stolen_size = 0; 376f51b7662SDaniel Vetter break; 377f51b7662SDaniel Vetter } 3781a997ff2SDaniel Vetter } else if (INTEL_GTT_GEN == 6) { 379f51b7662SDaniel Vetter /* 380f51b7662SDaniel Vetter * SandyBridge has new memory control reg at 0x50.w 381f51b7662SDaniel Vetter */ 382f51b7662SDaniel Vetter u16 snb_gmch_ctl; 383f51b7662SDaniel Vetter pci_read_config_word(intel_private.pcidev, SNB_GMCH_CTRL, &snb_gmch_ctl); 384f51b7662SDaniel Vetter switch (snb_gmch_ctl & SNB_GMCH_GMS_STOLEN_MASK) { 385f51b7662SDaniel Vetter case SNB_GMCH_GMS_STOLEN_32M: 386d8d9abcdSDaniel Vetter stolen_size = MB(32); 387f51b7662SDaniel Vetter break; 388f51b7662SDaniel Vetter case SNB_GMCH_GMS_STOLEN_64M: 389d8d9abcdSDaniel Vetter stolen_size = MB(64); 390f51b7662SDaniel Vetter break; 391f51b7662SDaniel Vetter case SNB_GMCH_GMS_STOLEN_96M: 392d8d9abcdSDaniel Vetter stolen_size = MB(96); 393f51b7662SDaniel Vetter break; 394f51b7662SDaniel Vetter case SNB_GMCH_GMS_STOLEN_128M: 395d8d9abcdSDaniel Vetter stolen_size = MB(128); 396f51b7662SDaniel Vetter break; 397f51b7662SDaniel Vetter case SNB_GMCH_GMS_STOLEN_160M: 398d8d9abcdSDaniel Vetter stolen_size = MB(160); 399f51b7662SDaniel Vetter break; 400f51b7662SDaniel Vetter case SNB_GMCH_GMS_STOLEN_192M: 401d8d9abcdSDaniel Vetter stolen_size = MB(192); 402f51b7662SDaniel Vetter break; 403f51b7662SDaniel Vetter case SNB_GMCH_GMS_STOLEN_224M: 404d8d9abcdSDaniel Vetter stolen_size = MB(224); 405f51b7662SDaniel Vetter break; 406f51b7662SDaniel Vetter case SNB_GMCH_GMS_STOLEN_256M: 407d8d9abcdSDaniel Vetter stolen_size = MB(256); 408f51b7662SDaniel Vetter break; 409f51b7662SDaniel Vetter case SNB_GMCH_GMS_STOLEN_288M: 410d8d9abcdSDaniel Vetter stolen_size = MB(288); 411f51b7662SDaniel Vetter break; 412f51b7662SDaniel Vetter case SNB_GMCH_GMS_STOLEN_320M: 413d8d9abcdSDaniel Vetter stolen_size = MB(320); 414f51b7662SDaniel Vetter break; 415f51b7662SDaniel Vetter case SNB_GMCH_GMS_STOLEN_352M: 416d8d9abcdSDaniel Vetter stolen_size = MB(352); 417f51b7662SDaniel Vetter break; 418f51b7662SDaniel Vetter case SNB_GMCH_GMS_STOLEN_384M: 419d8d9abcdSDaniel Vetter stolen_size = MB(384); 420f51b7662SDaniel Vetter break; 421f51b7662SDaniel Vetter case SNB_GMCH_GMS_STOLEN_416M: 422d8d9abcdSDaniel Vetter stolen_size = MB(416); 423f51b7662SDaniel Vetter break; 424f51b7662SDaniel Vetter case SNB_GMCH_GMS_STOLEN_448M: 425d8d9abcdSDaniel Vetter stolen_size = MB(448); 426f51b7662SDaniel Vetter break; 427f51b7662SDaniel Vetter case SNB_GMCH_GMS_STOLEN_480M: 428d8d9abcdSDaniel Vetter stolen_size = MB(480); 429f51b7662SDaniel Vetter break; 430f51b7662SDaniel Vetter case SNB_GMCH_GMS_STOLEN_512M: 431d8d9abcdSDaniel Vetter stolen_size = MB(512); 432f51b7662SDaniel Vetter break; 433f51b7662SDaniel Vetter } 434f51b7662SDaniel Vetter } else { 435f51b7662SDaniel Vetter switch (gmch_ctrl & I855_GMCH_GMS_MASK) { 436f51b7662SDaniel Vetter case I855_GMCH_GMS_STOLEN_1M: 437d8d9abcdSDaniel Vetter stolen_size = MB(1); 438f51b7662SDaniel Vetter break; 439f51b7662SDaniel Vetter case I855_GMCH_GMS_STOLEN_4M: 440d8d9abcdSDaniel Vetter stolen_size = MB(4); 441f51b7662SDaniel Vetter break; 442f51b7662SDaniel Vetter case I855_GMCH_GMS_STOLEN_8M: 443d8d9abcdSDaniel Vetter stolen_size = MB(8); 444f51b7662SDaniel Vetter break; 445f51b7662SDaniel Vetter case I855_GMCH_GMS_STOLEN_16M: 446d8d9abcdSDaniel Vetter stolen_size = MB(16); 447f51b7662SDaniel Vetter break; 448f51b7662SDaniel Vetter case I855_GMCH_GMS_STOLEN_32M: 449d8d9abcdSDaniel Vetter stolen_size = MB(32); 450f51b7662SDaniel Vetter break; 451f51b7662SDaniel Vetter case I915_GMCH_GMS_STOLEN_48M: 452d8d9abcdSDaniel Vetter stolen_size = MB(48); 453f51b7662SDaniel Vetter break; 454f51b7662SDaniel Vetter case I915_GMCH_GMS_STOLEN_64M: 455d8d9abcdSDaniel Vetter stolen_size = MB(64); 456f51b7662SDaniel Vetter break; 457f51b7662SDaniel Vetter case G33_GMCH_GMS_STOLEN_128M: 458d8d9abcdSDaniel Vetter stolen_size = MB(128); 459f51b7662SDaniel Vetter break; 460f51b7662SDaniel Vetter case G33_GMCH_GMS_STOLEN_256M: 461d8d9abcdSDaniel Vetter stolen_size = MB(256); 462f51b7662SDaniel Vetter break; 463f51b7662SDaniel Vetter case INTEL_GMCH_GMS_STOLEN_96M: 464d8d9abcdSDaniel Vetter stolen_size = MB(96); 465f51b7662SDaniel Vetter break; 466f51b7662SDaniel Vetter case INTEL_GMCH_GMS_STOLEN_160M: 467d8d9abcdSDaniel Vetter stolen_size = MB(160); 468f51b7662SDaniel Vetter break; 469f51b7662SDaniel Vetter case INTEL_GMCH_GMS_STOLEN_224M: 470d8d9abcdSDaniel Vetter stolen_size = MB(224); 471f51b7662SDaniel Vetter break; 472f51b7662SDaniel Vetter case INTEL_GMCH_GMS_STOLEN_352M: 473d8d9abcdSDaniel Vetter stolen_size = MB(352); 474f51b7662SDaniel Vetter break; 475f51b7662SDaniel Vetter default: 476d8d9abcdSDaniel Vetter stolen_size = 0; 477f51b7662SDaniel Vetter break; 478f51b7662SDaniel Vetter } 479f51b7662SDaniel Vetter } 4801784a5fbSDaniel Vetter 4811b6064d7SChris Wilson if (stolen_size > 0) { 482d7cca2f7SDaniel Vetter dev_info(&intel_private.bridge_dev->dev, "detected %dK %s memory\n", 483d8d9abcdSDaniel Vetter stolen_size / KB(1), local ? "local" : "stolen"); 484f51b7662SDaniel Vetter } else { 485d7cca2f7SDaniel Vetter dev_info(&intel_private.bridge_dev->dev, 486f51b7662SDaniel Vetter "no pre-allocated video memory detected\n"); 487d8d9abcdSDaniel Vetter stolen_size = 0; 488f51b7662SDaniel Vetter } 489f51b7662SDaniel Vetter 490c64f7ba5SChris Wilson return stolen_size; 491f51b7662SDaniel Vetter } 492f51b7662SDaniel Vetter 49320172842SDaniel Vetter static void i965_adjust_pgetbl_size(unsigned int size_flag) 49420172842SDaniel Vetter { 49520172842SDaniel Vetter u32 pgetbl_ctl, pgetbl_ctl2; 49620172842SDaniel Vetter 49720172842SDaniel Vetter /* ensure that ppgtt is disabled */ 49820172842SDaniel Vetter pgetbl_ctl2 = readl(intel_private.registers+I965_PGETBL_CTL2); 49920172842SDaniel Vetter pgetbl_ctl2 &= ~I810_PGETBL_ENABLED; 50020172842SDaniel Vetter writel(pgetbl_ctl2, intel_private.registers+I965_PGETBL_CTL2); 50120172842SDaniel Vetter 50220172842SDaniel Vetter /* write the new ggtt size */ 50320172842SDaniel Vetter pgetbl_ctl = readl(intel_private.registers+I810_PGETBL_CTL); 50420172842SDaniel Vetter pgetbl_ctl &= ~I965_PGETBL_SIZE_MASK; 50520172842SDaniel Vetter pgetbl_ctl |= size_flag; 50620172842SDaniel Vetter writel(pgetbl_ctl, intel_private.registers+I810_PGETBL_CTL); 50720172842SDaniel Vetter } 50820172842SDaniel Vetter 50920172842SDaniel Vetter static unsigned int i965_gtt_total_entries(void) 510fbe40783SDaniel Vetter { 511fbe40783SDaniel Vetter int size; 512fbe40783SDaniel Vetter u32 pgetbl_ctl; 51320172842SDaniel Vetter u16 gmch_ctl; 51420172842SDaniel Vetter 51520172842SDaniel Vetter pci_read_config_word(intel_private.bridge_dev, 51620172842SDaniel Vetter I830_GMCH_CTRL, &gmch_ctl); 51720172842SDaniel Vetter 51820172842SDaniel Vetter if (INTEL_GTT_GEN == 5) { 51920172842SDaniel Vetter switch (gmch_ctl & G4x_GMCH_SIZE_MASK) { 52020172842SDaniel Vetter case G4x_GMCH_SIZE_1M: 52120172842SDaniel Vetter case G4x_GMCH_SIZE_VT_1M: 52220172842SDaniel Vetter i965_adjust_pgetbl_size(I965_PGETBL_SIZE_1MB); 52320172842SDaniel Vetter break; 52420172842SDaniel Vetter case G4x_GMCH_SIZE_VT_1_5M: 52520172842SDaniel Vetter i965_adjust_pgetbl_size(I965_PGETBL_SIZE_1_5MB); 52620172842SDaniel Vetter break; 52720172842SDaniel Vetter case G4x_GMCH_SIZE_2M: 52820172842SDaniel Vetter case G4x_GMCH_SIZE_VT_2M: 52920172842SDaniel Vetter i965_adjust_pgetbl_size(I965_PGETBL_SIZE_2MB); 53020172842SDaniel Vetter break; 53120172842SDaniel Vetter } 53220172842SDaniel Vetter } 53320172842SDaniel Vetter 534fbe40783SDaniel Vetter pgetbl_ctl = readl(intel_private.registers+I810_PGETBL_CTL); 535fbe40783SDaniel Vetter 536fbe40783SDaniel Vetter switch (pgetbl_ctl & I965_PGETBL_SIZE_MASK) { 537fbe40783SDaniel Vetter case I965_PGETBL_SIZE_128KB: 538e5e408fcSDaniel Vetter size = KB(128); 539fbe40783SDaniel Vetter break; 540fbe40783SDaniel Vetter case I965_PGETBL_SIZE_256KB: 541e5e408fcSDaniel Vetter size = KB(256); 542fbe40783SDaniel Vetter break; 543fbe40783SDaniel Vetter case I965_PGETBL_SIZE_512KB: 544e5e408fcSDaniel Vetter size = KB(512); 545fbe40783SDaniel Vetter break; 54620172842SDaniel Vetter /* GTT pagetable sizes bigger than 512KB are not possible on G33! */ 547fbe40783SDaniel Vetter case I965_PGETBL_SIZE_1MB: 548e5e408fcSDaniel Vetter size = KB(1024); 549fbe40783SDaniel Vetter break; 550fbe40783SDaniel Vetter case I965_PGETBL_SIZE_2MB: 551e5e408fcSDaniel Vetter size = KB(2048); 552fbe40783SDaniel Vetter break; 553fbe40783SDaniel Vetter case I965_PGETBL_SIZE_1_5MB: 554e5e408fcSDaniel Vetter size = KB(1024 + 512); 555fbe40783SDaniel Vetter break; 556fbe40783SDaniel Vetter default: 557fbe40783SDaniel Vetter dev_info(&intel_private.pcidev->dev, 558fbe40783SDaniel Vetter "unknown page table size, assuming 512KB\n"); 559e5e408fcSDaniel Vetter size = KB(512); 560fbe40783SDaniel Vetter } 561e5e408fcSDaniel Vetter 562e5e408fcSDaniel Vetter return size/4; 56320172842SDaniel Vetter } 56420172842SDaniel Vetter 56520172842SDaniel Vetter static unsigned int intel_gtt_total_entries(void) 56620172842SDaniel Vetter { 56720172842SDaniel Vetter int size; 56820172842SDaniel Vetter 56920172842SDaniel Vetter if (IS_G33 || INTEL_GTT_GEN == 4 || INTEL_GTT_GEN == 5) 57020172842SDaniel Vetter return i965_gtt_total_entries(); 57120172842SDaniel Vetter else if (INTEL_GTT_GEN == 6) { 572210b23c2SDaniel Vetter u16 snb_gmch_ctl; 573210b23c2SDaniel Vetter 574210b23c2SDaniel Vetter pci_read_config_word(intel_private.pcidev, SNB_GMCH_CTRL, &snb_gmch_ctl); 575210b23c2SDaniel Vetter switch (snb_gmch_ctl & SNB_GTT_SIZE_MASK) { 576210b23c2SDaniel Vetter default: 577210b23c2SDaniel Vetter case SNB_GTT_SIZE_0M: 578210b23c2SDaniel Vetter printk(KERN_ERR "Bad GTT size mask: 0x%04x.\n", snb_gmch_ctl); 579210b23c2SDaniel Vetter size = MB(0); 580210b23c2SDaniel Vetter break; 581210b23c2SDaniel Vetter case SNB_GTT_SIZE_1M: 582210b23c2SDaniel Vetter size = MB(1); 583210b23c2SDaniel Vetter break; 584210b23c2SDaniel Vetter case SNB_GTT_SIZE_2M: 585210b23c2SDaniel Vetter size = MB(2); 586210b23c2SDaniel Vetter break; 587210b23c2SDaniel Vetter } 588210b23c2SDaniel Vetter return size/4; 589fbe40783SDaniel Vetter } else { 590fbe40783SDaniel Vetter /* On previous hardware, the GTT size was just what was 591fbe40783SDaniel Vetter * required to map the aperture. 592fbe40783SDaniel Vetter */ 593e5e408fcSDaniel Vetter return intel_private.base.gtt_mappable_entries; 594fbe40783SDaniel Vetter } 595fbe40783SDaniel Vetter } 596fbe40783SDaniel Vetter 5971784a5fbSDaniel Vetter static unsigned int intel_gtt_mappable_entries(void) 5981784a5fbSDaniel Vetter { 5991784a5fbSDaniel Vetter unsigned int aperture_size; 6001784a5fbSDaniel Vetter 601820647b9SDaniel Vetter if (INTEL_GTT_GEN == 1) { 602820647b9SDaniel Vetter u32 smram_miscc; 603820647b9SDaniel Vetter 604820647b9SDaniel Vetter pci_read_config_dword(intel_private.bridge_dev, 605820647b9SDaniel Vetter I810_SMRAM_MISCC, &smram_miscc); 606820647b9SDaniel Vetter 607820647b9SDaniel Vetter if ((smram_miscc & I810_GFX_MEM_WIN_SIZE) 608820647b9SDaniel Vetter == I810_GFX_MEM_WIN_32M) 609820647b9SDaniel Vetter aperture_size = MB(32); 610820647b9SDaniel Vetter else 611820647b9SDaniel Vetter aperture_size = MB(64); 612820647b9SDaniel Vetter } else if (INTEL_GTT_GEN == 2) { 613b1c5b0f8SChris Wilson u16 gmch_ctrl; 6141784a5fbSDaniel Vetter 6151784a5fbSDaniel Vetter pci_read_config_word(intel_private.bridge_dev, 6161784a5fbSDaniel Vetter I830_GMCH_CTRL, &gmch_ctrl); 6171784a5fbSDaniel Vetter 6181784a5fbSDaniel Vetter if ((gmch_ctrl & I830_GMCH_MEM_MASK) == I830_GMCH_MEM_64M) 619b1c5b0f8SChris Wilson aperture_size = MB(64); 6201784a5fbSDaniel Vetter else 621b1c5b0f8SChris Wilson aperture_size = MB(128); 622239918f7SDaniel Vetter } else { 6231784a5fbSDaniel Vetter /* 9xx supports large sizes, just look at the length */ 6241784a5fbSDaniel Vetter aperture_size = pci_resource_len(intel_private.pcidev, 2); 6251784a5fbSDaniel Vetter } 6261784a5fbSDaniel Vetter 6271784a5fbSDaniel Vetter return aperture_size >> PAGE_SHIFT; 6281784a5fbSDaniel Vetter } 6291784a5fbSDaniel Vetter 6300e87d2b0SDaniel Vetter static void intel_gtt_teardown_scratch_page(void) 6310e87d2b0SDaniel Vetter { 6320e87d2b0SDaniel Vetter set_pages_wb(intel_private.scratch_page, 1); 63350a4c4a9SDaniel Vetter pci_unmap_page(intel_private.pcidev, intel_private.base.scratch_page_dma, 6340e87d2b0SDaniel Vetter PAGE_SIZE, PCI_DMA_BIDIRECTIONAL); 6350e87d2b0SDaniel Vetter put_page(intel_private.scratch_page); 6360e87d2b0SDaniel Vetter __free_page(intel_private.scratch_page); 6370e87d2b0SDaniel Vetter } 6380e87d2b0SDaniel Vetter 6390e87d2b0SDaniel Vetter static void intel_gtt_cleanup(void) 6400e87d2b0SDaniel Vetter { 641ae83dd5cSDaniel Vetter intel_private.driver->cleanup(); 642ae83dd5cSDaniel Vetter 6430e87d2b0SDaniel Vetter iounmap(intel_private.gtt); 6440e87d2b0SDaniel Vetter iounmap(intel_private.registers); 6450e87d2b0SDaniel Vetter 6460e87d2b0SDaniel Vetter intel_gtt_teardown_scratch_page(); 6470e87d2b0SDaniel Vetter } 6480e87d2b0SDaniel Vetter 6491784a5fbSDaniel Vetter static int intel_gtt_init(void) 6501784a5fbSDaniel Vetter { 65132e3cd6eSDaniel Vetter u32 gma_addr; 652f67eab66SDaniel Vetter u32 gtt_map_size; 6533b15a9d7SDaniel Vetter int ret; 6543b15a9d7SDaniel Vetter 6553b15a9d7SDaniel Vetter ret = intel_private.driver->setup(); 6563b15a9d7SDaniel Vetter if (ret != 0) 6573b15a9d7SDaniel Vetter return ret; 658f67eab66SDaniel Vetter 659f67eab66SDaniel Vetter intel_private.base.gtt_mappable_entries = intel_gtt_mappable_entries(); 660f67eab66SDaniel Vetter intel_private.base.gtt_total_entries = intel_gtt_total_entries(); 661f67eab66SDaniel Vetter 662b3eafc5aSDaniel Vetter /* save the PGETBL reg for resume */ 663b3eafc5aSDaniel Vetter intel_private.PGETBL_save = 664b3eafc5aSDaniel Vetter readl(intel_private.registers+I810_PGETBL_CTL) 665b3eafc5aSDaniel Vetter & ~I810_PGETBL_ENABLED; 666100519e2SChris Wilson /* we only ever restore the register when enabling the PGTBL... */ 667100519e2SChris Wilson if (HAS_PGTBL_EN) 668100519e2SChris Wilson intel_private.PGETBL_save |= I810_PGETBL_ENABLED; 669b3eafc5aSDaniel Vetter 6700af9e92eSDaniel Vetter dev_info(&intel_private.bridge_dev->dev, 6710af9e92eSDaniel Vetter "detected gtt size: %dK total, %dK mappable\n", 6720af9e92eSDaniel Vetter intel_private.base.gtt_total_entries * 4, 6730af9e92eSDaniel Vetter intel_private.base.gtt_mappable_entries * 4); 6740af9e92eSDaniel Vetter 675f67eab66SDaniel Vetter gtt_map_size = intel_private.base.gtt_total_entries * 4; 676f67eab66SDaniel Vetter 677f67eab66SDaniel Vetter intel_private.gtt = ioremap(intel_private.gtt_bus_addr, 678f67eab66SDaniel Vetter gtt_map_size); 679f67eab66SDaniel Vetter if (!intel_private.gtt) { 680ae83dd5cSDaniel Vetter intel_private.driver->cleanup(); 681f67eab66SDaniel Vetter iounmap(intel_private.registers); 682f67eab66SDaniel Vetter return -ENOMEM; 683f67eab66SDaniel Vetter } 684428ccb21SDaniel Vetter intel_private.base.gtt = intel_private.gtt; 685f67eab66SDaniel Vetter 686f67eab66SDaniel Vetter global_cache_flush(); /* FIXME: ? */ 687f67eab66SDaniel Vetter 688c64f7ba5SChris Wilson intel_private.base.stolen_size = intel_gtt_stolen_size(); 6891784a5fbSDaniel Vetter 690a46f3108SDave Airlie intel_private.base.needs_dmar = USE_PCI_DMA_API && INTEL_GTT_GEN > 2; 691a46f3108SDave Airlie 6920e87d2b0SDaniel Vetter ret = intel_gtt_setup_scratch_page(); 6930e87d2b0SDaniel Vetter if (ret != 0) { 6940e87d2b0SDaniel Vetter intel_gtt_cleanup(); 6950e87d2b0SDaniel Vetter return ret; 6960e87d2b0SDaniel Vetter } 6970e87d2b0SDaniel Vetter 69832e3cd6eSDaniel Vetter if (INTEL_GTT_GEN <= 2) 69932e3cd6eSDaniel Vetter pci_read_config_dword(intel_private.pcidev, I810_GMADDR, 70032e3cd6eSDaniel Vetter &gma_addr); 70132e3cd6eSDaniel Vetter else 70232e3cd6eSDaniel Vetter pci_read_config_dword(intel_private.pcidev, I915_GMADDR, 70332e3cd6eSDaniel Vetter &gma_addr); 70432e3cd6eSDaniel Vetter 70532e3cd6eSDaniel Vetter intel_private.base.gma_bus_addr = (gma_addr & PCI_BASE_ADDRESS_MEM_MASK); 70632e3cd6eSDaniel Vetter 7071784a5fbSDaniel Vetter return 0; 7081784a5fbSDaniel Vetter } 7091784a5fbSDaniel Vetter 7103e921f98SDaniel Vetter static int intel_fake_agp_fetch_size(void) 7113e921f98SDaniel Vetter { 7129e76e7b8SChris Wilson int num_sizes = ARRAY_SIZE(intel_fake_agp_sizes); 7133e921f98SDaniel Vetter unsigned int aper_size; 7143e921f98SDaniel Vetter int i; 7153e921f98SDaniel Vetter 7163e921f98SDaniel Vetter aper_size = (intel_private.base.gtt_mappable_entries << PAGE_SHIFT) 7173e921f98SDaniel Vetter / MB(1); 7183e921f98SDaniel Vetter 7193e921f98SDaniel Vetter for (i = 0; i < num_sizes; i++) { 720ffdd7510SDaniel Vetter if (aper_size == intel_fake_agp_sizes[i].size) { 7219e76e7b8SChris Wilson agp_bridge->current_size = 7229e76e7b8SChris Wilson (void *) (intel_fake_agp_sizes + i); 7233e921f98SDaniel Vetter return aper_size; 7243e921f98SDaniel Vetter } 7253e921f98SDaniel Vetter } 7263e921f98SDaniel Vetter 7273e921f98SDaniel Vetter return 0; 7283e921f98SDaniel Vetter } 7293e921f98SDaniel Vetter 730ae83dd5cSDaniel Vetter static void i830_cleanup(void) 731f51b7662SDaniel Vetter { 732f51b7662SDaniel Vetter } 733f51b7662SDaniel Vetter 734f51b7662SDaniel Vetter /* The chipset_flush interface needs to get data that has already been 735f51b7662SDaniel Vetter * flushed out of the CPU all the way out to main memory, because the GPU 736f51b7662SDaniel Vetter * doesn't snoop those buffers. 737f51b7662SDaniel Vetter * 738f51b7662SDaniel Vetter * The 8xx series doesn't have the same lovely interface for flushing the 739f51b7662SDaniel Vetter * chipset write buffers that the later chips do. According to the 865 740f51b7662SDaniel Vetter * specs, it's 64 octwords, or 1KB. So, to get those previous things in 741f51b7662SDaniel Vetter * that buffer out, we just fill 1KB and clflush it out, on the assumption 742f51b7662SDaniel Vetter * that it'll push whatever was in there out. It appears to work. 743f51b7662SDaniel Vetter */ 7441b263f24SDaniel Vetter static void i830_chipset_flush(void) 745f51b7662SDaniel Vetter { 746bdb8b975SChris Wilson unsigned long timeout = jiffies + msecs_to_jiffies(1000); 747f51b7662SDaniel Vetter 748bdb8b975SChris Wilson /* Forcibly evict everything from the CPU write buffers. 749bdb8b975SChris Wilson * clflush appears to be insufficient. 750bdb8b975SChris Wilson */ 751bdb8b975SChris Wilson wbinvd_on_all_cpus(); 752f51b7662SDaniel Vetter 753bdb8b975SChris Wilson /* Now we've only seen documents for this magic bit on 855GM, 754bdb8b975SChris Wilson * we hope it exists for the other gen2 chipsets... 755bdb8b975SChris Wilson * 756bdb8b975SChris Wilson * Also works as advertised on my 845G. 757bdb8b975SChris Wilson */ 758bdb8b975SChris Wilson writel(readl(intel_private.registers+I830_HIC) | (1<<31), 759bdb8b975SChris Wilson intel_private.registers+I830_HIC); 760bdb8b975SChris Wilson 761bdb8b975SChris Wilson while (readl(intel_private.registers+I830_HIC) & (1<<31)) { 762bdb8b975SChris Wilson if (time_after(jiffies, timeout)) 763bdb8b975SChris Wilson break; 764bdb8b975SChris Wilson 765bdb8b975SChris Wilson udelay(50); 766bdb8b975SChris Wilson } 767f51b7662SDaniel Vetter } 768f51b7662SDaniel Vetter 769351bb278SDaniel Vetter static void i830_write_entry(dma_addr_t addr, unsigned int entry, 770351bb278SDaniel Vetter unsigned int flags) 771351bb278SDaniel Vetter { 772351bb278SDaniel Vetter u32 pte_flags = I810_PTE_VALID; 773351bb278SDaniel Vetter 774b47cf66fSDaniel Vetter if (flags == AGP_USER_CACHED_MEMORY) 775351bb278SDaniel Vetter pte_flags |= I830_PTE_SYSTEM_CACHED; 776351bb278SDaniel Vetter 777351bb278SDaniel Vetter writel(addr | pte_flags, intel_private.gtt + entry); 778351bb278SDaniel Vetter } 779351bb278SDaniel Vetter 7808ecd1a66SDaniel Vetter bool intel_enable_gtt(void) 78173800422SDaniel Vetter { 782e380f60bSChris Wilson u8 __iomem *reg; 78373800422SDaniel Vetter 784e380f60bSChris Wilson if (INTEL_GTT_GEN >= 6) 785e380f60bSChris Wilson return true; 78673800422SDaniel Vetter 787100519e2SChris Wilson if (INTEL_GTT_GEN == 2) { 788100519e2SChris Wilson u16 gmch_ctrl; 789100519e2SChris Wilson 790e380f60bSChris Wilson pci_read_config_word(intel_private.bridge_dev, 791e380f60bSChris Wilson I830_GMCH_CTRL, &gmch_ctrl); 792e380f60bSChris Wilson gmch_ctrl |= I830_GMCH_ENABLED; 793e380f60bSChris Wilson pci_write_config_word(intel_private.bridge_dev, 794e380f60bSChris Wilson I830_GMCH_CTRL, gmch_ctrl); 795e380f60bSChris Wilson 796e380f60bSChris Wilson pci_read_config_word(intel_private.bridge_dev, 797e380f60bSChris Wilson I830_GMCH_CTRL, &gmch_ctrl); 798e380f60bSChris Wilson if ((gmch_ctrl & I830_GMCH_ENABLED) == 0) { 799e380f60bSChris Wilson dev_err(&intel_private.pcidev->dev, 800e380f60bSChris Wilson "failed to enable the GTT: GMCH_CTRL=%x\n", 801e380f60bSChris Wilson gmch_ctrl); 802e380f60bSChris Wilson return false; 803e380f60bSChris Wilson } 804100519e2SChris Wilson } 805e380f60bSChris Wilson 806c97689d8SChris Wilson /* On the resume path we may be adjusting the PGTBL value, so 807c97689d8SChris Wilson * be paranoid and flush all chipset write buffers... 808c97689d8SChris Wilson */ 809c97689d8SChris Wilson if (INTEL_GTT_GEN >= 3) 810c97689d8SChris Wilson writel(0, intel_private.registers+GFX_FLSH_CNTL); 811c97689d8SChris Wilson 812e380f60bSChris Wilson reg = intel_private.registers+I810_PGETBL_CTL; 813100519e2SChris Wilson writel(intel_private.PGETBL_save, reg); 814100519e2SChris Wilson if (HAS_PGTBL_EN && (readl(reg) & I810_PGETBL_ENABLED) == 0) { 815e380f60bSChris Wilson dev_err(&intel_private.pcidev->dev, 816100519e2SChris Wilson "failed to enable the GTT: PGETBL=%x [expected %x]\n", 817e380f60bSChris Wilson readl(reg), intel_private.PGETBL_save); 818e380f60bSChris Wilson return false; 819e380f60bSChris Wilson } 820e380f60bSChris Wilson 821c97689d8SChris Wilson if (INTEL_GTT_GEN >= 3) 822c97689d8SChris Wilson writel(0, intel_private.registers+GFX_FLSH_CNTL); 823c97689d8SChris Wilson 824e380f60bSChris Wilson return true; 82573800422SDaniel Vetter } 8268ecd1a66SDaniel Vetter EXPORT_SYMBOL(intel_enable_gtt); 82773800422SDaniel Vetter 82873800422SDaniel Vetter static int i830_setup(void) 82973800422SDaniel Vetter { 83073800422SDaniel Vetter u32 reg_addr; 83173800422SDaniel Vetter 83273800422SDaniel Vetter pci_read_config_dword(intel_private.pcidev, I810_MMADDR, ®_addr); 83373800422SDaniel Vetter reg_addr &= 0xfff80000; 83473800422SDaniel Vetter 83573800422SDaniel Vetter intel_private.registers = ioremap(reg_addr, KB(64)); 83673800422SDaniel Vetter if (!intel_private.registers) 83773800422SDaniel Vetter return -ENOMEM; 83873800422SDaniel Vetter 83973800422SDaniel Vetter intel_private.gtt_bus_addr = reg_addr + I810_PTE_BASE; 84073800422SDaniel Vetter 84173800422SDaniel Vetter return 0; 84273800422SDaniel Vetter } 84373800422SDaniel Vetter 8443b15a9d7SDaniel Vetter static int intel_fake_agp_create_gatt_table(struct agp_bridge_data *bridge) 845f51b7662SDaniel Vetter { 84673800422SDaniel Vetter agp_bridge->gatt_table_real = NULL; 847f51b7662SDaniel Vetter agp_bridge->gatt_table = NULL; 84873800422SDaniel Vetter agp_bridge->gatt_bus_addr = 0; 849f51b7662SDaniel Vetter 850f51b7662SDaniel Vetter return 0; 851f51b7662SDaniel Vetter } 852f51b7662SDaniel Vetter 853ffdd7510SDaniel Vetter static int intel_fake_agp_free_gatt_table(struct agp_bridge_data *bridge) 854f51b7662SDaniel Vetter { 855f51b7662SDaniel Vetter return 0; 856f51b7662SDaniel Vetter } 857f51b7662SDaniel Vetter 858351bb278SDaniel Vetter static int intel_fake_agp_configure(void) 859f51b7662SDaniel Vetter { 860e380f60bSChris Wilson if (!intel_enable_gtt()) 861e380f60bSChris Wilson return -EIO; 862f51b7662SDaniel Vetter 863bee4a186SChris Wilson intel_private.clear_fake_agp = true; 864dd2757f8SDaniel Vetter agp_bridge->gart_bus_addr = intel_private.base.gma_bus_addr; 865f51b7662SDaniel Vetter 866f51b7662SDaniel Vetter return 0; 867f51b7662SDaniel Vetter } 868f51b7662SDaniel Vetter 8695cbecafcSDaniel Vetter static bool i830_check_flags(unsigned int flags) 870f51b7662SDaniel Vetter { 8715cbecafcSDaniel Vetter switch (flags) { 8725cbecafcSDaniel Vetter case 0: 8735cbecafcSDaniel Vetter case AGP_PHYS_MEMORY: 8745cbecafcSDaniel Vetter case AGP_USER_CACHED_MEMORY: 8755cbecafcSDaniel Vetter case AGP_USER_MEMORY: 8765cbecafcSDaniel Vetter return true; 8775cbecafcSDaniel Vetter } 8785cbecafcSDaniel Vetter 8795cbecafcSDaniel Vetter return false; 8805cbecafcSDaniel Vetter } 8815cbecafcSDaniel Vetter 8824080775bSDaniel Vetter void intel_gtt_insert_sg_entries(struct scatterlist *sg_list, 883fefaa70fSDaniel Vetter unsigned int sg_len, 884fefaa70fSDaniel Vetter unsigned int pg_start, 885fefaa70fSDaniel Vetter unsigned int flags) 886fefaa70fSDaniel Vetter { 887fefaa70fSDaniel Vetter struct scatterlist *sg; 888fefaa70fSDaniel Vetter unsigned int len, m; 889fefaa70fSDaniel Vetter int i, j; 890fefaa70fSDaniel Vetter 891fefaa70fSDaniel Vetter j = pg_start; 892fefaa70fSDaniel Vetter 893fefaa70fSDaniel Vetter /* sg may merge pages, but we have to separate 894fefaa70fSDaniel Vetter * per-page addr for GTT */ 895fefaa70fSDaniel Vetter for_each_sg(sg_list, sg, sg_len, i) { 896fefaa70fSDaniel Vetter len = sg_dma_len(sg) >> PAGE_SHIFT; 897fefaa70fSDaniel Vetter for (m = 0; m < len; m++) { 898fefaa70fSDaniel Vetter dma_addr_t addr = sg_dma_address(sg) + (m << PAGE_SHIFT); 899fefaa70fSDaniel Vetter intel_private.driver->write_entry(addr, 900fefaa70fSDaniel Vetter j, flags); 901fefaa70fSDaniel Vetter j++; 902fefaa70fSDaniel Vetter } 903fefaa70fSDaniel Vetter } 904fefaa70fSDaniel Vetter readl(intel_private.gtt+j-1); 905fefaa70fSDaniel Vetter } 9064080775bSDaniel Vetter EXPORT_SYMBOL(intel_gtt_insert_sg_entries); 9074080775bSDaniel Vetter 9084080775bSDaniel Vetter void intel_gtt_insert_pages(unsigned int first_entry, unsigned int num_entries, 9094080775bSDaniel Vetter struct page **pages, unsigned int flags) 9104080775bSDaniel Vetter { 9114080775bSDaniel Vetter int i, j; 9124080775bSDaniel Vetter 9134080775bSDaniel Vetter for (i = 0, j = first_entry; i < num_entries; i++, j++) { 9144080775bSDaniel Vetter dma_addr_t addr = page_to_phys(pages[i]); 9154080775bSDaniel Vetter intel_private.driver->write_entry(addr, 9164080775bSDaniel Vetter j, flags); 9174080775bSDaniel Vetter } 9184080775bSDaniel Vetter readl(intel_private.gtt+j-1); 9194080775bSDaniel Vetter } 9204080775bSDaniel Vetter EXPORT_SYMBOL(intel_gtt_insert_pages); 921fefaa70fSDaniel Vetter 9225cbecafcSDaniel Vetter static int intel_fake_agp_insert_entries(struct agp_memory *mem, 9235cbecafcSDaniel Vetter off_t pg_start, int type) 9245cbecafcSDaniel Vetter { 925f51b7662SDaniel Vetter int ret = -EINVAL; 926f51b7662SDaniel Vetter 9275c042287SBen Widawsky if (intel_private.base.do_idle_maps) 9285c042287SBen Widawsky return -ENODEV; 9295c042287SBen Widawsky 930bee4a186SChris Wilson if (intel_private.clear_fake_agp) { 931bee4a186SChris Wilson int start = intel_private.base.stolen_size / PAGE_SIZE; 932bee4a186SChris Wilson int end = intel_private.base.gtt_mappable_entries; 933bee4a186SChris Wilson intel_gtt_clear_range(start, end - start); 934bee4a186SChris Wilson intel_private.clear_fake_agp = false; 935bee4a186SChris Wilson } 936bee4a186SChris Wilson 937ff26860fSDaniel Vetter if (INTEL_GTT_GEN == 1 && type == AGP_DCACHE_MEMORY) 938ff26860fSDaniel Vetter return i810_insert_dcache_entries(mem, pg_start, type); 939ff26860fSDaniel Vetter 940f51b7662SDaniel Vetter if (mem->page_count == 0) 941f51b7662SDaniel Vetter goto out; 942f51b7662SDaniel Vetter 943c64f7ba5SChris Wilson if (pg_start + mem->page_count > intel_private.base.gtt_total_entries) 944f51b7662SDaniel Vetter goto out_err; 945f51b7662SDaniel Vetter 946f51b7662SDaniel Vetter if (type != mem->type) 947f51b7662SDaniel Vetter goto out_err; 948f51b7662SDaniel Vetter 9495cbecafcSDaniel Vetter if (!intel_private.driver->check_flags(type)) 950f51b7662SDaniel Vetter goto out_err; 951f51b7662SDaniel Vetter 952f51b7662SDaniel Vetter if (!mem->is_flushed) 953f51b7662SDaniel Vetter global_cache_flush(); 954f51b7662SDaniel Vetter 9554080775bSDaniel Vetter if (intel_private.base.needs_dmar) { 9564080775bSDaniel Vetter ret = intel_gtt_map_memory(mem->pages, mem->page_count, 9574080775bSDaniel Vetter &mem->sg_list, &mem->num_sg); 958fefaa70fSDaniel Vetter if (ret != 0) 959fefaa70fSDaniel Vetter return ret; 960fefaa70fSDaniel Vetter 961fefaa70fSDaniel Vetter intel_gtt_insert_sg_entries(mem->sg_list, mem->num_sg, 962fefaa70fSDaniel Vetter pg_start, type); 9634080775bSDaniel Vetter } else 9644080775bSDaniel Vetter intel_gtt_insert_pages(pg_start, mem->page_count, mem->pages, 9654080775bSDaniel Vetter type); 966f51b7662SDaniel Vetter 967f51b7662SDaniel Vetter out: 968f51b7662SDaniel Vetter ret = 0; 969f51b7662SDaniel Vetter out_err: 970f51b7662SDaniel Vetter mem->is_flushed = true; 971f51b7662SDaniel Vetter return ret; 972f51b7662SDaniel Vetter } 973f51b7662SDaniel Vetter 9744080775bSDaniel Vetter void intel_gtt_clear_range(unsigned int first_entry, unsigned int num_entries) 975f51b7662SDaniel Vetter { 9764080775bSDaniel Vetter unsigned int i; 977f51b7662SDaniel Vetter 9784080775bSDaniel Vetter for (i = first_entry; i < (first_entry + num_entries); i++) { 97950a4c4a9SDaniel Vetter intel_private.driver->write_entry(intel_private.base.scratch_page_dma, 9805cbecafcSDaniel Vetter i, 0); 981f51b7662SDaniel Vetter } 982fdfb58a9SDaniel Vetter readl(intel_private.gtt+i-1); 9834080775bSDaniel Vetter } 9844080775bSDaniel Vetter EXPORT_SYMBOL(intel_gtt_clear_range); 9854080775bSDaniel Vetter 9864080775bSDaniel Vetter static int intel_fake_agp_remove_entries(struct agp_memory *mem, 9874080775bSDaniel Vetter off_t pg_start, int type) 9884080775bSDaniel Vetter { 9894080775bSDaniel Vetter if (mem->page_count == 0) 9904080775bSDaniel Vetter return 0; 9914080775bSDaniel Vetter 9925c042287SBen Widawsky if (intel_private.base.do_idle_maps) 9935c042287SBen Widawsky return -ENODEV; 9945c042287SBen Widawsky 995d15eda5cSDave Airlie intel_gtt_clear_range(pg_start, mem->page_count); 996d15eda5cSDave Airlie 9974080775bSDaniel Vetter if (intel_private.base.needs_dmar) { 9984080775bSDaniel Vetter intel_gtt_unmap_memory(mem->sg_list, mem->num_sg); 9994080775bSDaniel Vetter mem->sg_list = NULL; 10004080775bSDaniel Vetter mem->num_sg = 0; 10014080775bSDaniel Vetter } 10024080775bSDaniel Vetter 1003f51b7662SDaniel Vetter return 0; 1004f51b7662SDaniel Vetter } 1005f51b7662SDaniel Vetter 1006ffdd7510SDaniel Vetter static struct agp_memory *intel_fake_agp_alloc_by_type(size_t pg_count, 1007ffdd7510SDaniel Vetter int type) 1008f51b7662SDaniel Vetter { 1009625dd9d3SDaniel Vetter struct agp_memory *new; 1010625dd9d3SDaniel Vetter 1011625dd9d3SDaniel Vetter if (type == AGP_DCACHE_MEMORY && INTEL_GTT_GEN == 1) { 1012625dd9d3SDaniel Vetter if (pg_count != intel_private.num_dcache_entries) 1013625dd9d3SDaniel Vetter return NULL; 1014625dd9d3SDaniel Vetter 1015625dd9d3SDaniel Vetter new = agp_create_memory(1); 1016625dd9d3SDaniel Vetter if (new == NULL) 1017625dd9d3SDaniel Vetter return NULL; 1018625dd9d3SDaniel Vetter 1019625dd9d3SDaniel Vetter new->type = AGP_DCACHE_MEMORY; 1020625dd9d3SDaniel Vetter new->page_count = pg_count; 1021625dd9d3SDaniel Vetter new->num_scratch_pages = 0; 1022625dd9d3SDaniel Vetter agp_free_page_array(new); 1023625dd9d3SDaniel Vetter return new; 1024625dd9d3SDaniel Vetter } 1025f51b7662SDaniel Vetter if (type == AGP_PHYS_MEMORY) 1026f51b7662SDaniel Vetter return alloc_agpphysmem_i8xx(pg_count, type); 1027f51b7662SDaniel Vetter /* always return NULL for other allocation types for now */ 1028f51b7662SDaniel Vetter return NULL; 1029f51b7662SDaniel Vetter } 1030f51b7662SDaniel Vetter 1031f51b7662SDaniel Vetter static int intel_alloc_chipset_flush_resource(void) 1032f51b7662SDaniel Vetter { 1033f51b7662SDaniel Vetter int ret; 1034d7cca2f7SDaniel Vetter ret = pci_bus_alloc_resource(intel_private.bridge_dev->bus, &intel_private.ifp_resource, PAGE_SIZE, 1035f51b7662SDaniel Vetter PAGE_SIZE, PCIBIOS_MIN_MEM, 0, 1036d7cca2f7SDaniel Vetter pcibios_align_resource, intel_private.bridge_dev); 1037f51b7662SDaniel Vetter 1038f51b7662SDaniel Vetter return ret; 1039f51b7662SDaniel Vetter } 1040f51b7662SDaniel Vetter 1041f51b7662SDaniel Vetter static void intel_i915_setup_chipset_flush(void) 1042f51b7662SDaniel Vetter { 1043f51b7662SDaniel Vetter int ret; 1044f51b7662SDaniel Vetter u32 temp; 1045f51b7662SDaniel Vetter 1046d7cca2f7SDaniel Vetter pci_read_config_dword(intel_private.bridge_dev, I915_IFPADDR, &temp); 1047f51b7662SDaniel Vetter if (!(temp & 0x1)) { 1048f51b7662SDaniel Vetter intel_alloc_chipset_flush_resource(); 1049f51b7662SDaniel Vetter intel_private.resource_valid = 1; 1050d7cca2f7SDaniel Vetter pci_write_config_dword(intel_private.bridge_dev, I915_IFPADDR, (intel_private.ifp_resource.start & 0xffffffff) | 0x1); 1051f51b7662SDaniel Vetter } else { 1052f51b7662SDaniel Vetter temp &= ~1; 1053f51b7662SDaniel Vetter 1054f51b7662SDaniel Vetter intel_private.resource_valid = 1; 1055f51b7662SDaniel Vetter intel_private.ifp_resource.start = temp; 1056f51b7662SDaniel Vetter intel_private.ifp_resource.end = temp + PAGE_SIZE; 1057f51b7662SDaniel Vetter ret = request_resource(&iomem_resource, &intel_private.ifp_resource); 1058f51b7662SDaniel Vetter /* some BIOSes reserve this area in a pnp some don't */ 1059f51b7662SDaniel Vetter if (ret) 1060f51b7662SDaniel Vetter intel_private.resource_valid = 0; 1061f51b7662SDaniel Vetter } 1062f51b7662SDaniel Vetter } 1063f51b7662SDaniel Vetter 1064f51b7662SDaniel Vetter static void intel_i965_g33_setup_chipset_flush(void) 1065f51b7662SDaniel Vetter { 1066f51b7662SDaniel Vetter u32 temp_hi, temp_lo; 1067f51b7662SDaniel Vetter int ret; 1068f51b7662SDaniel Vetter 1069d7cca2f7SDaniel Vetter pci_read_config_dword(intel_private.bridge_dev, I965_IFPADDR + 4, &temp_hi); 1070d7cca2f7SDaniel Vetter pci_read_config_dword(intel_private.bridge_dev, I965_IFPADDR, &temp_lo); 1071f51b7662SDaniel Vetter 1072f51b7662SDaniel Vetter if (!(temp_lo & 0x1)) { 1073f51b7662SDaniel Vetter 1074f51b7662SDaniel Vetter intel_alloc_chipset_flush_resource(); 1075f51b7662SDaniel Vetter 1076f51b7662SDaniel Vetter intel_private.resource_valid = 1; 1077d7cca2f7SDaniel Vetter pci_write_config_dword(intel_private.bridge_dev, I965_IFPADDR + 4, 1078f51b7662SDaniel Vetter upper_32_bits(intel_private.ifp_resource.start)); 1079d7cca2f7SDaniel Vetter pci_write_config_dword(intel_private.bridge_dev, I965_IFPADDR, (intel_private.ifp_resource.start & 0xffffffff) | 0x1); 1080f51b7662SDaniel Vetter } else { 1081f51b7662SDaniel Vetter u64 l64; 1082f51b7662SDaniel Vetter 1083f51b7662SDaniel Vetter temp_lo &= ~0x1; 1084f51b7662SDaniel Vetter l64 = ((u64)temp_hi << 32) | temp_lo; 1085f51b7662SDaniel Vetter 1086f51b7662SDaniel Vetter intel_private.resource_valid = 1; 1087f51b7662SDaniel Vetter intel_private.ifp_resource.start = l64; 1088f51b7662SDaniel Vetter intel_private.ifp_resource.end = l64 + PAGE_SIZE; 1089f51b7662SDaniel Vetter ret = request_resource(&iomem_resource, &intel_private.ifp_resource); 1090f51b7662SDaniel Vetter /* some BIOSes reserve this area in a pnp some don't */ 1091f51b7662SDaniel Vetter if (ret) 1092f51b7662SDaniel Vetter intel_private.resource_valid = 0; 1093f51b7662SDaniel Vetter } 1094f51b7662SDaniel Vetter } 1095f51b7662SDaniel Vetter 1096f51b7662SDaniel Vetter static void intel_i9xx_setup_flush(void) 1097f51b7662SDaniel Vetter { 1098f51b7662SDaniel Vetter /* return if already configured */ 1099f51b7662SDaniel Vetter if (intel_private.ifp_resource.start) 1100f51b7662SDaniel Vetter return; 1101f51b7662SDaniel Vetter 11021a997ff2SDaniel Vetter if (INTEL_GTT_GEN == 6) 1103f51b7662SDaniel Vetter return; 1104f51b7662SDaniel Vetter 1105f51b7662SDaniel Vetter /* setup a resource for this object */ 1106f51b7662SDaniel Vetter intel_private.ifp_resource.name = "Intel Flush Page"; 1107f51b7662SDaniel Vetter intel_private.ifp_resource.flags = IORESOURCE_MEM; 1108f51b7662SDaniel Vetter 1109f51b7662SDaniel Vetter /* Setup chipset flush for 915 */ 11101a997ff2SDaniel Vetter if (IS_G33 || INTEL_GTT_GEN >= 4) { 1111f51b7662SDaniel Vetter intel_i965_g33_setup_chipset_flush(); 1112f51b7662SDaniel Vetter } else { 1113f51b7662SDaniel Vetter intel_i915_setup_chipset_flush(); 1114f51b7662SDaniel Vetter } 1115f51b7662SDaniel Vetter 1116df51e7aaSChris Wilson if (intel_private.ifp_resource.start) 1117f51b7662SDaniel Vetter intel_private.i9xx_flush_page = ioremap_nocache(intel_private.ifp_resource.start, PAGE_SIZE); 1118f51b7662SDaniel Vetter if (!intel_private.i9xx_flush_page) 1119df51e7aaSChris Wilson dev_err(&intel_private.pcidev->dev, 1120df51e7aaSChris Wilson "can't ioremap flush page - no chipset flushing\n"); 1121f51b7662SDaniel Vetter } 1122f51b7662SDaniel Vetter 1123ae83dd5cSDaniel Vetter static void i9xx_cleanup(void) 1124ae83dd5cSDaniel Vetter { 1125ae83dd5cSDaniel Vetter if (intel_private.i9xx_flush_page) 1126ae83dd5cSDaniel Vetter iounmap(intel_private.i9xx_flush_page); 1127ae83dd5cSDaniel Vetter if (intel_private.resource_valid) 1128ae83dd5cSDaniel Vetter release_resource(&intel_private.ifp_resource); 1129ae83dd5cSDaniel Vetter intel_private.ifp_resource.start = 0; 1130ae83dd5cSDaniel Vetter intel_private.resource_valid = 0; 1131ae83dd5cSDaniel Vetter } 1132ae83dd5cSDaniel Vetter 11331b263f24SDaniel Vetter static void i9xx_chipset_flush(void) 1134f51b7662SDaniel Vetter { 1135f51b7662SDaniel Vetter if (intel_private.i9xx_flush_page) 1136f51b7662SDaniel Vetter writel(1, intel_private.i9xx_flush_page); 1137f51b7662SDaniel Vetter } 1138f51b7662SDaniel Vetter 113971f45660SChris Wilson static void i965_write_entry(dma_addr_t addr, 114071f45660SChris Wilson unsigned int entry, 1141a6963596SDaniel Vetter unsigned int flags) 1142a6963596SDaniel Vetter { 114371f45660SChris Wilson u32 pte_flags; 114471f45660SChris Wilson 114571f45660SChris Wilson pte_flags = I810_PTE_VALID; 114671f45660SChris Wilson if (flags == AGP_USER_CACHED_MEMORY) 114771f45660SChris Wilson pte_flags |= I830_PTE_SYSTEM_CACHED; 114871f45660SChris Wilson 1149a6963596SDaniel Vetter /* Shift high bits down */ 1150a6963596SDaniel Vetter addr |= (addr >> 28) & 0xf0; 115171f45660SChris Wilson writel(addr | pte_flags, intel_private.gtt + entry); 1152a6963596SDaniel Vetter } 1153a6963596SDaniel Vetter 115490cb149eSDaniel Vetter static bool gen6_check_flags(unsigned int flags) 115590cb149eSDaniel Vetter { 115690cb149eSDaniel Vetter return true; 115790cb149eSDaniel Vetter } 115890cb149eSDaniel Vetter 115997ef1bddSDaniel Vetter static void gen6_write_entry(dma_addr_t addr, unsigned int entry, 116097ef1bddSDaniel Vetter unsigned int flags) 116197ef1bddSDaniel Vetter { 116297ef1bddSDaniel Vetter unsigned int type_mask = flags & ~AGP_USER_CACHED_MEMORY_GFDT; 116397ef1bddSDaniel Vetter unsigned int gfdt = flags & AGP_USER_CACHED_MEMORY_GFDT; 116497ef1bddSDaniel Vetter u32 pte_flags; 116597ef1bddSDaniel Vetter 1166897ef192SZhenyu Wang if (type_mask == AGP_USER_MEMORY) 116785ccc35bSChris Wilson pte_flags = GEN6_PTE_UNCACHED | I810_PTE_VALID; 116897ef1bddSDaniel Vetter else if (type_mask == AGP_USER_CACHED_MEMORY_LLC_MLC) { 1169d1108525SZhenyu Wang pte_flags = GEN6_PTE_LLC_MLC | I810_PTE_VALID; 117097ef1bddSDaniel Vetter if (gfdt) 117197ef1bddSDaniel Vetter pte_flags |= GEN6_PTE_GFDT; 117297ef1bddSDaniel Vetter } else { /* set 'normal'/'cached' to LLC by default */ 1173d1108525SZhenyu Wang pte_flags = GEN6_PTE_LLC | I810_PTE_VALID; 117497ef1bddSDaniel Vetter if (gfdt) 117597ef1bddSDaniel Vetter pte_flags |= GEN6_PTE_GFDT; 117697ef1bddSDaniel Vetter } 117797ef1bddSDaniel Vetter 117897ef1bddSDaniel Vetter /* gen6 has bit11-4 for physical addr bit39-32 */ 117997ef1bddSDaniel Vetter addr |= (addr >> 28) & 0xff0; 118097ef1bddSDaniel Vetter writel(addr | pte_flags, intel_private.gtt + entry); 118197ef1bddSDaniel Vetter } 118297ef1bddSDaniel Vetter 118364757876SJesse Barnes static void valleyview_write_entry(dma_addr_t addr, unsigned int entry, 118464757876SJesse Barnes unsigned int flags) 118564757876SJesse Barnes { 1186e87c4699SJesse Barnes unsigned int type_mask = flags & ~AGP_USER_CACHED_MEMORY_GFDT; 1187e87c4699SJesse Barnes unsigned int gfdt = flags & AGP_USER_CACHED_MEMORY_GFDT; 118864757876SJesse Barnes u32 pte_flags; 118964757876SJesse Barnes 1190e87c4699SJesse Barnes if (type_mask == AGP_USER_MEMORY) 119164757876SJesse Barnes pte_flags = GEN6_PTE_UNCACHED | I810_PTE_VALID; 1192e87c4699SJesse Barnes else { 1193e87c4699SJesse Barnes pte_flags = GEN6_PTE_LLC | I810_PTE_VALID; 1194e87c4699SJesse Barnes if (gfdt) 1195e87c4699SJesse Barnes pte_flags |= GEN6_PTE_GFDT; 1196e87c4699SJesse Barnes } 119764757876SJesse Barnes 119864757876SJesse Barnes /* gen6 has bit11-4 for physical addr bit39-32 */ 119964757876SJesse Barnes addr |= (addr >> 28) & 0xff0; 120064757876SJesse Barnes writel(addr | pte_flags, intel_private.gtt + entry); 120164757876SJesse Barnes 120264757876SJesse Barnes writel(1, intel_private.registers + GFX_FLSH_CNTL_VLV); 120364757876SJesse Barnes } 120464757876SJesse Barnes 1205ae83dd5cSDaniel Vetter static void gen6_cleanup(void) 1206ae83dd5cSDaniel Vetter { 1207ae83dd5cSDaniel Vetter } 1208ae83dd5cSDaniel Vetter 12095c042287SBen Widawsky /* Certain Gen5 chipsets require require idling the GPU before 12105c042287SBen Widawsky * unmapping anything from the GTT when VT-d is enabled. 12115c042287SBen Widawsky */ 12125c042287SBen Widawsky static inline int needs_idle_maps(void) 12135c042287SBen Widawsky { 1214a08185a3SKeith Packard #ifdef CONFIG_INTEL_IOMMU 12155c042287SBen Widawsky const unsigned short gpu_devid = intel_private.pcidev->device; 12165c042287SBen Widawsky 12175c042287SBen Widawsky /* Query intel_iommu to see if we need the workaround. Presumably that 12185c042287SBen Widawsky * was loaded first. 12195c042287SBen Widawsky */ 12205c042287SBen Widawsky if ((gpu_devid == PCI_DEVICE_ID_INTEL_IRONLAKE_M_HB || 12215c042287SBen Widawsky gpu_devid == PCI_DEVICE_ID_INTEL_IRONLAKE_M_IG) && 12225c042287SBen Widawsky intel_iommu_gfx_mapped) 12235c042287SBen Widawsky return 1; 1224a08185a3SKeith Packard #endif 12255c042287SBen Widawsky return 0; 12265c042287SBen Widawsky } 12275c042287SBen Widawsky 12282d2430cfSDaniel Vetter static int i9xx_setup(void) 12292d2430cfSDaniel Vetter { 12302d2430cfSDaniel Vetter u32 reg_addr; 12314b60d29eSJesse Barnes int size = KB(512); 12322d2430cfSDaniel Vetter 12332d2430cfSDaniel Vetter pci_read_config_dword(intel_private.pcidev, I915_MMADDR, ®_addr); 12342d2430cfSDaniel Vetter 12352d2430cfSDaniel Vetter reg_addr &= 0xfff80000; 12362d2430cfSDaniel Vetter 12374b60d29eSJesse Barnes if (INTEL_GTT_GEN >= 7) 12384b60d29eSJesse Barnes size = MB(2); 12394b60d29eSJesse Barnes 12404b60d29eSJesse Barnes intel_private.registers = ioremap(reg_addr, size); 12412d2430cfSDaniel Vetter if (!intel_private.registers) 12422d2430cfSDaniel Vetter return -ENOMEM; 12432d2430cfSDaniel Vetter 12442d2430cfSDaniel Vetter if (INTEL_GTT_GEN == 3) { 12452d2430cfSDaniel Vetter u32 gtt_addr; 12463f08e4efSChris Wilson 12472d2430cfSDaniel Vetter pci_read_config_dword(intel_private.pcidev, 12482d2430cfSDaniel Vetter I915_PTEADDR, >t_addr); 12492d2430cfSDaniel Vetter intel_private.gtt_bus_addr = gtt_addr; 12502d2430cfSDaniel Vetter } else { 12512d2430cfSDaniel Vetter u32 gtt_offset; 12522d2430cfSDaniel Vetter 12532d2430cfSDaniel Vetter switch (INTEL_GTT_GEN) { 12542d2430cfSDaniel Vetter case 5: 12552d2430cfSDaniel Vetter case 6: 12562d2430cfSDaniel Vetter gtt_offset = MB(2); 12572d2430cfSDaniel Vetter break; 12582d2430cfSDaniel Vetter case 4: 12592d2430cfSDaniel Vetter default: 12602d2430cfSDaniel Vetter gtt_offset = KB(512); 12612d2430cfSDaniel Vetter break; 12622d2430cfSDaniel Vetter } 12632d2430cfSDaniel Vetter intel_private.gtt_bus_addr = reg_addr + gtt_offset; 12642d2430cfSDaniel Vetter } 12652d2430cfSDaniel Vetter 126635b09c9bSDan Carpenter if (needs_idle_maps()) 12675c042287SBen Widawsky intel_private.base.do_idle_maps = 1; 12685c042287SBen Widawsky 12692d2430cfSDaniel Vetter intel_i9xx_setup_flush(); 12702d2430cfSDaniel Vetter 12712d2430cfSDaniel Vetter return 0; 12722d2430cfSDaniel Vetter } 12732d2430cfSDaniel Vetter 1274e9b1cc81SDaniel Vetter static const struct agp_bridge_driver intel_fake_agp_driver = { 1275f51b7662SDaniel Vetter .owner = THIS_MODULE, 1276f51b7662SDaniel Vetter .size_type = FIXED_APER_SIZE, 12779e76e7b8SChris Wilson .aperture_sizes = intel_fake_agp_sizes, 12789e76e7b8SChris Wilson .num_aperture_sizes = ARRAY_SIZE(intel_fake_agp_sizes), 1279a6963596SDaniel Vetter .configure = intel_fake_agp_configure, 12803e921f98SDaniel Vetter .fetch_size = intel_fake_agp_fetch_size, 1281fdfb58a9SDaniel Vetter .cleanup = intel_gtt_cleanup, 1282ffdd7510SDaniel Vetter .agp_enable = intel_fake_agp_enable, 1283f51b7662SDaniel Vetter .cache_flush = global_cache_flush, 12843b15a9d7SDaniel Vetter .create_gatt_table = intel_fake_agp_create_gatt_table, 1285ffdd7510SDaniel Vetter .free_gatt_table = intel_fake_agp_free_gatt_table, 1286450f2b3dSDaniel Vetter .insert_memory = intel_fake_agp_insert_entries, 1287450f2b3dSDaniel Vetter .remove_memory = intel_fake_agp_remove_entries, 1288ffdd7510SDaniel Vetter .alloc_by_type = intel_fake_agp_alloc_by_type, 1289f51b7662SDaniel Vetter .free_by_type = intel_i810_free_by_type, 1290f51b7662SDaniel Vetter .agp_alloc_page = agp_generic_alloc_page, 1291f51b7662SDaniel Vetter .agp_alloc_pages = agp_generic_alloc_pages, 1292f51b7662SDaniel Vetter .agp_destroy_page = agp_generic_destroy_page, 1293f51b7662SDaniel Vetter .agp_destroy_pages = agp_generic_destroy_pages, 1294f51b7662SDaniel Vetter }; 129502c026ceSDaniel Vetter 1296bdd30729SDaniel Vetter static const struct intel_gtt_driver i81x_gtt_driver = { 1297bdd30729SDaniel Vetter .gen = 1, 1298820647b9SDaniel Vetter .has_pgtbl_enable = 1, 129922533b49SDaniel Vetter .dma_mask_size = 32, 1300820647b9SDaniel Vetter .setup = i810_setup, 1301820647b9SDaniel Vetter .cleanup = i810_cleanup, 1302625dd9d3SDaniel Vetter .check_flags = i830_check_flags, 1303625dd9d3SDaniel Vetter .write_entry = i810_write_entry, 1304bdd30729SDaniel Vetter }; 13051a997ff2SDaniel Vetter static const struct intel_gtt_driver i8xx_gtt_driver = { 13061a997ff2SDaniel Vetter .gen = 2, 1307100519e2SChris Wilson .has_pgtbl_enable = 1, 130873800422SDaniel Vetter .setup = i830_setup, 1309ae83dd5cSDaniel Vetter .cleanup = i830_cleanup, 1310351bb278SDaniel Vetter .write_entry = i830_write_entry, 131122533b49SDaniel Vetter .dma_mask_size = 32, 13125cbecafcSDaniel Vetter .check_flags = i830_check_flags, 13131b263f24SDaniel Vetter .chipset_flush = i830_chipset_flush, 13141a997ff2SDaniel Vetter }; 13151a997ff2SDaniel Vetter static const struct intel_gtt_driver i915_gtt_driver = { 13161a997ff2SDaniel Vetter .gen = 3, 1317100519e2SChris Wilson .has_pgtbl_enable = 1, 13182d2430cfSDaniel Vetter .setup = i9xx_setup, 1319ae83dd5cSDaniel Vetter .cleanup = i9xx_cleanup, 1320351bb278SDaniel Vetter /* i945 is the last gpu to need phys mem (for overlay and cursors). */ 1321351bb278SDaniel Vetter .write_entry = i830_write_entry, 132222533b49SDaniel Vetter .dma_mask_size = 32, 1323fefaa70fSDaniel Vetter .check_flags = i830_check_flags, 13241b263f24SDaniel Vetter .chipset_flush = i9xx_chipset_flush, 13251a997ff2SDaniel Vetter }; 13261a997ff2SDaniel Vetter static const struct intel_gtt_driver g33_gtt_driver = { 13271a997ff2SDaniel Vetter .gen = 3, 13281a997ff2SDaniel Vetter .is_g33 = 1, 13292d2430cfSDaniel Vetter .setup = i9xx_setup, 1330ae83dd5cSDaniel Vetter .cleanup = i9xx_cleanup, 1331a6963596SDaniel Vetter .write_entry = i965_write_entry, 133222533b49SDaniel Vetter .dma_mask_size = 36, 1333450f2b3dSDaniel Vetter .check_flags = i830_check_flags, 13341b263f24SDaniel Vetter .chipset_flush = i9xx_chipset_flush, 13351a997ff2SDaniel Vetter }; 13361a997ff2SDaniel Vetter static const struct intel_gtt_driver pineview_gtt_driver = { 13371a997ff2SDaniel Vetter .gen = 3, 13381a997ff2SDaniel Vetter .is_pineview = 1, .is_g33 = 1, 13392d2430cfSDaniel Vetter .setup = i9xx_setup, 1340ae83dd5cSDaniel Vetter .cleanup = i9xx_cleanup, 1341a6963596SDaniel Vetter .write_entry = i965_write_entry, 134222533b49SDaniel Vetter .dma_mask_size = 36, 1343450f2b3dSDaniel Vetter .check_flags = i830_check_flags, 13441b263f24SDaniel Vetter .chipset_flush = i9xx_chipset_flush, 13451a997ff2SDaniel Vetter }; 13461a997ff2SDaniel Vetter static const struct intel_gtt_driver i965_gtt_driver = { 13471a997ff2SDaniel Vetter .gen = 4, 1348100519e2SChris Wilson .has_pgtbl_enable = 1, 13492d2430cfSDaniel Vetter .setup = i9xx_setup, 1350ae83dd5cSDaniel Vetter .cleanup = i9xx_cleanup, 1351a6963596SDaniel Vetter .write_entry = i965_write_entry, 135222533b49SDaniel Vetter .dma_mask_size = 36, 1353450f2b3dSDaniel Vetter .check_flags = i830_check_flags, 13541b263f24SDaniel Vetter .chipset_flush = i9xx_chipset_flush, 13551a997ff2SDaniel Vetter }; 13561a997ff2SDaniel Vetter static const struct intel_gtt_driver g4x_gtt_driver = { 13571a997ff2SDaniel Vetter .gen = 5, 13582d2430cfSDaniel Vetter .setup = i9xx_setup, 1359ae83dd5cSDaniel Vetter .cleanup = i9xx_cleanup, 1360a6963596SDaniel Vetter .write_entry = i965_write_entry, 136122533b49SDaniel Vetter .dma_mask_size = 36, 1362450f2b3dSDaniel Vetter .check_flags = i830_check_flags, 13631b263f24SDaniel Vetter .chipset_flush = i9xx_chipset_flush, 13641a997ff2SDaniel Vetter }; 13651a997ff2SDaniel Vetter static const struct intel_gtt_driver ironlake_gtt_driver = { 13661a997ff2SDaniel Vetter .gen = 5, 13671a997ff2SDaniel Vetter .is_ironlake = 1, 13682d2430cfSDaniel Vetter .setup = i9xx_setup, 1369ae83dd5cSDaniel Vetter .cleanup = i9xx_cleanup, 1370a6963596SDaniel Vetter .write_entry = i965_write_entry, 137122533b49SDaniel Vetter .dma_mask_size = 36, 1372450f2b3dSDaniel Vetter .check_flags = i830_check_flags, 13731b263f24SDaniel Vetter .chipset_flush = i9xx_chipset_flush, 13741a997ff2SDaniel Vetter }; 13751a997ff2SDaniel Vetter static const struct intel_gtt_driver sandybridge_gtt_driver = { 13761a997ff2SDaniel Vetter .gen = 6, 13772d2430cfSDaniel Vetter .setup = i9xx_setup, 1378ae83dd5cSDaniel Vetter .cleanup = gen6_cleanup, 137997ef1bddSDaniel Vetter .write_entry = gen6_write_entry, 138022533b49SDaniel Vetter .dma_mask_size = 40, 138190cb149eSDaniel Vetter .check_flags = gen6_check_flags, 13821b263f24SDaniel Vetter .chipset_flush = i9xx_chipset_flush, 13831a997ff2SDaniel Vetter }; 138464757876SJesse Barnes static const struct intel_gtt_driver valleyview_gtt_driver = { 138564757876SJesse Barnes .gen = 7, 138664757876SJesse Barnes .setup = i9xx_setup, 138764757876SJesse Barnes .cleanup = gen6_cleanup, 138864757876SJesse Barnes .write_entry = valleyview_write_entry, 138964757876SJesse Barnes .dma_mask_size = 40, 139064757876SJesse Barnes .check_flags = gen6_check_flags, 139164757876SJesse Barnes }; 13921a997ff2SDaniel Vetter 139302c026ceSDaniel Vetter /* Table to describe Intel GMCH and AGP/PCIE GART drivers. At least one of 139402c026ceSDaniel Vetter * driver and gmch_driver must be non-null, and find_gmch will determine 139502c026ceSDaniel Vetter * which one should be used if a gmch_chip_id is present. 139602c026ceSDaniel Vetter */ 139702c026ceSDaniel Vetter static const struct intel_gtt_driver_description { 139802c026ceSDaniel Vetter unsigned int gmch_chip_id; 139902c026ceSDaniel Vetter char *name; 14001a997ff2SDaniel Vetter const struct intel_gtt_driver *gtt_driver; 140102c026ceSDaniel Vetter } intel_gtt_chipsets[] = { 1402ff26860fSDaniel Vetter { PCI_DEVICE_ID_INTEL_82810_IG1, "i810", 1403bdd30729SDaniel Vetter &i81x_gtt_driver}, 1404ff26860fSDaniel Vetter { PCI_DEVICE_ID_INTEL_82810_IG3, "i810", 1405bdd30729SDaniel Vetter &i81x_gtt_driver}, 1406ff26860fSDaniel Vetter { PCI_DEVICE_ID_INTEL_82810E_IG, "i810", 1407bdd30729SDaniel Vetter &i81x_gtt_driver}, 1408ff26860fSDaniel Vetter { PCI_DEVICE_ID_INTEL_82815_CGC, "i815", 1409bdd30729SDaniel Vetter &i81x_gtt_driver}, 14101a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_82830_CGC, "830M", 1411ff26860fSDaniel Vetter &i8xx_gtt_driver}, 141253371edaSOswald Buddenhagen { PCI_DEVICE_ID_INTEL_82845G_IG, "845G", 1413ff26860fSDaniel Vetter &i8xx_gtt_driver}, 14141a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_82854_IG, "854", 1415ff26860fSDaniel Vetter &i8xx_gtt_driver}, 14161a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_82855GM_IG, "855GM", 1417ff26860fSDaniel Vetter &i8xx_gtt_driver}, 14181a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_82865_IG, "865", 1419ff26860fSDaniel Vetter &i8xx_gtt_driver}, 14201a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_E7221_IG, "E7221 (i915)", 1421ff26860fSDaniel Vetter &i915_gtt_driver }, 14221a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_82915G_IG, "915G", 1423ff26860fSDaniel Vetter &i915_gtt_driver }, 14241a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_82915GM_IG, "915GM", 1425ff26860fSDaniel Vetter &i915_gtt_driver }, 14261a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_82945G_IG, "945G", 1427ff26860fSDaniel Vetter &i915_gtt_driver }, 14281a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_82945GM_IG, "945GM", 1429ff26860fSDaniel Vetter &i915_gtt_driver }, 14301a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_82945GME_IG, "945GME", 1431ff26860fSDaniel Vetter &i915_gtt_driver }, 14321a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_82946GZ_IG, "946GZ", 1433ff26860fSDaniel Vetter &i965_gtt_driver }, 14341a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_82G35_IG, "G35", 1435ff26860fSDaniel Vetter &i965_gtt_driver }, 14361a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_82965Q_IG, "965Q", 1437ff26860fSDaniel Vetter &i965_gtt_driver }, 14381a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_82965G_IG, "965G", 1439ff26860fSDaniel Vetter &i965_gtt_driver }, 14401a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_82965GM_IG, "965GM", 1441ff26860fSDaniel Vetter &i965_gtt_driver }, 14421a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_82965GME_IG, "965GME/GLE", 1443ff26860fSDaniel Vetter &i965_gtt_driver }, 14441a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_G33_IG, "G33", 1445ff26860fSDaniel Vetter &g33_gtt_driver }, 14461a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_Q35_IG, "Q35", 1447ff26860fSDaniel Vetter &g33_gtt_driver }, 14481a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_Q33_IG, "Q33", 1449ff26860fSDaniel Vetter &g33_gtt_driver }, 14501a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_PINEVIEW_M_IG, "GMA3150", 1451ff26860fSDaniel Vetter &pineview_gtt_driver }, 14521a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_PINEVIEW_IG, "GMA3150", 1453ff26860fSDaniel Vetter &pineview_gtt_driver }, 14541a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_GM45_IG, "GM45", 1455ff26860fSDaniel Vetter &g4x_gtt_driver }, 14561a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_EAGLELAKE_IG, "Eaglelake", 1457ff26860fSDaniel Vetter &g4x_gtt_driver }, 14581a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_Q45_IG, "Q45/Q43", 1459ff26860fSDaniel Vetter &g4x_gtt_driver }, 14601a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_G45_IG, "G45/G43", 1461ff26860fSDaniel Vetter &g4x_gtt_driver }, 14621a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_B43_IG, "B43", 1463ff26860fSDaniel Vetter &g4x_gtt_driver }, 1464e9e5f8e8SChris Wilson { PCI_DEVICE_ID_INTEL_B43_1_IG, "B43", 1465ff26860fSDaniel Vetter &g4x_gtt_driver }, 14661a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_G41_IG, "G41", 1467ff26860fSDaniel Vetter &g4x_gtt_driver }, 146802c026ceSDaniel Vetter { PCI_DEVICE_ID_INTEL_IRONLAKE_D_IG, 1469ff26860fSDaniel Vetter "HD Graphics", &ironlake_gtt_driver }, 147002c026ceSDaniel Vetter { PCI_DEVICE_ID_INTEL_IRONLAKE_M_IG, 1471ff26860fSDaniel Vetter "HD Graphics", &ironlake_gtt_driver }, 147202c026ceSDaniel Vetter { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_GT1_IG, 1473ff26860fSDaniel Vetter "Sandybridge", &sandybridge_gtt_driver }, 147402c026ceSDaniel Vetter { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_GT2_IG, 1475ff26860fSDaniel Vetter "Sandybridge", &sandybridge_gtt_driver }, 147602c026ceSDaniel Vetter { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_GT2_PLUS_IG, 1477ff26860fSDaniel Vetter "Sandybridge", &sandybridge_gtt_driver }, 147802c026ceSDaniel Vetter { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_GT1_IG, 1479ff26860fSDaniel Vetter "Sandybridge", &sandybridge_gtt_driver }, 148002c026ceSDaniel Vetter { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_GT2_IG, 1481ff26860fSDaniel Vetter "Sandybridge", &sandybridge_gtt_driver }, 148202c026ceSDaniel Vetter { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_GT2_PLUS_IG, 1483ff26860fSDaniel Vetter "Sandybridge", &sandybridge_gtt_driver }, 148402c026ceSDaniel Vetter { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_S_IG, 1485ff26860fSDaniel Vetter "Sandybridge", &sandybridge_gtt_driver }, 1486246d08b8SJesse Barnes { PCI_DEVICE_ID_INTEL_IVYBRIDGE_GT1_IG, 1487246d08b8SJesse Barnes "Ivybridge", &sandybridge_gtt_driver }, 1488246d08b8SJesse Barnes { PCI_DEVICE_ID_INTEL_IVYBRIDGE_GT2_IG, 1489246d08b8SJesse Barnes "Ivybridge", &sandybridge_gtt_driver }, 1490246d08b8SJesse Barnes { PCI_DEVICE_ID_INTEL_IVYBRIDGE_M_GT1_IG, 1491246d08b8SJesse Barnes "Ivybridge", &sandybridge_gtt_driver }, 1492246d08b8SJesse Barnes { PCI_DEVICE_ID_INTEL_IVYBRIDGE_M_GT2_IG, 1493246d08b8SJesse Barnes "Ivybridge", &sandybridge_gtt_driver }, 1494246d08b8SJesse Barnes { PCI_DEVICE_ID_INTEL_IVYBRIDGE_S_GT1_IG, 1495246d08b8SJesse Barnes "Ivybridge", &sandybridge_gtt_driver }, 1496cc22a938SEugeni Dodonov { PCI_DEVICE_ID_INTEL_IVYBRIDGE_S_GT2_IG, 1497cc22a938SEugeni Dodonov "Ivybridge", &sandybridge_gtt_driver }, 149864757876SJesse Barnes { PCI_DEVICE_ID_INTEL_VALLEYVIEW_IG, 149964757876SJesse Barnes "ValleyView", &valleyview_gtt_driver }, 15004cae9ae0SEugeni Dodonov { PCI_DEVICE_ID_INTEL_HASWELL_D_GT1_IG, 15014cae9ae0SEugeni Dodonov "Haswell", &sandybridge_gtt_driver }, 15024cae9ae0SEugeni Dodonov { PCI_DEVICE_ID_INTEL_HASWELL_D_GT2_IG, 15034cae9ae0SEugeni Dodonov "Haswell", &sandybridge_gtt_driver }, 15044cae9ae0SEugeni Dodonov { PCI_DEVICE_ID_INTEL_HASWELL_M_GT1_IG, 15054cae9ae0SEugeni Dodonov "Haswell", &sandybridge_gtt_driver }, 15064cae9ae0SEugeni Dodonov { PCI_DEVICE_ID_INTEL_HASWELL_M_GT2_IG, 15074cae9ae0SEugeni Dodonov "Haswell", &sandybridge_gtt_driver }, 15084cae9ae0SEugeni Dodonov { PCI_DEVICE_ID_INTEL_HASWELL_S_GT1_IG, 15094cae9ae0SEugeni Dodonov "Haswell", &sandybridge_gtt_driver }, 15104cae9ae0SEugeni Dodonov { PCI_DEVICE_ID_INTEL_HASWELL_S_GT2_IG, 15114cae9ae0SEugeni Dodonov "Haswell", &sandybridge_gtt_driver }, 15124cae9ae0SEugeni Dodonov { PCI_DEVICE_ID_INTEL_HASWELL_SDV, 15134cae9ae0SEugeni Dodonov "Haswell", &sandybridge_gtt_driver }, 151402c026ceSDaniel Vetter { 0, NULL, NULL } 151502c026ceSDaniel Vetter }; 151602c026ceSDaniel Vetter 151702c026ceSDaniel Vetter static int find_gmch(u16 device) 151802c026ceSDaniel Vetter { 151902c026ceSDaniel Vetter struct pci_dev *gmch_device; 152002c026ceSDaniel Vetter 152102c026ceSDaniel Vetter gmch_device = pci_get_device(PCI_VENDOR_ID_INTEL, device, NULL); 152202c026ceSDaniel Vetter if (gmch_device && PCI_FUNC(gmch_device->devfn) != 0) { 152302c026ceSDaniel Vetter gmch_device = pci_get_device(PCI_VENDOR_ID_INTEL, 152402c026ceSDaniel Vetter device, gmch_device); 152502c026ceSDaniel Vetter } 152602c026ceSDaniel Vetter 152702c026ceSDaniel Vetter if (!gmch_device) 152802c026ceSDaniel Vetter return 0; 152902c026ceSDaniel Vetter 153002c026ceSDaniel Vetter intel_private.pcidev = gmch_device; 153102c026ceSDaniel Vetter return 1; 153202c026ceSDaniel Vetter } 153302c026ceSDaniel Vetter 153414be93ddSDaniel Vetter int intel_gmch_probe(struct pci_dev *bridge_pdev, struct pci_dev *gpu_pdev, 153502c026ceSDaniel Vetter struct agp_bridge_data *bridge) 153602c026ceSDaniel Vetter { 153702c026ceSDaniel Vetter int i, mask; 153814be93ddSDaniel Vetter 153914be93ddSDaniel Vetter /* 154014be93ddSDaniel Vetter * Can be called from the fake agp driver but also directly from 154114be93ddSDaniel Vetter * drm/i915.ko. Hence we need to check whether everything is set up 154214be93ddSDaniel Vetter * already. 154314be93ddSDaniel Vetter */ 154414be93ddSDaniel Vetter if (intel_private.driver) { 154514be93ddSDaniel Vetter intel_private.refcount++; 154614be93ddSDaniel Vetter return 1; 154714be93ddSDaniel Vetter } 154802c026ceSDaniel Vetter 154902c026ceSDaniel Vetter for (i = 0; intel_gtt_chipsets[i].name != NULL; i++) { 155014be93ddSDaniel Vetter if (gpu_pdev) { 155114be93ddSDaniel Vetter if (gpu_pdev->device == 155214be93ddSDaniel Vetter intel_gtt_chipsets[i].gmch_chip_id) { 155314be93ddSDaniel Vetter intel_private.pcidev = pci_dev_get(gpu_pdev); 155414be93ddSDaniel Vetter intel_private.driver = 155514be93ddSDaniel Vetter intel_gtt_chipsets[i].gtt_driver; 155614be93ddSDaniel Vetter 155714be93ddSDaniel Vetter break; 155814be93ddSDaniel Vetter } 155914be93ddSDaniel Vetter } else if (find_gmch(intel_gtt_chipsets[i].gmch_chip_id)) { 15601a997ff2SDaniel Vetter intel_private.driver = 15611a997ff2SDaniel Vetter intel_gtt_chipsets[i].gtt_driver; 156202c026ceSDaniel Vetter break; 156302c026ceSDaniel Vetter } 156402c026ceSDaniel Vetter } 156502c026ceSDaniel Vetter 1566ff26860fSDaniel Vetter if (!intel_private.driver) 156702c026ceSDaniel Vetter return 0; 156802c026ceSDaniel Vetter 156914be93ddSDaniel Vetter intel_private.refcount++; 157014be93ddSDaniel Vetter 15717e8f6306SDaniel Vetter if (bridge) { 1572ff26860fSDaniel Vetter bridge->driver = &intel_fake_agp_driver; 157302c026ceSDaniel Vetter bridge->dev_private_data = &intel_private; 157414be93ddSDaniel Vetter bridge->dev = bridge_pdev; 15757e8f6306SDaniel Vetter } 157602c026ceSDaniel Vetter 157714be93ddSDaniel Vetter intel_private.bridge_dev = pci_dev_get(bridge_pdev); 1578d7cca2f7SDaniel Vetter 157914be93ddSDaniel Vetter dev_info(&bridge_pdev->dev, "Intel %s Chipset\n", intel_gtt_chipsets[i].name); 158002c026ceSDaniel Vetter 158122533b49SDaniel Vetter mask = intel_private.driver->dma_mask_size; 158202c026ceSDaniel Vetter if (pci_set_dma_mask(intel_private.pcidev, DMA_BIT_MASK(mask))) 158302c026ceSDaniel Vetter dev_err(&intel_private.pcidev->dev, 158402c026ceSDaniel Vetter "set gfx device dma mask %d-bit failed!\n", mask); 158502c026ceSDaniel Vetter else 158602c026ceSDaniel Vetter pci_set_consistent_dma_mask(intel_private.pcidev, 158702c026ceSDaniel Vetter DMA_BIT_MASK(mask)); 158802c026ceSDaniel Vetter 158914be93ddSDaniel Vetter if (intel_gtt_init() != 0) { 159014be93ddSDaniel Vetter intel_gmch_remove(); 159114be93ddSDaniel Vetter 15923b15a9d7SDaniel Vetter return 0; 159314be93ddSDaniel Vetter } 15941784a5fbSDaniel Vetter 159502c026ceSDaniel Vetter return 1; 159602c026ceSDaniel Vetter } 1597e2404e7cSDaniel Vetter EXPORT_SYMBOL(intel_gmch_probe); 159802c026ceSDaniel Vetter 1599c64f7ba5SChris Wilson const struct intel_gtt *intel_gtt_get(void) 160019966754SDaniel Vetter { 160119966754SDaniel Vetter return &intel_private.base; 160219966754SDaniel Vetter } 160319966754SDaniel Vetter EXPORT_SYMBOL(intel_gtt_get); 160419966754SDaniel Vetter 160540ce6575SDaniel Vetter void intel_gtt_chipset_flush(void) 160640ce6575SDaniel Vetter { 160740ce6575SDaniel Vetter if (intel_private.driver->chipset_flush) 160840ce6575SDaniel Vetter intel_private.driver->chipset_flush(); 160940ce6575SDaniel Vetter } 161040ce6575SDaniel Vetter EXPORT_SYMBOL(intel_gtt_chipset_flush); 161140ce6575SDaniel Vetter 161214be93ddSDaniel Vetter void intel_gmch_remove(void) 161302c026ceSDaniel Vetter { 161414be93ddSDaniel Vetter if (--intel_private.refcount) 161514be93ddSDaniel Vetter return; 161614be93ddSDaniel Vetter 161702c026ceSDaniel Vetter if (intel_private.pcidev) 161802c026ceSDaniel Vetter pci_dev_put(intel_private.pcidev); 1619d7cca2f7SDaniel Vetter if (intel_private.bridge_dev) 1620d7cca2f7SDaniel Vetter pci_dev_put(intel_private.bridge_dev); 162114be93ddSDaniel Vetter intel_private.driver = NULL; 162202c026ceSDaniel Vetter } 1623e2404e7cSDaniel Vetter EXPORT_SYMBOL(intel_gmch_remove); 1624e2404e7cSDaniel Vetter 1625e2404e7cSDaniel Vetter MODULE_AUTHOR("Dave Jones <davej@redhat.com>"); 1626e2404e7cSDaniel Vetter MODULE_LICENSE("GPL and additional rights"); 1627