162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * Intel GTT (Graphics Translation Table) routines 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Caveat: This driver implements the linux agp interface, but this is far from 562306a36Sopenharmony_ci * a agp driver! GTT support ended up here for purely historical reasons: The 662306a36Sopenharmony_ci * old userspace intel graphics drivers needed an interface to map memory into 762306a36Sopenharmony_ci * the GTT. And the drm provides a default interface for graphic devices sitting 862306a36Sopenharmony_ci * on an agp port. So it made sense to fake the GTT support as an agp port to 962306a36Sopenharmony_ci * avoid having to create a new api. 1062306a36Sopenharmony_ci * 1162306a36Sopenharmony_ci * With gem this does not make much sense anymore, just needlessly complicates 1262306a36Sopenharmony_ci * the code. But as long as the old graphics stack is still support, it's stuck 1362306a36Sopenharmony_ci * here. 1462306a36Sopenharmony_ci * 1562306a36Sopenharmony_ci * /fairy-tale-mode off 1662306a36Sopenharmony_ci */ 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci#include <linux/module.h> 1962306a36Sopenharmony_ci#include <linux/pci.h> 2062306a36Sopenharmony_ci#include <linux/kernel.h> 2162306a36Sopenharmony_ci#include <linux/pagemap.h> 2262306a36Sopenharmony_ci#include <linux/agp_backend.h> 2362306a36Sopenharmony_ci#include <linux/iommu.h> 2462306a36Sopenharmony_ci#include <linux/delay.h> 2562306a36Sopenharmony_ci#include <asm/smp.h> 2662306a36Sopenharmony_ci#include "agp.h" 2762306a36Sopenharmony_ci#include "intel-agp.h" 2862306a36Sopenharmony_ci#include <drm/intel-gtt.h> 2962306a36Sopenharmony_ci#include <asm/set_memory.h> 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci/* 3262306a36Sopenharmony_ci * If we have Intel graphics, we're not going to have anything other than 3362306a36Sopenharmony_ci * an Intel IOMMU. So make the correct use of the PCI DMA API contingent 3462306a36Sopenharmony_ci * on the Intel IOMMU support (CONFIG_INTEL_IOMMU). 3562306a36Sopenharmony_ci * Only newer chipsets need to bother with this, of course. 3662306a36Sopenharmony_ci */ 3762306a36Sopenharmony_ci#ifdef CONFIG_INTEL_IOMMU 3862306a36Sopenharmony_ci#define USE_PCI_DMA_API 1 3962306a36Sopenharmony_ci#else 4062306a36Sopenharmony_ci#define USE_PCI_DMA_API 0 4162306a36Sopenharmony_ci#endif 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_cistruct intel_gtt_driver { 4462306a36Sopenharmony_ci unsigned int gen : 8; 4562306a36Sopenharmony_ci unsigned int is_g33 : 1; 4662306a36Sopenharmony_ci unsigned int is_pineview : 1; 4762306a36Sopenharmony_ci unsigned int is_ironlake : 1; 4862306a36Sopenharmony_ci unsigned int has_pgtbl_enable : 1; 4962306a36Sopenharmony_ci unsigned int dma_mask_size : 8; 5062306a36Sopenharmony_ci /* Chipset specific GTT setup */ 5162306a36Sopenharmony_ci int (*setup)(void); 5262306a36Sopenharmony_ci /* This should undo anything done in ->setup() save the unmapping 5362306a36Sopenharmony_ci * of the mmio register file, that's done in the generic code. */ 5462306a36Sopenharmony_ci void (*cleanup)(void); 5562306a36Sopenharmony_ci void (*write_entry)(dma_addr_t addr, unsigned int entry, unsigned int flags); 5662306a36Sopenharmony_ci /* Flags is a more or less chipset specific opaque value. 5762306a36Sopenharmony_ci * For chipsets that need to support old ums (non-gem) code, this 5862306a36Sopenharmony_ci * needs to be identical to the various supported agp memory types! */ 5962306a36Sopenharmony_ci bool (*check_flags)(unsigned int flags); 6062306a36Sopenharmony_ci void (*chipset_flush)(void); 6162306a36Sopenharmony_ci}; 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_cistatic struct _intel_private { 6462306a36Sopenharmony_ci const struct intel_gtt_driver *driver; 6562306a36Sopenharmony_ci struct pci_dev *pcidev; /* device one */ 6662306a36Sopenharmony_ci struct pci_dev *bridge_dev; 6762306a36Sopenharmony_ci u8 __iomem *registers; 6862306a36Sopenharmony_ci phys_addr_t gtt_phys_addr; 6962306a36Sopenharmony_ci u32 PGETBL_save; 7062306a36Sopenharmony_ci u32 __iomem *gtt; /* I915G */ 7162306a36Sopenharmony_ci bool clear_fake_agp; /* on first access via agp, fill with scratch */ 7262306a36Sopenharmony_ci int num_dcache_entries; 7362306a36Sopenharmony_ci void __iomem *i9xx_flush_page; 7462306a36Sopenharmony_ci char *i81x_gtt_table; 7562306a36Sopenharmony_ci struct resource ifp_resource; 7662306a36Sopenharmony_ci int resource_valid; 7762306a36Sopenharmony_ci struct page *scratch_page; 7862306a36Sopenharmony_ci phys_addr_t scratch_page_dma; 7962306a36Sopenharmony_ci int refcount; 8062306a36Sopenharmony_ci /* Whether i915 needs to use the dmar apis or not. */ 8162306a36Sopenharmony_ci unsigned int needs_dmar : 1; 8262306a36Sopenharmony_ci phys_addr_t gma_bus_addr; 8362306a36Sopenharmony_ci /* Size of memory reserved for graphics by the BIOS */ 8462306a36Sopenharmony_ci resource_size_t stolen_size; 8562306a36Sopenharmony_ci /* Total number of gtt entries. */ 8662306a36Sopenharmony_ci unsigned int gtt_total_entries; 8762306a36Sopenharmony_ci /* Part of the gtt that is mappable by the cpu, for those chips where 8862306a36Sopenharmony_ci * this is not the full gtt. */ 8962306a36Sopenharmony_ci unsigned int gtt_mappable_entries; 9062306a36Sopenharmony_ci} intel_private; 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci#define INTEL_GTT_GEN intel_private.driver->gen 9362306a36Sopenharmony_ci#define IS_G33 intel_private.driver->is_g33 9462306a36Sopenharmony_ci#define IS_PINEVIEW intel_private.driver->is_pineview 9562306a36Sopenharmony_ci#define IS_IRONLAKE intel_private.driver->is_ironlake 9662306a36Sopenharmony_ci#define HAS_PGTBL_EN intel_private.driver->has_pgtbl_enable 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_AGP_INTEL) 9962306a36Sopenharmony_cistatic int intel_gtt_map_memory(struct page **pages, 10062306a36Sopenharmony_ci unsigned int num_entries, 10162306a36Sopenharmony_ci struct sg_table *st) 10262306a36Sopenharmony_ci{ 10362306a36Sopenharmony_ci struct scatterlist *sg; 10462306a36Sopenharmony_ci int i; 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci DBG("try mapping %lu pages\n", (unsigned long)num_entries); 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci if (sg_alloc_table(st, num_entries, GFP_KERNEL)) 10962306a36Sopenharmony_ci goto err; 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci for_each_sg(st->sgl, sg, num_entries, i) 11262306a36Sopenharmony_ci sg_set_page(sg, pages[i], PAGE_SIZE, 0); 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci if (!dma_map_sg(&intel_private.pcidev->dev, st->sgl, st->nents, 11562306a36Sopenharmony_ci DMA_BIDIRECTIONAL)) 11662306a36Sopenharmony_ci goto err; 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci return 0; 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_cierr: 12162306a36Sopenharmony_ci sg_free_table(st); 12262306a36Sopenharmony_ci return -ENOMEM; 12362306a36Sopenharmony_ci} 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_cistatic void intel_gtt_unmap_memory(struct scatterlist *sg_list, int num_sg) 12662306a36Sopenharmony_ci{ 12762306a36Sopenharmony_ci struct sg_table st; 12862306a36Sopenharmony_ci DBG("try unmapping %lu pages\n", (unsigned long)mem->page_count); 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci dma_unmap_sg(&intel_private.pcidev->dev, sg_list, num_sg, 13162306a36Sopenharmony_ci DMA_BIDIRECTIONAL); 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci st.sgl = sg_list; 13462306a36Sopenharmony_ci st.orig_nents = st.nents = num_sg; 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci sg_free_table(&st); 13762306a36Sopenharmony_ci} 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_cistatic void intel_fake_agp_enable(struct agp_bridge_data *bridge, u32 mode) 14062306a36Sopenharmony_ci{ 14162306a36Sopenharmony_ci return; 14262306a36Sopenharmony_ci} 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci/* Exists to support ARGB cursors */ 14562306a36Sopenharmony_cistatic struct page *i8xx_alloc_pages(void) 14662306a36Sopenharmony_ci{ 14762306a36Sopenharmony_ci struct page *page; 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci page = alloc_pages(GFP_KERNEL | GFP_DMA32, 2); 15062306a36Sopenharmony_ci if (page == NULL) 15162306a36Sopenharmony_ci return NULL; 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci if (set_pages_uc(page, 4) < 0) { 15462306a36Sopenharmony_ci set_pages_wb(page, 4); 15562306a36Sopenharmony_ci __free_pages(page, 2); 15662306a36Sopenharmony_ci return NULL; 15762306a36Sopenharmony_ci } 15862306a36Sopenharmony_ci atomic_inc(&agp_bridge->current_memory_agp); 15962306a36Sopenharmony_ci return page; 16062306a36Sopenharmony_ci} 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_cistatic void i8xx_destroy_pages(struct page *page) 16362306a36Sopenharmony_ci{ 16462306a36Sopenharmony_ci if (page == NULL) 16562306a36Sopenharmony_ci return; 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci set_pages_wb(page, 4); 16862306a36Sopenharmony_ci __free_pages(page, 2); 16962306a36Sopenharmony_ci atomic_dec(&agp_bridge->current_memory_agp); 17062306a36Sopenharmony_ci} 17162306a36Sopenharmony_ci#endif 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci#define I810_GTT_ORDER 4 17462306a36Sopenharmony_cistatic int i810_setup(void) 17562306a36Sopenharmony_ci{ 17662306a36Sopenharmony_ci phys_addr_t reg_addr; 17762306a36Sopenharmony_ci char *gtt_table; 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci /* i81x does not preallocate the gtt. It's always 64kb in size. */ 18062306a36Sopenharmony_ci gtt_table = alloc_gatt_pages(I810_GTT_ORDER); 18162306a36Sopenharmony_ci if (gtt_table == NULL) 18262306a36Sopenharmony_ci return -ENOMEM; 18362306a36Sopenharmony_ci intel_private.i81x_gtt_table = gtt_table; 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci reg_addr = pci_resource_start(intel_private.pcidev, I810_MMADR_BAR); 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci intel_private.registers = ioremap(reg_addr, KB(64)); 18862306a36Sopenharmony_ci if (!intel_private.registers) 18962306a36Sopenharmony_ci return -ENOMEM; 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci writel(virt_to_phys(gtt_table) | I810_PGETBL_ENABLED, 19262306a36Sopenharmony_ci intel_private.registers+I810_PGETBL_CTL); 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci intel_private.gtt_phys_addr = reg_addr + I810_PTE_BASE; 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci if ((readl(intel_private.registers+I810_DRAM_CTL) 19762306a36Sopenharmony_ci & I810_DRAM_ROW_0) == I810_DRAM_ROW_0_SDRAM) { 19862306a36Sopenharmony_ci dev_info(&intel_private.pcidev->dev, 19962306a36Sopenharmony_ci "detected 4MB dedicated video ram\n"); 20062306a36Sopenharmony_ci intel_private.num_dcache_entries = 1024; 20162306a36Sopenharmony_ci } 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci return 0; 20462306a36Sopenharmony_ci} 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_cistatic void i810_cleanup(void) 20762306a36Sopenharmony_ci{ 20862306a36Sopenharmony_ci writel(0, intel_private.registers+I810_PGETBL_CTL); 20962306a36Sopenharmony_ci free_gatt_pages(intel_private.i81x_gtt_table, I810_GTT_ORDER); 21062306a36Sopenharmony_ci} 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_AGP_INTEL) 21362306a36Sopenharmony_cistatic int i810_insert_dcache_entries(struct agp_memory *mem, off_t pg_start, 21462306a36Sopenharmony_ci int type) 21562306a36Sopenharmony_ci{ 21662306a36Sopenharmony_ci int i; 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci if ((pg_start + mem->page_count) 21962306a36Sopenharmony_ci > intel_private.num_dcache_entries) 22062306a36Sopenharmony_ci return -EINVAL; 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci if (!mem->is_flushed) 22362306a36Sopenharmony_ci global_cache_flush(); 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci for (i = pg_start; i < (pg_start + mem->page_count); i++) { 22662306a36Sopenharmony_ci dma_addr_t addr = i << PAGE_SHIFT; 22762306a36Sopenharmony_ci intel_private.driver->write_entry(addr, 22862306a36Sopenharmony_ci i, type); 22962306a36Sopenharmony_ci } 23062306a36Sopenharmony_ci wmb(); 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci return 0; 23362306a36Sopenharmony_ci} 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci/* 23662306a36Sopenharmony_ci * The i810/i830 requires a physical address to program its mouse 23762306a36Sopenharmony_ci * pointer into hardware. 23862306a36Sopenharmony_ci * However the Xserver still writes to it through the agp aperture. 23962306a36Sopenharmony_ci */ 24062306a36Sopenharmony_cistatic struct agp_memory *alloc_agpphysmem_i8xx(size_t pg_count, int type) 24162306a36Sopenharmony_ci{ 24262306a36Sopenharmony_ci struct agp_memory *new; 24362306a36Sopenharmony_ci struct page *page; 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci switch (pg_count) { 24662306a36Sopenharmony_ci case 1: page = agp_bridge->driver->agp_alloc_page(agp_bridge); 24762306a36Sopenharmony_ci break; 24862306a36Sopenharmony_ci case 4: 24962306a36Sopenharmony_ci /* kludge to get 4 physical pages for ARGB cursor */ 25062306a36Sopenharmony_ci page = i8xx_alloc_pages(); 25162306a36Sopenharmony_ci break; 25262306a36Sopenharmony_ci default: 25362306a36Sopenharmony_ci return NULL; 25462306a36Sopenharmony_ci } 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci if (page == NULL) 25762306a36Sopenharmony_ci return NULL; 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci new = agp_create_memory(pg_count); 26062306a36Sopenharmony_ci if (new == NULL) 26162306a36Sopenharmony_ci return NULL; 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci new->pages[0] = page; 26462306a36Sopenharmony_ci if (pg_count == 4) { 26562306a36Sopenharmony_ci /* kludge to get 4 physical pages for ARGB cursor */ 26662306a36Sopenharmony_ci new->pages[1] = new->pages[0] + 1; 26762306a36Sopenharmony_ci new->pages[2] = new->pages[1] + 1; 26862306a36Sopenharmony_ci new->pages[3] = new->pages[2] + 1; 26962306a36Sopenharmony_ci } 27062306a36Sopenharmony_ci new->page_count = pg_count; 27162306a36Sopenharmony_ci new->num_scratch_pages = pg_count; 27262306a36Sopenharmony_ci new->type = AGP_PHYS_MEMORY; 27362306a36Sopenharmony_ci new->physical = page_to_phys(new->pages[0]); 27462306a36Sopenharmony_ci return new; 27562306a36Sopenharmony_ci} 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_cistatic void intel_i810_free_by_type(struct agp_memory *curr) 27862306a36Sopenharmony_ci{ 27962306a36Sopenharmony_ci agp_free_key(curr->key); 28062306a36Sopenharmony_ci if (curr->type == AGP_PHYS_MEMORY) { 28162306a36Sopenharmony_ci if (curr->page_count == 4) 28262306a36Sopenharmony_ci i8xx_destroy_pages(curr->pages[0]); 28362306a36Sopenharmony_ci else { 28462306a36Sopenharmony_ci agp_bridge->driver->agp_destroy_page(curr->pages[0], 28562306a36Sopenharmony_ci AGP_PAGE_DESTROY_UNMAP); 28662306a36Sopenharmony_ci agp_bridge->driver->agp_destroy_page(curr->pages[0], 28762306a36Sopenharmony_ci AGP_PAGE_DESTROY_FREE); 28862306a36Sopenharmony_ci } 28962306a36Sopenharmony_ci agp_free_page_array(curr); 29062306a36Sopenharmony_ci } 29162306a36Sopenharmony_ci kfree(curr); 29262306a36Sopenharmony_ci} 29362306a36Sopenharmony_ci#endif 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_cistatic int intel_gtt_setup_scratch_page(void) 29662306a36Sopenharmony_ci{ 29762306a36Sopenharmony_ci struct page *page; 29862306a36Sopenharmony_ci dma_addr_t dma_addr; 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci page = alloc_page(GFP_KERNEL | GFP_DMA32 | __GFP_ZERO); 30162306a36Sopenharmony_ci if (page == NULL) 30262306a36Sopenharmony_ci return -ENOMEM; 30362306a36Sopenharmony_ci set_pages_uc(page, 1); 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci if (intel_private.needs_dmar) { 30662306a36Sopenharmony_ci dma_addr = dma_map_page(&intel_private.pcidev->dev, page, 0, 30762306a36Sopenharmony_ci PAGE_SIZE, DMA_BIDIRECTIONAL); 30862306a36Sopenharmony_ci if (dma_mapping_error(&intel_private.pcidev->dev, dma_addr)) { 30962306a36Sopenharmony_ci __free_page(page); 31062306a36Sopenharmony_ci return -EINVAL; 31162306a36Sopenharmony_ci } 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci intel_private.scratch_page_dma = dma_addr; 31462306a36Sopenharmony_ci } else 31562306a36Sopenharmony_ci intel_private.scratch_page_dma = page_to_phys(page); 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci intel_private.scratch_page = page; 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci return 0; 32062306a36Sopenharmony_ci} 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_cistatic void i810_write_entry(dma_addr_t addr, unsigned int entry, 32362306a36Sopenharmony_ci unsigned int flags) 32462306a36Sopenharmony_ci{ 32562306a36Sopenharmony_ci u32 pte_flags = I810_PTE_VALID; 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci switch (flags) { 32862306a36Sopenharmony_ci case AGP_DCACHE_MEMORY: 32962306a36Sopenharmony_ci pte_flags |= I810_PTE_LOCAL; 33062306a36Sopenharmony_ci break; 33162306a36Sopenharmony_ci case AGP_USER_CACHED_MEMORY: 33262306a36Sopenharmony_ci pte_flags |= I830_PTE_SYSTEM_CACHED; 33362306a36Sopenharmony_ci break; 33462306a36Sopenharmony_ci } 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci writel_relaxed(addr | pte_flags, intel_private.gtt + entry); 33762306a36Sopenharmony_ci} 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_cistatic resource_size_t intel_gtt_stolen_size(void) 34062306a36Sopenharmony_ci{ 34162306a36Sopenharmony_ci u16 gmch_ctrl; 34262306a36Sopenharmony_ci u8 rdct; 34362306a36Sopenharmony_ci int local = 0; 34462306a36Sopenharmony_ci static const int ddt[4] = { 0, 16, 32, 64 }; 34562306a36Sopenharmony_ci resource_size_t stolen_size = 0; 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci if (INTEL_GTT_GEN == 1) 34862306a36Sopenharmony_ci return 0; /* no stolen mem on i81x */ 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci pci_read_config_word(intel_private.bridge_dev, 35162306a36Sopenharmony_ci I830_GMCH_CTRL, &gmch_ctrl); 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci if (intel_private.bridge_dev->device == PCI_DEVICE_ID_INTEL_82830_HB || 35462306a36Sopenharmony_ci intel_private.bridge_dev->device == PCI_DEVICE_ID_INTEL_82845G_HB) { 35562306a36Sopenharmony_ci switch (gmch_ctrl & I830_GMCH_GMS_MASK) { 35662306a36Sopenharmony_ci case I830_GMCH_GMS_STOLEN_512: 35762306a36Sopenharmony_ci stolen_size = KB(512); 35862306a36Sopenharmony_ci break; 35962306a36Sopenharmony_ci case I830_GMCH_GMS_STOLEN_1024: 36062306a36Sopenharmony_ci stolen_size = MB(1); 36162306a36Sopenharmony_ci break; 36262306a36Sopenharmony_ci case I830_GMCH_GMS_STOLEN_8192: 36362306a36Sopenharmony_ci stolen_size = MB(8); 36462306a36Sopenharmony_ci break; 36562306a36Sopenharmony_ci case I830_GMCH_GMS_LOCAL: 36662306a36Sopenharmony_ci rdct = readb(intel_private.registers+I830_RDRAM_CHANNEL_TYPE); 36762306a36Sopenharmony_ci stolen_size = (I830_RDRAM_ND(rdct) + 1) * 36862306a36Sopenharmony_ci MB(ddt[I830_RDRAM_DDT(rdct)]); 36962306a36Sopenharmony_ci local = 1; 37062306a36Sopenharmony_ci break; 37162306a36Sopenharmony_ci default: 37262306a36Sopenharmony_ci stolen_size = 0; 37362306a36Sopenharmony_ci break; 37462306a36Sopenharmony_ci } 37562306a36Sopenharmony_ci } else { 37662306a36Sopenharmony_ci switch (gmch_ctrl & I855_GMCH_GMS_MASK) { 37762306a36Sopenharmony_ci case I855_GMCH_GMS_STOLEN_1M: 37862306a36Sopenharmony_ci stolen_size = MB(1); 37962306a36Sopenharmony_ci break; 38062306a36Sopenharmony_ci case I855_GMCH_GMS_STOLEN_4M: 38162306a36Sopenharmony_ci stolen_size = MB(4); 38262306a36Sopenharmony_ci break; 38362306a36Sopenharmony_ci case I855_GMCH_GMS_STOLEN_8M: 38462306a36Sopenharmony_ci stolen_size = MB(8); 38562306a36Sopenharmony_ci break; 38662306a36Sopenharmony_ci case I855_GMCH_GMS_STOLEN_16M: 38762306a36Sopenharmony_ci stolen_size = MB(16); 38862306a36Sopenharmony_ci break; 38962306a36Sopenharmony_ci case I855_GMCH_GMS_STOLEN_32M: 39062306a36Sopenharmony_ci stolen_size = MB(32); 39162306a36Sopenharmony_ci break; 39262306a36Sopenharmony_ci case I915_GMCH_GMS_STOLEN_48M: 39362306a36Sopenharmony_ci stolen_size = MB(48); 39462306a36Sopenharmony_ci break; 39562306a36Sopenharmony_ci case I915_GMCH_GMS_STOLEN_64M: 39662306a36Sopenharmony_ci stolen_size = MB(64); 39762306a36Sopenharmony_ci break; 39862306a36Sopenharmony_ci case G33_GMCH_GMS_STOLEN_128M: 39962306a36Sopenharmony_ci stolen_size = MB(128); 40062306a36Sopenharmony_ci break; 40162306a36Sopenharmony_ci case G33_GMCH_GMS_STOLEN_256M: 40262306a36Sopenharmony_ci stolen_size = MB(256); 40362306a36Sopenharmony_ci break; 40462306a36Sopenharmony_ci case INTEL_GMCH_GMS_STOLEN_96M: 40562306a36Sopenharmony_ci stolen_size = MB(96); 40662306a36Sopenharmony_ci break; 40762306a36Sopenharmony_ci case INTEL_GMCH_GMS_STOLEN_160M: 40862306a36Sopenharmony_ci stolen_size = MB(160); 40962306a36Sopenharmony_ci break; 41062306a36Sopenharmony_ci case INTEL_GMCH_GMS_STOLEN_224M: 41162306a36Sopenharmony_ci stolen_size = MB(224); 41262306a36Sopenharmony_ci break; 41362306a36Sopenharmony_ci case INTEL_GMCH_GMS_STOLEN_352M: 41462306a36Sopenharmony_ci stolen_size = MB(352); 41562306a36Sopenharmony_ci break; 41662306a36Sopenharmony_ci default: 41762306a36Sopenharmony_ci stolen_size = 0; 41862306a36Sopenharmony_ci break; 41962306a36Sopenharmony_ci } 42062306a36Sopenharmony_ci } 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci if (stolen_size > 0) { 42362306a36Sopenharmony_ci dev_info(&intel_private.bridge_dev->dev, "detected %lluK %s memory\n", 42462306a36Sopenharmony_ci (u64)stolen_size / KB(1), local ? "local" : "stolen"); 42562306a36Sopenharmony_ci } else { 42662306a36Sopenharmony_ci dev_info(&intel_private.bridge_dev->dev, 42762306a36Sopenharmony_ci "no pre-allocated video memory detected\n"); 42862306a36Sopenharmony_ci stolen_size = 0; 42962306a36Sopenharmony_ci } 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci return stolen_size; 43262306a36Sopenharmony_ci} 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_cistatic void i965_adjust_pgetbl_size(unsigned int size_flag) 43562306a36Sopenharmony_ci{ 43662306a36Sopenharmony_ci u32 pgetbl_ctl, pgetbl_ctl2; 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci /* ensure that ppgtt is disabled */ 43962306a36Sopenharmony_ci pgetbl_ctl2 = readl(intel_private.registers+I965_PGETBL_CTL2); 44062306a36Sopenharmony_ci pgetbl_ctl2 &= ~I810_PGETBL_ENABLED; 44162306a36Sopenharmony_ci writel(pgetbl_ctl2, intel_private.registers+I965_PGETBL_CTL2); 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci /* write the new ggtt size */ 44462306a36Sopenharmony_ci pgetbl_ctl = readl(intel_private.registers+I810_PGETBL_CTL); 44562306a36Sopenharmony_ci pgetbl_ctl &= ~I965_PGETBL_SIZE_MASK; 44662306a36Sopenharmony_ci pgetbl_ctl |= size_flag; 44762306a36Sopenharmony_ci writel(pgetbl_ctl, intel_private.registers+I810_PGETBL_CTL); 44862306a36Sopenharmony_ci} 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_cistatic unsigned int i965_gtt_total_entries(void) 45162306a36Sopenharmony_ci{ 45262306a36Sopenharmony_ci int size; 45362306a36Sopenharmony_ci u32 pgetbl_ctl; 45462306a36Sopenharmony_ci u16 gmch_ctl; 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci pci_read_config_word(intel_private.bridge_dev, 45762306a36Sopenharmony_ci I830_GMCH_CTRL, &gmch_ctl); 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci if (INTEL_GTT_GEN == 5) { 46062306a36Sopenharmony_ci switch (gmch_ctl & G4x_GMCH_SIZE_MASK) { 46162306a36Sopenharmony_ci case G4x_GMCH_SIZE_1M: 46262306a36Sopenharmony_ci case G4x_GMCH_SIZE_VT_1M: 46362306a36Sopenharmony_ci i965_adjust_pgetbl_size(I965_PGETBL_SIZE_1MB); 46462306a36Sopenharmony_ci break; 46562306a36Sopenharmony_ci case G4x_GMCH_SIZE_VT_1_5M: 46662306a36Sopenharmony_ci i965_adjust_pgetbl_size(I965_PGETBL_SIZE_1_5MB); 46762306a36Sopenharmony_ci break; 46862306a36Sopenharmony_ci case G4x_GMCH_SIZE_2M: 46962306a36Sopenharmony_ci case G4x_GMCH_SIZE_VT_2M: 47062306a36Sopenharmony_ci i965_adjust_pgetbl_size(I965_PGETBL_SIZE_2MB); 47162306a36Sopenharmony_ci break; 47262306a36Sopenharmony_ci } 47362306a36Sopenharmony_ci } 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci pgetbl_ctl = readl(intel_private.registers+I810_PGETBL_CTL); 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci switch (pgetbl_ctl & I965_PGETBL_SIZE_MASK) { 47862306a36Sopenharmony_ci case I965_PGETBL_SIZE_128KB: 47962306a36Sopenharmony_ci size = KB(128); 48062306a36Sopenharmony_ci break; 48162306a36Sopenharmony_ci case I965_PGETBL_SIZE_256KB: 48262306a36Sopenharmony_ci size = KB(256); 48362306a36Sopenharmony_ci break; 48462306a36Sopenharmony_ci case I965_PGETBL_SIZE_512KB: 48562306a36Sopenharmony_ci size = KB(512); 48662306a36Sopenharmony_ci break; 48762306a36Sopenharmony_ci /* GTT pagetable sizes bigger than 512KB are not possible on G33! */ 48862306a36Sopenharmony_ci case I965_PGETBL_SIZE_1MB: 48962306a36Sopenharmony_ci size = KB(1024); 49062306a36Sopenharmony_ci break; 49162306a36Sopenharmony_ci case I965_PGETBL_SIZE_2MB: 49262306a36Sopenharmony_ci size = KB(2048); 49362306a36Sopenharmony_ci break; 49462306a36Sopenharmony_ci case I965_PGETBL_SIZE_1_5MB: 49562306a36Sopenharmony_ci size = KB(1024 + 512); 49662306a36Sopenharmony_ci break; 49762306a36Sopenharmony_ci default: 49862306a36Sopenharmony_ci dev_info(&intel_private.pcidev->dev, 49962306a36Sopenharmony_ci "unknown page table size, assuming 512KB\n"); 50062306a36Sopenharmony_ci size = KB(512); 50162306a36Sopenharmony_ci } 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_ci return size/4; 50462306a36Sopenharmony_ci} 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_cistatic unsigned int intel_gtt_total_entries(void) 50762306a36Sopenharmony_ci{ 50862306a36Sopenharmony_ci if (IS_G33 || INTEL_GTT_GEN == 4 || INTEL_GTT_GEN == 5) 50962306a36Sopenharmony_ci return i965_gtt_total_entries(); 51062306a36Sopenharmony_ci else { 51162306a36Sopenharmony_ci /* On previous hardware, the GTT size was just what was 51262306a36Sopenharmony_ci * required to map the aperture. 51362306a36Sopenharmony_ci */ 51462306a36Sopenharmony_ci return intel_private.gtt_mappable_entries; 51562306a36Sopenharmony_ci } 51662306a36Sopenharmony_ci} 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_cistatic unsigned int intel_gtt_mappable_entries(void) 51962306a36Sopenharmony_ci{ 52062306a36Sopenharmony_ci unsigned int aperture_size; 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci if (INTEL_GTT_GEN == 1) { 52362306a36Sopenharmony_ci u32 smram_miscc; 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_ci pci_read_config_dword(intel_private.bridge_dev, 52662306a36Sopenharmony_ci I810_SMRAM_MISCC, &smram_miscc); 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci if ((smram_miscc & I810_GFX_MEM_WIN_SIZE) 52962306a36Sopenharmony_ci == I810_GFX_MEM_WIN_32M) 53062306a36Sopenharmony_ci aperture_size = MB(32); 53162306a36Sopenharmony_ci else 53262306a36Sopenharmony_ci aperture_size = MB(64); 53362306a36Sopenharmony_ci } else if (INTEL_GTT_GEN == 2) { 53462306a36Sopenharmony_ci u16 gmch_ctrl; 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci pci_read_config_word(intel_private.bridge_dev, 53762306a36Sopenharmony_ci I830_GMCH_CTRL, &gmch_ctrl); 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_ci if ((gmch_ctrl & I830_GMCH_MEM_MASK) == I830_GMCH_MEM_64M) 54062306a36Sopenharmony_ci aperture_size = MB(64); 54162306a36Sopenharmony_ci else 54262306a36Sopenharmony_ci aperture_size = MB(128); 54362306a36Sopenharmony_ci } else { 54462306a36Sopenharmony_ci /* 9xx supports large sizes, just look at the length */ 54562306a36Sopenharmony_ci aperture_size = pci_resource_len(intel_private.pcidev, 2); 54662306a36Sopenharmony_ci } 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_ci return aperture_size >> PAGE_SHIFT; 54962306a36Sopenharmony_ci} 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_cistatic void intel_gtt_teardown_scratch_page(void) 55262306a36Sopenharmony_ci{ 55362306a36Sopenharmony_ci set_pages_wb(intel_private.scratch_page, 1); 55462306a36Sopenharmony_ci if (intel_private.needs_dmar) 55562306a36Sopenharmony_ci dma_unmap_page(&intel_private.pcidev->dev, 55662306a36Sopenharmony_ci intel_private.scratch_page_dma, PAGE_SIZE, 55762306a36Sopenharmony_ci DMA_BIDIRECTIONAL); 55862306a36Sopenharmony_ci __free_page(intel_private.scratch_page); 55962306a36Sopenharmony_ci} 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_cistatic void intel_gtt_cleanup(void) 56262306a36Sopenharmony_ci{ 56362306a36Sopenharmony_ci intel_private.driver->cleanup(); 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_ci iounmap(intel_private.gtt); 56662306a36Sopenharmony_ci iounmap(intel_private.registers); 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci intel_gtt_teardown_scratch_page(); 56962306a36Sopenharmony_ci} 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_ci/* Certain Gen5 chipsets require require idling the GPU before 57262306a36Sopenharmony_ci * unmapping anything from the GTT when VT-d is enabled. 57362306a36Sopenharmony_ci */ 57462306a36Sopenharmony_cistatic inline int needs_ilk_vtd_wa(void) 57562306a36Sopenharmony_ci{ 57662306a36Sopenharmony_ci const unsigned short gpu_devid = intel_private.pcidev->device; 57762306a36Sopenharmony_ci 57862306a36Sopenharmony_ci /* 57962306a36Sopenharmony_ci * Query iommu subsystem to see if we need the workaround. Presumably 58062306a36Sopenharmony_ci * that was loaded first. 58162306a36Sopenharmony_ci */ 58262306a36Sopenharmony_ci return ((gpu_devid == PCI_DEVICE_ID_INTEL_IRONLAKE_D_IG || 58362306a36Sopenharmony_ci gpu_devid == PCI_DEVICE_ID_INTEL_IRONLAKE_M_IG) && 58462306a36Sopenharmony_ci device_iommu_mapped(&intel_private.pcidev->dev)); 58562306a36Sopenharmony_ci} 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_cistatic bool intel_gtt_can_wc(void) 58862306a36Sopenharmony_ci{ 58962306a36Sopenharmony_ci if (INTEL_GTT_GEN <= 2) 59062306a36Sopenharmony_ci return false; 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_ci if (INTEL_GTT_GEN >= 6) 59362306a36Sopenharmony_ci return false; 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_ci /* Reports of major corruption with ILK vt'd enabled */ 59662306a36Sopenharmony_ci if (needs_ilk_vtd_wa()) 59762306a36Sopenharmony_ci return false; 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_ci return true; 60062306a36Sopenharmony_ci} 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_cistatic int intel_gtt_init(void) 60362306a36Sopenharmony_ci{ 60462306a36Sopenharmony_ci u32 gtt_map_size; 60562306a36Sopenharmony_ci int ret, bar; 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_ci ret = intel_private.driver->setup(); 60862306a36Sopenharmony_ci if (ret != 0) 60962306a36Sopenharmony_ci return ret; 61062306a36Sopenharmony_ci 61162306a36Sopenharmony_ci intel_private.gtt_mappable_entries = intel_gtt_mappable_entries(); 61262306a36Sopenharmony_ci intel_private.gtt_total_entries = intel_gtt_total_entries(); 61362306a36Sopenharmony_ci 61462306a36Sopenharmony_ci /* save the PGETBL reg for resume */ 61562306a36Sopenharmony_ci intel_private.PGETBL_save = 61662306a36Sopenharmony_ci readl(intel_private.registers+I810_PGETBL_CTL) 61762306a36Sopenharmony_ci & ~I810_PGETBL_ENABLED; 61862306a36Sopenharmony_ci /* we only ever restore the register when enabling the PGTBL... */ 61962306a36Sopenharmony_ci if (HAS_PGTBL_EN) 62062306a36Sopenharmony_ci intel_private.PGETBL_save |= I810_PGETBL_ENABLED; 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ci dev_info(&intel_private.bridge_dev->dev, 62362306a36Sopenharmony_ci "detected gtt size: %dK total, %dK mappable\n", 62462306a36Sopenharmony_ci intel_private.gtt_total_entries * 4, 62562306a36Sopenharmony_ci intel_private.gtt_mappable_entries * 4); 62662306a36Sopenharmony_ci 62762306a36Sopenharmony_ci gtt_map_size = intel_private.gtt_total_entries * 4; 62862306a36Sopenharmony_ci 62962306a36Sopenharmony_ci intel_private.gtt = NULL; 63062306a36Sopenharmony_ci if (intel_gtt_can_wc()) 63162306a36Sopenharmony_ci intel_private.gtt = ioremap_wc(intel_private.gtt_phys_addr, 63262306a36Sopenharmony_ci gtt_map_size); 63362306a36Sopenharmony_ci if (intel_private.gtt == NULL) 63462306a36Sopenharmony_ci intel_private.gtt = ioremap(intel_private.gtt_phys_addr, 63562306a36Sopenharmony_ci gtt_map_size); 63662306a36Sopenharmony_ci if (intel_private.gtt == NULL) { 63762306a36Sopenharmony_ci intel_private.driver->cleanup(); 63862306a36Sopenharmony_ci iounmap(intel_private.registers); 63962306a36Sopenharmony_ci return -ENOMEM; 64062306a36Sopenharmony_ci } 64162306a36Sopenharmony_ci 64262306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_AGP_INTEL) 64362306a36Sopenharmony_ci global_cache_flush(); /* FIXME: ? */ 64462306a36Sopenharmony_ci#endif 64562306a36Sopenharmony_ci 64662306a36Sopenharmony_ci intel_private.stolen_size = intel_gtt_stolen_size(); 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_ci intel_private.needs_dmar = USE_PCI_DMA_API && INTEL_GTT_GEN > 2; 64962306a36Sopenharmony_ci 65062306a36Sopenharmony_ci ret = intel_gtt_setup_scratch_page(); 65162306a36Sopenharmony_ci if (ret != 0) { 65262306a36Sopenharmony_ci intel_gtt_cleanup(); 65362306a36Sopenharmony_ci return ret; 65462306a36Sopenharmony_ci } 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_ci if (INTEL_GTT_GEN <= 2) 65762306a36Sopenharmony_ci bar = I810_GMADR_BAR; 65862306a36Sopenharmony_ci else 65962306a36Sopenharmony_ci bar = I915_GMADR_BAR; 66062306a36Sopenharmony_ci 66162306a36Sopenharmony_ci intel_private.gma_bus_addr = pci_bus_address(intel_private.pcidev, bar); 66262306a36Sopenharmony_ci return 0; 66362306a36Sopenharmony_ci} 66462306a36Sopenharmony_ci 66562306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_AGP_INTEL) 66662306a36Sopenharmony_cistatic const struct aper_size_info_fixed intel_fake_agp_sizes[] = { 66762306a36Sopenharmony_ci {32, 8192, 3}, 66862306a36Sopenharmony_ci {64, 16384, 4}, 66962306a36Sopenharmony_ci {128, 32768, 5}, 67062306a36Sopenharmony_ci {256, 65536, 6}, 67162306a36Sopenharmony_ci {512, 131072, 7}, 67262306a36Sopenharmony_ci}; 67362306a36Sopenharmony_ci 67462306a36Sopenharmony_cistatic int intel_fake_agp_fetch_size(void) 67562306a36Sopenharmony_ci{ 67662306a36Sopenharmony_ci int num_sizes = ARRAY_SIZE(intel_fake_agp_sizes); 67762306a36Sopenharmony_ci unsigned int aper_size; 67862306a36Sopenharmony_ci int i; 67962306a36Sopenharmony_ci 68062306a36Sopenharmony_ci aper_size = (intel_private.gtt_mappable_entries << PAGE_SHIFT) / MB(1); 68162306a36Sopenharmony_ci 68262306a36Sopenharmony_ci for (i = 0; i < num_sizes; i++) { 68362306a36Sopenharmony_ci if (aper_size == intel_fake_agp_sizes[i].size) { 68462306a36Sopenharmony_ci agp_bridge->current_size = 68562306a36Sopenharmony_ci (void *) (intel_fake_agp_sizes + i); 68662306a36Sopenharmony_ci return aper_size; 68762306a36Sopenharmony_ci } 68862306a36Sopenharmony_ci } 68962306a36Sopenharmony_ci 69062306a36Sopenharmony_ci return 0; 69162306a36Sopenharmony_ci} 69262306a36Sopenharmony_ci#endif 69362306a36Sopenharmony_ci 69462306a36Sopenharmony_cistatic void i830_cleanup(void) 69562306a36Sopenharmony_ci{ 69662306a36Sopenharmony_ci} 69762306a36Sopenharmony_ci 69862306a36Sopenharmony_ci/* The chipset_flush interface needs to get data that has already been 69962306a36Sopenharmony_ci * flushed out of the CPU all the way out to main memory, because the GPU 70062306a36Sopenharmony_ci * doesn't snoop those buffers. 70162306a36Sopenharmony_ci * 70262306a36Sopenharmony_ci * The 8xx series doesn't have the same lovely interface for flushing the 70362306a36Sopenharmony_ci * chipset write buffers that the later chips do. According to the 865 70462306a36Sopenharmony_ci * specs, it's 64 octwords, or 1KB. So, to get those previous things in 70562306a36Sopenharmony_ci * that buffer out, we just fill 1KB and clflush it out, on the assumption 70662306a36Sopenharmony_ci * that it'll push whatever was in there out. It appears to work. 70762306a36Sopenharmony_ci */ 70862306a36Sopenharmony_cistatic void i830_chipset_flush(void) 70962306a36Sopenharmony_ci{ 71062306a36Sopenharmony_ci unsigned long timeout = jiffies + msecs_to_jiffies(1000); 71162306a36Sopenharmony_ci 71262306a36Sopenharmony_ci /* Forcibly evict everything from the CPU write buffers. 71362306a36Sopenharmony_ci * clflush appears to be insufficient. 71462306a36Sopenharmony_ci */ 71562306a36Sopenharmony_ci wbinvd_on_all_cpus(); 71662306a36Sopenharmony_ci 71762306a36Sopenharmony_ci /* Now we've only seen documents for this magic bit on 855GM, 71862306a36Sopenharmony_ci * we hope it exists for the other gen2 chipsets... 71962306a36Sopenharmony_ci * 72062306a36Sopenharmony_ci * Also works as advertised on my 845G. 72162306a36Sopenharmony_ci */ 72262306a36Sopenharmony_ci writel(readl(intel_private.registers+I830_HIC) | (1<<31), 72362306a36Sopenharmony_ci intel_private.registers+I830_HIC); 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_ci while (readl(intel_private.registers+I830_HIC) & (1<<31)) { 72662306a36Sopenharmony_ci if (time_after(jiffies, timeout)) 72762306a36Sopenharmony_ci break; 72862306a36Sopenharmony_ci 72962306a36Sopenharmony_ci udelay(50); 73062306a36Sopenharmony_ci } 73162306a36Sopenharmony_ci} 73262306a36Sopenharmony_ci 73362306a36Sopenharmony_cistatic void i830_write_entry(dma_addr_t addr, unsigned int entry, 73462306a36Sopenharmony_ci unsigned int flags) 73562306a36Sopenharmony_ci{ 73662306a36Sopenharmony_ci u32 pte_flags = I810_PTE_VALID; 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_ci if (flags == AGP_USER_CACHED_MEMORY) 73962306a36Sopenharmony_ci pte_flags |= I830_PTE_SYSTEM_CACHED; 74062306a36Sopenharmony_ci 74162306a36Sopenharmony_ci writel_relaxed(addr | pte_flags, intel_private.gtt + entry); 74262306a36Sopenharmony_ci} 74362306a36Sopenharmony_ci 74462306a36Sopenharmony_cibool intel_gmch_enable_gtt(void) 74562306a36Sopenharmony_ci{ 74662306a36Sopenharmony_ci u8 __iomem *reg; 74762306a36Sopenharmony_ci 74862306a36Sopenharmony_ci if (INTEL_GTT_GEN == 2) { 74962306a36Sopenharmony_ci u16 gmch_ctrl; 75062306a36Sopenharmony_ci 75162306a36Sopenharmony_ci pci_read_config_word(intel_private.bridge_dev, 75262306a36Sopenharmony_ci I830_GMCH_CTRL, &gmch_ctrl); 75362306a36Sopenharmony_ci gmch_ctrl |= I830_GMCH_ENABLED; 75462306a36Sopenharmony_ci pci_write_config_word(intel_private.bridge_dev, 75562306a36Sopenharmony_ci I830_GMCH_CTRL, gmch_ctrl); 75662306a36Sopenharmony_ci 75762306a36Sopenharmony_ci pci_read_config_word(intel_private.bridge_dev, 75862306a36Sopenharmony_ci I830_GMCH_CTRL, &gmch_ctrl); 75962306a36Sopenharmony_ci if ((gmch_ctrl & I830_GMCH_ENABLED) == 0) { 76062306a36Sopenharmony_ci dev_err(&intel_private.pcidev->dev, 76162306a36Sopenharmony_ci "failed to enable the GTT: GMCH_CTRL=%x\n", 76262306a36Sopenharmony_ci gmch_ctrl); 76362306a36Sopenharmony_ci return false; 76462306a36Sopenharmony_ci } 76562306a36Sopenharmony_ci } 76662306a36Sopenharmony_ci 76762306a36Sopenharmony_ci /* On the resume path we may be adjusting the PGTBL value, so 76862306a36Sopenharmony_ci * be paranoid and flush all chipset write buffers... 76962306a36Sopenharmony_ci */ 77062306a36Sopenharmony_ci if (INTEL_GTT_GEN >= 3) 77162306a36Sopenharmony_ci writel(0, intel_private.registers+GFX_FLSH_CNTL); 77262306a36Sopenharmony_ci 77362306a36Sopenharmony_ci reg = intel_private.registers+I810_PGETBL_CTL; 77462306a36Sopenharmony_ci writel(intel_private.PGETBL_save, reg); 77562306a36Sopenharmony_ci if (HAS_PGTBL_EN && (readl(reg) & I810_PGETBL_ENABLED) == 0) { 77662306a36Sopenharmony_ci dev_err(&intel_private.pcidev->dev, 77762306a36Sopenharmony_ci "failed to enable the GTT: PGETBL=%x [expected %x]\n", 77862306a36Sopenharmony_ci readl(reg), intel_private.PGETBL_save); 77962306a36Sopenharmony_ci return false; 78062306a36Sopenharmony_ci } 78162306a36Sopenharmony_ci 78262306a36Sopenharmony_ci if (INTEL_GTT_GEN >= 3) 78362306a36Sopenharmony_ci writel(0, intel_private.registers+GFX_FLSH_CNTL); 78462306a36Sopenharmony_ci 78562306a36Sopenharmony_ci return true; 78662306a36Sopenharmony_ci} 78762306a36Sopenharmony_ciEXPORT_SYMBOL(intel_gmch_enable_gtt); 78862306a36Sopenharmony_ci 78962306a36Sopenharmony_cistatic int i830_setup(void) 79062306a36Sopenharmony_ci{ 79162306a36Sopenharmony_ci phys_addr_t reg_addr; 79262306a36Sopenharmony_ci 79362306a36Sopenharmony_ci reg_addr = pci_resource_start(intel_private.pcidev, I810_MMADR_BAR); 79462306a36Sopenharmony_ci 79562306a36Sopenharmony_ci intel_private.registers = ioremap(reg_addr, KB(64)); 79662306a36Sopenharmony_ci if (!intel_private.registers) 79762306a36Sopenharmony_ci return -ENOMEM; 79862306a36Sopenharmony_ci 79962306a36Sopenharmony_ci intel_private.gtt_phys_addr = reg_addr + I810_PTE_BASE; 80062306a36Sopenharmony_ci 80162306a36Sopenharmony_ci return 0; 80262306a36Sopenharmony_ci} 80362306a36Sopenharmony_ci 80462306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_AGP_INTEL) 80562306a36Sopenharmony_cistatic int intel_fake_agp_create_gatt_table(struct agp_bridge_data *bridge) 80662306a36Sopenharmony_ci{ 80762306a36Sopenharmony_ci agp_bridge->gatt_table_real = NULL; 80862306a36Sopenharmony_ci agp_bridge->gatt_table = NULL; 80962306a36Sopenharmony_ci agp_bridge->gatt_bus_addr = 0; 81062306a36Sopenharmony_ci 81162306a36Sopenharmony_ci return 0; 81262306a36Sopenharmony_ci} 81362306a36Sopenharmony_ci 81462306a36Sopenharmony_cistatic int intel_fake_agp_free_gatt_table(struct agp_bridge_data *bridge) 81562306a36Sopenharmony_ci{ 81662306a36Sopenharmony_ci return 0; 81762306a36Sopenharmony_ci} 81862306a36Sopenharmony_ci 81962306a36Sopenharmony_cistatic int intel_fake_agp_configure(void) 82062306a36Sopenharmony_ci{ 82162306a36Sopenharmony_ci if (!intel_gmch_enable_gtt()) 82262306a36Sopenharmony_ci return -EIO; 82362306a36Sopenharmony_ci 82462306a36Sopenharmony_ci intel_private.clear_fake_agp = true; 82562306a36Sopenharmony_ci agp_bridge->gart_bus_addr = intel_private.gma_bus_addr; 82662306a36Sopenharmony_ci 82762306a36Sopenharmony_ci return 0; 82862306a36Sopenharmony_ci} 82962306a36Sopenharmony_ci#endif 83062306a36Sopenharmony_ci 83162306a36Sopenharmony_cistatic bool i830_check_flags(unsigned int flags) 83262306a36Sopenharmony_ci{ 83362306a36Sopenharmony_ci switch (flags) { 83462306a36Sopenharmony_ci case 0: 83562306a36Sopenharmony_ci case AGP_PHYS_MEMORY: 83662306a36Sopenharmony_ci case AGP_USER_CACHED_MEMORY: 83762306a36Sopenharmony_ci case AGP_USER_MEMORY: 83862306a36Sopenharmony_ci return true; 83962306a36Sopenharmony_ci } 84062306a36Sopenharmony_ci 84162306a36Sopenharmony_ci return false; 84262306a36Sopenharmony_ci} 84362306a36Sopenharmony_ci 84462306a36Sopenharmony_civoid intel_gmch_gtt_insert_page(dma_addr_t addr, 84562306a36Sopenharmony_ci unsigned int pg, 84662306a36Sopenharmony_ci unsigned int flags) 84762306a36Sopenharmony_ci{ 84862306a36Sopenharmony_ci intel_private.driver->write_entry(addr, pg, flags); 84962306a36Sopenharmony_ci readl(intel_private.gtt + pg); 85062306a36Sopenharmony_ci if (intel_private.driver->chipset_flush) 85162306a36Sopenharmony_ci intel_private.driver->chipset_flush(); 85262306a36Sopenharmony_ci} 85362306a36Sopenharmony_ciEXPORT_SYMBOL(intel_gmch_gtt_insert_page); 85462306a36Sopenharmony_ci 85562306a36Sopenharmony_civoid intel_gmch_gtt_insert_sg_entries(struct sg_table *st, 85662306a36Sopenharmony_ci unsigned int pg_start, 85762306a36Sopenharmony_ci unsigned int flags) 85862306a36Sopenharmony_ci{ 85962306a36Sopenharmony_ci struct scatterlist *sg; 86062306a36Sopenharmony_ci unsigned int len, m; 86162306a36Sopenharmony_ci int i, j; 86262306a36Sopenharmony_ci 86362306a36Sopenharmony_ci j = pg_start; 86462306a36Sopenharmony_ci 86562306a36Sopenharmony_ci /* sg may merge pages, but we have to separate 86662306a36Sopenharmony_ci * per-page addr for GTT */ 86762306a36Sopenharmony_ci for_each_sg(st->sgl, sg, st->nents, i) { 86862306a36Sopenharmony_ci len = sg_dma_len(sg) >> PAGE_SHIFT; 86962306a36Sopenharmony_ci for (m = 0; m < len; m++) { 87062306a36Sopenharmony_ci dma_addr_t addr = sg_dma_address(sg) + (m << PAGE_SHIFT); 87162306a36Sopenharmony_ci intel_private.driver->write_entry(addr, j, flags); 87262306a36Sopenharmony_ci j++; 87362306a36Sopenharmony_ci } 87462306a36Sopenharmony_ci } 87562306a36Sopenharmony_ci readl(intel_private.gtt + j - 1); 87662306a36Sopenharmony_ci if (intel_private.driver->chipset_flush) 87762306a36Sopenharmony_ci intel_private.driver->chipset_flush(); 87862306a36Sopenharmony_ci} 87962306a36Sopenharmony_ciEXPORT_SYMBOL(intel_gmch_gtt_insert_sg_entries); 88062306a36Sopenharmony_ci 88162306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_AGP_INTEL) 88262306a36Sopenharmony_cistatic void intel_gmch_gtt_insert_pages(unsigned int first_entry, 88362306a36Sopenharmony_ci unsigned int num_entries, 88462306a36Sopenharmony_ci struct page **pages, 88562306a36Sopenharmony_ci unsigned int flags) 88662306a36Sopenharmony_ci{ 88762306a36Sopenharmony_ci int i, j; 88862306a36Sopenharmony_ci 88962306a36Sopenharmony_ci for (i = 0, j = first_entry; i < num_entries; i++, j++) { 89062306a36Sopenharmony_ci dma_addr_t addr = page_to_phys(pages[i]); 89162306a36Sopenharmony_ci intel_private.driver->write_entry(addr, 89262306a36Sopenharmony_ci j, flags); 89362306a36Sopenharmony_ci } 89462306a36Sopenharmony_ci wmb(); 89562306a36Sopenharmony_ci} 89662306a36Sopenharmony_ci 89762306a36Sopenharmony_cistatic int intel_fake_agp_insert_entries(struct agp_memory *mem, 89862306a36Sopenharmony_ci off_t pg_start, int type) 89962306a36Sopenharmony_ci{ 90062306a36Sopenharmony_ci int ret = -EINVAL; 90162306a36Sopenharmony_ci 90262306a36Sopenharmony_ci if (intel_private.clear_fake_agp) { 90362306a36Sopenharmony_ci int start = intel_private.stolen_size / PAGE_SIZE; 90462306a36Sopenharmony_ci int end = intel_private.gtt_mappable_entries; 90562306a36Sopenharmony_ci intel_gmch_gtt_clear_range(start, end - start); 90662306a36Sopenharmony_ci intel_private.clear_fake_agp = false; 90762306a36Sopenharmony_ci } 90862306a36Sopenharmony_ci 90962306a36Sopenharmony_ci if (INTEL_GTT_GEN == 1 && type == AGP_DCACHE_MEMORY) 91062306a36Sopenharmony_ci return i810_insert_dcache_entries(mem, pg_start, type); 91162306a36Sopenharmony_ci 91262306a36Sopenharmony_ci if (mem->page_count == 0) 91362306a36Sopenharmony_ci goto out; 91462306a36Sopenharmony_ci 91562306a36Sopenharmony_ci if (pg_start + mem->page_count > intel_private.gtt_total_entries) 91662306a36Sopenharmony_ci goto out_err; 91762306a36Sopenharmony_ci 91862306a36Sopenharmony_ci if (type != mem->type) 91962306a36Sopenharmony_ci goto out_err; 92062306a36Sopenharmony_ci 92162306a36Sopenharmony_ci if (!intel_private.driver->check_flags(type)) 92262306a36Sopenharmony_ci goto out_err; 92362306a36Sopenharmony_ci 92462306a36Sopenharmony_ci if (!mem->is_flushed) 92562306a36Sopenharmony_ci global_cache_flush(); 92662306a36Sopenharmony_ci 92762306a36Sopenharmony_ci if (intel_private.needs_dmar) { 92862306a36Sopenharmony_ci struct sg_table st; 92962306a36Sopenharmony_ci 93062306a36Sopenharmony_ci ret = intel_gtt_map_memory(mem->pages, mem->page_count, &st); 93162306a36Sopenharmony_ci if (ret != 0) 93262306a36Sopenharmony_ci return ret; 93362306a36Sopenharmony_ci 93462306a36Sopenharmony_ci intel_gmch_gtt_insert_sg_entries(&st, pg_start, type); 93562306a36Sopenharmony_ci mem->sg_list = st.sgl; 93662306a36Sopenharmony_ci mem->num_sg = st.nents; 93762306a36Sopenharmony_ci } else 93862306a36Sopenharmony_ci intel_gmch_gtt_insert_pages(pg_start, mem->page_count, mem->pages, 93962306a36Sopenharmony_ci type); 94062306a36Sopenharmony_ci 94162306a36Sopenharmony_ciout: 94262306a36Sopenharmony_ci ret = 0; 94362306a36Sopenharmony_ciout_err: 94462306a36Sopenharmony_ci mem->is_flushed = true; 94562306a36Sopenharmony_ci return ret; 94662306a36Sopenharmony_ci} 94762306a36Sopenharmony_ci#endif 94862306a36Sopenharmony_ci 94962306a36Sopenharmony_civoid intel_gmch_gtt_clear_range(unsigned int first_entry, unsigned int num_entries) 95062306a36Sopenharmony_ci{ 95162306a36Sopenharmony_ci unsigned int i; 95262306a36Sopenharmony_ci 95362306a36Sopenharmony_ci for (i = first_entry; i < (first_entry + num_entries); i++) { 95462306a36Sopenharmony_ci intel_private.driver->write_entry(intel_private.scratch_page_dma, 95562306a36Sopenharmony_ci i, 0); 95662306a36Sopenharmony_ci } 95762306a36Sopenharmony_ci wmb(); 95862306a36Sopenharmony_ci} 95962306a36Sopenharmony_ciEXPORT_SYMBOL(intel_gmch_gtt_clear_range); 96062306a36Sopenharmony_ci 96162306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_AGP_INTEL) 96262306a36Sopenharmony_cistatic int intel_fake_agp_remove_entries(struct agp_memory *mem, 96362306a36Sopenharmony_ci off_t pg_start, int type) 96462306a36Sopenharmony_ci{ 96562306a36Sopenharmony_ci if (mem->page_count == 0) 96662306a36Sopenharmony_ci return 0; 96762306a36Sopenharmony_ci 96862306a36Sopenharmony_ci intel_gmch_gtt_clear_range(pg_start, mem->page_count); 96962306a36Sopenharmony_ci 97062306a36Sopenharmony_ci if (intel_private.needs_dmar) { 97162306a36Sopenharmony_ci intel_gtt_unmap_memory(mem->sg_list, mem->num_sg); 97262306a36Sopenharmony_ci mem->sg_list = NULL; 97362306a36Sopenharmony_ci mem->num_sg = 0; 97462306a36Sopenharmony_ci } 97562306a36Sopenharmony_ci 97662306a36Sopenharmony_ci return 0; 97762306a36Sopenharmony_ci} 97862306a36Sopenharmony_ci 97962306a36Sopenharmony_cistatic struct agp_memory *intel_fake_agp_alloc_by_type(size_t pg_count, 98062306a36Sopenharmony_ci int type) 98162306a36Sopenharmony_ci{ 98262306a36Sopenharmony_ci struct agp_memory *new; 98362306a36Sopenharmony_ci 98462306a36Sopenharmony_ci if (type == AGP_DCACHE_MEMORY && INTEL_GTT_GEN == 1) { 98562306a36Sopenharmony_ci if (pg_count != intel_private.num_dcache_entries) 98662306a36Sopenharmony_ci return NULL; 98762306a36Sopenharmony_ci 98862306a36Sopenharmony_ci new = agp_create_memory(1); 98962306a36Sopenharmony_ci if (new == NULL) 99062306a36Sopenharmony_ci return NULL; 99162306a36Sopenharmony_ci 99262306a36Sopenharmony_ci new->type = AGP_DCACHE_MEMORY; 99362306a36Sopenharmony_ci new->page_count = pg_count; 99462306a36Sopenharmony_ci new->num_scratch_pages = 0; 99562306a36Sopenharmony_ci agp_free_page_array(new); 99662306a36Sopenharmony_ci return new; 99762306a36Sopenharmony_ci } 99862306a36Sopenharmony_ci if (type == AGP_PHYS_MEMORY) 99962306a36Sopenharmony_ci return alloc_agpphysmem_i8xx(pg_count, type); 100062306a36Sopenharmony_ci /* always return NULL for other allocation types for now */ 100162306a36Sopenharmony_ci return NULL; 100262306a36Sopenharmony_ci} 100362306a36Sopenharmony_ci#endif 100462306a36Sopenharmony_ci 100562306a36Sopenharmony_cistatic int intel_alloc_chipset_flush_resource(void) 100662306a36Sopenharmony_ci{ 100762306a36Sopenharmony_ci int ret; 100862306a36Sopenharmony_ci ret = pci_bus_alloc_resource(intel_private.bridge_dev->bus, &intel_private.ifp_resource, PAGE_SIZE, 100962306a36Sopenharmony_ci PAGE_SIZE, PCIBIOS_MIN_MEM, 0, 101062306a36Sopenharmony_ci pcibios_align_resource, intel_private.bridge_dev); 101162306a36Sopenharmony_ci 101262306a36Sopenharmony_ci return ret; 101362306a36Sopenharmony_ci} 101462306a36Sopenharmony_ci 101562306a36Sopenharmony_cistatic void intel_i915_setup_chipset_flush(void) 101662306a36Sopenharmony_ci{ 101762306a36Sopenharmony_ci int ret; 101862306a36Sopenharmony_ci u32 temp; 101962306a36Sopenharmony_ci 102062306a36Sopenharmony_ci pci_read_config_dword(intel_private.bridge_dev, I915_IFPADDR, &temp); 102162306a36Sopenharmony_ci if (!(temp & 0x1)) { 102262306a36Sopenharmony_ci intel_alloc_chipset_flush_resource(); 102362306a36Sopenharmony_ci intel_private.resource_valid = 1; 102462306a36Sopenharmony_ci pci_write_config_dword(intel_private.bridge_dev, I915_IFPADDR, (intel_private.ifp_resource.start & 0xffffffff) | 0x1); 102562306a36Sopenharmony_ci } else { 102662306a36Sopenharmony_ci temp &= ~1; 102762306a36Sopenharmony_ci 102862306a36Sopenharmony_ci intel_private.resource_valid = 1; 102962306a36Sopenharmony_ci intel_private.ifp_resource.start = temp; 103062306a36Sopenharmony_ci intel_private.ifp_resource.end = temp + PAGE_SIZE; 103162306a36Sopenharmony_ci ret = request_resource(&iomem_resource, &intel_private.ifp_resource); 103262306a36Sopenharmony_ci /* some BIOSes reserve this area in a pnp some don't */ 103362306a36Sopenharmony_ci if (ret) 103462306a36Sopenharmony_ci intel_private.resource_valid = 0; 103562306a36Sopenharmony_ci } 103662306a36Sopenharmony_ci} 103762306a36Sopenharmony_ci 103862306a36Sopenharmony_cistatic void intel_i965_g33_setup_chipset_flush(void) 103962306a36Sopenharmony_ci{ 104062306a36Sopenharmony_ci u32 temp_hi, temp_lo; 104162306a36Sopenharmony_ci int ret; 104262306a36Sopenharmony_ci 104362306a36Sopenharmony_ci pci_read_config_dword(intel_private.bridge_dev, I965_IFPADDR + 4, &temp_hi); 104462306a36Sopenharmony_ci pci_read_config_dword(intel_private.bridge_dev, I965_IFPADDR, &temp_lo); 104562306a36Sopenharmony_ci 104662306a36Sopenharmony_ci if (!(temp_lo & 0x1)) { 104762306a36Sopenharmony_ci 104862306a36Sopenharmony_ci intel_alloc_chipset_flush_resource(); 104962306a36Sopenharmony_ci 105062306a36Sopenharmony_ci intel_private.resource_valid = 1; 105162306a36Sopenharmony_ci pci_write_config_dword(intel_private.bridge_dev, I965_IFPADDR + 4, 105262306a36Sopenharmony_ci upper_32_bits(intel_private.ifp_resource.start)); 105362306a36Sopenharmony_ci pci_write_config_dword(intel_private.bridge_dev, I965_IFPADDR, (intel_private.ifp_resource.start & 0xffffffff) | 0x1); 105462306a36Sopenharmony_ci } else { 105562306a36Sopenharmony_ci u64 l64; 105662306a36Sopenharmony_ci 105762306a36Sopenharmony_ci temp_lo &= ~0x1; 105862306a36Sopenharmony_ci l64 = ((u64)temp_hi << 32) | temp_lo; 105962306a36Sopenharmony_ci 106062306a36Sopenharmony_ci intel_private.resource_valid = 1; 106162306a36Sopenharmony_ci intel_private.ifp_resource.start = l64; 106262306a36Sopenharmony_ci intel_private.ifp_resource.end = l64 + PAGE_SIZE; 106362306a36Sopenharmony_ci ret = request_resource(&iomem_resource, &intel_private.ifp_resource); 106462306a36Sopenharmony_ci /* some BIOSes reserve this area in a pnp some don't */ 106562306a36Sopenharmony_ci if (ret) 106662306a36Sopenharmony_ci intel_private.resource_valid = 0; 106762306a36Sopenharmony_ci } 106862306a36Sopenharmony_ci} 106962306a36Sopenharmony_ci 107062306a36Sopenharmony_cistatic void intel_i9xx_setup_flush(void) 107162306a36Sopenharmony_ci{ 107262306a36Sopenharmony_ci /* return if already configured */ 107362306a36Sopenharmony_ci if (intel_private.ifp_resource.start) 107462306a36Sopenharmony_ci return; 107562306a36Sopenharmony_ci 107662306a36Sopenharmony_ci if (INTEL_GTT_GEN == 6) 107762306a36Sopenharmony_ci return; 107862306a36Sopenharmony_ci 107962306a36Sopenharmony_ci /* setup a resource for this object */ 108062306a36Sopenharmony_ci intel_private.ifp_resource.name = "Intel Flush Page"; 108162306a36Sopenharmony_ci intel_private.ifp_resource.flags = IORESOURCE_MEM; 108262306a36Sopenharmony_ci 108362306a36Sopenharmony_ci /* Setup chipset flush for 915 */ 108462306a36Sopenharmony_ci if (IS_G33 || INTEL_GTT_GEN >= 4) { 108562306a36Sopenharmony_ci intel_i965_g33_setup_chipset_flush(); 108662306a36Sopenharmony_ci } else { 108762306a36Sopenharmony_ci intel_i915_setup_chipset_flush(); 108862306a36Sopenharmony_ci } 108962306a36Sopenharmony_ci 109062306a36Sopenharmony_ci if (intel_private.ifp_resource.start) 109162306a36Sopenharmony_ci intel_private.i9xx_flush_page = ioremap(intel_private.ifp_resource.start, PAGE_SIZE); 109262306a36Sopenharmony_ci if (!intel_private.i9xx_flush_page) 109362306a36Sopenharmony_ci dev_err(&intel_private.pcidev->dev, 109462306a36Sopenharmony_ci "can't ioremap flush page - no chipset flushing\n"); 109562306a36Sopenharmony_ci} 109662306a36Sopenharmony_ci 109762306a36Sopenharmony_cistatic void i9xx_cleanup(void) 109862306a36Sopenharmony_ci{ 109962306a36Sopenharmony_ci if (intel_private.i9xx_flush_page) 110062306a36Sopenharmony_ci iounmap(intel_private.i9xx_flush_page); 110162306a36Sopenharmony_ci if (intel_private.resource_valid) 110262306a36Sopenharmony_ci release_resource(&intel_private.ifp_resource); 110362306a36Sopenharmony_ci intel_private.ifp_resource.start = 0; 110462306a36Sopenharmony_ci intel_private.resource_valid = 0; 110562306a36Sopenharmony_ci} 110662306a36Sopenharmony_ci 110762306a36Sopenharmony_cistatic void i9xx_chipset_flush(void) 110862306a36Sopenharmony_ci{ 110962306a36Sopenharmony_ci wmb(); 111062306a36Sopenharmony_ci if (intel_private.i9xx_flush_page) 111162306a36Sopenharmony_ci writel(1, intel_private.i9xx_flush_page); 111262306a36Sopenharmony_ci} 111362306a36Sopenharmony_ci 111462306a36Sopenharmony_cistatic void i965_write_entry(dma_addr_t addr, 111562306a36Sopenharmony_ci unsigned int entry, 111662306a36Sopenharmony_ci unsigned int flags) 111762306a36Sopenharmony_ci{ 111862306a36Sopenharmony_ci u32 pte_flags; 111962306a36Sopenharmony_ci 112062306a36Sopenharmony_ci pte_flags = I810_PTE_VALID; 112162306a36Sopenharmony_ci if (flags == AGP_USER_CACHED_MEMORY) 112262306a36Sopenharmony_ci pte_flags |= I830_PTE_SYSTEM_CACHED; 112362306a36Sopenharmony_ci 112462306a36Sopenharmony_ci /* Shift high bits down */ 112562306a36Sopenharmony_ci addr |= (addr >> 28) & 0xf0; 112662306a36Sopenharmony_ci writel_relaxed(addr | pte_flags, intel_private.gtt + entry); 112762306a36Sopenharmony_ci} 112862306a36Sopenharmony_ci 112962306a36Sopenharmony_cistatic int i9xx_setup(void) 113062306a36Sopenharmony_ci{ 113162306a36Sopenharmony_ci phys_addr_t reg_addr; 113262306a36Sopenharmony_ci int size = KB(512); 113362306a36Sopenharmony_ci 113462306a36Sopenharmony_ci reg_addr = pci_resource_start(intel_private.pcidev, I915_MMADR_BAR); 113562306a36Sopenharmony_ci 113662306a36Sopenharmony_ci intel_private.registers = ioremap(reg_addr, size); 113762306a36Sopenharmony_ci if (!intel_private.registers) 113862306a36Sopenharmony_ci return -ENOMEM; 113962306a36Sopenharmony_ci 114062306a36Sopenharmony_ci switch (INTEL_GTT_GEN) { 114162306a36Sopenharmony_ci case 3: 114262306a36Sopenharmony_ci intel_private.gtt_phys_addr = 114362306a36Sopenharmony_ci pci_resource_start(intel_private.pcidev, I915_PTE_BAR); 114462306a36Sopenharmony_ci break; 114562306a36Sopenharmony_ci case 5: 114662306a36Sopenharmony_ci intel_private.gtt_phys_addr = reg_addr + MB(2); 114762306a36Sopenharmony_ci break; 114862306a36Sopenharmony_ci default: 114962306a36Sopenharmony_ci intel_private.gtt_phys_addr = reg_addr + KB(512); 115062306a36Sopenharmony_ci break; 115162306a36Sopenharmony_ci } 115262306a36Sopenharmony_ci 115362306a36Sopenharmony_ci intel_i9xx_setup_flush(); 115462306a36Sopenharmony_ci 115562306a36Sopenharmony_ci return 0; 115662306a36Sopenharmony_ci} 115762306a36Sopenharmony_ci 115862306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_AGP_INTEL) 115962306a36Sopenharmony_cistatic const struct agp_bridge_driver intel_fake_agp_driver = { 116062306a36Sopenharmony_ci .owner = THIS_MODULE, 116162306a36Sopenharmony_ci .size_type = FIXED_APER_SIZE, 116262306a36Sopenharmony_ci .aperture_sizes = intel_fake_agp_sizes, 116362306a36Sopenharmony_ci .num_aperture_sizes = ARRAY_SIZE(intel_fake_agp_sizes), 116462306a36Sopenharmony_ci .configure = intel_fake_agp_configure, 116562306a36Sopenharmony_ci .fetch_size = intel_fake_agp_fetch_size, 116662306a36Sopenharmony_ci .cleanup = intel_gtt_cleanup, 116762306a36Sopenharmony_ci .agp_enable = intel_fake_agp_enable, 116862306a36Sopenharmony_ci .cache_flush = global_cache_flush, 116962306a36Sopenharmony_ci .create_gatt_table = intel_fake_agp_create_gatt_table, 117062306a36Sopenharmony_ci .free_gatt_table = intel_fake_agp_free_gatt_table, 117162306a36Sopenharmony_ci .insert_memory = intel_fake_agp_insert_entries, 117262306a36Sopenharmony_ci .remove_memory = intel_fake_agp_remove_entries, 117362306a36Sopenharmony_ci .alloc_by_type = intel_fake_agp_alloc_by_type, 117462306a36Sopenharmony_ci .free_by_type = intel_i810_free_by_type, 117562306a36Sopenharmony_ci .agp_alloc_page = agp_generic_alloc_page, 117662306a36Sopenharmony_ci .agp_alloc_pages = agp_generic_alloc_pages, 117762306a36Sopenharmony_ci .agp_destroy_page = agp_generic_destroy_page, 117862306a36Sopenharmony_ci .agp_destroy_pages = agp_generic_destroy_pages, 117962306a36Sopenharmony_ci}; 118062306a36Sopenharmony_ci#endif 118162306a36Sopenharmony_ci 118262306a36Sopenharmony_cistatic const struct intel_gtt_driver i81x_gtt_driver = { 118362306a36Sopenharmony_ci .gen = 1, 118462306a36Sopenharmony_ci .has_pgtbl_enable = 1, 118562306a36Sopenharmony_ci .dma_mask_size = 32, 118662306a36Sopenharmony_ci .setup = i810_setup, 118762306a36Sopenharmony_ci .cleanup = i810_cleanup, 118862306a36Sopenharmony_ci .check_flags = i830_check_flags, 118962306a36Sopenharmony_ci .write_entry = i810_write_entry, 119062306a36Sopenharmony_ci}; 119162306a36Sopenharmony_cistatic const struct intel_gtt_driver i8xx_gtt_driver = { 119262306a36Sopenharmony_ci .gen = 2, 119362306a36Sopenharmony_ci .has_pgtbl_enable = 1, 119462306a36Sopenharmony_ci .setup = i830_setup, 119562306a36Sopenharmony_ci .cleanup = i830_cleanup, 119662306a36Sopenharmony_ci .write_entry = i830_write_entry, 119762306a36Sopenharmony_ci .dma_mask_size = 32, 119862306a36Sopenharmony_ci .check_flags = i830_check_flags, 119962306a36Sopenharmony_ci .chipset_flush = i830_chipset_flush, 120062306a36Sopenharmony_ci}; 120162306a36Sopenharmony_cistatic const struct intel_gtt_driver i915_gtt_driver = { 120262306a36Sopenharmony_ci .gen = 3, 120362306a36Sopenharmony_ci .has_pgtbl_enable = 1, 120462306a36Sopenharmony_ci .setup = i9xx_setup, 120562306a36Sopenharmony_ci .cleanup = i9xx_cleanup, 120662306a36Sopenharmony_ci /* i945 is the last gpu to need phys mem (for overlay and cursors). */ 120762306a36Sopenharmony_ci .write_entry = i830_write_entry, 120862306a36Sopenharmony_ci .dma_mask_size = 32, 120962306a36Sopenharmony_ci .check_flags = i830_check_flags, 121062306a36Sopenharmony_ci .chipset_flush = i9xx_chipset_flush, 121162306a36Sopenharmony_ci}; 121262306a36Sopenharmony_cistatic const struct intel_gtt_driver g33_gtt_driver = { 121362306a36Sopenharmony_ci .gen = 3, 121462306a36Sopenharmony_ci .is_g33 = 1, 121562306a36Sopenharmony_ci .setup = i9xx_setup, 121662306a36Sopenharmony_ci .cleanup = i9xx_cleanup, 121762306a36Sopenharmony_ci .write_entry = i965_write_entry, 121862306a36Sopenharmony_ci .dma_mask_size = 36, 121962306a36Sopenharmony_ci .check_flags = i830_check_flags, 122062306a36Sopenharmony_ci .chipset_flush = i9xx_chipset_flush, 122162306a36Sopenharmony_ci}; 122262306a36Sopenharmony_cistatic const struct intel_gtt_driver pineview_gtt_driver = { 122362306a36Sopenharmony_ci .gen = 3, 122462306a36Sopenharmony_ci .is_pineview = 1, .is_g33 = 1, 122562306a36Sopenharmony_ci .setup = i9xx_setup, 122662306a36Sopenharmony_ci .cleanup = i9xx_cleanup, 122762306a36Sopenharmony_ci .write_entry = i965_write_entry, 122862306a36Sopenharmony_ci .dma_mask_size = 36, 122962306a36Sopenharmony_ci .check_flags = i830_check_flags, 123062306a36Sopenharmony_ci .chipset_flush = i9xx_chipset_flush, 123162306a36Sopenharmony_ci}; 123262306a36Sopenharmony_cistatic const struct intel_gtt_driver i965_gtt_driver = { 123362306a36Sopenharmony_ci .gen = 4, 123462306a36Sopenharmony_ci .has_pgtbl_enable = 1, 123562306a36Sopenharmony_ci .setup = i9xx_setup, 123662306a36Sopenharmony_ci .cleanup = i9xx_cleanup, 123762306a36Sopenharmony_ci .write_entry = i965_write_entry, 123862306a36Sopenharmony_ci .dma_mask_size = 36, 123962306a36Sopenharmony_ci .check_flags = i830_check_flags, 124062306a36Sopenharmony_ci .chipset_flush = i9xx_chipset_flush, 124162306a36Sopenharmony_ci}; 124262306a36Sopenharmony_cistatic const struct intel_gtt_driver g4x_gtt_driver = { 124362306a36Sopenharmony_ci .gen = 5, 124462306a36Sopenharmony_ci .setup = i9xx_setup, 124562306a36Sopenharmony_ci .cleanup = i9xx_cleanup, 124662306a36Sopenharmony_ci .write_entry = i965_write_entry, 124762306a36Sopenharmony_ci .dma_mask_size = 36, 124862306a36Sopenharmony_ci .check_flags = i830_check_flags, 124962306a36Sopenharmony_ci .chipset_flush = i9xx_chipset_flush, 125062306a36Sopenharmony_ci}; 125162306a36Sopenharmony_cistatic const struct intel_gtt_driver ironlake_gtt_driver = { 125262306a36Sopenharmony_ci .gen = 5, 125362306a36Sopenharmony_ci .is_ironlake = 1, 125462306a36Sopenharmony_ci .setup = i9xx_setup, 125562306a36Sopenharmony_ci .cleanup = i9xx_cleanup, 125662306a36Sopenharmony_ci .write_entry = i965_write_entry, 125762306a36Sopenharmony_ci .dma_mask_size = 36, 125862306a36Sopenharmony_ci .check_flags = i830_check_flags, 125962306a36Sopenharmony_ci .chipset_flush = i9xx_chipset_flush, 126062306a36Sopenharmony_ci}; 126162306a36Sopenharmony_ci 126262306a36Sopenharmony_ci/* Table to describe Intel GMCH and AGP/PCIE GART drivers. At least one of 126362306a36Sopenharmony_ci * driver and gmch_driver must be non-null, and find_gmch will determine 126462306a36Sopenharmony_ci * which one should be used if a gmch_chip_id is present. 126562306a36Sopenharmony_ci */ 126662306a36Sopenharmony_cistatic const struct intel_gtt_driver_description { 126762306a36Sopenharmony_ci unsigned int gmch_chip_id; 126862306a36Sopenharmony_ci char *name; 126962306a36Sopenharmony_ci const struct intel_gtt_driver *gtt_driver; 127062306a36Sopenharmony_ci} intel_gtt_chipsets[] = { 127162306a36Sopenharmony_ci { PCI_DEVICE_ID_INTEL_82810_IG1, "i810", 127262306a36Sopenharmony_ci &i81x_gtt_driver}, 127362306a36Sopenharmony_ci { PCI_DEVICE_ID_INTEL_82810_IG3, "i810", 127462306a36Sopenharmony_ci &i81x_gtt_driver}, 127562306a36Sopenharmony_ci { PCI_DEVICE_ID_INTEL_82810E_IG, "i810", 127662306a36Sopenharmony_ci &i81x_gtt_driver}, 127762306a36Sopenharmony_ci { PCI_DEVICE_ID_INTEL_82815_CGC, "i815", 127862306a36Sopenharmony_ci &i81x_gtt_driver}, 127962306a36Sopenharmony_ci { PCI_DEVICE_ID_INTEL_82830_CGC, "830M", 128062306a36Sopenharmony_ci &i8xx_gtt_driver}, 128162306a36Sopenharmony_ci { PCI_DEVICE_ID_INTEL_82845G_IG, "845G", 128262306a36Sopenharmony_ci &i8xx_gtt_driver}, 128362306a36Sopenharmony_ci { PCI_DEVICE_ID_INTEL_82854_IG, "854", 128462306a36Sopenharmony_ci &i8xx_gtt_driver}, 128562306a36Sopenharmony_ci { PCI_DEVICE_ID_INTEL_82855GM_IG, "855GM", 128662306a36Sopenharmony_ci &i8xx_gtt_driver}, 128762306a36Sopenharmony_ci { PCI_DEVICE_ID_INTEL_82865_IG, "865", 128862306a36Sopenharmony_ci &i8xx_gtt_driver}, 128962306a36Sopenharmony_ci { PCI_DEVICE_ID_INTEL_E7221_IG, "E7221 (i915)", 129062306a36Sopenharmony_ci &i915_gtt_driver }, 129162306a36Sopenharmony_ci { PCI_DEVICE_ID_INTEL_82915G_IG, "915G", 129262306a36Sopenharmony_ci &i915_gtt_driver }, 129362306a36Sopenharmony_ci { PCI_DEVICE_ID_INTEL_82915GM_IG, "915GM", 129462306a36Sopenharmony_ci &i915_gtt_driver }, 129562306a36Sopenharmony_ci { PCI_DEVICE_ID_INTEL_82945G_IG, "945G", 129662306a36Sopenharmony_ci &i915_gtt_driver }, 129762306a36Sopenharmony_ci { PCI_DEVICE_ID_INTEL_82945GM_IG, "945GM", 129862306a36Sopenharmony_ci &i915_gtt_driver }, 129962306a36Sopenharmony_ci { PCI_DEVICE_ID_INTEL_82945GME_IG, "945GME", 130062306a36Sopenharmony_ci &i915_gtt_driver }, 130162306a36Sopenharmony_ci { PCI_DEVICE_ID_INTEL_82946GZ_IG, "946GZ", 130262306a36Sopenharmony_ci &i965_gtt_driver }, 130362306a36Sopenharmony_ci { PCI_DEVICE_ID_INTEL_82G35_IG, "G35", 130462306a36Sopenharmony_ci &i965_gtt_driver }, 130562306a36Sopenharmony_ci { PCI_DEVICE_ID_INTEL_82965Q_IG, "965Q", 130662306a36Sopenharmony_ci &i965_gtt_driver }, 130762306a36Sopenharmony_ci { PCI_DEVICE_ID_INTEL_82965G_IG, "965G", 130862306a36Sopenharmony_ci &i965_gtt_driver }, 130962306a36Sopenharmony_ci { PCI_DEVICE_ID_INTEL_82965GM_IG, "965GM", 131062306a36Sopenharmony_ci &i965_gtt_driver }, 131162306a36Sopenharmony_ci { PCI_DEVICE_ID_INTEL_82965GME_IG, "965GME/GLE", 131262306a36Sopenharmony_ci &i965_gtt_driver }, 131362306a36Sopenharmony_ci { PCI_DEVICE_ID_INTEL_G33_IG, "G33", 131462306a36Sopenharmony_ci &g33_gtt_driver }, 131562306a36Sopenharmony_ci { PCI_DEVICE_ID_INTEL_Q35_IG, "Q35", 131662306a36Sopenharmony_ci &g33_gtt_driver }, 131762306a36Sopenharmony_ci { PCI_DEVICE_ID_INTEL_Q33_IG, "Q33", 131862306a36Sopenharmony_ci &g33_gtt_driver }, 131962306a36Sopenharmony_ci { PCI_DEVICE_ID_INTEL_PINEVIEW_M_IG, "GMA3150", 132062306a36Sopenharmony_ci &pineview_gtt_driver }, 132162306a36Sopenharmony_ci { PCI_DEVICE_ID_INTEL_PINEVIEW_IG, "GMA3150", 132262306a36Sopenharmony_ci &pineview_gtt_driver }, 132362306a36Sopenharmony_ci { PCI_DEVICE_ID_INTEL_GM45_IG, "GM45", 132462306a36Sopenharmony_ci &g4x_gtt_driver }, 132562306a36Sopenharmony_ci { PCI_DEVICE_ID_INTEL_EAGLELAKE_IG, "Eaglelake", 132662306a36Sopenharmony_ci &g4x_gtt_driver }, 132762306a36Sopenharmony_ci { PCI_DEVICE_ID_INTEL_Q45_IG, "Q45/Q43", 132862306a36Sopenharmony_ci &g4x_gtt_driver }, 132962306a36Sopenharmony_ci { PCI_DEVICE_ID_INTEL_G45_IG, "G45/G43", 133062306a36Sopenharmony_ci &g4x_gtt_driver }, 133162306a36Sopenharmony_ci { PCI_DEVICE_ID_INTEL_B43_IG, "B43", 133262306a36Sopenharmony_ci &g4x_gtt_driver }, 133362306a36Sopenharmony_ci { PCI_DEVICE_ID_INTEL_B43_1_IG, "B43", 133462306a36Sopenharmony_ci &g4x_gtt_driver }, 133562306a36Sopenharmony_ci { PCI_DEVICE_ID_INTEL_G41_IG, "G41", 133662306a36Sopenharmony_ci &g4x_gtt_driver }, 133762306a36Sopenharmony_ci { PCI_DEVICE_ID_INTEL_IRONLAKE_D_IG, 133862306a36Sopenharmony_ci "HD Graphics", &ironlake_gtt_driver }, 133962306a36Sopenharmony_ci { PCI_DEVICE_ID_INTEL_IRONLAKE_M_IG, 134062306a36Sopenharmony_ci "HD Graphics", &ironlake_gtt_driver }, 134162306a36Sopenharmony_ci { 0, NULL, NULL } 134262306a36Sopenharmony_ci}; 134362306a36Sopenharmony_ci 134462306a36Sopenharmony_cistatic int find_gmch(u16 device) 134562306a36Sopenharmony_ci{ 134662306a36Sopenharmony_ci struct pci_dev *gmch_device; 134762306a36Sopenharmony_ci 134862306a36Sopenharmony_ci gmch_device = pci_get_device(PCI_VENDOR_ID_INTEL, device, NULL); 134962306a36Sopenharmony_ci if (gmch_device && PCI_FUNC(gmch_device->devfn) != 0) { 135062306a36Sopenharmony_ci gmch_device = pci_get_device(PCI_VENDOR_ID_INTEL, 135162306a36Sopenharmony_ci device, gmch_device); 135262306a36Sopenharmony_ci } 135362306a36Sopenharmony_ci 135462306a36Sopenharmony_ci if (!gmch_device) 135562306a36Sopenharmony_ci return 0; 135662306a36Sopenharmony_ci 135762306a36Sopenharmony_ci intel_private.pcidev = gmch_device; 135862306a36Sopenharmony_ci return 1; 135962306a36Sopenharmony_ci} 136062306a36Sopenharmony_ci 136162306a36Sopenharmony_ciint intel_gmch_probe(struct pci_dev *bridge_pdev, struct pci_dev *gpu_pdev, 136262306a36Sopenharmony_ci struct agp_bridge_data *bridge) 136362306a36Sopenharmony_ci{ 136462306a36Sopenharmony_ci int i, mask; 136562306a36Sopenharmony_ci 136662306a36Sopenharmony_ci for (i = 0; intel_gtt_chipsets[i].name != NULL; i++) { 136762306a36Sopenharmony_ci if (gpu_pdev) { 136862306a36Sopenharmony_ci if (gpu_pdev->device == 136962306a36Sopenharmony_ci intel_gtt_chipsets[i].gmch_chip_id) { 137062306a36Sopenharmony_ci intel_private.pcidev = pci_dev_get(gpu_pdev); 137162306a36Sopenharmony_ci intel_private.driver = 137262306a36Sopenharmony_ci intel_gtt_chipsets[i].gtt_driver; 137362306a36Sopenharmony_ci 137462306a36Sopenharmony_ci break; 137562306a36Sopenharmony_ci } 137662306a36Sopenharmony_ci } else if (find_gmch(intel_gtt_chipsets[i].gmch_chip_id)) { 137762306a36Sopenharmony_ci intel_private.driver = 137862306a36Sopenharmony_ci intel_gtt_chipsets[i].gtt_driver; 137962306a36Sopenharmony_ci break; 138062306a36Sopenharmony_ci } 138162306a36Sopenharmony_ci } 138262306a36Sopenharmony_ci 138362306a36Sopenharmony_ci if (!intel_private.driver) 138462306a36Sopenharmony_ci return 0; 138562306a36Sopenharmony_ci 138662306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_AGP_INTEL) 138762306a36Sopenharmony_ci if (bridge) { 138862306a36Sopenharmony_ci if (INTEL_GTT_GEN > 1) 138962306a36Sopenharmony_ci return 0; 139062306a36Sopenharmony_ci 139162306a36Sopenharmony_ci bridge->driver = &intel_fake_agp_driver; 139262306a36Sopenharmony_ci bridge->dev_private_data = &intel_private; 139362306a36Sopenharmony_ci bridge->dev = bridge_pdev; 139462306a36Sopenharmony_ci } 139562306a36Sopenharmony_ci#endif 139662306a36Sopenharmony_ci 139762306a36Sopenharmony_ci 139862306a36Sopenharmony_ci /* 139962306a36Sopenharmony_ci * Can be called from the fake agp driver but also directly from 140062306a36Sopenharmony_ci * drm/i915.ko. Hence we need to check whether everything is set up 140162306a36Sopenharmony_ci * already. 140262306a36Sopenharmony_ci */ 140362306a36Sopenharmony_ci if (intel_private.refcount++) 140462306a36Sopenharmony_ci return 1; 140562306a36Sopenharmony_ci 140662306a36Sopenharmony_ci intel_private.bridge_dev = pci_dev_get(bridge_pdev); 140762306a36Sopenharmony_ci 140862306a36Sopenharmony_ci dev_info(&bridge_pdev->dev, "Intel %s Chipset\n", intel_gtt_chipsets[i].name); 140962306a36Sopenharmony_ci 141062306a36Sopenharmony_ci if (bridge) { 141162306a36Sopenharmony_ci mask = intel_private.driver->dma_mask_size; 141262306a36Sopenharmony_ci if (dma_set_mask(&intel_private.pcidev->dev, DMA_BIT_MASK(mask))) 141362306a36Sopenharmony_ci dev_err(&intel_private.pcidev->dev, 141462306a36Sopenharmony_ci "set gfx device dma mask %d-bit failed!\n", 141562306a36Sopenharmony_ci mask); 141662306a36Sopenharmony_ci else 141762306a36Sopenharmony_ci dma_set_coherent_mask(&intel_private.pcidev->dev, 141862306a36Sopenharmony_ci DMA_BIT_MASK(mask)); 141962306a36Sopenharmony_ci } 142062306a36Sopenharmony_ci 142162306a36Sopenharmony_ci if (intel_gtt_init() != 0) { 142262306a36Sopenharmony_ci intel_gmch_remove(); 142362306a36Sopenharmony_ci 142462306a36Sopenharmony_ci return 0; 142562306a36Sopenharmony_ci } 142662306a36Sopenharmony_ci 142762306a36Sopenharmony_ci return 1; 142862306a36Sopenharmony_ci} 142962306a36Sopenharmony_ciEXPORT_SYMBOL(intel_gmch_probe); 143062306a36Sopenharmony_ci 143162306a36Sopenharmony_civoid intel_gmch_gtt_get(u64 *gtt_total, 143262306a36Sopenharmony_ci phys_addr_t *mappable_base, 143362306a36Sopenharmony_ci resource_size_t *mappable_end) 143462306a36Sopenharmony_ci{ 143562306a36Sopenharmony_ci *gtt_total = intel_private.gtt_total_entries << PAGE_SHIFT; 143662306a36Sopenharmony_ci *mappable_base = intel_private.gma_bus_addr; 143762306a36Sopenharmony_ci *mappable_end = intel_private.gtt_mappable_entries << PAGE_SHIFT; 143862306a36Sopenharmony_ci} 143962306a36Sopenharmony_ciEXPORT_SYMBOL(intel_gmch_gtt_get); 144062306a36Sopenharmony_ci 144162306a36Sopenharmony_civoid intel_gmch_gtt_flush(void) 144262306a36Sopenharmony_ci{ 144362306a36Sopenharmony_ci if (intel_private.driver->chipset_flush) 144462306a36Sopenharmony_ci intel_private.driver->chipset_flush(); 144562306a36Sopenharmony_ci} 144662306a36Sopenharmony_ciEXPORT_SYMBOL(intel_gmch_gtt_flush); 144762306a36Sopenharmony_ci 144862306a36Sopenharmony_civoid intel_gmch_remove(void) 144962306a36Sopenharmony_ci{ 145062306a36Sopenharmony_ci if (--intel_private.refcount) 145162306a36Sopenharmony_ci return; 145262306a36Sopenharmony_ci 145362306a36Sopenharmony_ci if (intel_private.scratch_page) 145462306a36Sopenharmony_ci intel_gtt_teardown_scratch_page(); 145562306a36Sopenharmony_ci if (intel_private.pcidev) 145662306a36Sopenharmony_ci pci_dev_put(intel_private.pcidev); 145762306a36Sopenharmony_ci if (intel_private.bridge_dev) 145862306a36Sopenharmony_ci pci_dev_put(intel_private.bridge_dev); 145962306a36Sopenharmony_ci intel_private.driver = NULL; 146062306a36Sopenharmony_ci} 146162306a36Sopenharmony_ciEXPORT_SYMBOL(intel_gmch_remove); 146262306a36Sopenharmony_ci 146362306a36Sopenharmony_ciMODULE_AUTHOR("Dave Jones, Various @Intel"); 146462306a36Sopenharmony_ciMODULE_LICENSE("GPL and additional rights"); 1465