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