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; 98*b3eafc5aSDaniel 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 645fbe40783SDaniel Vetter static unsigned int intel_gtt_total_entries(void) 646fbe40783SDaniel Vetter { 647fbe40783SDaniel Vetter int size; 648fbe40783SDaniel Vetter 649210b23c2SDaniel Vetter if (IS_G33 || INTEL_GTT_GEN == 4 || INTEL_GTT_GEN == 5) { 650fbe40783SDaniel Vetter u32 pgetbl_ctl; 651fbe40783SDaniel Vetter pgetbl_ctl = readl(intel_private.registers+I810_PGETBL_CTL); 652fbe40783SDaniel Vetter 653fbe40783SDaniel Vetter switch (pgetbl_ctl & I965_PGETBL_SIZE_MASK) { 654fbe40783SDaniel Vetter case I965_PGETBL_SIZE_128KB: 655e5e408fcSDaniel Vetter size = KB(128); 656fbe40783SDaniel Vetter break; 657fbe40783SDaniel Vetter case I965_PGETBL_SIZE_256KB: 658e5e408fcSDaniel Vetter size = KB(256); 659fbe40783SDaniel Vetter break; 660fbe40783SDaniel Vetter case I965_PGETBL_SIZE_512KB: 661e5e408fcSDaniel Vetter size = KB(512); 662fbe40783SDaniel Vetter break; 663fbe40783SDaniel Vetter case I965_PGETBL_SIZE_1MB: 664e5e408fcSDaniel Vetter size = KB(1024); 665fbe40783SDaniel Vetter break; 666fbe40783SDaniel Vetter case I965_PGETBL_SIZE_2MB: 667e5e408fcSDaniel Vetter size = KB(2048); 668fbe40783SDaniel Vetter break; 669fbe40783SDaniel Vetter case I965_PGETBL_SIZE_1_5MB: 670e5e408fcSDaniel Vetter size = KB(1024 + 512); 671fbe40783SDaniel Vetter break; 672fbe40783SDaniel Vetter default: 673fbe40783SDaniel Vetter dev_info(&intel_private.pcidev->dev, 674fbe40783SDaniel Vetter "unknown page table size, assuming 512KB\n"); 675e5e408fcSDaniel Vetter size = KB(512); 676fbe40783SDaniel Vetter } 677e5e408fcSDaniel Vetter 678e5e408fcSDaniel Vetter return size/4; 679210b23c2SDaniel Vetter } else if (INTEL_GTT_GEN == 6) { 680210b23c2SDaniel Vetter u16 snb_gmch_ctl; 681210b23c2SDaniel Vetter 682210b23c2SDaniel Vetter pci_read_config_word(intel_private.pcidev, SNB_GMCH_CTRL, &snb_gmch_ctl); 683210b23c2SDaniel Vetter switch (snb_gmch_ctl & SNB_GTT_SIZE_MASK) { 684210b23c2SDaniel Vetter default: 685210b23c2SDaniel Vetter case SNB_GTT_SIZE_0M: 686210b23c2SDaniel Vetter printk(KERN_ERR "Bad GTT size mask: 0x%04x.\n", snb_gmch_ctl); 687210b23c2SDaniel Vetter size = MB(0); 688210b23c2SDaniel Vetter break; 689210b23c2SDaniel Vetter case SNB_GTT_SIZE_1M: 690210b23c2SDaniel Vetter size = MB(1); 691210b23c2SDaniel Vetter break; 692210b23c2SDaniel Vetter case SNB_GTT_SIZE_2M: 693210b23c2SDaniel Vetter size = MB(2); 694210b23c2SDaniel Vetter break; 695210b23c2SDaniel Vetter } 696210b23c2SDaniel Vetter return size/4; 697fbe40783SDaniel Vetter } else { 698fbe40783SDaniel Vetter /* On previous hardware, the GTT size was just what was 699fbe40783SDaniel Vetter * required to map the aperture. 700fbe40783SDaniel Vetter */ 701e5e408fcSDaniel Vetter return intel_private.base.gtt_mappable_entries; 702fbe40783SDaniel Vetter } 703fbe40783SDaniel Vetter } 704fbe40783SDaniel Vetter 7051784a5fbSDaniel Vetter static unsigned int intel_gtt_mappable_entries(void) 7061784a5fbSDaniel Vetter { 7071784a5fbSDaniel Vetter unsigned int aperture_size; 7081784a5fbSDaniel Vetter 709b1c5b0f8SChris Wilson if (INTEL_GTT_GEN == 2) { 710b1c5b0f8SChris Wilson u16 gmch_ctrl; 7111784a5fbSDaniel Vetter 7121784a5fbSDaniel Vetter pci_read_config_word(intel_private.bridge_dev, 7131784a5fbSDaniel Vetter I830_GMCH_CTRL, &gmch_ctrl); 7141784a5fbSDaniel Vetter 7151784a5fbSDaniel Vetter if ((gmch_ctrl & I830_GMCH_MEM_MASK) == I830_GMCH_MEM_64M) 716b1c5b0f8SChris Wilson aperture_size = MB(64); 7171784a5fbSDaniel Vetter else 718b1c5b0f8SChris Wilson aperture_size = MB(128); 719239918f7SDaniel Vetter } else { 7201784a5fbSDaniel Vetter /* 9xx supports large sizes, just look at the length */ 7211784a5fbSDaniel Vetter aperture_size = pci_resource_len(intel_private.pcidev, 2); 7221784a5fbSDaniel Vetter } 7231784a5fbSDaniel Vetter 7241784a5fbSDaniel Vetter return aperture_size >> PAGE_SHIFT; 7251784a5fbSDaniel Vetter } 7261784a5fbSDaniel Vetter 7270e87d2b0SDaniel Vetter static void intel_gtt_teardown_scratch_page(void) 7280e87d2b0SDaniel Vetter { 7290e87d2b0SDaniel Vetter set_pages_wb(intel_private.scratch_page, 1); 7300e87d2b0SDaniel Vetter pci_unmap_page(intel_private.pcidev, intel_private.scratch_page_dma, 7310e87d2b0SDaniel Vetter PAGE_SIZE, PCI_DMA_BIDIRECTIONAL); 7320e87d2b0SDaniel Vetter put_page(intel_private.scratch_page); 7330e87d2b0SDaniel Vetter __free_page(intel_private.scratch_page); 7340e87d2b0SDaniel Vetter } 7350e87d2b0SDaniel Vetter 7360e87d2b0SDaniel Vetter static void intel_gtt_cleanup(void) 7370e87d2b0SDaniel Vetter { 738ae83dd5cSDaniel Vetter intel_private.driver->cleanup(); 739ae83dd5cSDaniel Vetter 7400e87d2b0SDaniel Vetter iounmap(intel_private.gtt); 7410e87d2b0SDaniel Vetter iounmap(intel_private.registers); 7420e87d2b0SDaniel Vetter 7430e87d2b0SDaniel Vetter intel_gtt_teardown_scratch_page(); 7440e87d2b0SDaniel Vetter } 7450e87d2b0SDaniel Vetter 7461784a5fbSDaniel Vetter static int intel_gtt_init(void) 7471784a5fbSDaniel Vetter { 748f67eab66SDaniel Vetter u32 gtt_map_size; 7493b15a9d7SDaniel Vetter int ret; 7503b15a9d7SDaniel Vetter 7513b15a9d7SDaniel Vetter ret = intel_private.driver->setup(); 7523b15a9d7SDaniel Vetter if (ret != 0) 7533b15a9d7SDaniel Vetter return ret; 754f67eab66SDaniel Vetter 755f67eab66SDaniel Vetter intel_private.base.gtt_mappable_entries = intel_gtt_mappable_entries(); 756f67eab66SDaniel Vetter intel_private.base.gtt_total_entries = intel_gtt_total_entries(); 757f67eab66SDaniel Vetter 758*b3eafc5aSDaniel Vetter /* save the PGETBL reg for resume */ 759*b3eafc5aSDaniel Vetter intel_private.PGETBL_save = 760*b3eafc5aSDaniel Vetter readl(intel_private.registers+I810_PGETBL_CTL) 761*b3eafc5aSDaniel Vetter & ~I810_PGETBL_ENABLED; 762*b3eafc5aSDaniel Vetter 7630af9e92eSDaniel Vetter dev_info(&intel_private.bridge_dev->dev, 7640af9e92eSDaniel Vetter "detected gtt size: %dK total, %dK mappable\n", 7650af9e92eSDaniel Vetter intel_private.base.gtt_total_entries * 4, 7660af9e92eSDaniel Vetter intel_private.base.gtt_mappable_entries * 4); 7670af9e92eSDaniel Vetter 768f67eab66SDaniel Vetter gtt_map_size = intel_private.base.gtt_total_entries * 4; 769f67eab66SDaniel Vetter 770f67eab66SDaniel Vetter intel_private.gtt = ioremap(intel_private.gtt_bus_addr, 771f67eab66SDaniel Vetter gtt_map_size); 772f67eab66SDaniel Vetter if (!intel_private.gtt) { 773ae83dd5cSDaniel Vetter intel_private.driver->cleanup(); 774f67eab66SDaniel Vetter iounmap(intel_private.registers); 775f67eab66SDaniel Vetter return -ENOMEM; 776f67eab66SDaniel Vetter } 777f67eab66SDaniel Vetter 778f67eab66SDaniel Vetter global_cache_flush(); /* FIXME: ? */ 779f67eab66SDaniel Vetter 7801784a5fbSDaniel Vetter /* we have to call this as early as possible after the MMIO base address is known */ 7811784a5fbSDaniel Vetter intel_private.base.gtt_stolen_entries = intel_gtt_stolen_entries(); 7821784a5fbSDaniel Vetter if (intel_private.base.gtt_stolen_entries == 0) { 783ae83dd5cSDaniel Vetter intel_private.driver->cleanup(); 7841784a5fbSDaniel Vetter iounmap(intel_private.registers); 785f67eab66SDaniel Vetter iounmap(intel_private.gtt); 7861784a5fbSDaniel Vetter return -ENOMEM; 7871784a5fbSDaniel Vetter } 7881784a5fbSDaniel Vetter 7890e87d2b0SDaniel Vetter ret = intel_gtt_setup_scratch_page(); 7900e87d2b0SDaniel Vetter if (ret != 0) { 7910e87d2b0SDaniel Vetter intel_gtt_cleanup(); 7920e87d2b0SDaniel Vetter return ret; 7930e87d2b0SDaniel Vetter } 7940e87d2b0SDaniel Vetter 7951784a5fbSDaniel Vetter return 0; 7961784a5fbSDaniel Vetter } 7971784a5fbSDaniel Vetter 7983e921f98SDaniel Vetter static int intel_fake_agp_fetch_size(void) 7993e921f98SDaniel Vetter { 8009e76e7b8SChris Wilson int num_sizes = ARRAY_SIZE(intel_fake_agp_sizes); 8013e921f98SDaniel Vetter unsigned int aper_size; 8023e921f98SDaniel Vetter int i; 8033e921f98SDaniel Vetter 8043e921f98SDaniel Vetter aper_size = (intel_private.base.gtt_mappable_entries << PAGE_SHIFT) 8053e921f98SDaniel Vetter / MB(1); 8063e921f98SDaniel Vetter 8073e921f98SDaniel Vetter for (i = 0; i < num_sizes; i++) { 808ffdd7510SDaniel Vetter if (aper_size == intel_fake_agp_sizes[i].size) { 8099e76e7b8SChris Wilson agp_bridge->current_size = 8109e76e7b8SChris Wilson (void *) (intel_fake_agp_sizes + i); 8113e921f98SDaniel Vetter return aper_size; 8123e921f98SDaniel Vetter } 8133e921f98SDaniel Vetter } 8143e921f98SDaniel Vetter 8153e921f98SDaniel Vetter return 0; 8163e921f98SDaniel Vetter } 8173e921f98SDaniel Vetter 818ae83dd5cSDaniel Vetter static void i830_cleanup(void) 819f51b7662SDaniel Vetter { 820f51b7662SDaniel Vetter kunmap(intel_private.i8xx_page); 821f51b7662SDaniel Vetter intel_private.i8xx_flush_page = NULL; 822f51b7662SDaniel Vetter 823f51b7662SDaniel Vetter __free_page(intel_private.i8xx_page); 824f51b7662SDaniel Vetter intel_private.i8xx_page = NULL; 825f51b7662SDaniel Vetter } 826f51b7662SDaniel Vetter 827f51b7662SDaniel Vetter static void intel_i830_setup_flush(void) 828f51b7662SDaniel Vetter { 829f51b7662SDaniel Vetter /* return if we've already set the flush mechanism up */ 830f51b7662SDaniel Vetter if (intel_private.i8xx_page) 831f51b7662SDaniel Vetter return; 832f51b7662SDaniel Vetter 833e61cb0d5SJan Beulich intel_private.i8xx_page = alloc_page(GFP_KERNEL); 834f51b7662SDaniel Vetter if (!intel_private.i8xx_page) 835f51b7662SDaniel Vetter return; 836f51b7662SDaniel Vetter 837f51b7662SDaniel Vetter intel_private.i8xx_flush_page = kmap(intel_private.i8xx_page); 838f51b7662SDaniel Vetter if (!intel_private.i8xx_flush_page) 839ae83dd5cSDaniel Vetter i830_cleanup(); 840f51b7662SDaniel Vetter } 841f51b7662SDaniel Vetter 842f51b7662SDaniel Vetter /* The chipset_flush interface needs to get data that has already been 843f51b7662SDaniel Vetter * flushed out of the CPU all the way out to main memory, because the GPU 844f51b7662SDaniel Vetter * doesn't snoop those buffers. 845f51b7662SDaniel Vetter * 846f51b7662SDaniel Vetter * The 8xx series doesn't have the same lovely interface for flushing the 847f51b7662SDaniel Vetter * chipset write buffers that the later chips do. According to the 865 848f51b7662SDaniel Vetter * specs, it's 64 octwords, or 1KB. So, to get those previous things in 849f51b7662SDaniel Vetter * that buffer out, we just fill 1KB and clflush it out, on the assumption 850f51b7662SDaniel Vetter * that it'll push whatever was in there out. It appears to work. 851f51b7662SDaniel Vetter */ 8521b263f24SDaniel Vetter static void i830_chipset_flush(void) 853f51b7662SDaniel Vetter { 854f51b7662SDaniel Vetter unsigned int *pg = intel_private.i8xx_flush_page; 855f51b7662SDaniel Vetter 856f51b7662SDaniel Vetter memset(pg, 0, 1024); 857f51b7662SDaniel Vetter 858f51b7662SDaniel Vetter if (cpu_has_clflush) 859f51b7662SDaniel Vetter clflush_cache_range(pg, 1024); 860f51b7662SDaniel Vetter else if (wbinvd_on_all_cpus() != 0) 861f51b7662SDaniel Vetter printk(KERN_ERR "Timed out waiting for cache flush.\n"); 862f51b7662SDaniel Vetter } 863f51b7662SDaniel Vetter 864351bb278SDaniel Vetter static void i830_write_entry(dma_addr_t addr, unsigned int entry, 865351bb278SDaniel Vetter unsigned int flags) 866351bb278SDaniel Vetter { 867351bb278SDaniel Vetter u32 pte_flags = I810_PTE_VALID; 868351bb278SDaniel Vetter 869351bb278SDaniel Vetter switch (flags) { 870351bb278SDaniel Vetter case AGP_DCACHE_MEMORY: 871351bb278SDaniel Vetter pte_flags |= I810_PTE_LOCAL; 872351bb278SDaniel Vetter break; 873351bb278SDaniel Vetter case AGP_USER_CACHED_MEMORY: 874351bb278SDaniel Vetter pte_flags |= I830_PTE_SYSTEM_CACHED; 875351bb278SDaniel Vetter break; 876351bb278SDaniel Vetter } 877351bb278SDaniel Vetter 878351bb278SDaniel Vetter writel(addr | pte_flags, intel_private.gtt + entry); 879351bb278SDaniel Vetter } 880351bb278SDaniel Vetter 88173800422SDaniel Vetter static void intel_enable_gtt(void) 88273800422SDaniel Vetter { 8833f08e4efSChris Wilson u32 gma_addr; 88473800422SDaniel Vetter u16 gmch_ctrl; 88573800422SDaniel Vetter 8862d2430cfSDaniel Vetter if (INTEL_GTT_GEN == 2) 8872d2430cfSDaniel Vetter pci_read_config_dword(intel_private.pcidev, I810_GMADDR, 8882d2430cfSDaniel Vetter &gma_addr); 8892d2430cfSDaniel Vetter else 8902d2430cfSDaniel Vetter pci_read_config_dword(intel_private.pcidev, I915_GMADDR, 8912d2430cfSDaniel Vetter &gma_addr); 8922d2430cfSDaniel Vetter 89373800422SDaniel Vetter intel_private.gma_bus_addr = (gma_addr & PCI_BASE_ADDRESS_MEM_MASK); 89473800422SDaniel Vetter 89573800422SDaniel Vetter pci_read_config_word(intel_private.bridge_dev, I830_GMCH_CTRL, &gmch_ctrl); 89673800422SDaniel Vetter gmch_ctrl |= I830_GMCH_ENABLED; 89773800422SDaniel Vetter pci_write_config_word(intel_private.bridge_dev, I830_GMCH_CTRL, gmch_ctrl); 89873800422SDaniel Vetter 899*b3eafc5aSDaniel Vetter writel(intel_private.PGETBL_save|I810_PGETBL_ENABLED, 9003f08e4efSChris Wilson intel_private.registers+I810_PGETBL_CTL); 90173800422SDaniel Vetter readl(intel_private.registers+I810_PGETBL_CTL); /* PCI Posting. */ 90273800422SDaniel Vetter } 90373800422SDaniel Vetter 90473800422SDaniel Vetter static int i830_setup(void) 90573800422SDaniel Vetter { 90673800422SDaniel Vetter u32 reg_addr; 90773800422SDaniel Vetter 90873800422SDaniel Vetter pci_read_config_dword(intel_private.pcidev, I810_MMADDR, ®_addr); 90973800422SDaniel Vetter reg_addr &= 0xfff80000; 91073800422SDaniel Vetter 91173800422SDaniel Vetter intel_private.registers = ioremap(reg_addr, KB(64)); 91273800422SDaniel Vetter if (!intel_private.registers) 91373800422SDaniel Vetter return -ENOMEM; 91473800422SDaniel Vetter 91573800422SDaniel Vetter intel_private.gtt_bus_addr = reg_addr + I810_PTE_BASE; 91673800422SDaniel Vetter 91773800422SDaniel Vetter intel_i830_setup_flush(); 91873800422SDaniel Vetter 91973800422SDaniel Vetter return 0; 92073800422SDaniel Vetter } 92173800422SDaniel Vetter 9223b15a9d7SDaniel Vetter static int intel_fake_agp_create_gatt_table(struct agp_bridge_data *bridge) 923f51b7662SDaniel Vetter { 92473800422SDaniel Vetter agp_bridge->gatt_table_real = NULL; 925f51b7662SDaniel Vetter agp_bridge->gatt_table = NULL; 92673800422SDaniel Vetter agp_bridge->gatt_bus_addr = 0; 927f51b7662SDaniel Vetter 928f51b7662SDaniel Vetter return 0; 929f51b7662SDaniel Vetter } 930f51b7662SDaniel Vetter 931ffdd7510SDaniel Vetter static int intel_fake_agp_free_gatt_table(struct agp_bridge_data *bridge) 932f51b7662SDaniel Vetter { 933f51b7662SDaniel Vetter return 0; 934f51b7662SDaniel Vetter } 935f51b7662SDaniel Vetter 936351bb278SDaniel Vetter static int intel_fake_agp_configure(void) 937f51b7662SDaniel Vetter { 938f51b7662SDaniel Vetter int i; 939f51b7662SDaniel Vetter 94073800422SDaniel Vetter intel_enable_gtt(); 941f51b7662SDaniel Vetter 94273800422SDaniel Vetter agp_bridge->gart_bus_addr = intel_private.gma_bus_addr; 943f51b7662SDaniel Vetter 94473800422SDaniel Vetter for (i = intel_private.base.gtt_stolen_entries; 94573800422SDaniel Vetter i < intel_private.base.gtt_total_entries; i++) { 946351bb278SDaniel Vetter intel_private.driver->write_entry(intel_private.scratch_page_dma, 947351bb278SDaniel Vetter i, 0); 948f51b7662SDaniel Vetter } 949fdfb58a9SDaniel Vetter readl(intel_private.gtt+i-1); /* PCI Posting. */ 950f51b7662SDaniel Vetter 951f51b7662SDaniel Vetter global_cache_flush(); 952f51b7662SDaniel Vetter 953f51b7662SDaniel Vetter return 0; 954f51b7662SDaniel Vetter } 955f51b7662SDaniel Vetter 9565cbecafcSDaniel Vetter static bool i830_check_flags(unsigned int flags) 957f51b7662SDaniel Vetter { 9585cbecafcSDaniel Vetter switch (flags) { 9595cbecafcSDaniel Vetter case 0: 9605cbecafcSDaniel Vetter case AGP_PHYS_MEMORY: 9615cbecafcSDaniel Vetter case AGP_USER_CACHED_MEMORY: 9625cbecafcSDaniel Vetter case AGP_USER_MEMORY: 9635cbecafcSDaniel Vetter return true; 9645cbecafcSDaniel Vetter } 9655cbecafcSDaniel Vetter 9665cbecafcSDaniel Vetter return false; 9675cbecafcSDaniel Vetter } 9685cbecafcSDaniel Vetter 969fefaa70fSDaniel Vetter static void intel_gtt_insert_sg_entries(struct scatterlist *sg_list, 970fefaa70fSDaniel Vetter unsigned int sg_len, 971fefaa70fSDaniel Vetter unsigned int pg_start, 972fefaa70fSDaniel Vetter unsigned int flags) 973fefaa70fSDaniel Vetter { 974fefaa70fSDaniel Vetter struct scatterlist *sg; 975fefaa70fSDaniel Vetter unsigned int len, m; 976fefaa70fSDaniel Vetter int i, j; 977fefaa70fSDaniel Vetter 978fefaa70fSDaniel Vetter j = pg_start; 979fefaa70fSDaniel Vetter 980fefaa70fSDaniel Vetter /* sg may merge pages, but we have to separate 981fefaa70fSDaniel Vetter * per-page addr for GTT */ 982fefaa70fSDaniel Vetter for_each_sg(sg_list, sg, sg_len, i) { 983fefaa70fSDaniel Vetter len = sg_dma_len(sg) >> PAGE_SHIFT; 984fefaa70fSDaniel Vetter for (m = 0; m < len; m++) { 985fefaa70fSDaniel Vetter dma_addr_t addr = sg_dma_address(sg) + (m << PAGE_SHIFT); 986fefaa70fSDaniel Vetter intel_private.driver->write_entry(addr, 987fefaa70fSDaniel Vetter j, flags); 988fefaa70fSDaniel Vetter j++; 989fefaa70fSDaniel Vetter } 990fefaa70fSDaniel Vetter } 991fefaa70fSDaniel Vetter readl(intel_private.gtt+j-1); 992fefaa70fSDaniel Vetter } 993fefaa70fSDaniel Vetter 9945cbecafcSDaniel Vetter static int intel_fake_agp_insert_entries(struct agp_memory *mem, 9955cbecafcSDaniel Vetter off_t pg_start, int type) 9965cbecafcSDaniel Vetter { 9975cbecafcSDaniel Vetter int i, j; 998f51b7662SDaniel Vetter int ret = -EINVAL; 999f51b7662SDaniel Vetter 1000f51b7662SDaniel Vetter if (mem->page_count == 0) 1001f51b7662SDaniel Vetter goto out; 1002f51b7662SDaniel Vetter 10030ade6386SDaniel Vetter if (pg_start < intel_private.base.gtt_stolen_entries) { 1004f51b7662SDaniel Vetter dev_printk(KERN_DEBUG, &intel_private.pcidev->dev, 10050ade6386SDaniel Vetter "pg_start == 0x%.8lx, gtt_stolen_entries == 0x%.8x\n", 10060ade6386SDaniel Vetter pg_start, intel_private.base.gtt_stolen_entries); 1007f51b7662SDaniel Vetter 1008f51b7662SDaniel Vetter dev_info(&intel_private.pcidev->dev, 1009f51b7662SDaniel Vetter "trying to insert into local/stolen memory\n"); 1010f51b7662SDaniel Vetter goto out_err; 1011f51b7662SDaniel Vetter } 1012f51b7662SDaniel Vetter 10135cbecafcSDaniel Vetter if ((pg_start + mem->page_count) > intel_private.base.gtt_total_entries) 1014f51b7662SDaniel Vetter goto out_err; 1015f51b7662SDaniel Vetter 1016f51b7662SDaniel Vetter if (type != mem->type) 1017f51b7662SDaniel Vetter goto out_err; 1018f51b7662SDaniel Vetter 10195cbecafcSDaniel Vetter if (!intel_private.driver->check_flags(type)) 1020f51b7662SDaniel Vetter goto out_err; 1021f51b7662SDaniel Vetter 1022f51b7662SDaniel Vetter if (!mem->is_flushed) 1023f51b7662SDaniel Vetter global_cache_flush(); 1024f51b7662SDaniel Vetter 1025fefaa70fSDaniel Vetter if (USE_PCI_DMA_API && INTEL_GTT_GEN > 2) { 1026fefaa70fSDaniel Vetter ret = intel_agp_map_memory(mem); 1027fefaa70fSDaniel Vetter if (ret != 0) 1028fefaa70fSDaniel Vetter return ret; 1029fefaa70fSDaniel Vetter 1030fefaa70fSDaniel Vetter intel_gtt_insert_sg_entries(mem->sg_list, mem->num_sg, 1031fefaa70fSDaniel Vetter pg_start, type); 1032fefaa70fSDaniel Vetter } else { 1033f51b7662SDaniel Vetter for (i = 0, j = pg_start; i < mem->page_count; i++, j++) { 1034fefaa70fSDaniel Vetter dma_addr_t addr = page_to_phys(mem->pages[i]); 1035fefaa70fSDaniel Vetter intel_private.driver->write_entry(addr, 10365cbecafcSDaniel Vetter j, type); 1037f51b7662SDaniel Vetter } 1038fdfb58a9SDaniel Vetter readl(intel_private.gtt+j-1); 1039fefaa70fSDaniel Vetter } 1040f51b7662SDaniel Vetter 1041f51b7662SDaniel Vetter out: 1042f51b7662SDaniel Vetter ret = 0; 1043f51b7662SDaniel Vetter out_err: 1044f51b7662SDaniel Vetter mem->is_flushed = true; 1045f51b7662SDaniel Vetter return ret; 1046f51b7662SDaniel Vetter } 1047f51b7662SDaniel Vetter 10485cbecafcSDaniel Vetter static int intel_fake_agp_remove_entries(struct agp_memory *mem, 10495cbecafcSDaniel Vetter off_t pg_start, int type) 1050f51b7662SDaniel Vetter { 1051f51b7662SDaniel Vetter int i; 1052f51b7662SDaniel Vetter 1053f51b7662SDaniel Vetter if (mem->page_count == 0) 1054f51b7662SDaniel Vetter return 0; 1055f51b7662SDaniel Vetter 10560ade6386SDaniel Vetter if (pg_start < intel_private.base.gtt_stolen_entries) { 1057f51b7662SDaniel Vetter dev_info(&intel_private.pcidev->dev, 1058f51b7662SDaniel Vetter "trying to disable local/stolen memory\n"); 1059f51b7662SDaniel Vetter return -EINVAL; 1060f51b7662SDaniel Vetter } 1061f51b7662SDaniel Vetter 1062fefaa70fSDaniel Vetter if (USE_PCI_DMA_API && INTEL_GTT_GEN > 2) 1063fefaa70fSDaniel Vetter intel_agp_unmap_memory(mem); 1064fefaa70fSDaniel Vetter 1065f51b7662SDaniel Vetter for (i = pg_start; i < (mem->page_count + pg_start); i++) { 10665cbecafcSDaniel Vetter intel_private.driver->write_entry(intel_private.scratch_page_dma, 10675cbecafcSDaniel Vetter i, 0); 1068f51b7662SDaniel Vetter } 1069fdfb58a9SDaniel Vetter readl(intel_private.gtt+i-1); 1070f51b7662SDaniel Vetter 1071f51b7662SDaniel Vetter return 0; 1072f51b7662SDaniel Vetter } 1073f51b7662SDaniel Vetter 10741b263f24SDaniel Vetter static void intel_fake_agp_chipset_flush(struct agp_bridge_data *bridge) 10751b263f24SDaniel Vetter { 10761b263f24SDaniel Vetter intel_private.driver->chipset_flush(); 10771b263f24SDaniel Vetter } 10781b263f24SDaniel Vetter 1079ffdd7510SDaniel Vetter static struct agp_memory *intel_fake_agp_alloc_by_type(size_t pg_count, 1080ffdd7510SDaniel Vetter int type) 1081f51b7662SDaniel Vetter { 1082f51b7662SDaniel Vetter if (type == AGP_PHYS_MEMORY) 1083f51b7662SDaniel Vetter return alloc_agpphysmem_i8xx(pg_count, type); 1084f51b7662SDaniel Vetter /* always return NULL for other allocation types for now */ 1085f51b7662SDaniel Vetter return NULL; 1086f51b7662SDaniel Vetter } 1087f51b7662SDaniel Vetter 1088f51b7662SDaniel Vetter static int intel_alloc_chipset_flush_resource(void) 1089f51b7662SDaniel Vetter { 1090f51b7662SDaniel Vetter int ret; 1091d7cca2f7SDaniel Vetter ret = pci_bus_alloc_resource(intel_private.bridge_dev->bus, &intel_private.ifp_resource, PAGE_SIZE, 1092f51b7662SDaniel Vetter PAGE_SIZE, PCIBIOS_MIN_MEM, 0, 1093d7cca2f7SDaniel Vetter pcibios_align_resource, intel_private.bridge_dev); 1094f51b7662SDaniel Vetter 1095f51b7662SDaniel Vetter return ret; 1096f51b7662SDaniel Vetter } 1097f51b7662SDaniel Vetter 1098f51b7662SDaniel Vetter static void intel_i915_setup_chipset_flush(void) 1099f51b7662SDaniel Vetter { 1100f51b7662SDaniel Vetter int ret; 1101f51b7662SDaniel Vetter u32 temp; 1102f51b7662SDaniel Vetter 1103d7cca2f7SDaniel Vetter pci_read_config_dword(intel_private.bridge_dev, I915_IFPADDR, &temp); 1104f51b7662SDaniel Vetter if (!(temp & 0x1)) { 1105f51b7662SDaniel Vetter intel_alloc_chipset_flush_resource(); 1106f51b7662SDaniel Vetter intel_private.resource_valid = 1; 1107d7cca2f7SDaniel Vetter pci_write_config_dword(intel_private.bridge_dev, I915_IFPADDR, (intel_private.ifp_resource.start & 0xffffffff) | 0x1); 1108f51b7662SDaniel Vetter } else { 1109f51b7662SDaniel Vetter temp &= ~1; 1110f51b7662SDaniel Vetter 1111f51b7662SDaniel Vetter intel_private.resource_valid = 1; 1112f51b7662SDaniel Vetter intel_private.ifp_resource.start = temp; 1113f51b7662SDaniel Vetter intel_private.ifp_resource.end = temp + PAGE_SIZE; 1114f51b7662SDaniel Vetter ret = request_resource(&iomem_resource, &intel_private.ifp_resource); 1115f51b7662SDaniel Vetter /* some BIOSes reserve this area in a pnp some don't */ 1116f51b7662SDaniel Vetter if (ret) 1117f51b7662SDaniel Vetter intel_private.resource_valid = 0; 1118f51b7662SDaniel Vetter } 1119f51b7662SDaniel Vetter } 1120f51b7662SDaniel Vetter 1121f51b7662SDaniel Vetter static void intel_i965_g33_setup_chipset_flush(void) 1122f51b7662SDaniel Vetter { 1123f51b7662SDaniel Vetter u32 temp_hi, temp_lo; 1124f51b7662SDaniel Vetter int ret; 1125f51b7662SDaniel Vetter 1126d7cca2f7SDaniel Vetter pci_read_config_dword(intel_private.bridge_dev, I965_IFPADDR + 4, &temp_hi); 1127d7cca2f7SDaniel Vetter pci_read_config_dword(intel_private.bridge_dev, I965_IFPADDR, &temp_lo); 1128f51b7662SDaniel Vetter 1129f51b7662SDaniel Vetter if (!(temp_lo & 0x1)) { 1130f51b7662SDaniel Vetter 1131f51b7662SDaniel Vetter intel_alloc_chipset_flush_resource(); 1132f51b7662SDaniel Vetter 1133f51b7662SDaniel Vetter intel_private.resource_valid = 1; 1134d7cca2f7SDaniel Vetter pci_write_config_dword(intel_private.bridge_dev, I965_IFPADDR + 4, 1135f51b7662SDaniel Vetter upper_32_bits(intel_private.ifp_resource.start)); 1136d7cca2f7SDaniel Vetter pci_write_config_dword(intel_private.bridge_dev, I965_IFPADDR, (intel_private.ifp_resource.start & 0xffffffff) | 0x1); 1137f51b7662SDaniel Vetter } else { 1138f51b7662SDaniel Vetter u64 l64; 1139f51b7662SDaniel Vetter 1140f51b7662SDaniel Vetter temp_lo &= ~0x1; 1141f51b7662SDaniel Vetter l64 = ((u64)temp_hi << 32) | temp_lo; 1142f51b7662SDaniel Vetter 1143f51b7662SDaniel Vetter intel_private.resource_valid = 1; 1144f51b7662SDaniel Vetter intel_private.ifp_resource.start = l64; 1145f51b7662SDaniel Vetter intel_private.ifp_resource.end = l64 + PAGE_SIZE; 1146f51b7662SDaniel Vetter ret = request_resource(&iomem_resource, &intel_private.ifp_resource); 1147f51b7662SDaniel Vetter /* some BIOSes reserve this area in a pnp some don't */ 1148f51b7662SDaniel Vetter if (ret) 1149f51b7662SDaniel Vetter intel_private.resource_valid = 0; 1150f51b7662SDaniel Vetter } 1151f51b7662SDaniel Vetter } 1152f51b7662SDaniel Vetter 1153f51b7662SDaniel Vetter static void intel_i9xx_setup_flush(void) 1154f51b7662SDaniel Vetter { 1155f51b7662SDaniel Vetter /* return if already configured */ 1156f51b7662SDaniel Vetter if (intel_private.ifp_resource.start) 1157f51b7662SDaniel Vetter return; 1158f51b7662SDaniel Vetter 11591a997ff2SDaniel Vetter if (INTEL_GTT_GEN == 6) 1160f51b7662SDaniel Vetter return; 1161f51b7662SDaniel Vetter 1162f51b7662SDaniel Vetter /* setup a resource for this object */ 1163f51b7662SDaniel Vetter intel_private.ifp_resource.name = "Intel Flush Page"; 1164f51b7662SDaniel Vetter intel_private.ifp_resource.flags = IORESOURCE_MEM; 1165f51b7662SDaniel Vetter 1166f51b7662SDaniel Vetter /* Setup chipset flush for 915 */ 11671a997ff2SDaniel Vetter if (IS_G33 || INTEL_GTT_GEN >= 4) { 1168f51b7662SDaniel Vetter intel_i965_g33_setup_chipset_flush(); 1169f51b7662SDaniel Vetter } else { 1170f51b7662SDaniel Vetter intel_i915_setup_chipset_flush(); 1171f51b7662SDaniel Vetter } 1172f51b7662SDaniel Vetter 1173df51e7aaSChris Wilson if (intel_private.ifp_resource.start) 1174f51b7662SDaniel Vetter intel_private.i9xx_flush_page = ioremap_nocache(intel_private.ifp_resource.start, PAGE_SIZE); 1175f51b7662SDaniel Vetter if (!intel_private.i9xx_flush_page) 1176df51e7aaSChris Wilson dev_err(&intel_private.pcidev->dev, 1177df51e7aaSChris Wilson "can't ioremap flush page - no chipset flushing\n"); 1178f51b7662SDaniel Vetter } 1179f51b7662SDaniel Vetter 1180ae83dd5cSDaniel Vetter static void i9xx_cleanup(void) 1181ae83dd5cSDaniel Vetter { 1182ae83dd5cSDaniel Vetter if (intel_private.i9xx_flush_page) 1183ae83dd5cSDaniel Vetter iounmap(intel_private.i9xx_flush_page); 1184ae83dd5cSDaniel Vetter if (intel_private.resource_valid) 1185ae83dd5cSDaniel Vetter release_resource(&intel_private.ifp_resource); 1186ae83dd5cSDaniel Vetter intel_private.ifp_resource.start = 0; 1187ae83dd5cSDaniel Vetter intel_private.resource_valid = 0; 1188ae83dd5cSDaniel Vetter } 1189ae83dd5cSDaniel Vetter 11901b263f24SDaniel Vetter static void i9xx_chipset_flush(void) 1191f51b7662SDaniel Vetter { 1192f51b7662SDaniel Vetter if (intel_private.i9xx_flush_page) 1193f51b7662SDaniel Vetter writel(1, intel_private.i9xx_flush_page); 1194f51b7662SDaniel Vetter } 1195f51b7662SDaniel Vetter 1196a6963596SDaniel Vetter static void i965_write_entry(dma_addr_t addr, unsigned int entry, 1197a6963596SDaniel Vetter unsigned int flags) 1198a6963596SDaniel Vetter { 1199a6963596SDaniel Vetter /* Shift high bits down */ 1200a6963596SDaniel Vetter addr |= (addr >> 28) & 0xf0; 1201a6963596SDaniel Vetter writel(addr | I810_PTE_VALID, intel_private.gtt + entry); 1202a6963596SDaniel Vetter } 1203a6963596SDaniel Vetter 120490cb149eSDaniel Vetter static bool gen6_check_flags(unsigned int flags) 120590cb149eSDaniel Vetter { 120690cb149eSDaniel Vetter return true; 120790cb149eSDaniel Vetter } 120890cb149eSDaniel Vetter 120997ef1bddSDaniel Vetter static void gen6_write_entry(dma_addr_t addr, unsigned int entry, 121097ef1bddSDaniel Vetter unsigned int flags) 121197ef1bddSDaniel Vetter { 121297ef1bddSDaniel Vetter unsigned int type_mask = flags & ~AGP_USER_CACHED_MEMORY_GFDT; 121397ef1bddSDaniel Vetter unsigned int gfdt = flags & AGP_USER_CACHED_MEMORY_GFDT; 121497ef1bddSDaniel Vetter u32 pte_flags; 121597ef1bddSDaniel Vetter 121697ef1bddSDaniel Vetter if (type_mask == AGP_USER_UNCACHED_MEMORY) 121785ccc35bSChris Wilson pte_flags = GEN6_PTE_UNCACHED | I810_PTE_VALID; 121897ef1bddSDaniel Vetter else if (type_mask == AGP_USER_CACHED_MEMORY_LLC_MLC) { 121985ccc35bSChris Wilson pte_flags = GEN6_PTE_LLC | I810_PTE_VALID; 122097ef1bddSDaniel Vetter if (gfdt) 122197ef1bddSDaniel Vetter pte_flags |= GEN6_PTE_GFDT; 122297ef1bddSDaniel Vetter } else { /* set 'normal'/'cached' to LLC by default */ 122385ccc35bSChris Wilson pte_flags = GEN6_PTE_LLC_MLC | I810_PTE_VALID; 122497ef1bddSDaniel Vetter if (gfdt) 122597ef1bddSDaniel Vetter pte_flags |= GEN6_PTE_GFDT; 122697ef1bddSDaniel Vetter } 122797ef1bddSDaniel Vetter 122897ef1bddSDaniel Vetter /* gen6 has bit11-4 for physical addr bit39-32 */ 122997ef1bddSDaniel Vetter addr |= (addr >> 28) & 0xff0; 123097ef1bddSDaniel Vetter writel(addr | pte_flags, intel_private.gtt + entry); 123197ef1bddSDaniel Vetter } 123297ef1bddSDaniel Vetter 1233ae83dd5cSDaniel Vetter static void gen6_cleanup(void) 1234ae83dd5cSDaniel Vetter { 1235ae83dd5cSDaniel Vetter } 1236ae83dd5cSDaniel Vetter 12372d2430cfSDaniel Vetter static int i9xx_setup(void) 12382d2430cfSDaniel Vetter { 12392d2430cfSDaniel Vetter u32 reg_addr; 12402d2430cfSDaniel Vetter 12412d2430cfSDaniel Vetter pci_read_config_dword(intel_private.pcidev, I915_MMADDR, ®_addr); 12422d2430cfSDaniel Vetter 12432d2430cfSDaniel Vetter reg_addr &= 0xfff80000; 12442d2430cfSDaniel Vetter 12452d2430cfSDaniel Vetter intel_private.registers = ioremap(reg_addr, 128 * 4096); 12462d2430cfSDaniel Vetter if (!intel_private.registers) 12472d2430cfSDaniel Vetter return -ENOMEM; 12482d2430cfSDaniel Vetter 12492d2430cfSDaniel Vetter if (INTEL_GTT_GEN == 3) { 12502d2430cfSDaniel Vetter u32 gtt_addr; 12513f08e4efSChris Wilson 12522d2430cfSDaniel Vetter pci_read_config_dword(intel_private.pcidev, 12532d2430cfSDaniel Vetter I915_PTEADDR, >t_addr); 12542d2430cfSDaniel Vetter intel_private.gtt_bus_addr = gtt_addr; 12552d2430cfSDaniel Vetter } else { 12562d2430cfSDaniel Vetter u32 gtt_offset; 12572d2430cfSDaniel Vetter 12582d2430cfSDaniel Vetter switch (INTEL_GTT_GEN) { 12592d2430cfSDaniel Vetter case 5: 12602d2430cfSDaniel Vetter case 6: 12612d2430cfSDaniel Vetter gtt_offset = MB(2); 12622d2430cfSDaniel Vetter break; 12632d2430cfSDaniel Vetter case 4: 12642d2430cfSDaniel Vetter default: 12652d2430cfSDaniel Vetter gtt_offset = KB(512); 12662d2430cfSDaniel Vetter break; 12672d2430cfSDaniel Vetter } 12682d2430cfSDaniel Vetter intel_private.gtt_bus_addr = reg_addr + gtt_offset; 12692d2430cfSDaniel Vetter } 12702d2430cfSDaniel Vetter 12712d2430cfSDaniel Vetter intel_i9xx_setup_flush(); 12722d2430cfSDaniel Vetter 12732d2430cfSDaniel Vetter return 0; 12742d2430cfSDaniel Vetter } 12752d2430cfSDaniel Vetter 1276f51b7662SDaniel Vetter static const struct agp_bridge_driver intel_810_driver = { 1277f51b7662SDaniel Vetter .owner = THIS_MODULE, 1278f51b7662SDaniel Vetter .aperture_sizes = intel_i810_sizes, 1279f51b7662SDaniel Vetter .size_type = FIXED_APER_SIZE, 1280f51b7662SDaniel Vetter .num_aperture_sizes = 2, 1281f51b7662SDaniel Vetter .needs_scratch_page = true, 1282f51b7662SDaniel Vetter .configure = intel_i810_configure, 1283f51b7662SDaniel Vetter .fetch_size = intel_i810_fetch_size, 1284f51b7662SDaniel Vetter .cleanup = intel_i810_cleanup, 1285f51b7662SDaniel Vetter .mask_memory = intel_i810_mask_memory, 1286f51b7662SDaniel Vetter .masks = intel_i810_masks, 1287ffdd7510SDaniel Vetter .agp_enable = intel_fake_agp_enable, 1288f51b7662SDaniel Vetter .cache_flush = global_cache_flush, 1289f51b7662SDaniel Vetter .create_gatt_table = agp_generic_create_gatt_table, 1290f51b7662SDaniel Vetter .free_gatt_table = agp_generic_free_gatt_table, 1291f51b7662SDaniel Vetter .insert_memory = intel_i810_insert_entries, 1292f51b7662SDaniel Vetter .remove_memory = intel_i810_remove_entries, 1293f51b7662SDaniel Vetter .alloc_by_type = intel_i810_alloc_by_type, 1294f51b7662SDaniel Vetter .free_by_type = intel_i810_free_by_type, 1295f51b7662SDaniel Vetter .agp_alloc_page = agp_generic_alloc_page, 1296f51b7662SDaniel Vetter .agp_alloc_pages = agp_generic_alloc_pages, 1297f51b7662SDaniel Vetter .agp_destroy_page = agp_generic_destroy_page, 1298f51b7662SDaniel Vetter .agp_destroy_pages = agp_generic_destroy_pages, 1299f51b7662SDaniel Vetter .agp_type_to_mask_type = agp_generic_type_to_mask_type, 1300f51b7662SDaniel Vetter }; 1301f51b7662SDaniel Vetter 1302e9b1cc81SDaniel Vetter static const struct agp_bridge_driver intel_fake_agp_driver = { 1303f51b7662SDaniel Vetter .owner = THIS_MODULE, 1304f51b7662SDaniel Vetter .size_type = FIXED_APER_SIZE, 13059e76e7b8SChris Wilson .aperture_sizes = intel_fake_agp_sizes, 13069e76e7b8SChris Wilson .num_aperture_sizes = ARRAY_SIZE(intel_fake_agp_sizes), 1307a6963596SDaniel Vetter .configure = intel_fake_agp_configure, 13083e921f98SDaniel Vetter .fetch_size = intel_fake_agp_fetch_size, 1309fdfb58a9SDaniel Vetter .cleanup = intel_gtt_cleanup, 1310ffdd7510SDaniel Vetter .agp_enable = intel_fake_agp_enable, 1311f51b7662SDaniel Vetter .cache_flush = global_cache_flush, 13123b15a9d7SDaniel Vetter .create_gatt_table = intel_fake_agp_create_gatt_table, 1313ffdd7510SDaniel Vetter .free_gatt_table = intel_fake_agp_free_gatt_table, 1314450f2b3dSDaniel Vetter .insert_memory = intel_fake_agp_insert_entries, 1315450f2b3dSDaniel Vetter .remove_memory = intel_fake_agp_remove_entries, 1316ffdd7510SDaniel Vetter .alloc_by_type = intel_fake_agp_alloc_by_type, 1317f51b7662SDaniel Vetter .free_by_type = intel_i810_free_by_type, 1318f51b7662SDaniel Vetter .agp_alloc_page = agp_generic_alloc_page, 1319f51b7662SDaniel Vetter .agp_alloc_pages = agp_generic_alloc_pages, 1320f51b7662SDaniel Vetter .agp_destroy_page = agp_generic_destroy_page, 1321f51b7662SDaniel Vetter .agp_destroy_pages = agp_generic_destroy_pages, 13221b263f24SDaniel Vetter .chipset_flush = intel_fake_agp_chipset_flush, 1323f51b7662SDaniel Vetter }; 132402c026ceSDaniel Vetter 1325bdd30729SDaniel Vetter static const struct intel_gtt_driver i81x_gtt_driver = { 1326bdd30729SDaniel Vetter .gen = 1, 132722533b49SDaniel Vetter .dma_mask_size = 32, 1328bdd30729SDaniel Vetter }; 13291a997ff2SDaniel Vetter static const struct intel_gtt_driver i8xx_gtt_driver = { 13301a997ff2SDaniel Vetter .gen = 2, 133173800422SDaniel Vetter .setup = i830_setup, 1332ae83dd5cSDaniel Vetter .cleanup = i830_cleanup, 1333351bb278SDaniel Vetter .write_entry = i830_write_entry, 133422533b49SDaniel Vetter .dma_mask_size = 32, 13355cbecafcSDaniel Vetter .check_flags = i830_check_flags, 13361b263f24SDaniel Vetter .chipset_flush = i830_chipset_flush, 13371a997ff2SDaniel Vetter }; 13381a997ff2SDaniel Vetter static const struct intel_gtt_driver i915_gtt_driver = { 13391a997ff2SDaniel Vetter .gen = 3, 13402d2430cfSDaniel Vetter .setup = i9xx_setup, 1341ae83dd5cSDaniel Vetter .cleanup = i9xx_cleanup, 1342351bb278SDaniel Vetter /* i945 is the last gpu to need phys mem (for overlay and cursors). */ 1343351bb278SDaniel Vetter .write_entry = i830_write_entry, 134422533b49SDaniel Vetter .dma_mask_size = 32, 1345fefaa70fSDaniel Vetter .check_flags = i830_check_flags, 13461b263f24SDaniel Vetter .chipset_flush = i9xx_chipset_flush, 13471a997ff2SDaniel Vetter }; 13481a997ff2SDaniel Vetter static const struct intel_gtt_driver g33_gtt_driver = { 13491a997ff2SDaniel Vetter .gen = 3, 13501a997ff2SDaniel Vetter .is_g33 = 1, 13512d2430cfSDaniel Vetter .setup = i9xx_setup, 1352ae83dd5cSDaniel Vetter .cleanup = i9xx_cleanup, 1353a6963596SDaniel Vetter .write_entry = i965_write_entry, 135422533b49SDaniel Vetter .dma_mask_size = 36, 1355450f2b3dSDaniel Vetter .check_flags = i830_check_flags, 13561b263f24SDaniel Vetter .chipset_flush = i9xx_chipset_flush, 13571a997ff2SDaniel Vetter }; 13581a997ff2SDaniel Vetter static const struct intel_gtt_driver pineview_gtt_driver = { 13591a997ff2SDaniel Vetter .gen = 3, 13601a997ff2SDaniel Vetter .is_pineview = 1, .is_g33 = 1, 13612d2430cfSDaniel Vetter .setup = i9xx_setup, 1362ae83dd5cSDaniel Vetter .cleanup = i9xx_cleanup, 1363a6963596SDaniel Vetter .write_entry = i965_write_entry, 136422533b49SDaniel Vetter .dma_mask_size = 36, 1365450f2b3dSDaniel Vetter .check_flags = i830_check_flags, 13661b263f24SDaniel Vetter .chipset_flush = i9xx_chipset_flush, 13671a997ff2SDaniel Vetter }; 13681a997ff2SDaniel Vetter static const struct intel_gtt_driver i965_gtt_driver = { 13691a997ff2SDaniel Vetter .gen = 4, 13702d2430cfSDaniel Vetter .setup = i9xx_setup, 1371ae83dd5cSDaniel Vetter .cleanup = i9xx_cleanup, 1372a6963596SDaniel Vetter .write_entry = i965_write_entry, 137322533b49SDaniel Vetter .dma_mask_size = 36, 1374450f2b3dSDaniel Vetter .check_flags = i830_check_flags, 13751b263f24SDaniel Vetter .chipset_flush = i9xx_chipset_flush, 13761a997ff2SDaniel Vetter }; 13771a997ff2SDaniel Vetter static const struct intel_gtt_driver g4x_gtt_driver = { 13781a997ff2SDaniel Vetter .gen = 5, 13792d2430cfSDaniel Vetter .setup = i9xx_setup, 1380ae83dd5cSDaniel Vetter .cleanup = i9xx_cleanup, 1381a6963596SDaniel Vetter .write_entry = i965_write_entry, 138222533b49SDaniel Vetter .dma_mask_size = 36, 1383450f2b3dSDaniel Vetter .check_flags = i830_check_flags, 13841b263f24SDaniel Vetter .chipset_flush = i9xx_chipset_flush, 13851a997ff2SDaniel Vetter }; 13861a997ff2SDaniel Vetter static const struct intel_gtt_driver ironlake_gtt_driver = { 13871a997ff2SDaniel Vetter .gen = 5, 13881a997ff2SDaniel Vetter .is_ironlake = 1, 13892d2430cfSDaniel Vetter .setup = i9xx_setup, 1390ae83dd5cSDaniel Vetter .cleanup = i9xx_cleanup, 1391a6963596SDaniel Vetter .write_entry = i965_write_entry, 139222533b49SDaniel Vetter .dma_mask_size = 36, 1393450f2b3dSDaniel Vetter .check_flags = i830_check_flags, 13941b263f24SDaniel Vetter .chipset_flush = i9xx_chipset_flush, 13951a997ff2SDaniel Vetter }; 13961a997ff2SDaniel Vetter static const struct intel_gtt_driver sandybridge_gtt_driver = { 13971a997ff2SDaniel Vetter .gen = 6, 13982d2430cfSDaniel Vetter .setup = i9xx_setup, 1399ae83dd5cSDaniel Vetter .cleanup = gen6_cleanup, 140097ef1bddSDaniel Vetter .write_entry = gen6_write_entry, 140122533b49SDaniel Vetter .dma_mask_size = 40, 140290cb149eSDaniel Vetter .check_flags = gen6_check_flags, 14031b263f24SDaniel Vetter .chipset_flush = i9xx_chipset_flush, 14041a997ff2SDaniel Vetter }; 14051a997ff2SDaniel Vetter 140602c026ceSDaniel Vetter /* Table to describe Intel GMCH and AGP/PCIE GART drivers. At least one of 140702c026ceSDaniel Vetter * driver and gmch_driver must be non-null, and find_gmch will determine 140802c026ceSDaniel Vetter * which one should be used if a gmch_chip_id is present. 140902c026ceSDaniel Vetter */ 141002c026ceSDaniel Vetter static const struct intel_gtt_driver_description { 141102c026ceSDaniel Vetter unsigned int gmch_chip_id; 141202c026ceSDaniel Vetter char *name; 141302c026ceSDaniel Vetter const struct agp_bridge_driver *gmch_driver; 14141a997ff2SDaniel Vetter const struct intel_gtt_driver *gtt_driver; 141502c026ceSDaniel Vetter } intel_gtt_chipsets[] = { 1416bdd30729SDaniel Vetter { PCI_DEVICE_ID_INTEL_82810_IG1, "i810", &intel_810_driver, 1417bdd30729SDaniel Vetter &i81x_gtt_driver}, 1418bdd30729SDaniel Vetter { PCI_DEVICE_ID_INTEL_82810_IG3, "i810", &intel_810_driver, 1419bdd30729SDaniel Vetter &i81x_gtt_driver}, 1420bdd30729SDaniel Vetter { PCI_DEVICE_ID_INTEL_82810E_IG, "i810", &intel_810_driver, 1421bdd30729SDaniel Vetter &i81x_gtt_driver}, 1422bdd30729SDaniel Vetter { PCI_DEVICE_ID_INTEL_82815_CGC, "i815", &intel_810_driver, 1423bdd30729SDaniel Vetter &i81x_gtt_driver}, 14241a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_82830_CGC, "830M", 1425e9b1cc81SDaniel Vetter &intel_fake_agp_driver, &i8xx_gtt_driver}, 14261a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_82845G_IG, "830M", 1427e9b1cc81SDaniel Vetter &intel_fake_agp_driver, &i8xx_gtt_driver}, 14281a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_82854_IG, "854", 1429e9b1cc81SDaniel Vetter &intel_fake_agp_driver, &i8xx_gtt_driver}, 14301a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_82855GM_IG, "855GM", 1431e9b1cc81SDaniel Vetter &intel_fake_agp_driver, &i8xx_gtt_driver}, 14321a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_82865_IG, "865", 1433e9b1cc81SDaniel Vetter &intel_fake_agp_driver, &i8xx_gtt_driver}, 14341a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_E7221_IG, "E7221 (i915)", 1435e9b1cc81SDaniel Vetter &intel_fake_agp_driver, &i915_gtt_driver }, 14361a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_82915G_IG, "915G", 1437e9b1cc81SDaniel Vetter &intel_fake_agp_driver, &i915_gtt_driver }, 14381a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_82915GM_IG, "915GM", 1439e9b1cc81SDaniel Vetter &intel_fake_agp_driver, &i915_gtt_driver }, 14401a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_82945G_IG, "945G", 1441e9b1cc81SDaniel Vetter &intel_fake_agp_driver, &i915_gtt_driver }, 14421a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_82945GM_IG, "945GM", 1443e9b1cc81SDaniel Vetter &intel_fake_agp_driver, &i915_gtt_driver }, 14441a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_82945GME_IG, "945GME", 1445e9b1cc81SDaniel Vetter &intel_fake_agp_driver, &i915_gtt_driver }, 14461a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_82946GZ_IG, "946GZ", 1447e9b1cc81SDaniel Vetter &intel_fake_agp_driver, &i965_gtt_driver }, 14481a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_82G35_IG, "G35", 1449e9b1cc81SDaniel Vetter &intel_fake_agp_driver, &i965_gtt_driver }, 14501a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_82965Q_IG, "965Q", 1451e9b1cc81SDaniel Vetter &intel_fake_agp_driver, &i965_gtt_driver }, 14521a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_82965G_IG, "965G", 1453e9b1cc81SDaniel Vetter &intel_fake_agp_driver, &i965_gtt_driver }, 14541a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_82965GM_IG, "965GM", 1455e9b1cc81SDaniel Vetter &intel_fake_agp_driver, &i965_gtt_driver }, 14561a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_82965GME_IG, "965GME/GLE", 1457e9b1cc81SDaniel Vetter &intel_fake_agp_driver, &i965_gtt_driver }, 14581a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_G33_IG, "G33", 1459e9b1cc81SDaniel Vetter &intel_fake_agp_driver, &g33_gtt_driver }, 14601a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_Q35_IG, "Q35", 1461e9b1cc81SDaniel Vetter &intel_fake_agp_driver, &g33_gtt_driver }, 14621a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_Q33_IG, "Q33", 1463e9b1cc81SDaniel Vetter &intel_fake_agp_driver, &g33_gtt_driver }, 14641a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_PINEVIEW_M_IG, "GMA3150", 1465e9b1cc81SDaniel Vetter &intel_fake_agp_driver, &pineview_gtt_driver }, 14661a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_PINEVIEW_IG, "GMA3150", 1467e9b1cc81SDaniel Vetter &intel_fake_agp_driver, &pineview_gtt_driver }, 14681a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_GM45_IG, "GM45", 1469e9b1cc81SDaniel Vetter &intel_fake_agp_driver, &g4x_gtt_driver }, 14701a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_EAGLELAKE_IG, "Eaglelake", 1471e9b1cc81SDaniel Vetter &intel_fake_agp_driver, &g4x_gtt_driver }, 14721a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_Q45_IG, "Q45/Q43", 1473e9b1cc81SDaniel Vetter &intel_fake_agp_driver, &g4x_gtt_driver }, 14741a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_G45_IG, "G45/G43", 1475e9b1cc81SDaniel Vetter &intel_fake_agp_driver, &g4x_gtt_driver }, 14761a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_B43_IG, "B43", 1477e9b1cc81SDaniel Vetter &intel_fake_agp_driver, &g4x_gtt_driver }, 1478e9e5f8e8SChris Wilson { PCI_DEVICE_ID_INTEL_B43_1_IG, "B43", 1479e9b1cc81SDaniel Vetter &intel_fake_agp_driver, &g4x_gtt_driver }, 14801a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_G41_IG, "G41", 1481e9b1cc81SDaniel Vetter &intel_fake_agp_driver, &g4x_gtt_driver }, 148202c026ceSDaniel Vetter { PCI_DEVICE_ID_INTEL_IRONLAKE_D_IG, 1483e9b1cc81SDaniel Vetter "HD Graphics", &intel_fake_agp_driver, &ironlake_gtt_driver }, 148402c026ceSDaniel Vetter { PCI_DEVICE_ID_INTEL_IRONLAKE_M_IG, 1485e9b1cc81SDaniel Vetter "HD Graphics", &intel_fake_agp_driver, &ironlake_gtt_driver }, 148602c026ceSDaniel Vetter { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_GT1_IG, 1487e9b1cc81SDaniel Vetter "Sandybridge", &intel_fake_agp_driver, &sandybridge_gtt_driver }, 148802c026ceSDaniel Vetter { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_GT2_IG, 1489e9b1cc81SDaniel Vetter "Sandybridge", &intel_fake_agp_driver, &sandybridge_gtt_driver }, 149002c026ceSDaniel Vetter { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_GT2_PLUS_IG, 1491e9b1cc81SDaniel Vetter "Sandybridge", &intel_fake_agp_driver, &sandybridge_gtt_driver }, 149202c026ceSDaniel Vetter { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_GT1_IG, 1493e9b1cc81SDaniel Vetter "Sandybridge", &intel_fake_agp_driver, &sandybridge_gtt_driver }, 149402c026ceSDaniel Vetter { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_GT2_IG, 1495e9b1cc81SDaniel Vetter "Sandybridge", &intel_fake_agp_driver, &sandybridge_gtt_driver }, 149602c026ceSDaniel Vetter { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_GT2_PLUS_IG, 1497e9b1cc81SDaniel Vetter "Sandybridge", &intel_fake_agp_driver, &sandybridge_gtt_driver }, 149802c026ceSDaniel Vetter { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_S_IG, 1499e9b1cc81SDaniel Vetter "Sandybridge", &intel_fake_agp_driver, &sandybridge_gtt_driver }, 150002c026ceSDaniel Vetter { 0, NULL, NULL } 150102c026ceSDaniel Vetter }; 150202c026ceSDaniel Vetter 150302c026ceSDaniel Vetter static int find_gmch(u16 device) 150402c026ceSDaniel Vetter { 150502c026ceSDaniel Vetter struct pci_dev *gmch_device; 150602c026ceSDaniel Vetter 150702c026ceSDaniel Vetter gmch_device = pci_get_device(PCI_VENDOR_ID_INTEL, device, NULL); 150802c026ceSDaniel Vetter if (gmch_device && PCI_FUNC(gmch_device->devfn) != 0) { 150902c026ceSDaniel Vetter gmch_device = pci_get_device(PCI_VENDOR_ID_INTEL, 151002c026ceSDaniel Vetter device, gmch_device); 151102c026ceSDaniel Vetter } 151202c026ceSDaniel Vetter 151302c026ceSDaniel Vetter if (!gmch_device) 151402c026ceSDaniel Vetter return 0; 151502c026ceSDaniel Vetter 151602c026ceSDaniel Vetter intel_private.pcidev = gmch_device; 151702c026ceSDaniel Vetter return 1; 151802c026ceSDaniel Vetter } 151902c026ceSDaniel Vetter 1520e2404e7cSDaniel Vetter int intel_gmch_probe(struct pci_dev *pdev, 152102c026ceSDaniel Vetter struct agp_bridge_data *bridge) 152202c026ceSDaniel Vetter { 152302c026ceSDaniel Vetter int i, mask; 152402c026ceSDaniel Vetter bridge->driver = NULL; 152502c026ceSDaniel Vetter 152602c026ceSDaniel Vetter for (i = 0; intel_gtt_chipsets[i].name != NULL; i++) { 152702c026ceSDaniel Vetter if (find_gmch(intel_gtt_chipsets[i].gmch_chip_id)) { 152802c026ceSDaniel Vetter bridge->driver = 152902c026ceSDaniel Vetter intel_gtt_chipsets[i].gmch_driver; 15301a997ff2SDaniel Vetter intel_private.driver = 15311a997ff2SDaniel Vetter intel_gtt_chipsets[i].gtt_driver; 153202c026ceSDaniel Vetter break; 153302c026ceSDaniel Vetter } 153402c026ceSDaniel Vetter } 153502c026ceSDaniel Vetter 153602c026ceSDaniel Vetter if (!bridge->driver) 153702c026ceSDaniel Vetter return 0; 153802c026ceSDaniel Vetter 153902c026ceSDaniel Vetter bridge->dev_private_data = &intel_private; 154002c026ceSDaniel Vetter bridge->dev = pdev; 154102c026ceSDaniel Vetter 1542d7cca2f7SDaniel Vetter intel_private.bridge_dev = pci_dev_get(pdev); 1543d7cca2f7SDaniel Vetter 154402c026ceSDaniel Vetter dev_info(&pdev->dev, "Intel %s Chipset\n", intel_gtt_chipsets[i].name); 154502c026ceSDaniel Vetter 154622533b49SDaniel Vetter mask = intel_private.driver->dma_mask_size; 154702c026ceSDaniel Vetter if (pci_set_dma_mask(intel_private.pcidev, DMA_BIT_MASK(mask))) 154802c026ceSDaniel Vetter dev_err(&intel_private.pcidev->dev, 154902c026ceSDaniel Vetter "set gfx device dma mask %d-bit failed!\n", mask); 155002c026ceSDaniel Vetter else 155102c026ceSDaniel Vetter pci_set_consistent_dma_mask(intel_private.pcidev, 155202c026ceSDaniel Vetter DMA_BIT_MASK(mask)); 155302c026ceSDaniel Vetter 15541784a5fbSDaniel Vetter if (bridge->driver == &intel_810_driver) 15551784a5fbSDaniel Vetter return 1; 15561784a5fbSDaniel Vetter 15573b15a9d7SDaniel Vetter if (intel_gtt_init() != 0) 15583b15a9d7SDaniel Vetter return 0; 15591784a5fbSDaniel Vetter 156002c026ceSDaniel Vetter return 1; 156102c026ceSDaniel Vetter } 1562e2404e7cSDaniel Vetter EXPORT_SYMBOL(intel_gmch_probe); 156302c026ceSDaniel Vetter 156419966754SDaniel Vetter struct intel_gtt *intel_gtt_get(void) 156519966754SDaniel Vetter { 156619966754SDaniel Vetter return &intel_private.base; 156719966754SDaniel Vetter } 156819966754SDaniel Vetter EXPORT_SYMBOL(intel_gtt_get); 156919966754SDaniel Vetter 1570e2404e7cSDaniel Vetter void intel_gmch_remove(struct pci_dev *pdev) 157102c026ceSDaniel Vetter { 157202c026ceSDaniel Vetter if (intel_private.pcidev) 157302c026ceSDaniel Vetter pci_dev_put(intel_private.pcidev); 1574d7cca2f7SDaniel Vetter if (intel_private.bridge_dev) 1575d7cca2f7SDaniel Vetter pci_dev_put(intel_private.bridge_dev); 157602c026ceSDaniel Vetter } 1577e2404e7cSDaniel Vetter EXPORT_SYMBOL(intel_gmch_remove); 1578e2404e7cSDaniel Vetter 1579e2404e7cSDaniel Vetter MODULE_AUTHOR("Dave Jones <davej@redhat.com>"); 1580e2404e7cSDaniel Vetter MODULE_LICENSE("GPL and additional rights"); 1581