18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Intel GTT (Graphics Translation Table) routines 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Caveat: This driver implements the linux agp interface, but this is far from 58c2ecf20Sopenharmony_ci * a agp driver! GTT support ended up here for purely historical reasons: The 68c2ecf20Sopenharmony_ci * old userspace intel graphics drivers needed an interface to map memory into 78c2ecf20Sopenharmony_ci * the GTT. And the drm provides a default interface for graphic devices sitting 88c2ecf20Sopenharmony_ci * on an agp port. So it made sense to fake the GTT support as an agp port to 98c2ecf20Sopenharmony_ci * avoid having to create a new api. 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * With gem this does not make much sense anymore, just needlessly complicates 128c2ecf20Sopenharmony_ci * the code. But as long as the old graphics stack is still support, it's stuck 138c2ecf20Sopenharmony_ci * here. 148c2ecf20Sopenharmony_ci * 158c2ecf20Sopenharmony_ci * /fairy-tale-mode off 168c2ecf20Sopenharmony_ci */ 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#include <linux/module.h> 198c2ecf20Sopenharmony_ci#include <linux/pci.h> 208c2ecf20Sopenharmony_ci#include <linux/kernel.h> 218c2ecf20Sopenharmony_ci#include <linux/pagemap.h> 228c2ecf20Sopenharmony_ci#include <linux/agp_backend.h> 238c2ecf20Sopenharmony_ci#include <linux/delay.h> 248c2ecf20Sopenharmony_ci#include <asm/smp.h> 258c2ecf20Sopenharmony_ci#include "agp.h" 268c2ecf20Sopenharmony_ci#include "intel-agp.h" 278c2ecf20Sopenharmony_ci#include <drm/intel-gtt.h> 288c2ecf20Sopenharmony_ci#include <asm/set_memory.h> 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci/* 318c2ecf20Sopenharmony_ci * If we have Intel graphics, we're not going to have anything other than 328c2ecf20Sopenharmony_ci * an Intel IOMMU. So make the correct use of the PCI DMA API contingent 338c2ecf20Sopenharmony_ci * on the Intel IOMMU support (CONFIG_INTEL_IOMMU). 348c2ecf20Sopenharmony_ci * Only newer chipsets need to bother with this, of course. 358c2ecf20Sopenharmony_ci */ 368c2ecf20Sopenharmony_ci#ifdef CONFIG_INTEL_IOMMU 378c2ecf20Sopenharmony_ci#define USE_PCI_DMA_API 1 388c2ecf20Sopenharmony_ci#else 398c2ecf20Sopenharmony_ci#define USE_PCI_DMA_API 0 408c2ecf20Sopenharmony_ci#endif 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_cistruct intel_gtt_driver { 438c2ecf20Sopenharmony_ci unsigned int gen : 8; 448c2ecf20Sopenharmony_ci unsigned int is_g33 : 1; 458c2ecf20Sopenharmony_ci unsigned int is_pineview : 1; 468c2ecf20Sopenharmony_ci unsigned int is_ironlake : 1; 478c2ecf20Sopenharmony_ci unsigned int has_pgtbl_enable : 1; 488c2ecf20Sopenharmony_ci unsigned int dma_mask_size : 8; 498c2ecf20Sopenharmony_ci /* Chipset specific GTT setup */ 508c2ecf20Sopenharmony_ci int (*setup)(void); 518c2ecf20Sopenharmony_ci /* This should undo anything done in ->setup() save the unmapping 528c2ecf20Sopenharmony_ci * of the mmio register file, that's done in the generic code. */ 538c2ecf20Sopenharmony_ci void (*cleanup)(void); 548c2ecf20Sopenharmony_ci void (*write_entry)(dma_addr_t addr, unsigned int entry, unsigned int flags); 558c2ecf20Sopenharmony_ci /* Flags is a more or less chipset specific opaque value. 568c2ecf20Sopenharmony_ci * For chipsets that need to support old ums (non-gem) code, this 578c2ecf20Sopenharmony_ci * needs to be identical to the various supported agp memory types! */ 588c2ecf20Sopenharmony_ci bool (*check_flags)(unsigned int flags); 598c2ecf20Sopenharmony_ci void (*chipset_flush)(void); 608c2ecf20Sopenharmony_ci}; 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_cistatic struct _intel_private { 638c2ecf20Sopenharmony_ci const struct intel_gtt_driver *driver; 648c2ecf20Sopenharmony_ci struct pci_dev *pcidev; /* device one */ 658c2ecf20Sopenharmony_ci struct pci_dev *bridge_dev; 668c2ecf20Sopenharmony_ci u8 __iomem *registers; 678c2ecf20Sopenharmony_ci phys_addr_t gtt_phys_addr; 688c2ecf20Sopenharmony_ci u32 PGETBL_save; 698c2ecf20Sopenharmony_ci u32 __iomem *gtt; /* I915G */ 708c2ecf20Sopenharmony_ci bool clear_fake_agp; /* on first access via agp, fill with scratch */ 718c2ecf20Sopenharmony_ci int num_dcache_entries; 728c2ecf20Sopenharmony_ci void __iomem *i9xx_flush_page; 738c2ecf20Sopenharmony_ci char *i81x_gtt_table; 748c2ecf20Sopenharmony_ci struct resource ifp_resource; 758c2ecf20Sopenharmony_ci int resource_valid; 768c2ecf20Sopenharmony_ci struct page *scratch_page; 778c2ecf20Sopenharmony_ci phys_addr_t scratch_page_dma; 788c2ecf20Sopenharmony_ci int refcount; 798c2ecf20Sopenharmony_ci /* Whether i915 needs to use the dmar apis or not. */ 808c2ecf20Sopenharmony_ci unsigned int needs_dmar : 1; 818c2ecf20Sopenharmony_ci phys_addr_t gma_bus_addr; 828c2ecf20Sopenharmony_ci /* Size of memory reserved for graphics by the BIOS */ 838c2ecf20Sopenharmony_ci resource_size_t stolen_size; 848c2ecf20Sopenharmony_ci /* Total number of gtt entries. */ 858c2ecf20Sopenharmony_ci unsigned int gtt_total_entries; 868c2ecf20Sopenharmony_ci /* Part of the gtt that is mappable by the cpu, for those chips where 878c2ecf20Sopenharmony_ci * this is not the full gtt. */ 888c2ecf20Sopenharmony_ci unsigned int gtt_mappable_entries; 898c2ecf20Sopenharmony_ci} intel_private; 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci#define INTEL_GTT_GEN intel_private.driver->gen 928c2ecf20Sopenharmony_ci#define IS_G33 intel_private.driver->is_g33 938c2ecf20Sopenharmony_ci#define IS_PINEVIEW intel_private.driver->is_pineview 948c2ecf20Sopenharmony_ci#define IS_IRONLAKE intel_private.driver->is_ironlake 958c2ecf20Sopenharmony_ci#define HAS_PGTBL_EN intel_private.driver->has_pgtbl_enable 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_AGP_INTEL) 988c2ecf20Sopenharmony_cistatic int intel_gtt_map_memory(struct page **pages, 998c2ecf20Sopenharmony_ci unsigned int num_entries, 1008c2ecf20Sopenharmony_ci struct sg_table *st) 1018c2ecf20Sopenharmony_ci{ 1028c2ecf20Sopenharmony_ci struct scatterlist *sg; 1038c2ecf20Sopenharmony_ci int i; 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci DBG("try mapping %lu pages\n", (unsigned long)num_entries); 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci if (sg_alloc_table(st, num_entries, GFP_KERNEL)) 1088c2ecf20Sopenharmony_ci goto err; 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci for_each_sg(st->sgl, sg, num_entries, i) 1118c2ecf20Sopenharmony_ci sg_set_page(sg, pages[i], PAGE_SIZE, 0); 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci if (!pci_map_sg(intel_private.pcidev, 1148c2ecf20Sopenharmony_ci st->sgl, st->nents, PCI_DMA_BIDIRECTIONAL)) 1158c2ecf20Sopenharmony_ci goto err; 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci return 0; 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_cierr: 1208c2ecf20Sopenharmony_ci sg_free_table(st); 1218c2ecf20Sopenharmony_ci return -ENOMEM; 1228c2ecf20Sopenharmony_ci} 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_cistatic void intel_gtt_unmap_memory(struct scatterlist *sg_list, int num_sg) 1258c2ecf20Sopenharmony_ci{ 1268c2ecf20Sopenharmony_ci struct sg_table st; 1278c2ecf20Sopenharmony_ci DBG("try unmapping %lu pages\n", (unsigned long)mem->page_count); 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci pci_unmap_sg(intel_private.pcidev, sg_list, 1308c2ecf20Sopenharmony_ci num_sg, PCI_DMA_BIDIRECTIONAL); 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci st.sgl = sg_list; 1338c2ecf20Sopenharmony_ci st.orig_nents = st.nents = num_sg; 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci sg_free_table(&st); 1368c2ecf20Sopenharmony_ci} 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_cistatic void intel_fake_agp_enable(struct agp_bridge_data *bridge, u32 mode) 1398c2ecf20Sopenharmony_ci{ 1408c2ecf20Sopenharmony_ci return; 1418c2ecf20Sopenharmony_ci} 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci/* Exists to support ARGB cursors */ 1448c2ecf20Sopenharmony_cistatic struct page *i8xx_alloc_pages(void) 1458c2ecf20Sopenharmony_ci{ 1468c2ecf20Sopenharmony_ci struct page *page; 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci page = alloc_pages(GFP_KERNEL | GFP_DMA32, 2); 1498c2ecf20Sopenharmony_ci if (page == NULL) 1508c2ecf20Sopenharmony_ci return NULL; 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci if (set_pages_uc(page, 4) < 0) { 1538c2ecf20Sopenharmony_ci set_pages_wb(page, 4); 1548c2ecf20Sopenharmony_ci __free_pages(page, 2); 1558c2ecf20Sopenharmony_ci return NULL; 1568c2ecf20Sopenharmony_ci } 1578c2ecf20Sopenharmony_ci atomic_inc(&agp_bridge->current_memory_agp); 1588c2ecf20Sopenharmony_ci return page; 1598c2ecf20Sopenharmony_ci} 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_cistatic void i8xx_destroy_pages(struct page *page) 1628c2ecf20Sopenharmony_ci{ 1638c2ecf20Sopenharmony_ci if (page == NULL) 1648c2ecf20Sopenharmony_ci return; 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci set_pages_wb(page, 4); 1678c2ecf20Sopenharmony_ci __free_pages(page, 2); 1688c2ecf20Sopenharmony_ci atomic_dec(&agp_bridge->current_memory_agp); 1698c2ecf20Sopenharmony_ci} 1708c2ecf20Sopenharmony_ci#endif 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci#define I810_GTT_ORDER 4 1738c2ecf20Sopenharmony_cistatic int i810_setup(void) 1748c2ecf20Sopenharmony_ci{ 1758c2ecf20Sopenharmony_ci phys_addr_t reg_addr; 1768c2ecf20Sopenharmony_ci char *gtt_table; 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci /* i81x does not preallocate the gtt. It's always 64kb in size. */ 1798c2ecf20Sopenharmony_ci gtt_table = alloc_gatt_pages(I810_GTT_ORDER); 1808c2ecf20Sopenharmony_ci if (gtt_table == NULL) 1818c2ecf20Sopenharmony_ci return -ENOMEM; 1828c2ecf20Sopenharmony_ci intel_private.i81x_gtt_table = gtt_table; 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci reg_addr = pci_resource_start(intel_private.pcidev, I810_MMADR_BAR); 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci intel_private.registers = ioremap(reg_addr, KB(64)); 1878c2ecf20Sopenharmony_ci if (!intel_private.registers) 1888c2ecf20Sopenharmony_ci return -ENOMEM; 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci writel(virt_to_phys(gtt_table) | I810_PGETBL_ENABLED, 1918c2ecf20Sopenharmony_ci intel_private.registers+I810_PGETBL_CTL); 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci intel_private.gtt_phys_addr = reg_addr + I810_PTE_BASE; 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci if ((readl(intel_private.registers+I810_DRAM_CTL) 1968c2ecf20Sopenharmony_ci & I810_DRAM_ROW_0) == I810_DRAM_ROW_0_SDRAM) { 1978c2ecf20Sopenharmony_ci dev_info(&intel_private.pcidev->dev, 1988c2ecf20Sopenharmony_ci "detected 4MB dedicated video ram\n"); 1998c2ecf20Sopenharmony_ci intel_private.num_dcache_entries = 1024; 2008c2ecf20Sopenharmony_ci } 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci return 0; 2038c2ecf20Sopenharmony_ci} 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_cistatic void i810_cleanup(void) 2068c2ecf20Sopenharmony_ci{ 2078c2ecf20Sopenharmony_ci writel(0, intel_private.registers+I810_PGETBL_CTL); 2088c2ecf20Sopenharmony_ci free_gatt_pages(intel_private.i81x_gtt_table, I810_GTT_ORDER); 2098c2ecf20Sopenharmony_ci} 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_AGP_INTEL) 2128c2ecf20Sopenharmony_cistatic int i810_insert_dcache_entries(struct agp_memory *mem, off_t pg_start, 2138c2ecf20Sopenharmony_ci int type) 2148c2ecf20Sopenharmony_ci{ 2158c2ecf20Sopenharmony_ci int i; 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci if ((pg_start + mem->page_count) 2188c2ecf20Sopenharmony_ci > intel_private.num_dcache_entries) 2198c2ecf20Sopenharmony_ci return -EINVAL; 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci if (!mem->is_flushed) 2228c2ecf20Sopenharmony_ci global_cache_flush(); 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci for (i = pg_start; i < (pg_start + mem->page_count); i++) { 2258c2ecf20Sopenharmony_ci dma_addr_t addr = i << PAGE_SHIFT; 2268c2ecf20Sopenharmony_ci intel_private.driver->write_entry(addr, 2278c2ecf20Sopenharmony_ci i, type); 2288c2ecf20Sopenharmony_ci } 2298c2ecf20Sopenharmony_ci wmb(); 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci return 0; 2328c2ecf20Sopenharmony_ci} 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci/* 2358c2ecf20Sopenharmony_ci * The i810/i830 requires a physical address to program its mouse 2368c2ecf20Sopenharmony_ci * pointer into hardware. 2378c2ecf20Sopenharmony_ci * However the Xserver still writes to it through the agp aperture. 2388c2ecf20Sopenharmony_ci */ 2398c2ecf20Sopenharmony_cistatic struct agp_memory *alloc_agpphysmem_i8xx(size_t pg_count, int type) 2408c2ecf20Sopenharmony_ci{ 2418c2ecf20Sopenharmony_ci struct agp_memory *new; 2428c2ecf20Sopenharmony_ci struct page *page; 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci switch (pg_count) { 2458c2ecf20Sopenharmony_ci case 1: page = agp_bridge->driver->agp_alloc_page(agp_bridge); 2468c2ecf20Sopenharmony_ci break; 2478c2ecf20Sopenharmony_ci case 4: 2488c2ecf20Sopenharmony_ci /* kludge to get 4 physical pages for ARGB cursor */ 2498c2ecf20Sopenharmony_ci page = i8xx_alloc_pages(); 2508c2ecf20Sopenharmony_ci break; 2518c2ecf20Sopenharmony_ci default: 2528c2ecf20Sopenharmony_ci return NULL; 2538c2ecf20Sopenharmony_ci } 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci if (page == NULL) 2568c2ecf20Sopenharmony_ci return NULL; 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci new = agp_create_memory(pg_count); 2598c2ecf20Sopenharmony_ci if (new == NULL) 2608c2ecf20Sopenharmony_ci return NULL; 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci new->pages[0] = page; 2638c2ecf20Sopenharmony_ci if (pg_count == 4) { 2648c2ecf20Sopenharmony_ci /* kludge to get 4 physical pages for ARGB cursor */ 2658c2ecf20Sopenharmony_ci new->pages[1] = new->pages[0] + 1; 2668c2ecf20Sopenharmony_ci new->pages[2] = new->pages[1] + 1; 2678c2ecf20Sopenharmony_ci new->pages[3] = new->pages[2] + 1; 2688c2ecf20Sopenharmony_ci } 2698c2ecf20Sopenharmony_ci new->page_count = pg_count; 2708c2ecf20Sopenharmony_ci new->num_scratch_pages = pg_count; 2718c2ecf20Sopenharmony_ci new->type = AGP_PHYS_MEMORY; 2728c2ecf20Sopenharmony_ci new->physical = page_to_phys(new->pages[0]); 2738c2ecf20Sopenharmony_ci return new; 2748c2ecf20Sopenharmony_ci} 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_cistatic void intel_i810_free_by_type(struct agp_memory *curr) 2778c2ecf20Sopenharmony_ci{ 2788c2ecf20Sopenharmony_ci agp_free_key(curr->key); 2798c2ecf20Sopenharmony_ci if (curr->type == AGP_PHYS_MEMORY) { 2808c2ecf20Sopenharmony_ci if (curr->page_count == 4) 2818c2ecf20Sopenharmony_ci i8xx_destroy_pages(curr->pages[0]); 2828c2ecf20Sopenharmony_ci else { 2838c2ecf20Sopenharmony_ci agp_bridge->driver->agp_destroy_page(curr->pages[0], 2848c2ecf20Sopenharmony_ci AGP_PAGE_DESTROY_UNMAP); 2858c2ecf20Sopenharmony_ci agp_bridge->driver->agp_destroy_page(curr->pages[0], 2868c2ecf20Sopenharmony_ci AGP_PAGE_DESTROY_FREE); 2878c2ecf20Sopenharmony_ci } 2888c2ecf20Sopenharmony_ci agp_free_page_array(curr); 2898c2ecf20Sopenharmony_ci } 2908c2ecf20Sopenharmony_ci kfree(curr); 2918c2ecf20Sopenharmony_ci} 2928c2ecf20Sopenharmony_ci#endif 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_cistatic int intel_gtt_setup_scratch_page(void) 2958c2ecf20Sopenharmony_ci{ 2968c2ecf20Sopenharmony_ci struct page *page; 2978c2ecf20Sopenharmony_ci dma_addr_t dma_addr; 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci page = alloc_page(GFP_KERNEL | GFP_DMA32 | __GFP_ZERO); 3008c2ecf20Sopenharmony_ci if (page == NULL) 3018c2ecf20Sopenharmony_ci return -ENOMEM; 3028c2ecf20Sopenharmony_ci set_pages_uc(page, 1); 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci if (intel_private.needs_dmar) { 3058c2ecf20Sopenharmony_ci dma_addr = pci_map_page(intel_private.pcidev, page, 0, 3068c2ecf20Sopenharmony_ci PAGE_SIZE, PCI_DMA_BIDIRECTIONAL); 3078c2ecf20Sopenharmony_ci if (pci_dma_mapping_error(intel_private.pcidev, dma_addr)) { 3088c2ecf20Sopenharmony_ci __free_page(page); 3098c2ecf20Sopenharmony_ci return -EINVAL; 3108c2ecf20Sopenharmony_ci } 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci intel_private.scratch_page_dma = dma_addr; 3138c2ecf20Sopenharmony_ci } else 3148c2ecf20Sopenharmony_ci intel_private.scratch_page_dma = page_to_phys(page); 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci intel_private.scratch_page = page; 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci return 0; 3198c2ecf20Sopenharmony_ci} 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_cistatic void i810_write_entry(dma_addr_t addr, unsigned int entry, 3228c2ecf20Sopenharmony_ci unsigned int flags) 3238c2ecf20Sopenharmony_ci{ 3248c2ecf20Sopenharmony_ci u32 pte_flags = I810_PTE_VALID; 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci switch (flags) { 3278c2ecf20Sopenharmony_ci case AGP_DCACHE_MEMORY: 3288c2ecf20Sopenharmony_ci pte_flags |= I810_PTE_LOCAL; 3298c2ecf20Sopenharmony_ci break; 3308c2ecf20Sopenharmony_ci case AGP_USER_CACHED_MEMORY: 3318c2ecf20Sopenharmony_ci pte_flags |= I830_PTE_SYSTEM_CACHED; 3328c2ecf20Sopenharmony_ci break; 3338c2ecf20Sopenharmony_ci } 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci writel_relaxed(addr | pte_flags, intel_private.gtt + entry); 3368c2ecf20Sopenharmony_ci} 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_cistatic resource_size_t intel_gtt_stolen_size(void) 3398c2ecf20Sopenharmony_ci{ 3408c2ecf20Sopenharmony_ci u16 gmch_ctrl; 3418c2ecf20Sopenharmony_ci u8 rdct; 3428c2ecf20Sopenharmony_ci int local = 0; 3438c2ecf20Sopenharmony_ci static const int ddt[4] = { 0, 16, 32, 64 }; 3448c2ecf20Sopenharmony_ci resource_size_t stolen_size = 0; 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci if (INTEL_GTT_GEN == 1) 3478c2ecf20Sopenharmony_ci return 0; /* no stolen mem on i81x */ 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci pci_read_config_word(intel_private.bridge_dev, 3508c2ecf20Sopenharmony_ci I830_GMCH_CTRL, &gmch_ctrl); 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci if (intel_private.bridge_dev->device == PCI_DEVICE_ID_INTEL_82830_HB || 3538c2ecf20Sopenharmony_ci intel_private.bridge_dev->device == PCI_DEVICE_ID_INTEL_82845G_HB) { 3548c2ecf20Sopenharmony_ci switch (gmch_ctrl & I830_GMCH_GMS_MASK) { 3558c2ecf20Sopenharmony_ci case I830_GMCH_GMS_STOLEN_512: 3568c2ecf20Sopenharmony_ci stolen_size = KB(512); 3578c2ecf20Sopenharmony_ci break; 3588c2ecf20Sopenharmony_ci case I830_GMCH_GMS_STOLEN_1024: 3598c2ecf20Sopenharmony_ci stolen_size = MB(1); 3608c2ecf20Sopenharmony_ci break; 3618c2ecf20Sopenharmony_ci case I830_GMCH_GMS_STOLEN_8192: 3628c2ecf20Sopenharmony_ci stolen_size = MB(8); 3638c2ecf20Sopenharmony_ci break; 3648c2ecf20Sopenharmony_ci case I830_GMCH_GMS_LOCAL: 3658c2ecf20Sopenharmony_ci rdct = readb(intel_private.registers+I830_RDRAM_CHANNEL_TYPE); 3668c2ecf20Sopenharmony_ci stolen_size = (I830_RDRAM_ND(rdct) + 1) * 3678c2ecf20Sopenharmony_ci MB(ddt[I830_RDRAM_DDT(rdct)]); 3688c2ecf20Sopenharmony_ci local = 1; 3698c2ecf20Sopenharmony_ci break; 3708c2ecf20Sopenharmony_ci default: 3718c2ecf20Sopenharmony_ci stolen_size = 0; 3728c2ecf20Sopenharmony_ci break; 3738c2ecf20Sopenharmony_ci } 3748c2ecf20Sopenharmony_ci } else { 3758c2ecf20Sopenharmony_ci switch (gmch_ctrl & I855_GMCH_GMS_MASK) { 3768c2ecf20Sopenharmony_ci case I855_GMCH_GMS_STOLEN_1M: 3778c2ecf20Sopenharmony_ci stolen_size = MB(1); 3788c2ecf20Sopenharmony_ci break; 3798c2ecf20Sopenharmony_ci case I855_GMCH_GMS_STOLEN_4M: 3808c2ecf20Sopenharmony_ci stolen_size = MB(4); 3818c2ecf20Sopenharmony_ci break; 3828c2ecf20Sopenharmony_ci case I855_GMCH_GMS_STOLEN_8M: 3838c2ecf20Sopenharmony_ci stolen_size = MB(8); 3848c2ecf20Sopenharmony_ci break; 3858c2ecf20Sopenharmony_ci case I855_GMCH_GMS_STOLEN_16M: 3868c2ecf20Sopenharmony_ci stolen_size = MB(16); 3878c2ecf20Sopenharmony_ci break; 3888c2ecf20Sopenharmony_ci case I855_GMCH_GMS_STOLEN_32M: 3898c2ecf20Sopenharmony_ci stolen_size = MB(32); 3908c2ecf20Sopenharmony_ci break; 3918c2ecf20Sopenharmony_ci case I915_GMCH_GMS_STOLEN_48M: 3928c2ecf20Sopenharmony_ci stolen_size = MB(48); 3938c2ecf20Sopenharmony_ci break; 3948c2ecf20Sopenharmony_ci case I915_GMCH_GMS_STOLEN_64M: 3958c2ecf20Sopenharmony_ci stolen_size = MB(64); 3968c2ecf20Sopenharmony_ci break; 3978c2ecf20Sopenharmony_ci case G33_GMCH_GMS_STOLEN_128M: 3988c2ecf20Sopenharmony_ci stolen_size = MB(128); 3998c2ecf20Sopenharmony_ci break; 4008c2ecf20Sopenharmony_ci case G33_GMCH_GMS_STOLEN_256M: 4018c2ecf20Sopenharmony_ci stolen_size = MB(256); 4028c2ecf20Sopenharmony_ci break; 4038c2ecf20Sopenharmony_ci case INTEL_GMCH_GMS_STOLEN_96M: 4048c2ecf20Sopenharmony_ci stolen_size = MB(96); 4058c2ecf20Sopenharmony_ci break; 4068c2ecf20Sopenharmony_ci case INTEL_GMCH_GMS_STOLEN_160M: 4078c2ecf20Sopenharmony_ci stolen_size = MB(160); 4088c2ecf20Sopenharmony_ci break; 4098c2ecf20Sopenharmony_ci case INTEL_GMCH_GMS_STOLEN_224M: 4108c2ecf20Sopenharmony_ci stolen_size = MB(224); 4118c2ecf20Sopenharmony_ci break; 4128c2ecf20Sopenharmony_ci case INTEL_GMCH_GMS_STOLEN_352M: 4138c2ecf20Sopenharmony_ci stolen_size = MB(352); 4148c2ecf20Sopenharmony_ci break; 4158c2ecf20Sopenharmony_ci default: 4168c2ecf20Sopenharmony_ci stolen_size = 0; 4178c2ecf20Sopenharmony_ci break; 4188c2ecf20Sopenharmony_ci } 4198c2ecf20Sopenharmony_ci } 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci if (stolen_size > 0) { 4228c2ecf20Sopenharmony_ci dev_info(&intel_private.bridge_dev->dev, "detected %lluK %s memory\n", 4238c2ecf20Sopenharmony_ci (u64)stolen_size / KB(1), local ? "local" : "stolen"); 4248c2ecf20Sopenharmony_ci } else { 4258c2ecf20Sopenharmony_ci dev_info(&intel_private.bridge_dev->dev, 4268c2ecf20Sopenharmony_ci "no pre-allocated video memory detected\n"); 4278c2ecf20Sopenharmony_ci stolen_size = 0; 4288c2ecf20Sopenharmony_ci } 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_ci return stolen_size; 4318c2ecf20Sopenharmony_ci} 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_cistatic void i965_adjust_pgetbl_size(unsigned int size_flag) 4348c2ecf20Sopenharmony_ci{ 4358c2ecf20Sopenharmony_ci u32 pgetbl_ctl, pgetbl_ctl2; 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci /* ensure that ppgtt is disabled */ 4388c2ecf20Sopenharmony_ci pgetbl_ctl2 = readl(intel_private.registers+I965_PGETBL_CTL2); 4398c2ecf20Sopenharmony_ci pgetbl_ctl2 &= ~I810_PGETBL_ENABLED; 4408c2ecf20Sopenharmony_ci writel(pgetbl_ctl2, intel_private.registers+I965_PGETBL_CTL2); 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_ci /* write the new ggtt size */ 4438c2ecf20Sopenharmony_ci pgetbl_ctl = readl(intel_private.registers+I810_PGETBL_CTL); 4448c2ecf20Sopenharmony_ci pgetbl_ctl &= ~I965_PGETBL_SIZE_MASK; 4458c2ecf20Sopenharmony_ci pgetbl_ctl |= size_flag; 4468c2ecf20Sopenharmony_ci writel(pgetbl_ctl, intel_private.registers+I810_PGETBL_CTL); 4478c2ecf20Sopenharmony_ci} 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_cistatic unsigned int i965_gtt_total_entries(void) 4508c2ecf20Sopenharmony_ci{ 4518c2ecf20Sopenharmony_ci int size; 4528c2ecf20Sopenharmony_ci u32 pgetbl_ctl; 4538c2ecf20Sopenharmony_ci u16 gmch_ctl; 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci pci_read_config_word(intel_private.bridge_dev, 4568c2ecf20Sopenharmony_ci I830_GMCH_CTRL, &gmch_ctl); 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ci if (INTEL_GTT_GEN == 5) { 4598c2ecf20Sopenharmony_ci switch (gmch_ctl & G4x_GMCH_SIZE_MASK) { 4608c2ecf20Sopenharmony_ci case G4x_GMCH_SIZE_1M: 4618c2ecf20Sopenharmony_ci case G4x_GMCH_SIZE_VT_1M: 4628c2ecf20Sopenharmony_ci i965_adjust_pgetbl_size(I965_PGETBL_SIZE_1MB); 4638c2ecf20Sopenharmony_ci break; 4648c2ecf20Sopenharmony_ci case G4x_GMCH_SIZE_VT_1_5M: 4658c2ecf20Sopenharmony_ci i965_adjust_pgetbl_size(I965_PGETBL_SIZE_1_5MB); 4668c2ecf20Sopenharmony_ci break; 4678c2ecf20Sopenharmony_ci case G4x_GMCH_SIZE_2M: 4688c2ecf20Sopenharmony_ci case G4x_GMCH_SIZE_VT_2M: 4698c2ecf20Sopenharmony_ci i965_adjust_pgetbl_size(I965_PGETBL_SIZE_2MB); 4708c2ecf20Sopenharmony_ci break; 4718c2ecf20Sopenharmony_ci } 4728c2ecf20Sopenharmony_ci } 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_ci pgetbl_ctl = readl(intel_private.registers+I810_PGETBL_CTL); 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci switch (pgetbl_ctl & I965_PGETBL_SIZE_MASK) { 4778c2ecf20Sopenharmony_ci case I965_PGETBL_SIZE_128KB: 4788c2ecf20Sopenharmony_ci size = KB(128); 4798c2ecf20Sopenharmony_ci break; 4808c2ecf20Sopenharmony_ci case I965_PGETBL_SIZE_256KB: 4818c2ecf20Sopenharmony_ci size = KB(256); 4828c2ecf20Sopenharmony_ci break; 4838c2ecf20Sopenharmony_ci case I965_PGETBL_SIZE_512KB: 4848c2ecf20Sopenharmony_ci size = KB(512); 4858c2ecf20Sopenharmony_ci break; 4868c2ecf20Sopenharmony_ci /* GTT pagetable sizes bigger than 512KB are not possible on G33! */ 4878c2ecf20Sopenharmony_ci case I965_PGETBL_SIZE_1MB: 4888c2ecf20Sopenharmony_ci size = KB(1024); 4898c2ecf20Sopenharmony_ci break; 4908c2ecf20Sopenharmony_ci case I965_PGETBL_SIZE_2MB: 4918c2ecf20Sopenharmony_ci size = KB(2048); 4928c2ecf20Sopenharmony_ci break; 4938c2ecf20Sopenharmony_ci case I965_PGETBL_SIZE_1_5MB: 4948c2ecf20Sopenharmony_ci size = KB(1024 + 512); 4958c2ecf20Sopenharmony_ci break; 4968c2ecf20Sopenharmony_ci default: 4978c2ecf20Sopenharmony_ci dev_info(&intel_private.pcidev->dev, 4988c2ecf20Sopenharmony_ci "unknown page table size, assuming 512KB\n"); 4998c2ecf20Sopenharmony_ci size = KB(512); 5008c2ecf20Sopenharmony_ci } 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ci return size/4; 5038c2ecf20Sopenharmony_ci} 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_cistatic unsigned int intel_gtt_total_entries(void) 5068c2ecf20Sopenharmony_ci{ 5078c2ecf20Sopenharmony_ci if (IS_G33 || INTEL_GTT_GEN == 4 || INTEL_GTT_GEN == 5) 5088c2ecf20Sopenharmony_ci return i965_gtt_total_entries(); 5098c2ecf20Sopenharmony_ci else { 5108c2ecf20Sopenharmony_ci /* On previous hardware, the GTT size was just what was 5118c2ecf20Sopenharmony_ci * required to map the aperture. 5128c2ecf20Sopenharmony_ci */ 5138c2ecf20Sopenharmony_ci return intel_private.gtt_mappable_entries; 5148c2ecf20Sopenharmony_ci } 5158c2ecf20Sopenharmony_ci} 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_cistatic unsigned int intel_gtt_mappable_entries(void) 5188c2ecf20Sopenharmony_ci{ 5198c2ecf20Sopenharmony_ci unsigned int aperture_size; 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci if (INTEL_GTT_GEN == 1) { 5228c2ecf20Sopenharmony_ci u32 smram_miscc; 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_ci pci_read_config_dword(intel_private.bridge_dev, 5258c2ecf20Sopenharmony_ci I810_SMRAM_MISCC, &smram_miscc); 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ci if ((smram_miscc & I810_GFX_MEM_WIN_SIZE) 5288c2ecf20Sopenharmony_ci == I810_GFX_MEM_WIN_32M) 5298c2ecf20Sopenharmony_ci aperture_size = MB(32); 5308c2ecf20Sopenharmony_ci else 5318c2ecf20Sopenharmony_ci aperture_size = MB(64); 5328c2ecf20Sopenharmony_ci } else if (INTEL_GTT_GEN == 2) { 5338c2ecf20Sopenharmony_ci u16 gmch_ctrl; 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_ci pci_read_config_word(intel_private.bridge_dev, 5368c2ecf20Sopenharmony_ci I830_GMCH_CTRL, &gmch_ctrl); 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_ci if ((gmch_ctrl & I830_GMCH_MEM_MASK) == I830_GMCH_MEM_64M) 5398c2ecf20Sopenharmony_ci aperture_size = MB(64); 5408c2ecf20Sopenharmony_ci else 5418c2ecf20Sopenharmony_ci aperture_size = MB(128); 5428c2ecf20Sopenharmony_ci } else { 5438c2ecf20Sopenharmony_ci /* 9xx supports large sizes, just look at the length */ 5448c2ecf20Sopenharmony_ci aperture_size = pci_resource_len(intel_private.pcidev, 2); 5458c2ecf20Sopenharmony_ci } 5468c2ecf20Sopenharmony_ci 5478c2ecf20Sopenharmony_ci return aperture_size >> PAGE_SHIFT; 5488c2ecf20Sopenharmony_ci} 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_cistatic void intel_gtt_teardown_scratch_page(void) 5518c2ecf20Sopenharmony_ci{ 5528c2ecf20Sopenharmony_ci set_pages_wb(intel_private.scratch_page, 1); 5538c2ecf20Sopenharmony_ci if (intel_private.needs_dmar) 5548c2ecf20Sopenharmony_ci pci_unmap_page(intel_private.pcidev, 5558c2ecf20Sopenharmony_ci intel_private.scratch_page_dma, 5568c2ecf20Sopenharmony_ci PAGE_SIZE, PCI_DMA_BIDIRECTIONAL); 5578c2ecf20Sopenharmony_ci __free_page(intel_private.scratch_page); 5588c2ecf20Sopenharmony_ci} 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_cistatic void intel_gtt_cleanup(void) 5618c2ecf20Sopenharmony_ci{ 5628c2ecf20Sopenharmony_ci intel_private.driver->cleanup(); 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_ci iounmap(intel_private.gtt); 5658c2ecf20Sopenharmony_ci iounmap(intel_private.registers); 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_ci intel_gtt_teardown_scratch_page(); 5688c2ecf20Sopenharmony_ci} 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_ci/* Certain Gen5 chipsets require require idling the GPU before 5718c2ecf20Sopenharmony_ci * unmapping anything from the GTT when VT-d is enabled. 5728c2ecf20Sopenharmony_ci */ 5738c2ecf20Sopenharmony_cistatic inline int needs_ilk_vtd_wa(void) 5748c2ecf20Sopenharmony_ci{ 5758c2ecf20Sopenharmony_ci#ifdef CONFIG_INTEL_IOMMU 5768c2ecf20Sopenharmony_ci const unsigned short gpu_devid = intel_private.pcidev->device; 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_ci /* Query intel_iommu to see if we need the workaround. Presumably that 5798c2ecf20Sopenharmony_ci * was loaded first. 5808c2ecf20Sopenharmony_ci */ 5818c2ecf20Sopenharmony_ci if ((gpu_devid == PCI_DEVICE_ID_INTEL_IRONLAKE_D_IG || 5828c2ecf20Sopenharmony_ci gpu_devid == PCI_DEVICE_ID_INTEL_IRONLAKE_M_IG) && 5838c2ecf20Sopenharmony_ci intel_iommu_gfx_mapped) 5848c2ecf20Sopenharmony_ci return 1; 5858c2ecf20Sopenharmony_ci#endif 5868c2ecf20Sopenharmony_ci return 0; 5878c2ecf20Sopenharmony_ci} 5888c2ecf20Sopenharmony_ci 5898c2ecf20Sopenharmony_cistatic bool intel_gtt_can_wc(void) 5908c2ecf20Sopenharmony_ci{ 5918c2ecf20Sopenharmony_ci if (INTEL_GTT_GEN <= 2) 5928c2ecf20Sopenharmony_ci return false; 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_ci if (INTEL_GTT_GEN >= 6) 5958c2ecf20Sopenharmony_ci return false; 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_ci /* Reports of major corruption with ILK vt'd enabled */ 5988c2ecf20Sopenharmony_ci if (needs_ilk_vtd_wa()) 5998c2ecf20Sopenharmony_ci return false; 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_ci return true; 6028c2ecf20Sopenharmony_ci} 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_cistatic int intel_gtt_init(void) 6058c2ecf20Sopenharmony_ci{ 6068c2ecf20Sopenharmony_ci u32 gtt_map_size; 6078c2ecf20Sopenharmony_ci int ret, bar; 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_ci ret = intel_private.driver->setup(); 6108c2ecf20Sopenharmony_ci if (ret != 0) 6118c2ecf20Sopenharmony_ci return ret; 6128c2ecf20Sopenharmony_ci 6138c2ecf20Sopenharmony_ci intel_private.gtt_mappable_entries = intel_gtt_mappable_entries(); 6148c2ecf20Sopenharmony_ci intel_private.gtt_total_entries = intel_gtt_total_entries(); 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_ci /* save the PGETBL reg for resume */ 6178c2ecf20Sopenharmony_ci intel_private.PGETBL_save = 6188c2ecf20Sopenharmony_ci readl(intel_private.registers+I810_PGETBL_CTL) 6198c2ecf20Sopenharmony_ci & ~I810_PGETBL_ENABLED; 6208c2ecf20Sopenharmony_ci /* we only ever restore the register when enabling the PGTBL... */ 6218c2ecf20Sopenharmony_ci if (HAS_PGTBL_EN) 6228c2ecf20Sopenharmony_ci intel_private.PGETBL_save |= I810_PGETBL_ENABLED; 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_ci dev_info(&intel_private.bridge_dev->dev, 6258c2ecf20Sopenharmony_ci "detected gtt size: %dK total, %dK mappable\n", 6268c2ecf20Sopenharmony_ci intel_private.gtt_total_entries * 4, 6278c2ecf20Sopenharmony_ci intel_private.gtt_mappable_entries * 4); 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_ci gtt_map_size = intel_private.gtt_total_entries * 4; 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_ci intel_private.gtt = NULL; 6328c2ecf20Sopenharmony_ci if (intel_gtt_can_wc()) 6338c2ecf20Sopenharmony_ci intel_private.gtt = ioremap_wc(intel_private.gtt_phys_addr, 6348c2ecf20Sopenharmony_ci gtt_map_size); 6358c2ecf20Sopenharmony_ci if (intel_private.gtt == NULL) 6368c2ecf20Sopenharmony_ci intel_private.gtt = ioremap(intel_private.gtt_phys_addr, 6378c2ecf20Sopenharmony_ci gtt_map_size); 6388c2ecf20Sopenharmony_ci if (intel_private.gtt == NULL) { 6398c2ecf20Sopenharmony_ci intel_private.driver->cleanup(); 6408c2ecf20Sopenharmony_ci iounmap(intel_private.registers); 6418c2ecf20Sopenharmony_ci return -ENOMEM; 6428c2ecf20Sopenharmony_ci } 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_AGP_INTEL) 6458c2ecf20Sopenharmony_ci global_cache_flush(); /* FIXME: ? */ 6468c2ecf20Sopenharmony_ci#endif 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_ci intel_private.stolen_size = intel_gtt_stolen_size(); 6498c2ecf20Sopenharmony_ci 6508c2ecf20Sopenharmony_ci intel_private.needs_dmar = USE_PCI_DMA_API && INTEL_GTT_GEN > 2; 6518c2ecf20Sopenharmony_ci 6528c2ecf20Sopenharmony_ci ret = intel_gtt_setup_scratch_page(); 6538c2ecf20Sopenharmony_ci if (ret != 0) { 6548c2ecf20Sopenharmony_ci intel_gtt_cleanup(); 6558c2ecf20Sopenharmony_ci return ret; 6568c2ecf20Sopenharmony_ci } 6578c2ecf20Sopenharmony_ci 6588c2ecf20Sopenharmony_ci if (INTEL_GTT_GEN <= 2) 6598c2ecf20Sopenharmony_ci bar = I810_GMADR_BAR; 6608c2ecf20Sopenharmony_ci else 6618c2ecf20Sopenharmony_ci bar = I915_GMADR_BAR; 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_ci intel_private.gma_bus_addr = pci_bus_address(intel_private.pcidev, bar); 6648c2ecf20Sopenharmony_ci return 0; 6658c2ecf20Sopenharmony_ci} 6668c2ecf20Sopenharmony_ci 6678c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_AGP_INTEL) 6688c2ecf20Sopenharmony_cistatic const struct aper_size_info_fixed intel_fake_agp_sizes[] = { 6698c2ecf20Sopenharmony_ci {32, 8192, 3}, 6708c2ecf20Sopenharmony_ci {64, 16384, 4}, 6718c2ecf20Sopenharmony_ci {128, 32768, 5}, 6728c2ecf20Sopenharmony_ci {256, 65536, 6}, 6738c2ecf20Sopenharmony_ci {512, 131072, 7}, 6748c2ecf20Sopenharmony_ci}; 6758c2ecf20Sopenharmony_ci 6768c2ecf20Sopenharmony_cistatic int intel_fake_agp_fetch_size(void) 6778c2ecf20Sopenharmony_ci{ 6788c2ecf20Sopenharmony_ci int num_sizes = ARRAY_SIZE(intel_fake_agp_sizes); 6798c2ecf20Sopenharmony_ci unsigned int aper_size; 6808c2ecf20Sopenharmony_ci int i; 6818c2ecf20Sopenharmony_ci 6828c2ecf20Sopenharmony_ci aper_size = (intel_private.gtt_mappable_entries << PAGE_SHIFT) / MB(1); 6838c2ecf20Sopenharmony_ci 6848c2ecf20Sopenharmony_ci for (i = 0; i < num_sizes; i++) { 6858c2ecf20Sopenharmony_ci if (aper_size == intel_fake_agp_sizes[i].size) { 6868c2ecf20Sopenharmony_ci agp_bridge->current_size = 6878c2ecf20Sopenharmony_ci (void *) (intel_fake_agp_sizes + i); 6888c2ecf20Sopenharmony_ci return aper_size; 6898c2ecf20Sopenharmony_ci } 6908c2ecf20Sopenharmony_ci } 6918c2ecf20Sopenharmony_ci 6928c2ecf20Sopenharmony_ci return 0; 6938c2ecf20Sopenharmony_ci} 6948c2ecf20Sopenharmony_ci#endif 6958c2ecf20Sopenharmony_ci 6968c2ecf20Sopenharmony_cistatic void i830_cleanup(void) 6978c2ecf20Sopenharmony_ci{ 6988c2ecf20Sopenharmony_ci} 6998c2ecf20Sopenharmony_ci 7008c2ecf20Sopenharmony_ci/* The chipset_flush interface needs to get data that has already been 7018c2ecf20Sopenharmony_ci * flushed out of the CPU all the way out to main memory, because the GPU 7028c2ecf20Sopenharmony_ci * doesn't snoop those buffers. 7038c2ecf20Sopenharmony_ci * 7048c2ecf20Sopenharmony_ci * The 8xx series doesn't have the same lovely interface for flushing the 7058c2ecf20Sopenharmony_ci * chipset write buffers that the later chips do. According to the 865 7068c2ecf20Sopenharmony_ci * specs, it's 64 octwords, or 1KB. So, to get those previous things in 7078c2ecf20Sopenharmony_ci * that buffer out, we just fill 1KB and clflush it out, on the assumption 7088c2ecf20Sopenharmony_ci * that it'll push whatever was in there out. It appears to work. 7098c2ecf20Sopenharmony_ci */ 7108c2ecf20Sopenharmony_cistatic void i830_chipset_flush(void) 7118c2ecf20Sopenharmony_ci{ 7128c2ecf20Sopenharmony_ci unsigned long timeout = jiffies + msecs_to_jiffies(1000); 7138c2ecf20Sopenharmony_ci 7148c2ecf20Sopenharmony_ci /* Forcibly evict everything from the CPU write buffers. 7158c2ecf20Sopenharmony_ci * clflush appears to be insufficient. 7168c2ecf20Sopenharmony_ci */ 7178c2ecf20Sopenharmony_ci wbinvd_on_all_cpus(); 7188c2ecf20Sopenharmony_ci 7198c2ecf20Sopenharmony_ci /* Now we've only seen documents for this magic bit on 855GM, 7208c2ecf20Sopenharmony_ci * we hope it exists for the other gen2 chipsets... 7218c2ecf20Sopenharmony_ci * 7228c2ecf20Sopenharmony_ci * Also works as advertised on my 845G. 7238c2ecf20Sopenharmony_ci */ 7248c2ecf20Sopenharmony_ci writel(readl(intel_private.registers+I830_HIC) | (1<<31), 7258c2ecf20Sopenharmony_ci intel_private.registers+I830_HIC); 7268c2ecf20Sopenharmony_ci 7278c2ecf20Sopenharmony_ci while (readl(intel_private.registers+I830_HIC) & (1<<31)) { 7288c2ecf20Sopenharmony_ci if (time_after(jiffies, timeout)) 7298c2ecf20Sopenharmony_ci break; 7308c2ecf20Sopenharmony_ci 7318c2ecf20Sopenharmony_ci udelay(50); 7328c2ecf20Sopenharmony_ci } 7338c2ecf20Sopenharmony_ci} 7348c2ecf20Sopenharmony_ci 7358c2ecf20Sopenharmony_cistatic void i830_write_entry(dma_addr_t addr, unsigned int entry, 7368c2ecf20Sopenharmony_ci unsigned int flags) 7378c2ecf20Sopenharmony_ci{ 7388c2ecf20Sopenharmony_ci u32 pte_flags = I810_PTE_VALID; 7398c2ecf20Sopenharmony_ci 7408c2ecf20Sopenharmony_ci if (flags == AGP_USER_CACHED_MEMORY) 7418c2ecf20Sopenharmony_ci pte_flags |= I830_PTE_SYSTEM_CACHED; 7428c2ecf20Sopenharmony_ci 7438c2ecf20Sopenharmony_ci writel_relaxed(addr | pte_flags, intel_private.gtt + entry); 7448c2ecf20Sopenharmony_ci} 7458c2ecf20Sopenharmony_ci 7468c2ecf20Sopenharmony_cibool intel_enable_gtt(void) 7478c2ecf20Sopenharmony_ci{ 7488c2ecf20Sopenharmony_ci u8 __iomem *reg; 7498c2ecf20Sopenharmony_ci 7508c2ecf20Sopenharmony_ci if (INTEL_GTT_GEN == 2) { 7518c2ecf20Sopenharmony_ci u16 gmch_ctrl; 7528c2ecf20Sopenharmony_ci 7538c2ecf20Sopenharmony_ci pci_read_config_word(intel_private.bridge_dev, 7548c2ecf20Sopenharmony_ci I830_GMCH_CTRL, &gmch_ctrl); 7558c2ecf20Sopenharmony_ci gmch_ctrl |= I830_GMCH_ENABLED; 7568c2ecf20Sopenharmony_ci pci_write_config_word(intel_private.bridge_dev, 7578c2ecf20Sopenharmony_ci I830_GMCH_CTRL, gmch_ctrl); 7588c2ecf20Sopenharmony_ci 7598c2ecf20Sopenharmony_ci pci_read_config_word(intel_private.bridge_dev, 7608c2ecf20Sopenharmony_ci I830_GMCH_CTRL, &gmch_ctrl); 7618c2ecf20Sopenharmony_ci if ((gmch_ctrl & I830_GMCH_ENABLED) == 0) { 7628c2ecf20Sopenharmony_ci dev_err(&intel_private.pcidev->dev, 7638c2ecf20Sopenharmony_ci "failed to enable the GTT: GMCH_CTRL=%x\n", 7648c2ecf20Sopenharmony_ci gmch_ctrl); 7658c2ecf20Sopenharmony_ci return false; 7668c2ecf20Sopenharmony_ci } 7678c2ecf20Sopenharmony_ci } 7688c2ecf20Sopenharmony_ci 7698c2ecf20Sopenharmony_ci /* On the resume path we may be adjusting the PGTBL value, so 7708c2ecf20Sopenharmony_ci * be paranoid and flush all chipset write buffers... 7718c2ecf20Sopenharmony_ci */ 7728c2ecf20Sopenharmony_ci if (INTEL_GTT_GEN >= 3) 7738c2ecf20Sopenharmony_ci writel(0, intel_private.registers+GFX_FLSH_CNTL); 7748c2ecf20Sopenharmony_ci 7758c2ecf20Sopenharmony_ci reg = intel_private.registers+I810_PGETBL_CTL; 7768c2ecf20Sopenharmony_ci writel(intel_private.PGETBL_save, reg); 7778c2ecf20Sopenharmony_ci if (HAS_PGTBL_EN && (readl(reg) & I810_PGETBL_ENABLED) == 0) { 7788c2ecf20Sopenharmony_ci dev_err(&intel_private.pcidev->dev, 7798c2ecf20Sopenharmony_ci "failed to enable the GTT: PGETBL=%x [expected %x]\n", 7808c2ecf20Sopenharmony_ci readl(reg), intel_private.PGETBL_save); 7818c2ecf20Sopenharmony_ci return false; 7828c2ecf20Sopenharmony_ci } 7838c2ecf20Sopenharmony_ci 7848c2ecf20Sopenharmony_ci if (INTEL_GTT_GEN >= 3) 7858c2ecf20Sopenharmony_ci writel(0, intel_private.registers+GFX_FLSH_CNTL); 7868c2ecf20Sopenharmony_ci 7878c2ecf20Sopenharmony_ci return true; 7888c2ecf20Sopenharmony_ci} 7898c2ecf20Sopenharmony_ciEXPORT_SYMBOL(intel_enable_gtt); 7908c2ecf20Sopenharmony_ci 7918c2ecf20Sopenharmony_cistatic int i830_setup(void) 7928c2ecf20Sopenharmony_ci{ 7938c2ecf20Sopenharmony_ci phys_addr_t reg_addr; 7948c2ecf20Sopenharmony_ci 7958c2ecf20Sopenharmony_ci reg_addr = pci_resource_start(intel_private.pcidev, I810_MMADR_BAR); 7968c2ecf20Sopenharmony_ci 7978c2ecf20Sopenharmony_ci intel_private.registers = ioremap(reg_addr, KB(64)); 7988c2ecf20Sopenharmony_ci if (!intel_private.registers) 7998c2ecf20Sopenharmony_ci return -ENOMEM; 8008c2ecf20Sopenharmony_ci 8018c2ecf20Sopenharmony_ci intel_private.gtt_phys_addr = reg_addr + I810_PTE_BASE; 8028c2ecf20Sopenharmony_ci 8038c2ecf20Sopenharmony_ci return 0; 8048c2ecf20Sopenharmony_ci} 8058c2ecf20Sopenharmony_ci 8068c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_AGP_INTEL) 8078c2ecf20Sopenharmony_cistatic int intel_fake_agp_create_gatt_table(struct agp_bridge_data *bridge) 8088c2ecf20Sopenharmony_ci{ 8098c2ecf20Sopenharmony_ci agp_bridge->gatt_table_real = NULL; 8108c2ecf20Sopenharmony_ci agp_bridge->gatt_table = NULL; 8118c2ecf20Sopenharmony_ci agp_bridge->gatt_bus_addr = 0; 8128c2ecf20Sopenharmony_ci 8138c2ecf20Sopenharmony_ci return 0; 8148c2ecf20Sopenharmony_ci} 8158c2ecf20Sopenharmony_ci 8168c2ecf20Sopenharmony_cistatic int intel_fake_agp_free_gatt_table(struct agp_bridge_data *bridge) 8178c2ecf20Sopenharmony_ci{ 8188c2ecf20Sopenharmony_ci return 0; 8198c2ecf20Sopenharmony_ci} 8208c2ecf20Sopenharmony_ci 8218c2ecf20Sopenharmony_cistatic int intel_fake_agp_configure(void) 8228c2ecf20Sopenharmony_ci{ 8238c2ecf20Sopenharmony_ci if (!intel_enable_gtt()) 8248c2ecf20Sopenharmony_ci return -EIO; 8258c2ecf20Sopenharmony_ci 8268c2ecf20Sopenharmony_ci intel_private.clear_fake_agp = true; 8278c2ecf20Sopenharmony_ci agp_bridge->gart_bus_addr = intel_private.gma_bus_addr; 8288c2ecf20Sopenharmony_ci 8298c2ecf20Sopenharmony_ci return 0; 8308c2ecf20Sopenharmony_ci} 8318c2ecf20Sopenharmony_ci#endif 8328c2ecf20Sopenharmony_ci 8338c2ecf20Sopenharmony_cistatic bool i830_check_flags(unsigned int flags) 8348c2ecf20Sopenharmony_ci{ 8358c2ecf20Sopenharmony_ci switch (flags) { 8368c2ecf20Sopenharmony_ci case 0: 8378c2ecf20Sopenharmony_ci case AGP_PHYS_MEMORY: 8388c2ecf20Sopenharmony_ci case AGP_USER_CACHED_MEMORY: 8398c2ecf20Sopenharmony_ci case AGP_USER_MEMORY: 8408c2ecf20Sopenharmony_ci return true; 8418c2ecf20Sopenharmony_ci } 8428c2ecf20Sopenharmony_ci 8438c2ecf20Sopenharmony_ci return false; 8448c2ecf20Sopenharmony_ci} 8458c2ecf20Sopenharmony_ci 8468c2ecf20Sopenharmony_civoid intel_gtt_insert_page(dma_addr_t addr, 8478c2ecf20Sopenharmony_ci unsigned int pg, 8488c2ecf20Sopenharmony_ci unsigned int flags) 8498c2ecf20Sopenharmony_ci{ 8508c2ecf20Sopenharmony_ci intel_private.driver->write_entry(addr, pg, flags); 8518c2ecf20Sopenharmony_ci readl(intel_private.gtt + pg); 8528c2ecf20Sopenharmony_ci if (intel_private.driver->chipset_flush) 8538c2ecf20Sopenharmony_ci intel_private.driver->chipset_flush(); 8548c2ecf20Sopenharmony_ci} 8558c2ecf20Sopenharmony_ciEXPORT_SYMBOL(intel_gtt_insert_page); 8568c2ecf20Sopenharmony_ci 8578c2ecf20Sopenharmony_civoid intel_gtt_insert_sg_entries(struct sg_table *st, 8588c2ecf20Sopenharmony_ci unsigned int pg_start, 8598c2ecf20Sopenharmony_ci unsigned int flags) 8608c2ecf20Sopenharmony_ci{ 8618c2ecf20Sopenharmony_ci struct scatterlist *sg; 8628c2ecf20Sopenharmony_ci unsigned int len, m; 8638c2ecf20Sopenharmony_ci int i, j; 8648c2ecf20Sopenharmony_ci 8658c2ecf20Sopenharmony_ci j = pg_start; 8668c2ecf20Sopenharmony_ci 8678c2ecf20Sopenharmony_ci /* sg may merge pages, but we have to separate 8688c2ecf20Sopenharmony_ci * per-page addr for GTT */ 8698c2ecf20Sopenharmony_ci for_each_sg(st->sgl, sg, st->nents, i) { 8708c2ecf20Sopenharmony_ci len = sg_dma_len(sg) >> PAGE_SHIFT; 8718c2ecf20Sopenharmony_ci for (m = 0; m < len; m++) { 8728c2ecf20Sopenharmony_ci dma_addr_t addr = sg_dma_address(sg) + (m << PAGE_SHIFT); 8738c2ecf20Sopenharmony_ci intel_private.driver->write_entry(addr, j, flags); 8748c2ecf20Sopenharmony_ci j++; 8758c2ecf20Sopenharmony_ci } 8768c2ecf20Sopenharmony_ci } 8778c2ecf20Sopenharmony_ci readl(intel_private.gtt + j - 1); 8788c2ecf20Sopenharmony_ci if (intel_private.driver->chipset_flush) 8798c2ecf20Sopenharmony_ci intel_private.driver->chipset_flush(); 8808c2ecf20Sopenharmony_ci} 8818c2ecf20Sopenharmony_ciEXPORT_SYMBOL(intel_gtt_insert_sg_entries); 8828c2ecf20Sopenharmony_ci 8838c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_AGP_INTEL) 8848c2ecf20Sopenharmony_cistatic void intel_gtt_insert_pages(unsigned int first_entry, 8858c2ecf20Sopenharmony_ci unsigned int num_entries, 8868c2ecf20Sopenharmony_ci struct page **pages, 8878c2ecf20Sopenharmony_ci unsigned int flags) 8888c2ecf20Sopenharmony_ci{ 8898c2ecf20Sopenharmony_ci int i, j; 8908c2ecf20Sopenharmony_ci 8918c2ecf20Sopenharmony_ci for (i = 0, j = first_entry; i < num_entries; i++, j++) { 8928c2ecf20Sopenharmony_ci dma_addr_t addr = page_to_phys(pages[i]); 8938c2ecf20Sopenharmony_ci intel_private.driver->write_entry(addr, 8948c2ecf20Sopenharmony_ci j, flags); 8958c2ecf20Sopenharmony_ci } 8968c2ecf20Sopenharmony_ci wmb(); 8978c2ecf20Sopenharmony_ci} 8988c2ecf20Sopenharmony_ci 8998c2ecf20Sopenharmony_cistatic int intel_fake_agp_insert_entries(struct agp_memory *mem, 9008c2ecf20Sopenharmony_ci off_t pg_start, int type) 9018c2ecf20Sopenharmony_ci{ 9028c2ecf20Sopenharmony_ci int ret = -EINVAL; 9038c2ecf20Sopenharmony_ci 9048c2ecf20Sopenharmony_ci if (intel_private.clear_fake_agp) { 9058c2ecf20Sopenharmony_ci int start = intel_private.stolen_size / PAGE_SIZE; 9068c2ecf20Sopenharmony_ci int end = intel_private.gtt_mappable_entries; 9078c2ecf20Sopenharmony_ci intel_gtt_clear_range(start, end - start); 9088c2ecf20Sopenharmony_ci intel_private.clear_fake_agp = false; 9098c2ecf20Sopenharmony_ci } 9108c2ecf20Sopenharmony_ci 9118c2ecf20Sopenharmony_ci if (INTEL_GTT_GEN == 1 && type == AGP_DCACHE_MEMORY) 9128c2ecf20Sopenharmony_ci return i810_insert_dcache_entries(mem, pg_start, type); 9138c2ecf20Sopenharmony_ci 9148c2ecf20Sopenharmony_ci if (mem->page_count == 0) 9158c2ecf20Sopenharmony_ci goto out; 9168c2ecf20Sopenharmony_ci 9178c2ecf20Sopenharmony_ci if (pg_start + mem->page_count > intel_private.gtt_total_entries) 9188c2ecf20Sopenharmony_ci goto out_err; 9198c2ecf20Sopenharmony_ci 9208c2ecf20Sopenharmony_ci if (type != mem->type) 9218c2ecf20Sopenharmony_ci goto out_err; 9228c2ecf20Sopenharmony_ci 9238c2ecf20Sopenharmony_ci if (!intel_private.driver->check_flags(type)) 9248c2ecf20Sopenharmony_ci goto out_err; 9258c2ecf20Sopenharmony_ci 9268c2ecf20Sopenharmony_ci if (!mem->is_flushed) 9278c2ecf20Sopenharmony_ci global_cache_flush(); 9288c2ecf20Sopenharmony_ci 9298c2ecf20Sopenharmony_ci if (intel_private.needs_dmar) { 9308c2ecf20Sopenharmony_ci struct sg_table st; 9318c2ecf20Sopenharmony_ci 9328c2ecf20Sopenharmony_ci ret = intel_gtt_map_memory(mem->pages, mem->page_count, &st); 9338c2ecf20Sopenharmony_ci if (ret != 0) 9348c2ecf20Sopenharmony_ci return ret; 9358c2ecf20Sopenharmony_ci 9368c2ecf20Sopenharmony_ci intel_gtt_insert_sg_entries(&st, pg_start, type); 9378c2ecf20Sopenharmony_ci mem->sg_list = st.sgl; 9388c2ecf20Sopenharmony_ci mem->num_sg = st.nents; 9398c2ecf20Sopenharmony_ci } else 9408c2ecf20Sopenharmony_ci intel_gtt_insert_pages(pg_start, mem->page_count, mem->pages, 9418c2ecf20Sopenharmony_ci type); 9428c2ecf20Sopenharmony_ci 9438c2ecf20Sopenharmony_ciout: 9448c2ecf20Sopenharmony_ci ret = 0; 9458c2ecf20Sopenharmony_ciout_err: 9468c2ecf20Sopenharmony_ci mem->is_flushed = true; 9478c2ecf20Sopenharmony_ci return ret; 9488c2ecf20Sopenharmony_ci} 9498c2ecf20Sopenharmony_ci#endif 9508c2ecf20Sopenharmony_ci 9518c2ecf20Sopenharmony_civoid intel_gtt_clear_range(unsigned int first_entry, unsigned int num_entries) 9528c2ecf20Sopenharmony_ci{ 9538c2ecf20Sopenharmony_ci unsigned int i; 9548c2ecf20Sopenharmony_ci 9558c2ecf20Sopenharmony_ci for (i = first_entry; i < (first_entry + num_entries); i++) { 9568c2ecf20Sopenharmony_ci intel_private.driver->write_entry(intel_private.scratch_page_dma, 9578c2ecf20Sopenharmony_ci i, 0); 9588c2ecf20Sopenharmony_ci } 9598c2ecf20Sopenharmony_ci wmb(); 9608c2ecf20Sopenharmony_ci} 9618c2ecf20Sopenharmony_ciEXPORT_SYMBOL(intel_gtt_clear_range); 9628c2ecf20Sopenharmony_ci 9638c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_AGP_INTEL) 9648c2ecf20Sopenharmony_cistatic int intel_fake_agp_remove_entries(struct agp_memory *mem, 9658c2ecf20Sopenharmony_ci off_t pg_start, int type) 9668c2ecf20Sopenharmony_ci{ 9678c2ecf20Sopenharmony_ci if (mem->page_count == 0) 9688c2ecf20Sopenharmony_ci return 0; 9698c2ecf20Sopenharmony_ci 9708c2ecf20Sopenharmony_ci intel_gtt_clear_range(pg_start, mem->page_count); 9718c2ecf20Sopenharmony_ci 9728c2ecf20Sopenharmony_ci if (intel_private.needs_dmar) { 9738c2ecf20Sopenharmony_ci intel_gtt_unmap_memory(mem->sg_list, mem->num_sg); 9748c2ecf20Sopenharmony_ci mem->sg_list = NULL; 9758c2ecf20Sopenharmony_ci mem->num_sg = 0; 9768c2ecf20Sopenharmony_ci } 9778c2ecf20Sopenharmony_ci 9788c2ecf20Sopenharmony_ci return 0; 9798c2ecf20Sopenharmony_ci} 9808c2ecf20Sopenharmony_ci 9818c2ecf20Sopenharmony_cistatic struct agp_memory *intel_fake_agp_alloc_by_type(size_t pg_count, 9828c2ecf20Sopenharmony_ci int type) 9838c2ecf20Sopenharmony_ci{ 9848c2ecf20Sopenharmony_ci struct agp_memory *new; 9858c2ecf20Sopenharmony_ci 9868c2ecf20Sopenharmony_ci if (type == AGP_DCACHE_MEMORY && INTEL_GTT_GEN == 1) { 9878c2ecf20Sopenharmony_ci if (pg_count != intel_private.num_dcache_entries) 9888c2ecf20Sopenharmony_ci return NULL; 9898c2ecf20Sopenharmony_ci 9908c2ecf20Sopenharmony_ci new = agp_create_memory(1); 9918c2ecf20Sopenharmony_ci if (new == NULL) 9928c2ecf20Sopenharmony_ci return NULL; 9938c2ecf20Sopenharmony_ci 9948c2ecf20Sopenharmony_ci new->type = AGP_DCACHE_MEMORY; 9958c2ecf20Sopenharmony_ci new->page_count = pg_count; 9968c2ecf20Sopenharmony_ci new->num_scratch_pages = 0; 9978c2ecf20Sopenharmony_ci agp_free_page_array(new); 9988c2ecf20Sopenharmony_ci return new; 9998c2ecf20Sopenharmony_ci } 10008c2ecf20Sopenharmony_ci if (type == AGP_PHYS_MEMORY) 10018c2ecf20Sopenharmony_ci return alloc_agpphysmem_i8xx(pg_count, type); 10028c2ecf20Sopenharmony_ci /* always return NULL for other allocation types for now */ 10038c2ecf20Sopenharmony_ci return NULL; 10048c2ecf20Sopenharmony_ci} 10058c2ecf20Sopenharmony_ci#endif 10068c2ecf20Sopenharmony_ci 10078c2ecf20Sopenharmony_cistatic int intel_alloc_chipset_flush_resource(void) 10088c2ecf20Sopenharmony_ci{ 10098c2ecf20Sopenharmony_ci int ret; 10108c2ecf20Sopenharmony_ci ret = pci_bus_alloc_resource(intel_private.bridge_dev->bus, &intel_private.ifp_resource, PAGE_SIZE, 10118c2ecf20Sopenharmony_ci PAGE_SIZE, PCIBIOS_MIN_MEM, 0, 10128c2ecf20Sopenharmony_ci pcibios_align_resource, intel_private.bridge_dev); 10138c2ecf20Sopenharmony_ci 10148c2ecf20Sopenharmony_ci return ret; 10158c2ecf20Sopenharmony_ci} 10168c2ecf20Sopenharmony_ci 10178c2ecf20Sopenharmony_cistatic void intel_i915_setup_chipset_flush(void) 10188c2ecf20Sopenharmony_ci{ 10198c2ecf20Sopenharmony_ci int ret; 10208c2ecf20Sopenharmony_ci u32 temp; 10218c2ecf20Sopenharmony_ci 10228c2ecf20Sopenharmony_ci pci_read_config_dword(intel_private.bridge_dev, I915_IFPADDR, &temp); 10238c2ecf20Sopenharmony_ci if (!(temp & 0x1)) { 10248c2ecf20Sopenharmony_ci intel_alloc_chipset_flush_resource(); 10258c2ecf20Sopenharmony_ci intel_private.resource_valid = 1; 10268c2ecf20Sopenharmony_ci pci_write_config_dword(intel_private.bridge_dev, I915_IFPADDR, (intel_private.ifp_resource.start & 0xffffffff) | 0x1); 10278c2ecf20Sopenharmony_ci } else { 10288c2ecf20Sopenharmony_ci temp &= ~1; 10298c2ecf20Sopenharmony_ci 10308c2ecf20Sopenharmony_ci intel_private.resource_valid = 1; 10318c2ecf20Sopenharmony_ci intel_private.ifp_resource.start = temp; 10328c2ecf20Sopenharmony_ci intel_private.ifp_resource.end = temp + PAGE_SIZE; 10338c2ecf20Sopenharmony_ci ret = request_resource(&iomem_resource, &intel_private.ifp_resource); 10348c2ecf20Sopenharmony_ci /* some BIOSes reserve this area in a pnp some don't */ 10358c2ecf20Sopenharmony_ci if (ret) 10368c2ecf20Sopenharmony_ci intel_private.resource_valid = 0; 10378c2ecf20Sopenharmony_ci } 10388c2ecf20Sopenharmony_ci} 10398c2ecf20Sopenharmony_ci 10408c2ecf20Sopenharmony_cistatic void intel_i965_g33_setup_chipset_flush(void) 10418c2ecf20Sopenharmony_ci{ 10428c2ecf20Sopenharmony_ci u32 temp_hi, temp_lo; 10438c2ecf20Sopenharmony_ci int ret; 10448c2ecf20Sopenharmony_ci 10458c2ecf20Sopenharmony_ci pci_read_config_dword(intel_private.bridge_dev, I965_IFPADDR + 4, &temp_hi); 10468c2ecf20Sopenharmony_ci pci_read_config_dword(intel_private.bridge_dev, I965_IFPADDR, &temp_lo); 10478c2ecf20Sopenharmony_ci 10488c2ecf20Sopenharmony_ci if (!(temp_lo & 0x1)) { 10498c2ecf20Sopenharmony_ci 10508c2ecf20Sopenharmony_ci intel_alloc_chipset_flush_resource(); 10518c2ecf20Sopenharmony_ci 10528c2ecf20Sopenharmony_ci intel_private.resource_valid = 1; 10538c2ecf20Sopenharmony_ci pci_write_config_dword(intel_private.bridge_dev, I965_IFPADDR + 4, 10548c2ecf20Sopenharmony_ci upper_32_bits(intel_private.ifp_resource.start)); 10558c2ecf20Sopenharmony_ci pci_write_config_dword(intel_private.bridge_dev, I965_IFPADDR, (intel_private.ifp_resource.start & 0xffffffff) | 0x1); 10568c2ecf20Sopenharmony_ci } else { 10578c2ecf20Sopenharmony_ci u64 l64; 10588c2ecf20Sopenharmony_ci 10598c2ecf20Sopenharmony_ci temp_lo &= ~0x1; 10608c2ecf20Sopenharmony_ci l64 = ((u64)temp_hi << 32) | temp_lo; 10618c2ecf20Sopenharmony_ci 10628c2ecf20Sopenharmony_ci intel_private.resource_valid = 1; 10638c2ecf20Sopenharmony_ci intel_private.ifp_resource.start = l64; 10648c2ecf20Sopenharmony_ci intel_private.ifp_resource.end = l64 + PAGE_SIZE; 10658c2ecf20Sopenharmony_ci ret = request_resource(&iomem_resource, &intel_private.ifp_resource); 10668c2ecf20Sopenharmony_ci /* some BIOSes reserve this area in a pnp some don't */ 10678c2ecf20Sopenharmony_ci if (ret) 10688c2ecf20Sopenharmony_ci intel_private.resource_valid = 0; 10698c2ecf20Sopenharmony_ci } 10708c2ecf20Sopenharmony_ci} 10718c2ecf20Sopenharmony_ci 10728c2ecf20Sopenharmony_cistatic void intel_i9xx_setup_flush(void) 10738c2ecf20Sopenharmony_ci{ 10748c2ecf20Sopenharmony_ci /* return if already configured */ 10758c2ecf20Sopenharmony_ci if (intel_private.ifp_resource.start) 10768c2ecf20Sopenharmony_ci return; 10778c2ecf20Sopenharmony_ci 10788c2ecf20Sopenharmony_ci if (INTEL_GTT_GEN == 6) 10798c2ecf20Sopenharmony_ci return; 10808c2ecf20Sopenharmony_ci 10818c2ecf20Sopenharmony_ci /* setup a resource for this object */ 10828c2ecf20Sopenharmony_ci intel_private.ifp_resource.name = "Intel Flush Page"; 10838c2ecf20Sopenharmony_ci intel_private.ifp_resource.flags = IORESOURCE_MEM; 10848c2ecf20Sopenharmony_ci 10858c2ecf20Sopenharmony_ci /* Setup chipset flush for 915 */ 10868c2ecf20Sopenharmony_ci if (IS_G33 || INTEL_GTT_GEN >= 4) { 10878c2ecf20Sopenharmony_ci intel_i965_g33_setup_chipset_flush(); 10888c2ecf20Sopenharmony_ci } else { 10898c2ecf20Sopenharmony_ci intel_i915_setup_chipset_flush(); 10908c2ecf20Sopenharmony_ci } 10918c2ecf20Sopenharmony_ci 10928c2ecf20Sopenharmony_ci if (intel_private.ifp_resource.start) 10938c2ecf20Sopenharmony_ci intel_private.i9xx_flush_page = ioremap(intel_private.ifp_resource.start, PAGE_SIZE); 10948c2ecf20Sopenharmony_ci if (!intel_private.i9xx_flush_page) 10958c2ecf20Sopenharmony_ci dev_err(&intel_private.pcidev->dev, 10968c2ecf20Sopenharmony_ci "can't ioremap flush page - no chipset flushing\n"); 10978c2ecf20Sopenharmony_ci} 10988c2ecf20Sopenharmony_ci 10998c2ecf20Sopenharmony_cistatic void i9xx_cleanup(void) 11008c2ecf20Sopenharmony_ci{ 11018c2ecf20Sopenharmony_ci if (intel_private.i9xx_flush_page) 11028c2ecf20Sopenharmony_ci iounmap(intel_private.i9xx_flush_page); 11038c2ecf20Sopenharmony_ci if (intel_private.resource_valid) 11048c2ecf20Sopenharmony_ci release_resource(&intel_private.ifp_resource); 11058c2ecf20Sopenharmony_ci intel_private.ifp_resource.start = 0; 11068c2ecf20Sopenharmony_ci intel_private.resource_valid = 0; 11078c2ecf20Sopenharmony_ci} 11088c2ecf20Sopenharmony_ci 11098c2ecf20Sopenharmony_cistatic void i9xx_chipset_flush(void) 11108c2ecf20Sopenharmony_ci{ 11118c2ecf20Sopenharmony_ci wmb(); 11128c2ecf20Sopenharmony_ci if (intel_private.i9xx_flush_page) 11138c2ecf20Sopenharmony_ci writel(1, intel_private.i9xx_flush_page); 11148c2ecf20Sopenharmony_ci} 11158c2ecf20Sopenharmony_ci 11168c2ecf20Sopenharmony_cistatic void i965_write_entry(dma_addr_t addr, 11178c2ecf20Sopenharmony_ci unsigned int entry, 11188c2ecf20Sopenharmony_ci unsigned int flags) 11198c2ecf20Sopenharmony_ci{ 11208c2ecf20Sopenharmony_ci u32 pte_flags; 11218c2ecf20Sopenharmony_ci 11228c2ecf20Sopenharmony_ci pte_flags = I810_PTE_VALID; 11238c2ecf20Sopenharmony_ci if (flags == AGP_USER_CACHED_MEMORY) 11248c2ecf20Sopenharmony_ci pte_flags |= I830_PTE_SYSTEM_CACHED; 11258c2ecf20Sopenharmony_ci 11268c2ecf20Sopenharmony_ci /* Shift high bits down */ 11278c2ecf20Sopenharmony_ci addr |= (addr >> 28) & 0xf0; 11288c2ecf20Sopenharmony_ci writel_relaxed(addr | pte_flags, intel_private.gtt + entry); 11298c2ecf20Sopenharmony_ci} 11308c2ecf20Sopenharmony_ci 11318c2ecf20Sopenharmony_cistatic int i9xx_setup(void) 11328c2ecf20Sopenharmony_ci{ 11338c2ecf20Sopenharmony_ci phys_addr_t reg_addr; 11348c2ecf20Sopenharmony_ci int size = KB(512); 11358c2ecf20Sopenharmony_ci 11368c2ecf20Sopenharmony_ci reg_addr = pci_resource_start(intel_private.pcidev, I915_MMADR_BAR); 11378c2ecf20Sopenharmony_ci 11388c2ecf20Sopenharmony_ci intel_private.registers = ioremap(reg_addr, size); 11398c2ecf20Sopenharmony_ci if (!intel_private.registers) 11408c2ecf20Sopenharmony_ci return -ENOMEM; 11418c2ecf20Sopenharmony_ci 11428c2ecf20Sopenharmony_ci switch (INTEL_GTT_GEN) { 11438c2ecf20Sopenharmony_ci case 3: 11448c2ecf20Sopenharmony_ci intel_private.gtt_phys_addr = 11458c2ecf20Sopenharmony_ci pci_resource_start(intel_private.pcidev, I915_PTE_BAR); 11468c2ecf20Sopenharmony_ci break; 11478c2ecf20Sopenharmony_ci case 5: 11488c2ecf20Sopenharmony_ci intel_private.gtt_phys_addr = reg_addr + MB(2); 11498c2ecf20Sopenharmony_ci break; 11508c2ecf20Sopenharmony_ci default: 11518c2ecf20Sopenharmony_ci intel_private.gtt_phys_addr = reg_addr + KB(512); 11528c2ecf20Sopenharmony_ci break; 11538c2ecf20Sopenharmony_ci } 11548c2ecf20Sopenharmony_ci 11558c2ecf20Sopenharmony_ci intel_i9xx_setup_flush(); 11568c2ecf20Sopenharmony_ci 11578c2ecf20Sopenharmony_ci return 0; 11588c2ecf20Sopenharmony_ci} 11598c2ecf20Sopenharmony_ci 11608c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_AGP_INTEL) 11618c2ecf20Sopenharmony_cistatic const struct agp_bridge_driver intel_fake_agp_driver = { 11628c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 11638c2ecf20Sopenharmony_ci .size_type = FIXED_APER_SIZE, 11648c2ecf20Sopenharmony_ci .aperture_sizes = intel_fake_agp_sizes, 11658c2ecf20Sopenharmony_ci .num_aperture_sizes = ARRAY_SIZE(intel_fake_agp_sizes), 11668c2ecf20Sopenharmony_ci .configure = intel_fake_agp_configure, 11678c2ecf20Sopenharmony_ci .fetch_size = intel_fake_agp_fetch_size, 11688c2ecf20Sopenharmony_ci .cleanup = intel_gtt_cleanup, 11698c2ecf20Sopenharmony_ci .agp_enable = intel_fake_agp_enable, 11708c2ecf20Sopenharmony_ci .cache_flush = global_cache_flush, 11718c2ecf20Sopenharmony_ci .create_gatt_table = intel_fake_agp_create_gatt_table, 11728c2ecf20Sopenharmony_ci .free_gatt_table = intel_fake_agp_free_gatt_table, 11738c2ecf20Sopenharmony_ci .insert_memory = intel_fake_agp_insert_entries, 11748c2ecf20Sopenharmony_ci .remove_memory = intel_fake_agp_remove_entries, 11758c2ecf20Sopenharmony_ci .alloc_by_type = intel_fake_agp_alloc_by_type, 11768c2ecf20Sopenharmony_ci .free_by_type = intel_i810_free_by_type, 11778c2ecf20Sopenharmony_ci .agp_alloc_page = agp_generic_alloc_page, 11788c2ecf20Sopenharmony_ci .agp_alloc_pages = agp_generic_alloc_pages, 11798c2ecf20Sopenharmony_ci .agp_destroy_page = agp_generic_destroy_page, 11808c2ecf20Sopenharmony_ci .agp_destroy_pages = agp_generic_destroy_pages, 11818c2ecf20Sopenharmony_ci}; 11828c2ecf20Sopenharmony_ci#endif 11838c2ecf20Sopenharmony_ci 11848c2ecf20Sopenharmony_cistatic const struct intel_gtt_driver i81x_gtt_driver = { 11858c2ecf20Sopenharmony_ci .gen = 1, 11868c2ecf20Sopenharmony_ci .has_pgtbl_enable = 1, 11878c2ecf20Sopenharmony_ci .dma_mask_size = 32, 11888c2ecf20Sopenharmony_ci .setup = i810_setup, 11898c2ecf20Sopenharmony_ci .cleanup = i810_cleanup, 11908c2ecf20Sopenharmony_ci .check_flags = i830_check_flags, 11918c2ecf20Sopenharmony_ci .write_entry = i810_write_entry, 11928c2ecf20Sopenharmony_ci}; 11938c2ecf20Sopenharmony_cistatic const struct intel_gtt_driver i8xx_gtt_driver = { 11948c2ecf20Sopenharmony_ci .gen = 2, 11958c2ecf20Sopenharmony_ci .has_pgtbl_enable = 1, 11968c2ecf20Sopenharmony_ci .setup = i830_setup, 11978c2ecf20Sopenharmony_ci .cleanup = i830_cleanup, 11988c2ecf20Sopenharmony_ci .write_entry = i830_write_entry, 11998c2ecf20Sopenharmony_ci .dma_mask_size = 32, 12008c2ecf20Sopenharmony_ci .check_flags = i830_check_flags, 12018c2ecf20Sopenharmony_ci .chipset_flush = i830_chipset_flush, 12028c2ecf20Sopenharmony_ci}; 12038c2ecf20Sopenharmony_cistatic const struct intel_gtt_driver i915_gtt_driver = { 12048c2ecf20Sopenharmony_ci .gen = 3, 12058c2ecf20Sopenharmony_ci .has_pgtbl_enable = 1, 12068c2ecf20Sopenharmony_ci .setup = i9xx_setup, 12078c2ecf20Sopenharmony_ci .cleanup = i9xx_cleanup, 12088c2ecf20Sopenharmony_ci /* i945 is the last gpu to need phys mem (for overlay and cursors). */ 12098c2ecf20Sopenharmony_ci .write_entry = i830_write_entry, 12108c2ecf20Sopenharmony_ci .dma_mask_size = 32, 12118c2ecf20Sopenharmony_ci .check_flags = i830_check_flags, 12128c2ecf20Sopenharmony_ci .chipset_flush = i9xx_chipset_flush, 12138c2ecf20Sopenharmony_ci}; 12148c2ecf20Sopenharmony_cistatic const struct intel_gtt_driver g33_gtt_driver = { 12158c2ecf20Sopenharmony_ci .gen = 3, 12168c2ecf20Sopenharmony_ci .is_g33 = 1, 12178c2ecf20Sopenharmony_ci .setup = i9xx_setup, 12188c2ecf20Sopenharmony_ci .cleanup = i9xx_cleanup, 12198c2ecf20Sopenharmony_ci .write_entry = i965_write_entry, 12208c2ecf20Sopenharmony_ci .dma_mask_size = 36, 12218c2ecf20Sopenharmony_ci .check_flags = i830_check_flags, 12228c2ecf20Sopenharmony_ci .chipset_flush = i9xx_chipset_flush, 12238c2ecf20Sopenharmony_ci}; 12248c2ecf20Sopenharmony_cistatic const struct intel_gtt_driver pineview_gtt_driver = { 12258c2ecf20Sopenharmony_ci .gen = 3, 12268c2ecf20Sopenharmony_ci .is_pineview = 1, .is_g33 = 1, 12278c2ecf20Sopenharmony_ci .setup = i9xx_setup, 12288c2ecf20Sopenharmony_ci .cleanup = i9xx_cleanup, 12298c2ecf20Sopenharmony_ci .write_entry = i965_write_entry, 12308c2ecf20Sopenharmony_ci .dma_mask_size = 36, 12318c2ecf20Sopenharmony_ci .check_flags = i830_check_flags, 12328c2ecf20Sopenharmony_ci .chipset_flush = i9xx_chipset_flush, 12338c2ecf20Sopenharmony_ci}; 12348c2ecf20Sopenharmony_cistatic const struct intel_gtt_driver i965_gtt_driver = { 12358c2ecf20Sopenharmony_ci .gen = 4, 12368c2ecf20Sopenharmony_ci .has_pgtbl_enable = 1, 12378c2ecf20Sopenharmony_ci .setup = i9xx_setup, 12388c2ecf20Sopenharmony_ci .cleanup = i9xx_cleanup, 12398c2ecf20Sopenharmony_ci .write_entry = i965_write_entry, 12408c2ecf20Sopenharmony_ci .dma_mask_size = 36, 12418c2ecf20Sopenharmony_ci .check_flags = i830_check_flags, 12428c2ecf20Sopenharmony_ci .chipset_flush = i9xx_chipset_flush, 12438c2ecf20Sopenharmony_ci}; 12448c2ecf20Sopenharmony_cistatic const struct intel_gtt_driver g4x_gtt_driver = { 12458c2ecf20Sopenharmony_ci .gen = 5, 12468c2ecf20Sopenharmony_ci .setup = i9xx_setup, 12478c2ecf20Sopenharmony_ci .cleanup = i9xx_cleanup, 12488c2ecf20Sopenharmony_ci .write_entry = i965_write_entry, 12498c2ecf20Sopenharmony_ci .dma_mask_size = 36, 12508c2ecf20Sopenharmony_ci .check_flags = i830_check_flags, 12518c2ecf20Sopenharmony_ci .chipset_flush = i9xx_chipset_flush, 12528c2ecf20Sopenharmony_ci}; 12538c2ecf20Sopenharmony_cistatic const struct intel_gtt_driver ironlake_gtt_driver = { 12548c2ecf20Sopenharmony_ci .gen = 5, 12558c2ecf20Sopenharmony_ci .is_ironlake = 1, 12568c2ecf20Sopenharmony_ci .setup = i9xx_setup, 12578c2ecf20Sopenharmony_ci .cleanup = i9xx_cleanup, 12588c2ecf20Sopenharmony_ci .write_entry = i965_write_entry, 12598c2ecf20Sopenharmony_ci .dma_mask_size = 36, 12608c2ecf20Sopenharmony_ci .check_flags = i830_check_flags, 12618c2ecf20Sopenharmony_ci .chipset_flush = i9xx_chipset_flush, 12628c2ecf20Sopenharmony_ci}; 12638c2ecf20Sopenharmony_ci 12648c2ecf20Sopenharmony_ci/* Table to describe Intel GMCH and AGP/PCIE GART drivers. At least one of 12658c2ecf20Sopenharmony_ci * driver and gmch_driver must be non-null, and find_gmch will determine 12668c2ecf20Sopenharmony_ci * which one should be used if a gmch_chip_id is present. 12678c2ecf20Sopenharmony_ci */ 12688c2ecf20Sopenharmony_cistatic const struct intel_gtt_driver_description { 12698c2ecf20Sopenharmony_ci unsigned int gmch_chip_id; 12708c2ecf20Sopenharmony_ci char *name; 12718c2ecf20Sopenharmony_ci const struct intel_gtt_driver *gtt_driver; 12728c2ecf20Sopenharmony_ci} intel_gtt_chipsets[] = { 12738c2ecf20Sopenharmony_ci { PCI_DEVICE_ID_INTEL_82810_IG1, "i810", 12748c2ecf20Sopenharmony_ci &i81x_gtt_driver}, 12758c2ecf20Sopenharmony_ci { PCI_DEVICE_ID_INTEL_82810_IG3, "i810", 12768c2ecf20Sopenharmony_ci &i81x_gtt_driver}, 12778c2ecf20Sopenharmony_ci { PCI_DEVICE_ID_INTEL_82810E_IG, "i810", 12788c2ecf20Sopenharmony_ci &i81x_gtt_driver}, 12798c2ecf20Sopenharmony_ci { PCI_DEVICE_ID_INTEL_82815_CGC, "i815", 12808c2ecf20Sopenharmony_ci &i81x_gtt_driver}, 12818c2ecf20Sopenharmony_ci { PCI_DEVICE_ID_INTEL_82830_CGC, "830M", 12828c2ecf20Sopenharmony_ci &i8xx_gtt_driver}, 12838c2ecf20Sopenharmony_ci { PCI_DEVICE_ID_INTEL_82845G_IG, "845G", 12848c2ecf20Sopenharmony_ci &i8xx_gtt_driver}, 12858c2ecf20Sopenharmony_ci { PCI_DEVICE_ID_INTEL_82854_IG, "854", 12868c2ecf20Sopenharmony_ci &i8xx_gtt_driver}, 12878c2ecf20Sopenharmony_ci { PCI_DEVICE_ID_INTEL_82855GM_IG, "855GM", 12888c2ecf20Sopenharmony_ci &i8xx_gtt_driver}, 12898c2ecf20Sopenharmony_ci { PCI_DEVICE_ID_INTEL_82865_IG, "865", 12908c2ecf20Sopenharmony_ci &i8xx_gtt_driver}, 12918c2ecf20Sopenharmony_ci { PCI_DEVICE_ID_INTEL_E7221_IG, "E7221 (i915)", 12928c2ecf20Sopenharmony_ci &i915_gtt_driver }, 12938c2ecf20Sopenharmony_ci { PCI_DEVICE_ID_INTEL_82915G_IG, "915G", 12948c2ecf20Sopenharmony_ci &i915_gtt_driver }, 12958c2ecf20Sopenharmony_ci { PCI_DEVICE_ID_INTEL_82915GM_IG, "915GM", 12968c2ecf20Sopenharmony_ci &i915_gtt_driver }, 12978c2ecf20Sopenharmony_ci { PCI_DEVICE_ID_INTEL_82945G_IG, "945G", 12988c2ecf20Sopenharmony_ci &i915_gtt_driver }, 12998c2ecf20Sopenharmony_ci { PCI_DEVICE_ID_INTEL_82945GM_IG, "945GM", 13008c2ecf20Sopenharmony_ci &i915_gtt_driver }, 13018c2ecf20Sopenharmony_ci { PCI_DEVICE_ID_INTEL_82945GME_IG, "945GME", 13028c2ecf20Sopenharmony_ci &i915_gtt_driver }, 13038c2ecf20Sopenharmony_ci { PCI_DEVICE_ID_INTEL_82946GZ_IG, "946GZ", 13048c2ecf20Sopenharmony_ci &i965_gtt_driver }, 13058c2ecf20Sopenharmony_ci { PCI_DEVICE_ID_INTEL_82G35_IG, "G35", 13068c2ecf20Sopenharmony_ci &i965_gtt_driver }, 13078c2ecf20Sopenharmony_ci { PCI_DEVICE_ID_INTEL_82965Q_IG, "965Q", 13088c2ecf20Sopenharmony_ci &i965_gtt_driver }, 13098c2ecf20Sopenharmony_ci { PCI_DEVICE_ID_INTEL_82965G_IG, "965G", 13108c2ecf20Sopenharmony_ci &i965_gtt_driver }, 13118c2ecf20Sopenharmony_ci { PCI_DEVICE_ID_INTEL_82965GM_IG, "965GM", 13128c2ecf20Sopenharmony_ci &i965_gtt_driver }, 13138c2ecf20Sopenharmony_ci { PCI_DEVICE_ID_INTEL_82965GME_IG, "965GME/GLE", 13148c2ecf20Sopenharmony_ci &i965_gtt_driver }, 13158c2ecf20Sopenharmony_ci { PCI_DEVICE_ID_INTEL_G33_IG, "G33", 13168c2ecf20Sopenharmony_ci &g33_gtt_driver }, 13178c2ecf20Sopenharmony_ci { PCI_DEVICE_ID_INTEL_Q35_IG, "Q35", 13188c2ecf20Sopenharmony_ci &g33_gtt_driver }, 13198c2ecf20Sopenharmony_ci { PCI_DEVICE_ID_INTEL_Q33_IG, "Q33", 13208c2ecf20Sopenharmony_ci &g33_gtt_driver }, 13218c2ecf20Sopenharmony_ci { PCI_DEVICE_ID_INTEL_PINEVIEW_M_IG, "GMA3150", 13228c2ecf20Sopenharmony_ci &pineview_gtt_driver }, 13238c2ecf20Sopenharmony_ci { PCI_DEVICE_ID_INTEL_PINEVIEW_IG, "GMA3150", 13248c2ecf20Sopenharmony_ci &pineview_gtt_driver }, 13258c2ecf20Sopenharmony_ci { PCI_DEVICE_ID_INTEL_GM45_IG, "GM45", 13268c2ecf20Sopenharmony_ci &g4x_gtt_driver }, 13278c2ecf20Sopenharmony_ci { PCI_DEVICE_ID_INTEL_EAGLELAKE_IG, "Eaglelake", 13288c2ecf20Sopenharmony_ci &g4x_gtt_driver }, 13298c2ecf20Sopenharmony_ci { PCI_DEVICE_ID_INTEL_Q45_IG, "Q45/Q43", 13308c2ecf20Sopenharmony_ci &g4x_gtt_driver }, 13318c2ecf20Sopenharmony_ci { PCI_DEVICE_ID_INTEL_G45_IG, "G45/G43", 13328c2ecf20Sopenharmony_ci &g4x_gtt_driver }, 13338c2ecf20Sopenharmony_ci { PCI_DEVICE_ID_INTEL_B43_IG, "B43", 13348c2ecf20Sopenharmony_ci &g4x_gtt_driver }, 13358c2ecf20Sopenharmony_ci { PCI_DEVICE_ID_INTEL_B43_1_IG, "B43", 13368c2ecf20Sopenharmony_ci &g4x_gtt_driver }, 13378c2ecf20Sopenharmony_ci { PCI_DEVICE_ID_INTEL_G41_IG, "G41", 13388c2ecf20Sopenharmony_ci &g4x_gtt_driver }, 13398c2ecf20Sopenharmony_ci { PCI_DEVICE_ID_INTEL_IRONLAKE_D_IG, 13408c2ecf20Sopenharmony_ci "HD Graphics", &ironlake_gtt_driver }, 13418c2ecf20Sopenharmony_ci { PCI_DEVICE_ID_INTEL_IRONLAKE_M_IG, 13428c2ecf20Sopenharmony_ci "HD Graphics", &ironlake_gtt_driver }, 13438c2ecf20Sopenharmony_ci { 0, NULL, NULL } 13448c2ecf20Sopenharmony_ci}; 13458c2ecf20Sopenharmony_ci 13468c2ecf20Sopenharmony_cistatic int find_gmch(u16 device) 13478c2ecf20Sopenharmony_ci{ 13488c2ecf20Sopenharmony_ci struct pci_dev *gmch_device; 13498c2ecf20Sopenharmony_ci 13508c2ecf20Sopenharmony_ci gmch_device = pci_get_device(PCI_VENDOR_ID_INTEL, device, NULL); 13518c2ecf20Sopenharmony_ci if (gmch_device && PCI_FUNC(gmch_device->devfn) != 0) { 13528c2ecf20Sopenharmony_ci gmch_device = pci_get_device(PCI_VENDOR_ID_INTEL, 13538c2ecf20Sopenharmony_ci device, gmch_device); 13548c2ecf20Sopenharmony_ci } 13558c2ecf20Sopenharmony_ci 13568c2ecf20Sopenharmony_ci if (!gmch_device) 13578c2ecf20Sopenharmony_ci return 0; 13588c2ecf20Sopenharmony_ci 13598c2ecf20Sopenharmony_ci intel_private.pcidev = gmch_device; 13608c2ecf20Sopenharmony_ci return 1; 13618c2ecf20Sopenharmony_ci} 13628c2ecf20Sopenharmony_ci 13638c2ecf20Sopenharmony_ciint intel_gmch_probe(struct pci_dev *bridge_pdev, struct pci_dev *gpu_pdev, 13648c2ecf20Sopenharmony_ci struct agp_bridge_data *bridge) 13658c2ecf20Sopenharmony_ci{ 13668c2ecf20Sopenharmony_ci int i, mask; 13678c2ecf20Sopenharmony_ci 13688c2ecf20Sopenharmony_ci for (i = 0; intel_gtt_chipsets[i].name != NULL; i++) { 13698c2ecf20Sopenharmony_ci if (gpu_pdev) { 13708c2ecf20Sopenharmony_ci if (gpu_pdev->device == 13718c2ecf20Sopenharmony_ci intel_gtt_chipsets[i].gmch_chip_id) { 13728c2ecf20Sopenharmony_ci intel_private.pcidev = pci_dev_get(gpu_pdev); 13738c2ecf20Sopenharmony_ci intel_private.driver = 13748c2ecf20Sopenharmony_ci intel_gtt_chipsets[i].gtt_driver; 13758c2ecf20Sopenharmony_ci 13768c2ecf20Sopenharmony_ci break; 13778c2ecf20Sopenharmony_ci } 13788c2ecf20Sopenharmony_ci } else if (find_gmch(intel_gtt_chipsets[i].gmch_chip_id)) { 13798c2ecf20Sopenharmony_ci intel_private.driver = 13808c2ecf20Sopenharmony_ci intel_gtt_chipsets[i].gtt_driver; 13818c2ecf20Sopenharmony_ci break; 13828c2ecf20Sopenharmony_ci } 13838c2ecf20Sopenharmony_ci } 13848c2ecf20Sopenharmony_ci 13858c2ecf20Sopenharmony_ci if (!intel_private.driver) 13868c2ecf20Sopenharmony_ci return 0; 13878c2ecf20Sopenharmony_ci 13888c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_AGP_INTEL) 13898c2ecf20Sopenharmony_ci if (bridge) { 13908c2ecf20Sopenharmony_ci if (INTEL_GTT_GEN > 1) 13918c2ecf20Sopenharmony_ci return 0; 13928c2ecf20Sopenharmony_ci 13938c2ecf20Sopenharmony_ci bridge->driver = &intel_fake_agp_driver; 13948c2ecf20Sopenharmony_ci bridge->dev_private_data = &intel_private; 13958c2ecf20Sopenharmony_ci bridge->dev = bridge_pdev; 13968c2ecf20Sopenharmony_ci } 13978c2ecf20Sopenharmony_ci#endif 13988c2ecf20Sopenharmony_ci 13998c2ecf20Sopenharmony_ci 14008c2ecf20Sopenharmony_ci /* 14018c2ecf20Sopenharmony_ci * Can be called from the fake agp driver but also directly from 14028c2ecf20Sopenharmony_ci * drm/i915.ko. Hence we need to check whether everything is set up 14038c2ecf20Sopenharmony_ci * already. 14048c2ecf20Sopenharmony_ci */ 14058c2ecf20Sopenharmony_ci if (intel_private.refcount++) 14068c2ecf20Sopenharmony_ci return 1; 14078c2ecf20Sopenharmony_ci 14088c2ecf20Sopenharmony_ci intel_private.bridge_dev = pci_dev_get(bridge_pdev); 14098c2ecf20Sopenharmony_ci 14108c2ecf20Sopenharmony_ci dev_info(&bridge_pdev->dev, "Intel %s Chipset\n", intel_gtt_chipsets[i].name); 14118c2ecf20Sopenharmony_ci 14128c2ecf20Sopenharmony_ci if (bridge) { 14138c2ecf20Sopenharmony_ci mask = intel_private.driver->dma_mask_size; 14148c2ecf20Sopenharmony_ci if (pci_set_dma_mask(intel_private.pcidev, DMA_BIT_MASK(mask))) 14158c2ecf20Sopenharmony_ci dev_err(&intel_private.pcidev->dev, 14168c2ecf20Sopenharmony_ci "set gfx device dma mask %d-bit failed!\n", 14178c2ecf20Sopenharmony_ci mask); 14188c2ecf20Sopenharmony_ci else 14198c2ecf20Sopenharmony_ci pci_set_consistent_dma_mask(intel_private.pcidev, 14208c2ecf20Sopenharmony_ci DMA_BIT_MASK(mask)); 14218c2ecf20Sopenharmony_ci } 14228c2ecf20Sopenharmony_ci 14238c2ecf20Sopenharmony_ci if (intel_gtt_init() != 0) { 14248c2ecf20Sopenharmony_ci intel_gmch_remove(); 14258c2ecf20Sopenharmony_ci 14268c2ecf20Sopenharmony_ci return 0; 14278c2ecf20Sopenharmony_ci } 14288c2ecf20Sopenharmony_ci 14298c2ecf20Sopenharmony_ci return 1; 14308c2ecf20Sopenharmony_ci} 14318c2ecf20Sopenharmony_ciEXPORT_SYMBOL(intel_gmch_probe); 14328c2ecf20Sopenharmony_ci 14338c2ecf20Sopenharmony_civoid intel_gtt_get(u64 *gtt_total, 14348c2ecf20Sopenharmony_ci phys_addr_t *mappable_base, 14358c2ecf20Sopenharmony_ci resource_size_t *mappable_end) 14368c2ecf20Sopenharmony_ci{ 14378c2ecf20Sopenharmony_ci *gtt_total = intel_private.gtt_total_entries << PAGE_SHIFT; 14388c2ecf20Sopenharmony_ci *mappable_base = intel_private.gma_bus_addr; 14398c2ecf20Sopenharmony_ci *mappable_end = intel_private.gtt_mappable_entries << PAGE_SHIFT; 14408c2ecf20Sopenharmony_ci} 14418c2ecf20Sopenharmony_ciEXPORT_SYMBOL(intel_gtt_get); 14428c2ecf20Sopenharmony_ci 14438c2ecf20Sopenharmony_civoid intel_gtt_chipset_flush(void) 14448c2ecf20Sopenharmony_ci{ 14458c2ecf20Sopenharmony_ci if (intel_private.driver->chipset_flush) 14468c2ecf20Sopenharmony_ci intel_private.driver->chipset_flush(); 14478c2ecf20Sopenharmony_ci} 14488c2ecf20Sopenharmony_ciEXPORT_SYMBOL(intel_gtt_chipset_flush); 14498c2ecf20Sopenharmony_ci 14508c2ecf20Sopenharmony_civoid intel_gmch_remove(void) 14518c2ecf20Sopenharmony_ci{ 14528c2ecf20Sopenharmony_ci if (--intel_private.refcount) 14538c2ecf20Sopenharmony_ci return; 14548c2ecf20Sopenharmony_ci 14558c2ecf20Sopenharmony_ci if (intel_private.scratch_page) 14568c2ecf20Sopenharmony_ci intel_gtt_teardown_scratch_page(); 14578c2ecf20Sopenharmony_ci if (intel_private.pcidev) 14588c2ecf20Sopenharmony_ci pci_dev_put(intel_private.pcidev); 14598c2ecf20Sopenharmony_ci if (intel_private.bridge_dev) 14608c2ecf20Sopenharmony_ci pci_dev_put(intel_private.bridge_dev); 14618c2ecf20Sopenharmony_ci intel_private.driver = NULL; 14628c2ecf20Sopenharmony_ci} 14638c2ecf20Sopenharmony_ciEXPORT_SYMBOL(intel_gmch_remove); 14648c2ecf20Sopenharmony_ci 14658c2ecf20Sopenharmony_ciMODULE_AUTHOR("Dave Jones, Various @Intel"); 14668c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL and additional rights"); 1467