blob: 154bb9256961482c90c11127582d65673361c2d9 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * Intel AGPGART routines.
3 */
4
Linus Torvalds1da177e2005-04-16 15:20:36 -07005#include <linux/module.h>
6#include <linux/pci.h>
7#include <linux/init.h>
Ahmed S. Darwish1eaf1222007-02-06 18:08:28 +02008#include <linux/kernel.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -07009#include <linux/pagemap.h>
10#include <linux/agp_backend.h>
Borislav Petkov48a719c2010-01-22 16:01:04 +010011#include <asm/smp.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070012#include "agp.h"
Daniel Vetterff7cdd62010-04-14 00:29:51 +020013#include "intel-agp.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070014
Zhenyu Wang1f7a6e32010-02-23 14:05:24 +080015int intel_agp_enabled;
16EXPORT_SYMBOL(intel_agp_enabled);
17
Zhenyu Wang17661682009-07-27 12:59:57 +010018/*
19 * If we have Intel graphics, we're not going to have anything other than
20 * an Intel IOMMU. So make the correct use of the PCI DMA API contingent
21 * on the Intel IOMMU support (CONFIG_DMAR).
22 * Only newer chipsets need to bother with this, of course.
23 */
24#ifdef CONFIG_DMAR
25#define USE_PCI_DMA_API 1
26#endif
27
Thomas Hellstroma030ce42007-01-23 10:33:43 +010028extern int agp_memory_reserved;
29
30
Dave Jonese5524f32007-02-22 18:41:28 -050031static const struct aper_size_info_fixed intel_i810_sizes[] =
Linus Torvalds1da177e2005-04-16 15:20:36 -070032{
33 {64, 16384, 4},
34 /* The 32M mode still requires a 64k gatt */
35 {32, 8192, 4}
36};
37
38#define AGP_DCACHE_MEMORY 1
39#define AGP_PHYS_MEMORY 2
Thomas Hellstroma030ce42007-01-23 10:33:43 +010040#define INTEL_AGP_CACHED_MEMORY 3
Linus Torvalds1da177e2005-04-16 15:20:36 -070041
42static struct gatt_mask intel_i810_masks[] =
43{
44 {.mask = I810_PTE_VALID, .type = 0},
45 {.mask = (I810_PTE_VALID | I810_PTE_LOCAL), .type = AGP_DCACHE_MEMORY},
Thomas Hellstroma030ce42007-01-23 10:33:43 +010046 {.mask = I810_PTE_VALID, .type = 0},
47 {.mask = I810_PTE_VALID | I830_PTE_SYSTEM_CACHED,
48 .type = INTEL_AGP_CACHED_MEMORY}
Linus Torvalds1da177e2005-04-16 15:20:36 -070049};
50
Wang Zhenyuc4ca8812007-05-30 09:40:46 +080051static struct _intel_private {
52 struct pci_dev *pcidev; /* device one */
53 u8 __iomem *registers;
54 u32 __iomem *gtt; /* I915G */
Linus Torvalds1da177e2005-04-16 15:20:36 -070055 int num_dcache_entries;
Wang Zhenyuc4ca8812007-05-30 09:40:46 +080056 /* gtt_entries is the number of gtt entries that are already mapped
57 * to stolen memory. Stolen memory is larger than the memory mapped
58 * through gtt_entries, as it includes some reserved space for the BIOS
59 * popup and for the GTT.
60 */
61 int gtt_entries; /* i830+ */
David Woodhousefc619012009-12-02 11:00:05 +000062 int gtt_total_size;
Dave Airlie2162e6a2007-11-21 16:36:31 +100063 union {
64 void __iomem *i9xx_flush_page;
65 void *i8xx_flush_page;
66 };
67 struct page *i8xx_page;
Dave Airlie6c00a612007-10-29 18:06:10 +100068 struct resource ifp_resource;
Dave Airlie4d64dd92008-01-23 15:34:29 +100069 int resource_valid;
Wang Zhenyuc4ca8812007-05-30 09:40:46 +080070} intel_private;
Linus Torvalds1da177e2005-04-16 15:20:36 -070071
Zhenyu Wang17661682009-07-27 12:59:57 +010072#ifdef USE_PCI_DMA_API
David Woodhousec2980d82009-07-29 08:39:26 +010073static int intel_agp_map_page(struct page *page, dma_addr_t *ret)
Zhenyu Wang17661682009-07-27 12:59:57 +010074{
David Woodhousec2980d82009-07-29 08:39:26 +010075 *ret = pci_map_page(intel_private.pcidev, page, 0,
76 PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
Zhenyu Wang17661682009-07-27 12:59:57 +010077 if (pci_dma_mapping_error(intel_private.pcidev, *ret))
78 return -EINVAL;
79 return 0;
80}
81
David Woodhousec2980d82009-07-29 08:39:26 +010082static void intel_agp_unmap_page(struct page *page, dma_addr_t dma)
Zhenyu Wang17661682009-07-27 12:59:57 +010083{
David Woodhousec2980d82009-07-29 08:39:26 +010084 pci_unmap_page(intel_private.pcidev, dma,
85 PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
Zhenyu Wang17661682009-07-27 12:59:57 +010086}
87
David Woodhouse91b8e302009-07-29 08:49:12 +010088static void intel_agp_free_sglist(struct agp_memory *mem)
89{
David Woodhousef6927752009-07-29 09:28:45 +010090 struct sg_table st;
David Woodhouse91b8e302009-07-29 08:49:12 +010091
David Woodhousef6927752009-07-29 09:28:45 +010092 st.sgl = mem->sg_list;
93 st.orig_nents = st.nents = mem->page_count;
94
95 sg_free_table(&st);
96
David Woodhouse91b8e302009-07-29 08:49:12 +010097 mem->sg_list = NULL;
98 mem->num_sg = 0;
99}
100
Zhenyu Wang17661682009-07-27 12:59:57 +0100101static int intel_agp_map_memory(struct agp_memory *mem)
102{
David Woodhousef6927752009-07-29 09:28:45 +0100103 struct sg_table st;
Zhenyu Wang17661682009-07-27 12:59:57 +0100104 struct scatterlist *sg;
105 int i;
106
107 DBG("try mapping %lu pages\n", (unsigned long)mem->page_count);
108
David Woodhousef6927752009-07-29 09:28:45 +0100109 if (sg_alloc_table(&st, mem->page_count, GFP_KERNEL))
Zhenyu Wang17661682009-07-27 12:59:57 +0100110 return -ENOMEM;
Zhenyu Wang17661682009-07-27 12:59:57 +0100111
David Woodhousef6927752009-07-29 09:28:45 +0100112 mem->sg_list = sg = st.sgl;
113
Zhenyu Wang17661682009-07-27 12:59:57 +0100114 for (i = 0 ; i < mem->page_count; i++, sg = sg_next(sg))
115 sg_set_page(sg, mem->pages[i], PAGE_SIZE, 0);
116
117 mem->num_sg = pci_map_sg(intel_private.pcidev, mem->sg_list,
118 mem->page_count, PCI_DMA_BIDIRECTIONAL);
David Woodhouse91b8e302009-07-29 08:49:12 +0100119 if (unlikely(!mem->num_sg)) {
120 intel_agp_free_sglist(mem);
Zhenyu Wang17661682009-07-27 12:59:57 +0100121 return -ENOMEM;
122 }
123 return 0;
124}
125
126static void intel_agp_unmap_memory(struct agp_memory *mem)
127{
128 DBG("try unmapping %lu pages\n", (unsigned long)mem->page_count);
129
130 pci_unmap_sg(intel_private.pcidev, mem->sg_list,
131 mem->page_count, PCI_DMA_BIDIRECTIONAL);
David Woodhouse91b8e302009-07-29 08:49:12 +0100132 intel_agp_free_sglist(mem);
Zhenyu Wang17661682009-07-27 12:59:57 +0100133}
134
135static void intel_agp_insert_sg_entries(struct agp_memory *mem,
136 off_t pg_start, int mask_type)
137{
138 struct scatterlist *sg;
139 int i, j;
140
141 j = pg_start;
142
143 WARN_ON(!mem->num_sg);
144
145 if (mem->num_sg == mem->page_count) {
146 for_each_sg(mem->sg_list, sg, mem->page_count, i) {
147 writel(agp_bridge->driver->mask_memory(agp_bridge,
148 sg_dma_address(sg), mask_type),
149 intel_private.gtt+j);
150 j++;
151 }
152 } else {
Daniel Mack3ad2f3f2010-02-03 08:01:28 +0800153 /* sg may merge pages, but we have to separate
Zhenyu Wang17661682009-07-27 12:59:57 +0100154 * per-page addr for GTT */
155 unsigned int len, m;
156
157 for_each_sg(mem->sg_list, sg, mem->num_sg, i) {
158 len = sg_dma_len(sg) / PAGE_SIZE;
159 for (m = 0; m < len; m++) {
160 writel(agp_bridge->driver->mask_memory(agp_bridge,
161 sg_dma_address(sg) + m * PAGE_SIZE,
162 mask_type),
163 intel_private.gtt+j);
164 j++;
165 }
166 }
167 }
168 readl(intel_private.gtt+j-1);
169}
170
171#else
172
173static void intel_agp_insert_sg_entries(struct agp_memory *mem,
174 off_t pg_start, int mask_type)
175{
176 int i, j;
Eric Anholte3deb202009-11-02 15:33:05 -0800177 u32 cache_bits = 0;
178
Eric Anholt954bce52010-01-07 16:21:46 -0800179 if (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_SANDYBRIDGE_HB ||
180 agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_HB)
181 {
Eric Anholte3deb202009-11-02 15:33:05 -0800182 cache_bits = I830_PTE_SYSTEM_CACHED;
183 }
Zhenyu Wang17661682009-07-27 12:59:57 +0100184
185 for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
186 writel(agp_bridge->driver->mask_memory(agp_bridge,
David Woodhouse6a122352009-07-29 10:25:58 +0100187 page_to_phys(mem->pages[i]), mask_type),
Zhenyu Wang17661682009-07-27 12:59:57 +0100188 intel_private.gtt+j);
189 }
190
191 readl(intel_private.gtt+j-1);
192}
193
194#endif
195
Linus Torvalds1da177e2005-04-16 15:20:36 -0700196static int intel_i810_fetch_size(void)
197{
198 u32 smram_miscc;
199 struct aper_size_info_fixed *values;
200
201 pci_read_config_dword(agp_bridge->dev, I810_SMRAM_MISCC, &smram_miscc);
202 values = A_SIZE_FIX(agp_bridge->driver->aperture_sizes);
203
204 if ((smram_miscc & I810_GMS) == I810_GMS_DISABLE) {
Bjorn Helgaase3cf6952008-07-30 12:26:51 -0700205 dev_warn(&agp_bridge->dev->dev, "i810 is disabled\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700206 return 0;
207 }
208 if ((smram_miscc & I810_GFX_MEM_WIN_SIZE) == I810_GFX_MEM_WIN_32M) {
209 agp_bridge->previous_size =
210 agp_bridge->current_size = (void *) (values + 1);
211 agp_bridge->aperture_size_idx = 1;
212 return values[1].size;
213 } else {
214 agp_bridge->previous_size =
215 agp_bridge->current_size = (void *) (values);
216 agp_bridge->aperture_size_idx = 0;
217 return values[0].size;
218 }
219
220 return 0;
221}
222
223static int intel_i810_configure(void)
224{
225 struct aper_size_info_fixed *current_size;
226 u32 temp;
227 int i;
228
229 current_size = A_SIZE_FIX(agp_bridge->current_size);
230
Wang Zhenyuc4ca8812007-05-30 09:40:46 +0800231 if (!intel_private.registers) {
232 pci_read_config_dword(intel_private.pcidev, I810_MMADDR, &temp);
Dave Jonese4ac5e42007-02-04 17:37:42 -0500233 temp &= 0xfff80000;
234
Wang Zhenyuc4ca8812007-05-30 09:40:46 +0800235 intel_private.registers = ioremap(temp, 128 * 4096);
236 if (!intel_private.registers) {
Bjorn Helgaase3cf6952008-07-30 12:26:51 -0700237 dev_err(&intel_private.pcidev->dev,
238 "can't remap memory\n");
Dave Jonese4ac5e42007-02-04 17:37:42 -0500239 return -ENOMEM;
240 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700241 }
242
Wang Zhenyuc4ca8812007-05-30 09:40:46 +0800243 if ((readl(intel_private.registers+I810_DRAM_CTL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700244 & I810_DRAM_ROW_0) == I810_DRAM_ROW_0_SDRAM) {
245 /* This will need to be dynamically assigned */
Bjorn Helgaase3cf6952008-07-30 12:26:51 -0700246 dev_info(&intel_private.pcidev->dev,
247 "detected 4MB dedicated video ram\n");
Wang Zhenyuc4ca8812007-05-30 09:40:46 +0800248 intel_private.num_dcache_entries = 1024;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700249 }
Wang Zhenyuc4ca8812007-05-30 09:40:46 +0800250 pci_read_config_dword(intel_private.pcidev, I810_GMADDR, &temp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700251 agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
Wang Zhenyuc4ca8812007-05-30 09:40:46 +0800252 writel(agp_bridge->gatt_bus_addr | I810_PGETBL_ENABLED, intel_private.registers+I810_PGETBL_CTL);
253 readl(intel_private.registers+I810_PGETBL_CTL); /* PCI Posting. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700254
255 if (agp_bridge->driver->needs_scratch_page) {
256 for (i = 0; i < current_size->num_entries; i++) {
Wang Zhenyuc4ca8812007-05-30 09:40:46 +0800257 writel(agp_bridge->scratch_page, intel_private.registers+I810_PTE_BASE+(i*4));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258 }
Keith Packard44d49442008-10-14 17:18:45 -0700259 readl(intel_private.registers+I810_PTE_BASE+((i-1)*4)); /* PCI posting. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700260 }
261 global_cache_flush();
262 return 0;
263}
264
265static void intel_i810_cleanup(void)
266{
Wang Zhenyuc4ca8812007-05-30 09:40:46 +0800267 writel(0, intel_private.registers+I810_PGETBL_CTL);
268 readl(intel_private.registers); /* PCI Posting. */
269 iounmap(intel_private.registers);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700270}
271
272static void intel_i810_tlbflush(struct agp_memory *mem)
273{
274 return;
275}
276
277static void intel_i810_agp_enable(struct agp_bridge_data *bridge, u32 mode)
278{
279 return;
280}
281
282/* Exists to support ARGB cursors */
Dave Airlie07613ba2009-06-12 14:11:41 +1000283static struct page *i8xx_alloc_pages(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700284{
Dave Airlief011ae72008-01-25 11:23:04 +1000285 struct page *page;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700286
Linus Torvalds66c669b2006-11-22 14:55:29 -0800287 page = alloc_pages(GFP_KERNEL | GFP_DMA32, 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700288 if (page == NULL)
289 return NULL;
290
Arjan van de Ven6d238cc2008-01-30 13:34:06 +0100291 if (set_pages_uc(page, 4) < 0) {
292 set_pages_wb(page, 4);
Jan Beulich89cf7cc2007-04-02 14:50:14 +0100293 __free_pages(page, 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294 return NULL;
295 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700296 get_page(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700297 atomic_inc(&agp_bridge->current_memory_agp);
Dave Airlie07613ba2009-06-12 14:11:41 +1000298 return page;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700299}
300
Dave Airlie07613ba2009-06-12 14:11:41 +1000301static void i8xx_destroy_pages(struct page *page)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302{
Dave Airlie07613ba2009-06-12 14:11:41 +1000303 if (page == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700304 return;
305
Arjan van de Ven6d238cc2008-01-30 13:34:06 +0100306 set_pages_wb(page, 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700307 put_page(page);
Jan Beulich89cf7cc2007-04-02 14:50:14 +0100308 __free_pages(page, 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700309 atomic_dec(&agp_bridge->current_memory_agp);
310}
311
Thomas Hellstroma030ce42007-01-23 10:33:43 +0100312static int intel_i830_type_to_mask_type(struct agp_bridge_data *bridge,
313 int type)
314{
315 if (type < AGP_USER_TYPES)
316 return type;
317 else if (type == AGP_USER_CACHED_MEMORY)
318 return INTEL_AGP_CACHED_MEMORY;
319 else
320 return 0;
321}
322
Linus Torvalds1da177e2005-04-16 15:20:36 -0700323static int intel_i810_insert_entries(struct agp_memory *mem, off_t pg_start,
324 int type)
325{
326 int i, j, num_entries;
327 void *temp;
Thomas Hellstroma030ce42007-01-23 10:33:43 +0100328 int ret = -EINVAL;
329 int mask_type;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330
Thomas Hellstrom5aa80c72006-12-20 16:33:41 +0100331 if (mem->page_count == 0)
Thomas Hellstroma030ce42007-01-23 10:33:43 +0100332 goto out;
Thomas Hellstrom5aa80c72006-12-20 16:33:41 +0100333
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334 temp = agp_bridge->current_size;
335 num_entries = A_SIZE_FIX(temp)->num_entries;
336
Dave Jones6a92a4e2006-02-28 00:54:25 -0500337 if ((pg_start + mem->page_count) > num_entries)
Thomas Hellstroma030ce42007-01-23 10:33:43 +0100338 goto out_err;
339
Dave Jones6a92a4e2006-02-28 00:54:25 -0500340
Linus Torvalds1da177e2005-04-16 15:20:36 -0700341 for (j = pg_start; j < (pg_start + mem->page_count); j++) {
Thomas Hellstroma030ce42007-01-23 10:33:43 +0100342 if (!PGE_EMPTY(agp_bridge, readl(agp_bridge->gatt_table+j))) {
343 ret = -EBUSY;
344 goto out_err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700345 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700346 }
347
Thomas Hellstroma030ce42007-01-23 10:33:43 +0100348 if (type != mem->type)
349 goto out_err;
Thomas Hellstrom5aa80c72006-12-20 16:33:41 +0100350
Thomas Hellstroma030ce42007-01-23 10:33:43 +0100351 mask_type = agp_bridge->driver->agp_type_to_mask_type(agp_bridge, type);
352
353 switch (mask_type) {
354 case AGP_DCACHE_MEMORY:
355 if (!mem->is_flushed)
356 global_cache_flush();
357 for (i = pg_start; i < (pg_start + mem->page_count); i++) {
358 writel((i*4096)|I810_PTE_LOCAL|I810_PTE_VALID,
Wang Zhenyuc4ca8812007-05-30 09:40:46 +0800359 intel_private.registers+I810_PTE_BASE+(i*4));
Thomas Hellstroma030ce42007-01-23 10:33:43 +0100360 }
Wang Zhenyuc4ca8812007-05-30 09:40:46 +0800361 readl(intel_private.registers+I810_PTE_BASE+((i-1)*4));
Thomas Hellstroma030ce42007-01-23 10:33:43 +0100362 break;
363 case AGP_PHYS_MEMORY:
364 case AGP_NORMAL_MEMORY:
365 if (!mem->is_flushed)
366 global_cache_flush();
367 for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
368 writel(agp_bridge->driver->mask_memory(agp_bridge,
David Woodhouse6a122352009-07-29 10:25:58 +0100369 page_to_phys(mem->pages[i]), mask_type),
Wang Zhenyuc4ca8812007-05-30 09:40:46 +0800370 intel_private.registers+I810_PTE_BASE+(j*4));
Thomas Hellstroma030ce42007-01-23 10:33:43 +0100371 }
Wang Zhenyuc4ca8812007-05-30 09:40:46 +0800372 readl(intel_private.registers+I810_PTE_BASE+((j-1)*4));
Thomas Hellstroma030ce42007-01-23 10:33:43 +0100373 break;
374 default:
375 goto out_err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700376 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377
378 agp_bridge->driver->tlb_flush(mem);
Thomas Hellstroma030ce42007-01-23 10:33:43 +0100379out:
380 ret = 0;
381out_err:
Dave Airlie9516b032008-06-19 10:42:17 +1000382 mem->is_flushed = true;
Thomas Hellstroma030ce42007-01-23 10:33:43 +0100383 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384}
385
386static int intel_i810_remove_entries(struct agp_memory *mem, off_t pg_start,
387 int type)
388{
389 int i;
390
Thomas Hellstrom5aa80c72006-12-20 16:33:41 +0100391 if (mem->page_count == 0)
392 return 0;
393
Linus Torvalds1da177e2005-04-16 15:20:36 -0700394 for (i = pg_start; i < (mem->page_count + pg_start); i++) {
Wang Zhenyuc4ca8812007-05-30 09:40:46 +0800395 writel(agp_bridge->scratch_page, intel_private.registers+I810_PTE_BASE+(i*4));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700396 }
Wang Zhenyuc4ca8812007-05-30 09:40:46 +0800397 readl(intel_private.registers+I810_PTE_BASE+((i-1)*4));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399 agp_bridge->driver->tlb_flush(mem);
400 return 0;
401}
402
403/*
404 * The i810/i830 requires a physical address to program its mouse
405 * pointer into hardware.
406 * However the Xserver still writes to it through the agp aperture.
407 */
408static struct agp_memory *alloc_agpphysmem_i8xx(size_t pg_count, int type)
409{
410 struct agp_memory *new;
Dave Airlie07613ba2009-06-12 14:11:41 +1000411 struct page *page;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700412
Linus Torvalds1da177e2005-04-16 15:20:36 -0700413 switch (pg_count) {
Dave Airlie07613ba2009-06-12 14:11:41 +1000414 case 1: page = agp_bridge->driver->agp_alloc_page(agp_bridge);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415 break;
416 case 4:
417 /* kludge to get 4 physical pages for ARGB cursor */
Dave Airlie07613ba2009-06-12 14:11:41 +1000418 page = i8xx_alloc_pages();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700419 break;
420 default:
421 return NULL;
422 }
423
Dave Airlie07613ba2009-06-12 14:11:41 +1000424 if (page == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425 return NULL;
426
427 new = agp_create_memory(pg_count);
428 if (new == NULL)
429 return NULL;
430
Dave Airlie07613ba2009-06-12 14:11:41 +1000431 new->pages[0] = page;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700432 if (pg_count == 4) {
433 /* kludge to get 4 physical pages for ARGB cursor */
Dave Airlie07613ba2009-06-12 14:11:41 +1000434 new->pages[1] = new->pages[0] + 1;
435 new->pages[2] = new->pages[1] + 1;
436 new->pages[3] = new->pages[2] + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437 }
438 new->page_count = pg_count;
439 new->num_scratch_pages = pg_count;
440 new->type = AGP_PHYS_MEMORY;
Dave Airlie07613ba2009-06-12 14:11:41 +1000441 new->physical = page_to_phys(new->pages[0]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700442 return new;
443}
444
445static struct agp_memory *intel_i810_alloc_by_type(size_t pg_count, int type)
446{
447 struct agp_memory *new;
448
449 if (type == AGP_DCACHE_MEMORY) {
Wang Zhenyuc4ca8812007-05-30 09:40:46 +0800450 if (pg_count != intel_private.num_dcache_entries)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700451 return NULL;
452
453 new = agp_create_memory(1);
454 if (new == NULL)
455 return NULL;
456
457 new->type = AGP_DCACHE_MEMORY;
458 new->page_count = pg_count;
459 new->num_scratch_pages = 0;
Thomas Hellstroma030ce42007-01-23 10:33:43 +0100460 agp_free_page_array(new);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700461 return new;
462 }
463 if (type == AGP_PHYS_MEMORY)
464 return alloc_agpphysmem_i8xx(pg_count, type);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700465 return NULL;
466}
467
468static void intel_i810_free_by_type(struct agp_memory *curr)
469{
470 agp_free_key(curr->key);
Dave Jones6a92a4e2006-02-28 00:54:25 -0500471 if (curr->type == AGP_PHYS_MEMORY) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700472 if (curr->page_count == 4)
Dave Airlie07613ba2009-06-12 14:11:41 +1000473 i8xx_destroy_pages(curr->pages[0]);
Alan Hourihane88d51962005-11-06 23:35:34 -0800474 else {
Dave Airlie07613ba2009-06-12 14:11:41 +1000475 agp_bridge->driver->agp_destroy_page(curr->pages[0],
Dave Airliea2721e92007-10-15 10:19:16 +1000476 AGP_PAGE_DESTROY_UNMAP);
Dave Airlie07613ba2009-06-12 14:11:41 +1000477 agp_bridge->driver->agp_destroy_page(curr->pages[0],
Dave Airliea2721e92007-10-15 10:19:16 +1000478 AGP_PAGE_DESTROY_FREE);
Alan Hourihane88d51962005-11-06 23:35:34 -0800479 }
Thomas Hellstroma030ce42007-01-23 10:33:43 +0100480 agp_free_page_array(curr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700481 }
482 kfree(curr);
483}
484
485static unsigned long intel_i810_mask_memory(struct agp_bridge_data *bridge,
David Woodhouse2a4ceb62009-07-27 10:27:29 +0100486 dma_addr_t addr, int type)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700487{
488 /* Type checking must be done elsewhere */
489 return addr | bridge->driver->masks[type].mask;
490}
491
492static struct aper_size_info_fixed intel_i830_sizes[] =
493{
494 {128, 32768, 5},
495 /* The 64M mode still requires a 128k gatt */
496 {64, 16384, 5},
497 {256, 65536, 6},
Eric Anholt65c25aa2006-09-06 11:57:18 -0400498 {512, 131072, 7},
Linus Torvalds1da177e2005-04-16 15:20:36 -0700499};
500
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501static void intel_i830_init_gtt_entries(void)
502{
503 u16 gmch_ctrl;
Zhenyu Wang14bc4902009-11-11 01:25:25 +0800504 int gtt_entries = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700505 u8 rdct;
506 int local = 0;
507 static const int ddt[4] = { 0, 16, 32, 64 };
Eric Anholtc41e0de2006-12-19 12:57:24 -0800508 int size; /* reserved space (in kb) at the top of stolen memory */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700509
Dave Airlief011ae72008-01-25 11:23:04 +1000510 pci_read_config_word(agp_bridge->dev, I830_GMCH_CTRL, &gmch_ctrl);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700511
Eric Anholtc41e0de2006-12-19 12:57:24 -0800512 if (IS_I965) {
513 u32 pgetbl_ctl;
Wang Zhenyuc4ca8812007-05-30 09:40:46 +0800514 pgetbl_ctl = readl(intel_private.registers+I810_PGETBL_CTL);
Eric Anholtc41e0de2006-12-19 12:57:24 -0800515
Eric Anholtc41e0de2006-12-19 12:57:24 -0800516 /* The 965 has a field telling us the size of the GTT,
517 * which may be larger than what is necessary to map the
518 * aperture.
519 */
520 switch (pgetbl_ctl & I965_PGETBL_SIZE_MASK) {
521 case I965_PGETBL_SIZE_128KB:
522 size = 128;
523 break;
524 case I965_PGETBL_SIZE_256KB:
525 size = 256;
526 break;
527 case I965_PGETBL_SIZE_512KB:
528 size = 512;
529 break;
Zhenyu Wang4e8b6e22008-01-23 14:54:37 +1000530 case I965_PGETBL_SIZE_1MB:
531 size = 1024;
532 break;
533 case I965_PGETBL_SIZE_2MB:
534 size = 2048;
535 break;
536 case I965_PGETBL_SIZE_1_5MB:
537 size = 1024 + 512;
538 break;
Eric Anholtc41e0de2006-12-19 12:57:24 -0800539 default:
Bjorn Helgaase3cf6952008-07-30 12:26:51 -0700540 dev_info(&intel_private.pcidev->dev,
541 "unknown page table size, assuming 512KB\n");
Eric Anholtc41e0de2006-12-19 12:57:24 -0800542 size = 512;
543 }
544 size += 4; /* add in BIOS popup space */
Adam Jackson107f5172009-12-03 17:14:41 -0500545 } else if (IS_G33 && !IS_PINEVIEW) {
Wang Zhenyu874808c62007-06-06 11:16:25 +0800546 /* G33's GTT size defined in gmch_ctrl */
547 switch (gmch_ctrl & G33_PGETBL_SIZE_MASK) {
548 case G33_PGETBL_SIZE_1M:
549 size = 1024;
550 break;
551 case G33_PGETBL_SIZE_2M:
552 size = 2048;
553 break;
554 default:
Bjorn Helgaase3cf6952008-07-30 12:26:51 -0700555 dev_info(&agp_bridge->dev->dev,
556 "unknown page table size 0x%x, assuming 512KB\n",
Wang Zhenyu874808c62007-06-06 11:16:25 +0800557 (gmch_ctrl & G33_PGETBL_SIZE_MASK));
558 size = 512;
559 }
560 size += 4;
Adam Jackson107f5172009-12-03 17:14:41 -0500561 } else if (IS_G4X || IS_PINEVIEW) {
Zhenyu Wang25ce77a2008-06-19 14:17:58 +1000562 /* On 4 series hardware, GTT stolen is separate from graphics
Eric Anholt82e14a62008-10-14 11:28:58 -0700563 * stolen, ignore it in stolen gtt entries counting. However,
564 * 4KB of the stolen memory doesn't get mapped to the GTT.
565 */
566 size = 4;
Eric Anholtc41e0de2006-12-19 12:57:24 -0800567 } else {
568 /* On previous hardware, the GTT size was just what was
569 * required to map the aperture.
570 */
571 size = agp_bridge->driver->fetch_size() + 4;
572 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700573
574 if (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82830_HB ||
575 agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82845G_HB) {
576 switch (gmch_ctrl & I830_GMCH_GMS_MASK) {
577 case I830_GMCH_GMS_STOLEN_512:
578 gtt_entries = KB(512) - KB(size);
579 break;
580 case I830_GMCH_GMS_STOLEN_1024:
581 gtt_entries = MB(1) - KB(size);
582 break;
583 case I830_GMCH_GMS_STOLEN_8192:
584 gtt_entries = MB(8) - KB(size);
585 break;
586 case I830_GMCH_GMS_LOCAL:
Wang Zhenyuc4ca8812007-05-30 09:40:46 +0800587 rdct = readb(intel_private.registers+I830_RDRAM_CHANNEL_TYPE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700588 gtt_entries = (I830_RDRAM_ND(rdct) + 1) *
589 MB(ddt[I830_RDRAM_DDT(rdct)]);
590 local = 1;
591 break;
592 default:
593 gtt_entries = 0;
594 break;
595 }
Eric Anholt954bce52010-01-07 16:21:46 -0800596 } else if (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_SANDYBRIDGE_HB ||
597 agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_HB) {
Zhenyu Wang14bc4902009-11-11 01:25:25 +0800598 /*
599 * SandyBridge has new memory control reg at 0x50.w
Eric Anholt1089e302009-10-22 16:10:52 -0700600 */
Zhenyu Wang14bc4902009-11-11 01:25:25 +0800601 u16 snb_gmch_ctl;
602 pci_read_config_word(intel_private.pcidev, SNB_GMCH_CTRL, &snb_gmch_ctl);
603 switch (snb_gmch_ctl & SNB_GMCH_GMS_STOLEN_MASK) {
604 case SNB_GMCH_GMS_STOLEN_32M:
605 gtt_entries = MB(32) - KB(size);
606 break;
607 case SNB_GMCH_GMS_STOLEN_64M:
608 gtt_entries = MB(64) - KB(size);
609 break;
610 case SNB_GMCH_GMS_STOLEN_96M:
611 gtt_entries = MB(96) - KB(size);
612 break;
613 case SNB_GMCH_GMS_STOLEN_128M:
614 gtt_entries = MB(128) - KB(size);
615 break;
616 case SNB_GMCH_GMS_STOLEN_160M:
617 gtt_entries = MB(160) - KB(size);
618 break;
619 case SNB_GMCH_GMS_STOLEN_192M:
620 gtt_entries = MB(192) - KB(size);
621 break;
622 case SNB_GMCH_GMS_STOLEN_224M:
623 gtt_entries = MB(224) - KB(size);
624 break;
625 case SNB_GMCH_GMS_STOLEN_256M:
626 gtt_entries = MB(256) - KB(size);
627 break;
628 case SNB_GMCH_GMS_STOLEN_288M:
629 gtt_entries = MB(288) - KB(size);
630 break;
631 case SNB_GMCH_GMS_STOLEN_320M:
632 gtt_entries = MB(320) - KB(size);
633 break;
634 case SNB_GMCH_GMS_STOLEN_352M:
635 gtt_entries = MB(352) - KB(size);
636 break;
637 case SNB_GMCH_GMS_STOLEN_384M:
638 gtt_entries = MB(384) - KB(size);
639 break;
640 case SNB_GMCH_GMS_STOLEN_416M:
641 gtt_entries = MB(416) - KB(size);
642 break;
643 case SNB_GMCH_GMS_STOLEN_448M:
644 gtt_entries = MB(448) - KB(size);
645 break;
646 case SNB_GMCH_GMS_STOLEN_480M:
647 gtt_entries = MB(480) - KB(size);
648 break;
649 case SNB_GMCH_GMS_STOLEN_512M:
650 gtt_entries = MB(512) - KB(size);
651 break;
652 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700653 } else {
Dave Airliee67aa272007-09-18 22:46:35 -0700654 switch (gmch_ctrl & I855_GMCH_GMS_MASK) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655 case I855_GMCH_GMS_STOLEN_1M:
656 gtt_entries = MB(1) - KB(size);
657 break;
658 case I855_GMCH_GMS_STOLEN_4M:
659 gtt_entries = MB(4) - KB(size);
660 break;
661 case I855_GMCH_GMS_STOLEN_8M:
662 gtt_entries = MB(8) - KB(size);
663 break;
664 case I855_GMCH_GMS_STOLEN_16M:
665 gtt_entries = MB(16) - KB(size);
666 break;
667 case I855_GMCH_GMS_STOLEN_32M:
668 gtt_entries = MB(32) - KB(size);
669 break;
670 case I915_GMCH_GMS_STOLEN_48M:
671 /* Check it's really I915G */
Zhenyu Wang25ce77a2008-06-19 14:17:58 +1000672 if (IS_I915 || IS_I965 || IS_G33 || IS_G4X)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700673 gtt_entries = MB(48) - KB(size);
674 else
675 gtt_entries = 0;
676 break;
677 case I915_GMCH_GMS_STOLEN_64M:
678 /* Check it's really I915G */
Zhenyu Wang25ce77a2008-06-19 14:17:58 +1000679 if (IS_I915 || IS_I965 || IS_G33 || IS_G4X)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680 gtt_entries = MB(64) - KB(size);
681 else
682 gtt_entries = 0;
Wang Zhenyu874808c62007-06-06 11:16:25 +0800683 break;
684 case G33_GMCH_GMS_STOLEN_128M:
Zhenyu Wang25ce77a2008-06-19 14:17:58 +1000685 if (IS_G33 || IS_I965 || IS_G4X)
Wang Zhenyu874808c62007-06-06 11:16:25 +0800686 gtt_entries = MB(128) - KB(size);
687 else
688 gtt_entries = 0;
689 break;
690 case G33_GMCH_GMS_STOLEN_256M:
Zhenyu Wang25ce77a2008-06-19 14:17:58 +1000691 if (IS_G33 || IS_I965 || IS_G4X)
Wang Zhenyu874808c62007-06-06 11:16:25 +0800692 gtt_entries = MB(256) - KB(size);
693 else
694 gtt_entries = 0;
695 break;
Zhenyu Wang25ce77a2008-06-19 14:17:58 +1000696 case INTEL_GMCH_GMS_STOLEN_96M:
697 if (IS_I965 || IS_G4X)
698 gtt_entries = MB(96) - KB(size);
699 else
700 gtt_entries = 0;
701 break;
702 case INTEL_GMCH_GMS_STOLEN_160M:
703 if (IS_I965 || IS_G4X)
704 gtt_entries = MB(160) - KB(size);
705 else
706 gtt_entries = 0;
707 break;
708 case INTEL_GMCH_GMS_STOLEN_224M:
709 if (IS_I965 || IS_G4X)
710 gtt_entries = MB(224) - KB(size);
711 else
712 gtt_entries = 0;
713 break;
714 case INTEL_GMCH_GMS_STOLEN_352M:
715 if (IS_I965 || IS_G4X)
716 gtt_entries = MB(352) - KB(size);
717 else
718 gtt_entries = 0;
719 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720 default:
721 gtt_entries = 0;
722 break;
723 }
724 }
Lubomir Rintel9c1e8a42009-03-10 12:55:54 -0700725 if (gtt_entries > 0) {
Bjorn Helgaase3cf6952008-07-30 12:26:51 -0700726 dev_info(&agp_bridge->dev->dev, "detected %dK %s memory\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700727 gtt_entries / KB(1), local ? "local" : "stolen");
Lubomir Rintel9c1e8a42009-03-10 12:55:54 -0700728 gtt_entries /= KB(4);
729 } else {
Bjorn Helgaase3cf6952008-07-30 12:26:51 -0700730 dev_info(&agp_bridge->dev->dev,
731 "no pre-allocated video memory detected\n");
Lubomir Rintel9c1e8a42009-03-10 12:55:54 -0700732 gtt_entries = 0;
733 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734
Wang Zhenyuc4ca8812007-05-30 09:40:46 +0800735 intel_private.gtt_entries = gtt_entries;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700736}
737
Dave Airlie2162e6a2007-11-21 16:36:31 +1000738static void intel_i830_fini_flush(void)
739{
740 kunmap(intel_private.i8xx_page);
741 intel_private.i8xx_flush_page = NULL;
742 unmap_page_from_agp(intel_private.i8xx_page);
Dave Airlie2162e6a2007-11-21 16:36:31 +1000743
744 __free_page(intel_private.i8xx_page);
Dave Airlie4d64dd92008-01-23 15:34:29 +1000745 intel_private.i8xx_page = NULL;
Dave Airlie2162e6a2007-11-21 16:36:31 +1000746}
747
748static void intel_i830_setup_flush(void)
749{
Dave Airlie4d64dd92008-01-23 15:34:29 +1000750 /* return if we've already set the flush mechanism up */
751 if (intel_private.i8xx_page)
752 return;
Dave Airlie2162e6a2007-11-21 16:36:31 +1000753
754 intel_private.i8xx_page = alloc_page(GFP_KERNEL | __GFP_ZERO | GFP_DMA32);
Dave Airlief011ae72008-01-25 11:23:04 +1000755 if (!intel_private.i8xx_page)
Dave Airlie2162e6a2007-11-21 16:36:31 +1000756 return;
Dave Airlie2162e6a2007-11-21 16:36:31 +1000757
Dave Airlie2162e6a2007-11-21 16:36:31 +1000758 intel_private.i8xx_flush_page = kmap(intel_private.i8xx_page);
759 if (!intel_private.i8xx_flush_page)
760 intel_i830_fini_flush();
761}
762
Eric Anholte517a5e2009-09-10 17:48:48 -0700763/* The chipset_flush interface needs to get data that has already been
764 * flushed out of the CPU all the way out to main memory, because the GPU
765 * doesn't snoop those buffers.
766 *
767 * The 8xx series doesn't have the same lovely interface for flushing the
768 * chipset write buffers that the later chips do. According to the 865
769 * specs, it's 64 octwords, or 1KB. So, to get those previous things in
770 * that buffer out, we just fill 1KB and clflush it out, on the assumption
771 * that it'll push whatever was in there out. It appears to work.
772 */
Dave Airlie2162e6a2007-11-21 16:36:31 +1000773static void intel_i830_chipset_flush(struct agp_bridge_data *bridge)
774{
775 unsigned int *pg = intel_private.i8xx_flush_page;
Dave Airlie2162e6a2007-11-21 16:36:31 +1000776
Eric Anholte517a5e2009-09-10 17:48:48 -0700777 memset(pg, 0, 1024);
Dave Airlief011ae72008-01-25 11:23:04 +1000778
Borislav Petkov48a719c2010-01-22 16:01:04 +0100779 if (cpu_has_clflush)
Eric Anholte517a5e2009-09-10 17:48:48 -0700780 clflush_cache_range(pg, 1024);
Borislav Petkov48a719c2010-01-22 16:01:04 +0100781 else if (wbinvd_on_all_cpus() != 0)
782 printk(KERN_ERR "Timed out waiting for cache flush.\n");
Dave Airlie2162e6a2007-11-21 16:36:31 +1000783}
784
Linus Torvalds1da177e2005-04-16 15:20:36 -0700785/* The intel i830 automatically initializes the agp aperture during POST.
786 * Use the memory already set aside for in the GTT.
787 */
788static int intel_i830_create_gatt_table(struct agp_bridge_data *bridge)
789{
790 int page_order;
791 struct aper_size_info_fixed *size;
792 int num_entries;
793 u32 temp;
794
795 size = agp_bridge->current_size;
796 page_order = size->page_order;
797 num_entries = size->num_entries;
798 agp_bridge->gatt_table_real = NULL;
799
Dave Airlief011ae72008-01-25 11:23:04 +1000800 pci_read_config_dword(intel_private.pcidev, I810_MMADDR, &temp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700801 temp &= 0xfff80000;
802
Dave Airlief011ae72008-01-25 11:23:04 +1000803 intel_private.registers = ioremap(temp, 128 * 4096);
Wang Zhenyuc4ca8812007-05-30 09:40:46 +0800804 if (!intel_private.registers)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700805 return -ENOMEM;
806
Wang Zhenyuc4ca8812007-05-30 09:40:46 +0800807 temp = readl(intel_private.registers+I810_PGETBL_CTL) & 0xfffff000;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700808 global_cache_flush(); /* FIXME: ?? */
809
810 /* we have to call this as early as possible after the MMIO base address is known */
811 intel_i830_init_gtt_entries();
812
813 agp_bridge->gatt_table = NULL;
814
815 agp_bridge->gatt_bus_addr = temp;
816
817 return 0;
818}
819
820/* Return the gatt table to a sane state. Use the top of stolen
821 * memory for the GTT.
822 */
823static int intel_i830_free_gatt_table(struct agp_bridge_data *bridge)
824{
825 return 0;
826}
827
828static int intel_i830_fetch_size(void)
829{
830 u16 gmch_ctrl;
831 struct aper_size_info_fixed *values;
832
833 values = A_SIZE_FIX(agp_bridge->driver->aperture_sizes);
834
835 if (agp_bridge->dev->device != PCI_DEVICE_ID_INTEL_82830_HB &&
836 agp_bridge->dev->device != PCI_DEVICE_ID_INTEL_82845G_HB) {
837 /* 855GM/852GM/865G has 128MB aperture size */
838 agp_bridge->previous_size = agp_bridge->current_size = (void *) values;
839 agp_bridge->aperture_size_idx = 0;
840 return values[0].size;
841 }
842
Dave Airlief011ae72008-01-25 11:23:04 +1000843 pci_read_config_word(agp_bridge->dev, I830_GMCH_CTRL, &gmch_ctrl);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700844
845 if ((gmch_ctrl & I830_GMCH_MEM_MASK) == I830_GMCH_MEM_128M) {
846 agp_bridge->previous_size = agp_bridge->current_size = (void *) values;
847 agp_bridge->aperture_size_idx = 0;
848 return values[0].size;
849 } else {
850 agp_bridge->previous_size = agp_bridge->current_size = (void *) (values + 1);
851 agp_bridge->aperture_size_idx = 1;
852 return values[1].size;
853 }
854
855 return 0;
856}
857
858static int intel_i830_configure(void)
859{
860 struct aper_size_info_fixed *current_size;
861 u32 temp;
862 u16 gmch_ctrl;
863 int i;
864
865 current_size = A_SIZE_FIX(agp_bridge->current_size);
866
Dave Airlief011ae72008-01-25 11:23:04 +1000867 pci_read_config_dword(intel_private.pcidev, I810_GMADDR, &temp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700868 agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
869
Dave Airlief011ae72008-01-25 11:23:04 +1000870 pci_read_config_word(agp_bridge->dev, I830_GMCH_CTRL, &gmch_ctrl);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700871 gmch_ctrl |= I830_GMCH_ENABLED;
Dave Airlief011ae72008-01-25 11:23:04 +1000872 pci_write_config_word(agp_bridge->dev, I830_GMCH_CTRL, gmch_ctrl);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700873
Wang Zhenyuc4ca8812007-05-30 09:40:46 +0800874 writel(agp_bridge->gatt_bus_addr|I810_PGETBL_ENABLED, intel_private.registers+I810_PGETBL_CTL);
875 readl(intel_private.registers+I810_PGETBL_CTL); /* PCI Posting. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700876
877 if (agp_bridge->driver->needs_scratch_page) {
Wang Zhenyuc4ca8812007-05-30 09:40:46 +0800878 for (i = intel_private.gtt_entries; i < current_size->num_entries; i++) {
879 writel(agp_bridge->scratch_page, intel_private.registers+I810_PTE_BASE+(i*4));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880 }
Keith Packard44d49442008-10-14 17:18:45 -0700881 readl(intel_private.registers+I810_PTE_BASE+((i-1)*4)); /* PCI Posting. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700882 }
883
884 global_cache_flush();
Dave Airlie2162e6a2007-11-21 16:36:31 +1000885
886 intel_i830_setup_flush();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700887 return 0;
888}
889
890static void intel_i830_cleanup(void)
891{
Wang Zhenyuc4ca8812007-05-30 09:40:46 +0800892 iounmap(intel_private.registers);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700893}
894
Dave Airlief011ae72008-01-25 11:23:04 +1000895static int intel_i830_insert_entries(struct agp_memory *mem, off_t pg_start,
896 int type)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700897{
Dave Airlief011ae72008-01-25 11:23:04 +1000898 int i, j, num_entries;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700899 void *temp;
Thomas Hellstroma030ce42007-01-23 10:33:43 +0100900 int ret = -EINVAL;
901 int mask_type;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700902
Thomas Hellstrom5aa80c72006-12-20 16:33:41 +0100903 if (mem->page_count == 0)
Thomas Hellstroma030ce42007-01-23 10:33:43 +0100904 goto out;
Thomas Hellstrom5aa80c72006-12-20 16:33:41 +0100905
Linus Torvalds1da177e2005-04-16 15:20:36 -0700906 temp = agp_bridge->current_size;
907 num_entries = A_SIZE_FIX(temp)->num_entries;
908
Wang Zhenyuc4ca8812007-05-30 09:40:46 +0800909 if (pg_start < intel_private.gtt_entries) {
Bjorn Helgaase3cf6952008-07-30 12:26:51 -0700910 dev_printk(KERN_DEBUG, &intel_private.pcidev->dev,
911 "pg_start == 0x%.8lx, intel_private.gtt_entries == 0x%.8x\n",
912 pg_start, intel_private.gtt_entries);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700913
Bjorn Helgaase3cf6952008-07-30 12:26:51 -0700914 dev_info(&intel_private.pcidev->dev,
915 "trying to insert into local/stolen memory\n");
Thomas Hellstroma030ce42007-01-23 10:33:43 +0100916 goto out_err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700917 }
918
919 if ((pg_start + mem->page_count) > num_entries)
Thomas Hellstroma030ce42007-01-23 10:33:43 +0100920 goto out_err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700921
922 /* The i830 can't check the GTT for entries since its read only,
923 * depend on the caller to make the correct offset decisions.
924 */
925
Thomas Hellstroma030ce42007-01-23 10:33:43 +0100926 if (type != mem->type)
927 goto out_err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700928
Thomas Hellstroma030ce42007-01-23 10:33:43 +0100929 mask_type = agp_bridge->driver->agp_type_to_mask_type(agp_bridge, type);
930
931 if (mask_type != 0 && mask_type != AGP_PHYS_MEMORY &&
932 mask_type != INTEL_AGP_CACHED_MEMORY)
933 goto out_err;
934
935 if (!mem->is_flushed)
Thomas Hellstrom5aa80c72006-12-20 16:33:41 +0100936 global_cache_flush();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700937
938 for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
939 writel(agp_bridge->driver->mask_memory(agp_bridge,
David Woodhouse6a122352009-07-29 10:25:58 +0100940 page_to_phys(mem->pages[i]), mask_type),
Wang Zhenyuc4ca8812007-05-30 09:40:46 +0800941 intel_private.registers+I810_PTE_BASE+(j*4));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700942 }
Wang Zhenyuc4ca8812007-05-30 09:40:46 +0800943 readl(intel_private.registers+I810_PTE_BASE+((j-1)*4));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700944 agp_bridge->driver->tlb_flush(mem);
Thomas Hellstroma030ce42007-01-23 10:33:43 +0100945
946out:
947 ret = 0;
948out_err:
Dave Airlie9516b032008-06-19 10:42:17 +1000949 mem->is_flushed = true;
Thomas Hellstroma030ce42007-01-23 10:33:43 +0100950 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700951}
952
Dave Airlief011ae72008-01-25 11:23:04 +1000953static int intel_i830_remove_entries(struct agp_memory *mem, off_t pg_start,
954 int type)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700955{
956 int i;
957
Thomas Hellstrom5aa80c72006-12-20 16:33:41 +0100958 if (mem->page_count == 0)
959 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700960
Wang Zhenyuc4ca8812007-05-30 09:40:46 +0800961 if (pg_start < intel_private.gtt_entries) {
Bjorn Helgaase3cf6952008-07-30 12:26:51 -0700962 dev_info(&intel_private.pcidev->dev,
963 "trying to disable local/stolen memory\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700964 return -EINVAL;
965 }
966
967 for (i = pg_start; i < (mem->page_count + pg_start); i++) {
Wang Zhenyuc4ca8812007-05-30 09:40:46 +0800968 writel(agp_bridge->scratch_page, intel_private.registers+I810_PTE_BASE+(i*4));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700969 }
Wang Zhenyuc4ca8812007-05-30 09:40:46 +0800970 readl(intel_private.registers+I810_PTE_BASE+((i-1)*4));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700971
Linus Torvalds1da177e2005-04-16 15:20:36 -0700972 agp_bridge->driver->tlb_flush(mem);
973 return 0;
974}
975
Dave Airlief011ae72008-01-25 11:23:04 +1000976static struct agp_memory *intel_i830_alloc_by_type(size_t pg_count, int type)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700977{
978 if (type == AGP_PHYS_MEMORY)
979 return alloc_agpphysmem_i8xx(pg_count, type);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700980 /* always return NULL for other allocation types for now */
981 return NULL;
982}
983
Dave Airlie6c00a612007-10-29 18:06:10 +1000984static int intel_alloc_chipset_flush_resource(void)
985{
986 int ret;
987 ret = pci_bus_alloc_resource(agp_bridge->dev->bus, &intel_private.ifp_resource, PAGE_SIZE,
988 PAGE_SIZE, PCIBIOS_MIN_MEM, 0,
989 pcibios_align_resource, agp_bridge->dev);
Dave Airlie6c00a612007-10-29 18:06:10 +1000990
Dave Airlie2162e6a2007-11-21 16:36:31 +1000991 return ret;
Dave Airlie6c00a612007-10-29 18:06:10 +1000992}
993
994static void intel_i915_setup_chipset_flush(void)
995{
996 int ret;
997 u32 temp;
998
999 pci_read_config_dword(agp_bridge->dev, I915_IFPADDR, &temp);
1000 if (!(temp & 0x1)) {
1001 intel_alloc_chipset_flush_resource();
Dave Airlie4d64dd92008-01-23 15:34:29 +10001002 intel_private.resource_valid = 1;
Dave Airlie6c00a612007-10-29 18:06:10 +10001003 pci_write_config_dword(agp_bridge->dev, I915_IFPADDR, (intel_private.ifp_resource.start & 0xffffffff) | 0x1);
1004 } else {
1005 temp &= ~1;
1006
Dave Airlie4d64dd92008-01-23 15:34:29 +10001007 intel_private.resource_valid = 1;
Dave Airlie6c00a612007-10-29 18:06:10 +10001008 intel_private.ifp_resource.start = temp;
1009 intel_private.ifp_resource.end = temp + PAGE_SIZE;
1010 ret = request_resource(&iomem_resource, &intel_private.ifp_resource);
Dave Airlie4d64dd92008-01-23 15:34:29 +10001011 /* some BIOSes reserve this area in a pnp some don't */
1012 if (ret)
1013 intel_private.resource_valid = 0;
Dave Airlie6c00a612007-10-29 18:06:10 +10001014 }
1015}
1016
1017static void intel_i965_g33_setup_chipset_flush(void)
1018{
1019 u32 temp_hi, temp_lo;
1020 int ret;
1021
1022 pci_read_config_dword(agp_bridge->dev, I965_IFPADDR + 4, &temp_hi);
1023 pci_read_config_dword(agp_bridge->dev, I965_IFPADDR, &temp_lo);
1024
1025 if (!(temp_lo & 0x1)) {
1026
1027 intel_alloc_chipset_flush_resource();
1028
Dave Airlie4d64dd92008-01-23 15:34:29 +10001029 intel_private.resource_valid = 1;
Andrew Morton1fa4db72007-11-29 10:00:48 +10001030 pci_write_config_dword(agp_bridge->dev, I965_IFPADDR + 4,
1031 upper_32_bits(intel_private.ifp_resource.start));
Dave Airlie6c00a612007-10-29 18:06:10 +10001032 pci_write_config_dword(agp_bridge->dev, I965_IFPADDR, (intel_private.ifp_resource.start & 0xffffffff) | 0x1);
Dave Airlie6c00a612007-10-29 18:06:10 +10001033 } else {
1034 u64 l64;
Dave Airlief011ae72008-01-25 11:23:04 +10001035
Dave Airlie6c00a612007-10-29 18:06:10 +10001036 temp_lo &= ~0x1;
1037 l64 = ((u64)temp_hi << 32) | temp_lo;
1038
Dave Airlie4d64dd92008-01-23 15:34:29 +10001039 intel_private.resource_valid = 1;
Dave Airlie6c00a612007-10-29 18:06:10 +10001040 intel_private.ifp_resource.start = l64;
1041 intel_private.ifp_resource.end = l64 + PAGE_SIZE;
1042 ret = request_resource(&iomem_resource, &intel_private.ifp_resource);
Dave Airlie4d64dd92008-01-23 15:34:29 +10001043 /* some BIOSes reserve this area in a pnp some don't */
1044 if (ret)
1045 intel_private.resource_valid = 0;
Dave Airlie6c00a612007-10-29 18:06:10 +10001046 }
1047}
1048
Dave Airlie2162e6a2007-11-21 16:36:31 +10001049static void intel_i9xx_setup_flush(void)
1050{
Dave Airlie4d64dd92008-01-23 15:34:29 +10001051 /* return if already configured */
1052 if (intel_private.ifp_resource.start)
1053 return;
Dave Airlie2162e6a2007-11-21 16:36:31 +10001054
Eric Anholt66f6ff02010-03-18 12:19:37 -07001055 if (IS_SNB)
1056 return;
1057
Dave Airlie4d64dd92008-01-23 15:34:29 +10001058 /* setup a resource for this object */
Dave Airlie2162e6a2007-11-21 16:36:31 +10001059 intel_private.ifp_resource.name = "Intel Flush Page";
1060 intel_private.ifp_resource.flags = IORESOURCE_MEM;
1061
1062 /* Setup chipset flush for 915 */
Zhenyu Wang7d15ddf2008-06-20 11:48:06 +10001063 if (IS_I965 || IS_G33 || IS_G4X) {
Dave Airlie2162e6a2007-11-21 16:36:31 +10001064 intel_i965_g33_setup_chipset_flush();
1065 } else {
1066 intel_i915_setup_chipset_flush();
1067 }
1068
1069 if (intel_private.ifp_resource.start) {
1070 intel_private.i9xx_flush_page = ioremap_nocache(intel_private.ifp_resource.start, PAGE_SIZE);
1071 if (!intel_private.i9xx_flush_page)
Bjorn Helgaase3cf6952008-07-30 12:26:51 -07001072 dev_info(&intel_private.pcidev->dev, "can't ioremap flush page - no chipset flushing");
Dave Airlie2162e6a2007-11-21 16:36:31 +10001073 }
1074}
1075
Linus Torvalds1da177e2005-04-16 15:20:36 -07001076static int intel_i915_configure(void)
1077{
1078 struct aper_size_info_fixed *current_size;
1079 u32 temp;
1080 u16 gmch_ctrl;
1081 int i;
1082
1083 current_size = A_SIZE_FIX(agp_bridge->current_size);
1084
Wang Zhenyuc4ca8812007-05-30 09:40:46 +08001085 pci_read_config_dword(intel_private.pcidev, I915_GMADDR, &temp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001086
1087 agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
1088
Dave Airlief011ae72008-01-25 11:23:04 +10001089 pci_read_config_word(agp_bridge->dev, I830_GMCH_CTRL, &gmch_ctrl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001090 gmch_ctrl |= I830_GMCH_ENABLED;
Dave Airlief011ae72008-01-25 11:23:04 +10001091 pci_write_config_word(agp_bridge->dev, I830_GMCH_CTRL, gmch_ctrl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001092
Wang Zhenyuc4ca8812007-05-30 09:40:46 +08001093 writel(agp_bridge->gatt_bus_addr|I810_PGETBL_ENABLED, intel_private.registers+I810_PGETBL_CTL);
1094 readl(intel_private.registers+I810_PGETBL_CTL); /* PCI Posting. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001095
1096 if (agp_bridge->driver->needs_scratch_page) {
David Woodhousefc619012009-12-02 11:00:05 +00001097 for (i = intel_private.gtt_entries; i < intel_private.gtt_total_size; i++) {
Wang Zhenyuc4ca8812007-05-30 09:40:46 +08001098 writel(agp_bridge->scratch_page, intel_private.gtt+i);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001099 }
Keith Packard44d49442008-10-14 17:18:45 -07001100 readl(intel_private.gtt+i-1); /* PCI Posting. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001101 }
1102
1103 global_cache_flush();
Dave Airlie6c00a612007-10-29 18:06:10 +10001104
Dave Airlie2162e6a2007-11-21 16:36:31 +10001105 intel_i9xx_setup_flush();
Dave Airlief011ae72008-01-25 11:23:04 +10001106
Linus Torvalds1da177e2005-04-16 15:20:36 -07001107 return 0;
1108}
1109
1110static void intel_i915_cleanup(void)
1111{
Dave Airlie2162e6a2007-11-21 16:36:31 +10001112 if (intel_private.i9xx_flush_page)
1113 iounmap(intel_private.i9xx_flush_page);
Dave Airlie4d64dd92008-01-23 15:34:29 +10001114 if (intel_private.resource_valid)
1115 release_resource(&intel_private.ifp_resource);
1116 intel_private.ifp_resource.start = 0;
1117 intel_private.resource_valid = 0;
Wang Zhenyuc4ca8812007-05-30 09:40:46 +08001118 iounmap(intel_private.gtt);
1119 iounmap(intel_private.registers);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001120}
1121
Dave Airlie6c00a612007-10-29 18:06:10 +10001122static void intel_i915_chipset_flush(struct agp_bridge_data *bridge)
1123{
Dave Airlie2162e6a2007-11-21 16:36:31 +10001124 if (intel_private.i9xx_flush_page)
1125 writel(1, intel_private.i9xx_flush_page);
Dave Airlie6c00a612007-10-29 18:06:10 +10001126}
1127
Dave Airlief011ae72008-01-25 11:23:04 +10001128static int intel_i915_insert_entries(struct agp_memory *mem, off_t pg_start,
1129 int type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001130{
Zhenyu Wang17661682009-07-27 12:59:57 +01001131 int num_entries;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001132 void *temp;
Thomas Hellstroma030ce42007-01-23 10:33:43 +01001133 int ret = -EINVAL;
1134 int mask_type;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001135
Thomas Hellstrom5aa80c72006-12-20 16:33:41 +01001136 if (mem->page_count == 0)
Thomas Hellstroma030ce42007-01-23 10:33:43 +01001137 goto out;
Thomas Hellstrom5aa80c72006-12-20 16:33:41 +01001138
Linus Torvalds1da177e2005-04-16 15:20:36 -07001139 temp = agp_bridge->current_size;
1140 num_entries = A_SIZE_FIX(temp)->num_entries;
1141
Wang Zhenyuc4ca8812007-05-30 09:40:46 +08001142 if (pg_start < intel_private.gtt_entries) {
Bjorn Helgaase3cf6952008-07-30 12:26:51 -07001143 dev_printk(KERN_DEBUG, &intel_private.pcidev->dev,
1144 "pg_start == 0x%.8lx, intel_private.gtt_entries == 0x%.8x\n",
1145 pg_start, intel_private.gtt_entries);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001146
Bjorn Helgaase3cf6952008-07-30 12:26:51 -07001147 dev_info(&intel_private.pcidev->dev,
1148 "trying to insert into local/stolen memory\n");
Thomas Hellstroma030ce42007-01-23 10:33:43 +01001149 goto out_err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001150 }
1151
1152 if ((pg_start + mem->page_count) > num_entries)
Thomas Hellstroma030ce42007-01-23 10:33:43 +01001153 goto out_err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001154
Zhenyu Wang17661682009-07-27 12:59:57 +01001155 /* The i915 can't check the GTT for entries since it's read only;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001156 * depend on the caller to make the correct offset decisions.
1157 */
1158
Thomas Hellstroma030ce42007-01-23 10:33:43 +01001159 if (type != mem->type)
1160 goto out_err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001161
Thomas Hellstroma030ce42007-01-23 10:33:43 +01001162 mask_type = agp_bridge->driver->agp_type_to_mask_type(agp_bridge, type);
1163
1164 if (mask_type != 0 && mask_type != AGP_PHYS_MEMORY &&
1165 mask_type != INTEL_AGP_CACHED_MEMORY)
1166 goto out_err;
1167
1168 if (!mem->is_flushed)
Thomas Hellstrom5aa80c72006-12-20 16:33:41 +01001169 global_cache_flush();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001170
Zhenyu Wang17661682009-07-27 12:59:57 +01001171 intel_agp_insert_sg_entries(mem, pg_start, mask_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001172 agp_bridge->driver->tlb_flush(mem);
Thomas Hellstroma030ce42007-01-23 10:33:43 +01001173
1174 out:
1175 ret = 0;
1176 out_err:
Dave Airlie9516b032008-06-19 10:42:17 +10001177 mem->is_flushed = true;
Thomas Hellstroma030ce42007-01-23 10:33:43 +01001178 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001179}
1180
Dave Airlief011ae72008-01-25 11:23:04 +10001181static int intel_i915_remove_entries(struct agp_memory *mem, off_t pg_start,
1182 int type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001183{
1184 int i;
1185
Thomas Hellstrom5aa80c72006-12-20 16:33:41 +01001186 if (mem->page_count == 0)
1187 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001188
Wang Zhenyuc4ca8812007-05-30 09:40:46 +08001189 if (pg_start < intel_private.gtt_entries) {
Bjorn Helgaase3cf6952008-07-30 12:26:51 -07001190 dev_info(&intel_private.pcidev->dev,
1191 "trying to disable local/stolen memory\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001192 return -EINVAL;
1193 }
1194
Dave Airlief011ae72008-01-25 11:23:04 +10001195 for (i = pg_start; i < (mem->page_count + pg_start); i++)
Wang Zhenyuc4ca8812007-05-30 09:40:46 +08001196 writel(agp_bridge->scratch_page, intel_private.gtt+i);
Dave Airlief011ae72008-01-25 11:23:04 +10001197
Wang Zhenyuc4ca8812007-05-30 09:40:46 +08001198 readl(intel_private.gtt+i-1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001199
Linus Torvalds1da177e2005-04-16 15:20:36 -07001200 agp_bridge->driver->tlb_flush(mem);
1201 return 0;
1202}
1203
Eric Anholtc41e0de2006-12-19 12:57:24 -08001204/* Return the aperture size by just checking the resource length. The effect
1205 * described in the spec of the MSAC registers is just changing of the
1206 * resource size.
1207 */
1208static int intel_i9xx_fetch_size(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001209{
Ahmed S. Darwish1eaf1222007-02-06 18:08:28 +02001210 int num_sizes = ARRAY_SIZE(intel_i830_sizes);
Eric Anholtc41e0de2006-12-19 12:57:24 -08001211 int aper_size; /* size in megabytes */
1212 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001213
Wang Zhenyuc4ca8812007-05-30 09:40:46 +08001214 aper_size = pci_resource_len(intel_private.pcidev, 2) / MB(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001215
Eric Anholtc41e0de2006-12-19 12:57:24 -08001216 for (i = 0; i < num_sizes; i++) {
1217 if (aper_size == intel_i830_sizes[i].size) {
1218 agp_bridge->current_size = intel_i830_sizes + i;
1219 agp_bridge->previous_size = agp_bridge->current_size;
1220 return aper_size;
1221 }
1222 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001223
Eric Anholtc41e0de2006-12-19 12:57:24 -08001224 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001225}
1226
1227/* The intel i915 automatically initializes the agp aperture during POST.
1228 * Use the memory already set aside for in the GTT.
1229 */
1230static int intel_i915_create_gatt_table(struct agp_bridge_data *bridge)
1231{
1232 int page_order;
1233 struct aper_size_info_fixed *size;
1234 int num_entries;
1235 u32 temp, temp2;
Zhenyu Wang47406222007-09-11 15:23:58 -07001236 int gtt_map_size = 256 * 1024;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001237
1238 size = agp_bridge->current_size;
1239 page_order = size->page_order;
1240 num_entries = size->num_entries;
1241 agp_bridge->gatt_table_real = NULL;
1242
Wang Zhenyuc4ca8812007-05-30 09:40:46 +08001243 pci_read_config_dword(intel_private.pcidev, I915_MMADDR, &temp);
Dave Airlief011ae72008-01-25 11:23:04 +10001244 pci_read_config_dword(intel_private.pcidev, I915_PTEADDR, &temp2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001245
Zhenyu Wang47406222007-09-11 15:23:58 -07001246 if (IS_G33)
1247 gtt_map_size = 1024 * 1024; /* 1M on G33 */
1248 intel_private.gtt = ioremap(temp2, gtt_map_size);
Wang Zhenyuc4ca8812007-05-30 09:40:46 +08001249 if (!intel_private.gtt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001250 return -ENOMEM;
1251
David Woodhousefc619012009-12-02 11:00:05 +00001252 intel_private.gtt_total_size = gtt_map_size / 4;
1253
Linus Torvalds1da177e2005-04-16 15:20:36 -07001254 temp &= 0xfff80000;
1255
Dave Airlief011ae72008-01-25 11:23:04 +10001256 intel_private.registers = ioremap(temp, 128 * 4096);
Scott Thompson5bdbc7d2007-08-25 18:14:00 +10001257 if (!intel_private.registers) {
1258 iounmap(intel_private.gtt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001259 return -ENOMEM;
Scott Thompson5bdbc7d2007-08-25 18:14:00 +10001260 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001261
Wang Zhenyuc4ca8812007-05-30 09:40:46 +08001262 temp = readl(intel_private.registers+I810_PGETBL_CTL) & 0xfffff000;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001263 global_cache_flush(); /* FIXME: ? */
1264
1265 /* we have to call this as early as possible after the MMIO base address is known */
1266 intel_i830_init_gtt_entries();
1267
1268 agp_bridge->gatt_table = NULL;
1269
1270 agp_bridge->gatt_bus_addr = temp;
1271
1272 return 0;
1273}
Linus Torvalds7d915a32006-11-22 09:37:54 -08001274
1275/*
1276 * The i965 supports 36-bit physical addresses, but to keep
1277 * the format of the GTT the same, the bits that don't fit
1278 * in a 32-bit word are shifted down to bits 4..7.
1279 *
1280 * Gcc is smart enough to notice that "(addr >> 28) & 0xf0"
1281 * is always zero on 32-bit architectures, so no need to make
1282 * this conditional.
1283 */
1284static unsigned long intel_i965_mask_memory(struct agp_bridge_data *bridge,
David Woodhouse2a4ceb62009-07-27 10:27:29 +01001285 dma_addr_t addr, int type)
Linus Torvalds7d915a32006-11-22 09:37:54 -08001286{
1287 /* Shift high bits down */
1288 addr |= (addr >> 28) & 0xf0;
1289
1290 /* Type checking must be done elsewhere */
1291 return addr | bridge->driver->masks[type].mask;
1292}
1293
Zhenyu Wang25ce77a2008-06-19 14:17:58 +10001294static void intel_i965_get_gtt_range(int *gtt_offset, int *gtt_size)
1295{
Eric Anholt285aca82010-03-18 11:24:06 -07001296 u16 snb_gmch_ctl;
1297
Zhenyu Wang25ce77a2008-06-19 14:17:58 +10001298 switch (agp_bridge->dev->device) {
Zhenyu Wang99d32bd2008-07-30 12:26:50 -07001299 case PCI_DEVICE_ID_INTEL_GM45_HB:
Adam Jackson107f5172009-12-03 17:14:41 -05001300 case PCI_DEVICE_ID_INTEL_EAGLELAKE_HB:
Zhenyu Wang25ce77a2008-06-19 14:17:58 +10001301 case PCI_DEVICE_ID_INTEL_Q45_HB:
1302 case PCI_DEVICE_ID_INTEL_G45_HB:
Zhenyu Wanga50ccc62008-11-17 14:39:00 +08001303 case PCI_DEVICE_ID_INTEL_G41_HB:
Fabian Henze38d8a952009-09-08 00:59:58 +08001304 case PCI_DEVICE_ID_INTEL_B43_HB:
Adam Jackson107f5172009-12-03 17:14:41 -05001305 case PCI_DEVICE_ID_INTEL_IRONLAKE_D_HB:
1306 case PCI_DEVICE_ID_INTEL_IRONLAKE_M_HB:
1307 case PCI_DEVICE_ID_INTEL_IRONLAKE_MA_HB:
Dave Airlie3ff99162009-12-08 14:03:47 +10001308 case PCI_DEVICE_ID_INTEL_IRONLAKE_MC2_HB:
Eric Anholt285aca82010-03-18 11:24:06 -07001309 *gtt_offset = *gtt_size = MB(2);
1310 break;
Eric Anholt1089e302009-10-22 16:10:52 -07001311 case PCI_DEVICE_ID_INTEL_SANDYBRIDGE_HB:
Eric Anholt954bce52010-01-07 16:21:46 -08001312 case PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_HB:
Eric Anholt285aca82010-03-18 11:24:06 -07001313 *gtt_offset = MB(2);
1314
1315 pci_read_config_word(intel_private.pcidev, SNB_GMCH_CTRL, &snb_gmch_ctl);
1316 switch (snb_gmch_ctl & SNB_GTT_SIZE_MASK) {
1317 default:
1318 case SNB_GTT_SIZE_0M:
1319 printk(KERN_ERR "Bad GTT size mask: 0x%04x.\n", snb_gmch_ctl);
1320 *gtt_size = MB(0);
1321 break;
1322 case SNB_GTT_SIZE_1M:
1323 *gtt_size = MB(1);
1324 break;
1325 case SNB_GTT_SIZE_2M:
1326 *gtt_size = MB(2);
1327 break;
1328 }
Zhenyu Wang25ce77a2008-06-19 14:17:58 +10001329 break;
1330 default:
1331 *gtt_offset = *gtt_size = KB(512);
1332 }
1333}
1334
Eric Anholt65c25aa2006-09-06 11:57:18 -04001335/* The intel i965 automatically initializes the agp aperture during POST.
Eric Anholtc41e0de2006-12-19 12:57:24 -08001336 * Use the memory already set aside for in the GTT.
1337 */
Eric Anholt65c25aa2006-09-06 11:57:18 -04001338static int intel_i965_create_gatt_table(struct agp_bridge_data *bridge)
1339{
Dave Airlie62c96b92008-06-19 14:27:53 +10001340 int page_order;
1341 struct aper_size_info_fixed *size;
1342 int num_entries;
1343 u32 temp;
1344 int gtt_offset, gtt_size;
Eric Anholt65c25aa2006-09-06 11:57:18 -04001345
Dave Airlie62c96b92008-06-19 14:27:53 +10001346 size = agp_bridge->current_size;
1347 page_order = size->page_order;
1348 num_entries = size->num_entries;
1349 agp_bridge->gatt_table_real = NULL;
Eric Anholt65c25aa2006-09-06 11:57:18 -04001350
Dave Airlie62c96b92008-06-19 14:27:53 +10001351 pci_read_config_dword(intel_private.pcidev, I915_MMADDR, &temp);
Eric Anholt65c25aa2006-09-06 11:57:18 -04001352
Dave Airlie62c96b92008-06-19 14:27:53 +10001353 temp &= 0xfff00000;
Eric Anholt65c25aa2006-09-06 11:57:18 -04001354
Zhenyu Wang25ce77a2008-06-19 14:17:58 +10001355 intel_i965_get_gtt_range(&gtt_offset, &gtt_size);
Eric Anholt65c25aa2006-09-06 11:57:18 -04001356
Dave Airlie62c96b92008-06-19 14:27:53 +10001357 intel_private.gtt = ioremap((temp + gtt_offset) , gtt_size);
Eric Anholt65c25aa2006-09-06 11:57:18 -04001358
Dave Airlie62c96b92008-06-19 14:27:53 +10001359 if (!intel_private.gtt)
1360 return -ENOMEM;
Zhenyu Wang4e8b6e22008-01-23 14:54:37 +10001361
David Woodhousefc619012009-12-02 11:00:05 +00001362 intel_private.gtt_total_size = gtt_size / 4;
1363
Dave Airlie62c96b92008-06-19 14:27:53 +10001364 intel_private.registers = ioremap(temp, 128 * 4096);
1365 if (!intel_private.registers) {
Scott Thompson5bdbc7d2007-08-25 18:14:00 +10001366 iounmap(intel_private.gtt);
1367 return -ENOMEM;
1368 }
Eric Anholt65c25aa2006-09-06 11:57:18 -04001369
Dave Airlie62c96b92008-06-19 14:27:53 +10001370 temp = readl(intel_private.registers+I810_PGETBL_CTL) & 0xfffff000;
1371 global_cache_flush(); /* FIXME: ? */
Eric Anholt65c25aa2006-09-06 11:57:18 -04001372
Dave Airlie62c96b92008-06-19 14:27:53 +10001373 /* we have to call this as early as possible after the MMIO base address is known */
1374 intel_i830_init_gtt_entries();
Eric Anholt65c25aa2006-09-06 11:57:18 -04001375
Dave Airlie62c96b92008-06-19 14:27:53 +10001376 agp_bridge->gatt_table = NULL;
Eric Anholt65c25aa2006-09-06 11:57:18 -04001377
Dave Airlie62c96b92008-06-19 14:27:53 +10001378 agp_bridge->gatt_bus_addr = temp;
Eric Anholt65c25aa2006-09-06 11:57:18 -04001379
Dave Airlie62c96b92008-06-19 14:27:53 +10001380 return 0;
Eric Anholt65c25aa2006-09-06 11:57:18 -04001381}
1382
Linus Torvalds1da177e2005-04-16 15:20:36 -07001383
1384static int intel_fetch_size(void)
1385{
1386 int i;
1387 u16 temp;
1388 struct aper_size_info_16 *values;
1389
1390 pci_read_config_word(agp_bridge->dev, INTEL_APSIZE, &temp);
1391 values = A_SIZE_16(agp_bridge->driver->aperture_sizes);
1392
1393 for (i = 0; i < agp_bridge->driver->num_aperture_sizes; i++) {
1394 if (temp == values[i].size_value) {
1395 agp_bridge->previous_size = agp_bridge->current_size = (void *) (values + i);
1396 agp_bridge->aperture_size_idx = i;
1397 return values[i].size;
1398 }
1399 }
1400
1401 return 0;
1402}
1403
1404static int __intel_8xx_fetch_size(u8 temp)
1405{
1406 int i;
1407 struct aper_size_info_8 *values;
1408
1409 values = A_SIZE_8(agp_bridge->driver->aperture_sizes);
1410
1411 for (i = 0; i < agp_bridge->driver->num_aperture_sizes; i++) {
1412 if (temp == values[i].size_value) {
1413 agp_bridge->previous_size =
1414 agp_bridge->current_size = (void *) (values + i);
1415 agp_bridge->aperture_size_idx = i;
1416 return values[i].size;
1417 }
1418 }
1419 return 0;
1420}
1421
1422static int intel_8xx_fetch_size(void)
1423{
1424 u8 temp;
1425
1426 pci_read_config_byte(agp_bridge->dev, INTEL_APSIZE, &temp);
1427 return __intel_8xx_fetch_size(temp);
1428}
1429
1430static int intel_815_fetch_size(void)
1431{
1432 u8 temp;
1433
1434 /* Intel 815 chipsets have a _weird_ APSIZE register with only
1435 * one non-reserved bit, so mask the others out ... */
1436 pci_read_config_byte(agp_bridge->dev, INTEL_APSIZE, &temp);
1437 temp &= (1 << 3);
1438
1439 return __intel_8xx_fetch_size(temp);
1440}
1441
1442static void intel_tlbflush(struct agp_memory *mem)
1443{
1444 pci_write_config_dword(agp_bridge->dev, INTEL_AGPCTRL, 0x2200);
1445 pci_write_config_dword(agp_bridge->dev, INTEL_AGPCTRL, 0x2280);
1446}
1447
1448
1449static void intel_8xx_tlbflush(struct agp_memory *mem)
1450{
1451 u32 temp;
1452 pci_read_config_dword(agp_bridge->dev, INTEL_AGPCTRL, &temp);
1453 pci_write_config_dword(agp_bridge->dev, INTEL_AGPCTRL, temp & ~(1 << 7));
1454 pci_read_config_dword(agp_bridge->dev, INTEL_AGPCTRL, &temp);
1455 pci_write_config_dword(agp_bridge->dev, INTEL_AGPCTRL, temp | (1 << 7));
1456}
1457
1458
1459static void intel_cleanup(void)
1460{
1461 u16 temp;
1462 struct aper_size_info_16 *previous_size;
1463
1464 previous_size = A_SIZE_16(agp_bridge->previous_size);
1465 pci_read_config_word(agp_bridge->dev, INTEL_NBXCFG, &temp);
1466 pci_write_config_word(agp_bridge->dev, INTEL_NBXCFG, temp & ~(1 << 9));
1467 pci_write_config_word(agp_bridge->dev, INTEL_APSIZE, previous_size->size_value);
1468}
1469
1470
1471static void intel_8xx_cleanup(void)
1472{
1473 u16 temp;
1474 struct aper_size_info_8 *previous_size;
1475
1476 previous_size = A_SIZE_8(agp_bridge->previous_size);
1477 pci_read_config_word(agp_bridge->dev, INTEL_NBXCFG, &temp);
1478 pci_write_config_word(agp_bridge->dev, INTEL_NBXCFG, temp & ~(1 << 9));
1479 pci_write_config_byte(agp_bridge->dev, INTEL_APSIZE, previous_size->size_value);
1480}
1481
1482
1483static int intel_configure(void)
1484{
1485 u32 temp;
1486 u16 temp2;
1487 struct aper_size_info_16 *current_size;
1488
1489 current_size = A_SIZE_16(agp_bridge->current_size);
1490
1491 /* aperture size */
1492 pci_write_config_word(agp_bridge->dev, INTEL_APSIZE, current_size->size_value);
1493
1494 /* address to map to */
1495 pci_read_config_dword(agp_bridge->dev, AGP_APBASE, &temp);
1496 agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
1497
1498 /* attbase - aperture base */
1499 pci_write_config_dword(agp_bridge->dev, INTEL_ATTBASE, agp_bridge->gatt_bus_addr);
1500
1501 /* agpctrl */
1502 pci_write_config_dword(agp_bridge->dev, INTEL_AGPCTRL, 0x2280);
1503
1504 /* paccfg/nbxcfg */
1505 pci_read_config_word(agp_bridge->dev, INTEL_NBXCFG, &temp2);
1506 pci_write_config_word(agp_bridge->dev, INTEL_NBXCFG,
1507 (temp2 & ~(1 << 10)) | (1 << 9));
1508 /* clear any possible error conditions */
1509 pci_write_config_byte(agp_bridge->dev, INTEL_ERRSTS + 1, 7);
1510 return 0;
1511}
1512
1513static int intel_815_configure(void)
1514{
1515 u32 temp, addr;
1516 u8 temp2;
1517 struct aper_size_info_8 *current_size;
1518
1519 /* attbase - aperture base */
1520 /* the Intel 815 chipset spec. says that bits 29-31 in the
1521 * ATTBASE register are reserved -> try not to write them */
1522 if (agp_bridge->gatt_bus_addr & INTEL_815_ATTBASE_MASK) {
Bjorn Helgaase3cf6952008-07-30 12:26:51 -07001523 dev_emerg(&agp_bridge->dev->dev, "gatt bus addr too high");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001524 return -EINVAL;
1525 }
1526
1527 current_size = A_SIZE_8(agp_bridge->current_size);
1528
1529 /* aperture size */
1530 pci_write_config_byte(agp_bridge->dev, INTEL_APSIZE,
1531 current_size->size_value);
1532
1533 /* address to map to */
1534 pci_read_config_dword(agp_bridge->dev, AGP_APBASE, &temp);
1535 agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
1536
1537 pci_read_config_dword(agp_bridge->dev, INTEL_ATTBASE, &addr);
1538 addr &= INTEL_815_ATTBASE_MASK;
1539 addr |= agp_bridge->gatt_bus_addr;
1540 pci_write_config_dword(agp_bridge->dev, INTEL_ATTBASE, addr);
1541
1542 /* agpctrl */
1543 pci_write_config_dword(agp_bridge->dev, INTEL_AGPCTRL, 0x0000);
1544
1545 /* apcont */
1546 pci_read_config_byte(agp_bridge->dev, INTEL_815_APCONT, &temp2);
1547 pci_write_config_byte(agp_bridge->dev, INTEL_815_APCONT, temp2 | (1 << 1));
1548
1549 /* clear any possible error conditions */
1550 /* Oddness : this chipset seems to have no ERRSTS register ! */
1551 return 0;
1552}
1553
1554static void intel_820_tlbflush(struct agp_memory *mem)
1555{
1556 return;
1557}
1558
1559static void intel_820_cleanup(void)
1560{
1561 u8 temp;
1562 struct aper_size_info_8 *previous_size;
1563
1564 previous_size = A_SIZE_8(agp_bridge->previous_size);
1565 pci_read_config_byte(agp_bridge->dev, INTEL_I820_RDCR, &temp);
1566 pci_write_config_byte(agp_bridge->dev, INTEL_I820_RDCR,
1567 temp & ~(1 << 1));
1568 pci_write_config_byte(agp_bridge->dev, INTEL_APSIZE,
1569 previous_size->size_value);
1570}
1571
1572
1573static int intel_820_configure(void)
1574{
1575 u32 temp;
1576 u8 temp2;
1577 struct aper_size_info_8 *current_size;
1578
1579 current_size = A_SIZE_8(agp_bridge->current_size);
1580
1581 /* aperture size */
1582 pci_write_config_byte(agp_bridge->dev, INTEL_APSIZE, current_size->size_value);
1583
1584 /* address to map to */
1585 pci_read_config_dword(agp_bridge->dev, AGP_APBASE, &temp);
1586 agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
1587
1588 /* attbase - aperture base */
1589 pci_write_config_dword(agp_bridge->dev, INTEL_ATTBASE, agp_bridge->gatt_bus_addr);
1590
1591 /* agpctrl */
1592 pci_write_config_dword(agp_bridge->dev, INTEL_AGPCTRL, 0x0000);
1593
1594 /* global enable aperture access */
1595 /* This flag is not accessed through MCHCFG register as in */
1596 /* i850 chipset. */
1597 pci_read_config_byte(agp_bridge->dev, INTEL_I820_RDCR, &temp2);
1598 pci_write_config_byte(agp_bridge->dev, INTEL_I820_RDCR, temp2 | (1 << 1));
1599 /* clear any possible AGP-related error conditions */
1600 pci_write_config_word(agp_bridge->dev, INTEL_I820_ERRSTS, 0x001c);
1601 return 0;
1602}
1603
1604static int intel_840_configure(void)
1605{
1606 u32 temp;
1607 u16 temp2;
1608 struct aper_size_info_8 *current_size;
1609
1610 current_size = A_SIZE_8(agp_bridge->current_size);
1611
1612 /* aperture size */
1613 pci_write_config_byte(agp_bridge->dev, INTEL_APSIZE, current_size->size_value);
1614
1615 /* address to map to */
1616 pci_read_config_dword(agp_bridge->dev, AGP_APBASE, &temp);
1617 agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
1618
1619 /* attbase - aperture base */
1620 pci_write_config_dword(agp_bridge->dev, INTEL_ATTBASE, agp_bridge->gatt_bus_addr);
1621
1622 /* agpctrl */
1623 pci_write_config_dword(agp_bridge->dev, INTEL_AGPCTRL, 0x0000);
1624
1625 /* mcgcfg */
1626 pci_read_config_word(agp_bridge->dev, INTEL_I840_MCHCFG, &temp2);
1627 pci_write_config_word(agp_bridge->dev, INTEL_I840_MCHCFG, temp2 | (1 << 9));
1628 /* clear any possible error conditions */
1629 pci_write_config_word(agp_bridge->dev, INTEL_I840_ERRSTS, 0xc000);
1630 return 0;
1631}
1632
1633static int intel_845_configure(void)
1634{
1635 u32 temp;
1636 u8 temp2;
1637 struct aper_size_info_8 *current_size;
1638
1639 current_size = A_SIZE_8(agp_bridge->current_size);
1640
1641 /* aperture size */
1642 pci_write_config_byte(agp_bridge->dev, INTEL_APSIZE, current_size->size_value);
1643
Matthew Garrettb0825482005-07-29 14:03:39 -07001644 if (agp_bridge->apbase_config != 0) {
1645 pci_write_config_dword(agp_bridge->dev, AGP_APBASE,
1646 agp_bridge->apbase_config);
1647 } else {
1648 /* address to map to */
1649 pci_read_config_dword(agp_bridge->dev, AGP_APBASE, &temp);
1650 agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
1651 agp_bridge->apbase_config = temp;
1652 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001653
1654 /* attbase - aperture base */
1655 pci_write_config_dword(agp_bridge->dev, INTEL_ATTBASE, agp_bridge->gatt_bus_addr);
1656
1657 /* agpctrl */
1658 pci_write_config_dword(agp_bridge->dev, INTEL_AGPCTRL, 0x0000);
1659
1660 /* agpm */
1661 pci_read_config_byte(agp_bridge->dev, INTEL_I845_AGPM, &temp2);
1662 pci_write_config_byte(agp_bridge->dev, INTEL_I845_AGPM, temp2 | (1 << 1));
1663 /* clear any possible error conditions */
1664 pci_write_config_word(agp_bridge->dev, INTEL_I845_ERRSTS, 0x001c);
1665 return 0;
1666}
1667
1668static int intel_850_configure(void)
1669{
1670 u32 temp;
1671 u16 temp2;
1672 struct aper_size_info_8 *current_size;
1673
1674 current_size = A_SIZE_8(agp_bridge->current_size);
1675
1676 /* aperture size */
1677 pci_write_config_byte(agp_bridge->dev, INTEL_APSIZE, current_size->size_value);
1678
1679 /* address to map to */
1680 pci_read_config_dword(agp_bridge->dev, AGP_APBASE, &temp);
1681 agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
1682
1683 /* attbase - aperture base */
1684 pci_write_config_dword(agp_bridge->dev, INTEL_ATTBASE, agp_bridge->gatt_bus_addr);
1685
1686 /* agpctrl */
1687 pci_write_config_dword(agp_bridge->dev, INTEL_AGPCTRL, 0x0000);
1688
1689 /* mcgcfg */
1690 pci_read_config_word(agp_bridge->dev, INTEL_I850_MCHCFG, &temp2);
1691 pci_write_config_word(agp_bridge->dev, INTEL_I850_MCHCFG, temp2 | (1 << 9));
1692 /* clear any possible AGP-related error conditions */
1693 pci_write_config_word(agp_bridge->dev, INTEL_I850_ERRSTS, 0x001c);
1694 return 0;
1695}
1696
1697static int intel_860_configure(void)
1698{
1699 u32 temp;
1700 u16 temp2;
1701 struct aper_size_info_8 *current_size;
1702
1703 current_size = A_SIZE_8(agp_bridge->current_size);
1704
1705 /* aperture size */
1706 pci_write_config_byte(agp_bridge->dev, INTEL_APSIZE, current_size->size_value);
1707
1708 /* address to map to */
1709 pci_read_config_dword(agp_bridge->dev, AGP_APBASE, &temp);
1710 agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
1711
1712 /* attbase - aperture base */
1713 pci_write_config_dword(agp_bridge->dev, INTEL_ATTBASE, agp_bridge->gatt_bus_addr);
1714
1715 /* agpctrl */
1716 pci_write_config_dword(agp_bridge->dev, INTEL_AGPCTRL, 0x0000);
1717
1718 /* mcgcfg */
1719 pci_read_config_word(agp_bridge->dev, INTEL_I860_MCHCFG, &temp2);
1720 pci_write_config_word(agp_bridge->dev, INTEL_I860_MCHCFG, temp2 | (1 << 9));
1721 /* clear any possible AGP-related error conditions */
1722 pci_write_config_word(agp_bridge->dev, INTEL_I860_ERRSTS, 0xf700);
1723 return 0;
1724}
1725
1726static int intel_830mp_configure(void)
1727{
1728 u32 temp;
1729 u16 temp2;
1730 struct aper_size_info_8 *current_size;
1731
1732 current_size = A_SIZE_8(agp_bridge->current_size);
1733
1734 /* aperture size */
1735 pci_write_config_byte(agp_bridge->dev, INTEL_APSIZE, current_size->size_value);
1736
1737 /* address to map to */
1738 pci_read_config_dword(agp_bridge->dev, AGP_APBASE, &temp);
1739 agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
1740
1741 /* attbase - aperture base */
1742 pci_write_config_dword(agp_bridge->dev, INTEL_ATTBASE, agp_bridge->gatt_bus_addr);
1743
1744 /* agpctrl */
1745 pci_write_config_dword(agp_bridge->dev, INTEL_AGPCTRL, 0x0000);
1746
1747 /* gmch */
1748 pci_read_config_word(agp_bridge->dev, INTEL_NBXCFG, &temp2);
1749 pci_write_config_word(agp_bridge->dev, INTEL_NBXCFG, temp2 | (1 << 9));
1750 /* clear any possible AGP-related error conditions */
1751 pci_write_config_word(agp_bridge->dev, INTEL_I830_ERRSTS, 0x1c);
1752 return 0;
1753}
1754
1755static int intel_7505_configure(void)
1756{
1757 u32 temp;
1758 u16 temp2;
1759 struct aper_size_info_8 *current_size;
1760
1761 current_size = A_SIZE_8(agp_bridge->current_size);
1762
1763 /* aperture size */
1764 pci_write_config_byte(agp_bridge->dev, INTEL_APSIZE, current_size->size_value);
1765
1766 /* address to map to */
1767 pci_read_config_dword(agp_bridge->dev, AGP_APBASE, &temp);
1768 agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
1769
1770 /* attbase - aperture base */
1771 pci_write_config_dword(agp_bridge->dev, INTEL_ATTBASE, agp_bridge->gatt_bus_addr);
1772
1773 /* agpctrl */
1774 pci_write_config_dword(agp_bridge->dev, INTEL_AGPCTRL, 0x0000);
1775
1776 /* mchcfg */
1777 pci_read_config_word(agp_bridge->dev, INTEL_I7505_MCHCFG, &temp2);
1778 pci_write_config_word(agp_bridge->dev, INTEL_I7505_MCHCFG, temp2 | (1 << 9));
1779
1780 return 0;
1781}
1782
1783/* Setup function */
Dave Jonese5524f32007-02-22 18:41:28 -05001784static const struct gatt_mask intel_generic_masks[] =
Linus Torvalds1da177e2005-04-16 15:20:36 -07001785{
1786 {.mask = 0x00000017, .type = 0}
1787};
1788
Dave Jonese5524f32007-02-22 18:41:28 -05001789static const struct aper_size_info_8 intel_815_sizes[2] =
Linus Torvalds1da177e2005-04-16 15:20:36 -07001790{
1791 {64, 16384, 4, 0},
1792 {32, 8192, 3, 8},
1793};
1794
Dave Jonese5524f32007-02-22 18:41:28 -05001795static const struct aper_size_info_8 intel_8xx_sizes[7] =
Linus Torvalds1da177e2005-04-16 15:20:36 -07001796{
1797 {256, 65536, 6, 0},
1798 {128, 32768, 5, 32},
1799 {64, 16384, 4, 48},
1800 {32, 8192, 3, 56},
1801 {16, 4096, 2, 60},
1802 {8, 2048, 1, 62},
1803 {4, 1024, 0, 63}
1804};
1805
Dave Jonese5524f32007-02-22 18:41:28 -05001806static const struct aper_size_info_16 intel_generic_sizes[7] =
Linus Torvalds1da177e2005-04-16 15:20:36 -07001807{
1808 {256, 65536, 6, 0},
1809 {128, 32768, 5, 32},
1810 {64, 16384, 4, 48},
1811 {32, 8192, 3, 56},
1812 {16, 4096, 2, 60},
1813 {8, 2048, 1, 62},
1814 {4, 1024, 0, 63}
1815};
1816
Dave Jonese5524f32007-02-22 18:41:28 -05001817static const struct aper_size_info_8 intel_830mp_sizes[4] =
Linus Torvalds1da177e2005-04-16 15:20:36 -07001818{
1819 {256, 65536, 6, 0},
1820 {128, 32768, 5, 32},
1821 {64, 16384, 4, 48},
1822 {32, 8192, 3, 56}
1823};
1824
Dave Jonese5524f32007-02-22 18:41:28 -05001825static const struct agp_bridge_driver intel_generic_driver = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001826 .owner = THIS_MODULE,
1827 .aperture_sizes = intel_generic_sizes,
1828 .size_type = U16_APER_SIZE,
1829 .num_aperture_sizes = 7,
1830 .configure = intel_configure,
1831 .fetch_size = intel_fetch_size,
1832 .cleanup = intel_cleanup,
1833 .tlb_flush = intel_tlbflush,
1834 .mask_memory = agp_generic_mask_memory,
1835 .masks = intel_generic_masks,
1836 .agp_enable = agp_generic_enable,
1837 .cache_flush = global_cache_flush,
1838 .create_gatt_table = agp_generic_create_gatt_table,
1839 .free_gatt_table = agp_generic_free_gatt_table,
1840 .insert_memory = agp_generic_insert_memory,
1841 .remove_memory = agp_generic_remove_memory,
1842 .alloc_by_type = agp_generic_alloc_by_type,
1843 .free_by_type = agp_generic_free_by_type,
1844 .agp_alloc_page = agp_generic_alloc_page,
Shaohua Li37acee12008-08-21 10:46:11 +08001845 .agp_alloc_pages = agp_generic_alloc_pages,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001846 .agp_destroy_page = agp_generic_destroy_page,
Shaohua Libd079282008-08-21 10:46:17 +08001847 .agp_destroy_pages = agp_generic_destroy_pages,
Thomas Hellstroma030ce42007-01-23 10:33:43 +01001848 .agp_type_to_mask_type = agp_generic_type_to_mask_type,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001849};
1850
Dave Jonese5524f32007-02-22 18:41:28 -05001851static const struct agp_bridge_driver intel_810_driver = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001852 .owner = THIS_MODULE,
1853 .aperture_sizes = intel_i810_sizes,
1854 .size_type = FIXED_APER_SIZE,
1855 .num_aperture_sizes = 2,
Joe Perchesc7258012008-03-26 14:10:02 -07001856 .needs_scratch_page = true,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001857 .configure = intel_i810_configure,
1858 .fetch_size = intel_i810_fetch_size,
1859 .cleanup = intel_i810_cleanup,
1860 .tlb_flush = intel_i810_tlbflush,
1861 .mask_memory = intel_i810_mask_memory,
1862 .masks = intel_i810_masks,
1863 .agp_enable = intel_i810_agp_enable,
1864 .cache_flush = global_cache_flush,
1865 .create_gatt_table = agp_generic_create_gatt_table,
1866 .free_gatt_table = agp_generic_free_gatt_table,
1867 .insert_memory = intel_i810_insert_entries,
1868 .remove_memory = intel_i810_remove_entries,
1869 .alloc_by_type = intel_i810_alloc_by_type,
1870 .free_by_type = intel_i810_free_by_type,
1871 .agp_alloc_page = agp_generic_alloc_page,
Shaohua Li37acee12008-08-21 10:46:11 +08001872 .agp_alloc_pages = agp_generic_alloc_pages,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001873 .agp_destroy_page = agp_generic_destroy_page,
Shaohua Libd079282008-08-21 10:46:17 +08001874 .agp_destroy_pages = agp_generic_destroy_pages,
Thomas Hellstroma030ce42007-01-23 10:33:43 +01001875 .agp_type_to_mask_type = agp_generic_type_to_mask_type,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001876};
1877
Dave Jonese5524f32007-02-22 18:41:28 -05001878static const struct agp_bridge_driver intel_815_driver = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001879 .owner = THIS_MODULE,
1880 .aperture_sizes = intel_815_sizes,
1881 .size_type = U8_APER_SIZE,
1882 .num_aperture_sizes = 2,
1883 .configure = intel_815_configure,
1884 .fetch_size = intel_815_fetch_size,
1885 .cleanup = intel_8xx_cleanup,
1886 .tlb_flush = intel_8xx_tlbflush,
1887 .mask_memory = agp_generic_mask_memory,
1888 .masks = intel_generic_masks,
1889 .agp_enable = agp_generic_enable,
1890 .cache_flush = global_cache_flush,
1891 .create_gatt_table = agp_generic_create_gatt_table,
1892 .free_gatt_table = agp_generic_free_gatt_table,
1893 .insert_memory = agp_generic_insert_memory,
1894 .remove_memory = agp_generic_remove_memory,
1895 .alloc_by_type = agp_generic_alloc_by_type,
1896 .free_by_type = agp_generic_free_by_type,
1897 .agp_alloc_page = agp_generic_alloc_page,
Shaohua Li37acee12008-08-21 10:46:11 +08001898 .agp_alloc_pages = agp_generic_alloc_pages,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001899 .agp_destroy_page = agp_generic_destroy_page,
Shaohua Libd079282008-08-21 10:46:17 +08001900 .agp_destroy_pages = agp_generic_destroy_pages,
Dave Airlie62c96b92008-06-19 14:27:53 +10001901 .agp_type_to_mask_type = agp_generic_type_to_mask_type,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001902};
1903
Dave Jonese5524f32007-02-22 18:41:28 -05001904static const struct agp_bridge_driver intel_830_driver = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001905 .owner = THIS_MODULE,
1906 .aperture_sizes = intel_i830_sizes,
1907 .size_type = FIXED_APER_SIZE,
Dave Jonesc14635e2006-09-06 11:59:35 -04001908 .num_aperture_sizes = 4,
Joe Perchesc7258012008-03-26 14:10:02 -07001909 .needs_scratch_page = true,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001910 .configure = intel_i830_configure,
1911 .fetch_size = intel_i830_fetch_size,
1912 .cleanup = intel_i830_cleanup,
1913 .tlb_flush = intel_i810_tlbflush,
1914 .mask_memory = intel_i810_mask_memory,
1915 .masks = intel_i810_masks,
1916 .agp_enable = intel_i810_agp_enable,
1917 .cache_flush = global_cache_flush,
1918 .create_gatt_table = intel_i830_create_gatt_table,
1919 .free_gatt_table = intel_i830_free_gatt_table,
1920 .insert_memory = intel_i830_insert_entries,
1921 .remove_memory = intel_i830_remove_entries,
1922 .alloc_by_type = intel_i830_alloc_by_type,
1923 .free_by_type = intel_i810_free_by_type,
1924 .agp_alloc_page = agp_generic_alloc_page,
Shaohua Li37acee12008-08-21 10:46:11 +08001925 .agp_alloc_pages = agp_generic_alloc_pages,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001926 .agp_destroy_page = agp_generic_destroy_page,
Shaohua Libd079282008-08-21 10:46:17 +08001927 .agp_destroy_pages = agp_generic_destroy_pages,
Thomas Hellstroma030ce42007-01-23 10:33:43 +01001928 .agp_type_to_mask_type = intel_i830_type_to_mask_type,
Dave Airlie2162e6a2007-11-21 16:36:31 +10001929 .chipset_flush = intel_i830_chipset_flush,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001930};
1931
Dave Jonese5524f32007-02-22 18:41:28 -05001932static const struct agp_bridge_driver intel_820_driver = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001933 .owner = THIS_MODULE,
1934 .aperture_sizes = intel_8xx_sizes,
1935 .size_type = U8_APER_SIZE,
1936 .num_aperture_sizes = 7,
1937 .configure = intel_820_configure,
1938 .fetch_size = intel_8xx_fetch_size,
1939 .cleanup = intel_820_cleanup,
1940 .tlb_flush = intel_820_tlbflush,
1941 .mask_memory = agp_generic_mask_memory,
1942 .masks = intel_generic_masks,
1943 .agp_enable = agp_generic_enable,
1944 .cache_flush = global_cache_flush,
1945 .create_gatt_table = agp_generic_create_gatt_table,
1946 .free_gatt_table = agp_generic_free_gatt_table,
1947 .insert_memory = agp_generic_insert_memory,
1948 .remove_memory = agp_generic_remove_memory,
1949 .alloc_by_type = agp_generic_alloc_by_type,
1950 .free_by_type = agp_generic_free_by_type,
1951 .agp_alloc_page = agp_generic_alloc_page,
Shaohua Li37acee12008-08-21 10:46:11 +08001952 .agp_alloc_pages = agp_generic_alloc_pages,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001953 .agp_destroy_page = agp_generic_destroy_page,
Shaohua Libd079282008-08-21 10:46:17 +08001954 .agp_destroy_pages = agp_generic_destroy_pages,
Thomas Hellstroma030ce42007-01-23 10:33:43 +01001955 .agp_type_to_mask_type = agp_generic_type_to_mask_type,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001956};
1957
Dave Jonese5524f32007-02-22 18:41:28 -05001958static const struct agp_bridge_driver intel_830mp_driver = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001959 .owner = THIS_MODULE,
1960 .aperture_sizes = intel_830mp_sizes,
1961 .size_type = U8_APER_SIZE,
1962 .num_aperture_sizes = 4,
1963 .configure = intel_830mp_configure,
1964 .fetch_size = intel_8xx_fetch_size,
1965 .cleanup = intel_8xx_cleanup,
1966 .tlb_flush = intel_8xx_tlbflush,
1967 .mask_memory = agp_generic_mask_memory,
1968 .masks = intel_generic_masks,
1969 .agp_enable = agp_generic_enable,
1970 .cache_flush = global_cache_flush,
1971 .create_gatt_table = agp_generic_create_gatt_table,
1972 .free_gatt_table = agp_generic_free_gatt_table,
1973 .insert_memory = agp_generic_insert_memory,
1974 .remove_memory = agp_generic_remove_memory,
1975 .alloc_by_type = agp_generic_alloc_by_type,
1976 .free_by_type = agp_generic_free_by_type,
1977 .agp_alloc_page = agp_generic_alloc_page,
Shaohua Li37acee12008-08-21 10:46:11 +08001978 .agp_alloc_pages = agp_generic_alloc_pages,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001979 .agp_destroy_page = agp_generic_destroy_page,
Shaohua Libd079282008-08-21 10:46:17 +08001980 .agp_destroy_pages = agp_generic_destroy_pages,
Thomas Hellstroma030ce42007-01-23 10:33:43 +01001981 .agp_type_to_mask_type = agp_generic_type_to_mask_type,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001982};
1983
Dave Jonese5524f32007-02-22 18:41:28 -05001984static const struct agp_bridge_driver intel_840_driver = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001985 .owner = THIS_MODULE,
1986 .aperture_sizes = intel_8xx_sizes,
1987 .size_type = U8_APER_SIZE,
1988 .num_aperture_sizes = 7,
1989 .configure = intel_840_configure,
1990 .fetch_size = intel_8xx_fetch_size,
1991 .cleanup = intel_8xx_cleanup,
1992 .tlb_flush = intel_8xx_tlbflush,
1993 .mask_memory = agp_generic_mask_memory,
1994 .masks = intel_generic_masks,
1995 .agp_enable = agp_generic_enable,
1996 .cache_flush = global_cache_flush,
1997 .create_gatt_table = agp_generic_create_gatt_table,
1998 .free_gatt_table = agp_generic_free_gatt_table,
1999 .insert_memory = agp_generic_insert_memory,
2000 .remove_memory = agp_generic_remove_memory,
2001 .alloc_by_type = agp_generic_alloc_by_type,
2002 .free_by_type = agp_generic_free_by_type,
2003 .agp_alloc_page = agp_generic_alloc_page,
Shaohua Li37acee12008-08-21 10:46:11 +08002004 .agp_alloc_pages = agp_generic_alloc_pages,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002005 .agp_destroy_page = agp_generic_destroy_page,
Shaohua Libd079282008-08-21 10:46:17 +08002006 .agp_destroy_pages = agp_generic_destroy_pages,
Thomas Hellstroma030ce42007-01-23 10:33:43 +01002007 .agp_type_to_mask_type = agp_generic_type_to_mask_type,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002008};
2009
Dave Jonese5524f32007-02-22 18:41:28 -05002010static const struct agp_bridge_driver intel_845_driver = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002011 .owner = THIS_MODULE,
2012 .aperture_sizes = intel_8xx_sizes,
2013 .size_type = U8_APER_SIZE,
2014 .num_aperture_sizes = 7,
2015 .configure = intel_845_configure,
2016 .fetch_size = intel_8xx_fetch_size,
2017 .cleanup = intel_8xx_cleanup,
2018 .tlb_flush = intel_8xx_tlbflush,
2019 .mask_memory = agp_generic_mask_memory,
2020 .masks = intel_generic_masks,
2021 .agp_enable = agp_generic_enable,
2022 .cache_flush = global_cache_flush,
2023 .create_gatt_table = agp_generic_create_gatt_table,
2024 .free_gatt_table = agp_generic_free_gatt_table,
2025 .insert_memory = agp_generic_insert_memory,
2026 .remove_memory = agp_generic_remove_memory,
2027 .alloc_by_type = agp_generic_alloc_by_type,
2028 .free_by_type = agp_generic_free_by_type,
2029 .agp_alloc_page = agp_generic_alloc_page,
Shaohua Li37acee12008-08-21 10:46:11 +08002030 .agp_alloc_pages = agp_generic_alloc_pages,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002031 .agp_destroy_page = agp_generic_destroy_page,
Shaohua Libd079282008-08-21 10:46:17 +08002032 .agp_destroy_pages = agp_generic_destroy_pages,
Thomas Hellstroma030ce42007-01-23 10:33:43 +01002033 .agp_type_to_mask_type = agp_generic_type_to_mask_type,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002034};
2035
Dave Jonese5524f32007-02-22 18:41:28 -05002036static const struct agp_bridge_driver intel_850_driver = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002037 .owner = THIS_MODULE,
2038 .aperture_sizes = intel_8xx_sizes,
2039 .size_type = U8_APER_SIZE,
2040 .num_aperture_sizes = 7,
2041 .configure = intel_850_configure,
2042 .fetch_size = intel_8xx_fetch_size,
2043 .cleanup = intel_8xx_cleanup,
2044 .tlb_flush = intel_8xx_tlbflush,
2045 .mask_memory = agp_generic_mask_memory,
2046 .masks = intel_generic_masks,
2047 .agp_enable = agp_generic_enable,
2048 .cache_flush = global_cache_flush,
2049 .create_gatt_table = agp_generic_create_gatt_table,
2050 .free_gatt_table = agp_generic_free_gatt_table,
2051 .insert_memory = agp_generic_insert_memory,
2052 .remove_memory = agp_generic_remove_memory,
2053 .alloc_by_type = agp_generic_alloc_by_type,
2054 .free_by_type = agp_generic_free_by_type,
2055 .agp_alloc_page = agp_generic_alloc_page,
Shaohua Li37acee12008-08-21 10:46:11 +08002056 .agp_alloc_pages = agp_generic_alloc_pages,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002057 .agp_destroy_page = agp_generic_destroy_page,
Shaohua Libd079282008-08-21 10:46:17 +08002058 .agp_destroy_pages = agp_generic_destroy_pages,
Thomas Hellstroma030ce42007-01-23 10:33:43 +01002059 .agp_type_to_mask_type = agp_generic_type_to_mask_type,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002060};
2061
Dave Jonese5524f32007-02-22 18:41:28 -05002062static const struct agp_bridge_driver intel_860_driver = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002063 .owner = THIS_MODULE,
2064 .aperture_sizes = intel_8xx_sizes,
2065 .size_type = U8_APER_SIZE,
2066 .num_aperture_sizes = 7,
2067 .configure = intel_860_configure,
2068 .fetch_size = intel_8xx_fetch_size,
2069 .cleanup = intel_8xx_cleanup,
2070 .tlb_flush = intel_8xx_tlbflush,
2071 .mask_memory = agp_generic_mask_memory,
2072 .masks = intel_generic_masks,
2073 .agp_enable = agp_generic_enable,
2074 .cache_flush = global_cache_flush,
2075 .create_gatt_table = agp_generic_create_gatt_table,
2076 .free_gatt_table = agp_generic_free_gatt_table,
2077 .insert_memory = agp_generic_insert_memory,
2078 .remove_memory = agp_generic_remove_memory,
2079 .alloc_by_type = agp_generic_alloc_by_type,
2080 .free_by_type = agp_generic_free_by_type,
2081 .agp_alloc_page = agp_generic_alloc_page,
Shaohua Li37acee12008-08-21 10:46:11 +08002082 .agp_alloc_pages = agp_generic_alloc_pages,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002083 .agp_destroy_page = agp_generic_destroy_page,
Shaohua Libd079282008-08-21 10:46:17 +08002084 .agp_destroy_pages = agp_generic_destroy_pages,
Thomas Hellstroma030ce42007-01-23 10:33:43 +01002085 .agp_type_to_mask_type = agp_generic_type_to_mask_type,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002086};
2087
Dave Jonese5524f32007-02-22 18:41:28 -05002088static const struct agp_bridge_driver intel_915_driver = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002089 .owner = THIS_MODULE,
2090 .aperture_sizes = intel_i830_sizes,
2091 .size_type = FIXED_APER_SIZE,
Dave Jonesc14635e2006-09-06 11:59:35 -04002092 .num_aperture_sizes = 4,
Joe Perchesc7258012008-03-26 14:10:02 -07002093 .needs_scratch_page = true,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002094 .configure = intel_i915_configure,
Eric Anholtc41e0de2006-12-19 12:57:24 -08002095 .fetch_size = intel_i9xx_fetch_size,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002096 .cleanup = intel_i915_cleanup,
2097 .tlb_flush = intel_i810_tlbflush,
2098 .mask_memory = intel_i810_mask_memory,
2099 .masks = intel_i810_masks,
2100 .agp_enable = intel_i810_agp_enable,
2101 .cache_flush = global_cache_flush,
2102 .create_gatt_table = intel_i915_create_gatt_table,
2103 .free_gatt_table = intel_i830_free_gatt_table,
2104 .insert_memory = intel_i915_insert_entries,
2105 .remove_memory = intel_i915_remove_entries,
2106 .alloc_by_type = intel_i830_alloc_by_type,
2107 .free_by_type = intel_i810_free_by_type,
2108 .agp_alloc_page = agp_generic_alloc_page,
Shaohua Li37acee12008-08-21 10:46:11 +08002109 .agp_alloc_pages = agp_generic_alloc_pages,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002110 .agp_destroy_page = agp_generic_destroy_page,
Shaohua Libd079282008-08-21 10:46:17 +08002111 .agp_destroy_pages = agp_generic_destroy_pages,
Thomas Hellstroma030ce42007-01-23 10:33:43 +01002112 .agp_type_to_mask_type = intel_i830_type_to_mask_type,
Dave Airlie6c00a612007-10-29 18:06:10 +10002113 .chipset_flush = intel_i915_chipset_flush,
Zhenyu Wang17661682009-07-27 12:59:57 +01002114#ifdef USE_PCI_DMA_API
2115 .agp_map_page = intel_agp_map_page,
2116 .agp_unmap_page = intel_agp_unmap_page,
2117 .agp_map_memory = intel_agp_map_memory,
2118 .agp_unmap_memory = intel_agp_unmap_memory,
2119#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07002120};
2121
Dave Jonese5524f32007-02-22 18:41:28 -05002122static const struct agp_bridge_driver intel_i965_driver = {
Dave Airlie62c96b92008-06-19 14:27:53 +10002123 .owner = THIS_MODULE,
2124 .aperture_sizes = intel_i830_sizes,
2125 .size_type = FIXED_APER_SIZE,
2126 .num_aperture_sizes = 4,
2127 .needs_scratch_page = true,
Dave Airlie0e480e52008-06-19 14:57:31 +10002128 .configure = intel_i915_configure,
2129 .fetch_size = intel_i9xx_fetch_size,
Dave Airlie62c96b92008-06-19 14:27:53 +10002130 .cleanup = intel_i915_cleanup,
2131 .tlb_flush = intel_i810_tlbflush,
2132 .mask_memory = intel_i965_mask_memory,
2133 .masks = intel_i810_masks,
2134 .agp_enable = intel_i810_agp_enable,
2135 .cache_flush = global_cache_flush,
2136 .create_gatt_table = intel_i965_create_gatt_table,
2137 .free_gatt_table = intel_i830_free_gatt_table,
2138 .insert_memory = intel_i915_insert_entries,
2139 .remove_memory = intel_i915_remove_entries,
2140 .alloc_by_type = intel_i830_alloc_by_type,
2141 .free_by_type = intel_i810_free_by_type,
2142 .agp_alloc_page = agp_generic_alloc_page,
Shaohua Li37acee12008-08-21 10:46:11 +08002143 .agp_alloc_pages = agp_generic_alloc_pages,
Dave Airlie62c96b92008-06-19 14:27:53 +10002144 .agp_destroy_page = agp_generic_destroy_page,
Shaohua Libd079282008-08-21 10:46:17 +08002145 .agp_destroy_pages = agp_generic_destroy_pages,
Dave Airlie62c96b92008-06-19 14:27:53 +10002146 .agp_type_to_mask_type = intel_i830_type_to_mask_type,
Dave Airlie6c00a612007-10-29 18:06:10 +10002147 .chipset_flush = intel_i915_chipset_flush,
Zhenyu Wang17661682009-07-27 12:59:57 +01002148#ifdef USE_PCI_DMA_API
2149 .agp_map_page = intel_agp_map_page,
2150 .agp_unmap_page = intel_agp_unmap_page,
2151 .agp_map_memory = intel_agp_map_memory,
2152 .agp_unmap_memory = intel_agp_unmap_memory,
2153#endif
Eric Anholt65c25aa2006-09-06 11:57:18 -04002154};
Linus Torvalds1da177e2005-04-16 15:20:36 -07002155
Dave Jonese5524f32007-02-22 18:41:28 -05002156static const struct agp_bridge_driver intel_7505_driver = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002157 .owner = THIS_MODULE,
2158 .aperture_sizes = intel_8xx_sizes,
2159 .size_type = U8_APER_SIZE,
2160 .num_aperture_sizes = 7,
2161 .configure = intel_7505_configure,
2162 .fetch_size = intel_8xx_fetch_size,
2163 .cleanup = intel_8xx_cleanup,
2164 .tlb_flush = intel_8xx_tlbflush,
2165 .mask_memory = agp_generic_mask_memory,
2166 .masks = intel_generic_masks,
2167 .agp_enable = agp_generic_enable,
2168 .cache_flush = global_cache_flush,
2169 .create_gatt_table = agp_generic_create_gatt_table,
2170 .free_gatt_table = agp_generic_free_gatt_table,
2171 .insert_memory = agp_generic_insert_memory,
2172 .remove_memory = agp_generic_remove_memory,
2173 .alloc_by_type = agp_generic_alloc_by_type,
2174 .free_by_type = agp_generic_free_by_type,
2175 .agp_alloc_page = agp_generic_alloc_page,
Shaohua Li37acee12008-08-21 10:46:11 +08002176 .agp_alloc_pages = agp_generic_alloc_pages,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002177 .agp_destroy_page = agp_generic_destroy_page,
Shaohua Libd079282008-08-21 10:46:17 +08002178 .agp_destroy_pages = agp_generic_destroy_pages,
Thomas Hellstroma030ce42007-01-23 10:33:43 +01002179 .agp_type_to_mask_type = agp_generic_type_to_mask_type,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002180};
2181
Wang Zhenyu874808c62007-06-06 11:16:25 +08002182static const struct agp_bridge_driver intel_g33_driver = {
Dave Airlie62c96b92008-06-19 14:27:53 +10002183 .owner = THIS_MODULE,
2184 .aperture_sizes = intel_i830_sizes,
2185 .size_type = FIXED_APER_SIZE,
2186 .num_aperture_sizes = 4,
2187 .needs_scratch_page = true,
2188 .configure = intel_i915_configure,
2189 .fetch_size = intel_i9xx_fetch_size,
2190 .cleanup = intel_i915_cleanup,
2191 .tlb_flush = intel_i810_tlbflush,
2192 .mask_memory = intel_i965_mask_memory,
2193 .masks = intel_i810_masks,
2194 .agp_enable = intel_i810_agp_enable,
2195 .cache_flush = global_cache_flush,
2196 .create_gatt_table = intel_i915_create_gatt_table,
2197 .free_gatt_table = intel_i830_free_gatt_table,
2198 .insert_memory = intel_i915_insert_entries,
2199 .remove_memory = intel_i915_remove_entries,
2200 .alloc_by_type = intel_i830_alloc_by_type,
2201 .free_by_type = intel_i810_free_by_type,
2202 .agp_alloc_page = agp_generic_alloc_page,
Shaohua Li37acee12008-08-21 10:46:11 +08002203 .agp_alloc_pages = agp_generic_alloc_pages,
Dave Airlie62c96b92008-06-19 14:27:53 +10002204 .agp_destroy_page = agp_generic_destroy_page,
Shaohua Libd079282008-08-21 10:46:17 +08002205 .agp_destroy_pages = agp_generic_destroy_pages,
Dave Airlie62c96b92008-06-19 14:27:53 +10002206 .agp_type_to_mask_type = intel_i830_type_to_mask_type,
Dave Airlie6c00a612007-10-29 18:06:10 +10002207 .chipset_flush = intel_i915_chipset_flush,
Zhenyu Wang17661682009-07-27 12:59:57 +01002208#ifdef USE_PCI_DMA_API
2209 .agp_map_page = intel_agp_map_page,
2210 .agp_unmap_page = intel_agp_unmap_page,
2211 .agp_map_memory = intel_agp_map_memory,
2212 .agp_unmap_memory = intel_agp_unmap_memory,
2213#endif
Wang Zhenyu874808c62007-06-06 11:16:25 +08002214};
Wang Zhenyu9614ece2007-05-30 09:45:58 +08002215
2216static int find_gmch(u16 device)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002217{
Wang Zhenyu9614ece2007-05-30 09:45:58 +08002218 struct pci_dev *gmch_device;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002219
Wang Zhenyu9614ece2007-05-30 09:45:58 +08002220 gmch_device = pci_get_device(PCI_VENDOR_ID_INTEL, device, NULL);
2221 if (gmch_device && PCI_FUNC(gmch_device->devfn) != 0) {
2222 gmch_device = pci_get_device(PCI_VENDOR_ID_INTEL,
Dave Airlief011ae72008-01-25 11:23:04 +10002223 device, gmch_device);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002224 }
2225
Wang Zhenyu9614ece2007-05-30 09:45:58 +08002226 if (!gmch_device)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002227 return 0;
2228
Wang Zhenyu9614ece2007-05-30 09:45:58 +08002229 intel_private.pcidev = gmch_device;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002230 return 1;
2231}
2232
Wang Zhenyu9614ece2007-05-30 09:45:58 +08002233/* Table to describe Intel GMCH and AGP/PCIE GART drivers. At least one of
2234 * driver and gmch_driver must be non-null, and find_gmch will determine
2235 * which one should be used if a gmch_chip_id is present.
2236 */
2237static const struct intel_driver_description {
2238 unsigned int chip_id;
2239 unsigned int gmch_chip_id;
Wang Zhenyu88889852007-06-14 10:01:04 +08002240 unsigned int multi_gmch_chip; /* if we have more gfx chip type on this HB. */
Wang Zhenyu9614ece2007-05-30 09:45:58 +08002241 char *name;
2242 const struct agp_bridge_driver *driver;
2243 const struct agp_bridge_driver *gmch_driver;
2244} intel_agp_chipsets[] = {
Wang Zhenyu88889852007-06-14 10:01:04 +08002245 { PCI_DEVICE_ID_INTEL_82443LX_0, 0, 0, "440LX", &intel_generic_driver, NULL },
2246 { PCI_DEVICE_ID_INTEL_82443BX_0, 0, 0, "440BX", &intel_generic_driver, NULL },
2247 { PCI_DEVICE_ID_INTEL_82443GX_0, 0, 0, "440GX", &intel_generic_driver, NULL },
2248 { PCI_DEVICE_ID_INTEL_82810_MC1, PCI_DEVICE_ID_INTEL_82810_IG1, 0, "i810",
Wang Zhenyu9614ece2007-05-30 09:45:58 +08002249 NULL, &intel_810_driver },
Wang Zhenyu88889852007-06-14 10:01:04 +08002250 { PCI_DEVICE_ID_INTEL_82810_MC3, PCI_DEVICE_ID_INTEL_82810_IG3, 0, "i810",
Wang Zhenyu9614ece2007-05-30 09:45:58 +08002251 NULL, &intel_810_driver },
Wang Zhenyu88889852007-06-14 10:01:04 +08002252 { PCI_DEVICE_ID_INTEL_82810E_MC, PCI_DEVICE_ID_INTEL_82810E_IG, 0, "i810",
Wang Zhenyu9614ece2007-05-30 09:45:58 +08002253 NULL, &intel_810_driver },
Wang Zhenyu88889852007-06-14 10:01:04 +08002254 { PCI_DEVICE_ID_INTEL_82815_MC, PCI_DEVICE_ID_INTEL_82815_CGC, 0, "i815",
2255 &intel_815_driver, &intel_810_driver },
2256 { PCI_DEVICE_ID_INTEL_82820_HB, 0, 0, "i820", &intel_820_driver, NULL },
2257 { PCI_DEVICE_ID_INTEL_82820_UP_HB, 0, 0, "i820", &intel_820_driver, NULL },
2258 { PCI_DEVICE_ID_INTEL_82830_HB, PCI_DEVICE_ID_INTEL_82830_CGC, 0, "830M",
Wang Zhenyu9614ece2007-05-30 09:45:58 +08002259 &intel_830mp_driver, &intel_830_driver },
Wang Zhenyu88889852007-06-14 10:01:04 +08002260 { PCI_DEVICE_ID_INTEL_82840_HB, 0, 0, "i840", &intel_840_driver, NULL },
2261 { PCI_DEVICE_ID_INTEL_82845_HB, 0, 0, "845G", &intel_845_driver, NULL },
2262 { PCI_DEVICE_ID_INTEL_82845G_HB, PCI_DEVICE_ID_INTEL_82845G_IG, 0, "830M",
Wang Zhenyu9614ece2007-05-30 09:45:58 +08002263 &intel_845_driver, &intel_830_driver },
Wang Zhenyu88889852007-06-14 10:01:04 +08002264 { PCI_DEVICE_ID_INTEL_82850_HB, 0, 0, "i850", &intel_850_driver, NULL },
Stefan Husemann347486b2009-04-13 14:40:10 -07002265 { PCI_DEVICE_ID_INTEL_82854_HB, PCI_DEVICE_ID_INTEL_82854_IG, 0, "854",
2266 &intel_845_driver, &intel_830_driver },
Wang Zhenyu88889852007-06-14 10:01:04 +08002267 { PCI_DEVICE_ID_INTEL_82855PM_HB, 0, 0, "855PM", &intel_845_driver, NULL },
2268 { PCI_DEVICE_ID_INTEL_82855GM_HB, PCI_DEVICE_ID_INTEL_82855GM_IG, 0, "855GM",
Wang Zhenyu9614ece2007-05-30 09:45:58 +08002269 &intel_845_driver, &intel_830_driver },
Wang Zhenyu88889852007-06-14 10:01:04 +08002270 { PCI_DEVICE_ID_INTEL_82860_HB, 0, 0, "i860", &intel_860_driver, NULL },
2271 { PCI_DEVICE_ID_INTEL_82865_HB, PCI_DEVICE_ID_INTEL_82865_IG, 0, "865",
Wang Zhenyu9614ece2007-05-30 09:45:58 +08002272 &intel_845_driver, &intel_830_driver },
Wang Zhenyu88889852007-06-14 10:01:04 +08002273 { PCI_DEVICE_ID_INTEL_82875_HB, 0, 0, "i875", &intel_845_driver, NULL },
Carlos Martíne914a362008-01-24 10:34:09 +10002274 { PCI_DEVICE_ID_INTEL_E7221_HB, PCI_DEVICE_ID_INTEL_E7221_IG, 0, "E7221 (i915)",
2275 NULL, &intel_915_driver },
Wang Zhenyu88889852007-06-14 10:01:04 +08002276 { PCI_DEVICE_ID_INTEL_82915G_HB, PCI_DEVICE_ID_INTEL_82915G_IG, 0, "915G",
Wang Zhenyu47d46372007-06-21 13:43:18 +08002277 NULL, &intel_915_driver },
Wang Zhenyu88889852007-06-14 10:01:04 +08002278 { PCI_DEVICE_ID_INTEL_82915GM_HB, PCI_DEVICE_ID_INTEL_82915GM_IG, 0, "915GM",
Wang Zhenyu47d46372007-06-21 13:43:18 +08002279 NULL, &intel_915_driver },
Wang Zhenyu88889852007-06-14 10:01:04 +08002280 { PCI_DEVICE_ID_INTEL_82945G_HB, PCI_DEVICE_ID_INTEL_82945G_IG, 0, "945G",
Wang Zhenyu47d46372007-06-21 13:43:18 +08002281 NULL, &intel_915_driver },
Zhenyu Wangdde47872007-07-26 09:18:09 +08002282 { PCI_DEVICE_ID_INTEL_82945GM_HB, PCI_DEVICE_ID_INTEL_82945GM_IG, 0, "945GM",
Wang Zhenyu47d46372007-06-21 13:43:18 +08002283 NULL, &intel_915_driver },
Zhenyu Wangdde47872007-07-26 09:18:09 +08002284 { PCI_DEVICE_ID_INTEL_82945GME_HB, PCI_DEVICE_ID_INTEL_82945GME_IG, 0, "945GME",
Wang Zhenyu47d46372007-06-21 13:43:18 +08002285 NULL, &intel_915_driver },
Wang Zhenyu88889852007-06-14 10:01:04 +08002286 { PCI_DEVICE_ID_INTEL_82946GZ_HB, PCI_DEVICE_ID_INTEL_82946GZ_IG, 0, "946GZ",
Wang Zhenyu47d46372007-06-21 13:43:18 +08002287 NULL, &intel_i965_driver },
Zhenyu Wang9119f852008-01-23 15:49:26 +10002288 { PCI_DEVICE_ID_INTEL_82G35_HB, PCI_DEVICE_ID_INTEL_82G35_IG, 0, "G35",
Wang Zhenyu47d46372007-06-21 13:43:18 +08002289 NULL, &intel_i965_driver },
Wang Zhenyu88889852007-06-14 10:01:04 +08002290 { PCI_DEVICE_ID_INTEL_82965Q_HB, PCI_DEVICE_ID_INTEL_82965Q_IG, 0, "965Q",
Wang Zhenyu47d46372007-06-21 13:43:18 +08002291 NULL, &intel_i965_driver },
Wang Zhenyu88889852007-06-14 10:01:04 +08002292 { PCI_DEVICE_ID_INTEL_82965G_HB, PCI_DEVICE_ID_INTEL_82965G_IG, 0, "965G",
Wang Zhenyu47d46372007-06-21 13:43:18 +08002293 NULL, &intel_i965_driver },
Zhenyu Wangdde47872007-07-26 09:18:09 +08002294 { PCI_DEVICE_ID_INTEL_82965GM_HB, PCI_DEVICE_ID_INTEL_82965GM_IG, 0, "965GM",
Wang Zhenyu47d46372007-06-21 13:43:18 +08002295 NULL, &intel_i965_driver },
Zhenyu Wangdde47872007-07-26 09:18:09 +08002296 { PCI_DEVICE_ID_INTEL_82965GME_HB, PCI_DEVICE_ID_INTEL_82965GME_IG, 0, "965GME/GLE",
Wang Zhenyu47d46372007-06-21 13:43:18 +08002297 NULL, &intel_i965_driver },
Wang Zhenyu88889852007-06-14 10:01:04 +08002298 { PCI_DEVICE_ID_INTEL_7505_0, 0, 0, "E7505", &intel_7505_driver, NULL },
2299 { PCI_DEVICE_ID_INTEL_7205_0, 0, 0, "E7205", &intel_7505_driver, NULL },
2300 { PCI_DEVICE_ID_INTEL_G33_HB, PCI_DEVICE_ID_INTEL_G33_IG, 0, "G33",
Wang Zhenyu47d46372007-06-21 13:43:18 +08002301 NULL, &intel_g33_driver },
Wang Zhenyu88889852007-06-14 10:01:04 +08002302 { PCI_DEVICE_ID_INTEL_Q35_HB, PCI_DEVICE_ID_INTEL_Q35_IG, 0, "Q35",
Wang Zhenyu47d46372007-06-21 13:43:18 +08002303 NULL, &intel_g33_driver },
Wang Zhenyu88889852007-06-14 10:01:04 +08002304 { PCI_DEVICE_ID_INTEL_Q33_HB, PCI_DEVICE_ID_INTEL_Q33_IG, 0, "Q33",
Wang Zhenyu47d46372007-06-21 13:43:18 +08002305 NULL, &intel_g33_driver },
Zhenyu Wangaf86d4b2010-02-10 10:39:33 +08002306 { PCI_DEVICE_ID_INTEL_PINEVIEW_M_HB, PCI_DEVICE_ID_INTEL_PINEVIEW_M_IG, 0, "GMA3150",
Shaohua Li21778322009-02-23 15:19:16 +08002307 NULL, &intel_g33_driver },
Zhenyu Wangaf86d4b2010-02-10 10:39:33 +08002308 { PCI_DEVICE_ID_INTEL_PINEVIEW_HB, PCI_DEVICE_ID_INTEL_PINEVIEW_IG, 0, "GMA3150",
Shaohua Li21778322009-02-23 15:19:16 +08002309 NULL, &intel_g33_driver },
Zhenyu Wang99d32bd2008-07-30 12:26:50 -07002310 { PCI_DEVICE_ID_INTEL_GM45_HB, PCI_DEVICE_ID_INTEL_GM45_IG, 0,
Adam Jackson107f5172009-12-03 17:14:41 -05002311 "GM45", NULL, &intel_i965_driver },
2312 { PCI_DEVICE_ID_INTEL_EAGLELAKE_HB, PCI_DEVICE_ID_INTEL_EAGLELAKE_IG, 0,
2313 "Eaglelake", NULL, &intel_i965_driver },
Zhenyu Wang25ce77a2008-06-19 14:17:58 +10002314 { PCI_DEVICE_ID_INTEL_Q45_HB, PCI_DEVICE_ID_INTEL_Q45_IG, 0,
2315 "Q45/Q43", NULL, &intel_i965_driver },
2316 { PCI_DEVICE_ID_INTEL_G45_HB, PCI_DEVICE_ID_INTEL_G45_IG, 0,
2317 "G45/G43", NULL, &intel_i965_driver },
Fabian Henze38d8a952009-09-08 00:59:58 +08002318 { PCI_DEVICE_ID_INTEL_B43_HB, PCI_DEVICE_ID_INTEL_B43_IG, 0,
2319 "B43", NULL, &intel_i965_driver },
Zhenyu Wanga50ccc62008-11-17 14:39:00 +08002320 { PCI_DEVICE_ID_INTEL_G41_HB, PCI_DEVICE_ID_INTEL_G41_IG, 0,
2321 "G41", NULL, &intel_i965_driver },
Adam Jackson107f5172009-12-03 17:14:41 -05002322 { PCI_DEVICE_ID_INTEL_IRONLAKE_D_HB, PCI_DEVICE_ID_INTEL_IRONLAKE_D_IG, 0,
Zhenyu Wangaf86d4b2010-02-10 10:39:33 +08002323 "HD Graphics", NULL, &intel_i965_driver },
Adam Jackson107f5172009-12-03 17:14:41 -05002324 { PCI_DEVICE_ID_INTEL_IRONLAKE_M_HB, PCI_DEVICE_ID_INTEL_IRONLAKE_M_IG, 0,
Zhenyu Wangaf86d4b2010-02-10 10:39:33 +08002325 "HD Graphics", NULL, &intel_i965_driver },
Adam Jackson107f5172009-12-03 17:14:41 -05002326 { PCI_DEVICE_ID_INTEL_IRONLAKE_MA_HB, PCI_DEVICE_ID_INTEL_IRONLAKE_M_IG, 0,
Zhenyu Wangaf86d4b2010-02-10 10:39:33 +08002327 "HD Graphics", NULL, &intel_i965_driver },
Dave Airlie3ff99162009-12-08 14:03:47 +10002328 { PCI_DEVICE_ID_INTEL_IRONLAKE_MC2_HB, PCI_DEVICE_ID_INTEL_IRONLAKE_M_IG, 0,
Zhenyu Wangaf86d4b2010-02-10 10:39:33 +08002329 "HD Graphics", NULL, &intel_i965_driver },
Eric Anholt1089e302009-10-22 16:10:52 -07002330 { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_HB, PCI_DEVICE_ID_INTEL_SANDYBRIDGE_IG, 0,
2331 "Sandybridge", NULL, &intel_i965_driver },
Eric Anholt954bce52010-01-07 16:21:46 -08002332 { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_HB, PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_IG, 0,
2333 "Sandybridge", NULL, &intel_i965_driver },
Wang Zhenyu88889852007-06-14 10:01:04 +08002334 { 0, 0, 0, NULL, NULL, NULL }
Wang Zhenyu9614ece2007-05-30 09:45:58 +08002335};
2336
Linus Torvalds1da177e2005-04-16 15:20:36 -07002337static int __devinit agp_intel_probe(struct pci_dev *pdev,
2338 const struct pci_device_id *ent)
2339{
2340 struct agp_bridge_data *bridge;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002341 u8 cap_ptr = 0;
2342 struct resource *r;
Zhenyu Wang1f7a6e32010-02-23 14:05:24 +08002343 int i, err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002344
2345 cap_ptr = pci_find_capability(pdev, PCI_CAP_ID_AGP);
2346
2347 bridge = agp_alloc_bridge();
2348 if (!bridge)
2349 return -ENOMEM;
2350
Wang Zhenyu9614ece2007-05-30 09:45:58 +08002351 for (i = 0; intel_agp_chipsets[i].name != NULL; i++) {
2352 /* In case that multiple models of gfx chip may
2353 stand on same host bridge type, this can be
2354 sure we detect the right IGD. */
Wang Zhenyu88889852007-06-14 10:01:04 +08002355 if (pdev->device == intel_agp_chipsets[i].chip_id) {
2356 if ((intel_agp_chipsets[i].gmch_chip_id != 0) &&
2357 find_gmch(intel_agp_chipsets[i].gmch_chip_id)) {
2358 bridge->driver =
2359 intel_agp_chipsets[i].gmch_driver;
2360 break;
2361 } else if (intel_agp_chipsets[i].multi_gmch_chip) {
2362 continue;
2363 } else {
2364 bridge->driver = intel_agp_chipsets[i].driver;
2365 break;
2366 }
2367 }
Wang Zhenyu9614ece2007-05-30 09:45:58 +08002368 }
2369
2370 if (intel_agp_chipsets[i].name == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002371 if (cap_ptr)
Bjorn Helgaase3cf6952008-07-30 12:26:51 -07002372 dev_warn(&pdev->dev, "unsupported Intel chipset [%04x/%04x]\n",
2373 pdev->vendor, pdev->device);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002374 agp_put_bridge(bridge);
2375 return -ENODEV;
Wang Zhenyu9614ece2007-05-30 09:45:58 +08002376 }
2377
Wang Zhenyu9614ece2007-05-30 09:45:58 +08002378 if (bridge->driver == NULL) {
Wang Zhenyu47d46372007-06-21 13:43:18 +08002379 /* bridge has no AGP and no IGD detected */
2380 if (cap_ptr)
Bjorn Helgaase3cf6952008-07-30 12:26:51 -07002381 dev_warn(&pdev->dev, "can't find bridge device (chip_id: %04x)\n",
2382 intel_agp_chipsets[i].gmch_chip_id);
Wang Zhenyu9614ece2007-05-30 09:45:58 +08002383 agp_put_bridge(bridge);
2384 return -ENODEV;
Dave Airlief011ae72008-01-25 11:23:04 +10002385 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002386
2387 bridge->dev = pdev;
2388 bridge->capndx = cap_ptr;
Wang Zhenyuc4ca8812007-05-30 09:40:46 +08002389 bridge->dev_private_data = &intel_private;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002390
Bjorn Helgaase3cf6952008-07-30 12:26:51 -07002391 dev_info(&pdev->dev, "Intel %s Chipset\n", intel_agp_chipsets[i].name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002392
2393 /*
2394 * The following fixes the case where the BIOS has "forgotten" to
2395 * provide an address range for the GART.
2396 * 20030610 - hamish@zot.org
2397 */
2398 r = &pdev->resource[0];
2399 if (!r->start && r->end) {
Dave Jones6a92a4e2006-02-28 00:54:25 -05002400 if (pci_assign_resource(pdev, 0)) {
Bjorn Helgaase3cf6952008-07-30 12:26:51 -07002401 dev_err(&pdev->dev, "can't assign resource 0\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002402 agp_put_bridge(bridge);
2403 return -ENODEV;
2404 }
2405 }
2406
2407 /*
2408 * If the device has not been properly setup, the following will catch
2409 * the problem and should stop the system from crashing.
2410 * 20030610 - hamish@zot.org
2411 */
2412 if (pci_enable_device(pdev)) {
Bjorn Helgaase3cf6952008-07-30 12:26:51 -07002413 dev_err(&pdev->dev, "can't enable PCI device\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002414 agp_put_bridge(bridge);
2415 return -ENODEV;
2416 }
2417
2418 /* Fill in the mode register */
2419 if (cap_ptr) {
2420 pci_read_config_dword(pdev,
2421 bridge->capndx+PCI_AGP_STATUS,
2422 &bridge->mode);
2423 }
2424
Zhenyu Wang9b974cc2010-01-05 11:25:06 +08002425 if (bridge->driver->mask_memory == intel_i965_mask_memory) {
David Woodhouseec402ba2009-11-18 10:22:46 +00002426 if (pci_set_dma_mask(intel_private.pcidev, DMA_BIT_MASK(36)))
2427 dev_err(&intel_private.pcidev->dev,
2428 "set gfx device dma mask 36bit failed!\n");
Zhenyu Wang9b974cc2010-01-05 11:25:06 +08002429 else
2430 pci_set_consistent_dma_mask(intel_private.pcidev,
2431 DMA_BIT_MASK(36));
2432 }
David Woodhouseec402ba2009-11-18 10:22:46 +00002433
Linus Torvalds1da177e2005-04-16 15:20:36 -07002434 pci_set_drvdata(pdev, bridge);
Zhenyu Wang1f7a6e32010-02-23 14:05:24 +08002435 err = agp_add_bridge(bridge);
2436 if (!err)
2437 intel_agp_enabled = 1;
2438 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002439}
2440
2441static void __devexit agp_intel_remove(struct pci_dev *pdev)
2442{
2443 struct agp_bridge_data *bridge = pci_get_drvdata(pdev);
2444
2445 agp_remove_bridge(bridge);
2446
Wang Zhenyuc4ca8812007-05-30 09:40:46 +08002447 if (intel_private.pcidev)
2448 pci_dev_put(intel_private.pcidev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002449
2450 agp_put_bridge(bridge);
2451}
2452
Alexey Dobriyan85be7d62006-08-12 02:02:02 +04002453#ifdef CONFIG_PM
Linus Torvalds1da177e2005-04-16 15:20:36 -07002454static int agp_intel_resume(struct pci_dev *pdev)
2455{
2456 struct agp_bridge_data *bridge = pci_get_drvdata(pdev);
Keith Packarda8c84df2008-07-31 15:48:07 +10002457 int ret_val;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002458
Linus Torvalds1da177e2005-04-16 15:20:36 -07002459 if (bridge->driver == &intel_generic_driver)
2460 intel_configure();
2461 else if (bridge->driver == &intel_850_driver)
2462 intel_850_configure();
2463 else if (bridge->driver == &intel_845_driver)
2464 intel_845_configure();
2465 else if (bridge->driver == &intel_830mp_driver)
2466 intel_830mp_configure();
2467 else if (bridge->driver == &intel_915_driver)
2468 intel_i915_configure();
2469 else if (bridge->driver == &intel_830_driver)
2470 intel_i830_configure();
2471 else if (bridge->driver == &intel_810_driver)
2472 intel_i810_configure();
Dave Jones08da3f42006-09-10 21:09:26 -04002473 else if (bridge->driver == &intel_i965_driver)
2474 intel_i915_configure();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002475
Keith Packarda8c84df2008-07-31 15:48:07 +10002476 ret_val = agp_rebind_memory();
2477 if (ret_val != 0)
2478 return ret_val;
2479
Linus Torvalds1da177e2005-04-16 15:20:36 -07002480 return 0;
2481}
Alexey Dobriyan85be7d62006-08-12 02:02:02 +04002482#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07002483
2484static struct pci_device_id agp_intel_pci_table[] = {
2485#define ID(x) \
2486 { \
2487 .class = (PCI_CLASS_BRIDGE_HOST << 8), \
2488 .class_mask = ~0, \
2489 .vendor = PCI_VENDOR_ID_INTEL, \
2490 .device = x, \
2491 .subvendor = PCI_ANY_ID, \
2492 .subdevice = PCI_ANY_ID, \
2493 }
2494 ID(PCI_DEVICE_ID_INTEL_82443LX_0),
2495 ID(PCI_DEVICE_ID_INTEL_82443BX_0),
2496 ID(PCI_DEVICE_ID_INTEL_82443GX_0),
2497 ID(PCI_DEVICE_ID_INTEL_82810_MC1),
2498 ID(PCI_DEVICE_ID_INTEL_82810_MC3),
2499 ID(PCI_DEVICE_ID_INTEL_82810E_MC),
2500 ID(PCI_DEVICE_ID_INTEL_82815_MC),
2501 ID(PCI_DEVICE_ID_INTEL_82820_HB),
2502 ID(PCI_DEVICE_ID_INTEL_82820_UP_HB),
2503 ID(PCI_DEVICE_ID_INTEL_82830_HB),
2504 ID(PCI_DEVICE_ID_INTEL_82840_HB),
2505 ID(PCI_DEVICE_ID_INTEL_82845_HB),
2506 ID(PCI_DEVICE_ID_INTEL_82845G_HB),
2507 ID(PCI_DEVICE_ID_INTEL_82850_HB),
Stefan Husemann347486b2009-04-13 14:40:10 -07002508 ID(PCI_DEVICE_ID_INTEL_82854_HB),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002509 ID(PCI_DEVICE_ID_INTEL_82855PM_HB),
2510 ID(PCI_DEVICE_ID_INTEL_82855GM_HB),
2511 ID(PCI_DEVICE_ID_INTEL_82860_HB),
2512 ID(PCI_DEVICE_ID_INTEL_82865_HB),
2513 ID(PCI_DEVICE_ID_INTEL_82875_HB),
2514 ID(PCI_DEVICE_ID_INTEL_7505_0),
2515 ID(PCI_DEVICE_ID_INTEL_7205_0),
Carlos Martíne914a362008-01-24 10:34:09 +10002516 ID(PCI_DEVICE_ID_INTEL_E7221_HB),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002517 ID(PCI_DEVICE_ID_INTEL_82915G_HB),
2518 ID(PCI_DEVICE_ID_INTEL_82915GM_HB),
Alan Hourihaned0de98f2005-05-31 19:50:49 +01002519 ID(PCI_DEVICE_ID_INTEL_82945G_HB),
Alan Hourihane3b0e8ea2006-01-19 14:08:40 +00002520 ID(PCI_DEVICE_ID_INTEL_82945GM_HB),
Zhenyu Wangdde47872007-07-26 09:18:09 +08002521 ID(PCI_DEVICE_ID_INTEL_82945GME_HB),
Adam Jackson107f5172009-12-03 17:14:41 -05002522 ID(PCI_DEVICE_ID_INTEL_PINEVIEW_M_HB),
2523 ID(PCI_DEVICE_ID_INTEL_PINEVIEW_HB),
Eric Anholt65c25aa2006-09-06 11:57:18 -04002524 ID(PCI_DEVICE_ID_INTEL_82946GZ_HB),
Zhenyu Wang9119f852008-01-23 15:49:26 +10002525 ID(PCI_DEVICE_ID_INTEL_82G35_HB),
Eric Anholt65c25aa2006-09-06 11:57:18 -04002526 ID(PCI_DEVICE_ID_INTEL_82965Q_HB),
2527 ID(PCI_DEVICE_ID_INTEL_82965G_HB),
Wang Zhenyu4598af32007-04-09 08:51:36 +08002528 ID(PCI_DEVICE_ID_INTEL_82965GM_HB),
Zhenyu Wangdde47872007-07-26 09:18:09 +08002529 ID(PCI_DEVICE_ID_INTEL_82965GME_HB),
Wang Zhenyu874808c62007-06-06 11:16:25 +08002530 ID(PCI_DEVICE_ID_INTEL_G33_HB),
2531 ID(PCI_DEVICE_ID_INTEL_Q35_HB),
2532 ID(PCI_DEVICE_ID_INTEL_Q33_HB),
Zhenyu Wang99d32bd2008-07-30 12:26:50 -07002533 ID(PCI_DEVICE_ID_INTEL_GM45_HB),
Adam Jackson107f5172009-12-03 17:14:41 -05002534 ID(PCI_DEVICE_ID_INTEL_EAGLELAKE_HB),
Zhenyu Wang25ce77a2008-06-19 14:17:58 +10002535 ID(PCI_DEVICE_ID_INTEL_Q45_HB),
2536 ID(PCI_DEVICE_ID_INTEL_G45_HB),
Zhenyu Wanga50ccc62008-11-17 14:39:00 +08002537 ID(PCI_DEVICE_ID_INTEL_G41_HB),
Fabian Henze38d8a952009-09-08 00:59:58 +08002538 ID(PCI_DEVICE_ID_INTEL_B43_HB),
Adam Jackson107f5172009-12-03 17:14:41 -05002539 ID(PCI_DEVICE_ID_INTEL_IRONLAKE_D_HB),
2540 ID(PCI_DEVICE_ID_INTEL_IRONLAKE_M_HB),
2541 ID(PCI_DEVICE_ID_INTEL_IRONLAKE_MA_HB),
Dave Airlie3ff99162009-12-08 14:03:47 +10002542 ID(PCI_DEVICE_ID_INTEL_IRONLAKE_MC2_HB),
Eric Anholt1089e302009-10-22 16:10:52 -07002543 ID(PCI_DEVICE_ID_INTEL_SANDYBRIDGE_HB),
Eric Anholt954bce52010-01-07 16:21:46 -08002544 ID(PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_HB),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002545 { }
2546};
2547
2548MODULE_DEVICE_TABLE(pci, agp_intel_pci_table);
2549
2550static struct pci_driver agp_intel_pci_driver = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002551 .name = "agpgart-intel",
2552 .id_table = agp_intel_pci_table,
2553 .probe = agp_intel_probe,
2554 .remove = __devexit_p(agp_intel_remove),
Alexey Dobriyan85be7d62006-08-12 02:02:02 +04002555#ifdef CONFIG_PM
Linus Torvalds1da177e2005-04-16 15:20:36 -07002556 .resume = agp_intel_resume,
Alexey Dobriyan85be7d62006-08-12 02:02:02 +04002557#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07002558};
2559
2560static int __init agp_intel_init(void)
2561{
2562 if (agp_off)
2563 return -EINVAL;
2564 return pci_register_driver(&agp_intel_pci_driver);
2565}
2566
2567static void __exit agp_intel_cleanup(void)
2568{
2569 pci_unregister_driver(&agp_intel_pci_driver);
2570}
2571
2572module_init(agp_intel_init);
2573module_exit(agp_intel_cleanup);
2574
Dave Jonesf4432c52008-10-20 13:31:45 -04002575MODULE_AUTHOR("Dave Jones <davej@redhat.com>");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002576MODULE_LICENSE("GPL and additional rights");