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; 7673800422SDaniel Vetter /* Chipset specific GTT setup */ 7773800422SDaniel Vetter int (*setup)(void); 78351bb278SDaniel Vetter void (*write_entry)(dma_addr_t addr, unsigned int entry, unsigned int flags); 79351bb278SDaniel Vetter /* Flags is a more or less chipset specific opaque value. 80351bb278SDaniel Vetter * For chipsets that need to support old ums (non-gem) code, this 81351bb278SDaniel Vetter * needs to be identical to the various supported agp memory types! */ 825cbecafcSDaniel Vetter bool (*check_flags)(unsigned int flags); 831b263f24SDaniel Vetter void (*chipset_flush)(void); 841a997ff2SDaniel Vetter }; 851a997ff2SDaniel Vetter 86f51b7662SDaniel Vetter static struct _intel_private { 870ade6386SDaniel Vetter struct intel_gtt base; 881a997ff2SDaniel Vetter const struct intel_gtt_driver *driver; 89f51b7662SDaniel Vetter struct pci_dev *pcidev; /* device one */ 90d7cca2f7SDaniel Vetter struct pci_dev *bridge_dev; 91f51b7662SDaniel Vetter u8 __iomem *registers; 92f67eab66SDaniel Vetter phys_addr_t gtt_bus_addr; 9373800422SDaniel Vetter phys_addr_t gma_bus_addr; 943f08e4efSChris Wilson phys_addr_t pte_bus_addr; 95f51b7662SDaniel Vetter u32 __iomem *gtt; /* I915G */ 96f51b7662SDaniel Vetter int num_dcache_entries; 97f51b7662SDaniel Vetter union { 98f51b7662SDaniel Vetter void __iomem *i9xx_flush_page; 99f51b7662SDaniel Vetter void *i8xx_flush_page; 100f51b7662SDaniel Vetter }; 101f51b7662SDaniel Vetter struct page *i8xx_page; 102f51b7662SDaniel Vetter struct resource ifp_resource; 103f51b7662SDaniel Vetter int resource_valid; 1040e87d2b0SDaniel Vetter struct page *scratch_page; 1050e87d2b0SDaniel Vetter dma_addr_t scratch_page_dma; 106f51b7662SDaniel Vetter } intel_private; 107f51b7662SDaniel Vetter 1081a997ff2SDaniel Vetter #define INTEL_GTT_GEN intel_private.driver->gen 1091a997ff2SDaniel Vetter #define IS_G33 intel_private.driver->is_g33 1101a997ff2SDaniel Vetter #define IS_PINEVIEW intel_private.driver->is_pineview 1111a997ff2SDaniel Vetter #define IS_IRONLAKE intel_private.driver->is_ironlake 1121a997ff2SDaniel Vetter 113f51b7662SDaniel Vetter static void intel_agp_free_sglist(struct agp_memory *mem) 114f51b7662SDaniel Vetter { 115f51b7662SDaniel Vetter struct sg_table st; 116f51b7662SDaniel Vetter 117f51b7662SDaniel Vetter st.sgl = mem->sg_list; 118f51b7662SDaniel Vetter st.orig_nents = st.nents = mem->page_count; 119f51b7662SDaniel Vetter 120f51b7662SDaniel Vetter sg_free_table(&st); 121f51b7662SDaniel Vetter 122f51b7662SDaniel Vetter mem->sg_list = NULL; 123f51b7662SDaniel Vetter mem->num_sg = 0; 124f51b7662SDaniel Vetter } 125f51b7662SDaniel Vetter 126f51b7662SDaniel Vetter static int intel_agp_map_memory(struct agp_memory *mem) 127f51b7662SDaniel Vetter { 128f51b7662SDaniel Vetter struct sg_table st; 129f51b7662SDaniel Vetter struct scatterlist *sg; 130f51b7662SDaniel Vetter int i; 131f51b7662SDaniel Vetter 132fefaa70fSDaniel Vetter if (mem->sg_list) 133fefaa70fSDaniel Vetter return 0; /* already mapped (for e.g. resume */ 134fefaa70fSDaniel Vetter 135f51b7662SDaniel Vetter DBG("try mapping %lu pages\n", (unsigned long)mem->page_count); 136f51b7662SDaniel Vetter 137f51b7662SDaniel Vetter if (sg_alloc_table(&st, mem->page_count, GFP_KERNEL)) 138831cd445SChris Wilson goto err; 139f51b7662SDaniel Vetter 140f51b7662SDaniel Vetter mem->sg_list = sg = st.sgl; 141f51b7662SDaniel Vetter 142f51b7662SDaniel Vetter for (i = 0 ; i < mem->page_count; i++, sg = sg_next(sg)) 143f51b7662SDaniel Vetter sg_set_page(sg, mem->pages[i], PAGE_SIZE, 0); 144f51b7662SDaniel Vetter 145f51b7662SDaniel Vetter mem->num_sg = pci_map_sg(intel_private.pcidev, mem->sg_list, 146f51b7662SDaniel Vetter mem->page_count, PCI_DMA_BIDIRECTIONAL); 147831cd445SChris Wilson if (unlikely(!mem->num_sg)) 148831cd445SChris Wilson goto err; 149831cd445SChris Wilson 150f51b7662SDaniel Vetter return 0; 151831cd445SChris Wilson 152831cd445SChris Wilson err: 153831cd445SChris Wilson sg_free_table(&st); 154831cd445SChris Wilson return -ENOMEM; 155f51b7662SDaniel Vetter } 156f51b7662SDaniel Vetter 157f51b7662SDaniel Vetter static void intel_agp_unmap_memory(struct agp_memory *mem) 158f51b7662SDaniel Vetter { 159f51b7662SDaniel Vetter DBG("try unmapping %lu pages\n", (unsigned long)mem->page_count); 160f51b7662SDaniel Vetter 161f51b7662SDaniel Vetter pci_unmap_sg(intel_private.pcidev, mem->sg_list, 162f51b7662SDaniel Vetter mem->page_count, PCI_DMA_BIDIRECTIONAL); 163f51b7662SDaniel Vetter intel_agp_free_sglist(mem); 164f51b7662SDaniel Vetter } 165f51b7662SDaniel Vetter 166f51b7662SDaniel Vetter static int intel_i810_fetch_size(void) 167f51b7662SDaniel Vetter { 168f51b7662SDaniel Vetter u32 smram_miscc; 169f51b7662SDaniel Vetter struct aper_size_info_fixed *values; 170f51b7662SDaniel Vetter 171d7cca2f7SDaniel Vetter pci_read_config_dword(intel_private.bridge_dev, 172d7cca2f7SDaniel Vetter I810_SMRAM_MISCC, &smram_miscc); 173f51b7662SDaniel Vetter values = A_SIZE_FIX(agp_bridge->driver->aperture_sizes); 174f51b7662SDaniel Vetter 175f51b7662SDaniel Vetter if ((smram_miscc & I810_GMS) == I810_GMS_DISABLE) { 176d7cca2f7SDaniel Vetter dev_warn(&intel_private.bridge_dev->dev, "i810 is disabled\n"); 177f51b7662SDaniel Vetter return 0; 178f51b7662SDaniel Vetter } 179f51b7662SDaniel Vetter if ((smram_miscc & I810_GFX_MEM_WIN_SIZE) == I810_GFX_MEM_WIN_32M) { 180f51b7662SDaniel Vetter agp_bridge->current_size = (void *) (values + 1); 181f51b7662SDaniel Vetter agp_bridge->aperture_size_idx = 1; 182f51b7662SDaniel Vetter return values[1].size; 183f51b7662SDaniel Vetter } else { 184f51b7662SDaniel Vetter agp_bridge->current_size = (void *) (values); 185f51b7662SDaniel Vetter agp_bridge->aperture_size_idx = 0; 186f51b7662SDaniel Vetter return values[0].size; 187f51b7662SDaniel Vetter } 188f51b7662SDaniel Vetter 189f51b7662SDaniel Vetter return 0; 190f51b7662SDaniel Vetter } 191f51b7662SDaniel Vetter 192f51b7662SDaniel Vetter static int intel_i810_configure(void) 193f51b7662SDaniel Vetter { 194f51b7662SDaniel Vetter struct aper_size_info_fixed *current_size; 195f51b7662SDaniel Vetter u32 temp; 196f51b7662SDaniel Vetter int i; 197f51b7662SDaniel Vetter 198f51b7662SDaniel Vetter current_size = A_SIZE_FIX(agp_bridge->current_size); 199f51b7662SDaniel Vetter 200f51b7662SDaniel Vetter if (!intel_private.registers) { 201f51b7662SDaniel Vetter pci_read_config_dword(intel_private.pcidev, I810_MMADDR, &temp); 202f51b7662SDaniel Vetter temp &= 0xfff80000; 203f51b7662SDaniel Vetter 204f51b7662SDaniel Vetter intel_private.registers = ioremap(temp, 128 * 4096); 205f51b7662SDaniel Vetter if (!intel_private.registers) { 206f51b7662SDaniel Vetter dev_err(&intel_private.pcidev->dev, 207f51b7662SDaniel Vetter "can't remap memory\n"); 208f51b7662SDaniel Vetter return -ENOMEM; 209f51b7662SDaniel Vetter } 210f51b7662SDaniel Vetter } 211f51b7662SDaniel Vetter 212f51b7662SDaniel Vetter if ((readl(intel_private.registers+I810_DRAM_CTL) 213f51b7662SDaniel Vetter & I810_DRAM_ROW_0) == I810_DRAM_ROW_0_SDRAM) { 214f51b7662SDaniel Vetter /* This will need to be dynamically assigned */ 215f51b7662SDaniel Vetter dev_info(&intel_private.pcidev->dev, 216f51b7662SDaniel Vetter "detected 4MB dedicated video ram\n"); 217f51b7662SDaniel Vetter intel_private.num_dcache_entries = 1024; 218f51b7662SDaniel Vetter } 219f51b7662SDaniel Vetter pci_read_config_dword(intel_private.pcidev, I810_GMADDR, &temp); 220f51b7662SDaniel Vetter agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); 221f51b7662SDaniel Vetter writel(agp_bridge->gatt_bus_addr | I810_PGETBL_ENABLED, intel_private.registers+I810_PGETBL_CTL); 222f51b7662SDaniel Vetter readl(intel_private.registers+I810_PGETBL_CTL); /* PCI Posting. */ 223f51b7662SDaniel Vetter 224f51b7662SDaniel Vetter if (agp_bridge->driver->needs_scratch_page) { 225f51b7662SDaniel Vetter for (i = 0; i < current_size->num_entries; i++) { 226f51b7662SDaniel Vetter writel(agp_bridge->scratch_page, intel_private.registers+I810_PTE_BASE+(i*4)); 227f51b7662SDaniel Vetter } 228f51b7662SDaniel Vetter readl(intel_private.registers+I810_PTE_BASE+((i-1)*4)); /* PCI posting. */ 229f51b7662SDaniel Vetter } 230f51b7662SDaniel Vetter global_cache_flush(); 231f51b7662SDaniel Vetter return 0; 232f51b7662SDaniel Vetter } 233f51b7662SDaniel Vetter 234f51b7662SDaniel Vetter static void intel_i810_cleanup(void) 235f51b7662SDaniel Vetter { 236f51b7662SDaniel Vetter writel(0, intel_private.registers+I810_PGETBL_CTL); 237f51b7662SDaniel Vetter readl(intel_private.registers); /* PCI Posting. */ 238f51b7662SDaniel Vetter iounmap(intel_private.registers); 239f51b7662SDaniel Vetter } 240f51b7662SDaniel Vetter 241ffdd7510SDaniel Vetter static void intel_fake_agp_enable(struct agp_bridge_data *bridge, u32 mode) 242f51b7662SDaniel Vetter { 243f51b7662SDaniel Vetter return; 244f51b7662SDaniel Vetter } 245f51b7662SDaniel Vetter 246f51b7662SDaniel Vetter /* Exists to support ARGB cursors */ 247f51b7662SDaniel Vetter static struct page *i8xx_alloc_pages(void) 248f51b7662SDaniel Vetter { 249f51b7662SDaniel Vetter struct page *page; 250f51b7662SDaniel Vetter 251f51b7662SDaniel Vetter page = alloc_pages(GFP_KERNEL | GFP_DMA32, 2); 252f51b7662SDaniel Vetter if (page == NULL) 253f51b7662SDaniel Vetter return NULL; 254f51b7662SDaniel Vetter 255f51b7662SDaniel Vetter if (set_pages_uc(page, 4) < 0) { 256f51b7662SDaniel Vetter set_pages_wb(page, 4); 257f51b7662SDaniel Vetter __free_pages(page, 2); 258f51b7662SDaniel Vetter return NULL; 259f51b7662SDaniel Vetter } 260f51b7662SDaniel Vetter get_page(page); 261f51b7662SDaniel Vetter atomic_inc(&agp_bridge->current_memory_agp); 262f51b7662SDaniel Vetter return page; 263f51b7662SDaniel Vetter } 264f51b7662SDaniel Vetter 265f51b7662SDaniel Vetter static void i8xx_destroy_pages(struct page *page) 266f51b7662SDaniel Vetter { 267f51b7662SDaniel Vetter if (page == NULL) 268f51b7662SDaniel Vetter return; 269f51b7662SDaniel Vetter 270f51b7662SDaniel Vetter set_pages_wb(page, 4); 271f51b7662SDaniel Vetter put_page(page); 272f51b7662SDaniel Vetter __free_pages(page, 2); 273f51b7662SDaniel Vetter atomic_dec(&agp_bridge->current_memory_agp); 274f51b7662SDaniel Vetter } 275f51b7662SDaniel Vetter 276f51b7662SDaniel Vetter static int intel_i810_insert_entries(struct agp_memory *mem, off_t pg_start, 277f51b7662SDaniel Vetter int type) 278f51b7662SDaniel Vetter { 279f51b7662SDaniel Vetter int i, j, num_entries; 280f51b7662SDaniel Vetter void *temp; 281f51b7662SDaniel Vetter int ret = -EINVAL; 282f51b7662SDaniel Vetter int mask_type; 283f51b7662SDaniel Vetter 284f51b7662SDaniel Vetter if (mem->page_count == 0) 285f51b7662SDaniel Vetter goto out; 286f51b7662SDaniel Vetter 287f51b7662SDaniel Vetter temp = agp_bridge->current_size; 288f51b7662SDaniel Vetter num_entries = A_SIZE_FIX(temp)->num_entries; 289f51b7662SDaniel Vetter 290f51b7662SDaniel Vetter if ((pg_start + mem->page_count) > num_entries) 291f51b7662SDaniel Vetter goto out_err; 292f51b7662SDaniel Vetter 293f51b7662SDaniel Vetter 294f51b7662SDaniel Vetter for (j = pg_start; j < (pg_start + mem->page_count); j++) { 295f51b7662SDaniel Vetter if (!PGE_EMPTY(agp_bridge, readl(agp_bridge->gatt_table+j))) { 296f51b7662SDaniel Vetter ret = -EBUSY; 297f51b7662SDaniel Vetter goto out_err; 298f51b7662SDaniel Vetter } 299f51b7662SDaniel Vetter } 300f51b7662SDaniel Vetter 301f51b7662SDaniel Vetter if (type != mem->type) 302f51b7662SDaniel Vetter goto out_err; 303f51b7662SDaniel Vetter 304f51b7662SDaniel Vetter mask_type = agp_bridge->driver->agp_type_to_mask_type(agp_bridge, type); 305f51b7662SDaniel Vetter 306f51b7662SDaniel Vetter switch (mask_type) { 307f51b7662SDaniel Vetter case AGP_DCACHE_MEMORY: 308f51b7662SDaniel Vetter if (!mem->is_flushed) 309f51b7662SDaniel Vetter global_cache_flush(); 310f51b7662SDaniel Vetter for (i = pg_start; i < (pg_start + mem->page_count); i++) { 311f51b7662SDaniel Vetter writel((i*4096)|I810_PTE_LOCAL|I810_PTE_VALID, 312f51b7662SDaniel Vetter intel_private.registers+I810_PTE_BASE+(i*4)); 313f51b7662SDaniel Vetter } 314f51b7662SDaniel Vetter readl(intel_private.registers+I810_PTE_BASE+((i-1)*4)); 315f51b7662SDaniel Vetter break; 316f51b7662SDaniel Vetter case AGP_PHYS_MEMORY: 317f51b7662SDaniel Vetter case AGP_NORMAL_MEMORY: 318f51b7662SDaniel Vetter if (!mem->is_flushed) 319f51b7662SDaniel Vetter global_cache_flush(); 320f51b7662SDaniel Vetter for (i = 0, j = pg_start; i < mem->page_count; i++, j++) { 321f51b7662SDaniel Vetter writel(agp_bridge->driver->mask_memory(agp_bridge, 322f51b7662SDaniel Vetter page_to_phys(mem->pages[i]), mask_type), 323f51b7662SDaniel Vetter intel_private.registers+I810_PTE_BASE+(j*4)); 324f51b7662SDaniel Vetter } 325f51b7662SDaniel Vetter readl(intel_private.registers+I810_PTE_BASE+((j-1)*4)); 326f51b7662SDaniel Vetter break; 327f51b7662SDaniel Vetter default: 328f51b7662SDaniel Vetter goto out_err; 329f51b7662SDaniel Vetter } 330f51b7662SDaniel Vetter 331f51b7662SDaniel Vetter out: 332f51b7662SDaniel Vetter ret = 0; 333f51b7662SDaniel Vetter out_err: 334f51b7662SDaniel Vetter mem->is_flushed = true; 335f51b7662SDaniel Vetter return ret; 336f51b7662SDaniel Vetter } 337f51b7662SDaniel Vetter 338f51b7662SDaniel Vetter static int intel_i810_remove_entries(struct agp_memory *mem, off_t pg_start, 339f51b7662SDaniel Vetter int type) 340f51b7662SDaniel Vetter { 341f51b7662SDaniel Vetter int i; 342f51b7662SDaniel Vetter 343f51b7662SDaniel Vetter if (mem->page_count == 0) 344f51b7662SDaniel Vetter return 0; 345f51b7662SDaniel Vetter 346f51b7662SDaniel Vetter for (i = pg_start; i < (mem->page_count + pg_start); i++) { 347f51b7662SDaniel Vetter writel(agp_bridge->scratch_page, intel_private.registers+I810_PTE_BASE+(i*4)); 348f51b7662SDaniel Vetter } 349f51b7662SDaniel Vetter readl(intel_private.registers+I810_PTE_BASE+((i-1)*4)); 350f51b7662SDaniel Vetter 351f51b7662SDaniel Vetter return 0; 352f51b7662SDaniel Vetter } 353f51b7662SDaniel Vetter 354f51b7662SDaniel Vetter /* 355f51b7662SDaniel Vetter * The i810/i830 requires a physical address to program its mouse 356f51b7662SDaniel Vetter * pointer into hardware. 357f51b7662SDaniel Vetter * However the Xserver still writes to it through the agp aperture. 358f51b7662SDaniel Vetter */ 359f51b7662SDaniel Vetter static struct agp_memory *alloc_agpphysmem_i8xx(size_t pg_count, int type) 360f51b7662SDaniel Vetter { 361f51b7662SDaniel Vetter struct agp_memory *new; 362f51b7662SDaniel Vetter struct page *page; 363f51b7662SDaniel Vetter 364f51b7662SDaniel Vetter switch (pg_count) { 365f51b7662SDaniel Vetter case 1: page = agp_bridge->driver->agp_alloc_page(agp_bridge); 366f51b7662SDaniel Vetter break; 367f51b7662SDaniel Vetter case 4: 368f51b7662SDaniel Vetter /* kludge to get 4 physical pages for ARGB cursor */ 369f51b7662SDaniel Vetter page = i8xx_alloc_pages(); 370f51b7662SDaniel Vetter break; 371f51b7662SDaniel Vetter default: 372f51b7662SDaniel Vetter return NULL; 373f51b7662SDaniel Vetter } 374f51b7662SDaniel Vetter 375f51b7662SDaniel Vetter if (page == NULL) 376f51b7662SDaniel Vetter return NULL; 377f51b7662SDaniel Vetter 378f51b7662SDaniel Vetter new = agp_create_memory(pg_count); 379f51b7662SDaniel Vetter if (new == NULL) 380f51b7662SDaniel Vetter return NULL; 381f51b7662SDaniel Vetter 382f51b7662SDaniel Vetter new->pages[0] = page; 383f51b7662SDaniel Vetter if (pg_count == 4) { 384f51b7662SDaniel Vetter /* kludge to get 4 physical pages for ARGB cursor */ 385f51b7662SDaniel Vetter new->pages[1] = new->pages[0] + 1; 386f51b7662SDaniel Vetter new->pages[2] = new->pages[1] + 1; 387f51b7662SDaniel Vetter new->pages[3] = new->pages[2] + 1; 388f51b7662SDaniel Vetter } 389f51b7662SDaniel Vetter new->page_count = pg_count; 390f51b7662SDaniel Vetter new->num_scratch_pages = pg_count; 391f51b7662SDaniel Vetter new->type = AGP_PHYS_MEMORY; 392f51b7662SDaniel Vetter new->physical = page_to_phys(new->pages[0]); 393f51b7662SDaniel Vetter return new; 394f51b7662SDaniel Vetter } 395f51b7662SDaniel Vetter 396f51b7662SDaniel Vetter static struct agp_memory *intel_i810_alloc_by_type(size_t pg_count, int type) 397f51b7662SDaniel Vetter { 398f51b7662SDaniel Vetter struct agp_memory *new; 399f51b7662SDaniel Vetter 400f51b7662SDaniel Vetter if (type == AGP_DCACHE_MEMORY) { 401f51b7662SDaniel Vetter if (pg_count != intel_private.num_dcache_entries) 402f51b7662SDaniel Vetter return NULL; 403f51b7662SDaniel Vetter 404f51b7662SDaniel Vetter new = agp_create_memory(1); 405f51b7662SDaniel Vetter if (new == NULL) 406f51b7662SDaniel Vetter return NULL; 407f51b7662SDaniel Vetter 408f51b7662SDaniel Vetter new->type = AGP_DCACHE_MEMORY; 409f51b7662SDaniel Vetter new->page_count = pg_count; 410f51b7662SDaniel Vetter new->num_scratch_pages = 0; 411f51b7662SDaniel Vetter agp_free_page_array(new); 412f51b7662SDaniel Vetter return new; 413f51b7662SDaniel Vetter } 414f51b7662SDaniel Vetter if (type == AGP_PHYS_MEMORY) 415f51b7662SDaniel Vetter return alloc_agpphysmem_i8xx(pg_count, type); 416f51b7662SDaniel Vetter return NULL; 417f51b7662SDaniel Vetter } 418f51b7662SDaniel Vetter 419f51b7662SDaniel Vetter static void intel_i810_free_by_type(struct agp_memory *curr) 420f51b7662SDaniel Vetter { 421f51b7662SDaniel Vetter agp_free_key(curr->key); 422f51b7662SDaniel Vetter if (curr->type == AGP_PHYS_MEMORY) { 423f51b7662SDaniel Vetter if (curr->page_count == 4) 424f51b7662SDaniel Vetter i8xx_destroy_pages(curr->pages[0]); 425f51b7662SDaniel Vetter else { 426f51b7662SDaniel Vetter agp_bridge->driver->agp_destroy_page(curr->pages[0], 427f51b7662SDaniel Vetter AGP_PAGE_DESTROY_UNMAP); 428f51b7662SDaniel Vetter agp_bridge->driver->agp_destroy_page(curr->pages[0], 429f51b7662SDaniel Vetter AGP_PAGE_DESTROY_FREE); 430f51b7662SDaniel Vetter } 431f51b7662SDaniel Vetter agp_free_page_array(curr); 432f51b7662SDaniel Vetter } 433f51b7662SDaniel Vetter kfree(curr); 434f51b7662SDaniel Vetter } 435f51b7662SDaniel Vetter 436f51b7662SDaniel Vetter static unsigned long intel_i810_mask_memory(struct agp_bridge_data *bridge, 437f51b7662SDaniel Vetter dma_addr_t addr, int type) 438f51b7662SDaniel Vetter { 439f51b7662SDaniel Vetter /* Type checking must be done elsewhere */ 440f51b7662SDaniel Vetter return addr | bridge->driver->masks[type].mask; 441f51b7662SDaniel Vetter } 442f51b7662SDaniel Vetter 4430e87d2b0SDaniel Vetter static int intel_gtt_setup_scratch_page(void) 4440e87d2b0SDaniel Vetter { 4450e87d2b0SDaniel Vetter struct page *page; 4460e87d2b0SDaniel Vetter dma_addr_t dma_addr; 4470e87d2b0SDaniel Vetter 4480e87d2b0SDaniel Vetter page = alloc_page(GFP_KERNEL | GFP_DMA32 | __GFP_ZERO); 4490e87d2b0SDaniel Vetter if (page == NULL) 4500e87d2b0SDaniel Vetter return -ENOMEM; 4510e87d2b0SDaniel Vetter get_page(page); 4520e87d2b0SDaniel Vetter set_pages_uc(page, 1); 4530e87d2b0SDaniel Vetter 4540e87d2b0SDaniel Vetter if (USE_PCI_DMA_API && INTEL_GTT_GEN > 2) { 4550e87d2b0SDaniel Vetter dma_addr = pci_map_page(intel_private.pcidev, page, 0, 4560e87d2b0SDaniel Vetter PAGE_SIZE, PCI_DMA_BIDIRECTIONAL); 4570e87d2b0SDaniel Vetter if (pci_dma_mapping_error(intel_private.pcidev, dma_addr)) 4580e87d2b0SDaniel Vetter return -EINVAL; 4590e87d2b0SDaniel Vetter 4600e87d2b0SDaniel Vetter intel_private.scratch_page_dma = dma_addr; 4610e87d2b0SDaniel Vetter } else 4620e87d2b0SDaniel Vetter intel_private.scratch_page_dma = page_to_phys(page); 4630e87d2b0SDaniel Vetter 4640e87d2b0SDaniel Vetter intel_private.scratch_page = page; 4650e87d2b0SDaniel Vetter 4660e87d2b0SDaniel Vetter return 0; 4670e87d2b0SDaniel Vetter } 4680e87d2b0SDaniel Vetter 4699e76e7b8SChris Wilson static const struct aper_size_info_fixed const intel_fake_agp_sizes[] = { 470f51b7662SDaniel Vetter {128, 32768, 5}, 471f51b7662SDaniel Vetter /* The 64M mode still requires a 128k gatt */ 472f51b7662SDaniel Vetter {64, 16384, 5}, 473f51b7662SDaniel Vetter {256, 65536, 6}, 474f51b7662SDaniel Vetter {512, 131072, 7}, 475f51b7662SDaniel Vetter }; 476f51b7662SDaniel Vetter 477bfde067bSDaniel Vetter static unsigned int intel_gtt_stolen_entries(void) 478f51b7662SDaniel Vetter { 479f51b7662SDaniel Vetter u16 gmch_ctrl; 480f51b7662SDaniel Vetter u8 rdct; 481f51b7662SDaniel Vetter int local = 0; 482f51b7662SDaniel Vetter static const int ddt[4] = { 0, 16, 32, 64 }; 483d8d9abcdSDaniel Vetter unsigned int overhead_entries, stolen_entries; 484d8d9abcdSDaniel Vetter unsigned int stolen_size = 0; 485f51b7662SDaniel Vetter 486d7cca2f7SDaniel Vetter pci_read_config_word(intel_private.bridge_dev, 487d7cca2f7SDaniel Vetter I830_GMCH_CTRL, &gmch_ctrl); 488f51b7662SDaniel Vetter 4891a997ff2SDaniel Vetter if (INTEL_GTT_GEN > 4 || IS_PINEVIEW) 490fbe40783SDaniel Vetter overhead_entries = 0; 491fbe40783SDaniel Vetter else 492fbe40783SDaniel Vetter overhead_entries = intel_private.base.gtt_mappable_entries 493fbe40783SDaniel Vetter / 1024; 494f51b7662SDaniel Vetter 495fbe40783SDaniel Vetter overhead_entries += 1; /* BIOS popup */ 496d8d9abcdSDaniel Vetter 497d7cca2f7SDaniel Vetter if (intel_private.bridge_dev->device == PCI_DEVICE_ID_INTEL_82830_HB || 498d7cca2f7SDaniel Vetter intel_private.bridge_dev->device == PCI_DEVICE_ID_INTEL_82845G_HB) { 499f51b7662SDaniel Vetter switch (gmch_ctrl & I830_GMCH_GMS_MASK) { 500f51b7662SDaniel Vetter case I830_GMCH_GMS_STOLEN_512: 501d8d9abcdSDaniel Vetter stolen_size = KB(512); 502f51b7662SDaniel Vetter break; 503f51b7662SDaniel Vetter case I830_GMCH_GMS_STOLEN_1024: 504d8d9abcdSDaniel Vetter stolen_size = MB(1); 505f51b7662SDaniel Vetter break; 506f51b7662SDaniel Vetter case I830_GMCH_GMS_STOLEN_8192: 507d8d9abcdSDaniel Vetter stolen_size = MB(8); 508f51b7662SDaniel Vetter break; 509f51b7662SDaniel Vetter case I830_GMCH_GMS_LOCAL: 510f51b7662SDaniel Vetter rdct = readb(intel_private.registers+I830_RDRAM_CHANNEL_TYPE); 511d8d9abcdSDaniel Vetter stolen_size = (I830_RDRAM_ND(rdct) + 1) * 512f51b7662SDaniel Vetter MB(ddt[I830_RDRAM_DDT(rdct)]); 513f51b7662SDaniel Vetter local = 1; 514f51b7662SDaniel Vetter break; 515f51b7662SDaniel Vetter default: 516d8d9abcdSDaniel Vetter stolen_size = 0; 517f51b7662SDaniel Vetter break; 518f51b7662SDaniel Vetter } 5191a997ff2SDaniel Vetter } else if (INTEL_GTT_GEN == 6) { 520f51b7662SDaniel Vetter /* 521f51b7662SDaniel Vetter * SandyBridge has new memory control reg at 0x50.w 522f51b7662SDaniel Vetter */ 523f51b7662SDaniel Vetter u16 snb_gmch_ctl; 524f51b7662SDaniel Vetter pci_read_config_word(intel_private.pcidev, SNB_GMCH_CTRL, &snb_gmch_ctl); 525f51b7662SDaniel Vetter switch (snb_gmch_ctl & SNB_GMCH_GMS_STOLEN_MASK) { 526f51b7662SDaniel Vetter case SNB_GMCH_GMS_STOLEN_32M: 527d8d9abcdSDaniel Vetter stolen_size = MB(32); 528f51b7662SDaniel Vetter break; 529f51b7662SDaniel Vetter case SNB_GMCH_GMS_STOLEN_64M: 530d8d9abcdSDaniel Vetter stolen_size = MB(64); 531f51b7662SDaniel Vetter break; 532f51b7662SDaniel Vetter case SNB_GMCH_GMS_STOLEN_96M: 533d8d9abcdSDaniel Vetter stolen_size = MB(96); 534f51b7662SDaniel Vetter break; 535f51b7662SDaniel Vetter case SNB_GMCH_GMS_STOLEN_128M: 536d8d9abcdSDaniel Vetter stolen_size = MB(128); 537f51b7662SDaniel Vetter break; 538f51b7662SDaniel Vetter case SNB_GMCH_GMS_STOLEN_160M: 539d8d9abcdSDaniel Vetter stolen_size = MB(160); 540f51b7662SDaniel Vetter break; 541f51b7662SDaniel Vetter case SNB_GMCH_GMS_STOLEN_192M: 542d8d9abcdSDaniel Vetter stolen_size = MB(192); 543f51b7662SDaniel Vetter break; 544f51b7662SDaniel Vetter case SNB_GMCH_GMS_STOLEN_224M: 545d8d9abcdSDaniel Vetter stolen_size = MB(224); 546f51b7662SDaniel Vetter break; 547f51b7662SDaniel Vetter case SNB_GMCH_GMS_STOLEN_256M: 548d8d9abcdSDaniel Vetter stolen_size = MB(256); 549f51b7662SDaniel Vetter break; 550f51b7662SDaniel Vetter case SNB_GMCH_GMS_STOLEN_288M: 551d8d9abcdSDaniel Vetter stolen_size = MB(288); 552f51b7662SDaniel Vetter break; 553f51b7662SDaniel Vetter case SNB_GMCH_GMS_STOLEN_320M: 554d8d9abcdSDaniel Vetter stolen_size = MB(320); 555f51b7662SDaniel Vetter break; 556f51b7662SDaniel Vetter case SNB_GMCH_GMS_STOLEN_352M: 557d8d9abcdSDaniel Vetter stolen_size = MB(352); 558f51b7662SDaniel Vetter break; 559f51b7662SDaniel Vetter case SNB_GMCH_GMS_STOLEN_384M: 560d8d9abcdSDaniel Vetter stolen_size = MB(384); 561f51b7662SDaniel Vetter break; 562f51b7662SDaniel Vetter case SNB_GMCH_GMS_STOLEN_416M: 563d8d9abcdSDaniel Vetter stolen_size = MB(416); 564f51b7662SDaniel Vetter break; 565f51b7662SDaniel Vetter case SNB_GMCH_GMS_STOLEN_448M: 566d8d9abcdSDaniel Vetter stolen_size = MB(448); 567f51b7662SDaniel Vetter break; 568f51b7662SDaniel Vetter case SNB_GMCH_GMS_STOLEN_480M: 569d8d9abcdSDaniel Vetter stolen_size = MB(480); 570f51b7662SDaniel Vetter break; 571f51b7662SDaniel Vetter case SNB_GMCH_GMS_STOLEN_512M: 572d8d9abcdSDaniel Vetter stolen_size = MB(512); 573f51b7662SDaniel Vetter break; 574f51b7662SDaniel Vetter } 575f51b7662SDaniel Vetter } else { 576f51b7662SDaniel Vetter switch (gmch_ctrl & I855_GMCH_GMS_MASK) { 577f51b7662SDaniel Vetter case I855_GMCH_GMS_STOLEN_1M: 578d8d9abcdSDaniel Vetter stolen_size = MB(1); 579f51b7662SDaniel Vetter break; 580f51b7662SDaniel Vetter case I855_GMCH_GMS_STOLEN_4M: 581d8d9abcdSDaniel Vetter stolen_size = MB(4); 582f51b7662SDaniel Vetter break; 583f51b7662SDaniel Vetter case I855_GMCH_GMS_STOLEN_8M: 584d8d9abcdSDaniel Vetter stolen_size = MB(8); 585f51b7662SDaniel Vetter break; 586f51b7662SDaniel Vetter case I855_GMCH_GMS_STOLEN_16M: 587d8d9abcdSDaniel Vetter stolen_size = MB(16); 588f51b7662SDaniel Vetter break; 589f51b7662SDaniel Vetter case I855_GMCH_GMS_STOLEN_32M: 590d8d9abcdSDaniel Vetter stolen_size = MB(32); 591f51b7662SDaniel Vetter break; 592f51b7662SDaniel Vetter case I915_GMCH_GMS_STOLEN_48M: 593d8d9abcdSDaniel Vetter stolen_size = MB(48); 594f51b7662SDaniel Vetter break; 595f51b7662SDaniel Vetter case I915_GMCH_GMS_STOLEN_64M: 596d8d9abcdSDaniel Vetter stolen_size = MB(64); 597f51b7662SDaniel Vetter break; 598f51b7662SDaniel Vetter case G33_GMCH_GMS_STOLEN_128M: 599d8d9abcdSDaniel Vetter stolen_size = MB(128); 600f51b7662SDaniel Vetter break; 601f51b7662SDaniel Vetter case G33_GMCH_GMS_STOLEN_256M: 602d8d9abcdSDaniel Vetter stolen_size = MB(256); 603f51b7662SDaniel Vetter break; 604f51b7662SDaniel Vetter case INTEL_GMCH_GMS_STOLEN_96M: 605d8d9abcdSDaniel Vetter stolen_size = MB(96); 606f51b7662SDaniel Vetter break; 607f51b7662SDaniel Vetter case INTEL_GMCH_GMS_STOLEN_160M: 608d8d9abcdSDaniel Vetter stolen_size = MB(160); 609f51b7662SDaniel Vetter break; 610f51b7662SDaniel Vetter case INTEL_GMCH_GMS_STOLEN_224M: 611d8d9abcdSDaniel Vetter stolen_size = MB(224); 612f51b7662SDaniel Vetter break; 613f51b7662SDaniel Vetter case INTEL_GMCH_GMS_STOLEN_352M: 614d8d9abcdSDaniel Vetter stolen_size = MB(352); 615f51b7662SDaniel Vetter break; 616f51b7662SDaniel Vetter default: 617d8d9abcdSDaniel Vetter stolen_size = 0; 618f51b7662SDaniel Vetter break; 619f51b7662SDaniel Vetter } 620f51b7662SDaniel Vetter } 6211784a5fbSDaniel Vetter 622d8d9abcdSDaniel Vetter if (!local && stolen_size > intel_max_stolen) { 623d7cca2f7SDaniel Vetter dev_info(&intel_private.bridge_dev->dev, 624d1d6ca73SJesse Barnes "detected %dK stolen memory, trimming to %dK\n", 625d8d9abcdSDaniel Vetter stolen_size / KB(1), intel_max_stolen / KB(1)); 626d8d9abcdSDaniel Vetter stolen_size = intel_max_stolen; 627d8d9abcdSDaniel Vetter } else if (stolen_size > 0) { 628d7cca2f7SDaniel Vetter dev_info(&intel_private.bridge_dev->dev, "detected %dK %s memory\n", 629d8d9abcdSDaniel Vetter stolen_size / KB(1), local ? "local" : "stolen"); 630f51b7662SDaniel Vetter } else { 631d7cca2f7SDaniel Vetter dev_info(&intel_private.bridge_dev->dev, 632f51b7662SDaniel Vetter "no pre-allocated video memory detected\n"); 633d8d9abcdSDaniel Vetter stolen_size = 0; 634f51b7662SDaniel Vetter } 635f51b7662SDaniel Vetter 636d8d9abcdSDaniel Vetter stolen_entries = stolen_size/KB(4) - overhead_entries; 637d8d9abcdSDaniel Vetter 638d8d9abcdSDaniel Vetter return stolen_entries; 639f51b7662SDaniel Vetter } 640f51b7662SDaniel Vetter 641fbe40783SDaniel Vetter static unsigned int intel_gtt_total_entries(void) 642fbe40783SDaniel Vetter { 643fbe40783SDaniel Vetter int size; 644fbe40783SDaniel Vetter 645210b23c2SDaniel Vetter if (IS_G33 || INTEL_GTT_GEN == 4 || INTEL_GTT_GEN == 5) { 646fbe40783SDaniel Vetter u32 pgetbl_ctl; 647fbe40783SDaniel Vetter pgetbl_ctl = readl(intel_private.registers+I810_PGETBL_CTL); 648fbe40783SDaniel Vetter 649fbe40783SDaniel Vetter switch (pgetbl_ctl & I965_PGETBL_SIZE_MASK) { 650fbe40783SDaniel Vetter case I965_PGETBL_SIZE_128KB: 651e5e408fcSDaniel Vetter size = KB(128); 652fbe40783SDaniel Vetter break; 653fbe40783SDaniel Vetter case I965_PGETBL_SIZE_256KB: 654e5e408fcSDaniel Vetter size = KB(256); 655fbe40783SDaniel Vetter break; 656fbe40783SDaniel Vetter case I965_PGETBL_SIZE_512KB: 657e5e408fcSDaniel Vetter size = KB(512); 658fbe40783SDaniel Vetter break; 659fbe40783SDaniel Vetter case I965_PGETBL_SIZE_1MB: 660e5e408fcSDaniel Vetter size = KB(1024); 661fbe40783SDaniel Vetter break; 662fbe40783SDaniel Vetter case I965_PGETBL_SIZE_2MB: 663e5e408fcSDaniel Vetter size = KB(2048); 664fbe40783SDaniel Vetter break; 665fbe40783SDaniel Vetter case I965_PGETBL_SIZE_1_5MB: 666e5e408fcSDaniel Vetter size = KB(1024 + 512); 667fbe40783SDaniel Vetter break; 668fbe40783SDaniel Vetter default: 669fbe40783SDaniel Vetter dev_info(&intel_private.pcidev->dev, 670fbe40783SDaniel Vetter "unknown page table size, assuming 512KB\n"); 671e5e408fcSDaniel Vetter size = KB(512); 672fbe40783SDaniel Vetter } 673e5e408fcSDaniel Vetter 674e5e408fcSDaniel Vetter return size/4; 675210b23c2SDaniel Vetter } else if (INTEL_GTT_GEN == 6) { 676210b23c2SDaniel Vetter u16 snb_gmch_ctl; 677210b23c2SDaniel Vetter 678210b23c2SDaniel Vetter pci_read_config_word(intel_private.pcidev, SNB_GMCH_CTRL, &snb_gmch_ctl); 679210b23c2SDaniel Vetter switch (snb_gmch_ctl & SNB_GTT_SIZE_MASK) { 680210b23c2SDaniel Vetter default: 681210b23c2SDaniel Vetter case SNB_GTT_SIZE_0M: 682210b23c2SDaniel Vetter printk(KERN_ERR "Bad GTT size mask: 0x%04x.\n", snb_gmch_ctl); 683210b23c2SDaniel Vetter size = MB(0); 684210b23c2SDaniel Vetter break; 685210b23c2SDaniel Vetter case SNB_GTT_SIZE_1M: 686210b23c2SDaniel Vetter size = MB(1); 687210b23c2SDaniel Vetter break; 688210b23c2SDaniel Vetter case SNB_GTT_SIZE_2M: 689210b23c2SDaniel Vetter size = MB(2); 690210b23c2SDaniel Vetter break; 691210b23c2SDaniel Vetter } 692210b23c2SDaniel Vetter return size/4; 693fbe40783SDaniel Vetter } else { 694fbe40783SDaniel Vetter /* On previous hardware, the GTT size was just what was 695fbe40783SDaniel Vetter * required to map the aperture. 696fbe40783SDaniel Vetter */ 697e5e408fcSDaniel Vetter return intel_private.base.gtt_mappable_entries; 698fbe40783SDaniel Vetter } 699fbe40783SDaniel Vetter } 700fbe40783SDaniel Vetter 7011784a5fbSDaniel Vetter static unsigned int intel_gtt_mappable_entries(void) 7021784a5fbSDaniel Vetter { 7031784a5fbSDaniel Vetter unsigned int aperture_size; 7041784a5fbSDaniel Vetter 705b1c5b0f8SChris Wilson if (INTEL_GTT_GEN == 2) { 706b1c5b0f8SChris Wilson u16 gmch_ctrl; 7071784a5fbSDaniel Vetter 7081784a5fbSDaniel Vetter pci_read_config_word(intel_private.bridge_dev, 7091784a5fbSDaniel Vetter I830_GMCH_CTRL, &gmch_ctrl); 7101784a5fbSDaniel Vetter 7111784a5fbSDaniel Vetter if ((gmch_ctrl & I830_GMCH_MEM_MASK) == I830_GMCH_MEM_64M) 712b1c5b0f8SChris Wilson aperture_size = MB(64); 7131784a5fbSDaniel Vetter else 714b1c5b0f8SChris Wilson aperture_size = MB(128); 715239918f7SDaniel Vetter } else { 7161784a5fbSDaniel Vetter /* 9xx supports large sizes, just look at the length */ 7171784a5fbSDaniel Vetter aperture_size = pci_resource_len(intel_private.pcidev, 2); 7181784a5fbSDaniel Vetter } 7191784a5fbSDaniel Vetter 7201784a5fbSDaniel Vetter return aperture_size >> PAGE_SHIFT; 7211784a5fbSDaniel Vetter } 7221784a5fbSDaniel Vetter 7230e87d2b0SDaniel Vetter static void intel_gtt_teardown_scratch_page(void) 7240e87d2b0SDaniel Vetter { 7250e87d2b0SDaniel Vetter set_pages_wb(intel_private.scratch_page, 1); 7260e87d2b0SDaniel Vetter pci_unmap_page(intel_private.pcidev, intel_private.scratch_page_dma, 7270e87d2b0SDaniel Vetter PAGE_SIZE, PCI_DMA_BIDIRECTIONAL); 7280e87d2b0SDaniel Vetter put_page(intel_private.scratch_page); 7290e87d2b0SDaniel Vetter __free_page(intel_private.scratch_page); 7300e87d2b0SDaniel Vetter } 7310e87d2b0SDaniel Vetter 7320e87d2b0SDaniel Vetter static void intel_gtt_cleanup(void) 7330e87d2b0SDaniel Vetter { 7340e87d2b0SDaniel Vetter if (intel_private.i9xx_flush_page) 7350e87d2b0SDaniel Vetter iounmap(intel_private.i9xx_flush_page); 7360e87d2b0SDaniel Vetter if (intel_private.resource_valid) 7370e87d2b0SDaniel Vetter release_resource(&intel_private.ifp_resource); 7380e87d2b0SDaniel Vetter intel_private.ifp_resource.start = 0; 7390e87d2b0SDaniel Vetter intel_private.resource_valid = 0; 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 7580af9e92eSDaniel Vetter dev_info(&intel_private.bridge_dev->dev, 7590af9e92eSDaniel Vetter "detected gtt size: %dK total, %dK mappable\n", 7600af9e92eSDaniel Vetter intel_private.base.gtt_total_entries * 4, 7610af9e92eSDaniel Vetter intel_private.base.gtt_mappable_entries * 4); 7620af9e92eSDaniel Vetter 763f67eab66SDaniel Vetter gtt_map_size = intel_private.base.gtt_total_entries * 4; 764f67eab66SDaniel Vetter 765f67eab66SDaniel Vetter intel_private.gtt = ioremap(intel_private.gtt_bus_addr, 766f67eab66SDaniel Vetter gtt_map_size); 767f67eab66SDaniel Vetter if (!intel_private.gtt) { 768f67eab66SDaniel Vetter iounmap(intel_private.registers); 769f67eab66SDaniel Vetter return -ENOMEM; 770f67eab66SDaniel Vetter } 771f67eab66SDaniel Vetter 772f67eab66SDaniel Vetter global_cache_flush(); /* FIXME: ? */ 773f67eab66SDaniel Vetter 7741784a5fbSDaniel Vetter /* we have to call this as early as possible after the MMIO base address is known */ 7751784a5fbSDaniel Vetter intel_private.base.gtt_stolen_entries = intel_gtt_stolen_entries(); 7761784a5fbSDaniel Vetter if (intel_private.base.gtt_stolen_entries == 0) { 7771784a5fbSDaniel Vetter iounmap(intel_private.registers); 778f67eab66SDaniel Vetter iounmap(intel_private.gtt); 7791784a5fbSDaniel Vetter return -ENOMEM; 7801784a5fbSDaniel Vetter } 7811784a5fbSDaniel Vetter 7820e87d2b0SDaniel Vetter ret = intel_gtt_setup_scratch_page(); 7830e87d2b0SDaniel Vetter if (ret != 0) { 7840e87d2b0SDaniel Vetter intel_gtt_cleanup(); 7850e87d2b0SDaniel Vetter return ret; 7860e87d2b0SDaniel Vetter } 7870e87d2b0SDaniel Vetter 7881784a5fbSDaniel Vetter return 0; 7891784a5fbSDaniel Vetter } 7901784a5fbSDaniel Vetter 7913e921f98SDaniel Vetter static int intel_fake_agp_fetch_size(void) 7923e921f98SDaniel Vetter { 7939e76e7b8SChris Wilson int num_sizes = ARRAY_SIZE(intel_fake_agp_sizes); 7943e921f98SDaniel Vetter unsigned int aper_size; 7953e921f98SDaniel Vetter int i; 7963e921f98SDaniel Vetter 7973e921f98SDaniel Vetter aper_size = (intel_private.base.gtt_mappable_entries << PAGE_SHIFT) 7983e921f98SDaniel Vetter / MB(1); 7993e921f98SDaniel Vetter 8003e921f98SDaniel Vetter for (i = 0; i < num_sizes; i++) { 801ffdd7510SDaniel Vetter if (aper_size == intel_fake_agp_sizes[i].size) { 8029e76e7b8SChris Wilson agp_bridge->current_size = 8039e76e7b8SChris Wilson (void *) (intel_fake_agp_sizes + i); 8043e921f98SDaniel Vetter return aper_size; 8053e921f98SDaniel Vetter } 8063e921f98SDaniel Vetter } 8073e921f98SDaniel Vetter 8083e921f98SDaniel Vetter return 0; 8093e921f98SDaniel Vetter } 8103e921f98SDaniel Vetter 811f51b7662SDaniel Vetter static void intel_i830_fini_flush(void) 812f51b7662SDaniel Vetter { 813f51b7662SDaniel Vetter kunmap(intel_private.i8xx_page); 814f51b7662SDaniel Vetter intel_private.i8xx_flush_page = NULL; 815f51b7662SDaniel Vetter unmap_page_from_agp(intel_private.i8xx_page); 816f51b7662SDaniel Vetter 817f51b7662SDaniel Vetter __free_page(intel_private.i8xx_page); 818f51b7662SDaniel Vetter intel_private.i8xx_page = NULL; 819f51b7662SDaniel Vetter } 820f51b7662SDaniel Vetter 821f51b7662SDaniel Vetter static void intel_i830_setup_flush(void) 822f51b7662SDaniel Vetter { 823f51b7662SDaniel Vetter /* return if we've already set the flush mechanism up */ 824f51b7662SDaniel Vetter if (intel_private.i8xx_page) 825f51b7662SDaniel Vetter return; 826f51b7662SDaniel Vetter 827f51b7662SDaniel Vetter intel_private.i8xx_page = alloc_page(GFP_KERNEL | __GFP_ZERO | GFP_DMA32); 828f51b7662SDaniel Vetter if (!intel_private.i8xx_page) 829f51b7662SDaniel Vetter return; 830f51b7662SDaniel Vetter 831f51b7662SDaniel Vetter intel_private.i8xx_flush_page = kmap(intel_private.i8xx_page); 832f51b7662SDaniel Vetter if (!intel_private.i8xx_flush_page) 833f51b7662SDaniel Vetter intel_i830_fini_flush(); 834f51b7662SDaniel Vetter } 835f51b7662SDaniel Vetter 836f51b7662SDaniel Vetter /* The chipset_flush interface needs to get data that has already been 837f51b7662SDaniel Vetter * flushed out of the CPU all the way out to main memory, because the GPU 838f51b7662SDaniel Vetter * doesn't snoop those buffers. 839f51b7662SDaniel Vetter * 840f51b7662SDaniel Vetter * The 8xx series doesn't have the same lovely interface for flushing the 841f51b7662SDaniel Vetter * chipset write buffers that the later chips do. According to the 865 842f51b7662SDaniel Vetter * specs, it's 64 octwords, or 1KB. So, to get those previous things in 843f51b7662SDaniel Vetter * that buffer out, we just fill 1KB and clflush it out, on the assumption 844f51b7662SDaniel Vetter * that it'll push whatever was in there out. It appears to work. 845f51b7662SDaniel Vetter */ 8461b263f24SDaniel Vetter static void i830_chipset_flush(void) 847f51b7662SDaniel Vetter { 848f51b7662SDaniel Vetter unsigned int *pg = intel_private.i8xx_flush_page; 849f51b7662SDaniel Vetter 850f51b7662SDaniel Vetter memset(pg, 0, 1024); 851f51b7662SDaniel Vetter 852f51b7662SDaniel Vetter if (cpu_has_clflush) 853f51b7662SDaniel Vetter clflush_cache_range(pg, 1024); 854f51b7662SDaniel Vetter else if (wbinvd_on_all_cpus() != 0) 855f51b7662SDaniel Vetter printk(KERN_ERR "Timed out waiting for cache flush.\n"); 856f51b7662SDaniel Vetter } 857f51b7662SDaniel Vetter 858351bb278SDaniel Vetter static void i830_write_entry(dma_addr_t addr, unsigned int entry, 859351bb278SDaniel Vetter unsigned int flags) 860351bb278SDaniel Vetter { 861351bb278SDaniel Vetter u32 pte_flags = I810_PTE_VALID; 862351bb278SDaniel Vetter 863351bb278SDaniel Vetter switch (flags) { 864351bb278SDaniel Vetter case AGP_DCACHE_MEMORY: 865351bb278SDaniel Vetter pte_flags |= I810_PTE_LOCAL; 866351bb278SDaniel Vetter break; 867351bb278SDaniel Vetter case AGP_USER_CACHED_MEMORY: 868351bb278SDaniel Vetter pte_flags |= I830_PTE_SYSTEM_CACHED; 869351bb278SDaniel Vetter break; 870351bb278SDaniel Vetter } 871351bb278SDaniel Vetter 872351bb278SDaniel Vetter writel(addr | pte_flags, intel_private.gtt + entry); 873351bb278SDaniel Vetter } 874351bb278SDaniel Vetter 87573800422SDaniel Vetter static void intel_enable_gtt(void) 87673800422SDaniel Vetter { 8773f08e4efSChris Wilson u32 gma_addr; 87873800422SDaniel Vetter u16 gmch_ctrl; 87973800422SDaniel Vetter 8802d2430cfSDaniel Vetter if (INTEL_GTT_GEN == 2) 8812d2430cfSDaniel Vetter pci_read_config_dword(intel_private.pcidev, I810_GMADDR, 8822d2430cfSDaniel Vetter &gma_addr); 8832d2430cfSDaniel Vetter else 8842d2430cfSDaniel Vetter pci_read_config_dword(intel_private.pcidev, I915_GMADDR, 8852d2430cfSDaniel Vetter &gma_addr); 8862d2430cfSDaniel Vetter 88773800422SDaniel Vetter intel_private.gma_bus_addr = (gma_addr & PCI_BASE_ADDRESS_MEM_MASK); 88873800422SDaniel Vetter 88973800422SDaniel Vetter pci_read_config_word(intel_private.bridge_dev, I830_GMCH_CTRL, &gmch_ctrl); 89073800422SDaniel Vetter gmch_ctrl |= I830_GMCH_ENABLED; 89173800422SDaniel Vetter pci_write_config_word(intel_private.bridge_dev, I830_GMCH_CTRL, gmch_ctrl); 89273800422SDaniel Vetter 8933f08e4efSChris Wilson writel(intel_private.pte_bus_addr|I810_PGETBL_ENABLED, 8943f08e4efSChris Wilson intel_private.registers+I810_PGETBL_CTL); 89573800422SDaniel Vetter readl(intel_private.registers+I810_PGETBL_CTL); /* PCI Posting. */ 89673800422SDaniel Vetter } 89773800422SDaniel Vetter 89873800422SDaniel Vetter static int i830_setup(void) 89973800422SDaniel Vetter { 90073800422SDaniel Vetter u32 reg_addr; 90173800422SDaniel Vetter 90273800422SDaniel Vetter pci_read_config_dword(intel_private.pcidev, I810_MMADDR, ®_addr); 90373800422SDaniel Vetter reg_addr &= 0xfff80000; 90473800422SDaniel Vetter 90573800422SDaniel Vetter intel_private.registers = ioremap(reg_addr, KB(64)); 90673800422SDaniel Vetter if (!intel_private.registers) 90773800422SDaniel Vetter return -ENOMEM; 90873800422SDaniel Vetter 90973800422SDaniel Vetter intel_private.gtt_bus_addr = reg_addr + I810_PTE_BASE; 9103f08e4efSChris Wilson intel_private.pte_bus_addr = 9113f08e4efSChris Wilson readl(intel_private.registers+I810_PGETBL_CTL) & 0xfffff000; 91273800422SDaniel Vetter 91373800422SDaniel Vetter intel_i830_setup_flush(); 91473800422SDaniel Vetter 91573800422SDaniel Vetter return 0; 91673800422SDaniel Vetter } 91773800422SDaniel Vetter 9183b15a9d7SDaniel Vetter static int intel_fake_agp_create_gatt_table(struct agp_bridge_data *bridge) 919f51b7662SDaniel Vetter { 92073800422SDaniel Vetter agp_bridge->gatt_table_real = NULL; 921f51b7662SDaniel Vetter agp_bridge->gatt_table = NULL; 92273800422SDaniel Vetter agp_bridge->gatt_bus_addr = 0; 923f51b7662SDaniel Vetter 924f51b7662SDaniel Vetter return 0; 925f51b7662SDaniel Vetter } 926f51b7662SDaniel Vetter 927ffdd7510SDaniel Vetter static int intel_fake_agp_free_gatt_table(struct agp_bridge_data *bridge) 928f51b7662SDaniel Vetter { 929f51b7662SDaniel Vetter return 0; 930f51b7662SDaniel Vetter } 931f51b7662SDaniel Vetter 932351bb278SDaniel Vetter static int intel_fake_agp_configure(void) 933f51b7662SDaniel Vetter { 934f51b7662SDaniel Vetter int i; 935f51b7662SDaniel Vetter 93673800422SDaniel Vetter intel_enable_gtt(); 937f51b7662SDaniel Vetter 93873800422SDaniel Vetter agp_bridge->gart_bus_addr = intel_private.gma_bus_addr; 939f51b7662SDaniel Vetter 94073800422SDaniel Vetter for (i = intel_private.base.gtt_stolen_entries; 94173800422SDaniel Vetter i < intel_private.base.gtt_total_entries; i++) { 942351bb278SDaniel Vetter intel_private.driver->write_entry(intel_private.scratch_page_dma, 943351bb278SDaniel Vetter i, 0); 944f51b7662SDaniel Vetter } 945fdfb58a9SDaniel Vetter readl(intel_private.gtt+i-1); /* PCI Posting. */ 946f51b7662SDaniel Vetter 947f51b7662SDaniel Vetter global_cache_flush(); 948f51b7662SDaniel Vetter 949f51b7662SDaniel Vetter return 0; 950f51b7662SDaniel Vetter } 951f51b7662SDaniel Vetter 9525cbecafcSDaniel Vetter static bool i830_check_flags(unsigned int flags) 953f51b7662SDaniel Vetter { 9545cbecafcSDaniel Vetter switch (flags) { 9555cbecafcSDaniel Vetter case 0: 9565cbecafcSDaniel Vetter case AGP_PHYS_MEMORY: 9575cbecafcSDaniel Vetter case AGP_USER_CACHED_MEMORY: 9585cbecafcSDaniel Vetter case AGP_USER_MEMORY: 9595cbecafcSDaniel Vetter return true; 9605cbecafcSDaniel Vetter } 9615cbecafcSDaniel Vetter 9625cbecafcSDaniel Vetter return false; 9635cbecafcSDaniel Vetter } 9645cbecafcSDaniel Vetter 965fefaa70fSDaniel Vetter static void intel_gtt_insert_sg_entries(struct scatterlist *sg_list, 966fefaa70fSDaniel Vetter unsigned int sg_len, 967fefaa70fSDaniel Vetter unsigned int pg_start, 968fefaa70fSDaniel Vetter unsigned int flags) 969fefaa70fSDaniel Vetter { 970fefaa70fSDaniel Vetter struct scatterlist *sg; 971fefaa70fSDaniel Vetter unsigned int len, m; 972fefaa70fSDaniel Vetter int i, j; 973fefaa70fSDaniel Vetter 974fefaa70fSDaniel Vetter j = pg_start; 975fefaa70fSDaniel Vetter 976fefaa70fSDaniel Vetter /* sg may merge pages, but we have to separate 977fefaa70fSDaniel Vetter * per-page addr for GTT */ 978fefaa70fSDaniel Vetter for_each_sg(sg_list, sg, sg_len, i) { 979fefaa70fSDaniel Vetter len = sg_dma_len(sg) >> PAGE_SHIFT; 980fefaa70fSDaniel Vetter for (m = 0; m < len; m++) { 981fefaa70fSDaniel Vetter dma_addr_t addr = sg_dma_address(sg) + (m << PAGE_SHIFT); 982fefaa70fSDaniel Vetter intel_private.driver->write_entry(addr, 983fefaa70fSDaniel Vetter j, flags); 984fefaa70fSDaniel Vetter j++; 985fefaa70fSDaniel Vetter } 986fefaa70fSDaniel Vetter } 987fefaa70fSDaniel Vetter readl(intel_private.gtt+j-1); 988fefaa70fSDaniel Vetter } 989fefaa70fSDaniel Vetter 9905cbecafcSDaniel Vetter static int intel_fake_agp_insert_entries(struct agp_memory *mem, 9915cbecafcSDaniel Vetter off_t pg_start, int type) 9925cbecafcSDaniel Vetter { 9935cbecafcSDaniel Vetter int i, j; 994f51b7662SDaniel Vetter int ret = -EINVAL; 995f51b7662SDaniel Vetter 996f51b7662SDaniel Vetter if (mem->page_count == 0) 997f51b7662SDaniel Vetter goto out; 998f51b7662SDaniel Vetter 9990ade6386SDaniel Vetter if (pg_start < intel_private.base.gtt_stolen_entries) { 1000f51b7662SDaniel Vetter dev_printk(KERN_DEBUG, &intel_private.pcidev->dev, 10010ade6386SDaniel Vetter "pg_start == 0x%.8lx, gtt_stolen_entries == 0x%.8x\n", 10020ade6386SDaniel Vetter pg_start, intel_private.base.gtt_stolen_entries); 1003f51b7662SDaniel Vetter 1004f51b7662SDaniel Vetter dev_info(&intel_private.pcidev->dev, 1005f51b7662SDaniel Vetter "trying to insert into local/stolen memory\n"); 1006f51b7662SDaniel Vetter goto out_err; 1007f51b7662SDaniel Vetter } 1008f51b7662SDaniel Vetter 10095cbecafcSDaniel Vetter if ((pg_start + mem->page_count) > intel_private.base.gtt_total_entries) 1010f51b7662SDaniel Vetter goto out_err; 1011f51b7662SDaniel Vetter 1012f51b7662SDaniel Vetter if (type != mem->type) 1013f51b7662SDaniel Vetter goto out_err; 1014f51b7662SDaniel Vetter 10155cbecafcSDaniel Vetter if (!intel_private.driver->check_flags(type)) 1016f51b7662SDaniel Vetter goto out_err; 1017f51b7662SDaniel Vetter 1018f51b7662SDaniel Vetter if (!mem->is_flushed) 1019f51b7662SDaniel Vetter global_cache_flush(); 1020f51b7662SDaniel Vetter 1021fefaa70fSDaniel Vetter if (USE_PCI_DMA_API && INTEL_GTT_GEN > 2) { 1022fefaa70fSDaniel Vetter ret = intel_agp_map_memory(mem); 1023fefaa70fSDaniel Vetter if (ret != 0) 1024fefaa70fSDaniel Vetter return ret; 1025fefaa70fSDaniel Vetter 1026fefaa70fSDaniel Vetter intel_gtt_insert_sg_entries(mem->sg_list, mem->num_sg, 1027fefaa70fSDaniel Vetter pg_start, type); 1028fefaa70fSDaniel Vetter } else { 1029f51b7662SDaniel Vetter for (i = 0, j = pg_start; i < mem->page_count; i++, j++) { 1030fefaa70fSDaniel Vetter dma_addr_t addr = page_to_phys(mem->pages[i]); 1031fefaa70fSDaniel Vetter intel_private.driver->write_entry(addr, 10325cbecafcSDaniel Vetter j, type); 1033f51b7662SDaniel Vetter } 1034fdfb58a9SDaniel Vetter readl(intel_private.gtt+j-1); 1035fefaa70fSDaniel Vetter } 1036f51b7662SDaniel Vetter 1037f51b7662SDaniel Vetter out: 1038f51b7662SDaniel Vetter ret = 0; 1039f51b7662SDaniel Vetter out_err: 1040f51b7662SDaniel Vetter mem->is_flushed = true; 1041f51b7662SDaniel Vetter return ret; 1042f51b7662SDaniel Vetter } 1043f51b7662SDaniel Vetter 10445cbecafcSDaniel Vetter static int intel_fake_agp_remove_entries(struct agp_memory *mem, 10455cbecafcSDaniel Vetter off_t pg_start, int type) 1046f51b7662SDaniel Vetter { 1047f51b7662SDaniel Vetter int i; 1048f51b7662SDaniel Vetter 1049f51b7662SDaniel Vetter if (mem->page_count == 0) 1050f51b7662SDaniel Vetter return 0; 1051f51b7662SDaniel Vetter 10520ade6386SDaniel Vetter if (pg_start < intel_private.base.gtt_stolen_entries) { 1053f51b7662SDaniel Vetter dev_info(&intel_private.pcidev->dev, 1054f51b7662SDaniel Vetter "trying to disable local/stolen memory\n"); 1055f51b7662SDaniel Vetter return -EINVAL; 1056f51b7662SDaniel Vetter } 1057f51b7662SDaniel Vetter 1058fefaa70fSDaniel Vetter if (USE_PCI_DMA_API && INTEL_GTT_GEN > 2) 1059fefaa70fSDaniel Vetter intel_agp_unmap_memory(mem); 1060fefaa70fSDaniel Vetter 1061f51b7662SDaniel Vetter for (i = pg_start; i < (mem->page_count + pg_start); i++) { 10625cbecafcSDaniel Vetter intel_private.driver->write_entry(intel_private.scratch_page_dma, 10635cbecafcSDaniel Vetter i, 0); 1064f51b7662SDaniel Vetter } 1065fdfb58a9SDaniel Vetter readl(intel_private.gtt+i-1); 1066f51b7662SDaniel Vetter 1067f51b7662SDaniel Vetter return 0; 1068f51b7662SDaniel Vetter } 1069f51b7662SDaniel Vetter 10701b263f24SDaniel Vetter static void intel_fake_agp_chipset_flush(struct agp_bridge_data *bridge) 10711b263f24SDaniel Vetter { 10721b263f24SDaniel Vetter intel_private.driver->chipset_flush(); 10731b263f24SDaniel Vetter } 10741b263f24SDaniel Vetter 1075ffdd7510SDaniel Vetter static struct agp_memory *intel_fake_agp_alloc_by_type(size_t pg_count, 1076ffdd7510SDaniel Vetter int type) 1077f51b7662SDaniel Vetter { 1078f51b7662SDaniel Vetter if (type == AGP_PHYS_MEMORY) 1079f51b7662SDaniel Vetter return alloc_agpphysmem_i8xx(pg_count, type); 1080f51b7662SDaniel Vetter /* always return NULL for other allocation types for now */ 1081f51b7662SDaniel Vetter return NULL; 1082f51b7662SDaniel Vetter } 1083f51b7662SDaniel Vetter 1084f51b7662SDaniel Vetter static int intel_alloc_chipset_flush_resource(void) 1085f51b7662SDaniel Vetter { 1086f51b7662SDaniel Vetter int ret; 1087d7cca2f7SDaniel Vetter ret = pci_bus_alloc_resource(intel_private.bridge_dev->bus, &intel_private.ifp_resource, PAGE_SIZE, 1088f51b7662SDaniel Vetter PAGE_SIZE, PCIBIOS_MIN_MEM, 0, 1089d7cca2f7SDaniel Vetter pcibios_align_resource, intel_private.bridge_dev); 1090f51b7662SDaniel Vetter 1091f51b7662SDaniel Vetter return ret; 1092f51b7662SDaniel Vetter } 1093f51b7662SDaniel Vetter 1094f51b7662SDaniel Vetter static void intel_i915_setup_chipset_flush(void) 1095f51b7662SDaniel Vetter { 1096f51b7662SDaniel Vetter int ret; 1097f51b7662SDaniel Vetter u32 temp; 1098f51b7662SDaniel Vetter 1099d7cca2f7SDaniel Vetter pci_read_config_dword(intel_private.bridge_dev, I915_IFPADDR, &temp); 1100f51b7662SDaniel Vetter if (!(temp & 0x1)) { 1101f51b7662SDaniel Vetter intel_alloc_chipset_flush_resource(); 1102f51b7662SDaniel Vetter intel_private.resource_valid = 1; 1103d7cca2f7SDaniel Vetter pci_write_config_dword(intel_private.bridge_dev, I915_IFPADDR, (intel_private.ifp_resource.start & 0xffffffff) | 0x1); 1104f51b7662SDaniel Vetter } else { 1105f51b7662SDaniel Vetter temp &= ~1; 1106f51b7662SDaniel Vetter 1107f51b7662SDaniel Vetter intel_private.resource_valid = 1; 1108f51b7662SDaniel Vetter intel_private.ifp_resource.start = temp; 1109f51b7662SDaniel Vetter intel_private.ifp_resource.end = temp + PAGE_SIZE; 1110f51b7662SDaniel Vetter ret = request_resource(&iomem_resource, &intel_private.ifp_resource); 1111f51b7662SDaniel Vetter /* some BIOSes reserve this area in a pnp some don't */ 1112f51b7662SDaniel Vetter if (ret) 1113f51b7662SDaniel Vetter intel_private.resource_valid = 0; 1114f51b7662SDaniel Vetter } 1115f51b7662SDaniel Vetter } 1116f51b7662SDaniel Vetter 1117f51b7662SDaniel Vetter static void intel_i965_g33_setup_chipset_flush(void) 1118f51b7662SDaniel Vetter { 1119f51b7662SDaniel Vetter u32 temp_hi, temp_lo; 1120f51b7662SDaniel Vetter int ret; 1121f51b7662SDaniel Vetter 1122d7cca2f7SDaniel Vetter pci_read_config_dword(intel_private.bridge_dev, I965_IFPADDR + 4, &temp_hi); 1123d7cca2f7SDaniel Vetter pci_read_config_dword(intel_private.bridge_dev, I965_IFPADDR, &temp_lo); 1124f51b7662SDaniel Vetter 1125f51b7662SDaniel Vetter if (!(temp_lo & 0x1)) { 1126f51b7662SDaniel Vetter 1127f51b7662SDaniel Vetter intel_alloc_chipset_flush_resource(); 1128f51b7662SDaniel Vetter 1129f51b7662SDaniel Vetter intel_private.resource_valid = 1; 1130d7cca2f7SDaniel Vetter pci_write_config_dword(intel_private.bridge_dev, I965_IFPADDR + 4, 1131f51b7662SDaniel Vetter upper_32_bits(intel_private.ifp_resource.start)); 1132d7cca2f7SDaniel Vetter pci_write_config_dword(intel_private.bridge_dev, I965_IFPADDR, (intel_private.ifp_resource.start & 0xffffffff) | 0x1); 1133f51b7662SDaniel Vetter } else { 1134f51b7662SDaniel Vetter u64 l64; 1135f51b7662SDaniel Vetter 1136f51b7662SDaniel Vetter temp_lo &= ~0x1; 1137f51b7662SDaniel Vetter l64 = ((u64)temp_hi << 32) | temp_lo; 1138f51b7662SDaniel Vetter 1139f51b7662SDaniel Vetter intel_private.resource_valid = 1; 1140f51b7662SDaniel Vetter intel_private.ifp_resource.start = l64; 1141f51b7662SDaniel Vetter intel_private.ifp_resource.end = l64 + PAGE_SIZE; 1142f51b7662SDaniel Vetter ret = request_resource(&iomem_resource, &intel_private.ifp_resource); 1143f51b7662SDaniel Vetter /* some BIOSes reserve this area in a pnp some don't */ 1144f51b7662SDaniel Vetter if (ret) 1145f51b7662SDaniel Vetter intel_private.resource_valid = 0; 1146f51b7662SDaniel Vetter } 1147f51b7662SDaniel Vetter } 1148f51b7662SDaniel Vetter 1149f51b7662SDaniel Vetter static void intel_i9xx_setup_flush(void) 1150f51b7662SDaniel Vetter { 1151f51b7662SDaniel Vetter /* return if already configured */ 1152f51b7662SDaniel Vetter if (intel_private.ifp_resource.start) 1153f51b7662SDaniel Vetter return; 1154f51b7662SDaniel Vetter 11551a997ff2SDaniel Vetter if (INTEL_GTT_GEN == 6) 1156f51b7662SDaniel Vetter return; 1157f51b7662SDaniel Vetter 1158f51b7662SDaniel Vetter /* setup a resource for this object */ 1159f51b7662SDaniel Vetter intel_private.ifp_resource.name = "Intel Flush Page"; 1160f51b7662SDaniel Vetter intel_private.ifp_resource.flags = IORESOURCE_MEM; 1161f51b7662SDaniel Vetter 1162f51b7662SDaniel Vetter /* Setup chipset flush for 915 */ 11631a997ff2SDaniel Vetter if (IS_G33 || INTEL_GTT_GEN >= 4) { 1164f51b7662SDaniel Vetter intel_i965_g33_setup_chipset_flush(); 1165f51b7662SDaniel Vetter } else { 1166f51b7662SDaniel Vetter intel_i915_setup_chipset_flush(); 1167f51b7662SDaniel Vetter } 1168f51b7662SDaniel Vetter 1169df51e7aaSChris Wilson if (intel_private.ifp_resource.start) 1170f51b7662SDaniel Vetter intel_private.i9xx_flush_page = ioremap_nocache(intel_private.ifp_resource.start, PAGE_SIZE); 1171f51b7662SDaniel Vetter if (!intel_private.i9xx_flush_page) 1172df51e7aaSChris Wilson dev_err(&intel_private.pcidev->dev, 1173df51e7aaSChris Wilson "can't ioremap flush page - no chipset flushing\n"); 1174f51b7662SDaniel Vetter } 1175f51b7662SDaniel Vetter 11761b263f24SDaniel Vetter static void i9xx_chipset_flush(void) 1177f51b7662SDaniel Vetter { 1178f51b7662SDaniel Vetter if (intel_private.i9xx_flush_page) 1179f51b7662SDaniel Vetter writel(1, intel_private.i9xx_flush_page); 1180f51b7662SDaniel Vetter } 1181f51b7662SDaniel Vetter 1182a6963596SDaniel Vetter static void i965_write_entry(dma_addr_t addr, unsigned int entry, 1183a6963596SDaniel Vetter unsigned int flags) 1184a6963596SDaniel Vetter { 1185a6963596SDaniel Vetter /* Shift high bits down */ 1186a6963596SDaniel Vetter addr |= (addr >> 28) & 0xf0; 1187a6963596SDaniel Vetter writel(addr | I810_PTE_VALID, intel_private.gtt + entry); 1188a6963596SDaniel Vetter } 1189a6963596SDaniel Vetter 119090cb149eSDaniel Vetter static bool gen6_check_flags(unsigned int flags) 119190cb149eSDaniel Vetter { 119290cb149eSDaniel Vetter return true; 119390cb149eSDaniel Vetter } 119490cb149eSDaniel Vetter 119597ef1bddSDaniel Vetter static void gen6_write_entry(dma_addr_t addr, unsigned int entry, 119697ef1bddSDaniel Vetter unsigned int flags) 119797ef1bddSDaniel Vetter { 119897ef1bddSDaniel Vetter unsigned int type_mask = flags & ~AGP_USER_CACHED_MEMORY_GFDT; 119997ef1bddSDaniel Vetter unsigned int gfdt = flags & AGP_USER_CACHED_MEMORY_GFDT; 120097ef1bddSDaniel Vetter u32 pte_flags; 120197ef1bddSDaniel Vetter 120297ef1bddSDaniel Vetter if (type_mask == AGP_USER_UNCACHED_MEMORY) 120397ef1bddSDaniel Vetter pte_flags = GEN6_PTE_UNCACHED; 120497ef1bddSDaniel Vetter else if (type_mask == AGP_USER_CACHED_MEMORY_LLC_MLC) { 120597ef1bddSDaniel Vetter pte_flags = GEN6_PTE_LLC; 120697ef1bddSDaniel Vetter if (gfdt) 120797ef1bddSDaniel Vetter pte_flags |= GEN6_PTE_GFDT; 120897ef1bddSDaniel Vetter } else { /* set 'normal'/'cached' to LLC by default */ 120997ef1bddSDaniel Vetter pte_flags = GEN6_PTE_LLC_MLC; 121097ef1bddSDaniel Vetter if (gfdt) 121197ef1bddSDaniel Vetter pte_flags |= GEN6_PTE_GFDT; 121297ef1bddSDaniel Vetter } 121397ef1bddSDaniel Vetter 121497ef1bddSDaniel Vetter /* gen6 has bit11-4 for physical addr bit39-32 */ 121597ef1bddSDaniel Vetter addr |= (addr >> 28) & 0xff0; 121697ef1bddSDaniel Vetter writel(addr | pte_flags, intel_private.gtt + entry); 121797ef1bddSDaniel Vetter } 121897ef1bddSDaniel Vetter 12192d2430cfSDaniel Vetter static int i9xx_setup(void) 12202d2430cfSDaniel Vetter { 12212d2430cfSDaniel Vetter u32 reg_addr; 12222d2430cfSDaniel Vetter 12232d2430cfSDaniel Vetter pci_read_config_dword(intel_private.pcidev, I915_MMADDR, ®_addr); 12242d2430cfSDaniel Vetter 12252d2430cfSDaniel Vetter reg_addr &= 0xfff80000; 12262d2430cfSDaniel Vetter 12272d2430cfSDaniel Vetter intel_private.registers = ioremap(reg_addr, 128 * 4096); 12282d2430cfSDaniel Vetter if (!intel_private.registers) 12292d2430cfSDaniel Vetter return -ENOMEM; 12302d2430cfSDaniel Vetter 12312d2430cfSDaniel Vetter if (INTEL_GTT_GEN == 3) { 12322d2430cfSDaniel Vetter u32 gtt_addr; 12333f08e4efSChris Wilson 12342d2430cfSDaniel Vetter pci_read_config_dword(intel_private.pcidev, 12352d2430cfSDaniel Vetter I915_PTEADDR, >t_addr); 12362d2430cfSDaniel Vetter intel_private.gtt_bus_addr = gtt_addr; 12372d2430cfSDaniel Vetter } else { 12382d2430cfSDaniel Vetter u32 gtt_offset; 12392d2430cfSDaniel Vetter 12402d2430cfSDaniel Vetter switch (INTEL_GTT_GEN) { 12412d2430cfSDaniel Vetter case 5: 12422d2430cfSDaniel Vetter case 6: 12432d2430cfSDaniel Vetter gtt_offset = MB(2); 12442d2430cfSDaniel Vetter break; 12452d2430cfSDaniel Vetter case 4: 12462d2430cfSDaniel Vetter default: 12472d2430cfSDaniel Vetter gtt_offset = KB(512); 12482d2430cfSDaniel Vetter break; 12492d2430cfSDaniel Vetter } 12502d2430cfSDaniel Vetter intel_private.gtt_bus_addr = reg_addr + gtt_offset; 12512d2430cfSDaniel Vetter } 12522d2430cfSDaniel Vetter 12533f08e4efSChris Wilson intel_private.pte_bus_addr = 12543f08e4efSChris Wilson readl(intel_private.registers+I810_PGETBL_CTL) & 0xfffff000; 12553f08e4efSChris Wilson 12562d2430cfSDaniel Vetter intel_i9xx_setup_flush(); 12572d2430cfSDaniel Vetter 12582d2430cfSDaniel Vetter return 0; 12592d2430cfSDaniel Vetter } 12602d2430cfSDaniel Vetter 1261f51b7662SDaniel Vetter static const struct agp_bridge_driver intel_810_driver = { 1262f51b7662SDaniel Vetter .owner = THIS_MODULE, 1263f51b7662SDaniel Vetter .aperture_sizes = intel_i810_sizes, 1264f51b7662SDaniel Vetter .size_type = FIXED_APER_SIZE, 1265f51b7662SDaniel Vetter .num_aperture_sizes = 2, 1266f51b7662SDaniel Vetter .needs_scratch_page = true, 1267f51b7662SDaniel Vetter .configure = intel_i810_configure, 1268f51b7662SDaniel Vetter .fetch_size = intel_i810_fetch_size, 1269f51b7662SDaniel Vetter .cleanup = intel_i810_cleanup, 1270f51b7662SDaniel Vetter .mask_memory = intel_i810_mask_memory, 1271f51b7662SDaniel Vetter .masks = intel_i810_masks, 1272ffdd7510SDaniel Vetter .agp_enable = intel_fake_agp_enable, 1273f51b7662SDaniel Vetter .cache_flush = global_cache_flush, 1274f51b7662SDaniel Vetter .create_gatt_table = agp_generic_create_gatt_table, 1275f51b7662SDaniel Vetter .free_gatt_table = agp_generic_free_gatt_table, 1276f51b7662SDaniel Vetter .insert_memory = intel_i810_insert_entries, 1277f51b7662SDaniel Vetter .remove_memory = intel_i810_remove_entries, 1278f51b7662SDaniel Vetter .alloc_by_type = intel_i810_alloc_by_type, 1279f51b7662SDaniel Vetter .free_by_type = intel_i810_free_by_type, 1280f51b7662SDaniel Vetter .agp_alloc_page = agp_generic_alloc_page, 1281f51b7662SDaniel Vetter .agp_alloc_pages = agp_generic_alloc_pages, 1282f51b7662SDaniel Vetter .agp_destroy_page = agp_generic_destroy_page, 1283f51b7662SDaniel Vetter .agp_destroy_pages = agp_generic_destroy_pages, 1284f51b7662SDaniel Vetter .agp_type_to_mask_type = agp_generic_type_to_mask_type, 1285f51b7662SDaniel Vetter }; 1286f51b7662SDaniel Vetter 1287e9b1cc81SDaniel Vetter static const struct agp_bridge_driver intel_fake_agp_driver = { 1288f51b7662SDaniel Vetter .owner = THIS_MODULE, 1289f51b7662SDaniel Vetter .size_type = FIXED_APER_SIZE, 12909e76e7b8SChris Wilson .aperture_sizes = intel_fake_agp_sizes, 12919e76e7b8SChris Wilson .num_aperture_sizes = ARRAY_SIZE(intel_fake_agp_sizes), 1292a6963596SDaniel Vetter .configure = intel_fake_agp_configure, 12933e921f98SDaniel Vetter .fetch_size = intel_fake_agp_fetch_size, 1294fdfb58a9SDaniel Vetter .cleanup = intel_gtt_cleanup, 1295ffdd7510SDaniel Vetter .agp_enable = intel_fake_agp_enable, 1296f51b7662SDaniel Vetter .cache_flush = global_cache_flush, 12973b15a9d7SDaniel Vetter .create_gatt_table = intel_fake_agp_create_gatt_table, 1298ffdd7510SDaniel Vetter .free_gatt_table = intel_fake_agp_free_gatt_table, 1299450f2b3dSDaniel Vetter .insert_memory = intel_fake_agp_insert_entries, 1300450f2b3dSDaniel Vetter .remove_memory = intel_fake_agp_remove_entries, 1301ffdd7510SDaniel Vetter .alloc_by_type = intel_fake_agp_alloc_by_type, 1302f51b7662SDaniel Vetter .free_by_type = intel_i810_free_by_type, 1303f51b7662SDaniel Vetter .agp_alloc_page = agp_generic_alloc_page, 1304f51b7662SDaniel Vetter .agp_alloc_pages = agp_generic_alloc_pages, 1305f51b7662SDaniel Vetter .agp_destroy_page = agp_generic_destroy_page, 1306f51b7662SDaniel Vetter .agp_destroy_pages = agp_generic_destroy_pages, 13071b263f24SDaniel Vetter .chipset_flush = intel_fake_agp_chipset_flush, 1308f51b7662SDaniel Vetter }; 130902c026ceSDaniel Vetter 1310bdd30729SDaniel Vetter static const struct intel_gtt_driver i81x_gtt_driver = { 1311bdd30729SDaniel Vetter .gen = 1, 1312bdd30729SDaniel Vetter }; 13131a997ff2SDaniel Vetter static const struct intel_gtt_driver i8xx_gtt_driver = { 13141a997ff2SDaniel Vetter .gen = 2, 131573800422SDaniel Vetter .setup = i830_setup, 1316351bb278SDaniel Vetter .write_entry = i830_write_entry, 13175cbecafcSDaniel Vetter .check_flags = i830_check_flags, 13181b263f24SDaniel Vetter .chipset_flush = i830_chipset_flush, 13191a997ff2SDaniel Vetter }; 13201a997ff2SDaniel Vetter static const struct intel_gtt_driver i915_gtt_driver = { 13211a997ff2SDaniel Vetter .gen = 3, 13222d2430cfSDaniel Vetter .setup = i9xx_setup, 1323351bb278SDaniel Vetter /* i945 is the last gpu to need phys mem (for overlay and cursors). */ 1324351bb278SDaniel Vetter .write_entry = i830_write_entry, 1325fefaa70fSDaniel Vetter .check_flags = i830_check_flags, 13261b263f24SDaniel Vetter .chipset_flush = i9xx_chipset_flush, 13271a997ff2SDaniel Vetter }; 13281a997ff2SDaniel Vetter static const struct intel_gtt_driver g33_gtt_driver = { 13291a997ff2SDaniel Vetter .gen = 3, 13301a997ff2SDaniel Vetter .is_g33 = 1, 13312d2430cfSDaniel Vetter .setup = i9xx_setup, 1332a6963596SDaniel Vetter .write_entry = i965_write_entry, 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, 1340a6963596SDaniel Vetter .write_entry = i965_write_entry, 1341450f2b3dSDaniel Vetter .check_flags = i830_check_flags, 13421b263f24SDaniel Vetter .chipset_flush = i9xx_chipset_flush, 13431a997ff2SDaniel Vetter }; 13441a997ff2SDaniel Vetter static const struct intel_gtt_driver i965_gtt_driver = { 13451a997ff2SDaniel Vetter .gen = 4, 13462d2430cfSDaniel Vetter .setup = i9xx_setup, 1347a6963596SDaniel Vetter .write_entry = i965_write_entry, 1348450f2b3dSDaniel Vetter .check_flags = i830_check_flags, 13491b263f24SDaniel Vetter .chipset_flush = i9xx_chipset_flush, 13501a997ff2SDaniel Vetter }; 13511a997ff2SDaniel Vetter static const struct intel_gtt_driver g4x_gtt_driver = { 13521a997ff2SDaniel Vetter .gen = 5, 13532d2430cfSDaniel Vetter .setup = i9xx_setup, 1354a6963596SDaniel Vetter .write_entry = i965_write_entry, 1355450f2b3dSDaniel Vetter .check_flags = i830_check_flags, 13561b263f24SDaniel Vetter .chipset_flush = i9xx_chipset_flush, 13571a997ff2SDaniel Vetter }; 13581a997ff2SDaniel Vetter static const struct intel_gtt_driver ironlake_gtt_driver = { 13591a997ff2SDaniel Vetter .gen = 5, 13601a997ff2SDaniel Vetter .is_ironlake = 1, 13612d2430cfSDaniel Vetter .setup = i9xx_setup, 1362a6963596SDaniel Vetter .write_entry = i965_write_entry, 1363450f2b3dSDaniel Vetter .check_flags = i830_check_flags, 13641b263f24SDaniel Vetter .chipset_flush = i9xx_chipset_flush, 13651a997ff2SDaniel Vetter }; 13661a997ff2SDaniel Vetter static const struct intel_gtt_driver sandybridge_gtt_driver = { 13671a997ff2SDaniel Vetter .gen = 6, 13682d2430cfSDaniel Vetter .setup = i9xx_setup, 136997ef1bddSDaniel Vetter .write_entry = gen6_write_entry, 137090cb149eSDaniel Vetter .check_flags = gen6_check_flags, 13711b263f24SDaniel Vetter .chipset_flush = i9xx_chipset_flush, 13721a997ff2SDaniel Vetter }; 13731a997ff2SDaniel Vetter 137402c026ceSDaniel Vetter /* Table to describe Intel GMCH and AGP/PCIE GART drivers. At least one of 137502c026ceSDaniel Vetter * driver and gmch_driver must be non-null, and find_gmch will determine 137602c026ceSDaniel Vetter * which one should be used if a gmch_chip_id is present. 137702c026ceSDaniel Vetter */ 137802c026ceSDaniel Vetter static const struct intel_gtt_driver_description { 137902c026ceSDaniel Vetter unsigned int gmch_chip_id; 138002c026ceSDaniel Vetter char *name; 138102c026ceSDaniel Vetter const struct agp_bridge_driver *gmch_driver; 13821a997ff2SDaniel Vetter const struct intel_gtt_driver *gtt_driver; 138302c026ceSDaniel Vetter } intel_gtt_chipsets[] = { 1384bdd30729SDaniel Vetter { PCI_DEVICE_ID_INTEL_82810_IG1, "i810", &intel_810_driver, 1385bdd30729SDaniel Vetter &i81x_gtt_driver}, 1386bdd30729SDaniel Vetter { PCI_DEVICE_ID_INTEL_82810_IG3, "i810", &intel_810_driver, 1387bdd30729SDaniel Vetter &i81x_gtt_driver}, 1388bdd30729SDaniel Vetter { PCI_DEVICE_ID_INTEL_82810E_IG, "i810", &intel_810_driver, 1389bdd30729SDaniel Vetter &i81x_gtt_driver}, 1390bdd30729SDaniel Vetter { PCI_DEVICE_ID_INTEL_82815_CGC, "i815", &intel_810_driver, 1391bdd30729SDaniel Vetter &i81x_gtt_driver}, 13921a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_82830_CGC, "830M", 1393e9b1cc81SDaniel Vetter &intel_fake_agp_driver, &i8xx_gtt_driver}, 13941a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_82845G_IG, "830M", 1395e9b1cc81SDaniel Vetter &intel_fake_agp_driver, &i8xx_gtt_driver}, 13961a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_82854_IG, "854", 1397e9b1cc81SDaniel Vetter &intel_fake_agp_driver, &i8xx_gtt_driver}, 13981a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_82855GM_IG, "855GM", 1399e9b1cc81SDaniel Vetter &intel_fake_agp_driver, &i8xx_gtt_driver}, 14001a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_82865_IG, "865", 1401e9b1cc81SDaniel Vetter &intel_fake_agp_driver, &i8xx_gtt_driver}, 14021a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_E7221_IG, "E7221 (i915)", 1403e9b1cc81SDaniel Vetter &intel_fake_agp_driver, &i915_gtt_driver }, 14041a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_82915G_IG, "915G", 1405e9b1cc81SDaniel Vetter &intel_fake_agp_driver, &i915_gtt_driver }, 14061a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_82915GM_IG, "915GM", 1407e9b1cc81SDaniel Vetter &intel_fake_agp_driver, &i915_gtt_driver }, 14081a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_82945G_IG, "945G", 1409e9b1cc81SDaniel Vetter &intel_fake_agp_driver, &i915_gtt_driver }, 14101a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_82945GM_IG, "945GM", 1411e9b1cc81SDaniel Vetter &intel_fake_agp_driver, &i915_gtt_driver }, 14121a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_82945GME_IG, "945GME", 1413e9b1cc81SDaniel Vetter &intel_fake_agp_driver, &i915_gtt_driver }, 14141a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_82946GZ_IG, "946GZ", 1415e9b1cc81SDaniel Vetter &intel_fake_agp_driver, &i965_gtt_driver }, 14161a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_82G35_IG, "G35", 1417e9b1cc81SDaniel Vetter &intel_fake_agp_driver, &i965_gtt_driver }, 14181a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_82965Q_IG, "965Q", 1419e9b1cc81SDaniel Vetter &intel_fake_agp_driver, &i965_gtt_driver }, 14201a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_82965G_IG, "965G", 1421e9b1cc81SDaniel Vetter &intel_fake_agp_driver, &i965_gtt_driver }, 14221a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_82965GM_IG, "965GM", 1423e9b1cc81SDaniel Vetter &intel_fake_agp_driver, &i965_gtt_driver }, 14241a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_82965GME_IG, "965GME/GLE", 1425e9b1cc81SDaniel Vetter &intel_fake_agp_driver, &i965_gtt_driver }, 14261a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_G33_IG, "G33", 1427e9b1cc81SDaniel Vetter &intel_fake_agp_driver, &g33_gtt_driver }, 14281a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_Q35_IG, "Q35", 1429e9b1cc81SDaniel Vetter &intel_fake_agp_driver, &g33_gtt_driver }, 14301a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_Q33_IG, "Q33", 1431e9b1cc81SDaniel Vetter &intel_fake_agp_driver, &g33_gtt_driver }, 14321a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_PINEVIEW_M_IG, "GMA3150", 1433e9b1cc81SDaniel Vetter &intel_fake_agp_driver, &pineview_gtt_driver }, 14341a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_PINEVIEW_IG, "GMA3150", 1435e9b1cc81SDaniel Vetter &intel_fake_agp_driver, &pineview_gtt_driver }, 14361a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_GM45_IG, "GM45", 1437e9b1cc81SDaniel Vetter &intel_fake_agp_driver, &g4x_gtt_driver }, 14381a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_EAGLELAKE_IG, "Eaglelake", 1439e9b1cc81SDaniel Vetter &intel_fake_agp_driver, &g4x_gtt_driver }, 14401a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_Q45_IG, "Q45/Q43", 1441e9b1cc81SDaniel Vetter &intel_fake_agp_driver, &g4x_gtt_driver }, 14421a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_G45_IG, "G45/G43", 1443e9b1cc81SDaniel Vetter &intel_fake_agp_driver, &g4x_gtt_driver }, 14441a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_B43_IG, "B43", 1445e9b1cc81SDaniel Vetter &intel_fake_agp_driver, &g4x_gtt_driver }, 1446e9e5f8e8SChris Wilson { PCI_DEVICE_ID_INTEL_B43_1_IG, "B43", 1447e9b1cc81SDaniel Vetter &intel_fake_agp_driver, &g4x_gtt_driver }, 14481a997ff2SDaniel Vetter { PCI_DEVICE_ID_INTEL_G41_IG, "G41", 1449e9b1cc81SDaniel Vetter &intel_fake_agp_driver, &g4x_gtt_driver }, 145002c026ceSDaniel Vetter { PCI_DEVICE_ID_INTEL_IRONLAKE_D_IG, 1451e9b1cc81SDaniel Vetter "HD Graphics", &intel_fake_agp_driver, &ironlake_gtt_driver }, 145202c026ceSDaniel Vetter { PCI_DEVICE_ID_INTEL_IRONLAKE_M_IG, 1453e9b1cc81SDaniel Vetter "HD Graphics", &intel_fake_agp_driver, &ironlake_gtt_driver }, 145402c026ceSDaniel Vetter { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_GT1_IG, 1455e9b1cc81SDaniel Vetter "Sandybridge", &intel_fake_agp_driver, &sandybridge_gtt_driver }, 145602c026ceSDaniel Vetter { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_GT2_IG, 1457e9b1cc81SDaniel Vetter "Sandybridge", &intel_fake_agp_driver, &sandybridge_gtt_driver }, 145802c026ceSDaniel Vetter { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_GT2_PLUS_IG, 1459e9b1cc81SDaniel Vetter "Sandybridge", &intel_fake_agp_driver, &sandybridge_gtt_driver }, 146002c026ceSDaniel Vetter { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_GT1_IG, 1461e9b1cc81SDaniel Vetter "Sandybridge", &intel_fake_agp_driver, &sandybridge_gtt_driver }, 146202c026ceSDaniel Vetter { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_GT2_IG, 1463e9b1cc81SDaniel Vetter "Sandybridge", &intel_fake_agp_driver, &sandybridge_gtt_driver }, 146402c026ceSDaniel Vetter { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_GT2_PLUS_IG, 1465e9b1cc81SDaniel Vetter "Sandybridge", &intel_fake_agp_driver, &sandybridge_gtt_driver }, 146602c026ceSDaniel Vetter { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_S_IG, 1467e9b1cc81SDaniel Vetter "Sandybridge", &intel_fake_agp_driver, &sandybridge_gtt_driver }, 146802c026ceSDaniel Vetter { 0, NULL, NULL } 146902c026ceSDaniel Vetter }; 147002c026ceSDaniel Vetter 147102c026ceSDaniel Vetter static int find_gmch(u16 device) 147202c026ceSDaniel Vetter { 147302c026ceSDaniel Vetter struct pci_dev *gmch_device; 147402c026ceSDaniel Vetter 147502c026ceSDaniel Vetter gmch_device = pci_get_device(PCI_VENDOR_ID_INTEL, device, NULL); 147602c026ceSDaniel Vetter if (gmch_device && PCI_FUNC(gmch_device->devfn) != 0) { 147702c026ceSDaniel Vetter gmch_device = pci_get_device(PCI_VENDOR_ID_INTEL, 147802c026ceSDaniel Vetter device, gmch_device); 147902c026ceSDaniel Vetter } 148002c026ceSDaniel Vetter 148102c026ceSDaniel Vetter if (!gmch_device) 148202c026ceSDaniel Vetter return 0; 148302c026ceSDaniel Vetter 148402c026ceSDaniel Vetter intel_private.pcidev = gmch_device; 148502c026ceSDaniel Vetter return 1; 148602c026ceSDaniel Vetter } 148702c026ceSDaniel Vetter 1488e2404e7cSDaniel Vetter int intel_gmch_probe(struct pci_dev *pdev, 148902c026ceSDaniel Vetter struct agp_bridge_data *bridge) 149002c026ceSDaniel Vetter { 149102c026ceSDaniel Vetter int i, mask; 149202c026ceSDaniel Vetter bridge->driver = NULL; 149302c026ceSDaniel Vetter 149402c026ceSDaniel Vetter for (i = 0; intel_gtt_chipsets[i].name != NULL; i++) { 149502c026ceSDaniel Vetter if (find_gmch(intel_gtt_chipsets[i].gmch_chip_id)) { 149602c026ceSDaniel Vetter bridge->driver = 149702c026ceSDaniel Vetter intel_gtt_chipsets[i].gmch_driver; 14981a997ff2SDaniel Vetter intel_private.driver = 14991a997ff2SDaniel Vetter intel_gtt_chipsets[i].gtt_driver; 150002c026ceSDaniel Vetter break; 150102c026ceSDaniel Vetter } 150202c026ceSDaniel Vetter } 150302c026ceSDaniel Vetter 150402c026ceSDaniel Vetter if (!bridge->driver) 150502c026ceSDaniel Vetter return 0; 150602c026ceSDaniel Vetter 150702c026ceSDaniel Vetter bridge->dev_private_data = &intel_private; 150802c026ceSDaniel Vetter bridge->dev = pdev; 150902c026ceSDaniel Vetter 1510d7cca2f7SDaniel Vetter intel_private.bridge_dev = pci_dev_get(pdev); 1511d7cca2f7SDaniel Vetter 151202c026ceSDaniel Vetter dev_info(&pdev->dev, "Intel %s Chipset\n", intel_gtt_chipsets[i].name); 151302c026ceSDaniel Vetter 1514bdd30729SDaniel Vetter if (intel_private.driver->write_entry == gen6_write_entry) 151502c026ceSDaniel Vetter mask = 40; 1516bdd30729SDaniel Vetter else if (intel_private.driver->write_entry == i965_write_entry) 151702c026ceSDaniel Vetter mask = 36; 151802c026ceSDaniel Vetter else 151902c026ceSDaniel Vetter mask = 32; 152002c026ceSDaniel Vetter 152102c026ceSDaniel Vetter if (pci_set_dma_mask(intel_private.pcidev, DMA_BIT_MASK(mask))) 152202c026ceSDaniel Vetter dev_err(&intel_private.pcidev->dev, 152302c026ceSDaniel Vetter "set gfx device dma mask %d-bit failed!\n", mask); 152402c026ceSDaniel Vetter else 152502c026ceSDaniel Vetter pci_set_consistent_dma_mask(intel_private.pcidev, 152602c026ceSDaniel Vetter DMA_BIT_MASK(mask)); 152702c026ceSDaniel Vetter 15281784a5fbSDaniel Vetter if (bridge->driver == &intel_810_driver) 15291784a5fbSDaniel Vetter return 1; 15301784a5fbSDaniel Vetter 15313b15a9d7SDaniel Vetter if (intel_gtt_init() != 0) 15323b15a9d7SDaniel Vetter return 0; 15331784a5fbSDaniel Vetter 153402c026ceSDaniel Vetter return 1; 153502c026ceSDaniel Vetter } 1536e2404e7cSDaniel Vetter EXPORT_SYMBOL(intel_gmch_probe); 153702c026ceSDaniel Vetter 153819966754SDaniel Vetter struct intel_gtt *intel_gtt_get(void) 153919966754SDaniel Vetter { 154019966754SDaniel Vetter return &intel_private.base; 154119966754SDaniel Vetter } 154219966754SDaniel Vetter EXPORT_SYMBOL(intel_gtt_get); 154319966754SDaniel Vetter 1544e2404e7cSDaniel Vetter void intel_gmch_remove(struct pci_dev *pdev) 154502c026ceSDaniel Vetter { 154602c026ceSDaniel Vetter if (intel_private.pcidev) 154702c026ceSDaniel Vetter pci_dev_put(intel_private.pcidev); 1548d7cca2f7SDaniel Vetter if (intel_private.bridge_dev) 1549d7cca2f7SDaniel Vetter pci_dev_put(intel_private.bridge_dev); 155002c026ceSDaniel Vetter } 1551e2404e7cSDaniel Vetter EXPORT_SYMBOL(intel_gmch_remove); 1552e2404e7cSDaniel Vetter 1553e2404e7cSDaniel Vetter MODULE_AUTHOR("Dave Jones <davej@redhat.com>"); 1554e2404e7cSDaniel Vetter MODULE_LICENSE("GPL and additional rights"); 1555