xref: /linux/drivers/char/agp/intel-gtt.c (revision b3eafc5af02a799650757f2c5b2b0d4835dd0a5f)
1f51b7662SDaniel Vetter /*
2f51b7662SDaniel Vetter  * Intel GTT (Graphics Translation Table) routines
3f51b7662SDaniel Vetter  *
4f51b7662SDaniel Vetter  * Caveat: This driver implements the linux agp interface, but this is far from
5f51b7662SDaniel Vetter  * a agp driver! GTT support ended up here for purely historical reasons: The
6f51b7662SDaniel Vetter  * old userspace intel graphics drivers needed an interface to map memory into
7f51b7662SDaniel Vetter  * the GTT. And the drm provides a default interface for graphic devices sitting
8f51b7662SDaniel Vetter  * on an agp port. So it made sense to fake the GTT support as an agp port to
9f51b7662SDaniel Vetter  * avoid having to create a new api.
10f51b7662SDaniel Vetter  *
11f51b7662SDaniel Vetter  * With gem this does not make much sense anymore, just needlessly complicates
12f51b7662SDaniel Vetter  * the code. But as long as the old graphics stack is still support, it's stuck
13f51b7662SDaniel Vetter  * here.
14f51b7662SDaniel Vetter  *
15f51b7662SDaniel Vetter  * /fairy-tale-mode off
16f51b7662SDaniel Vetter  */
17f51b7662SDaniel Vetter 
18e2404e7cSDaniel Vetter #include <linux/module.h>
19e2404e7cSDaniel Vetter #include <linux/pci.h>
20e2404e7cSDaniel Vetter #include <linux/init.h>
21e2404e7cSDaniel Vetter #include <linux/kernel.h>
22e2404e7cSDaniel Vetter #include <linux/pagemap.h>
23e2404e7cSDaniel Vetter #include <linux/agp_backend.h>
24e2404e7cSDaniel Vetter #include <asm/smp.h>
25e2404e7cSDaniel Vetter #include "agp.h"
26e2404e7cSDaniel Vetter #include "intel-agp.h"
27e2404e7cSDaniel Vetter #include <linux/intel-gtt.h>
280ade6386SDaniel Vetter #include <drm/intel-gtt.h>
29e2404e7cSDaniel Vetter 
30f51b7662SDaniel Vetter /*
31f51b7662SDaniel Vetter  * If we have Intel graphics, we're not going to have anything other than
32f51b7662SDaniel Vetter  * an Intel IOMMU. So make the correct use of the PCI DMA API contingent
33f51b7662SDaniel Vetter  * on the Intel IOMMU support (CONFIG_DMAR).
34f51b7662SDaniel Vetter  * Only newer chipsets need to bother with this, of course.
35f51b7662SDaniel Vetter  */
36f51b7662SDaniel Vetter #ifdef CONFIG_DMAR
37f51b7662SDaniel Vetter #define USE_PCI_DMA_API 1
380e87d2b0SDaniel Vetter #else
390e87d2b0SDaniel Vetter #define USE_PCI_DMA_API 0
40f51b7662SDaniel Vetter #endif
41f51b7662SDaniel Vetter 
42d1d6ca73SJesse Barnes /* Max amount of stolen space, anything above will be returned to Linux */
43d1d6ca73SJesse Barnes int intel_max_stolen = 32 * 1024 * 1024;
44d1d6ca73SJesse Barnes 
45f51b7662SDaniel Vetter static const struct aper_size_info_fixed intel_i810_sizes[] =
46f51b7662SDaniel Vetter {
47f51b7662SDaniel Vetter 	{64, 16384, 4},
48f51b7662SDaniel Vetter 	/* The 32M mode still requires a 64k gatt */
49f51b7662SDaniel Vetter 	{32, 8192, 4}
50f51b7662SDaniel Vetter };
51f51b7662SDaniel Vetter 
52f51b7662SDaniel Vetter #define AGP_DCACHE_MEMORY	1
53f51b7662SDaniel Vetter #define AGP_PHYS_MEMORY		2
54f51b7662SDaniel Vetter #define INTEL_AGP_CACHED_MEMORY 3
55f51b7662SDaniel Vetter 
56f51b7662SDaniel Vetter static struct gatt_mask intel_i810_masks[] =
57f51b7662SDaniel Vetter {
58f51b7662SDaniel Vetter 	{.mask = I810_PTE_VALID, .type = 0},
59f51b7662SDaniel Vetter 	{.mask = (I810_PTE_VALID | I810_PTE_LOCAL), .type = AGP_DCACHE_MEMORY},
60f51b7662SDaniel Vetter 	{.mask = I810_PTE_VALID, .type = 0},
61f51b7662SDaniel Vetter 	{.mask = I810_PTE_VALID | I830_PTE_SYSTEM_CACHED,
62f51b7662SDaniel Vetter 	 .type = INTEL_AGP_CACHED_MEMORY}
63f51b7662SDaniel Vetter };
64f51b7662SDaniel Vetter 
65f8f235e5SZhenyu Wang #define INTEL_AGP_UNCACHED_MEMORY              0
66f8f235e5SZhenyu Wang #define INTEL_AGP_CACHED_MEMORY_LLC            1
67f8f235e5SZhenyu Wang #define INTEL_AGP_CACHED_MEMORY_LLC_GFDT       2
68f8f235e5SZhenyu Wang #define INTEL_AGP_CACHED_MEMORY_LLC_MLC        3
69f8f235e5SZhenyu Wang #define INTEL_AGP_CACHED_MEMORY_LLC_MLC_GFDT   4
70f8f235e5SZhenyu Wang 
711a997ff2SDaniel Vetter struct intel_gtt_driver {
721a997ff2SDaniel Vetter 	unsigned int gen : 8;
731a997ff2SDaniel Vetter 	unsigned int is_g33 : 1;
741a997ff2SDaniel Vetter 	unsigned int is_pineview : 1;
751a997ff2SDaniel Vetter 	unsigned int is_ironlake : 1;
7622533b49SDaniel Vetter 	unsigned int dma_mask_size : 8;
7773800422SDaniel Vetter 	/* Chipset specific GTT setup */
7873800422SDaniel Vetter 	int (*setup)(void);
79ae83dd5cSDaniel Vetter 	/* This should undo anything done in ->setup() save the unmapping
80ae83dd5cSDaniel Vetter 	 * of the mmio register file, that's done in the generic code. */
81ae83dd5cSDaniel Vetter 	void (*cleanup)(void);
82351bb278SDaniel Vetter 	void (*write_entry)(dma_addr_t addr, unsigned int entry, unsigned int flags);
83351bb278SDaniel Vetter 	/* Flags is a more or less chipset specific opaque value.
84351bb278SDaniel Vetter 	 * For chipsets that need to support old ums (non-gem) code, this
85351bb278SDaniel Vetter 	 * needs to be identical to the various supported agp memory types! */
865cbecafcSDaniel Vetter 	bool (*check_flags)(unsigned int flags);
871b263f24SDaniel Vetter 	void (*chipset_flush)(void);
881a997ff2SDaniel Vetter };
891a997ff2SDaniel Vetter 
90f51b7662SDaniel Vetter static struct _intel_private {
910ade6386SDaniel Vetter 	struct intel_gtt base;
921a997ff2SDaniel Vetter 	const struct intel_gtt_driver *driver;
93f51b7662SDaniel Vetter 	struct pci_dev *pcidev;	/* device one */
94d7cca2f7SDaniel Vetter 	struct pci_dev *bridge_dev;
95f51b7662SDaniel Vetter 	u8 __iomem *registers;
96f67eab66SDaniel Vetter 	phys_addr_t gtt_bus_addr;
9773800422SDaniel Vetter 	phys_addr_t gma_bus_addr;
98*b3eafc5aSDaniel Vetter 	u32 PGETBL_save;
99f51b7662SDaniel Vetter 	u32 __iomem *gtt;		/* I915G */
100f51b7662SDaniel Vetter 	int num_dcache_entries;
101f51b7662SDaniel Vetter 	union {
102f51b7662SDaniel Vetter 		void __iomem *i9xx_flush_page;
103f51b7662SDaniel Vetter 		void *i8xx_flush_page;
104f51b7662SDaniel Vetter 	};
105f51b7662SDaniel Vetter 	struct page *i8xx_page;
106f51b7662SDaniel Vetter 	struct resource ifp_resource;
107f51b7662SDaniel Vetter 	int resource_valid;
1080e87d2b0SDaniel Vetter 	struct page *scratch_page;
1090e87d2b0SDaniel Vetter 	dma_addr_t scratch_page_dma;
110f51b7662SDaniel Vetter } intel_private;
111f51b7662SDaniel Vetter 
1121a997ff2SDaniel Vetter #define INTEL_GTT_GEN	intel_private.driver->gen
1131a997ff2SDaniel Vetter #define IS_G33		intel_private.driver->is_g33
1141a997ff2SDaniel Vetter #define IS_PINEVIEW	intel_private.driver->is_pineview
1151a997ff2SDaniel Vetter #define IS_IRONLAKE	intel_private.driver->is_ironlake
1161a997ff2SDaniel Vetter 
117f51b7662SDaniel Vetter static void intel_agp_free_sglist(struct agp_memory *mem)
118f51b7662SDaniel Vetter {
119f51b7662SDaniel Vetter 	struct sg_table st;
120f51b7662SDaniel Vetter 
121f51b7662SDaniel Vetter 	st.sgl = mem->sg_list;
122f51b7662SDaniel Vetter 	st.orig_nents = st.nents = mem->page_count;
123f51b7662SDaniel Vetter 
124f51b7662SDaniel Vetter 	sg_free_table(&st);
125f51b7662SDaniel Vetter 
126f51b7662SDaniel Vetter 	mem->sg_list = NULL;
127f51b7662SDaniel Vetter 	mem->num_sg = 0;
128f51b7662SDaniel Vetter }
129f51b7662SDaniel Vetter 
130f51b7662SDaniel Vetter static int intel_agp_map_memory(struct agp_memory *mem)
131f51b7662SDaniel Vetter {
132f51b7662SDaniel Vetter 	struct sg_table st;
133f51b7662SDaniel Vetter 	struct scatterlist *sg;
134f51b7662SDaniel Vetter 	int i;
135f51b7662SDaniel Vetter 
136fefaa70fSDaniel Vetter 	if (mem->sg_list)
137fefaa70fSDaniel Vetter 		return 0; /* already mapped (for e.g. resume */
138fefaa70fSDaniel Vetter 
139f51b7662SDaniel Vetter 	DBG("try mapping %lu pages\n", (unsigned long)mem->page_count);
140f51b7662SDaniel Vetter 
141f51b7662SDaniel Vetter 	if (sg_alloc_table(&st, mem->page_count, GFP_KERNEL))
142831cd445SChris Wilson 		goto err;
143f51b7662SDaniel Vetter 
144f51b7662SDaniel Vetter 	mem->sg_list = sg = st.sgl;
145f51b7662SDaniel Vetter 
146f51b7662SDaniel Vetter 	for (i = 0 ; i < mem->page_count; i++, sg = sg_next(sg))
147f51b7662SDaniel Vetter 		sg_set_page(sg, mem->pages[i], PAGE_SIZE, 0);
148f51b7662SDaniel Vetter 
149f51b7662SDaniel Vetter 	mem->num_sg = pci_map_sg(intel_private.pcidev, mem->sg_list,
150f51b7662SDaniel Vetter 				 mem->page_count, PCI_DMA_BIDIRECTIONAL);
151831cd445SChris Wilson 	if (unlikely(!mem->num_sg))
152831cd445SChris Wilson 		goto err;
153831cd445SChris Wilson 
154f51b7662SDaniel Vetter 	return 0;
155831cd445SChris Wilson 
156831cd445SChris Wilson err:
157831cd445SChris Wilson 	sg_free_table(&st);
158831cd445SChris Wilson 	return -ENOMEM;
159f51b7662SDaniel Vetter }
160f51b7662SDaniel Vetter 
161f51b7662SDaniel Vetter static void intel_agp_unmap_memory(struct agp_memory *mem)
162f51b7662SDaniel Vetter {
163f51b7662SDaniel Vetter 	DBG("try unmapping %lu pages\n", (unsigned long)mem->page_count);
164f51b7662SDaniel Vetter 
165f51b7662SDaniel Vetter 	pci_unmap_sg(intel_private.pcidev, mem->sg_list,
166f51b7662SDaniel Vetter 		     mem->page_count, PCI_DMA_BIDIRECTIONAL);
167f51b7662SDaniel Vetter 	intel_agp_free_sglist(mem);
168f51b7662SDaniel Vetter }
169f51b7662SDaniel Vetter 
170f51b7662SDaniel Vetter static int intel_i810_fetch_size(void)
171f51b7662SDaniel Vetter {
172f51b7662SDaniel Vetter 	u32 smram_miscc;
173f51b7662SDaniel Vetter 	struct aper_size_info_fixed *values;
174f51b7662SDaniel Vetter 
175d7cca2f7SDaniel Vetter 	pci_read_config_dword(intel_private.bridge_dev,
176d7cca2f7SDaniel Vetter 			      I810_SMRAM_MISCC, &smram_miscc);
177f51b7662SDaniel Vetter 	values = A_SIZE_FIX(agp_bridge->driver->aperture_sizes);
178f51b7662SDaniel Vetter 
179f51b7662SDaniel Vetter 	if ((smram_miscc & I810_GMS) == I810_GMS_DISABLE) {
180d7cca2f7SDaniel Vetter 		dev_warn(&intel_private.bridge_dev->dev, "i810 is disabled\n");
181f51b7662SDaniel Vetter 		return 0;
182f51b7662SDaniel Vetter 	}
183f51b7662SDaniel Vetter 	if ((smram_miscc & I810_GFX_MEM_WIN_SIZE) == I810_GFX_MEM_WIN_32M) {
184f51b7662SDaniel Vetter 		agp_bridge->current_size = (void *) (values + 1);
185f51b7662SDaniel Vetter 		agp_bridge->aperture_size_idx = 1;
186f51b7662SDaniel Vetter 		return values[1].size;
187f51b7662SDaniel Vetter 	} else {
188f51b7662SDaniel Vetter 		agp_bridge->current_size = (void *) (values);
189f51b7662SDaniel Vetter 		agp_bridge->aperture_size_idx = 0;
190f51b7662SDaniel Vetter 		return values[0].size;
191f51b7662SDaniel Vetter 	}
192f51b7662SDaniel Vetter 
193f51b7662SDaniel Vetter 	return 0;
194f51b7662SDaniel Vetter }
195f51b7662SDaniel Vetter 
196f51b7662SDaniel Vetter static int intel_i810_configure(void)
197f51b7662SDaniel Vetter {
198f51b7662SDaniel Vetter 	struct aper_size_info_fixed *current_size;
199f51b7662SDaniel Vetter 	u32 temp;
200f51b7662SDaniel Vetter 	int i;
201f51b7662SDaniel Vetter 
202f51b7662SDaniel Vetter 	current_size = A_SIZE_FIX(agp_bridge->current_size);
203f51b7662SDaniel Vetter 
204f51b7662SDaniel Vetter 	if (!intel_private.registers) {
205f51b7662SDaniel Vetter 		pci_read_config_dword(intel_private.pcidev, I810_MMADDR, &temp);
206f51b7662SDaniel Vetter 		temp &= 0xfff80000;
207f51b7662SDaniel Vetter 
208f51b7662SDaniel Vetter 		intel_private.registers = ioremap(temp, 128 * 4096);
209f51b7662SDaniel Vetter 		if (!intel_private.registers) {
210f51b7662SDaniel Vetter 			dev_err(&intel_private.pcidev->dev,
211f51b7662SDaniel Vetter 				"can't remap memory\n");
212f51b7662SDaniel Vetter 			return -ENOMEM;
213f51b7662SDaniel Vetter 		}
214f51b7662SDaniel Vetter 	}
215f51b7662SDaniel Vetter 
216f51b7662SDaniel Vetter 	if ((readl(intel_private.registers+I810_DRAM_CTL)
217f51b7662SDaniel Vetter 		& I810_DRAM_ROW_0) == I810_DRAM_ROW_0_SDRAM) {
218f51b7662SDaniel Vetter 		/* This will need to be dynamically assigned */
219f51b7662SDaniel Vetter 		dev_info(&intel_private.pcidev->dev,
220f51b7662SDaniel Vetter 			 "detected 4MB dedicated video ram\n");
221f51b7662SDaniel Vetter 		intel_private.num_dcache_entries = 1024;
222f51b7662SDaniel Vetter 	}
223f51b7662SDaniel Vetter 	pci_read_config_dword(intel_private.pcidev, I810_GMADDR, &temp);
224f51b7662SDaniel Vetter 	agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
225f51b7662SDaniel Vetter 	writel(agp_bridge->gatt_bus_addr | I810_PGETBL_ENABLED, intel_private.registers+I810_PGETBL_CTL);
226f51b7662SDaniel Vetter 	readl(intel_private.registers+I810_PGETBL_CTL);	/* PCI Posting. */
227f51b7662SDaniel Vetter 
228f51b7662SDaniel Vetter 	if (agp_bridge->driver->needs_scratch_page) {
229f51b7662SDaniel Vetter 		for (i = 0; i < current_size->num_entries; i++) {
230f51b7662SDaniel Vetter 			writel(agp_bridge->scratch_page, intel_private.registers+I810_PTE_BASE+(i*4));
231f51b7662SDaniel Vetter 		}
232f51b7662SDaniel Vetter 		readl(intel_private.registers+I810_PTE_BASE+((i-1)*4));	/* PCI posting. */
233f51b7662SDaniel Vetter 	}
234f51b7662SDaniel Vetter 	global_cache_flush();
235f51b7662SDaniel Vetter 	return 0;
236f51b7662SDaniel Vetter }
237f51b7662SDaniel Vetter 
238f51b7662SDaniel Vetter static void intel_i810_cleanup(void)
239f51b7662SDaniel Vetter {
240f51b7662SDaniel Vetter 	writel(0, intel_private.registers+I810_PGETBL_CTL);
241f51b7662SDaniel Vetter 	readl(intel_private.registers);	/* PCI Posting. */
242f51b7662SDaniel Vetter 	iounmap(intel_private.registers);
243f51b7662SDaniel Vetter }
244f51b7662SDaniel Vetter 
245ffdd7510SDaniel Vetter static void intel_fake_agp_enable(struct agp_bridge_data *bridge, u32 mode)
246f51b7662SDaniel Vetter {
247f51b7662SDaniel Vetter 	return;
248f51b7662SDaniel Vetter }
249f51b7662SDaniel Vetter 
250f51b7662SDaniel Vetter /* Exists to support ARGB cursors */
251f51b7662SDaniel Vetter static struct page *i8xx_alloc_pages(void)
252f51b7662SDaniel Vetter {
253f51b7662SDaniel Vetter 	struct page *page;
254f51b7662SDaniel Vetter 
255f51b7662SDaniel Vetter 	page = alloc_pages(GFP_KERNEL | GFP_DMA32, 2);
256f51b7662SDaniel Vetter 	if (page == NULL)
257f51b7662SDaniel Vetter 		return NULL;
258f51b7662SDaniel Vetter 
259f51b7662SDaniel Vetter 	if (set_pages_uc(page, 4) < 0) {
260f51b7662SDaniel Vetter 		set_pages_wb(page, 4);
261f51b7662SDaniel Vetter 		__free_pages(page, 2);
262f51b7662SDaniel Vetter 		return NULL;
263f51b7662SDaniel Vetter 	}
264f51b7662SDaniel Vetter 	get_page(page);
265f51b7662SDaniel Vetter 	atomic_inc(&agp_bridge->current_memory_agp);
266f51b7662SDaniel Vetter 	return page;
267f51b7662SDaniel Vetter }
268f51b7662SDaniel Vetter 
269f51b7662SDaniel Vetter static void i8xx_destroy_pages(struct page *page)
270f51b7662SDaniel Vetter {
271f51b7662SDaniel Vetter 	if (page == NULL)
272f51b7662SDaniel Vetter 		return;
273f51b7662SDaniel Vetter 
274f51b7662SDaniel Vetter 	set_pages_wb(page, 4);
275f51b7662SDaniel Vetter 	put_page(page);
276f51b7662SDaniel Vetter 	__free_pages(page, 2);
277f51b7662SDaniel Vetter 	atomic_dec(&agp_bridge->current_memory_agp);
278f51b7662SDaniel Vetter }
279f51b7662SDaniel Vetter 
280f51b7662SDaniel Vetter static int intel_i810_insert_entries(struct agp_memory *mem, off_t pg_start,
281f51b7662SDaniel Vetter 				int type)
282f51b7662SDaniel Vetter {
283f51b7662SDaniel Vetter 	int i, j, num_entries;
284f51b7662SDaniel Vetter 	void *temp;
285f51b7662SDaniel Vetter 	int ret = -EINVAL;
286f51b7662SDaniel Vetter 	int mask_type;
287f51b7662SDaniel Vetter 
288f51b7662SDaniel Vetter 	if (mem->page_count == 0)
289f51b7662SDaniel Vetter 		goto out;
290f51b7662SDaniel Vetter 
291f51b7662SDaniel Vetter 	temp = agp_bridge->current_size;
292f51b7662SDaniel Vetter 	num_entries = A_SIZE_FIX(temp)->num_entries;
293f51b7662SDaniel Vetter 
294f51b7662SDaniel Vetter 	if ((pg_start + mem->page_count) > num_entries)
295f51b7662SDaniel Vetter 		goto out_err;
296f51b7662SDaniel Vetter 
297f51b7662SDaniel Vetter 
298f51b7662SDaniel Vetter 	for (j = pg_start; j < (pg_start + mem->page_count); j++) {
299f51b7662SDaniel Vetter 		if (!PGE_EMPTY(agp_bridge, readl(agp_bridge->gatt_table+j))) {
300f51b7662SDaniel Vetter 			ret = -EBUSY;
301f51b7662SDaniel Vetter 			goto out_err;
302f51b7662SDaniel Vetter 		}
303f51b7662SDaniel Vetter 	}
304f51b7662SDaniel Vetter 
305f51b7662SDaniel Vetter 	if (type != mem->type)
306f51b7662SDaniel Vetter 		goto out_err;
307f51b7662SDaniel Vetter 
308f51b7662SDaniel Vetter 	mask_type = agp_bridge->driver->agp_type_to_mask_type(agp_bridge, type);
309f51b7662SDaniel Vetter 
310f51b7662SDaniel Vetter 	switch (mask_type) {
311f51b7662SDaniel Vetter 	case AGP_DCACHE_MEMORY:
312f51b7662SDaniel Vetter 		if (!mem->is_flushed)
313f51b7662SDaniel Vetter 			global_cache_flush();
314f51b7662SDaniel Vetter 		for (i = pg_start; i < (pg_start + mem->page_count); i++) {
315f51b7662SDaniel Vetter 			writel((i*4096)|I810_PTE_LOCAL|I810_PTE_VALID,
316f51b7662SDaniel Vetter 			       intel_private.registers+I810_PTE_BASE+(i*4));
317f51b7662SDaniel Vetter 		}
318f51b7662SDaniel Vetter 		readl(intel_private.registers+I810_PTE_BASE+((i-1)*4));
319f51b7662SDaniel Vetter 		break;
320f51b7662SDaniel Vetter 	case AGP_PHYS_MEMORY:
321f51b7662SDaniel Vetter 	case AGP_NORMAL_MEMORY:
322f51b7662SDaniel Vetter 		if (!mem->is_flushed)
323f51b7662SDaniel Vetter 			global_cache_flush();
324f51b7662SDaniel Vetter 		for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
325f51b7662SDaniel Vetter 			writel(agp_bridge->driver->mask_memory(agp_bridge,
326f51b7662SDaniel Vetter 					page_to_phys(mem->pages[i]), mask_type),
327f51b7662SDaniel Vetter 			       intel_private.registers+I810_PTE_BASE+(j*4));
328f51b7662SDaniel Vetter 		}
329f51b7662SDaniel Vetter 		readl(intel_private.registers+I810_PTE_BASE+((j-1)*4));
330f51b7662SDaniel Vetter 		break;
331f51b7662SDaniel Vetter 	default:
332f51b7662SDaniel Vetter 		goto out_err;
333f51b7662SDaniel Vetter 	}
334f51b7662SDaniel Vetter 
335f51b7662SDaniel Vetter out:
336f51b7662SDaniel Vetter 	ret = 0;
337f51b7662SDaniel Vetter out_err:
338f51b7662SDaniel Vetter 	mem->is_flushed = true;
339f51b7662SDaniel Vetter 	return ret;
340f51b7662SDaniel Vetter }
341f51b7662SDaniel Vetter 
342f51b7662SDaniel Vetter static int intel_i810_remove_entries(struct agp_memory *mem, off_t pg_start,
343f51b7662SDaniel Vetter 				int type)
344f51b7662SDaniel Vetter {
345f51b7662SDaniel Vetter 	int i;
346f51b7662SDaniel Vetter 
347f51b7662SDaniel Vetter 	if (mem->page_count == 0)
348f51b7662SDaniel Vetter 		return 0;
349f51b7662SDaniel Vetter 
350f51b7662SDaniel Vetter 	for (i = pg_start; i < (mem->page_count + pg_start); i++) {
351f51b7662SDaniel Vetter 		writel(agp_bridge->scratch_page, intel_private.registers+I810_PTE_BASE+(i*4));
352f51b7662SDaniel Vetter 	}
353f51b7662SDaniel Vetter 	readl(intel_private.registers+I810_PTE_BASE+((i-1)*4));
354f51b7662SDaniel Vetter 
355f51b7662SDaniel Vetter 	return 0;
356f51b7662SDaniel Vetter }
357f51b7662SDaniel Vetter 
358f51b7662SDaniel Vetter /*
359f51b7662SDaniel Vetter  * The i810/i830 requires a physical address to program its mouse
360f51b7662SDaniel Vetter  * pointer into hardware.
361f51b7662SDaniel Vetter  * However the Xserver still writes to it through the agp aperture.
362f51b7662SDaniel Vetter  */
363f51b7662SDaniel Vetter static struct agp_memory *alloc_agpphysmem_i8xx(size_t pg_count, int type)
364f51b7662SDaniel Vetter {
365f51b7662SDaniel Vetter 	struct agp_memory *new;
366f51b7662SDaniel Vetter 	struct page *page;
367f51b7662SDaniel Vetter 
368f51b7662SDaniel Vetter 	switch (pg_count) {
369f51b7662SDaniel Vetter 	case 1: page = agp_bridge->driver->agp_alloc_page(agp_bridge);
370f51b7662SDaniel Vetter 		break;
371f51b7662SDaniel Vetter 	case 4:
372f51b7662SDaniel Vetter 		/* kludge to get 4 physical pages for ARGB cursor */
373f51b7662SDaniel Vetter 		page = i8xx_alloc_pages();
374f51b7662SDaniel Vetter 		break;
375f51b7662SDaniel Vetter 	default:
376f51b7662SDaniel Vetter 		return NULL;
377f51b7662SDaniel Vetter 	}
378f51b7662SDaniel Vetter 
379f51b7662SDaniel Vetter 	if (page == NULL)
380f51b7662SDaniel Vetter 		return NULL;
381f51b7662SDaniel Vetter 
382f51b7662SDaniel Vetter 	new = agp_create_memory(pg_count);
383f51b7662SDaniel Vetter 	if (new == NULL)
384f51b7662SDaniel Vetter 		return NULL;
385f51b7662SDaniel Vetter 
386f51b7662SDaniel Vetter 	new->pages[0] = page;
387f51b7662SDaniel Vetter 	if (pg_count == 4) {
388f51b7662SDaniel Vetter 		/* kludge to get 4 physical pages for ARGB cursor */
389f51b7662SDaniel Vetter 		new->pages[1] = new->pages[0] + 1;
390f51b7662SDaniel Vetter 		new->pages[2] = new->pages[1] + 1;
391f51b7662SDaniel Vetter 		new->pages[3] = new->pages[2] + 1;
392f51b7662SDaniel Vetter 	}
393f51b7662SDaniel Vetter 	new->page_count = pg_count;
394f51b7662SDaniel Vetter 	new->num_scratch_pages = pg_count;
395f51b7662SDaniel Vetter 	new->type = AGP_PHYS_MEMORY;
396f51b7662SDaniel Vetter 	new->physical = page_to_phys(new->pages[0]);
397f51b7662SDaniel Vetter 	return new;
398f51b7662SDaniel Vetter }
399f51b7662SDaniel Vetter 
400f51b7662SDaniel Vetter static struct agp_memory *intel_i810_alloc_by_type(size_t pg_count, int type)
401f51b7662SDaniel Vetter {
402f51b7662SDaniel Vetter 	struct agp_memory *new;
403f51b7662SDaniel Vetter 
404f51b7662SDaniel Vetter 	if (type == AGP_DCACHE_MEMORY) {
405f51b7662SDaniel Vetter 		if (pg_count != intel_private.num_dcache_entries)
406f51b7662SDaniel Vetter 			return NULL;
407f51b7662SDaniel Vetter 
408f51b7662SDaniel Vetter 		new = agp_create_memory(1);
409f51b7662SDaniel Vetter 		if (new == NULL)
410f51b7662SDaniel Vetter 			return NULL;
411f51b7662SDaniel Vetter 
412f51b7662SDaniel Vetter 		new->type = AGP_DCACHE_MEMORY;
413f51b7662SDaniel Vetter 		new->page_count = pg_count;
414f51b7662SDaniel Vetter 		new->num_scratch_pages = 0;
415f51b7662SDaniel Vetter 		agp_free_page_array(new);
416f51b7662SDaniel Vetter 		return new;
417f51b7662SDaniel Vetter 	}
418f51b7662SDaniel Vetter 	if (type == AGP_PHYS_MEMORY)
419f51b7662SDaniel Vetter 		return alloc_agpphysmem_i8xx(pg_count, type);
420f51b7662SDaniel Vetter 	return NULL;
421f51b7662SDaniel Vetter }
422f51b7662SDaniel Vetter 
423f51b7662SDaniel Vetter static void intel_i810_free_by_type(struct agp_memory *curr)
424f51b7662SDaniel Vetter {
425f51b7662SDaniel Vetter 	agp_free_key(curr->key);
426f51b7662SDaniel Vetter 	if (curr->type == AGP_PHYS_MEMORY) {
427f51b7662SDaniel Vetter 		if (curr->page_count == 4)
428f51b7662SDaniel Vetter 			i8xx_destroy_pages(curr->pages[0]);
429f51b7662SDaniel Vetter 		else {
430f51b7662SDaniel Vetter 			agp_bridge->driver->agp_destroy_page(curr->pages[0],
431f51b7662SDaniel Vetter 							     AGP_PAGE_DESTROY_UNMAP);
432f51b7662SDaniel Vetter 			agp_bridge->driver->agp_destroy_page(curr->pages[0],
433f51b7662SDaniel Vetter 							     AGP_PAGE_DESTROY_FREE);
434f51b7662SDaniel Vetter 		}
435f51b7662SDaniel Vetter 		agp_free_page_array(curr);
436f51b7662SDaniel Vetter 	}
437f51b7662SDaniel Vetter 	kfree(curr);
438f51b7662SDaniel Vetter }
439f51b7662SDaniel Vetter 
440f51b7662SDaniel Vetter static unsigned long intel_i810_mask_memory(struct agp_bridge_data *bridge,
441f51b7662SDaniel Vetter 					    dma_addr_t addr, int type)
442f51b7662SDaniel Vetter {
443f51b7662SDaniel Vetter 	/* Type checking must be done elsewhere */
444f51b7662SDaniel Vetter 	return addr | bridge->driver->masks[type].mask;
445f51b7662SDaniel Vetter }
446f51b7662SDaniel Vetter 
4470e87d2b0SDaniel Vetter static int intel_gtt_setup_scratch_page(void)
4480e87d2b0SDaniel Vetter {
4490e87d2b0SDaniel Vetter 	struct page *page;
4500e87d2b0SDaniel Vetter 	dma_addr_t dma_addr;
4510e87d2b0SDaniel Vetter 
4520e87d2b0SDaniel Vetter 	page = alloc_page(GFP_KERNEL | GFP_DMA32 | __GFP_ZERO);
4530e87d2b0SDaniel Vetter 	if (page == NULL)
4540e87d2b0SDaniel Vetter 		return -ENOMEM;
4550e87d2b0SDaniel Vetter 	get_page(page);
4560e87d2b0SDaniel Vetter 	set_pages_uc(page, 1);
4570e87d2b0SDaniel Vetter 
4580e87d2b0SDaniel Vetter 	if (USE_PCI_DMA_API && INTEL_GTT_GEN > 2) {
4590e87d2b0SDaniel Vetter 		dma_addr = pci_map_page(intel_private.pcidev, page, 0,
4600e87d2b0SDaniel Vetter 				    PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
4610e87d2b0SDaniel Vetter 		if (pci_dma_mapping_error(intel_private.pcidev, dma_addr))
4620e87d2b0SDaniel Vetter 			return -EINVAL;
4630e87d2b0SDaniel Vetter 
4640e87d2b0SDaniel Vetter 		intel_private.scratch_page_dma = dma_addr;
4650e87d2b0SDaniel Vetter 	} else
4660e87d2b0SDaniel Vetter 		intel_private.scratch_page_dma = page_to_phys(page);
4670e87d2b0SDaniel Vetter 
4680e87d2b0SDaniel Vetter 	intel_private.scratch_page = page;
4690e87d2b0SDaniel Vetter 
4700e87d2b0SDaniel Vetter 	return 0;
4710e87d2b0SDaniel Vetter }
4720e87d2b0SDaniel Vetter 
4739e76e7b8SChris Wilson static const struct aper_size_info_fixed const intel_fake_agp_sizes[] = {
474f51b7662SDaniel Vetter 	{128, 32768, 5},
475f51b7662SDaniel Vetter 	/* The 64M mode still requires a 128k gatt */
476f51b7662SDaniel Vetter 	{64, 16384, 5},
477f51b7662SDaniel Vetter 	{256, 65536, 6},
478f51b7662SDaniel Vetter 	{512, 131072, 7},
479f51b7662SDaniel Vetter };
480f51b7662SDaniel Vetter 
481bfde067bSDaniel Vetter static unsigned int intel_gtt_stolen_entries(void)
482f51b7662SDaniel Vetter {
483f51b7662SDaniel Vetter 	u16 gmch_ctrl;
484f51b7662SDaniel Vetter 	u8 rdct;
485f51b7662SDaniel Vetter 	int local = 0;
486f51b7662SDaniel Vetter 	static const int ddt[4] = { 0, 16, 32, 64 };
487d8d9abcdSDaniel Vetter 	unsigned int overhead_entries, stolen_entries;
488d8d9abcdSDaniel Vetter 	unsigned int stolen_size = 0;
489f51b7662SDaniel Vetter 
490d7cca2f7SDaniel Vetter 	pci_read_config_word(intel_private.bridge_dev,
491d7cca2f7SDaniel Vetter 			     I830_GMCH_CTRL, &gmch_ctrl);
492f51b7662SDaniel Vetter 
4931a997ff2SDaniel Vetter 	if (INTEL_GTT_GEN > 4 || IS_PINEVIEW)
494fbe40783SDaniel Vetter 		overhead_entries = 0;
495fbe40783SDaniel Vetter 	else
496fbe40783SDaniel Vetter 		overhead_entries = intel_private.base.gtt_mappable_entries
497fbe40783SDaniel Vetter 			/ 1024;
498f51b7662SDaniel Vetter 
499fbe40783SDaniel Vetter 	overhead_entries += 1; /* BIOS popup */
500d8d9abcdSDaniel Vetter 
501d7cca2f7SDaniel Vetter 	if (intel_private.bridge_dev->device == PCI_DEVICE_ID_INTEL_82830_HB ||
502d7cca2f7SDaniel Vetter 	    intel_private.bridge_dev->device == PCI_DEVICE_ID_INTEL_82845G_HB) {
503f51b7662SDaniel Vetter 		switch (gmch_ctrl & I830_GMCH_GMS_MASK) {
504f51b7662SDaniel Vetter 		case I830_GMCH_GMS_STOLEN_512:
505d8d9abcdSDaniel Vetter 			stolen_size = KB(512);
506f51b7662SDaniel Vetter 			break;
507f51b7662SDaniel Vetter 		case I830_GMCH_GMS_STOLEN_1024:
508d8d9abcdSDaniel Vetter 			stolen_size = MB(1);
509f51b7662SDaniel Vetter 			break;
510f51b7662SDaniel Vetter 		case I830_GMCH_GMS_STOLEN_8192:
511d8d9abcdSDaniel Vetter 			stolen_size = MB(8);
512f51b7662SDaniel Vetter 			break;
513f51b7662SDaniel Vetter 		case I830_GMCH_GMS_LOCAL:
514f51b7662SDaniel Vetter 			rdct = readb(intel_private.registers+I830_RDRAM_CHANNEL_TYPE);
515d8d9abcdSDaniel Vetter 			stolen_size = (I830_RDRAM_ND(rdct) + 1) *
516f51b7662SDaniel Vetter 					MB(ddt[I830_RDRAM_DDT(rdct)]);
517f51b7662SDaniel Vetter 			local = 1;
518f51b7662SDaniel Vetter 			break;
519f51b7662SDaniel Vetter 		default:
520d8d9abcdSDaniel Vetter 			stolen_size = 0;
521f51b7662SDaniel Vetter 			break;
522f51b7662SDaniel Vetter 		}
5231a997ff2SDaniel Vetter 	} else if (INTEL_GTT_GEN == 6) {
524f51b7662SDaniel Vetter 		/*
525f51b7662SDaniel Vetter 		 * SandyBridge has new memory control reg at 0x50.w
526f51b7662SDaniel Vetter 		 */
527f51b7662SDaniel Vetter 		u16 snb_gmch_ctl;
528f51b7662SDaniel Vetter 		pci_read_config_word(intel_private.pcidev, SNB_GMCH_CTRL, &snb_gmch_ctl);
529f51b7662SDaniel Vetter 		switch (snb_gmch_ctl & SNB_GMCH_GMS_STOLEN_MASK) {
530f51b7662SDaniel Vetter 		case SNB_GMCH_GMS_STOLEN_32M:
531d8d9abcdSDaniel Vetter 			stolen_size = MB(32);
532f51b7662SDaniel Vetter 			break;
533f51b7662SDaniel Vetter 		case SNB_GMCH_GMS_STOLEN_64M:
534d8d9abcdSDaniel Vetter 			stolen_size = MB(64);
535f51b7662SDaniel Vetter 			break;
536f51b7662SDaniel Vetter 		case SNB_GMCH_GMS_STOLEN_96M:
537d8d9abcdSDaniel Vetter 			stolen_size = MB(96);
538f51b7662SDaniel Vetter 			break;
539f51b7662SDaniel Vetter 		case SNB_GMCH_GMS_STOLEN_128M:
540d8d9abcdSDaniel Vetter 			stolen_size = MB(128);
541f51b7662SDaniel Vetter 			break;
542f51b7662SDaniel Vetter 		case SNB_GMCH_GMS_STOLEN_160M:
543d8d9abcdSDaniel Vetter 			stolen_size = MB(160);
544f51b7662SDaniel Vetter 			break;
545f51b7662SDaniel Vetter 		case SNB_GMCH_GMS_STOLEN_192M:
546d8d9abcdSDaniel Vetter 			stolen_size = MB(192);
547f51b7662SDaniel Vetter 			break;
548f51b7662SDaniel Vetter 		case SNB_GMCH_GMS_STOLEN_224M:
549d8d9abcdSDaniel Vetter 			stolen_size = MB(224);
550f51b7662SDaniel Vetter 			break;
551f51b7662SDaniel Vetter 		case SNB_GMCH_GMS_STOLEN_256M:
552d8d9abcdSDaniel Vetter 			stolen_size = MB(256);
553f51b7662SDaniel Vetter 			break;
554f51b7662SDaniel Vetter 		case SNB_GMCH_GMS_STOLEN_288M:
555d8d9abcdSDaniel Vetter 			stolen_size = MB(288);
556f51b7662SDaniel Vetter 			break;
557f51b7662SDaniel Vetter 		case SNB_GMCH_GMS_STOLEN_320M:
558d8d9abcdSDaniel Vetter 			stolen_size = MB(320);
559f51b7662SDaniel Vetter 			break;
560f51b7662SDaniel Vetter 		case SNB_GMCH_GMS_STOLEN_352M:
561d8d9abcdSDaniel Vetter 			stolen_size = MB(352);
562f51b7662SDaniel Vetter 			break;
563f51b7662SDaniel Vetter 		case SNB_GMCH_GMS_STOLEN_384M:
564d8d9abcdSDaniel Vetter 			stolen_size = MB(384);
565f51b7662SDaniel Vetter 			break;
566f51b7662SDaniel Vetter 		case SNB_GMCH_GMS_STOLEN_416M:
567d8d9abcdSDaniel Vetter 			stolen_size = MB(416);
568f51b7662SDaniel Vetter 			break;
569f51b7662SDaniel Vetter 		case SNB_GMCH_GMS_STOLEN_448M:
570d8d9abcdSDaniel Vetter 			stolen_size = MB(448);
571f51b7662SDaniel Vetter 			break;
572f51b7662SDaniel Vetter 		case SNB_GMCH_GMS_STOLEN_480M:
573d8d9abcdSDaniel Vetter 			stolen_size = MB(480);
574f51b7662SDaniel Vetter 			break;
575f51b7662SDaniel Vetter 		case SNB_GMCH_GMS_STOLEN_512M:
576d8d9abcdSDaniel Vetter 			stolen_size = MB(512);
577f51b7662SDaniel Vetter 			break;
578f51b7662SDaniel Vetter 		}
579f51b7662SDaniel Vetter 	} else {
580f51b7662SDaniel Vetter 		switch (gmch_ctrl & I855_GMCH_GMS_MASK) {
581f51b7662SDaniel Vetter 		case I855_GMCH_GMS_STOLEN_1M:
582d8d9abcdSDaniel Vetter 			stolen_size = MB(1);
583f51b7662SDaniel Vetter 			break;
584f51b7662SDaniel Vetter 		case I855_GMCH_GMS_STOLEN_4M:
585d8d9abcdSDaniel Vetter 			stolen_size = MB(4);
586f51b7662SDaniel Vetter 			break;
587f51b7662SDaniel Vetter 		case I855_GMCH_GMS_STOLEN_8M:
588d8d9abcdSDaniel Vetter 			stolen_size = MB(8);
589f51b7662SDaniel Vetter 			break;
590f51b7662SDaniel Vetter 		case I855_GMCH_GMS_STOLEN_16M:
591d8d9abcdSDaniel Vetter 			stolen_size = MB(16);
592f51b7662SDaniel Vetter 			break;
593f51b7662SDaniel Vetter 		case I855_GMCH_GMS_STOLEN_32M:
594d8d9abcdSDaniel Vetter 			stolen_size = MB(32);
595f51b7662SDaniel Vetter 			break;
596f51b7662SDaniel Vetter 		case I915_GMCH_GMS_STOLEN_48M:
597d8d9abcdSDaniel Vetter 			stolen_size = MB(48);
598f51b7662SDaniel Vetter 			break;
599f51b7662SDaniel Vetter 		case I915_GMCH_GMS_STOLEN_64M:
600d8d9abcdSDaniel Vetter 			stolen_size = MB(64);
601f51b7662SDaniel Vetter 			break;
602f51b7662SDaniel Vetter 		case G33_GMCH_GMS_STOLEN_128M:
603d8d9abcdSDaniel Vetter 			stolen_size = MB(128);
604f51b7662SDaniel Vetter 			break;
605f51b7662SDaniel Vetter 		case G33_GMCH_GMS_STOLEN_256M:
606d8d9abcdSDaniel Vetter 			stolen_size = MB(256);
607f51b7662SDaniel Vetter 			break;
608f51b7662SDaniel Vetter 		case INTEL_GMCH_GMS_STOLEN_96M:
609d8d9abcdSDaniel Vetter 			stolen_size = MB(96);
610f51b7662SDaniel Vetter 			break;
611f51b7662SDaniel Vetter 		case INTEL_GMCH_GMS_STOLEN_160M:
612d8d9abcdSDaniel Vetter 			stolen_size = MB(160);
613f51b7662SDaniel Vetter 			break;
614f51b7662SDaniel Vetter 		case INTEL_GMCH_GMS_STOLEN_224M:
615d8d9abcdSDaniel Vetter 			stolen_size = MB(224);
616f51b7662SDaniel Vetter 			break;
617f51b7662SDaniel Vetter 		case INTEL_GMCH_GMS_STOLEN_352M:
618d8d9abcdSDaniel Vetter 			stolen_size = MB(352);
619f51b7662SDaniel Vetter 			break;
620f51b7662SDaniel Vetter 		default:
621d8d9abcdSDaniel Vetter 			stolen_size = 0;
622f51b7662SDaniel Vetter 			break;
623f51b7662SDaniel Vetter 		}
624f51b7662SDaniel Vetter 	}
6251784a5fbSDaniel Vetter 
626d8d9abcdSDaniel Vetter 	if (!local && stolen_size > intel_max_stolen) {
627d7cca2f7SDaniel Vetter 		dev_info(&intel_private.bridge_dev->dev,
628d1d6ca73SJesse Barnes 			 "detected %dK stolen memory, trimming to %dK\n",
629d8d9abcdSDaniel Vetter 			 stolen_size / KB(1), intel_max_stolen / KB(1));
630d8d9abcdSDaniel Vetter 		stolen_size = intel_max_stolen;
631d8d9abcdSDaniel Vetter 	} else if (stolen_size > 0) {
632d7cca2f7SDaniel Vetter 		dev_info(&intel_private.bridge_dev->dev, "detected %dK %s memory\n",
633d8d9abcdSDaniel Vetter 		       stolen_size / KB(1), local ? "local" : "stolen");
634f51b7662SDaniel Vetter 	} else {
635d7cca2f7SDaniel Vetter 		dev_info(&intel_private.bridge_dev->dev,
636f51b7662SDaniel Vetter 		       "no pre-allocated video memory detected\n");
637d8d9abcdSDaniel Vetter 		stolen_size = 0;
638f51b7662SDaniel Vetter 	}
639f51b7662SDaniel Vetter 
640d8d9abcdSDaniel Vetter 	stolen_entries = stolen_size/KB(4) - overhead_entries;
641d8d9abcdSDaniel Vetter 
642d8d9abcdSDaniel Vetter 	return stolen_entries;
643f51b7662SDaniel Vetter }
644f51b7662SDaniel Vetter 
645fbe40783SDaniel Vetter static unsigned int intel_gtt_total_entries(void)
646fbe40783SDaniel Vetter {
647fbe40783SDaniel Vetter 	int size;
648fbe40783SDaniel Vetter 
649210b23c2SDaniel Vetter 	if (IS_G33 || INTEL_GTT_GEN == 4 || INTEL_GTT_GEN == 5) {
650fbe40783SDaniel Vetter 		u32 pgetbl_ctl;
651fbe40783SDaniel Vetter 		pgetbl_ctl = readl(intel_private.registers+I810_PGETBL_CTL);
652fbe40783SDaniel Vetter 
653fbe40783SDaniel Vetter 		switch (pgetbl_ctl & I965_PGETBL_SIZE_MASK) {
654fbe40783SDaniel Vetter 		case I965_PGETBL_SIZE_128KB:
655e5e408fcSDaniel Vetter 			size = KB(128);
656fbe40783SDaniel Vetter 			break;
657fbe40783SDaniel Vetter 		case I965_PGETBL_SIZE_256KB:
658e5e408fcSDaniel Vetter 			size = KB(256);
659fbe40783SDaniel Vetter 			break;
660fbe40783SDaniel Vetter 		case I965_PGETBL_SIZE_512KB:
661e5e408fcSDaniel Vetter 			size = KB(512);
662fbe40783SDaniel Vetter 			break;
663fbe40783SDaniel Vetter 		case I965_PGETBL_SIZE_1MB:
664e5e408fcSDaniel Vetter 			size = KB(1024);
665fbe40783SDaniel Vetter 			break;
666fbe40783SDaniel Vetter 		case I965_PGETBL_SIZE_2MB:
667e5e408fcSDaniel Vetter 			size = KB(2048);
668fbe40783SDaniel Vetter 			break;
669fbe40783SDaniel Vetter 		case I965_PGETBL_SIZE_1_5MB:
670e5e408fcSDaniel Vetter 			size = KB(1024 + 512);
671fbe40783SDaniel Vetter 			break;
672fbe40783SDaniel Vetter 		default:
673fbe40783SDaniel Vetter 			dev_info(&intel_private.pcidev->dev,
674fbe40783SDaniel Vetter 				 "unknown page table size, assuming 512KB\n");
675e5e408fcSDaniel Vetter 			size = KB(512);
676fbe40783SDaniel Vetter 		}
677e5e408fcSDaniel Vetter 
678e5e408fcSDaniel Vetter 		return size/4;
679210b23c2SDaniel Vetter 	} else if (INTEL_GTT_GEN == 6) {
680210b23c2SDaniel Vetter 		u16 snb_gmch_ctl;
681210b23c2SDaniel Vetter 
682210b23c2SDaniel Vetter 		pci_read_config_word(intel_private.pcidev, SNB_GMCH_CTRL, &snb_gmch_ctl);
683210b23c2SDaniel Vetter 		switch (snb_gmch_ctl & SNB_GTT_SIZE_MASK) {
684210b23c2SDaniel Vetter 		default:
685210b23c2SDaniel Vetter 		case SNB_GTT_SIZE_0M:
686210b23c2SDaniel Vetter 			printk(KERN_ERR "Bad GTT size mask: 0x%04x.\n", snb_gmch_ctl);
687210b23c2SDaniel Vetter 			size = MB(0);
688210b23c2SDaniel Vetter 			break;
689210b23c2SDaniel Vetter 		case SNB_GTT_SIZE_1M:
690210b23c2SDaniel Vetter 			size = MB(1);
691210b23c2SDaniel Vetter 			break;
692210b23c2SDaniel Vetter 		case SNB_GTT_SIZE_2M:
693210b23c2SDaniel Vetter 			size = MB(2);
694210b23c2SDaniel Vetter 			break;
695210b23c2SDaniel Vetter 		}
696210b23c2SDaniel Vetter 		return size/4;
697fbe40783SDaniel Vetter 	} else {
698fbe40783SDaniel Vetter 		/* On previous hardware, the GTT size was just what was
699fbe40783SDaniel Vetter 		 * required to map the aperture.
700fbe40783SDaniel Vetter 		 */
701e5e408fcSDaniel Vetter 		return intel_private.base.gtt_mappable_entries;
702fbe40783SDaniel Vetter 	}
703fbe40783SDaniel Vetter }
704fbe40783SDaniel Vetter 
7051784a5fbSDaniel Vetter static unsigned int intel_gtt_mappable_entries(void)
7061784a5fbSDaniel Vetter {
7071784a5fbSDaniel Vetter 	unsigned int aperture_size;
7081784a5fbSDaniel Vetter 
709b1c5b0f8SChris Wilson 	if (INTEL_GTT_GEN == 2) {
710b1c5b0f8SChris Wilson 		u16 gmch_ctrl;
7111784a5fbSDaniel Vetter 
7121784a5fbSDaniel Vetter 		pci_read_config_word(intel_private.bridge_dev,
7131784a5fbSDaniel Vetter 				     I830_GMCH_CTRL, &gmch_ctrl);
7141784a5fbSDaniel Vetter 
7151784a5fbSDaniel Vetter 		if ((gmch_ctrl & I830_GMCH_MEM_MASK) == I830_GMCH_MEM_64M)
716b1c5b0f8SChris Wilson 			aperture_size = MB(64);
7171784a5fbSDaniel Vetter 		else
718b1c5b0f8SChris Wilson 			aperture_size = MB(128);
719239918f7SDaniel Vetter 	} else {
7201784a5fbSDaniel Vetter 		/* 9xx supports large sizes, just look at the length */
7211784a5fbSDaniel Vetter 		aperture_size = pci_resource_len(intel_private.pcidev, 2);
7221784a5fbSDaniel Vetter 	}
7231784a5fbSDaniel Vetter 
7241784a5fbSDaniel Vetter 	return aperture_size >> PAGE_SHIFT;
7251784a5fbSDaniel Vetter }
7261784a5fbSDaniel Vetter 
7270e87d2b0SDaniel Vetter static void intel_gtt_teardown_scratch_page(void)
7280e87d2b0SDaniel Vetter {
7290e87d2b0SDaniel Vetter 	set_pages_wb(intel_private.scratch_page, 1);
7300e87d2b0SDaniel Vetter 	pci_unmap_page(intel_private.pcidev, intel_private.scratch_page_dma,
7310e87d2b0SDaniel Vetter 		       PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
7320e87d2b0SDaniel Vetter 	put_page(intel_private.scratch_page);
7330e87d2b0SDaniel Vetter 	__free_page(intel_private.scratch_page);
7340e87d2b0SDaniel Vetter }
7350e87d2b0SDaniel Vetter 
7360e87d2b0SDaniel Vetter static void intel_gtt_cleanup(void)
7370e87d2b0SDaniel Vetter {
738ae83dd5cSDaniel Vetter 	intel_private.driver->cleanup();
739ae83dd5cSDaniel Vetter 
7400e87d2b0SDaniel Vetter 	iounmap(intel_private.gtt);
7410e87d2b0SDaniel Vetter 	iounmap(intel_private.registers);
7420e87d2b0SDaniel Vetter 
7430e87d2b0SDaniel Vetter 	intel_gtt_teardown_scratch_page();
7440e87d2b0SDaniel Vetter }
7450e87d2b0SDaniel Vetter 
7461784a5fbSDaniel Vetter static int intel_gtt_init(void)
7471784a5fbSDaniel Vetter {
748f67eab66SDaniel Vetter 	u32 gtt_map_size;
7493b15a9d7SDaniel Vetter 	int ret;
7503b15a9d7SDaniel Vetter 
7513b15a9d7SDaniel Vetter 	ret = intel_private.driver->setup();
7523b15a9d7SDaniel Vetter 	if (ret != 0)
7533b15a9d7SDaniel Vetter 		return ret;
754f67eab66SDaniel Vetter 
755f67eab66SDaniel Vetter 	intel_private.base.gtt_mappable_entries = intel_gtt_mappable_entries();
756f67eab66SDaniel Vetter 	intel_private.base.gtt_total_entries = intel_gtt_total_entries();
757f67eab66SDaniel Vetter 
758*b3eafc5aSDaniel Vetter 	/* save the PGETBL reg for resume */
759*b3eafc5aSDaniel Vetter 	intel_private.PGETBL_save =
760*b3eafc5aSDaniel Vetter 		readl(intel_private.registers+I810_PGETBL_CTL)
761*b3eafc5aSDaniel Vetter 			& ~I810_PGETBL_ENABLED;
762*b3eafc5aSDaniel Vetter 
7630af9e92eSDaniel Vetter 	dev_info(&intel_private.bridge_dev->dev,
7640af9e92eSDaniel Vetter 			"detected gtt size: %dK total, %dK mappable\n",
7650af9e92eSDaniel Vetter 			intel_private.base.gtt_total_entries * 4,
7660af9e92eSDaniel Vetter 			intel_private.base.gtt_mappable_entries * 4);
7670af9e92eSDaniel Vetter 
768f67eab66SDaniel Vetter 	gtt_map_size = intel_private.base.gtt_total_entries * 4;
769f67eab66SDaniel Vetter 
770f67eab66SDaniel Vetter 	intel_private.gtt = ioremap(intel_private.gtt_bus_addr,
771f67eab66SDaniel Vetter 				    gtt_map_size);
772f67eab66SDaniel Vetter 	if (!intel_private.gtt) {
773ae83dd5cSDaniel Vetter 		intel_private.driver->cleanup();
774f67eab66SDaniel Vetter 		iounmap(intel_private.registers);
775f67eab66SDaniel Vetter 		return -ENOMEM;
776f67eab66SDaniel Vetter 	}
777f67eab66SDaniel Vetter 
778f67eab66SDaniel Vetter 	global_cache_flush();   /* FIXME: ? */
779f67eab66SDaniel Vetter 
7801784a5fbSDaniel Vetter 	/* we have to call this as early as possible after the MMIO base address is known */
7811784a5fbSDaniel Vetter 	intel_private.base.gtt_stolen_entries = intel_gtt_stolen_entries();
7821784a5fbSDaniel Vetter 	if (intel_private.base.gtt_stolen_entries == 0) {
783ae83dd5cSDaniel Vetter 		intel_private.driver->cleanup();
7841784a5fbSDaniel Vetter 		iounmap(intel_private.registers);
785f67eab66SDaniel Vetter 		iounmap(intel_private.gtt);
7861784a5fbSDaniel Vetter 		return -ENOMEM;
7871784a5fbSDaniel Vetter 	}
7881784a5fbSDaniel Vetter 
7890e87d2b0SDaniel Vetter 	ret = intel_gtt_setup_scratch_page();
7900e87d2b0SDaniel Vetter 	if (ret != 0) {
7910e87d2b0SDaniel Vetter 		intel_gtt_cleanup();
7920e87d2b0SDaniel Vetter 		return ret;
7930e87d2b0SDaniel Vetter 	}
7940e87d2b0SDaniel Vetter 
7951784a5fbSDaniel Vetter 	return 0;
7961784a5fbSDaniel Vetter }
7971784a5fbSDaniel Vetter 
7983e921f98SDaniel Vetter static int intel_fake_agp_fetch_size(void)
7993e921f98SDaniel Vetter {
8009e76e7b8SChris Wilson 	int num_sizes = ARRAY_SIZE(intel_fake_agp_sizes);
8013e921f98SDaniel Vetter 	unsigned int aper_size;
8023e921f98SDaniel Vetter 	int i;
8033e921f98SDaniel Vetter 
8043e921f98SDaniel Vetter 	aper_size = (intel_private.base.gtt_mappable_entries << PAGE_SHIFT)
8053e921f98SDaniel Vetter 		    / MB(1);
8063e921f98SDaniel Vetter 
8073e921f98SDaniel Vetter 	for (i = 0; i < num_sizes; i++) {
808ffdd7510SDaniel Vetter 		if (aper_size == intel_fake_agp_sizes[i].size) {
8099e76e7b8SChris Wilson 			agp_bridge->current_size =
8109e76e7b8SChris Wilson 				(void *) (intel_fake_agp_sizes + i);
8113e921f98SDaniel Vetter 			return aper_size;
8123e921f98SDaniel Vetter 		}
8133e921f98SDaniel Vetter 	}
8143e921f98SDaniel Vetter 
8153e921f98SDaniel Vetter 	return 0;
8163e921f98SDaniel Vetter }
8173e921f98SDaniel Vetter 
818ae83dd5cSDaniel Vetter static void i830_cleanup(void)
819f51b7662SDaniel Vetter {
820f51b7662SDaniel Vetter 	kunmap(intel_private.i8xx_page);
821f51b7662SDaniel Vetter 	intel_private.i8xx_flush_page = NULL;
822f51b7662SDaniel Vetter 
823f51b7662SDaniel Vetter 	__free_page(intel_private.i8xx_page);
824f51b7662SDaniel Vetter 	intel_private.i8xx_page = NULL;
825f51b7662SDaniel Vetter }
826f51b7662SDaniel Vetter 
827f51b7662SDaniel Vetter static void intel_i830_setup_flush(void)
828f51b7662SDaniel Vetter {
829f51b7662SDaniel Vetter 	/* return if we've already set the flush mechanism up */
830f51b7662SDaniel Vetter 	if (intel_private.i8xx_page)
831f51b7662SDaniel Vetter 		return;
832f51b7662SDaniel Vetter 
833e61cb0d5SJan Beulich 	intel_private.i8xx_page = alloc_page(GFP_KERNEL);
834f51b7662SDaniel Vetter 	if (!intel_private.i8xx_page)
835f51b7662SDaniel Vetter 		return;
836f51b7662SDaniel Vetter 
837f51b7662SDaniel Vetter 	intel_private.i8xx_flush_page = kmap(intel_private.i8xx_page);
838f51b7662SDaniel Vetter 	if (!intel_private.i8xx_flush_page)
839ae83dd5cSDaniel Vetter 		i830_cleanup();
840f51b7662SDaniel Vetter }
841f51b7662SDaniel Vetter 
842f51b7662SDaniel Vetter /* The chipset_flush interface needs to get data that has already been
843f51b7662SDaniel Vetter  * flushed out of the CPU all the way out to main memory, because the GPU
844f51b7662SDaniel Vetter  * doesn't snoop those buffers.
845f51b7662SDaniel Vetter  *
846f51b7662SDaniel Vetter  * The 8xx series doesn't have the same lovely interface for flushing the
847f51b7662SDaniel Vetter  * chipset write buffers that the later chips do. According to the 865
848f51b7662SDaniel Vetter  * specs, it's 64 octwords, or 1KB.  So, to get those previous things in
849f51b7662SDaniel Vetter  * that buffer out, we just fill 1KB and clflush it out, on the assumption
850f51b7662SDaniel Vetter  * that it'll push whatever was in there out.  It appears to work.
851f51b7662SDaniel Vetter  */
8521b263f24SDaniel Vetter static void i830_chipset_flush(void)
853f51b7662SDaniel Vetter {
854f51b7662SDaniel Vetter 	unsigned int *pg = intel_private.i8xx_flush_page;
855f51b7662SDaniel Vetter 
856f51b7662SDaniel Vetter 	memset(pg, 0, 1024);
857f51b7662SDaniel Vetter 
858f51b7662SDaniel Vetter 	if (cpu_has_clflush)
859f51b7662SDaniel Vetter 		clflush_cache_range(pg, 1024);
860f51b7662SDaniel Vetter 	else if (wbinvd_on_all_cpus() != 0)
861f51b7662SDaniel Vetter 		printk(KERN_ERR "Timed out waiting for cache flush.\n");
862f51b7662SDaniel Vetter }
863f51b7662SDaniel Vetter 
864351bb278SDaniel Vetter static void i830_write_entry(dma_addr_t addr, unsigned int entry,
865351bb278SDaniel Vetter 			     unsigned int flags)
866351bb278SDaniel Vetter {
867351bb278SDaniel Vetter 	u32 pte_flags = I810_PTE_VALID;
868351bb278SDaniel Vetter 
869351bb278SDaniel Vetter 	switch (flags) {
870351bb278SDaniel Vetter 	case AGP_DCACHE_MEMORY:
871351bb278SDaniel Vetter 		pte_flags |= I810_PTE_LOCAL;
872351bb278SDaniel Vetter 		break;
873351bb278SDaniel Vetter 	case AGP_USER_CACHED_MEMORY:
874351bb278SDaniel Vetter 		pte_flags |= I830_PTE_SYSTEM_CACHED;
875351bb278SDaniel Vetter 		break;
876351bb278SDaniel Vetter 	}
877351bb278SDaniel Vetter 
878351bb278SDaniel Vetter 	writel(addr | pte_flags, intel_private.gtt + entry);
879351bb278SDaniel Vetter }
880351bb278SDaniel Vetter 
88173800422SDaniel Vetter static void intel_enable_gtt(void)
88273800422SDaniel Vetter {
8833f08e4efSChris Wilson 	u32 gma_addr;
88473800422SDaniel Vetter 	u16 gmch_ctrl;
88573800422SDaniel Vetter 
8862d2430cfSDaniel Vetter 	if (INTEL_GTT_GEN == 2)
8872d2430cfSDaniel Vetter 		pci_read_config_dword(intel_private.pcidev, I810_GMADDR,
8882d2430cfSDaniel Vetter 				      &gma_addr);
8892d2430cfSDaniel Vetter 	else
8902d2430cfSDaniel Vetter 		pci_read_config_dword(intel_private.pcidev, I915_GMADDR,
8912d2430cfSDaniel Vetter 				      &gma_addr);
8922d2430cfSDaniel Vetter 
89373800422SDaniel Vetter 	intel_private.gma_bus_addr = (gma_addr & PCI_BASE_ADDRESS_MEM_MASK);
89473800422SDaniel Vetter 
89573800422SDaniel Vetter 	pci_read_config_word(intel_private.bridge_dev, I830_GMCH_CTRL, &gmch_ctrl);
89673800422SDaniel Vetter 	gmch_ctrl |= I830_GMCH_ENABLED;
89773800422SDaniel Vetter 	pci_write_config_word(intel_private.bridge_dev, I830_GMCH_CTRL, gmch_ctrl);
89873800422SDaniel Vetter 
899*b3eafc5aSDaniel Vetter 	writel(intel_private.PGETBL_save|I810_PGETBL_ENABLED,
9003f08e4efSChris Wilson 	       intel_private.registers+I810_PGETBL_CTL);
90173800422SDaniel Vetter 	readl(intel_private.registers+I810_PGETBL_CTL);	/* PCI Posting. */
90273800422SDaniel Vetter }
90373800422SDaniel Vetter 
90473800422SDaniel Vetter static int i830_setup(void)
90573800422SDaniel Vetter {
90673800422SDaniel Vetter 	u32 reg_addr;
90773800422SDaniel Vetter 
90873800422SDaniel Vetter 	pci_read_config_dword(intel_private.pcidev, I810_MMADDR, &reg_addr);
90973800422SDaniel Vetter 	reg_addr &= 0xfff80000;
91073800422SDaniel Vetter 
91173800422SDaniel Vetter 	intel_private.registers = ioremap(reg_addr, KB(64));
91273800422SDaniel Vetter 	if (!intel_private.registers)
91373800422SDaniel Vetter 		return -ENOMEM;
91473800422SDaniel Vetter 
91573800422SDaniel Vetter 	intel_private.gtt_bus_addr = reg_addr + I810_PTE_BASE;
91673800422SDaniel Vetter 
91773800422SDaniel Vetter 	intel_i830_setup_flush();
91873800422SDaniel Vetter 
91973800422SDaniel Vetter 	return 0;
92073800422SDaniel Vetter }
92173800422SDaniel Vetter 
9223b15a9d7SDaniel Vetter static int intel_fake_agp_create_gatt_table(struct agp_bridge_data *bridge)
923f51b7662SDaniel Vetter {
92473800422SDaniel Vetter 	agp_bridge->gatt_table_real = NULL;
925f51b7662SDaniel Vetter 	agp_bridge->gatt_table = NULL;
92673800422SDaniel Vetter 	agp_bridge->gatt_bus_addr = 0;
927f51b7662SDaniel Vetter 
928f51b7662SDaniel Vetter 	return 0;
929f51b7662SDaniel Vetter }
930f51b7662SDaniel Vetter 
931ffdd7510SDaniel Vetter static int intel_fake_agp_free_gatt_table(struct agp_bridge_data *bridge)
932f51b7662SDaniel Vetter {
933f51b7662SDaniel Vetter 	return 0;
934f51b7662SDaniel Vetter }
935f51b7662SDaniel Vetter 
936351bb278SDaniel Vetter static int intel_fake_agp_configure(void)
937f51b7662SDaniel Vetter {
938f51b7662SDaniel Vetter 	int i;
939f51b7662SDaniel Vetter 
94073800422SDaniel Vetter 	intel_enable_gtt();
941f51b7662SDaniel Vetter 
94273800422SDaniel Vetter 	agp_bridge->gart_bus_addr = intel_private.gma_bus_addr;
943f51b7662SDaniel Vetter 
94473800422SDaniel Vetter 	for (i = intel_private.base.gtt_stolen_entries;
94573800422SDaniel Vetter 			i < intel_private.base.gtt_total_entries; i++) {
946351bb278SDaniel Vetter 		intel_private.driver->write_entry(intel_private.scratch_page_dma,
947351bb278SDaniel Vetter 						  i, 0);
948f51b7662SDaniel Vetter 	}
949fdfb58a9SDaniel Vetter 	readl(intel_private.gtt+i-1);	/* PCI Posting. */
950f51b7662SDaniel Vetter 
951f51b7662SDaniel Vetter 	global_cache_flush();
952f51b7662SDaniel Vetter 
953f51b7662SDaniel Vetter 	return 0;
954f51b7662SDaniel Vetter }
955f51b7662SDaniel Vetter 
9565cbecafcSDaniel Vetter static bool i830_check_flags(unsigned int flags)
957f51b7662SDaniel Vetter {
9585cbecafcSDaniel Vetter 	switch (flags) {
9595cbecafcSDaniel Vetter 	case 0:
9605cbecafcSDaniel Vetter 	case AGP_PHYS_MEMORY:
9615cbecafcSDaniel Vetter 	case AGP_USER_CACHED_MEMORY:
9625cbecafcSDaniel Vetter 	case AGP_USER_MEMORY:
9635cbecafcSDaniel Vetter 		return true;
9645cbecafcSDaniel Vetter 	}
9655cbecafcSDaniel Vetter 
9665cbecafcSDaniel Vetter 	return false;
9675cbecafcSDaniel Vetter }
9685cbecafcSDaniel Vetter 
969fefaa70fSDaniel Vetter static void intel_gtt_insert_sg_entries(struct scatterlist *sg_list,
970fefaa70fSDaniel Vetter 					unsigned int sg_len,
971fefaa70fSDaniel Vetter 					unsigned int pg_start,
972fefaa70fSDaniel Vetter 					unsigned int flags)
973fefaa70fSDaniel Vetter {
974fefaa70fSDaniel Vetter 	struct scatterlist *sg;
975fefaa70fSDaniel Vetter 	unsigned int len, m;
976fefaa70fSDaniel Vetter 	int i, j;
977fefaa70fSDaniel Vetter 
978fefaa70fSDaniel Vetter 	j = pg_start;
979fefaa70fSDaniel Vetter 
980fefaa70fSDaniel Vetter 	/* sg may merge pages, but we have to separate
981fefaa70fSDaniel Vetter 	 * per-page addr for GTT */
982fefaa70fSDaniel Vetter 	for_each_sg(sg_list, sg, sg_len, i) {
983fefaa70fSDaniel Vetter 		len = sg_dma_len(sg) >> PAGE_SHIFT;
984fefaa70fSDaniel Vetter 		for (m = 0; m < len; m++) {
985fefaa70fSDaniel Vetter 			dma_addr_t addr = sg_dma_address(sg) + (m << PAGE_SHIFT);
986fefaa70fSDaniel Vetter 			intel_private.driver->write_entry(addr,
987fefaa70fSDaniel Vetter 							  j, flags);
988fefaa70fSDaniel Vetter 			j++;
989fefaa70fSDaniel Vetter 		}
990fefaa70fSDaniel Vetter 	}
991fefaa70fSDaniel Vetter 	readl(intel_private.gtt+j-1);
992fefaa70fSDaniel Vetter }
993fefaa70fSDaniel Vetter 
9945cbecafcSDaniel Vetter static int intel_fake_agp_insert_entries(struct agp_memory *mem,
9955cbecafcSDaniel Vetter 					 off_t pg_start, int type)
9965cbecafcSDaniel Vetter {
9975cbecafcSDaniel Vetter 	int i, j;
998f51b7662SDaniel Vetter 	int ret = -EINVAL;
999f51b7662SDaniel Vetter 
1000f51b7662SDaniel Vetter 	if (mem->page_count == 0)
1001f51b7662SDaniel Vetter 		goto out;
1002f51b7662SDaniel Vetter 
10030ade6386SDaniel Vetter 	if (pg_start < intel_private.base.gtt_stolen_entries) {
1004f51b7662SDaniel Vetter 		dev_printk(KERN_DEBUG, &intel_private.pcidev->dev,
10050ade6386SDaniel Vetter 			   "pg_start == 0x%.8lx, gtt_stolen_entries == 0x%.8x\n",
10060ade6386SDaniel Vetter 			   pg_start, intel_private.base.gtt_stolen_entries);
1007f51b7662SDaniel Vetter 
1008f51b7662SDaniel Vetter 		dev_info(&intel_private.pcidev->dev,
1009f51b7662SDaniel Vetter 			 "trying to insert into local/stolen memory\n");
1010f51b7662SDaniel Vetter 		goto out_err;
1011f51b7662SDaniel Vetter 	}
1012f51b7662SDaniel Vetter 
10135cbecafcSDaniel Vetter 	if ((pg_start + mem->page_count) > intel_private.base.gtt_total_entries)
1014f51b7662SDaniel Vetter 		goto out_err;
1015f51b7662SDaniel Vetter 
1016f51b7662SDaniel Vetter 	if (type != mem->type)
1017f51b7662SDaniel Vetter 		goto out_err;
1018f51b7662SDaniel Vetter 
10195cbecafcSDaniel Vetter 	if (!intel_private.driver->check_flags(type))
1020f51b7662SDaniel Vetter 		goto out_err;
1021f51b7662SDaniel Vetter 
1022f51b7662SDaniel Vetter 	if (!mem->is_flushed)
1023f51b7662SDaniel Vetter 		global_cache_flush();
1024f51b7662SDaniel Vetter 
1025fefaa70fSDaniel Vetter 	if (USE_PCI_DMA_API && INTEL_GTT_GEN > 2) {
1026fefaa70fSDaniel Vetter 		ret = intel_agp_map_memory(mem);
1027fefaa70fSDaniel Vetter 		if (ret != 0)
1028fefaa70fSDaniel Vetter 			return ret;
1029fefaa70fSDaniel Vetter 
1030fefaa70fSDaniel Vetter 		intel_gtt_insert_sg_entries(mem->sg_list, mem->num_sg,
1031fefaa70fSDaniel Vetter 					    pg_start, type);
1032fefaa70fSDaniel Vetter 	} else {
1033f51b7662SDaniel Vetter 		for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
1034fefaa70fSDaniel Vetter 			dma_addr_t addr = page_to_phys(mem->pages[i]);
1035fefaa70fSDaniel Vetter 			intel_private.driver->write_entry(addr,
10365cbecafcSDaniel Vetter 							  j, type);
1037f51b7662SDaniel Vetter 		}
1038fdfb58a9SDaniel Vetter 		readl(intel_private.gtt+j-1);
1039fefaa70fSDaniel Vetter 	}
1040f51b7662SDaniel Vetter 
1041f51b7662SDaniel Vetter out:
1042f51b7662SDaniel Vetter 	ret = 0;
1043f51b7662SDaniel Vetter out_err:
1044f51b7662SDaniel Vetter 	mem->is_flushed = true;
1045f51b7662SDaniel Vetter 	return ret;
1046f51b7662SDaniel Vetter }
1047f51b7662SDaniel Vetter 
10485cbecafcSDaniel Vetter static int intel_fake_agp_remove_entries(struct agp_memory *mem,
10495cbecafcSDaniel Vetter 					 off_t pg_start, int type)
1050f51b7662SDaniel Vetter {
1051f51b7662SDaniel Vetter 	int i;
1052f51b7662SDaniel Vetter 
1053f51b7662SDaniel Vetter 	if (mem->page_count == 0)
1054f51b7662SDaniel Vetter 		return 0;
1055f51b7662SDaniel Vetter 
10560ade6386SDaniel Vetter 	if (pg_start < intel_private.base.gtt_stolen_entries) {
1057f51b7662SDaniel Vetter 		dev_info(&intel_private.pcidev->dev,
1058f51b7662SDaniel Vetter 			 "trying to disable local/stolen memory\n");
1059f51b7662SDaniel Vetter 		return -EINVAL;
1060f51b7662SDaniel Vetter 	}
1061f51b7662SDaniel Vetter 
1062fefaa70fSDaniel Vetter 	if (USE_PCI_DMA_API && INTEL_GTT_GEN > 2)
1063fefaa70fSDaniel Vetter 		intel_agp_unmap_memory(mem);
1064fefaa70fSDaniel Vetter 
1065f51b7662SDaniel Vetter 	for (i = pg_start; i < (mem->page_count + pg_start); i++) {
10665cbecafcSDaniel Vetter 		intel_private.driver->write_entry(intel_private.scratch_page_dma,
10675cbecafcSDaniel Vetter 						  i, 0);
1068f51b7662SDaniel Vetter 	}
1069fdfb58a9SDaniel Vetter 	readl(intel_private.gtt+i-1);
1070f51b7662SDaniel Vetter 
1071f51b7662SDaniel Vetter 	return 0;
1072f51b7662SDaniel Vetter }
1073f51b7662SDaniel Vetter 
10741b263f24SDaniel Vetter static void intel_fake_agp_chipset_flush(struct agp_bridge_data *bridge)
10751b263f24SDaniel Vetter {
10761b263f24SDaniel Vetter 	intel_private.driver->chipset_flush();
10771b263f24SDaniel Vetter }
10781b263f24SDaniel Vetter 
1079ffdd7510SDaniel Vetter static struct agp_memory *intel_fake_agp_alloc_by_type(size_t pg_count,
1080ffdd7510SDaniel Vetter 						       int type)
1081f51b7662SDaniel Vetter {
1082f51b7662SDaniel Vetter 	if (type == AGP_PHYS_MEMORY)
1083f51b7662SDaniel Vetter 		return alloc_agpphysmem_i8xx(pg_count, type);
1084f51b7662SDaniel Vetter 	/* always return NULL for other allocation types for now */
1085f51b7662SDaniel Vetter 	return NULL;
1086f51b7662SDaniel Vetter }
1087f51b7662SDaniel Vetter 
1088f51b7662SDaniel Vetter static int intel_alloc_chipset_flush_resource(void)
1089f51b7662SDaniel Vetter {
1090f51b7662SDaniel Vetter 	int ret;
1091d7cca2f7SDaniel Vetter 	ret = pci_bus_alloc_resource(intel_private.bridge_dev->bus, &intel_private.ifp_resource, PAGE_SIZE,
1092f51b7662SDaniel Vetter 				     PAGE_SIZE, PCIBIOS_MIN_MEM, 0,
1093d7cca2f7SDaniel Vetter 				     pcibios_align_resource, intel_private.bridge_dev);
1094f51b7662SDaniel Vetter 
1095f51b7662SDaniel Vetter 	return ret;
1096f51b7662SDaniel Vetter }
1097f51b7662SDaniel Vetter 
1098f51b7662SDaniel Vetter static void intel_i915_setup_chipset_flush(void)
1099f51b7662SDaniel Vetter {
1100f51b7662SDaniel Vetter 	int ret;
1101f51b7662SDaniel Vetter 	u32 temp;
1102f51b7662SDaniel Vetter 
1103d7cca2f7SDaniel Vetter 	pci_read_config_dword(intel_private.bridge_dev, I915_IFPADDR, &temp);
1104f51b7662SDaniel Vetter 	if (!(temp & 0x1)) {
1105f51b7662SDaniel Vetter 		intel_alloc_chipset_flush_resource();
1106f51b7662SDaniel Vetter 		intel_private.resource_valid = 1;
1107d7cca2f7SDaniel Vetter 		pci_write_config_dword(intel_private.bridge_dev, I915_IFPADDR, (intel_private.ifp_resource.start & 0xffffffff) | 0x1);
1108f51b7662SDaniel Vetter 	} else {
1109f51b7662SDaniel Vetter 		temp &= ~1;
1110f51b7662SDaniel Vetter 
1111f51b7662SDaniel Vetter 		intel_private.resource_valid = 1;
1112f51b7662SDaniel Vetter 		intel_private.ifp_resource.start = temp;
1113f51b7662SDaniel Vetter 		intel_private.ifp_resource.end = temp + PAGE_SIZE;
1114f51b7662SDaniel Vetter 		ret = request_resource(&iomem_resource, &intel_private.ifp_resource);
1115f51b7662SDaniel Vetter 		/* some BIOSes reserve this area in a pnp some don't */
1116f51b7662SDaniel Vetter 		if (ret)
1117f51b7662SDaniel Vetter 			intel_private.resource_valid = 0;
1118f51b7662SDaniel Vetter 	}
1119f51b7662SDaniel Vetter }
1120f51b7662SDaniel Vetter 
1121f51b7662SDaniel Vetter static void intel_i965_g33_setup_chipset_flush(void)
1122f51b7662SDaniel Vetter {
1123f51b7662SDaniel Vetter 	u32 temp_hi, temp_lo;
1124f51b7662SDaniel Vetter 	int ret;
1125f51b7662SDaniel Vetter 
1126d7cca2f7SDaniel Vetter 	pci_read_config_dword(intel_private.bridge_dev, I965_IFPADDR + 4, &temp_hi);
1127d7cca2f7SDaniel Vetter 	pci_read_config_dword(intel_private.bridge_dev, I965_IFPADDR, &temp_lo);
1128f51b7662SDaniel Vetter 
1129f51b7662SDaniel Vetter 	if (!(temp_lo & 0x1)) {
1130f51b7662SDaniel Vetter 
1131f51b7662SDaniel Vetter 		intel_alloc_chipset_flush_resource();
1132f51b7662SDaniel Vetter 
1133f51b7662SDaniel Vetter 		intel_private.resource_valid = 1;
1134d7cca2f7SDaniel Vetter 		pci_write_config_dword(intel_private.bridge_dev, I965_IFPADDR + 4,
1135f51b7662SDaniel Vetter 			upper_32_bits(intel_private.ifp_resource.start));
1136d7cca2f7SDaniel Vetter 		pci_write_config_dword(intel_private.bridge_dev, I965_IFPADDR, (intel_private.ifp_resource.start & 0xffffffff) | 0x1);
1137f51b7662SDaniel Vetter 	} else {
1138f51b7662SDaniel Vetter 		u64 l64;
1139f51b7662SDaniel Vetter 
1140f51b7662SDaniel Vetter 		temp_lo &= ~0x1;
1141f51b7662SDaniel Vetter 		l64 = ((u64)temp_hi << 32) | temp_lo;
1142f51b7662SDaniel Vetter 
1143f51b7662SDaniel Vetter 		intel_private.resource_valid = 1;
1144f51b7662SDaniel Vetter 		intel_private.ifp_resource.start = l64;
1145f51b7662SDaniel Vetter 		intel_private.ifp_resource.end = l64 + PAGE_SIZE;
1146f51b7662SDaniel Vetter 		ret = request_resource(&iomem_resource, &intel_private.ifp_resource);
1147f51b7662SDaniel Vetter 		/* some BIOSes reserve this area in a pnp some don't */
1148f51b7662SDaniel Vetter 		if (ret)
1149f51b7662SDaniel Vetter 			intel_private.resource_valid = 0;
1150f51b7662SDaniel Vetter 	}
1151f51b7662SDaniel Vetter }
1152f51b7662SDaniel Vetter 
1153f51b7662SDaniel Vetter static void intel_i9xx_setup_flush(void)
1154f51b7662SDaniel Vetter {
1155f51b7662SDaniel Vetter 	/* return if already configured */
1156f51b7662SDaniel Vetter 	if (intel_private.ifp_resource.start)
1157f51b7662SDaniel Vetter 		return;
1158f51b7662SDaniel Vetter 
11591a997ff2SDaniel Vetter 	if (INTEL_GTT_GEN == 6)
1160f51b7662SDaniel Vetter 		return;
1161f51b7662SDaniel Vetter 
1162f51b7662SDaniel Vetter 	/* setup a resource for this object */
1163f51b7662SDaniel Vetter 	intel_private.ifp_resource.name = "Intel Flush Page";
1164f51b7662SDaniel Vetter 	intel_private.ifp_resource.flags = IORESOURCE_MEM;
1165f51b7662SDaniel Vetter 
1166f51b7662SDaniel Vetter 	/* Setup chipset flush for 915 */
11671a997ff2SDaniel Vetter 	if (IS_G33 || INTEL_GTT_GEN >= 4) {
1168f51b7662SDaniel Vetter 		intel_i965_g33_setup_chipset_flush();
1169f51b7662SDaniel Vetter 	} else {
1170f51b7662SDaniel Vetter 		intel_i915_setup_chipset_flush();
1171f51b7662SDaniel Vetter 	}
1172f51b7662SDaniel Vetter 
1173df51e7aaSChris Wilson 	if (intel_private.ifp_resource.start)
1174f51b7662SDaniel Vetter 		intel_private.i9xx_flush_page = ioremap_nocache(intel_private.ifp_resource.start, PAGE_SIZE);
1175f51b7662SDaniel Vetter 	if (!intel_private.i9xx_flush_page)
1176df51e7aaSChris Wilson 		dev_err(&intel_private.pcidev->dev,
1177df51e7aaSChris Wilson 			"can't ioremap flush page - no chipset flushing\n");
1178f51b7662SDaniel Vetter }
1179f51b7662SDaniel Vetter 
1180ae83dd5cSDaniel Vetter static void i9xx_cleanup(void)
1181ae83dd5cSDaniel Vetter {
1182ae83dd5cSDaniel Vetter 	if (intel_private.i9xx_flush_page)
1183ae83dd5cSDaniel Vetter 		iounmap(intel_private.i9xx_flush_page);
1184ae83dd5cSDaniel Vetter 	if (intel_private.resource_valid)
1185ae83dd5cSDaniel Vetter 		release_resource(&intel_private.ifp_resource);
1186ae83dd5cSDaniel Vetter 	intel_private.ifp_resource.start = 0;
1187ae83dd5cSDaniel Vetter 	intel_private.resource_valid = 0;
1188ae83dd5cSDaniel Vetter }
1189ae83dd5cSDaniel Vetter 
11901b263f24SDaniel Vetter static void i9xx_chipset_flush(void)
1191f51b7662SDaniel Vetter {
1192f51b7662SDaniel Vetter 	if (intel_private.i9xx_flush_page)
1193f51b7662SDaniel Vetter 		writel(1, intel_private.i9xx_flush_page);
1194f51b7662SDaniel Vetter }
1195f51b7662SDaniel Vetter 
1196a6963596SDaniel Vetter static void i965_write_entry(dma_addr_t addr, unsigned int entry,
1197a6963596SDaniel Vetter 			     unsigned int flags)
1198a6963596SDaniel Vetter {
1199a6963596SDaniel Vetter 	/* Shift high bits down */
1200a6963596SDaniel Vetter 	addr |= (addr >> 28) & 0xf0;
1201a6963596SDaniel Vetter 	writel(addr | I810_PTE_VALID, intel_private.gtt + entry);
1202a6963596SDaniel Vetter }
1203a6963596SDaniel Vetter 
120490cb149eSDaniel Vetter static bool gen6_check_flags(unsigned int flags)
120590cb149eSDaniel Vetter {
120690cb149eSDaniel Vetter 	return true;
120790cb149eSDaniel Vetter }
120890cb149eSDaniel Vetter 
120997ef1bddSDaniel Vetter static void gen6_write_entry(dma_addr_t addr, unsigned int entry,
121097ef1bddSDaniel Vetter 			     unsigned int flags)
121197ef1bddSDaniel Vetter {
121297ef1bddSDaniel Vetter 	unsigned int type_mask = flags & ~AGP_USER_CACHED_MEMORY_GFDT;
121397ef1bddSDaniel Vetter 	unsigned int gfdt = flags & AGP_USER_CACHED_MEMORY_GFDT;
121497ef1bddSDaniel Vetter 	u32 pte_flags;
121597ef1bddSDaniel Vetter 
121697ef1bddSDaniel Vetter 	if (type_mask == AGP_USER_UNCACHED_MEMORY)
121785ccc35bSChris Wilson 		pte_flags = GEN6_PTE_UNCACHED | I810_PTE_VALID;
121897ef1bddSDaniel Vetter 	else if (type_mask == AGP_USER_CACHED_MEMORY_LLC_MLC) {
121985ccc35bSChris Wilson 		pte_flags = GEN6_PTE_LLC | I810_PTE_VALID;
122097ef1bddSDaniel Vetter 		if (gfdt)
122197ef1bddSDaniel Vetter 			pte_flags |= GEN6_PTE_GFDT;
122297ef1bddSDaniel Vetter 	} else { /* set 'normal'/'cached' to LLC by default */
122385ccc35bSChris Wilson 		pte_flags = GEN6_PTE_LLC_MLC | I810_PTE_VALID;
122497ef1bddSDaniel Vetter 		if (gfdt)
122597ef1bddSDaniel Vetter 			pte_flags |= GEN6_PTE_GFDT;
122697ef1bddSDaniel Vetter 	}
122797ef1bddSDaniel Vetter 
122897ef1bddSDaniel Vetter 	/* gen6 has bit11-4 for physical addr bit39-32 */
122997ef1bddSDaniel Vetter 	addr |= (addr >> 28) & 0xff0;
123097ef1bddSDaniel Vetter 	writel(addr | pte_flags, intel_private.gtt + entry);
123197ef1bddSDaniel Vetter }
123297ef1bddSDaniel Vetter 
1233ae83dd5cSDaniel Vetter static void gen6_cleanup(void)
1234ae83dd5cSDaniel Vetter {
1235ae83dd5cSDaniel Vetter }
1236ae83dd5cSDaniel Vetter 
12372d2430cfSDaniel Vetter static int i9xx_setup(void)
12382d2430cfSDaniel Vetter {
12392d2430cfSDaniel Vetter 	u32 reg_addr;
12402d2430cfSDaniel Vetter 
12412d2430cfSDaniel Vetter 	pci_read_config_dword(intel_private.pcidev, I915_MMADDR, &reg_addr);
12422d2430cfSDaniel Vetter 
12432d2430cfSDaniel Vetter 	reg_addr &= 0xfff80000;
12442d2430cfSDaniel Vetter 
12452d2430cfSDaniel Vetter 	intel_private.registers = ioremap(reg_addr, 128 * 4096);
12462d2430cfSDaniel Vetter 	if (!intel_private.registers)
12472d2430cfSDaniel Vetter 		return -ENOMEM;
12482d2430cfSDaniel Vetter 
12492d2430cfSDaniel Vetter 	if (INTEL_GTT_GEN == 3) {
12502d2430cfSDaniel Vetter 		u32 gtt_addr;
12513f08e4efSChris Wilson 
12522d2430cfSDaniel Vetter 		pci_read_config_dword(intel_private.pcidev,
12532d2430cfSDaniel Vetter 				      I915_PTEADDR, &gtt_addr);
12542d2430cfSDaniel Vetter 		intel_private.gtt_bus_addr = gtt_addr;
12552d2430cfSDaniel Vetter 	} else {
12562d2430cfSDaniel Vetter 		u32 gtt_offset;
12572d2430cfSDaniel Vetter 
12582d2430cfSDaniel Vetter 		switch (INTEL_GTT_GEN) {
12592d2430cfSDaniel Vetter 		case 5:
12602d2430cfSDaniel Vetter 		case 6:
12612d2430cfSDaniel Vetter 			gtt_offset = MB(2);
12622d2430cfSDaniel Vetter 			break;
12632d2430cfSDaniel Vetter 		case 4:
12642d2430cfSDaniel Vetter 		default:
12652d2430cfSDaniel Vetter 			gtt_offset =  KB(512);
12662d2430cfSDaniel Vetter 			break;
12672d2430cfSDaniel Vetter 		}
12682d2430cfSDaniel Vetter 		intel_private.gtt_bus_addr = reg_addr + gtt_offset;
12692d2430cfSDaniel Vetter 	}
12702d2430cfSDaniel Vetter 
12712d2430cfSDaniel Vetter 	intel_i9xx_setup_flush();
12722d2430cfSDaniel Vetter 
12732d2430cfSDaniel Vetter 	return 0;
12742d2430cfSDaniel Vetter }
12752d2430cfSDaniel Vetter 
1276f51b7662SDaniel Vetter static const struct agp_bridge_driver intel_810_driver = {
1277f51b7662SDaniel Vetter 	.owner			= THIS_MODULE,
1278f51b7662SDaniel Vetter 	.aperture_sizes		= intel_i810_sizes,
1279f51b7662SDaniel Vetter 	.size_type		= FIXED_APER_SIZE,
1280f51b7662SDaniel Vetter 	.num_aperture_sizes	= 2,
1281f51b7662SDaniel Vetter 	.needs_scratch_page	= true,
1282f51b7662SDaniel Vetter 	.configure		= intel_i810_configure,
1283f51b7662SDaniel Vetter 	.fetch_size		= intel_i810_fetch_size,
1284f51b7662SDaniel Vetter 	.cleanup		= intel_i810_cleanup,
1285f51b7662SDaniel Vetter 	.mask_memory		= intel_i810_mask_memory,
1286f51b7662SDaniel Vetter 	.masks			= intel_i810_masks,
1287ffdd7510SDaniel Vetter 	.agp_enable		= intel_fake_agp_enable,
1288f51b7662SDaniel Vetter 	.cache_flush		= global_cache_flush,
1289f51b7662SDaniel Vetter 	.create_gatt_table	= agp_generic_create_gatt_table,
1290f51b7662SDaniel Vetter 	.free_gatt_table	= agp_generic_free_gatt_table,
1291f51b7662SDaniel Vetter 	.insert_memory		= intel_i810_insert_entries,
1292f51b7662SDaniel Vetter 	.remove_memory		= intel_i810_remove_entries,
1293f51b7662SDaniel Vetter 	.alloc_by_type		= intel_i810_alloc_by_type,
1294f51b7662SDaniel Vetter 	.free_by_type		= intel_i810_free_by_type,
1295f51b7662SDaniel Vetter 	.agp_alloc_page		= agp_generic_alloc_page,
1296f51b7662SDaniel Vetter 	.agp_alloc_pages        = agp_generic_alloc_pages,
1297f51b7662SDaniel Vetter 	.agp_destroy_page	= agp_generic_destroy_page,
1298f51b7662SDaniel Vetter 	.agp_destroy_pages      = agp_generic_destroy_pages,
1299f51b7662SDaniel Vetter 	.agp_type_to_mask_type  = agp_generic_type_to_mask_type,
1300f51b7662SDaniel Vetter };
1301f51b7662SDaniel Vetter 
1302e9b1cc81SDaniel Vetter static const struct agp_bridge_driver intel_fake_agp_driver = {
1303f51b7662SDaniel Vetter 	.owner			= THIS_MODULE,
1304f51b7662SDaniel Vetter 	.size_type		= FIXED_APER_SIZE,
13059e76e7b8SChris Wilson 	.aperture_sizes		= intel_fake_agp_sizes,
13069e76e7b8SChris Wilson 	.num_aperture_sizes	= ARRAY_SIZE(intel_fake_agp_sizes),
1307a6963596SDaniel Vetter 	.configure		= intel_fake_agp_configure,
13083e921f98SDaniel Vetter 	.fetch_size		= intel_fake_agp_fetch_size,
1309fdfb58a9SDaniel Vetter 	.cleanup		= intel_gtt_cleanup,
1310ffdd7510SDaniel Vetter 	.agp_enable		= intel_fake_agp_enable,
1311f51b7662SDaniel Vetter 	.cache_flush		= global_cache_flush,
13123b15a9d7SDaniel Vetter 	.create_gatt_table	= intel_fake_agp_create_gatt_table,
1313ffdd7510SDaniel Vetter 	.free_gatt_table	= intel_fake_agp_free_gatt_table,
1314450f2b3dSDaniel Vetter 	.insert_memory		= intel_fake_agp_insert_entries,
1315450f2b3dSDaniel Vetter 	.remove_memory		= intel_fake_agp_remove_entries,
1316ffdd7510SDaniel Vetter 	.alloc_by_type		= intel_fake_agp_alloc_by_type,
1317f51b7662SDaniel Vetter 	.free_by_type		= intel_i810_free_by_type,
1318f51b7662SDaniel Vetter 	.agp_alloc_page		= agp_generic_alloc_page,
1319f51b7662SDaniel Vetter 	.agp_alloc_pages        = agp_generic_alloc_pages,
1320f51b7662SDaniel Vetter 	.agp_destroy_page	= agp_generic_destroy_page,
1321f51b7662SDaniel Vetter 	.agp_destroy_pages      = agp_generic_destroy_pages,
13221b263f24SDaniel Vetter 	.chipset_flush		= intel_fake_agp_chipset_flush,
1323f51b7662SDaniel Vetter };
132402c026ceSDaniel Vetter 
1325bdd30729SDaniel Vetter static const struct intel_gtt_driver i81x_gtt_driver = {
1326bdd30729SDaniel Vetter 	.gen = 1,
132722533b49SDaniel Vetter 	.dma_mask_size = 32,
1328bdd30729SDaniel Vetter };
13291a997ff2SDaniel Vetter static const struct intel_gtt_driver i8xx_gtt_driver = {
13301a997ff2SDaniel Vetter 	.gen = 2,
133173800422SDaniel Vetter 	.setup = i830_setup,
1332ae83dd5cSDaniel Vetter 	.cleanup = i830_cleanup,
1333351bb278SDaniel Vetter 	.write_entry = i830_write_entry,
133422533b49SDaniel Vetter 	.dma_mask_size = 32,
13355cbecafcSDaniel Vetter 	.check_flags = i830_check_flags,
13361b263f24SDaniel Vetter 	.chipset_flush = i830_chipset_flush,
13371a997ff2SDaniel Vetter };
13381a997ff2SDaniel Vetter static const struct intel_gtt_driver i915_gtt_driver = {
13391a997ff2SDaniel Vetter 	.gen = 3,
13402d2430cfSDaniel Vetter 	.setup = i9xx_setup,
1341ae83dd5cSDaniel Vetter 	.cleanup = i9xx_cleanup,
1342351bb278SDaniel Vetter 	/* i945 is the last gpu to need phys mem (for overlay and cursors). */
1343351bb278SDaniel Vetter 	.write_entry = i830_write_entry,
134422533b49SDaniel Vetter 	.dma_mask_size = 32,
1345fefaa70fSDaniel Vetter 	.check_flags = i830_check_flags,
13461b263f24SDaniel Vetter 	.chipset_flush = i9xx_chipset_flush,
13471a997ff2SDaniel Vetter };
13481a997ff2SDaniel Vetter static const struct intel_gtt_driver g33_gtt_driver = {
13491a997ff2SDaniel Vetter 	.gen = 3,
13501a997ff2SDaniel Vetter 	.is_g33 = 1,
13512d2430cfSDaniel Vetter 	.setup = i9xx_setup,
1352ae83dd5cSDaniel Vetter 	.cleanup = i9xx_cleanup,
1353a6963596SDaniel Vetter 	.write_entry = i965_write_entry,
135422533b49SDaniel Vetter 	.dma_mask_size = 36,
1355450f2b3dSDaniel Vetter 	.check_flags = i830_check_flags,
13561b263f24SDaniel Vetter 	.chipset_flush = i9xx_chipset_flush,
13571a997ff2SDaniel Vetter };
13581a997ff2SDaniel Vetter static const struct intel_gtt_driver pineview_gtt_driver = {
13591a997ff2SDaniel Vetter 	.gen = 3,
13601a997ff2SDaniel Vetter 	.is_pineview = 1, .is_g33 = 1,
13612d2430cfSDaniel Vetter 	.setup = i9xx_setup,
1362ae83dd5cSDaniel Vetter 	.cleanup = i9xx_cleanup,
1363a6963596SDaniel Vetter 	.write_entry = i965_write_entry,
136422533b49SDaniel Vetter 	.dma_mask_size = 36,
1365450f2b3dSDaniel Vetter 	.check_flags = i830_check_flags,
13661b263f24SDaniel Vetter 	.chipset_flush = i9xx_chipset_flush,
13671a997ff2SDaniel Vetter };
13681a997ff2SDaniel Vetter static const struct intel_gtt_driver i965_gtt_driver = {
13691a997ff2SDaniel Vetter 	.gen = 4,
13702d2430cfSDaniel Vetter 	.setup = i9xx_setup,
1371ae83dd5cSDaniel Vetter 	.cleanup = i9xx_cleanup,
1372a6963596SDaniel Vetter 	.write_entry = i965_write_entry,
137322533b49SDaniel Vetter 	.dma_mask_size = 36,
1374450f2b3dSDaniel Vetter 	.check_flags = i830_check_flags,
13751b263f24SDaniel Vetter 	.chipset_flush = i9xx_chipset_flush,
13761a997ff2SDaniel Vetter };
13771a997ff2SDaniel Vetter static const struct intel_gtt_driver g4x_gtt_driver = {
13781a997ff2SDaniel Vetter 	.gen = 5,
13792d2430cfSDaniel Vetter 	.setup = i9xx_setup,
1380ae83dd5cSDaniel Vetter 	.cleanup = i9xx_cleanup,
1381a6963596SDaniel Vetter 	.write_entry = i965_write_entry,
138222533b49SDaniel Vetter 	.dma_mask_size = 36,
1383450f2b3dSDaniel Vetter 	.check_flags = i830_check_flags,
13841b263f24SDaniel Vetter 	.chipset_flush = i9xx_chipset_flush,
13851a997ff2SDaniel Vetter };
13861a997ff2SDaniel Vetter static const struct intel_gtt_driver ironlake_gtt_driver = {
13871a997ff2SDaniel Vetter 	.gen = 5,
13881a997ff2SDaniel Vetter 	.is_ironlake = 1,
13892d2430cfSDaniel Vetter 	.setup = i9xx_setup,
1390ae83dd5cSDaniel Vetter 	.cleanup = i9xx_cleanup,
1391a6963596SDaniel Vetter 	.write_entry = i965_write_entry,
139222533b49SDaniel Vetter 	.dma_mask_size = 36,
1393450f2b3dSDaniel Vetter 	.check_flags = i830_check_flags,
13941b263f24SDaniel Vetter 	.chipset_flush = i9xx_chipset_flush,
13951a997ff2SDaniel Vetter };
13961a997ff2SDaniel Vetter static const struct intel_gtt_driver sandybridge_gtt_driver = {
13971a997ff2SDaniel Vetter 	.gen = 6,
13982d2430cfSDaniel Vetter 	.setup = i9xx_setup,
1399ae83dd5cSDaniel Vetter 	.cleanup = gen6_cleanup,
140097ef1bddSDaniel Vetter 	.write_entry = gen6_write_entry,
140122533b49SDaniel Vetter 	.dma_mask_size = 40,
140290cb149eSDaniel Vetter 	.check_flags = gen6_check_flags,
14031b263f24SDaniel Vetter 	.chipset_flush = i9xx_chipset_flush,
14041a997ff2SDaniel Vetter };
14051a997ff2SDaniel Vetter 
140602c026ceSDaniel Vetter /* Table to describe Intel GMCH and AGP/PCIE GART drivers.  At least one of
140702c026ceSDaniel Vetter  * driver and gmch_driver must be non-null, and find_gmch will determine
140802c026ceSDaniel Vetter  * which one should be used if a gmch_chip_id is present.
140902c026ceSDaniel Vetter  */
141002c026ceSDaniel Vetter static const struct intel_gtt_driver_description {
141102c026ceSDaniel Vetter 	unsigned int gmch_chip_id;
141202c026ceSDaniel Vetter 	char *name;
141302c026ceSDaniel Vetter 	const struct agp_bridge_driver *gmch_driver;
14141a997ff2SDaniel Vetter 	const struct intel_gtt_driver *gtt_driver;
141502c026ceSDaniel Vetter } intel_gtt_chipsets[] = {
1416bdd30729SDaniel Vetter 	{ PCI_DEVICE_ID_INTEL_82810_IG1, "i810", &intel_810_driver,
1417bdd30729SDaniel Vetter 		&i81x_gtt_driver},
1418bdd30729SDaniel Vetter 	{ PCI_DEVICE_ID_INTEL_82810_IG3, "i810", &intel_810_driver,
1419bdd30729SDaniel Vetter 		&i81x_gtt_driver},
1420bdd30729SDaniel Vetter 	{ PCI_DEVICE_ID_INTEL_82810E_IG, "i810", &intel_810_driver,
1421bdd30729SDaniel Vetter 		&i81x_gtt_driver},
1422bdd30729SDaniel Vetter 	{ PCI_DEVICE_ID_INTEL_82815_CGC, "i815", &intel_810_driver,
1423bdd30729SDaniel Vetter 		&i81x_gtt_driver},
14241a997ff2SDaniel Vetter 	{ PCI_DEVICE_ID_INTEL_82830_CGC, "830M",
1425e9b1cc81SDaniel Vetter 		&intel_fake_agp_driver, &i8xx_gtt_driver},
14261a997ff2SDaniel Vetter 	{ PCI_DEVICE_ID_INTEL_82845G_IG, "830M",
1427e9b1cc81SDaniel Vetter 		&intel_fake_agp_driver, &i8xx_gtt_driver},
14281a997ff2SDaniel Vetter 	{ PCI_DEVICE_ID_INTEL_82854_IG, "854",
1429e9b1cc81SDaniel Vetter 		&intel_fake_agp_driver, &i8xx_gtt_driver},
14301a997ff2SDaniel Vetter 	{ PCI_DEVICE_ID_INTEL_82855GM_IG, "855GM",
1431e9b1cc81SDaniel Vetter 		&intel_fake_agp_driver, &i8xx_gtt_driver},
14321a997ff2SDaniel Vetter 	{ PCI_DEVICE_ID_INTEL_82865_IG, "865",
1433e9b1cc81SDaniel Vetter 		&intel_fake_agp_driver, &i8xx_gtt_driver},
14341a997ff2SDaniel Vetter 	{ PCI_DEVICE_ID_INTEL_E7221_IG, "E7221 (i915)",
1435e9b1cc81SDaniel Vetter 		&intel_fake_agp_driver, &i915_gtt_driver },
14361a997ff2SDaniel Vetter 	{ PCI_DEVICE_ID_INTEL_82915G_IG, "915G",
1437e9b1cc81SDaniel Vetter 		&intel_fake_agp_driver, &i915_gtt_driver },
14381a997ff2SDaniel Vetter 	{ PCI_DEVICE_ID_INTEL_82915GM_IG, "915GM",
1439e9b1cc81SDaniel Vetter 		&intel_fake_agp_driver, &i915_gtt_driver },
14401a997ff2SDaniel Vetter 	{ PCI_DEVICE_ID_INTEL_82945G_IG, "945G",
1441e9b1cc81SDaniel Vetter 		&intel_fake_agp_driver, &i915_gtt_driver },
14421a997ff2SDaniel Vetter 	{ PCI_DEVICE_ID_INTEL_82945GM_IG, "945GM",
1443e9b1cc81SDaniel Vetter 		&intel_fake_agp_driver, &i915_gtt_driver },
14441a997ff2SDaniel Vetter 	{ PCI_DEVICE_ID_INTEL_82945GME_IG, "945GME",
1445e9b1cc81SDaniel Vetter 		&intel_fake_agp_driver, &i915_gtt_driver },
14461a997ff2SDaniel Vetter 	{ PCI_DEVICE_ID_INTEL_82946GZ_IG, "946GZ",
1447e9b1cc81SDaniel Vetter 		&intel_fake_agp_driver, &i965_gtt_driver },
14481a997ff2SDaniel Vetter 	{ PCI_DEVICE_ID_INTEL_82G35_IG, "G35",
1449e9b1cc81SDaniel Vetter 		&intel_fake_agp_driver, &i965_gtt_driver },
14501a997ff2SDaniel Vetter 	{ PCI_DEVICE_ID_INTEL_82965Q_IG, "965Q",
1451e9b1cc81SDaniel Vetter 		&intel_fake_agp_driver, &i965_gtt_driver },
14521a997ff2SDaniel Vetter 	{ PCI_DEVICE_ID_INTEL_82965G_IG, "965G",
1453e9b1cc81SDaniel Vetter 		&intel_fake_agp_driver, &i965_gtt_driver },
14541a997ff2SDaniel Vetter 	{ PCI_DEVICE_ID_INTEL_82965GM_IG, "965GM",
1455e9b1cc81SDaniel Vetter 		&intel_fake_agp_driver, &i965_gtt_driver },
14561a997ff2SDaniel Vetter 	{ PCI_DEVICE_ID_INTEL_82965GME_IG, "965GME/GLE",
1457e9b1cc81SDaniel Vetter 		&intel_fake_agp_driver, &i965_gtt_driver },
14581a997ff2SDaniel Vetter 	{ PCI_DEVICE_ID_INTEL_G33_IG, "G33",
1459e9b1cc81SDaniel Vetter 		&intel_fake_agp_driver, &g33_gtt_driver },
14601a997ff2SDaniel Vetter 	{ PCI_DEVICE_ID_INTEL_Q35_IG, "Q35",
1461e9b1cc81SDaniel Vetter 		&intel_fake_agp_driver, &g33_gtt_driver },
14621a997ff2SDaniel Vetter 	{ PCI_DEVICE_ID_INTEL_Q33_IG, "Q33",
1463e9b1cc81SDaniel Vetter 		&intel_fake_agp_driver, &g33_gtt_driver },
14641a997ff2SDaniel Vetter 	{ PCI_DEVICE_ID_INTEL_PINEVIEW_M_IG, "GMA3150",
1465e9b1cc81SDaniel Vetter 		&intel_fake_agp_driver, &pineview_gtt_driver },
14661a997ff2SDaniel Vetter 	{ PCI_DEVICE_ID_INTEL_PINEVIEW_IG, "GMA3150",
1467e9b1cc81SDaniel Vetter 		&intel_fake_agp_driver, &pineview_gtt_driver },
14681a997ff2SDaniel Vetter 	{ PCI_DEVICE_ID_INTEL_GM45_IG, "GM45",
1469e9b1cc81SDaniel Vetter 		&intel_fake_agp_driver, &g4x_gtt_driver },
14701a997ff2SDaniel Vetter 	{ PCI_DEVICE_ID_INTEL_EAGLELAKE_IG, "Eaglelake",
1471e9b1cc81SDaniel Vetter 		&intel_fake_agp_driver, &g4x_gtt_driver },
14721a997ff2SDaniel Vetter 	{ PCI_DEVICE_ID_INTEL_Q45_IG, "Q45/Q43",
1473e9b1cc81SDaniel Vetter 		&intel_fake_agp_driver, &g4x_gtt_driver },
14741a997ff2SDaniel Vetter 	{ PCI_DEVICE_ID_INTEL_G45_IG, "G45/G43",
1475e9b1cc81SDaniel Vetter 		&intel_fake_agp_driver, &g4x_gtt_driver },
14761a997ff2SDaniel Vetter 	{ PCI_DEVICE_ID_INTEL_B43_IG, "B43",
1477e9b1cc81SDaniel Vetter 		&intel_fake_agp_driver, &g4x_gtt_driver },
1478e9e5f8e8SChris Wilson 	{ PCI_DEVICE_ID_INTEL_B43_1_IG, "B43",
1479e9b1cc81SDaniel Vetter 		&intel_fake_agp_driver, &g4x_gtt_driver },
14801a997ff2SDaniel Vetter 	{ PCI_DEVICE_ID_INTEL_G41_IG, "G41",
1481e9b1cc81SDaniel Vetter 		&intel_fake_agp_driver, &g4x_gtt_driver },
148202c026ceSDaniel Vetter 	{ PCI_DEVICE_ID_INTEL_IRONLAKE_D_IG,
1483e9b1cc81SDaniel Vetter 	    "HD Graphics", &intel_fake_agp_driver, &ironlake_gtt_driver },
148402c026ceSDaniel Vetter 	{ PCI_DEVICE_ID_INTEL_IRONLAKE_M_IG,
1485e9b1cc81SDaniel Vetter 	    "HD Graphics", &intel_fake_agp_driver, &ironlake_gtt_driver },
148602c026ceSDaniel Vetter 	{ PCI_DEVICE_ID_INTEL_SANDYBRIDGE_GT1_IG,
1487e9b1cc81SDaniel Vetter 	    "Sandybridge", &intel_fake_agp_driver, &sandybridge_gtt_driver },
148802c026ceSDaniel Vetter 	{ PCI_DEVICE_ID_INTEL_SANDYBRIDGE_GT2_IG,
1489e9b1cc81SDaniel Vetter 	    "Sandybridge", &intel_fake_agp_driver, &sandybridge_gtt_driver },
149002c026ceSDaniel Vetter 	{ PCI_DEVICE_ID_INTEL_SANDYBRIDGE_GT2_PLUS_IG,
1491e9b1cc81SDaniel Vetter 	    "Sandybridge", &intel_fake_agp_driver, &sandybridge_gtt_driver },
149202c026ceSDaniel Vetter 	{ PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_GT1_IG,
1493e9b1cc81SDaniel Vetter 	    "Sandybridge", &intel_fake_agp_driver, &sandybridge_gtt_driver },
149402c026ceSDaniel Vetter 	{ PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_GT2_IG,
1495e9b1cc81SDaniel Vetter 	    "Sandybridge", &intel_fake_agp_driver, &sandybridge_gtt_driver },
149602c026ceSDaniel Vetter 	{ PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_GT2_PLUS_IG,
1497e9b1cc81SDaniel Vetter 	    "Sandybridge", &intel_fake_agp_driver, &sandybridge_gtt_driver },
149802c026ceSDaniel Vetter 	{ PCI_DEVICE_ID_INTEL_SANDYBRIDGE_S_IG,
1499e9b1cc81SDaniel Vetter 	    "Sandybridge", &intel_fake_agp_driver, &sandybridge_gtt_driver },
150002c026ceSDaniel Vetter 	{ 0, NULL, NULL }
150102c026ceSDaniel Vetter };
150202c026ceSDaniel Vetter 
150302c026ceSDaniel Vetter static int find_gmch(u16 device)
150402c026ceSDaniel Vetter {
150502c026ceSDaniel Vetter 	struct pci_dev *gmch_device;
150602c026ceSDaniel Vetter 
150702c026ceSDaniel Vetter 	gmch_device = pci_get_device(PCI_VENDOR_ID_INTEL, device, NULL);
150802c026ceSDaniel Vetter 	if (gmch_device && PCI_FUNC(gmch_device->devfn) != 0) {
150902c026ceSDaniel Vetter 		gmch_device = pci_get_device(PCI_VENDOR_ID_INTEL,
151002c026ceSDaniel Vetter 					     device, gmch_device);
151102c026ceSDaniel Vetter 	}
151202c026ceSDaniel Vetter 
151302c026ceSDaniel Vetter 	if (!gmch_device)
151402c026ceSDaniel Vetter 		return 0;
151502c026ceSDaniel Vetter 
151602c026ceSDaniel Vetter 	intel_private.pcidev = gmch_device;
151702c026ceSDaniel Vetter 	return 1;
151802c026ceSDaniel Vetter }
151902c026ceSDaniel Vetter 
1520e2404e7cSDaniel Vetter int intel_gmch_probe(struct pci_dev *pdev,
152102c026ceSDaniel Vetter 				      struct agp_bridge_data *bridge)
152202c026ceSDaniel Vetter {
152302c026ceSDaniel Vetter 	int i, mask;
152402c026ceSDaniel Vetter 	bridge->driver = NULL;
152502c026ceSDaniel Vetter 
152602c026ceSDaniel Vetter 	for (i = 0; intel_gtt_chipsets[i].name != NULL; i++) {
152702c026ceSDaniel Vetter 		if (find_gmch(intel_gtt_chipsets[i].gmch_chip_id)) {
152802c026ceSDaniel Vetter 			bridge->driver =
152902c026ceSDaniel Vetter 				intel_gtt_chipsets[i].gmch_driver;
15301a997ff2SDaniel Vetter 			intel_private.driver =
15311a997ff2SDaniel Vetter 				intel_gtt_chipsets[i].gtt_driver;
153202c026ceSDaniel Vetter 			break;
153302c026ceSDaniel Vetter 		}
153402c026ceSDaniel Vetter 	}
153502c026ceSDaniel Vetter 
153602c026ceSDaniel Vetter 	if (!bridge->driver)
153702c026ceSDaniel Vetter 		return 0;
153802c026ceSDaniel Vetter 
153902c026ceSDaniel Vetter 	bridge->dev_private_data = &intel_private;
154002c026ceSDaniel Vetter 	bridge->dev = pdev;
154102c026ceSDaniel Vetter 
1542d7cca2f7SDaniel Vetter 	intel_private.bridge_dev = pci_dev_get(pdev);
1543d7cca2f7SDaniel Vetter 
154402c026ceSDaniel Vetter 	dev_info(&pdev->dev, "Intel %s Chipset\n", intel_gtt_chipsets[i].name);
154502c026ceSDaniel Vetter 
154622533b49SDaniel Vetter 	mask = intel_private.driver->dma_mask_size;
154702c026ceSDaniel Vetter 	if (pci_set_dma_mask(intel_private.pcidev, DMA_BIT_MASK(mask)))
154802c026ceSDaniel Vetter 		dev_err(&intel_private.pcidev->dev,
154902c026ceSDaniel Vetter 			"set gfx device dma mask %d-bit failed!\n", mask);
155002c026ceSDaniel Vetter 	else
155102c026ceSDaniel Vetter 		pci_set_consistent_dma_mask(intel_private.pcidev,
155202c026ceSDaniel Vetter 					    DMA_BIT_MASK(mask));
155302c026ceSDaniel Vetter 
15541784a5fbSDaniel Vetter 	if (bridge->driver == &intel_810_driver)
15551784a5fbSDaniel Vetter 		return 1;
15561784a5fbSDaniel Vetter 
15573b15a9d7SDaniel Vetter 	if (intel_gtt_init() != 0)
15583b15a9d7SDaniel Vetter 		return 0;
15591784a5fbSDaniel Vetter 
156002c026ceSDaniel Vetter 	return 1;
156102c026ceSDaniel Vetter }
1562e2404e7cSDaniel Vetter EXPORT_SYMBOL(intel_gmch_probe);
156302c026ceSDaniel Vetter 
156419966754SDaniel Vetter struct intel_gtt *intel_gtt_get(void)
156519966754SDaniel Vetter {
156619966754SDaniel Vetter 	return &intel_private.base;
156719966754SDaniel Vetter }
156819966754SDaniel Vetter EXPORT_SYMBOL(intel_gtt_get);
156919966754SDaniel Vetter 
1570e2404e7cSDaniel Vetter void intel_gmch_remove(struct pci_dev *pdev)
157102c026ceSDaniel Vetter {
157202c026ceSDaniel Vetter 	if (intel_private.pcidev)
157302c026ceSDaniel Vetter 		pci_dev_put(intel_private.pcidev);
1574d7cca2f7SDaniel Vetter 	if (intel_private.bridge_dev)
1575d7cca2f7SDaniel Vetter 		pci_dev_put(intel_private.bridge_dev);
157602c026ceSDaniel Vetter }
1577e2404e7cSDaniel Vetter EXPORT_SYMBOL(intel_gmch_remove);
1578e2404e7cSDaniel Vetter 
1579e2404e7cSDaniel Vetter MODULE_AUTHOR("Dave Jones <davej@redhat.com>");
1580e2404e7cSDaniel Vetter MODULE_LICENSE("GPL and additional rights");
1581