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