blob: 33b4853b1353b65639385c2543ca85f5d02c428c [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>
11#include "agp.h"
12
Zhenyu Wang17661682009-07-27 12:59:57 +010013/*
14 * If we have Intel graphics, we're not going to have anything other than
15 * an Intel IOMMU. So make the correct use of the PCI DMA API contingent
16 * on the Intel IOMMU support (CONFIG_DMAR).
17 * Only newer chipsets need to bother with this, of course.
18 */
19#ifdef CONFIG_DMAR
20#define USE_PCI_DMA_API 1
21#endif
22
Carlos Martíne914a362008-01-24 10:34:09 +100023#define PCI_DEVICE_ID_INTEL_E7221_HB 0x2588
24#define PCI_DEVICE_ID_INTEL_E7221_IG 0x258a
Eric Anholt65c25aa2006-09-06 11:57:18 -040025#define PCI_DEVICE_ID_INTEL_82946GZ_HB 0x2970
26#define PCI_DEVICE_ID_INTEL_82946GZ_IG 0x2972
Zhenyu Wang9119f852008-01-23 15:49:26 +100027#define PCI_DEVICE_ID_INTEL_82G35_HB 0x2980
28#define PCI_DEVICE_ID_INTEL_82G35_IG 0x2982
Eric Anholt65c25aa2006-09-06 11:57:18 -040029#define PCI_DEVICE_ID_INTEL_82965Q_HB 0x2990
30#define PCI_DEVICE_ID_INTEL_82965Q_IG 0x2992
31#define PCI_DEVICE_ID_INTEL_82965G_HB 0x29A0
32#define PCI_DEVICE_ID_INTEL_82965G_IG 0x29A2
Wang Zhenyu4598af32007-04-09 08:51:36 +080033#define PCI_DEVICE_ID_INTEL_82965GM_HB 0x2A00
34#define PCI_DEVICE_ID_INTEL_82965GM_IG 0x2A02
Zhenyu Wangdde47872007-07-26 09:18:09 +080035#define PCI_DEVICE_ID_INTEL_82965GME_HB 0x2A10
Wang Zhenyuc8eebfd2007-05-31 11:34:06 +080036#define PCI_DEVICE_ID_INTEL_82965GME_IG 0x2A12
Zhenyu Wangdde47872007-07-26 09:18:09 +080037#define PCI_DEVICE_ID_INTEL_82945GME_HB 0x27AC
Wang Zhenyudf80b142007-05-31 11:51:12 +080038#define PCI_DEVICE_ID_INTEL_82945GME_IG 0x27AE
Adam Jackson107f5172009-12-03 17:14:41 -050039#define PCI_DEVICE_ID_INTEL_PINEVIEW_M_HB 0xA010
40#define PCI_DEVICE_ID_INTEL_PINEVIEW_M_IG 0xA011
41#define PCI_DEVICE_ID_INTEL_PINEVIEW_HB 0xA000
42#define PCI_DEVICE_ID_INTEL_PINEVIEW_IG 0xA001
Wang Zhenyu874808c62007-06-06 11:16:25 +080043#define PCI_DEVICE_ID_INTEL_G33_HB 0x29C0
44#define PCI_DEVICE_ID_INTEL_G33_IG 0x29C2
45#define PCI_DEVICE_ID_INTEL_Q35_HB 0x29B0
46#define PCI_DEVICE_ID_INTEL_Q35_IG 0x29B2
47#define PCI_DEVICE_ID_INTEL_Q33_HB 0x29D0
48#define PCI_DEVICE_ID_INTEL_Q33_IG 0x29D2
Fabian Henze38d8a952009-09-08 00:59:58 +080049#define PCI_DEVICE_ID_INTEL_B43_HB 0x2E40
50#define PCI_DEVICE_ID_INTEL_B43_IG 0x2E42
Zhenyu Wang99d32bd2008-07-30 12:26:50 -070051#define PCI_DEVICE_ID_INTEL_GM45_HB 0x2A40
52#define PCI_DEVICE_ID_INTEL_GM45_IG 0x2A42
Adam Jackson107f5172009-12-03 17:14:41 -050053#define PCI_DEVICE_ID_INTEL_EAGLELAKE_HB 0x2E00
54#define PCI_DEVICE_ID_INTEL_EAGLELAKE_IG 0x2E02
Zhenyu Wang25ce77a2008-06-19 14:17:58 +100055#define PCI_DEVICE_ID_INTEL_Q45_HB 0x2E10
56#define PCI_DEVICE_ID_INTEL_Q45_IG 0x2E12
57#define PCI_DEVICE_ID_INTEL_G45_HB 0x2E20
58#define PCI_DEVICE_ID_INTEL_G45_IG 0x2E22
Zhenyu Wanga50ccc62008-11-17 14:39:00 +080059#define PCI_DEVICE_ID_INTEL_G41_HB 0x2E30
60#define PCI_DEVICE_ID_INTEL_G41_IG 0x2E32
Adam Jackson107f5172009-12-03 17:14:41 -050061#define PCI_DEVICE_ID_INTEL_IRONLAKE_D_HB 0x0040
62#define PCI_DEVICE_ID_INTEL_IRONLAKE_D_IG 0x0042
63#define PCI_DEVICE_ID_INTEL_IRONLAKE_M_HB 0x0044
64#define PCI_DEVICE_ID_INTEL_IRONLAKE_MA_HB 0x0062
65#define PCI_DEVICE_ID_INTEL_IRONLAKE_M_IG 0x0046
Eric Anholt65c25aa2006-09-06 11:57:18 -040066
Dave Airlief011ae72008-01-25 11:23:04 +100067/* cover 915 and 945 variants */
68#define IS_I915 (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_E7221_HB || \
69 agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82915G_HB || \
70 agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82915GM_HB || \
71 agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945G_HB || \
72 agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945GM_HB || \
73 agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945GME_HB)
74
Eric Anholt65c25aa2006-09-06 11:57:18 -040075#define IS_I965 (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82946GZ_HB || \
Dave Airlief011ae72008-01-25 11:23:04 +100076 agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82G35_HB || \
77 agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82965Q_HB || \
78 agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82965G_HB || \
79 agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82965GM_HB || \
Eric Anholt82e14a62008-10-14 11:28:58 -070080 agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82965GME_HB)
Eric Anholt65c25aa2006-09-06 11:57:18 -040081
Wang Zhenyu874808c62007-06-06 11:16:25 +080082#define IS_G33 (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_G33_HB || \
83 agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_Q35_HB || \
Shaohua Li21778322009-02-23 15:19:16 +080084 agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_Q33_HB || \
Adam Jackson107f5172009-12-03 17:14:41 -050085 agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_PINEVIEW_M_HB || \
86 agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_PINEVIEW_HB)
Shaohua Li21778322009-02-23 15:19:16 +080087
Adam Jackson107f5172009-12-03 17:14:41 -050088#define IS_PINEVIEW (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_PINEVIEW_M_HB || \
89 agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_PINEVIEW_HB)
Eric Anholt65c25aa2006-09-06 11:57:18 -040090
Adam Jackson107f5172009-12-03 17:14:41 -050091#define IS_G4X (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_EAGLELAKE_HB || \
Zhenyu Wang25ce77a2008-06-19 14:17:58 +100092 agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_Q45_HB || \
Eric Anholt82e14a62008-10-14 11:28:58 -070093 agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_G45_HB || \
Zhenyu Wanga50ccc62008-11-17 14:39:00 +080094 agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_GM45_HB || \
Zhenyu Wang32cb0552009-06-05 15:38:36 +080095 agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_G41_HB || \
Fabian Henze38d8a952009-09-08 00:59:58 +080096 agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_B43_HB || \
Adam Jackson107f5172009-12-03 17:14:41 -050097 agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_IRONLAKE_D_HB || \
98 agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_IRONLAKE_M_HB || \
99 agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_IRONLAKE_MA_HB)
Zhenyu Wang25ce77a2008-06-19 14:17:58 +1000100
Thomas Hellstroma030ce42007-01-23 10:33:43 +0100101extern int agp_memory_reserved;
102
103
Linus Torvalds1da177e2005-04-16 15:20:36 -0700104/* Intel 815 register */
105#define INTEL_815_APCONT 0x51
106#define INTEL_815_ATTBASE_MASK ~0x1FFFFFFF
107
108/* Intel i820 registers */
109#define INTEL_I820_RDCR 0x51
110#define INTEL_I820_ERRSTS 0xc8
111
112/* Intel i840 registers */
113#define INTEL_I840_MCHCFG 0x50
114#define INTEL_I840_ERRSTS 0xc8
115
116/* Intel i850 registers */
117#define INTEL_I850_MCHCFG 0x50
118#define INTEL_I850_ERRSTS 0xc8
119
120/* intel 915G registers */
121#define I915_GMADDR 0x18
122#define I915_MMADDR 0x10
123#define I915_PTEADDR 0x1C
124#define I915_GMCH_GMS_STOLEN_48M (0x6 << 4)
125#define I915_GMCH_GMS_STOLEN_64M (0x7 << 4)
Zhenyu Wang25ce77a2008-06-19 14:17:58 +1000126#define G33_GMCH_GMS_STOLEN_128M (0x8 << 4)
127#define G33_GMCH_GMS_STOLEN_256M (0x9 << 4)
128#define INTEL_GMCH_GMS_STOLEN_96M (0xa << 4)
129#define INTEL_GMCH_GMS_STOLEN_160M (0xb << 4)
130#define INTEL_GMCH_GMS_STOLEN_224M (0xc << 4)
131#define INTEL_GMCH_GMS_STOLEN_352M (0xd << 4)
132
Dave Airlie6c00a612007-10-29 18:06:10 +1000133#define I915_IFPADDR 0x60
Linus Torvalds1da177e2005-04-16 15:20:36 -0700134
Eric Anholt65c25aa2006-09-06 11:57:18 -0400135/* Intel 965G registers */
136#define I965_MSAC 0x62
Dave Airlie6c00a612007-10-29 18:06:10 +1000137#define I965_IFPADDR 0x70
Linus Torvalds1da177e2005-04-16 15:20:36 -0700138
139/* Intel 7505 registers */
140#define INTEL_I7505_APSIZE 0x74
141#define INTEL_I7505_NCAPID 0x60
142#define INTEL_I7505_NISTAT 0x6c
143#define INTEL_I7505_ATTBASE 0x78
144#define INTEL_I7505_ERRSTS 0x42
145#define INTEL_I7505_AGPCTRL 0x70
146#define INTEL_I7505_MCHCFG 0x50
147
Dave Jonese5524f32007-02-22 18:41:28 -0500148static const struct aper_size_info_fixed intel_i810_sizes[] =
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149{
150 {64, 16384, 4},
151 /* The 32M mode still requires a 64k gatt */
152 {32, 8192, 4}
153};
154
155#define AGP_DCACHE_MEMORY 1
156#define AGP_PHYS_MEMORY 2
Thomas Hellstroma030ce42007-01-23 10:33:43 +0100157#define INTEL_AGP_CACHED_MEMORY 3
Linus Torvalds1da177e2005-04-16 15:20:36 -0700158
159static struct gatt_mask intel_i810_masks[] =
160{
161 {.mask = I810_PTE_VALID, .type = 0},
162 {.mask = (I810_PTE_VALID | I810_PTE_LOCAL), .type = AGP_DCACHE_MEMORY},
Thomas Hellstroma030ce42007-01-23 10:33:43 +0100163 {.mask = I810_PTE_VALID, .type = 0},
164 {.mask = I810_PTE_VALID | I830_PTE_SYSTEM_CACHED,
165 .type = INTEL_AGP_CACHED_MEMORY}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700166};
167
Wang Zhenyuc4ca8812007-05-30 09:40:46 +0800168static struct _intel_private {
169 struct pci_dev *pcidev; /* device one */
170 u8 __iomem *registers;
171 u32 __iomem *gtt; /* I915G */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172 int num_dcache_entries;
Wang Zhenyuc4ca8812007-05-30 09:40:46 +0800173 /* gtt_entries is the number of gtt entries that are already mapped
174 * to stolen memory. Stolen memory is larger than the memory mapped
175 * through gtt_entries, as it includes some reserved space for the BIOS
176 * popup and for the GTT.
177 */
178 int gtt_entries; /* i830+ */
David Woodhousefc619012009-12-02 11:00:05 +0000179 int gtt_total_size;
Dave Airlie2162e6a2007-11-21 16:36:31 +1000180 union {
181 void __iomem *i9xx_flush_page;
182 void *i8xx_flush_page;
183 };
184 struct page *i8xx_page;
Dave Airlie6c00a612007-10-29 18:06:10 +1000185 struct resource ifp_resource;
Dave Airlie4d64dd92008-01-23 15:34:29 +1000186 int resource_valid;
Wang Zhenyuc4ca8812007-05-30 09:40:46 +0800187} intel_private;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700188
Zhenyu Wang17661682009-07-27 12:59:57 +0100189#ifdef USE_PCI_DMA_API
David Woodhousec2980d82009-07-29 08:39:26 +0100190static int intel_agp_map_page(struct page *page, dma_addr_t *ret)
Zhenyu Wang17661682009-07-27 12:59:57 +0100191{
David Woodhousec2980d82009-07-29 08:39:26 +0100192 *ret = pci_map_page(intel_private.pcidev, page, 0,
193 PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
Zhenyu Wang17661682009-07-27 12:59:57 +0100194 if (pci_dma_mapping_error(intel_private.pcidev, *ret))
195 return -EINVAL;
196 return 0;
197}
198
David Woodhousec2980d82009-07-29 08:39:26 +0100199static void intel_agp_unmap_page(struct page *page, dma_addr_t dma)
Zhenyu Wang17661682009-07-27 12:59:57 +0100200{
David Woodhousec2980d82009-07-29 08:39:26 +0100201 pci_unmap_page(intel_private.pcidev, dma,
202 PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
Zhenyu Wang17661682009-07-27 12:59:57 +0100203}
204
David Woodhouse91b8e302009-07-29 08:49:12 +0100205static void intel_agp_free_sglist(struct agp_memory *mem)
206{
David Woodhousef6927752009-07-29 09:28:45 +0100207 struct sg_table st;
David Woodhouse91b8e302009-07-29 08:49:12 +0100208
David Woodhousef6927752009-07-29 09:28:45 +0100209 st.sgl = mem->sg_list;
210 st.orig_nents = st.nents = mem->page_count;
211
212 sg_free_table(&st);
213
David Woodhouse91b8e302009-07-29 08:49:12 +0100214 mem->sg_list = NULL;
215 mem->num_sg = 0;
216}
217
Zhenyu Wang17661682009-07-27 12:59:57 +0100218static int intel_agp_map_memory(struct agp_memory *mem)
219{
David Woodhousef6927752009-07-29 09:28:45 +0100220 struct sg_table st;
Zhenyu Wang17661682009-07-27 12:59:57 +0100221 struct scatterlist *sg;
222 int i;
223
224 DBG("try mapping %lu pages\n", (unsigned long)mem->page_count);
225
David Woodhousef6927752009-07-29 09:28:45 +0100226 if (sg_alloc_table(&st, mem->page_count, GFP_KERNEL))
Zhenyu Wang17661682009-07-27 12:59:57 +0100227 return -ENOMEM;
Zhenyu Wang17661682009-07-27 12:59:57 +0100228
David Woodhousef6927752009-07-29 09:28:45 +0100229 mem->sg_list = sg = st.sgl;
230
Zhenyu Wang17661682009-07-27 12:59:57 +0100231 for (i = 0 ; i < mem->page_count; i++, sg = sg_next(sg))
232 sg_set_page(sg, mem->pages[i], PAGE_SIZE, 0);
233
234 mem->num_sg = pci_map_sg(intel_private.pcidev, mem->sg_list,
235 mem->page_count, PCI_DMA_BIDIRECTIONAL);
David Woodhouse91b8e302009-07-29 08:49:12 +0100236 if (unlikely(!mem->num_sg)) {
237 intel_agp_free_sglist(mem);
Zhenyu Wang17661682009-07-27 12:59:57 +0100238 return -ENOMEM;
239 }
240 return 0;
241}
242
243static void intel_agp_unmap_memory(struct agp_memory *mem)
244{
245 DBG("try unmapping %lu pages\n", (unsigned long)mem->page_count);
246
247 pci_unmap_sg(intel_private.pcidev, mem->sg_list,
248 mem->page_count, PCI_DMA_BIDIRECTIONAL);
David Woodhouse91b8e302009-07-29 08:49:12 +0100249 intel_agp_free_sglist(mem);
Zhenyu Wang17661682009-07-27 12:59:57 +0100250}
251
252static void intel_agp_insert_sg_entries(struct agp_memory *mem,
253 off_t pg_start, int mask_type)
254{
255 struct scatterlist *sg;
256 int i, j;
257
258 j = pg_start;
259
260 WARN_ON(!mem->num_sg);
261
262 if (mem->num_sg == mem->page_count) {
263 for_each_sg(mem->sg_list, sg, mem->page_count, i) {
264 writel(agp_bridge->driver->mask_memory(agp_bridge,
265 sg_dma_address(sg), mask_type),
266 intel_private.gtt+j);
267 j++;
268 }
269 } else {
270 /* sg may merge pages, but we have to seperate
271 * per-page addr for GTT */
272 unsigned int len, m;
273
274 for_each_sg(mem->sg_list, sg, mem->num_sg, i) {
275 len = sg_dma_len(sg) / PAGE_SIZE;
276 for (m = 0; m < len; m++) {
277 writel(agp_bridge->driver->mask_memory(agp_bridge,
278 sg_dma_address(sg) + m * PAGE_SIZE,
279 mask_type),
280 intel_private.gtt+j);
281 j++;
282 }
283 }
284 }
285 readl(intel_private.gtt+j-1);
286}
287
288#else
289
290static void intel_agp_insert_sg_entries(struct agp_memory *mem,
291 off_t pg_start, int mask_type)
292{
293 int i, j;
294
295 for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
296 writel(agp_bridge->driver->mask_memory(agp_bridge,
David Woodhouse6a122352009-07-29 10:25:58 +0100297 page_to_phys(mem->pages[i]), mask_type),
Zhenyu Wang17661682009-07-27 12:59:57 +0100298 intel_private.gtt+j);
299 }
300
301 readl(intel_private.gtt+j-1);
302}
303
304#endif
305
Linus Torvalds1da177e2005-04-16 15:20:36 -0700306static int intel_i810_fetch_size(void)
307{
308 u32 smram_miscc;
309 struct aper_size_info_fixed *values;
310
311 pci_read_config_dword(agp_bridge->dev, I810_SMRAM_MISCC, &smram_miscc);
312 values = A_SIZE_FIX(agp_bridge->driver->aperture_sizes);
313
314 if ((smram_miscc & I810_GMS) == I810_GMS_DISABLE) {
Bjorn Helgaase3cf6952008-07-30 12:26:51 -0700315 dev_warn(&agp_bridge->dev->dev, "i810 is disabled\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316 return 0;
317 }
318 if ((smram_miscc & I810_GFX_MEM_WIN_SIZE) == I810_GFX_MEM_WIN_32M) {
319 agp_bridge->previous_size =
320 agp_bridge->current_size = (void *) (values + 1);
321 agp_bridge->aperture_size_idx = 1;
322 return values[1].size;
323 } else {
324 agp_bridge->previous_size =
325 agp_bridge->current_size = (void *) (values);
326 agp_bridge->aperture_size_idx = 0;
327 return values[0].size;
328 }
329
330 return 0;
331}
332
333static int intel_i810_configure(void)
334{
335 struct aper_size_info_fixed *current_size;
336 u32 temp;
337 int i;
338
339 current_size = A_SIZE_FIX(agp_bridge->current_size);
340
Wang Zhenyuc4ca8812007-05-30 09:40:46 +0800341 if (!intel_private.registers) {
342 pci_read_config_dword(intel_private.pcidev, I810_MMADDR, &temp);
Dave Jonese4ac5e42007-02-04 17:37:42 -0500343 temp &= 0xfff80000;
344
Wang Zhenyuc4ca8812007-05-30 09:40:46 +0800345 intel_private.registers = ioremap(temp, 128 * 4096);
346 if (!intel_private.registers) {
Bjorn Helgaase3cf6952008-07-30 12:26:51 -0700347 dev_err(&intel_private.pcidev->dev,
348 "can't remap memory\n");
Dave Jonese4ac5e42007-02-04 17:37:42 -0500349 return -ENOMEM;
350 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351 }
352
Wang Zhenyuc4ca8812007-05-30 09:40:46 +0800353 if ((readl(intel_private.registers+I810_DRAM_CTL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700354 & I810_DRAM_ROW_0) == I810_DRAM_ROW_0_SDRAM) {
355 /* This will need to be dynamically assigned */
Bjorn Helgaase3cf6952008-07-30 12:26:51 -0700356 dev_info(&intel_private.pcidev->dev,
357 "detected 4MB dedicated video ram\n");
Wang Zhenyuc4ca8812007-05-30 09:40:46 +0800358 intel_private.num_dcache_entries = 1024;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700359 }
Wang Zhenyuc4ca8812007-05-30 09:40:46 +0800360 pci_read_config_dword(intel_private.pcidev, I810_GMADDR, &temp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361 agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
Wang Zhenyuc4ca8812007-05-30 09:40:46 +0800362 writel(agp_bridge->gatt_bus_addr | I810_PGETBL_ENABLED, intel_private.registers+I810_PGETBL_CTL);
363 readl(intel_private.registers+I810_PGETBL_CTL); /* PCI Posting. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700364
365 if (agp_bridge->driver->needs_scratch_page) {
366 for (i = 0; i < current_size->num_entries; i++) {
Wang Zhenyuc4ca8812007-05-30 09:40:46 +0800367 writel(agp_bridge->scratch_page, intel_private.registers+I810_PTE_BASE+(i*4));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368 }
Keith Packard44d49442008-10-14 17:18:45 -0700369 readl(intel_private.registers+I810_PTE_BASE+((i-1)*4)); /* PCI posting. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700370 }
371 global_cache_flush();
372 return 0;
373}
374
375static void intel_i810_cleanup(void)
376{
Wang Zhenyuc4ca8812007-05-30 09:40:46 +0800377 writel(0, intel_private.registers+I810_PGETBL_CTL);
378 readl(intel_private.registers); /* PCI Posting. */
379 iounmap(intel_private.registers);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380}
381
382static void intel_i810_tlbflush(struct agp_memory *mem)
383{
384 return;
385}
386
387static void intel_i810_agp_enable(struct agp_bridge_data *bridge, u32 mode)
388{
389 return;
390}
391
392/* Exists to support ARGB cursors */
Dave Airlie07613ba2009-06-12 14:11:41 +1000393static struct page *i8xx_alloc_pages(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700394{
Dave Airlief011ae72008-01-25 11:23:04 +1000395 struct page *page;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700396
Linus Torvalds66c669b2006-11-22 14:55:29 -0800397 page = alloc_pages(GFP_KERNEL | GFP_DMA32, 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398 if (page == NULL)
399 return NULL;
400
Arjan van de Ven6d238cc2008-01-30 13:34:06 +0100401 if (set_pages_uc(page, 4) < 0) {
402 set_pages_wb(page, 4);
Jan Beulich89cf7cc2007-04-02 14:50:14 +0100403 __free_pages(page, 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404 return NULL;
405 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700406 get_page(page);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700407 atomic_inc(&agp_bridge->current_memory_agp);
Dave Airlie07613ba2009-06-12 14:11:41 +1000408 return page;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700409}
410
Dave Airlie07613ba2009-06-12 14:11:41 +1000411static void i8xx_destroy_pages(struct page *page)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700412{
Dave Airlie07613ba2009-06-12 14:11:41 +1000413 if (page == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700414 return;
415
Arjan van de Ven6d238cc2008-01-30 13:34:06 +0100416 set_pages_wb(page, 4);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700417 put_page(page);
Jan Beulich89cf7cc2007-04-02 14:50:14 +0100418 __free_pages(page, 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700419 atomic_dec(&agp_bridge->current_memory_agp);
420}
421
Thomas Hellstroma030ce42007-01-23 10:33:43 +0100422static int intel_i830_type_to_mask_type(struct agp_bridge_data *bridge,
423 int type)
424{
425 if (type < AGP_USER_TYPES)
426 return type;
427 else if (type == AGP_USER_CACHED_MEMORY)
428 return INTEL_AGP_CACHED_MEMORY;
429 else
430 return 0;
431}
432
Linus Torvalds1da177e2005-04-16 15:20:36 -0700433static int intel_i810_insert_entries(struct agp_memory *mem, off_t pg_start,
434 int type)
435{
436 int i, j, num_entries;
437 void *temp;
Thomas Hellstroma030ce42007-01-23 10:33:43 +0100438 int ret = -EINVAL;
439 int mask_type;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700440
Thomas Hellstrom5aa80c72006-12-20 16:33:41 +0100441 if (mem->page_count == 0)
Thomas Hellstroma030ce42007-01-23 10:33:43 +0100442 goto out;
Thomas Hellstrom5aa80c72006-12-20 16:33:41 +0100443
Linus Torvalds1da177e2005-04-16 15:20:36 -0700444 temp = agp_bridge->current_size;
445 num_entries = A_SIZE_FIX(temp)->num_entries;
446
Dave Jones6a92a4e2006-02-28 00:54:25 -0500447 if ((pg_start + mem->page_count) > num_entries)
Thomas Hellstroma030ce42007-01-23 10:33:43 +0100448 goto out_err;
449
Dave Jones6a92a4e2006-02-28 00:54:25 -0500450
Linus Torvalds1da177e2005-04-16 15:20:36 -0700451 for (j = pg_start; j < (pg_start + mem->page_count); j++) {
Thomas Hellstroma030ce42007-01-23 10:33:43 +0100452 if (!PGE_EMPTY(agp_bridge, readl(agp_bridge->gatt_table+j))) {
453 ret = -EBUSY;
454 goto out_err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700455 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700456 }
457
Thomas Hellstroma030ce42007-01-23 10:33:43 +0100458 if (type != mem->type)
459 goto out_err;
Thomas Hellstrom5aa80c72006-12-20 16:33:41 +0100460
Thomas Hellstroma030ce42007-01-23 10:33:43 +0100461 mask_type = agp_bridge->driver->agp_type_to_mask_type(agp_bridge, type);
462
463 switch (mask_type) {
464 case AGP_DCACHE_MEMORY:
465 if (!mem->is_flushed)
466 global_cache_flush();
467 for (i = pg_start; i < (pg_start + mem->page_count); i++) {
468 writel((i*4096)|I810_PTE_LOCAL|I810_PTE_VALID,
Wang Zhenyuc4ca8812007-05-30 09:40:46 +0800469 intel_private.registers+I810_PTE_BASE+(i*4));
Thomas Hellstroma030ce42007-01-23 10:33:43 +0100470 }
Wang Zhenyuc4ca8812007-05-30 09:40:46 +0800471 readl(intel_private.registers+I810_PTE_BASE+((i-1)*4));
Thomas Hellstroma030ce42007-01-23 10:33:43 +0100472 break;
473 case AGP_PHYS_MEMORY:
474 case AGP_NORMAL_MEMORY:
475 if (!mem->is_flushed)
476 global_cache_flush();
477 for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
478 writel(agp_bridge->driver->mask_memory(agp_bridge,
David Woodhouse6a122352009-07-29 10:25:58 +0100479 page_to_phys(mem->pages[i]), mask_type),
Wang Zhenyuc4ca8812007-05-30 09:40:46 +0800480 intel_private.registers+I810_PTE_BASE+(j*4));
Thomas Hellstroma030ce42007-01-23 10:33:43 +0100481 }
Wang Zhenyuc4ca8812007-05-30 09:40:46 +0800482 readl(intel_private.registers+I810_PTE_BASE+((j-1)*4));
Thomas Hellstroma030ce42007-01-23 10:33:43 +0100483 break;
484 default:
485 goto out_err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700487
488 agp_bridge->driver->tlb_flush(mem);
Thomas Hellstroma030ce42007-01-23 10:33:43 +0100489out:
490 ret = 0;
491out_err:
Dave Airlie9516b032008-06-19 10:42:17 +1000492 mem->is_flushed = true;
Thomas Hellstroma030ce42007-01-23 10:33:43 +0100493 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494}
495
496static int intel_i810_remove_entries(struct agp_memory *mem, off_t pg_start,
497 int type)
498{
499 int i;
500
Thomas Hellstrom5aa80c72006-12-20 16:33:41 +0100501 if (mem->page_count == 0)
502 return 0;
503
Linus Torvalds1da177e2005-04-16 15:20:36 -0700504 for (i = pg_start; i < (mem->page_count + pg_start); i++) {
Wang Zhenyuc4ca8812007-05-30 09:40:46 +0800505 writel(agp_bridge->scratch_page, intel_private.registers+I810_PTE_BASE+(i*4));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700506 }
Wang Zhenyuc4ca8812007-05-30 09:40:46 +0800507 readl(intel_private.registers+I810_PTE_BASE+((i-1)*4));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700508
Linus Torvalds1da177e2005-04-16 15:20:36 -0700509 agp_bridge->driver->tlb_flush(mem);
510 return 0;
511}
512
513/*
514 * The i810/i830 requires a physical address to program its mouse
515 * pointer into hardware.
516 * However the Xserver still writes to it through the agp aperture.
517 */
518static struct agp_memory *alloc_agpphysmem_i8xx(size_t pg_count, int type)
519{
520 struct agp_memory *new;
Dave Airlie07613ba2009-06-12 14:11:41 +1000521 struct page *page;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700522
Linus Torvalds1da177e2005-04-16 15:20:36 -0700523 switch (pg_count) {
Dave Airlie07613ba2009-06-12 14:11:41 +1000524 case 1: page = agp_bridge->driver->agp_alloc_page(agp_bridge);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700525 break;
526 case 4:
527 /* kludge to get 4 physical pages for ARGB cursor */
Dave Airlie07613ba2009-06-12 14:11:41 +1000528 page = i8xx_alloc_pages();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700529 break;
530 default:
531 return NULL;
532 }
533
Dave Airlie07613ba2009-06-12 14:11:41 +1000534 if (page == NULL)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700535 return NULL;
536
537 new = agp_create_memory(pg_count);
538 if (new == NULL)
539 return NULL;
540
Dave Airlie07613ba2009-06-12 14:11:41 +1000541 new->pages[0] = page;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700542 if (pg_count == 4) {
543 /* kludge to get 4 physical pages for ARGB cursor */
Dave Airlie07613ba2009-06-12 14:11:41 +1000544 new->pages[1] = new->pages[0] + 1;
545 new->pages[2] = new->pages[1] + 1;
546 new->pages[3] = new->pages[2] + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700547 }
548 new->page_count = pg_count;
549 new->num_scratch_pages = pg_count;
550 new->type = AGP_PHYS_MEMORY;
Dave Airlie07613ba2009-06-12 14:11:41 +1000551 new->physical = page_to_phys(new->pages[0]);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700552 return new;
553}
554
555static struct agp_memory *intel_i810_alloc_by_type(size_t pg_count, int type)
556{
557 struct agp_memory *new;
558
559 if (type == AGP_DCACHE_MEMORY) {
Wang Zhenyuc4ca8812007-05-30 09:40:46 +0800560 if (pg_count != intel_private.num_dcache_entries)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700561 return NULL;
562
563 new = agp_create_memory(1);
564 if (new == NULL)
565 return NULL;
566
567 new->type = AGP_DCACHE_MEMORY;
568 new->page_count = pg_count;
569 new->num_scratch_pages = 0;
Thomas Hellstroma030ce42007-01-23 10:33:43 +0100570 agp_free_page_array(new);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700571 return new;
572 }
573 if (type == AGP_PHYS_MEMORY)
574 return alloc_agpphysmem_i8xx(pg_count, type);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700575 return NULL;
576}
577
578static void intel_i810_free_by_type(struct agp_memory *curr)
579{
580 agp_free_key(curr->key);
Dave Jones6a92a4e2006-02-28 00:54:25 -0500581 if (curr->type == AGP_PHYS_MEMORY) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700582 if (curr->page_count == 4)
Dave Airlie07613ba2009-06-12 14:11:41 +1000583 i8xx_destroy_pages(curr->pages[0]);
Alan Hourihane88d51962005-11-06 23:35:34 -0800584 else {
Dave Airlie07613ba2009-06-12 14:11:41 +1000585 agp_bridge->driver->agp_destroy_page(curr->pages[0],
Dave Airliea2721e92007-10-15 10:19:16 +1000586 AGP_PAGE_DESTROY_UNMAP);
Dave Airlie07613ba2009-06-12 14:11:41 +1000587 agp_bridge->driver->agp_destroy_page(curr->pages[0],
Dave Airliea2721e92007-10-15 10:19:16 +1000588 AGP_PAGE_DESTROY_FREE);
Alan Hourihane88d51962005-11-06 23:35:34 -0800589 }
Thomas Hellstroma030ce42007-01-23 10:33:43 +0100590 agp_free_page_array(curr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700591 }
592 kfree(curr);
593}
594
595static unsigned long intel_i810_mask_memory(struct agp_bridge_data *bridge,
David Woodhouse2a4ceb62009-07-27 10:27:29 +0100596 dma_addr_t addr, int type)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700597{
598 /* Type checking must be done elsewhere */
599 return addr | bridge->driver->masks[type].mask;
600}
601
602static struct aper_size_info_fixed intel_i830_sizes[] =
603{
604 {128, 32768, 5},
605 /* The 64M mode still requires a 128k gatt */
606 {64, 16384, 5},
607 {256, 65536, 6},
Eric Anholt65c25aa2006-09-06 11:57:18 -0400608 {512, 131072, 7},
Linus Torvalds1da177e2005-04-16 15:20:36 -0700609};
610
Linus Torvalds1da177e2005-04-16 15:20:36 -0700611static void intel_i830_init_gtt_entries(void)
612{
613 u16 gmch_ctrl;
614 int gtt_entries;
615 u8 rdct;
616 int local = 0;
617 static const int ddt[4] = { 0, 16, 32, 64 };
Eric Anholtc41e0de2006-12-19 12:57:24 -0800618 int size; /* reserved space (in kb) at the top of stolen memory */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700619
Dave Airlief011ae72008-01-25 11:23:04 +1000620 pci_read_config_word(agp_bridge->dev, I830_GMCH_CTRL, &gmch_ctrl);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700621
Eric Anholtc41e0de2006-12-19 12:57:24 -0800622 if (IS_I965) {
623 u32 pgetbl_ctl;
Wang Zhenyuc4ca8812007-05-30 09:40:46 +0800624 pgetbl_ctl = readl(intel_private.registers+I810_PGETBL_CTL);
Eric Anholtc41e0de2006-12-19 12:57:24 -0800625
Eric Anholtc41e0de2006-12-19 12:57:24 -0800626 /* The 965 has a field telling us the size of the GTT,
627 * which may be larger than what is necessary to map the
628 * aperture.
629 */
630 switch (pgetbl_ctl & I965_PGETBL_SIZE_MASK) {
631 case I965_PGETBL_SIZE_128KB:
632 size = 128;
633 break;
634 case I965_PGETBL_SIZE_256KB:
635 size = 256;
636 break;
637 case I965_PGETBL_SIZE_512KB:
638 size = 512;
639 break;
Zhenyu Wang4e8b6e22008-01-23 14:54:37 +1000640 case I965_PGETBL_SIZE_1MB:
641 size = 1024;
642 break;
643 case I965_PGETBL_SIZE_2MB:
644 size = 2048;
645 break;
646 case I965_PGETBL_SIZE_1_5MB:
647 size = 1024 + 512;
648 break;
Eric Anholtc41e0de2006-12-19 12:57:24 -0800649 default:
Bjorn Helgaase3cf6952008-07-30 12:26:51 -0700650 dev_info(&intel_private.pcidev->dev,
651 "unknown page table size, assuming 512KB\n");
Eric Anholtc41e0de2006-12-19 12:57:24 -0800652 size = 512;
653 }
654 size += 4; /* add in BIOS popup space */
Adam Jackson107f5172009-12-03 17:14:41 -0500655 } else if (IS_G33 && !IS_PINEVIEW) {
Wang Zhenyu874808c62007-06-06 11:16:25 +0800656 /* G33's GTT size defined in gmch_ctrl */
657 switch (gmch_ctrl & G33_PGETBL_SIZE_MASK) {
658 case G33_PGETBL_SIZE_1M:
659 size = 1024;
660 break;
661 case G33_PGETBL_SIZE_2M:
662 size = 2048;
663 break;
664 default:
Bjorn Helgaase3cf6952008-07-30 12:26:51 -0700665 dev_info(&agp_bridge->dev->dev,
666 "unknown page table size 0x%x, assuming 512KB\n",
Wang Zhenyu874808c62007-06-06 11:16:25 +0800667 (gmch_ctrl & G33_PGETBL_SIZE_MASK));
668 size = 512;
669 }
670 size += 4;
Adam Jackson107f5172009-12-03 17:14:41 -0500671 } else if (IS_G4X || IS_PINEVIEW) {
Zhenyu Wang25ce77a2008-06-19 14:17:58 +1000672 /* On 4 series hardware, GTT stolen is separate from graphics
Eric Anholt82e14a62008-10-14 11:28:58 -0700673 * stolen, ignore it in stolen gtt entries counting. However,
674 * 4KB of the stolen memory doesn't get mapped to the GTT.
675 */
676 size = 4;
Eric Anholtc41e0de2006-12-19 12:57:24 -0800677 } else {
678 /* On previous hardware, the GTT size was just what was
679 * required to map the aperture.
680 */
681 size = agp_bridge->driver->fetch_size() + 4;
682 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700683
684 if (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82830_HB ||
685 agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82845G_HB) {
686 switch (gmch_ctrl & I830_GMCH_GMS_MASK) {
687 case I830_GMCH_GMS_STOLEN_512:
688 gtt_entries = KB(512) - KB(size);
689 break;
690 case I830_GMCH_GMS_STOLEN_1024:
691 gtt_entries = MB(1) - KB(size);
692 break;
693 case I830_GMCH_GMS_STOLEN_8192:
694 gtt_entries = MB(8) - KB(size);
695 break;
696 case I830_GMCH_GMS_LOCAL:
Wang Zhenyuc4ca8812007-05-30 09:40:46 +0800697 rdct = readb(intel_private.registers+I830_RDRAM_CHANNEL_TYPE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700698 gtt_entries = (I830_RDRAM_ND(rdct) + 1) *
699 MB(ddt[I830_RDRAM_DDT(rdct)]);
700 local = 1;
701 break;
702 default:
703 gtt_entries = 0;
704 break;
705 }
706 } else {
Dave Airliee67aa272007-09-18 22:46:35 -0700707 switch (gmch_ctrl & I855_GMCH_GMS_MASK) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708 case I855_GMCH_GMS_STOLEN_1M:
709 gtt_entries = MB(1) - KB(size);
710 break;
711 case I855_GMCH_GMS_STOLEN_4M:
712 gtt_entries = MB(4) - KB(size);
713 break;
714 case I855_GMCH_GMS_STOLEN_8M:
715 gtt_entries = MB(8) - KB(size);
716 break;
717 case I855_GMCH_GMS_STOLEN_16M:
718 gtt_entries = MB(16) - KB(size);
719 break;
720 case I855_GMCH_GMS_STOLEN_32M:
721 gtt_entries = MB(32) - KB(size);
722 break;
723 case I915_GMCH_GMS_STOLEN_48M:
724 /* Check it's really I915G */
Zhenyu Wang25ce77a2008-06-19 14:17:58 +1000725 if (IS_I915 || IS_I965 || IS_G33 || IS_G4X)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700726 gtt_entries = MB(48) - KB(size);
727 else
728 gtt_entries = 0;
729 break;
730 case I915_GMCH_GMS_STOLEN_64M:
731 /* Check it's really I915G */
Zhenyu Wang25ce77a2008-06-19 14:17:58 +1000732 if (IS_I915 || IS_I965 || IS_G33 || IS_G4X)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700733 gtt_entries = MB(64) - KB(size);
734 else
735 gtt_entries = 0;
Wang Zhenyu874808c62007-06-06 11:16:25 +0800736 break;
737 case G33_GMCH_GMS_STOLEN_128M:
Zhenyu Wang25ce77a2008-06-19 14:17:58 +1000738 if (IS_G33 || IS_I965 || IS_G4X)
Wang Zhenyu874808c62007-06-06 11:16:25 +0800739 gtt_entries = MB(128) - KB(size);
740 else
741 gtt_entries = 0;
742 break;
743 case G33_GMCH_GMS_STOLEN_256M:
Zhenyu Wang25ce77a2008-06-19 14:17:58 +1000744 if (IS_G33 || IS_I965 || IS_G4X)
Wang Zhenyu874808c62007-06-06 11:16:25 +0800745 gtt_entries = MB(256) - KB(size);
746 else
747 gtt_entries = 0;
748 break;
Zhenyu Wang25ce77a2008-06-19 14:17:58 +1000749 case INTEL_GMCH_GMS_STOLEN_96M:
750 if (IS_I965 || IS_G4X)
751 gtt_entries = MB(96) - KB(size);
752 else
753 gtt_entries = 0;
754 break;
755 case INTEL_GMCH_GMS_STOLEN_160M:
756 if (IS_I965 || IS_G4X)
757 gtt_entries = MB(160) - KB(size);
758 else
759 gtt_entries = 0;
760 break;
761 case INTEL_GMCH_GMS_STOLEN_224M:
762 if (IS_I965 || IS_G4X)
763 gtt_entries = MB(224) - KB(size);
764 else
765 gtt_entries = 0;
766 break;
767 case INTEL_GMCH_GMS_STOLEN_352M:
768 if (IS_I965 || IS_G4X)
769 gtt_entries = MB(352) - KB(size);
770 else
771 gtt_entries = 0;
772 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700773 default:
774 gtt_entries = 0;
775 break;
776 }
777 }
Lubomir Rintel9c1e8a42009-03-10 12:55:54 -0700778 if (gtt_entries > 0) {
Bjorn Helgaase3cf6952008-07-30 12:26:51 -0700779 dev_info(&agp_bridge->dev->dev, "detected %dK %s memory\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780 gtt_entries / KB(1), local ? "local" : "stolen");
Lubomir Rintel9c1e8a42009-03-10 12:55:54 -0700781 gtt_entries /= KB(4);
782 } else {
Bjorn Helgaase3cf6952008-07-30 12:26:51 -0700783 dev_info(&agp_bridge->dev->dev,
784 "no pre-allocated video memory detected\n");
Lubomir Rintel9c1e8a42009-03-10 12:55:54 -0700785 gtt_entries = 0;
786 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700787
Wang Zhenyuc4ca8812007-05-30 09:40:46 +0800788 intel_private.gtt_entries = gtt_entries;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700789}
790
Dave Airlie2162e6a2007-11-21 16:36:31 +1000791static void intel_i830_fini_flush(void)
792{
793 kunmap(intel_private.i8xx_page);
794 intel_private.i8xx_flush_page = NULL;
795 unmap_page_from_agp(intel_private.i8xx_page);
Dave Airlie2162e6a2007-11-21 16:36:31 +1000796
797 __free_page(intel_private.i8xx_page);
Dave Airlie4d64dd92008-01-23 15:34:29 +1000798 intel_private.i8xx_page = NULL;
Dave Airlie2162e6a2007-11-21 16:36:31 +1000799}
800
801static void intel_i830_setup_flush(void)
802{
Dave Airlie4d64dd92008-01-23 15:34:29 +1000803 /* return if we've already set the flush mechanism up */
804 if (intel_private.i8xx_page)
805 return;
Dave Airlie2162e6a2007-11-21 16:36:31 +1000806
807 intel_private.i8xx_page = alloc_page(GFP_KERNEL | __GFP_ZERO | GFP_DMA32);
Dave Airlief011ae72008-01-25 11:23:04 +1000808 if (!intel_private.i8xx_page)
Dave Airlie2162e6a2007-11-21 16:36:31 +1000809 return;
Dave Airlie2162e6a2007-11-21 16:36:31 +1000810
Dave Airlie2162e6a2007-11-21 16:36:31 +1000811 intel_private.i8xx_flush_page = kmap(intel_private.i8xx_page);
812 if (!intel_private.i8xx_flush_page)
813 intel_i830_fini_flush();
814}
815
Eric Anholte517a5e2009-09-10 17:48:48 -0700816static void
817do_wbinvd(void *null)
818{
819 wbinvd();
820}
821
822/* The chipset_flush interface needs to get data that has already been
823 * flushed out of the CPU all the way out to main memory, because the GPU
824 * doesn't snoop those buffers.
825 *
826 * The 8xx series doesn't have the same lovely interface for flushing the
827 * chipset write buffers that the later chips do. According to the 865
828 * specs, it's 64 octwords, or 1KB. So, to get those previous things in
829 * that buffer out, we just fill 1KB and clflush it out, on the assumption
830 * that it'll push whatever was in there out. It appears to work.
831 */
Dave Airlie2162e6a2007-11-21 16:36:31 +1000832static void intel_i830_chipset_flush(struct agp_bridge_data *bridge)
833{
834 unsigned int *pg = intel_private.i8xx_flush_page;
Dave Airlie2162e6a2007-11-21 16:36:31 +1000835
Eric Anholte517a5e2009-09-10 17:48:48 -0700836 memset(pg, 0, 1024);
Dave Airlief011ae72008-01-25 11:23:04 +1000837
Eric Anholte517a5e2009-09-10 17:48:48 -0700838 if (cpu_has_clflush) {
839 clflush_cache_range(pg, 1024);
840 } else {
841 if (on_each_cpu(do_wbinvd, NULL, 1) != 0)
842 printk(KERN_ERR "Timed out waiting for cache flush.\n");
843 }
Dave Airlie2162e6a2007-11-21 16:36:31 +1000844}
845
Linus Torvalds1da177e2005-04-16 15:20:36 -0700846/* The intel i830 automatically initializes the agp aperture during POST.
847 * Use the memory already set aside for in the GTT.
848 */
849static int intel_i830_create_gatt_table(struct agp_bridge_data *bridge)
850{
851 int page_order;
852 struct aper_size_info_fixed *size;
853 int num_entries;
854 u32 temp;
855
856 size = agp_bridge->current_size;
857 page_order = size->page_order;
858 num_entries = size->num_entries;
859 agp_bridge->gatt_table_real = NULL;
860
Dave Airlief011ae72008-01-25 11:23:04 +1000861 pci_read_config_dword(intel_private.pcidev, I810_MMADDR, &temp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700862 temp &= 0xfff80000;
863
Dave Airlief011ae72008-01-25 11:23:04 +1000864 intel_private.registers = ioremap(temp, 128 * 4096);
Wang Zhenyuc4ca8812007-05-30 09:40:46 +0800865 if (!intel_private.registers)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700866 return -ENOMEM;
867
Wang Zhenyuc4ca8812007-05-30 09:40:46 +0800868 temp = readl(intel_private.registers+I810_PGETBL_CTL) & 0xfffff000;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700869 global_cache_flush(); /* FIXME: ?? */
870
871 /* we have to call this as early as possible after the MMIO base address is known */
872 intel_i830_init_gtt_entries();
873
874 agp_bridge->gatt_table = NULL;
875
876 agp_bridge->gatt_bus_addr = temp;
877
878 return 0;
879}
880
881/* Return the gatt table to a sane state. Use the top of stolen
882 * memory for the GTT.
883 */
884static int intel_i830_free_gatt_table(struct agp_bridge_data *bridge)
885{
886 return 0;
887}
888
889static int intel_i830_fetch_size(void)
890{
891 u16 gmch_ctrl;
892 struct aper_size_info_fixed *values;
893
894 values = A_SIZE_FIX(agp_bridge->driver->aperture_sizes);
895
896 if (agp_bridge->dev->device != PCI_DEVICE_ID_INTEL_82830_HB &&
897 agp_bridge->dev->device != PCI_DEVICE_ID_INTEL_82845G_HB) {
898 /* 855GM/852GM/865G has 128MB aperture size */
899 agp_bridge->previous_size = agp_bridge->current_size = (void *) values;
900 agp_bridge->aperture_size_idx = 0;
901 return values[0].size;
902 }
903
Dave Airlief011ae72008-01-25 11:23:04 +1000904 pci_read_config_word(agp_bridge->dev, I830_GMCH_CTRL, &gmch_ctrl);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700905
906 if ((gmch_ctrl & I830_GMCH_MEM_MASK) == I830_GMCH_MEM_128M) {
907 agp_bridge->previous_size = agp_bridge->current_size = (void *) values;
908 agp_bridge->aperture_size_idx = 0;
909 return values[0].size;
910 } else {
911 agp_bridge->previous_size = agp_bridge->current_size = (void *) (values + 1);
912 agp_bridge->aperture_size_idx = 1;
913 return values[1].size;
914 }
915
916 return 0;
917}
918
919static int intel_i830_configure(void)
920{
921 struct aper_size_info_fixed *current_size;
922 u32 temp;
923 u16 gmch_ctrl;
924 int i;
925
926 current_size = A_SIZE_FIX(agp_bridge->current_size);
927
Dave Airlief011ae72008-01-25 11:23:04 +1000928 pci_read_config_dword(intel_private.pcidev, I810_GMADDR, &temp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700929 agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
930
Dave Airlief011ae72008-01-25 11:23:04 +1000931 pci_read_config_word(agp_bridge->dev, I830_GMCH_CTRL, &gmch_ctrl);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700932 gmch_ctrl |= I830_GMCH_ENABLED;
Dave Airlief011ae72008-01-25 11:23:04 +1000933 pci_write_config_word(agp_bridge->dev, I830_GMCH_CTRL, gmch_ctrl);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700934
Wang Zhenyuc4ca8812007-05-30 09:40:46 +0800935 writel(agp_bridge->gatt_bus_addr|I810_PGETBL_ENABLED, intel_private.registers+I810_PGETBL_CTL);
936 readl(intel_private.registers+I810_PGETBL_CTL); /* PCI Posting. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700937
938 if (agp_bridge->driver->needs_scratch_page) {
Wang Zhenyuc4ca8812007-05-30 09:40:46 +0800939 for (i = intel_private.gtt_entries; i < current_size->num_entries; i++) {
940 writel(agp_bridge->scratch_page, intel_private.registers+I810_PTE_BASE+(i*4));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700941 }
Keith Packard44d49442008-10-14 17:18:45 -0700942 readl(intel_private.registers+I810_PTE_BASE+((i-1)*4)); /* PCI Posting. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700943 }
944
945 global_cache_flush();
Dave Airlie2162e6a2007-11-21 16:36:31 +1000946
947 intel_i830_setup_flush();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700948 return 0;
949}
950
951static void intel_i830_cleanup(void)
952{
Wang Zhenyuc4ca8812007-05-30 09:40:46 +0800953 iounmap(intel_private.registers);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700954}
955
Dave Airlief011ae72008-01-25 11:23:04 +1000956static int intel_i830_insert_entries(struct agp_memory *mem, off_t pg_start,
957 int type)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700958{
Dave Airlief011ae72008-01-25 11:23:04 +1000959 int i, j, num_entries;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700960 void *temp;
Thomas Hellstroma030ce42007-01-23 10:33:43 +0100961 int ret = -EINVAL;
962 int mask_type;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700963
Thomas Hellstrom5aa80c72006-12-20 16:33:41 +0100964 if (mem->page_count == 0)
Thomas Hellstroma030ce42007-01-23 10:33:43 +0100965 goto out;
Thomas Hellstrom5aa80c72006-12-20 16:33:41 +0100966
Linus Torvalds1da177e2005-04-16 15:20:36 -0700967 temp = agp_bridge->current_size;
968 num_entries = A_SIZE_FIX(temp)->num_entries;
969
Wang Zhenyuc4ca8812007-05-30 09:40:46 +0800970 if (pg_start < intel_private.gtt_entries) {
Bjorn Helgaase3cf6952008-07-30 12:26:51 -0700971 dev_printk(KERN_DEBUG, &intel_private.pcidev->dev,
972 "pg_start == 0x%.8lx, intel_private.gtt_entries == 0x%.8x\n",
973 pg_start, intel_private.gtt_entries);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700974
Bjorn Helgaase3cf6952008-07-30 12:26:51 -0700975 dev_info(&intel_private.pcidev->dev,
976 "trying to insert into local/stolen memory\n");
Thomas Hellstroma030ce42007-01-23 10:33:43 +0100977 goto out_err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700978 }
979
980 if ((pg_start + mem->page_count) > num_entries)
Thomas Hellstroma030ce42007-01-23 10:33:43 +0100981 goto out_err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700982
983 /* The i830 can't check the GTT for entries since its read only,
984 * depend on the caller to make the correct offset decisions.
985 */
986
Thomas Hellstroma030ce42007-01-23 10:33:43 +0100987 if (type != mem->type)
988 goto out_err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700989
Thomas Hellstroma030ce42007-01-23 10:33:43 +0100990 mask_type = agp_bridge->driver->agp_type_to_mask_type(agp_bridge, type);
991
992 if (mask_type != 0 && mask_type != AGP_PHYS_MEMORY &&
993 mask_type != INTEL_AGP_CACHED_MEMORY)
994 goto out_err;
995
996 if (!mem->is_flushed)
Thomas Hellstrom5aa80c72006-12-20 16:33:41 +0100997 global_cache_flush();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700998
999 for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
1000 writel(agp_bridge->driver->mask_memory(agp_bridge,
David Woodhouse6a122352009-07-29 10:25:58 +01001001 page_to_phys(mem->pages[i]), mask_type),
Wang Zhenyuc4ca8812007-05-30 09:40:46 +08001002 intel_private.registers+I810_PTE_BASE+(j*4));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001003 }
Wang Zhenyuc4ca8812007-05-30 09:40:46 +08001004 readl(intel_private.registers+I810_PTE_BASE+((j-1)*4));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001005 agp_bridge->driver->tlb_flush(mem);
Thomas Hellstroma030ce42007-01-23 10:33:43 +01001006
1007out:
1008 ret = 0;
1009out_err:
Dave Airlie9516b032008-06-19 10:42:17 +10001010 mem->is_flushed = true;
Thomas Hellstroma030ce42007-01-23 10:33:43 +01001011 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001012}
1013
Dave Airlief011ae72008-01-25 11:23:04 +10001014static int intel_i830_remove_entries(struct agp_memory *mem, off_t pg_start,
1015 int type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001016{
1017 int i;
1018
Thomas Hellstrom5aa80c72006-12-20 16:33:41 +01001019 if (mem->page_count == 0)
1020 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001021
Wang Zhenyuc4ca8812007-05-30 09:40:46 +08001022 if (pg_start < intel_private.gtt_entries) {
Bjorn Helgaase3cf6952008-07-30 12:26:51 -07001023 dev_info(&intel_private.pcidev->dev,
1024 "trying to disable local/stolen memory\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001025 return -EINVAL;
1026 }
1027
1028 for (i = pg_start; i < (mem->page_count + pg_start); i++) {
Wang Zhenyuc4ca8812007-05-30 09:40:46 +08001029 writel(agp_bridge->scratch_page, intel_private.registers+I810_PTE_BASE+(i*4));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001030 }
Wang Zhenyuc4ca8812007-05-30 09:40:46 +08001031 readl(intel_private.registers+I810_PTE_BASE+((i-1)*4));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001032
Linus Torvalds1da177e2005-04-16 15:20:36 -07001033 agp_bridge->driver->tlb_flush(mem);
1034 return 0;
1035}
1036
Dave Airlief011ae72008-01-25 11:23:04 +10001037static struct agp_memory *intel_i830_alloc_by_type(size_t pg_count, int type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001038{
1039 if (type == AGP_PHYS_MEMORY)
1040 return alloc_agpphysmem_i8xx(pg_count, type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001041 /* always return NULL for other allocation types for now */
1042 return NULL;
1043}
1044
Dave Airlie6c00a612007-10-29 18:06:10 +10001045static int intel_alloc_chipset_flush_resource(void)
1046{
1047 int ret;
1048 ret = pci_bus_alloc_resource(agp_bridge->dev->bus, &intel_private.ifp_resource, PAGE_SIZE,
1049 PAGE_SIZE, PCIBIOS_MIN_MEM, 0,
1050 pcibios_align_resource, agp_bridge->dev);
Dave Airlie6c00a612007-10-29 18:06:10 +10001051
Dave Airlie2162e6a2007-11-21 16:36:31 +10001052 return ret;
Dave Airlie6c00a612007-10-29 18:06:10 +10001053}
1054
1055static void intel_i915_setup_chipset_flush(void)
1056{
1057 int ret;
1058 u32 temp;
1059
1060 pci_read_config_dword(agp_bridge->dev, I915_IFPADDR, &temp);
1061 if (!(temp & 0x1)) {
1062 intel_alloc_chipset_flush_resource();
Dave Airlie4d64dd92008-01-23 15:34:29 +10001063 intel_private.resource_valid = 1;
Dave Airlie6c00a612007-10-29 18:06:10 +10001064 pci_write_config_dword(agp_bridge->dev, I915_IFPADDR, (intel_private.ifp_resource.start & 0xffffffff) | 0x1);
1065 } else {
1066 temp &= ~1;
1067
Dave Airlie4d64dd92008-01-23 15:34:29 +10001068 intel_private.resource_valid = 1;
Dave Airlie6c00a612007-10-29 18:06:10 +10001069 intel_private.ifp_resource.start = temp;
1070 intel_private.ifp_resource.end = temp + PAGE_SIZE;
1071 ret = request_resource(&iomem_resource, &intel_private.ifp_resource);
Dave Airlie4d64dd92008-01-23 15:34:29 +10001072 /* some BIOSes reserve this area in a pnp some don't */
1073 if (ret)
1074 intel_private.resource_valid = 0;
Dave Airlie6c00a612007-10-29 18:06:10 +10001075 }
1076}
1077
1078static void intel_i965_g33_setup_chipset_flush(void)
1079{
1080 u32 temp_hi, temp_lo;
1081 int ret;
1082
1083 pci_read_config_dword(agp_bridge->dev, I965_IFPADDR + 4, &temp_hi);
1084 pci_read_config_dword(agp_bridge->dev, I965_IFPADDR, &temp_lo);
1085
1086 if (!(temp_lo & 0x1)) {
1087
1088 intel_alloc_chipset_flush_resource();
1089
Dave Airlie4d64dd92008-01-23 15:34:29 +10001090 intel_private.resource_valid = 1;
Andrew Morton1fa4db72007-11-29 10:00:48 +10001091 pci_write_config_dword(agp_bridge->dev, I965_IFPADDR + 4,
1092 upper_32_bits(intel_private.ifp_resource.start));
Dave Airlie6c00a612007-10-29 18:06:10 +10001093 pci_write_config_dword(agp_bridge->dev, I965_IFPADDR, (intel_private.ifp_resource.start & 0xffffffff) | 0x1);
Dave Airlie6c00a612007-10-29 18:06:10 +10001094 } else {
1095 u64 l64;
Dave Airlief011ae72008-01-25 11:23:04 +10001096
Dave Airlie6c00a612007-10-29 18:06:10 +10001097 temp_lo &= ~0x1;
1098 l64 = ((u64)temp_hi << 32) | temp_lo;
1099
Dave Airlie4d64dd92008-01-23 15:34:29 +10001100 intel_private.resource_valid = 1;
Dave Airlie6c00a612007-10-29 18:06:10 +10001101 intel_private.ifp_resource.start = l64;
1102 intel_private.ifp_resource.end = l64 + PAGE_SIZE;
1103 ret = request_resource(&iomem_resource, &intel_private.ifp_resource);
Dave Airlie4d64dd92008-01-23 15:34:29 +10001104 /* some BIOSes reserve this area in a pnp some don't */
1105 if (ret)
1106 intel_private.resource_valid = 0;
Dave Airlie6c00a612007-10-29 18:06:10 +10001107 }
1108}
1109
Dave Airlie2162e6a2007-11-21 16:36:31 +10001110static void intel_i9xx_setup_flush(void)
1111{
Dave Airlie4d64dd92008-01-23 15:34:29 +10001112 /* return if already configured */
1113 if (intel_private.ifp_resource.start)
1114 return;
Dave Airlie2162e6a2007-11-21 16:36:31 +10001115
Dave Airlie4d64dd92008-01-23 15:34:29 +10001116 /* setup a resource for this object */
Dave Airlie2162e6a2007-11-21 16:36:31 +10001117 intel_private.ifp_resource.name = "Intel Flush Page";
1118 intel_private.ifp_resource.flags = IORESOURCE_MEM;
1119
1120 /* Setup chipset flush for 915 */
Zhenyu Wang7d15ddf2008-06-20 11:48:06 +10001121 if (IS_I965 || IS_G33 || IS_G4X) {
Dave Airlie2162e6a2007-11-21 16:36:31 +10001122 intel_i965_g33_setup_chipset_flush();
1123 } else {
1124 intel_i915_setup_chipset_flush();
1125 }
1126
1127 if (intel_private.ifp_resource.start) {
1128 intel_private.i9xx_flush_page = ioremap_nocache(intel_private.ifp_resource.start, PAGE_SIZE);
1129 if (!intel_private.i9xx_flush_page)
Bjorn Helgaase3cf6952008-07-30 12:26:51 -07001130 dev_info(&intel_private.pcidev->dev, "can't ioremap flush page - no chipset flushing");
Dave Airlie2162e6a2007-11-21 16:36:31 +10001131 }
1132}
1133
Linus Torvalds1da177e2005-04-16 15:20:36 -07001134static int intel_i915_configure(void)
1135{
1136 struct aper_size_info_fixed *current_size;
1137 u32 temp;
1138 u16 gmch_ctrl;
1139 int i;
1140
1141 current_size = A_SIZE_FIX(agp_bridge->current_size);
1142
Wang Zhenyuc4ca8812007-05-30 09:40:46 +08001143 pci_read_config_dword(intel_private.pcidev, I915_GMADDR, &temp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001144
1145 agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
1146
Dave Airlief011ae72008-01-25 11:23:04 +10001147 pci_read_config_word(agp_bridge->dev, I830_GMCH_CTRL, &gmch_ctrl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001148 gmch_ctrl |= I830_GMCH_ENABLED;
Dave Airlief011ae72008-01-25 11:23:04 +10001149 pci_write_config_word(agp_bridge->dev, I830_GMCH_CTRL, gmch_ctrl);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001150
Wang Zhenyuc4ca8812007-05-30 09:40:46 +08001151 writel(agp_bridge->gatt_bus_addr|I810_PGETBL_ENABLED, intel_private.registers+I810_PGETBL_CTL);
1152 readl(intel_private.registers+I810_PGETBL_CTL); /* PCI Posting. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001153
1154 if (agp_bridge->driver->needs_scratch_page) {
David Woodhousefc619012009-12-02 11:00:05 +00001155 for (i = intel_private.gtt_entries; i < intel_private.gtt_total_size; i++) {
Wang Zhenyuc4ca8812007-05-30 09:40:46 +08001156 writel(agp_bridge->scratch_page, intel_private.gtt+i);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001157 }
Keith Packard44d49442008-10-14 17:18:45 -07001158 readl(intel_private.gtt+i-1); /* PCI Posting. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001159 }
1160
1161 global_cache_flush();
Dave Airlie6c00a612007-10-29 18:06:10 +10001162
Dave Airlie2162e6a2007-11-21 16:36:31 +10001163 intel_i9xx_setup_flush();
Dave Airlief011ae72008-01-25 11:23:04 +10001164
David Woodhouseba3139f2009-08-05 08:12:40 +01001165#ifdef USE_PCI_DMA_API
1166 if (pci_set_dma_mask(intel_private.pcidev, DMA_BIT_MASK(36)))
1167 dev_err(&intel_private.pcidev->dev,
1168 "set gfx device dma mask 36bit failed!\n");
1169#endif
1170
Linus Torvalds1da177e2005-04-16 15:20:36 -07001171 return 0;
1172}
1173
1174static void intel_i915_cleanup(void)
1175{
Dave Airlie2162e6a2007-11-21 16:36:31 +10001176 if (intel_private.i9xx_flush_page)
1177 iounmap(intel_private.i9xx_flush_page);
Dave Airlie4d64dd92008-01-23 15:34:29 +10001178 if (intel_private.resource_valid)
1179 release_resource(&intel_private.ifp_resource);
1180 intel_private.ifp_resource.start = 0;
1181 intel_private.resource_valid = 0;
Wang Zhenyuc4ca8812007-05-30 09:40:46 +08001182 iounmap(intel_private.gtt);
1183 iounmap(intel_private.registers);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001184}
1185
Dave Airlie6c00a612007-10-29 18:06:10 +10001186static void intel_i915_chipset_flush(struct agp_bridge_data *bridge)
1187{
Dave Airlie2162e6a2007-11-21 16:36:31 +10001188 if (intel_private.i9xx_flush_page)
1189 writel(1, intel_private.i9xx_flush_page);
Dave Airlie6c00a612007-10-29 18:06:10 +10001190}
1191
Dave Airlief011ae72008-01-25 11:23:04 +10001192static int intel_i915_insert_entries(struct agp_memory *mem, off_t pg_start,
1193 int type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001194{
Zhenyu Wang17661682009-07-27 12:59:57 +01001195 int num_entries;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001196 void *temp;
Thomas Hellstroma030ce42007-01-23 10:33:43 +01001197 int ret = -EINVAL;
1198 int mask_type;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001199
Thomas Hellstrom5aa80c72006-12-20 16:33:41 +01001200 if (mem->page_count == 0)
Thomas Hellstroma030ce42007-01-23 10:33:43 +01001201 goto out;
Thomas Hellstrom5aa80c72006-12-20 16:33:41 +01001202
Linus Torvalds1da177e2005-04-16 15:20:36 -07001203 temp = agp_bridge->current_size;
1204 num_entries = A_SIZE_FIX(temp)->num_entries;
1205
Wang Zhenyuc4ca8812007-05-30 09:40:46 +08001206 if (pg_start < intel_private.gtt_entries) {
Bjorn Helgaase3cf6952008-07-30 12:26:51 -07001207 dev_printk(KERN_DEBUG, &intel_private.pcidev->dev,
1208 "pg_start == 0x%.8lx, intel_private.gtt_entries == 0x%.8x\n",
1209 pg_start, intel_private.gtt_entries);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001210
Bjorn Helgaase3cf6952008-07-30 12:26:51 -07001211 dev_info(&intel_private.pcidev->dev,
1212 "trying to insert into local/stolen memory\n");
Thomas Hellstroma030ce42007-01-23 10:33:43 +01001213 goto out_err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001214 }
1215
1216 if ((pg_start + mem->page_count) > num_entries)
Thomas Hellstroma030ce42007-01-23 10:33:43 +01001217 goto out_err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001218
Zhenyu Wang17661682009-07-27 12:59:57 +01001219 /* The i915 can't check the GTT for entries since it's read only;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001220 * depend on the caller to make the correct offset decisions.
1221 */
1222
Thomas Hellstroma030ce42007-01-23 10:33:43 +01001223 if (type != mem->type)
1224 goto out_err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001225
Thomas Hellstroma030ce42007-01-23 10:33:43 +01001226 mask_type = agp_bridge->driver->agp_type_to_mask_type(agp_bridge, type);
1227
1228 if (mask_type != 0 && mask_type != AGP_PHYS_MEMORY &&
1229 mask_type != INTEL_AGP_CACHED_MEMORY)
1230 goto out_err;
1231
1232 if (!mem->is_flushed)
Thomas Hellstrom5aa80c72006-12-20 16:33:41 +01001233 global_cache_flush();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001234
Zhenyu Wang17661682009-07-27 12:59:57 +01001235 intel_agp_insert_sg_entries(mem, pg_start, mask_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001236 agp_bridge->driver->tlb_flush(mem);
Thomas Hellstroma030ce42007-01-23 10:33:43 +01001237
1238 out:
1239 ret = 0;
1240 out_err:
Dave Airlie9516b032008-06-19 10:42:17 +10001241 mem->is_flushed = true;
Thomas Hellstroma030ce42007-01-23 10:33:43 +01001242 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001243}
1244
Dave Airlief011ae72008-01-25 11:23:04 +10001245static int intel_i915_remove_entries(struct agp_memory *mem, off_t pg_start,
1246 int type)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001247{
1248 int i;
1249
Thomas Hellstrom5aa80c72006-12-20 16:33:41 +01001250 if (mem->page_count == 0)
1251 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001252
Wang Zhenyuc4ca8812007-05-30 09:40:46 +08001253 if (pg_start < intel_private.gtt_entries) {
Bjorn Helgaase3cf6952008-07-30 12:26:51 -07001254 dev_info(&intel_private.pcidev->dev,
1255 "trying to disable local/stolen memory\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001256 return -EINVAL;
1257 }
1258
Dave Airlief011ae72008-01-25 11:23:04 +10001259 for (i = pg_start; i < (mem->page_count + pg_start); i++)
Wang Zhenyuc4ca8812007-05-30 09:40:46 +08001260 writel(agp_bridge->scratch_page, intel_private.gtt+i);
Dave Airlief011ae72008-01-25 11:23:04 +10001261
Wang Zhenyuc4ca8812007-05-30 09:40:46 +08001262 readl(intel_private.gtt+i-1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001263
Linus Torvalds1da177e2005-04-16 15:20:36 -07001264 agp_bridge->driver->tlb_flush(mem);
1265 return 0;
1266}
1267
Eric Anholtc41e0de2006-12-19 12:57:24 -08001268/* Return the aperture size by just checking the resource length. The effect
1269 * described in the spec of the MSAC registers is just changing of the
1270 * resource size.
1271 */
1272static int intel_i9xx_fetch_size(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001273{
Ahmed S. Darwish1eaf1222007-02-06 18:08:28 +02001274 int num_sizes = ARRAY_SIZE(intel_i830_sizes);
Eric Anholtc41e0de2006-12-19 12:57:24 -08001275 int aper_size; /* size in megabytes */
1276 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001277
Wang Zhenyuc4ca8812007-05-30 09:40:46 +08001278 aper_size = pci_resource_len(intel_private.pcidev, 2) / MB(1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001279
Eric Anholtc41e0de2006-12-19 12:57:24 -08001280 for (i = 0; i < num_sizes; i++) {
1281 if (aper_size == intel_i830_sizes[i].size) {
1282 agp_bridge->current_size = intel_i830_sizes + i;
1283 agp_bridge->previous_size = agp_bridge->current_size;
1284 return aper_size;
1285 }
1286 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001287
Eric Anholtc41e0de2006-12-19 12:57:24 -08001288 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001289}
1290
1291/* The intel i915 automatically initializes the agp aperture during POST.
1292 * Use the memory already set aside for in the GTT.
1293 */
1294static int intel_i915_create_gatt_table(struct agp_bridge_data *bridge)
1295{
1296 int page_order;
1297 struct aper_size_info_fixed *size;
1298 int num_entries;
1299 u32 temp, temp2;
Zhenyu Wang47406222007-09-11 15:23:58 -07001300 int gtt_map_size = 256 * 1024;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001301
1302 size = agp_bridge->current_size;
1303 page_order = size->page_order;
1304 num_entries = size->num_entries;
1305 agp_bridge->gatt_table_real = NULL;
1306
Wang Zhenyuc4ca8812007-05-30 09:40:46 +08001307 pci_read_config_dword(intel_private.pcidev, I915_MMADDR, &temp);
Dave Airlief011ae72008-01-25 11:23:04 +10001308 pci_read_config_dword(intel_private.pcidev, I915_PTEADDR, &temp2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001309
Zhenyu Wang47406222007-09-11 15:23:58 -07001310 if (IS_G33)
1311 gtt_map_size = 1024 * 1024; /* 1M on G33 */
1312 intel_private.gtt = ioremap(temp2, gtt_map_size);
Wang Zhenyuc4ca8812007-05-30 09:40:46 +08001313 if (!intel_private.gtt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001314 return -ENOMEM;
1315
David Woodhousefc619012009-12-02 11:00:05 +00001316 intel_private.gtt_total_size = gtt_map_size / 4;
1317
Linus Torvalds1da177e2005-04-16 15:20:36 -07001318 temp &= 0xfff80000;
1319
Dave Airlief011ae72008-01-25 11:23:04 +10001320 intel_private.registers = ioremap(temp, 128 * 4096);
Scott Thompson5bdbc7d2007-08-25 18:14:00 +10001321 if (!intel_private.registers) {
1322 iounmap(intel_private.gtt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001323 return -ENOMEM;
Scott Thompson5bdbc7d2007-08-25 18:14:00 +10001324 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001325
Wang Zhenyuc4ca8812007-05-30 09:40:46 +08001326 temp = readl(intel_private.registers+I810_PGETBL_CTL) & 0xfffff000;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001327 global_cache_flush(); /* FIXME: ? */
1328
1329 /* we have to call this as early as possible after the MMIO base address is known */
1330 intel_i830_init_gtt_entries();
1331
1332 agp_bridge->gatt_table = NULL;
1333
1334 agp_bridge->gatt_bus_addr = temp;
1335
1336 return 0;
1337}
Linus Torvalds7d915a32006-11-22 09:37:54 -08001338
1339/*
1340 * The i965 supports 36-bit physical addresses, but to keep
1341 * the format of the GTT the same, the bits that don't fit
1342 * in a 32-bit word are shifted down to bits 4..7.
1343 *
1344 * Gcc is smart enough to notice that "(addr >> 28) & 0xf0"
1345 * is always zero on 32-bit architectures, so no need to make
1346 * this conditional.
1347 */
1348static unsigned long intel_i965_mask_memory(struct agp_bridge_data *bridge,
David Woodhouse2a4ceb62009-07-27 10:27:29 +01001349 dma_addr_t addr, int type)
Linus Torvalds7d915a32006-11-22 09:37:54 -08001350{
1351 /* Shift high bits down */
1352 addr |= (addr >> 28) & 0xf0;
1353
1354 /* Type checking must be done elsewhere */
1355 return addr | bridge->driver->masks[type].mask;
1356}
1357
Zhenyu Wang25ce77a2008-06-19 14:17:58 +10001358static void intel_i965_get_gtt_range(int *gtt_offset, int *gtt_size)
1359{
1360 switch (agp_bridge->dev->device) {
Zhenyu Wang99d32bd2008-07-30 12:26:50 -07001361 case PCI_DEVICE_ID_INTEL_GM45_HB:
Adam Jackson107f5172009-12-03 17:14:41 -05001362 case PCI_DEVICE_ID_INTEL_EAGLELAKE_HB:
Zhenyu Wang25ce77a2008-06-19 14:17:58 +10001363 case PCI_DEVICE_ID_INTEL_Q45_HB:
1364 case PCI_DEVICE_ID_INTEL_G45_HB:
Zhenyu Wanga50ccc62008-11-17 14:39:00 +08001365 case PCI_DEVICE_ID_INTEL_G41_HB:
Fabian Henze38d8a952009-09-08 00:59:58 +08001366 case PCI_DEVICE_ID_INTEL_B43_HB:
Adam Jackson107f5172009-12-03 17:14:41 -05001367 case PCI_DEVICE_ID_INTEL_IRONLAKE_D_HB:
1368 case PCI_DEVICE_ID_INTEL_IRONLAKE_M_HB:
1369 case PCI_DEVICE_ID_INTEL_IRONLAKE_MA_HB:
Zhenyu Wang25ce77a2008-06-19 14:17:58 +10001370 *gtt_offset = *gtt_size = MB(2);
1371 break;
1372 default:
1373 *gtt_offset = *gtt_size = KB(512);
1374 }
1375}
1376
Eric Anholt65c25aa2006-09-06 11:57:18 -04001377/* The intel i965 automatically initializes the agp aperture during POST.
Eric Anholtc41e0de2006-12-19 12:57:24 -08001378 * Use the memory already set aside for in the GTT.
1379 */
Eric Anholt65c25aa2006-09-06 11:57:18 -04001380static int intel_i965_create_gatt_table(struct agp_bridge_data *bridge)
1381{
Dave Airlie62c96b92008-06-19 14:27:53 +10001382 int page_order;
1383 struct aper_size_info_fixed *size;
1384 int num_entries;
1385 u32 temp;
1386 int gtt_offset, gtt_size;
Eric Anholt65c25aa2006-09-06 11:57:18 -04001387
Dave Airlie62c96b92008-06-19 14:27:53 +10001388 size = agp_bridge->current_size;
1389 page_order = size->page_order;
1390 num_entries = size->num_entries;
1391 agp_bridge->gatt_table_real = NULL;
Eric Anholt65c25aa2006-09-06 11:57:18 -04001392
Dave Airlie62c96b92008-06-19 14:27:53 +10001393 pci_read_config_dword(intel_private.pcidev, I915_MMADDR, &temp);
Eric Anholt65c25aa2006-09-06 11:57:18 -04001394
Dave Airlie62c96b92008-06-19 14:27:53 +10001395 temp &= 0xfff00000;
Eric Anholt65c25aa2006-09-06 11:57:18 -04001396
Zhenyu Wang25ce77a2008-06-19 14:17:58 +10001397 intel_i965_get_gtt_range(&gtt_offset, &gtt_size);
Eric Anholt65c25aa2006-09-06 11:57:18 -04001398
Dave Airlie62c96b92008-06-19 14:27:53 +10001399 intel_private.gtt = ioremap((temp + gtt_offset) , gtt_size);
Eric Anholt65c25aa2006-09-06 11:57:18 -04001400
Dave Airlie62c96b92008-06-19 14:27:53 +10001401 if (!intel_private.gtt)
1402 return -ENOMEM;
Zhenyu Wang4e8b6e22008-01-23 14:54:37 +10001403
David Woodhousefc619012009-12-02 11:00:05 +00001404 intel_private.gtt_total_size = gtt_size / 4;
1405
Dave Airlie62c96b92008-06-19 14:27:53 +10001406 intel_private.registers = ioremap(temp, 128 * 4096);
1407 if (!intel_private.registers) {
Scott Thompson5bdbc7d2007-08-25 18:14:00 +10001408 iounmap(intel_private.gtt);
1409 return -ENOMEM;
1410 }
Eric Anholt65c25aa2006-09-06 11:57:18 -04001411
Dave Airlie62c96b92008-06-19 14:27:53 +10001412 temp = readl(intel_private.registers+I810_PGETBL_CTL) & 0xfffff000;
1413 global_cache_flush(); /* FIXME: ? */
Eric Anholt65c25aa2006-09-06 11:57:18 -04001414
Dave Airlie62c96b92008-06-19 14:27:53 +10001415 /* we have to call this as early as possible after the MMIO base address is known */
1416 intel_i830_init_gtt_entries();
Eric Anholt65c25aa2006-09-06 11:57:18 -04001417
Dave Airlie62c96b92008-06-19 14:27:53 +10001418 agp_bridge->gatt_table = NULL;
Eric Anholt65c25aa2006-09-06 11:57:18 -04001419
Dave Airlie62c96b92008-06-19 14:27:53 +10001420 agp_bridge->gatt_bus_addr = temp;
Eric Anholt65c25aa2006-09-06 11:57:18 -04001421
Dave Airlie62c96b92008-06-19 14:27:53 +10001422 return 0;
Eric Anholt65c25aa2006-09-06 11:57:18 -04001423}
1424
Linus Torvalds1da177e2005-04-16 15:20:36 -07001425
1426static int intel_fetch_size(void)
1427{
1428 int i;
1429 u16 temp;
1430 struct aper_size_info_16 *values;
1431
1432 pci_read_config_word(agp_bridge->dev, INTEL_APSIZE, &temp);
1433 values = A_SIZE_16(agp_bridge->driver->aperture_sizes);
1434
1435 for (i = 0; i < agp_bridge->driver->num_aperture_sizes; i++) {
1436 if (temp == values[i].size_value) {
1437 agp_bridge->previous_size = agp_bridge->current_size = (void *) (values + i);
1438 agp_bridge->aperture_size_idx = i;
1439 return values[i].size;
1440 }
1441 }
1442
1443 return 0;
1444}
1445
1446static int __intel_8xx_fetch_size(u8 temp)
1447{
1448 int i;
1449 struct aper_size_info_8 *values;
1450
1451 values = A_SIZE_8(agp_bridge->driver->aperture_sizes);
1452
1453 for (i = 0; i < agp_bridge->driver->num_aperture_sizes; i++) {
1454 if (temp == values[i].size_value) {
1455 agp_bridge->previous_size =
1456 agp_bridge->current_size = (void *) (values + i);
1457 agp_bridge->aperture_size_idx = i;
1458 return values[i].size;
1459 }
1460 }
1461 return 0;
1462}
1463
1464static int intel_8xx_fetch_size(void)
1465{
1466 u8 temp;
1467
1468 pci_read_config_byte(agp_bridge->dev, INTEL_APSIZE, &temp);
1469 return __intel_8xx_fetch_size(temp);
1470}
1471
1472static int intel_815_fetch_size(void)
1473{
1474 u8 temp;
1475
1476 /* Intel 815 chipsets have a _weird_ APSIZE register with only
1477 * one non-reserved bit, so mask the others out ... */
1478 pci_read_config_byte(agp_bridge->dev, INTEL_APSIZE, &temp);
1479 temp &= (1 << 3);
1480
1481 return __intel_8xx_fetch_size(temp);
1482}
1483
1484static void intel_tlbflush(struct agp_memory *mem)
1485{
1486 pci_write_config_dword(agp_bridge->dev, INTEL_AGPCTRL, 0x2200);
1487 pci_write_config_dword(agp_bridge->dev, INTEL_AGPCTRL, 0x2280);
1488}
1489
1490
1491static void intel_8xx_tlbflush(struct agp_memory *mem)
1492{
1493 u32 temp;
1494 pci_read_config_dword(agp_bridge->dev, INTEL_AGPCTRL, &temp);
1495 pci_write_config_dword(agp_bridge->dev, INTEL_AGPCTRL, temp & ~(1 << 7));
1496 pci_read_config_dword(agp_bridge->dev, INTEL_AGPCTRL, &temp);
1497 pci_write_config_dword(agp_bridge->dev, INTEL_AGPCTRL, temp | (1 << 7));
1498}
1499
1500
1501static void intel_cleanup(void)
1502{
1503 u16 temp;
1504 struct aper_size_info_16 *previous_size;
1505
1506 previous_size = A_SIZE_16(agp_bridge->previous_size);
1507 pci_read_config_word(agp_bridge->dev, INTEL_NBXCFG, &temp);
1508 pci_write_config_word(agp_bridge->dev, INTEL_NBXCFG, temp & ~(1 << 9));
1509 pci_write_config_word(agp_bridge->dev, INTEL_APSIZE, previous_size->size_value);
1510}
1511
1512
1513static void intel_8xx_cleanup(void)
1514{
1515 u16 temp;
1516 struct aper_size_info_8 *previous_size;
1517
1518 previous_size = A_SIZE_8(agp_bridge->previous_size);
1519 pci_read_config_word(agp_bridge->dev, INTEL_NBXCFG, &temp);
1520 pci_write_config_word(agp_bridge->dev, INTEL_NBXCFG, temp & ~(1 << 9));
1521 pci_write_config_byte(agp_bridge->dev, INTEL_APSIZE, previous_size->size_value);
1522}
1523
1524
1525static int intel_configure(void)
1526{
1527 u32 temp;
1528 u16 temp2;
1529 struct aper_size_info_16 *current_size;
1530
1531 current_size = A_SIZE_16(agp_bridge->current_size);
1532
1533 /* aperture size */
1534 pci_write_config_word(agp_bridge->dev, INTEL_APSIZE, current_size->size_value);
1535
1536 /* address to map to */
1537 pci_read_config_dword(agp_bridge->dev, AGP_APBASE, &temp);
1538 agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
1539
1540 /* attbase - aperture base */
1541 pci_write_config_dword(agp_bridge->dev, INTEL_ATTBASE, agp_bridge->gatt_bus_addr);
1542
1543 /* agpctrl */
1544 pci_write_config_dword(agp_bridge->dev, INTEL_AGPCTRL, 0x2280);
1545
1546 /* paccfg/nbxcfg */
1547 pci_read_config_word(agp_bridge->dev, INTEL_NBXCFG, &temp2);
1548 pci_write_config_word(agp_bridge->dev, INTEL_NBXCFG,
1549 (temp2 & ~(1 << 10)) | (1 << 9));
1550 /* clear any possible error conditions */
1551 pci_write_config_byte(agp_bridge->dev, INTEL_ERRSTS + 1, 7);
1552 return 0;
1553}
1554
1555static int intel_815_configure(void)
1556{
1557 u32 temp, addr;
1558 u8 temp2;
1559 struct aper_size_info_8 *current_size;
1560
1561 /* attbase - aperture base */
1562 /* the Intel 815 chipset spec. says that bits 29-31 in the
1563 * ATTBASE register are reserved -> try not to write them */
1564 if (agp_bridge->gatt_bus_addr & INTEL_815_ATTBASE_MASK) {
Bjorn Helgaase3cf6952008-07-30 12:26:51 -07001565 dev_emerg(&agp_bridge->dev->dev, "gatt bus addr too high");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001566 return -EINVAL;
1567 }
1568
1569 current_size = A_SIZE_8(agp_bridge->current_size);
1570
1571 /* aperture size */
1572 pci_write_config_byte(agp_bridge->dev, INTEL_APSIZE,
1573 current_size->size_value);
1574
1575 /* address to map to */
1576 pci_read_config_dword(agp_bridge->dev, AGP_APBASE, &temp);
1577 agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
1578
1579 pci_read_config_dword(agp_bridge->dev, INTEL_ATTBASE, &addr);
1580 addr &= INTEL_815_ATTBASE_MASK;
1581 addr |= agp_bridge->gatt_bus_addr;
1582 pci_write_config_dword(agp_bridge->dev, INTEL_ATTBASE, addr);
1583
1584 /* agpctrl */
1585 pci_write_config_dword(agp_bridge->dev, INTEL_AGPCTRL, 0x0000);
1586
1587 /* apcont */
1588 pci_read_config_byte(agp_bridge->dev, INTEL_815_APCONT, &temp2);
1589 pci_write_config_byte(agp_bridge->dev, INTEL_815_APCONT, temp2 | (1 << 1));
1590
1591 /* clear any possible error conditions */
1592 /* Oddness : this chipset seems to have no ERRSTS register ! */
1593 return 0;
1594}
1595
1596static void intel_820_tlbflush(struct agp_memory *mem)
1597{
1598 return;
1599}
1600
1601static void intel_820_cleanup(void)
1602{
1603 u8 temp;
1604 struct aper_size_info_8 *previous_size;
1605
1606 previous_size = A_SIZE_8(agp_bridge->previous_size);
1607 pci_read_config_byte(agp_bridge->dev, INTEL_I820_RDCR, &temp);
1608 pci_write_config_byte(agp_bridge->dev, INTEL_I820_RDCR,
1609 temp & ~(1 << 1));
1610 pci_write_config_byte(agp_bridge->dev, INTEL_APSIZE,
1611 previous_size->size_value);
1612}
1613
1614
1615static int intel_820_configure(void)
1616{
1617 u32 temp;
1618 u8 temp2;
1619 struct aper_size_info_8 *current_size;
1620
1621 current_size = A_SIZE_8(agp_bridge->current_size);
1622
1623 /* aperture size */
1624 pci_write_config_byte(agp_bridge->dev, INTEL_APSIZE, current_size->size_value);
1625
1626 /* address to map to */
1627 pci_read_config_dword(agp_bridge->dev, AGP_APBASE, &temp);
1628 agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
1629
1630 /* attbase - aperture base */
1631 pci_write_config_dword(agp_bridge->dev, INTEL_ATTBASE, agp_bridge->gatt_bus_addr);
1632
1633 /* agpctrl */
1634 pci_write_config_dword(agp_bridge->dev, INTEL_AGPCTRL, 0x0000);
1635
1636 /* global enable aperture access */
1637 /* This flag is not accessed through MCHCFG register as in */
1638 /* i850 chipset. */
1639 pci_read_config_byte(agp_bridge->dev, INTEL_I820_RDCR, &temp2);
1640 pci_write_config_byte(agp_bridge->dev, INTEL_I820_RDCR, temp2 | (1 << 1));
1641 /* clear any possible AGP-related error conditions */
1642 pci_write_config_word(agp_bridge->dev, INTEL_I820_ERRSTS, 0x001c);
1643 return 0;
1644}
1645
1646static int intel_840_configure(void)
1647{
1648 u32 temp;
1649 u16 temp2;
1650 struct aper_size_info_8 *current_size;
1651
1652 current_size = A_SIZE_8(agp_bridge->current_size);
1653
1654 /* aperture size */
1655 pci_write_config_byte(agp_bridge->dev, INTEL_APSIZE, current_size->size_value);
1656
1657 /* address to map to */
1658 pci_read_config_dword(agp_bridge->dev, AGP_APBASE, &temp);
1659 agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
1660
1661 /* attbase - aperture base */
1662 pci_write_config_dword(agp_bridge->dev, INTEL_ATTBASE, agp_bridge->gatt_bus_addr);
1663
1664 /* agpctrl */
1665 pci_write_config_dword(agp_bridge->dev, INTEL_AGPCTRL, 0x0000);
1666
1667 /* mcgcfg */
1668 pci_read_config_word(agp_bridge->dev, INTEL_I840_MCHCFG, &temp2);
1669 pci_write_config_word(agp_bridge->dev, INTEL_I840_MCHCFG, temp2 | (1 << 9));
1670 /* clear any possible error conditions */
1671 pci_write_config_word(agp_bridge->dev, INTEL_I840_ERRSTS, 0xc000);
1672 return 0;
1673}
1674
1675static int intel_845_configure(void)
1676{
1677 u32 temp;
1678 u8 temp2;
1679 struct aper_size_info_8 *current_size;
1680
1681 current_size = A_SIZE_8(agp_bridge->current_size);
1682
1683 /* aperture size */
1684 pci_write_config_byte(agp_bridge->dev, INTEL_APSIZE, current_size->size_value);
1685
Matthew Garrettb0825482005-07-29 14:03:39 -07001686 if (agp_bridge->apbase_config != 0) {
1687 pci_write_config_dword(agp_bridge->dev, AGP_APBASE,
1688 agp_bridge->apbase_config);
1689 } else {
1690 /* address to map to */
1691 pci_read_config_dword(agp_bridge->dev, AGP_APBASE, &temp);
1692 agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
1693 agp_bridge->apbase_config = temp;
1694 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001695
1696 /* attbase - aperture base */
1697 pci_write_config_dword(agp_bridge->dev, INTEL_ATTBASE, agp_bridge->gatt_bus_addr);
1698
1699 /* agpctrl */
1700 pci_write_config_dword(agp_bridge->dev, INTEL_AGPCTRL, 0x0000);
1701
1702 /* agpm */
1703 pci_read_config_byte(agp_bridge->dev, INTEL_I845_AGPM, &temp2);
1704 pci_write_config_byte(agp_bridge->dev, INTEL_I845_AGPM, temp2 | (1 << 1));
1705 /* clear any possible error conditions */
1706 pci_write_config_word(agp_bridge->dev, INTEL_I845_ERRSTS, 0x001c);
Dave Airlie2162e6a2007-11-21 16:36:31 +10001707
1708 intel_i830_setup_flush();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001709 return 0;
1710}
1711
1712static int intel_850_configure(void)
1713{
1714 u32 temp;
1715 u16 temp2;
1716 struct aper_size_info_8 *current_size;
1717
1718 current_size = A_SIZE_8(agp_bridge->current_size);
1719
1720 /* aperture size */
1721 pci_write_config_byte(agp_bridge->dev, INTEL_APSIZE, current_size->size_value);
1722
1723 /* address to map to */
1724 pci_read_config_dword(agp_bridge->dev, AGP_APBASE, &temp);
1725 agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
1726
1727 /* attbase - aperture base */
1728 pci_write_config_dword(agp_bridge->dev, INTEL_ATTBASE, agp_bridge->gatt_bus_addr);
1729
1730 /* agpctrl */
1731 pci_write_config_dword(agp_bridge->dev, INTEL_AGPCTRL, 0x0000);
1732
1733 /* mcgcfg */
1734 pci_read_config_word(agp_bridge->dev, INTEL_I850_MCHCFG, &temp2);
1735 pci_write_config_word(agp_bridge->dev, INTEL_I850_MCHCFG, temp2 | (1 << 9));
1736 /* clear any possible AGP-related error conditions */
1737 pci_write_config_word(agp_bridge->dev, INTEL_I850_ERRSTS, 0x001c);
1738 return 0;
1739}
1740
1741static int intel_860_configure(void)
1742{
1743 u32 temp;
1744 u16 temp2;
1745 struct aper_size_info_8 *current_size;
1746
1747 current_size = A_SIZE_8(agp_bridge->current_size);
1748
1749 /* aperture size */
1750 pci_write_config_byte(agp_bridge->dev, INTEL_APSIZE, current_size->size_value);
1751
1752 /* address to map to */
1753 pci_read_config_dword(agp_bridge->dev, AGP_APBASE, &temp);
1754 agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
1755
1756 /* attbase - aperture base */
1757 pci_write_config_dword(agp_bridge->dev, INTEL_ATTBASE, agp_bridge->gatt_bus_addr);
1758
1759 /* agpctrl */
1760 pci_write_config_dword(agp_bridge->dev, INTEL_AGPCTRL, 0x0000);
1761
1762 /* mcgcfg */
1763 pci_read_config_word(agp_bridge->dev, INTEL_I860_MCHCFG, &temp2);
1764 pci_write_config_word(agp_bridge->dev, INTEL_I860_MCHCFG, temp2 | (1 << 9));
1765 /* clear any possible AGP-related error conditions */
1766 pci_write_config_word(agp_bridge->dev, INTEL_I860_ERRSTS, 0xf700);
1767 return 0;
1768}
1769
1770static int intel_830mp_configure(void)
1771{
1772 u32 temp;
1773 u16 temp2;
1774 struct aper_size_info_8 *current_size;
1775
1776 current_size = A_SIZE_8(agp_bridge->current_size);
1777
1778 /* aperture size */
1779 pci_write_config_byte(agp_bridge->dev, INTEL_APSIZE, current_size->size_value);
1780
1781 /* address to map to */
1782 pci_read_config_dword(agp_bridge->dev, AGP_APBASE, &temp);
1783 agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
1784
1785 /* attbase - aperture base */
1786 pci_write_config_dword(agp_bridge->dev, INTEL_ATTBASE, agp_bridge->gatt_bus_addr);
1787
1788 /* agpctrl */
1789 pci_write_config_dword(agp_bridge->dev, INTEL_AGPCTRL, 0x0000);
1790
1791 /* gmch */
1792 pci_read_config_word(agp_bridge->dev, INTEL_NBXCFG, &temp2);
1793 pci_write_config_word(agp_bridge->dev, INTEL_NBXCFG, temp2 | (1 << 9));
1794 /* clear any possible AGP-related error conditions */
1795 pci_write_config_word(agp_bridge->dev, INTEL_I830_ERRSTS, 0x1c);
1796 return 0;
1797}
1798
1799static int intel_7505_configure(void)
1800{
1801 u32 temp;
1802 u16 temp2;
1803 struct aper_size_info_8 *current_size;
1804
1805 current_size = A_SIZE_8(agp_bridge->current_size);
1806
1807 /* aperture size */
1808 pci_write_config_byte(agp_bridge->dev, INTEL_APSIZE, current_size->size_value);
1809
1810 /* address to map to */
1811 pci_read_config_dword(agp_bridge->dev, AGP_APBASE, &temp);
1812 agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
1813
1814 /* attbase - aperture base */
1815 pci_write_config_dword(agp_bridge->dev, INTEL_ATTBASE, agp_bridge->gatt_bus_addr);
1816
1817 /* agpctrl */
1818 pci_write_config_dword(agp_bridge->dev, INTEL_AGPCTRL, 0x0000);
1819
1820 /* mchcfg */
1821 pci_read_config_word(agp_bridge->dev, INTEL_I7505_MCHCFG, &temp2);
1822 pci_write_config_word(agp_bridge->dev, INTEL_I7505_MCHCFG, temp2 | (1 << 9));
1823
1824 return 0;
1825}
1826
1827/* Setup function */
Dave Jonese5524f32007-02-22 18:41:28 -05001828static const struct gatt_mask intel_generic_masks[] =
Linus Torvalds1da177e2005-04-16 15:20:36 -07001829{
1830 {.mask = 0x00000017, .type = 0}
1831};
1832
Dave Jonese5524f32007-02-22 18:41:28 -05001833static const struct aper_size_info_8 intel_815_sizes[2] =
Linus Torvalds1da177e2005-04-16 15:20:36 -07001834{
1835 {64, 16384, 4, 0},
1836 {32, 8192, 3, 8},
1837};
1838
Dave Jonese5524f32007-02-22 18:41:28 -05001839static const struct aper_size_info_8 intel_8xx_sizes[7] =
Linus Torvalds1da177e2005-04-16 15:20:36 -07001840{
1841 {256, 65536, 6, 0},
1842 {128, 32768, 5, 32},
1843 {64, 16384, 4, 48},
1844 {32, 8192, 3, 56},
1845 {16, 4096, 2, 60},
1846 {8, 2048, 1, 62},
1847 {4, 1024, 0, 63}
1848};
1849
Dave Jonese5524f32007-02-22 18:41:28 -05001850static const struct aper_size_info_16 intel_generic_sizes[7] =
Linus Torvalds1da177e2005-04-16 15:20:36 -07001851{
1852 {256, 65536, 6, 0},
1853 {128, 32768, 5, 32},
1854 {64, 16384, 4, 48},
1855 {32, 8192, 3, 56},
1856 {16, 4096, 2, 60},
1857 {8, 2048, 1, 62},
1858 {4, 1024, 0, 63}
1859};
1860
Dave Jonese5524f32007-02-22 18:41:28 -05001861static const struct aper_size_info_8 intel_830mp_sizes[4] =
Linus Torvalds1da177e2005-04-16 15:20:36 -07001862{
1863 {256, 65536, 6, 0},
1864 {128, 32768, 5, 32},
1865 {64, 16384, 4, 48},
1866 {32, 8192, 3, 56}
1867};
1868
Dave Jonese5524f32007-02-22 18:41:28 -05001869static const struct agp_bridge_driver intel_generic_driver = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001870 .owner = THIS_MODULE,
1871 .aperture_sizes = intel_generic_sizes,
1872 .size_type = U16_APER_SIZE,
1873 .num_aperture_sizes = 7,
1874 .configure = intel_configure,
1875 .fetch_size = intel_fetch_size,
1876 .cleanup = intel_cleanup,
1877 .tlb_flush = intel_tlbflush,
1878 .mask_memory = agp_generic_mask_memory,
1879 .masks = intel_generic_masks,
1880 .agp_enable = agp_generic_enable,
1881 .cache_flush = global_cache_flush,
1882 .create_gatt_table = agp_generic_create_gatt_table,
1883 .free_gatt_table = agp_generic_free_gatt_table,
1884 .insert_memory = agp_generic_insert_memory,
1885 .remove_memory = agp_generic_remove_memory,
1886 .alloc_by_type = agp_generic_alloc_by_type,
1887 .free_by_type = agp_generic_free_by_type,
1888 .agp_alloc_page = agp_generic_alloc_page,
Shaohua Li37acee12008-08-21 10:46:11 +08001889 .agp_alloc_pages = agp_generic_alloc_pages,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001890 .agp_destroy_page = agp_generic_destroy_page,
Shaohua Libd079282008-08-21 10:46:17 +08001891 .agp_destroy_pages = agp_generic_destroy_pages,
Thomas Hellstroma030ce42007-01-23 10:33:43 +01001892 .agp_type_to_mask_type = agp_generic_type_to_mask_type,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001893};
1894
Dave Jonese5524f32007-02-22 18:41:28 -05001895static const struct agp_bridge_driver intel_810_driver = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001896 .owner = THIS_MODULE,
1897 .aperture_sizes = intel_i810_sizes,
1898 .size_type = FIXED_APER_SIZE,
1899 .num_aperture_sizes = 2,
Joe Perchesc7258012008-03-26 14:10:02 -07001900 .needs_scratch_page = true,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001901 .configure = intel_i810_configure,
1902 .fetch_size = intel_i810_fetch_size,
1903 .cleanup = intel_i810_cleanup,
1904 .tlb_flush = intel_i810_tlbflush,
1905 .mask_memory = intel_i810_mask_memory,
1906 .masks = intel_i810_masks,
1907 .agp_enable = intel_i810_agp_enable,
1908 .cache_flush = global_cache_flush,
1909 .create_gatt_table = agp_generic_create_gatt_table,
1910 .free_gatt_table = agp_generic_free_gatt_table,
1911 .insert_memory = intel_i810_insert_entries,
1912 .remove_memory = intel_i810_remove_entries,
1913 .alloc_by_type = intel_i810_alloc_by_type,
1914 .free_by_type = intel_i810_free_by_type,
1915 .agp_alloc_page = agp_generic_alloc_page,
Shaohua Li37acee12008-08-21 10:46:11 +08001916 .agp_alloc_pages = agp_generic_alloc_pages,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001917 .agp_destroy_page = agp_generic_destroy_page,
Shaohua Libd079282008-08-21 10:46:17 +08001918 .agp_destroy_pages = agp_generic_destroy_pages,
Thomas Hellstroma030ce42007-01-23 10:33:43 +01001919 .agp_type_to_mask_type = agp_generic_type_to_mask_type,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001920};
1921
Dave Jonese5524f32007-02-22 18:41:28 -05001922static const struct agp_bridge_driver intel_815_driver = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001923 .owner = THIS_MODULE,
1924 .aperture_sizes = intel_815_sizes,
1925 .size_type = U8_APER_SIZE,
1926 .num_aperture_sizes = 2,
1927 .configure = intel_815_configure,
1928 .fetch_size = intel_815_fetch_size,
1929 .cleanup = intel_8xx_cleanup,
1930 .tlb_flush = intel_8xx_tlbflush,
1931 .mask_memory = agp_generic_mask_memory,
1932 .masks = intel_generic_masks,
1933 .agp_enable = agp_generic_enable,
1934 .cache_flush = global_cache_flush,
1935 .create_gatt_table = agp_generic_create_gatt_table,
1936 .free_gatt_table = agp_generic_free_gatt_table,
1937 .insert_memory = agp_generic_insert_memory,
1938 .remove_memory = agp_generic_remove_memory,
1939 .alloc_by_type = agp_generic_alloc_by_type,
1940 .free_by_type = agp_generic_free_by_type,
1941 .agp_alloc_page = agp_generic_alloc_page,
Shaohua Li37acee12008-08-21 10:46:11 +08001942 .agp_alloc_pages = agp_generic_alloc_pages,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001943 .agp_destroy_page = agp_generic_destroy_page,
Shaohua Libd079282008-08-21 10:46:17 +08001944 .agp_destroy_pages = agp_generic_destroy_pages,
Dave Airlie62c96b92008-06-19 14:27:53 +10001945 .agp_type_to_mask_type = agp_generic_type_to_mask_type,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001946};
1947
Dave Jonese5524f32007-02-22 18:41:28 -05001948static const struct agp_bridge_driver intel_830_driver = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001949 .owner = THIS_MODULE,
1950 .aperture_sizes = intel_i830_sizes,
1951 .size_type = FIXED_APER_SIZE,
Dave Jonesc14635e2006-09-06 11:59:35 -04001952 .num_aperture_sizes = 4,
Joe Perchesc7258012008-03-26 14:10:02 -07001953 .needs_scratch_page = true,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001954 .configure = intel_i830_configure,
1955 .fetch_size = intel_i830_fetch_size,
1956 .cleanup = intel_i830_cleanup,
1957 .tlb_flush = intel_i810_tlbflush,
1958 .mask_memory = intel_i810_mask_memory,
1959 .masks = intel_i810_masks,
1960 .agp_enable = intel_i810_agp_enable,
1961 .cache_flush = global_cache_flush,
1962 .create_gatt_table = intel_i830_create_gatt_table,
1963 .free_gatt_table = intel_i830_free_gatt_table,
1964 .insert_memory = intel_i830_insert_entries,
1965 .remove_memory = intel_i830_remove_entries,
1966 .alloc_by_type = intel_i830_alloc_by_type,
1967 .free_by_type = intel_i810_free_by_type,
1968 .agp_alloc_page = agp_generic_alloc_page,
Shaohua Li37acee12008-08-21 10:46:11 +08001969 .agp_alloc_pages = agp_generic_alloc_pages,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001970 .agp_destroy_page = agp_generic_destroy_page,
Shaohua Libd079282008-08-21 10:46:17 +08001971 .agp_destroy_pages = agp_generic_destroy_pages,
Thomas Hellstroma030ce42007-01-23 10:33:43 +01001972 .agp_type_to_mask_type = intel_i830_type_to_mask_type,
Dave Airlie2162e6a2007-11-21 16:36:31 +10001973 .chipset_flush = intel_i830_chipset_flush,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001974};
1975
Dave Jonese5524f32007-02-22 18:41:28 -05001976static const struct agp_bridge_driver intel_820_driver = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001977 .owner = THIS_MODULE,
1978 .aperture_sizes = intel_8xx_sizes,
1979 .size_type = U8_APER_SIZE,
1980 .num_aperture_sizes = 7,
1981 .configure = intel_820_configure,
1982 .fetch_size = intel_8xx_fetch_size,
1983 .cleanup = intel_820_cleanup,
1984 .tlb_flush = intel_820_tlbflush,
1985 .mask_memory = agp_generic_mask_memory,
1986 .masks = intel_generic_masks,
1987 .agp_enable = agp_generic_enable,
1988 .cache_flush = global_cache_flush,
1989 .create_gatt_table = agp_generic_create_gatt_table,
1990 .free_gatt_table = agp_generic_free_gatt_table,
1991 .insert_memory = agp_generic_insert_memory,
1992 .remove_memory = agp_generic_remove_memory,
1993 .alloc_by_type = agp_generic_alloc_by_type,
1994 .free_by_type = agp_generic_free_by_type,
1995 .agp_alloc_page = agp_generic_alloc_page,
Shaohua Li37acee12008-08-21 10:46:11 +08001996 .agp_alloc_pages = agp_generic_alloc_pages,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001997 .agp_destroy_page = agp_generic_destroy_page,
Shaohua Libd079282008-08-21 10:46:17 +08001998 .agp_destroy_pages = agp_generic_destroy_pages,
Thomas Hellstroma030ce42007-01-23 10:33:43 +01001999 .agp_type_to_mask_type = agp_generic_type_to_mask_type,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002000};
2001
Dave Jonese5524f32007-02-22 18:41:28 -05002002static const struct agp_bridge_driver intel_830mp_driver = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002003 .owner = THIS_MODULE,
2004 .aperture_sizes = intel_830mp_sizes,
2005 .size_type = U8_APER_SIZE,
2006 .num_aperture_sizes = 4,
2007 .configure = intel_830mp_configure,
2008 .fetch_size = intel_8xx_fetch_size,
2009 .cleanup = intel_8xx_cleanup,
2010 .tlb_flush = intel_8xx_tlbflush,
2011 .mask_memory = agp_generic_mask_memory,
2012 .masks = intel_generic_masks,
2013 .agp_enable = agp_generic_enable,
2014 .cache_flush = global_cache_flush,
2015 .create_gatt_table = agp_generic_create_gatt_table,
2016 .free_gatt_table = agp_generic_free_gatt_table,
2017 .insert_memory = agp_generic_insert_memory,
2018 .remove_memory = agp_generic_remove_memory,
2019 .alloc_by_type = agp_generic_alloc_by_type,
2020 .free_by_type = agp_generic_free_by_type,
2021 .agp_alloc_page = agp_generic_alloc_page,
Shaohua Li37acee12008-08-21 10:46:11 +08002022 .agp_alloc_pages = agp_generic_alloc_pages,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002023 .agp_destroy_page = agp_generic_destroy_page,
Shaohua Libd079282008-08-21 10:46:17 +08002024 .agp_destroy_pages = agp_generic_destroy_pages,
Thomas Hellstroma030ce42007-01-23 10:33:43 +01002025 .agp_type_to_mask_type = agp_generic_type_to_mask_type,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002026};
2027
Dave Jonese5524f32007-02-22 18:41:28 -05002028static const struct agp_bridge_driver intel_840_driver = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002029 .owner = THIS_MODULE,
2030 .aperture_sizes = intel_8xx_sizes,
2031 .size_type = U8_APER_SIZE,
2032 .num_aperture_sizes = 7,
2033 .configure = intel_840_configure,
2034 .fetch_size = intel_8xx_fetch_size,
2035 .cleanup = intel_8xx_cleanup,
2036 .tlb_flush = intel_8xx_tlbflush,
2037 .mask_memory = agp_generic_mask_memory,
2038 .masks = intel_generic_masks,
2039 .agp_enable = agp_generic_enable,
2040 .cache_flush = global_cache_flush,
2041 .create_gatt_table = agp_generic_create_gatt_table,
2042 .free_gatt_table = agp_generic_free_gatt_table,
2043 .insert_memory = agp_generic_insert_memory,
2044 .remove_memory = agp_generic_remove_memory,
2045 .alloc_by_type = agp_generic_alloc_by_type,
2046 .free_by_type = agp_generic_free_by_type,
2047 .agp_alloc_page = agp_generic_alloc_page,
Shaohua Li37acee12008-08-21 10:46:11 +08002048 .agp_alloc_pages = agp_generic_alloc_pages,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002049 .agp_destroy_page = agp_generic_destroy_page,
Shaohua Libd079282008-08-21 10:46:17 +08002050 .agp_destroy_pages = agp_generic_destroy_pages,
Thomas Hellstroma030ce42007-01-23 10:33:43 +01002051 .agp_type_to_mask_type = agp_generic_type_to_mask_type,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002052};
2053
Dave Jonese5524f32007-02-22 18:41:28 -05002054static const struct agp_bridge_driver intel_845_driver = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002055 .owner = THIS_MODULE,
2056 .aperture_sizes = intel_8xx_sizes,
2057 .size_type = U8_APER_SIZE,
2058 .num_aperture_sizes = 7,
2059 .configure = intel_845_configure,
2060 .fetch_size = intel_8xx_fetch_size,
2061 .cleanup = intel_8xx_cleanup,
2062 .tlb_flush = intel_8xx_tlbflush,
2063 .mask_memory = agp_generic_mask_memory,
2064 .masks = intel_generic_masks,
2065 .agp_enable = agp_generic_enable,
2066 .cache_flush = global_cache_flush,
2067 .create_gatt_table = agp_generic_create_gatt_table,
2068 .free_gatt_table = agp_generic_free_gatt_table,
2069 .insert_memory = agp_generic_insert_memory,
2070 .remove_memory = agp_generic_remove_memory,
2071 .alloc_by_type = agp_generic_alloc_by_type,
2072 .free_by_type = agp_generic_free_by_type,
2073 .agp_alloc_page = agp_generic_alloc_page,
Shaohua Li37acee12008-08-21 10:46:11 +08002074 .agp_alloc_pages = agp_generic_alloc_pages,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002075 .agp_destroy_page = agp_generic_destroy_page,
Shaohua Libd079282008-08-21 10:46:17 +08002076 .agp_destroy_pages = agp_generic_destroy_pages,
Thomas Hellstroma030ce42007-01-23 10:33:43 +01002077 .agp_type_to_mask_type = agp_generic_type_to_mask_type,
Dave Airlie2162e6a2007-11-21 16:36:31 +10002078 .chipset_flush = intel_i830_chipset_flush,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002079};
2080
Dave Jonese5524f32007-02-22 18:41:28 -05002081static const struct agp_bridge_driver intel_850_driver = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002082 .owner = THIS_MODULE,
2083 .aperture_sizes = intel_8xx_sizes,
2084 .size_type = U8_APER_SIZE,
2085 .num_aperture_sizes = 7,
2086 .configure = intel_850_configure,
2087 .fetch_size = intel_8xx_fetch_size,
2088 .cleanup = intel_8xx_cleanup,
2089 .tlb_flush = intel_8xx_tlbflush,
2090 .mask_memory = agp_generic_mask_memory,
2091 .masks = intel_generic_masks,
2092 .agp_enable = agp_generic_enable,
2093 .cache_flush = global_cache_flush,
2094 .create_gatt_table = agp_generic_create_gatt_table,
2095 .free_gatt_table = agp_generic_free_gatt_table,
2096 .insert_memory = agp_generic_insert_memory,
2097 .remove_memory = agp_generic_remove_memory,
2098 .alloc_by_type = agp_generic_alloc_by_type,
2099 .free_by_type = agp_generic_free_by_type,
2100 .agp_alloc_page = agp_generic_alloc_page,
Shaohua Li37acee12008-08-21 10:46:11 +08002101 .agp_alloc_pages = agp_generic_alloc_pages,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002102 .agp_destroy_page = agp_generic_destroy_page,
Shaohua Libd079282008-08-21 10:46:17 +08002103 .agp_destroy_pages = agp_generic_destroy_pages,
Thomas Hellstroma030ce42007-01-23 10:33:43 +01002104 .agp_type_to_mask_type = agp_generic_type_to_mask_type,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002105};
2106
Dave Jonese5524f32007-02-22 18:41:28 -05002107static const struct agp_bridge_driver intel_860_driver = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002108 .owner = THIS_MODULE,
2109 .aperture_sizes = intel_8xx_sizes,
2110 .size_type = U8_APER_SIZE,
2111 .num_aperture_sizes = 7,
2112 .configure = intel_860_configure,
2113 .fetch_size = intel_8xx_fetch_size,
2114 .cleanup = intel_8xx_cleanup,
2115 .tlb_flush = intel_8xx_tlbflush,
2116 .mask_memory = agp_generic_mask_memory,
2117 .masks = intel_generic_masks,
2118 .agp_enable = agp_generic_enable,
2119 .cache_flush = global_cache_flush,
2120 .create_gatt_table = agp_generic_create_gatt_table,
2121 .free_gatt_table = agp_generic_free_gatt_table,
2122 .insert_memory = agp_generic_insert_memory,
2123 .remove_memory = agp_generic_remove_memory,
2124 .alloc_by_type = agp_generic_alloc_by_type,
2125 .free_by_type = agp_generic_free_by_type,
2126 .agp_alloc_page = agp_generic_alloc_page,
Shaohua Li37acee12008-08-21 10:46:11 +08002127 .agp_alloc_pages = agp_generic_alloc_pages,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002128 .agp_destroy_page = agp_generic_destroy_page,
Shaohua Libd079282008-08-21 10:46:17 +08002129 .agp_destroy_pages = agp_generic_destroy_pages,
Thomas Hellstroma030ce42007-01-23 10:33:43 +01002130 .agp_type_to_mask_type = agp_generic_type_to_mask_type,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002131};
2132
Dave Jonese5524f32007-02-22 18:41:28 -05002133static const struct agp_bridge_driver intel_915_driver = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002134 .owner = THIS_MODULE,
2135 .aperture_sizes = intel_i830_sizes,
2136 .size_type = FIXED_APER_SIZE,
Dave Jonesc14635e2006-09-06 11:59:35 -04002137 .num_aperture_sizes = 4,
Joe Perchesc7258012008-03-26 14:10:02 -07002138 .needs_scratch_page = true,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002139 .configure = intel_i915_configure,
Eric Anholtc41e0de2006-12-19 12:57:24 -08002140 .fetch_size = intel_i9xx_fetch_size,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002141 .cleanup = intel_i915_cleanup,
2142 .tlb_flush = intel_i810_tlbflush,
2143 .mask_memory = intel_i810_mask_memory,
2144 .masks = intel_i810_masks,
2145 .agp_enable = intel_i810_agp_enable,
2146 .cache_flush = global_cache_flush,
2147 .create_gatt_table = intel_i915_create_gatt_table,
2148 .free_gatt_table = intel_i830_free_gatt_table,
2149 .insert_memory = intel_i915_insert_entries,
2150 .remove_memory = intel_i915_remove_entries,
2151 .alloc_by_type = intel_i830_alloc_by_type,
2152 .free_by_type = intel_i810_free_by_type,
2153 .agp_alloc_page = agp_generic_alloc_page,
Shaohua Li37acee12008-08-21 10:46:11 +08002154 .agp_alloc_pages = agp_generic_alloc_pages,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002155 .agp_destroy_page = agp_generic_destroy_page,
Shaohua Libd079282008-08-21 10:46:17 +08002156 .agp_destroy_pages = agp_generic_destroy_pages,
Thomas Hellstroma030ce42007-01-23 10:33:43 +01002157 .agp_type_to_mask_type = intel_i830_type_to_mask_type,
Dave Airlie6c00a612007-10-29 18:06:10 +10002158 .chipset_flush = intel_i915_chipset_flush,
Zhenyu Wang17661682009-07-27 12:59:57 +01002159#ifdef USE_PCI_DMA_API
2160 .agp_map_page = intel_agp_map_page,
2161 .agp_unmap_page = intel_agp_unmap_page,
2162 .agp_map_memory = intel_agp_map_memory,
2163 .agp_unmap_memory = intel_agp_unmap_memory,
2164#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07002165};
2166
Dave Jonese5524f32007-02-22 18:41:28 -05002167static const struct agp_bridge_driver intel_i965_driver = {
Dave Airlie62c96b92008-06-19 14:27:53 +10002168 .owner = THIS_MODULE,
2169 .aperture_sizes = intel_i830_sizes,
2170 .size_type = FIXED_APER_SIZE,
2171 .num_aperture_sizes = 4,
2172 .needs_scratch_page = true,
Dave Airlie0e480e52008-06-19 14:57:31 +10002173 .configure = intel_i915_configure,
2174 .fetch_size = intel_i9xx_fetch_size,
Dave Airlie62c96b92008-06-19 14:27:53 +10002175 .cleanup = intel_i915_cleanup,
2176 .tlb_flush = intel_i810_tlbflush,
2177 .mask_memory = intel_i965_mask_memory,
2178 .masks = intel_i810_masks,
2179 .agp_enable = intel_i810_agp_enable,
2180 .cache_flush = global_cache_flush,
2181 .create_gatt_table = intel_i965_create_gatt_table,
2182 .free_gatt_table = intel_i830_free_gatt_table,
2183 .insert_memory = intel_i915_insert_entries,
2184 .remove_memory = intel_i915_remove_entries,
2185 .alloc_by_type = intel_i830_alloc_by_type,
2186 .free_by_type = intel_i810_free_by_type,
2187 .agp_alloc_page = agp_generic_alloc_page,
Shaohua Li37acee12008-08-21 10:46:11 +08002188 .agp_alloc_pages = agp_generic_alloc_pages,
Dave Airlie62c96b92008-06-19 14:27:53 +10002189 .agp_destroy_page = agp_generic_destroy_page,
Shaohua Libd079282008-08-21 10:46:17 +08002190 .agp_destroy_pages = agp_generic_destroy_pages,
Dave Airlie62c96b92008-06-19 14:27:53 +10002191 .agp_type_to_mask_type = intel_i830_type_to_mask_type,
Dave Airlie6c00a612007-10-29 18:06:10 +10002192 .chipset_flush = intel_i915_chipset_flush,
Zhenyu Wang17661682009-07-27 12:59:57 +01002193#ifdef USE_PCI_DMA_API
2194 .agp_map_page = intel_agp_map_page,
2195 .agp_unmap_page = intel_agp_unmap_page,
2196 .agp_map_memory = intel_agp_map_memory,
2197 .agp_unmap_memory = intel_agp_unmap_memory,
2198#endif
Eric Anholt65c25aa2006-09-06 11:57:18 -04002199};
Linus Torvalds1da177e2005-04-16 15:20:36 -07002200
Dave Jonese5524f32007-02-22 18:41:28 -05002201static const struct agp_bridge_driver intel_7505_driver = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002202 .owner = THIS_MODULE,
2203 .aperture_sizes = intel_8xx_sizes,
2204 .size_type = U8_APER_SIZE,
2205 .num_aperture_sizes = 7,
2206 .configure = intel_7505_configure,
2207 .fetch_size = intel_8xx_fetch_size,
2208 .cleanup = intel_8xx_cleanup,
2209 .tlb_flush = intel_8xx_tlbflush,
2210 .mask_memory = agp_generic_mask_memory,
2211 .masks = intel_generic_masks,
2212 .agp_enable = agp_generic_enable,
2213 .cache_flush = global_cache_flush,
2214 .create_gatt_table = agp_generic_create_gatt_table,
2215 .free_gatt_table = agp_generic_free_gatt_table,
2216 .insert_memory = agp_generic_insert_memory,
2217 .remove_memory = agp_generic_remove_memory,
2218 .alloc_by_type = agp_generic_alloc_by_type,
2219 .free_by_type = agp_generic_free_by_type,
2220 .agp_alloc_page = agp_generic_alloc_page,
Shaohua Li37acee12008-08-21 10:46:11 +08002221 .agp_alloc_pages = agp_generic_alloc_pages,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002222 .agp_destroy_page = agp_generic_destroy_page,
Shaohua Libd079282008-08-21 10:46:17 +08002223 .agp_destroy_pages = agp_generic_destroy_pages,
Thomas Hellstroma030ce42007-01-23 10:33:43 +01002224 .agp_type_to_mask_type = agp_generic_type_to_mask_type,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002225};
2226
Wang Zhenyu874808c62007-06-06 11:16:25 +08002227static const struct agp_bridge_driver intel_g33_driver = {
Dave Airlie62c96b92008-06-19 14:27:53 +10002228 .owner = THIS_MODULE,
2229 .aperture_sizes = intel_i830_sizes,
2230 .size_type = FIXED_APER_SIZE,
2231 .num_aperture_sizes = 4,
2232 .needs_scratch_page = true,
2233 .configure = intel_i915_configure,
2234 .fetch_size = intel_i9xx_fetch_size,
2235 .cleanup = intel_i915_cleanup,
2236 .tlb_flush = intel_i810_tlbflush,
2237 .mask_memory = intel_i965_mask_memory,
2238 .masks = intel_i810_masks,
2239 .agp_enable = intel_i810_agp_enable,
2240 .cache_flush = global_cache_flush,
2241 .create_gatt_table = intel_i915_create_gatt_table,
2242 .free_gatt_table = intel_i830_free_gatt_table,
2243 .insert_memory = intel_i915_insert_entries,
2244 .remove_memory = intel_i915_remove_entries,
2245 .alloc_by_type = intel_i830_alloc_by_type,
2246 .free_by_type = intel_i810_free_by_type,
2247 .agp_alloc_page = agp_generic_alloc_page,
Shaohua Li37acee12008-08-21 10:46:11 +08002248 .agp_alloc_pages = agp_generic_alloc_pages,
Dave Airlie62c96b92008-06-19 14:27:53 +10002249 .agp_destroy_page = agp_generic_destroy_page,
Shaohua Libd079282008-08-21 10:46:17 +08002250 .agp_destroy_pages = agp_generic_destroy_pages,
Dave Airlie62c96b92008-06-19 14:27:53 +10002251 .agp_type_to_mask_type = intel_i830_type_to_mask_type,
Dave Airlie6c00a612007-10-29 18:06:10 +10002252 .chipset_flush = intel_i915_chipset_flush,
Zhenyu Wang17661682009-07-27 12:59:57 +01002253#ifdef USE_PCI_DMA_API
2254 .agp_map_page = intel_agp_map_page,
2255 .agp_unmap_page = intel_agp_unmap_page,
2256 .agp_map_memory = intel_agp_map_memory,
2257 .agp_unmap_memory = intel_agp_unmap_memory,
2258#endif
Wang Zhenyu874808c62007-06-06 11:16:25 +08002259};
Wang Zhenyu9614ece2007-05-30 09:45:58 +08002260
2261static int find_gmch(u16 device)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002262{
Wang Zhenyu9614ece2007-05-30 09:45:58 +08002263 struct pci_dev *gmch_device;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002264
Wang Zhenyu9614ece2007-05-30 09:45:58 +08002265 gmch_device = pci_get_device(PCI_VENDOR_ID_INTEL, device, NULL);
2266 if (gmch_device && PCI_FUNC(gmch_device->devfn) != 0) {
2267 gmch_device = pci_get_device(PCI_VENDOR_ID_INTEL,
Dave Airlief011ae72008-01-25 11:23:04 +10002268 device, gmch_device);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002269 }
2270
Wang Zhenyu9614ece2007-05-30 09:45:58 +08002271 if (!gmch_device)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002272 return 0;
2273
Wang Zhenyu9614ece2007-05-30 09:45:58 +08002274 intel_private.pcidev = gmch_device;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002275 return 1;
2276}
2277
Wang Zhenyu9614ece2007-05-30 09:45:58 +08002278/* Table to describe Intel GMCH and AGP/PCIE GART drivers. At least one of
2279 * driver and gmch_driver must be non-null, and find_gmch will determine
2280 * which one should be used if a gmch_chip_id is present.
2281 */
2282static const struct intel_driver_description {
2283 unsigned int chip_id;
2284 unsigned int gmch_chip_id;
Wang Zhenyu88889852007-06-14 10:01:04 +08002285 unsigned int multi_gmch_chip; /* if we have more gfx chip type on this HB. */
Wang Zhenyu9614ece2007-05-30 09:45:58 +08002286 char *name;
2287 const struct agp_bridge_driver *driver;
2288 const struct agp_bridge_driver *gmch_driver;
2289} intel_agp_chipsets[] = {
Wang Zhenyu88889852007-06-14 10:01:04 +08002290 { PCI_DEVICE_ID_INTEL_82443LX_0, 0, 0, "440LX", &intel_generic_driver, NULL },
2291 { PCI_DEVICE_ID_INTEL_82443BX_0, 0, 0, "440BX", &intel_generic_driver, NULL },
2292 { PCI_DEVICE_ID_INTEL_82443GX_0, 0, 0, "440GX", &intel_generic_driver, NULL },
2293 { PCI_DEVICE_ID_INTEL_82810_MC1, PCI_DEVICE_ID_INTEL_82810_IG1, 0, "i810",
Wang Zhenyu9614ece2007-05-30 09:45:58 +08002294 NULL, &intel_810_driver },
Wang Zhenyu88889852007-06-14 10:01:04 +08002295 { PCI_DEVICE_ID_INTEL_82810_MC3, PCI_DEVICE_ID_INTEL_82810_IG3, 0, "i810",
Wang Zhenyu9614ece2007-05-30 09:45:58 +08002296 NULL, &intel_810_driver },
Wang Zhenyu88889852007-06-14 10:01:04 +08002297 { PCI_DEVICE_ID_INTEL_82810E_MC, PCI_DEVICE_ID_INTEL_82810E_IG, 0, "i810",
Wang Zhenyu9614ece2007-05-30 09:45:58 +08002298 NULL, &intel_810_driver },
Wang Zhenyu88889852007-06-14 10:01:04 +08002299 { PCI_DEVICE_ID_INTEL_82815_MC, PCI_DEVICE_ID_INTEL_82815_CGC, 0, "i815",
2300 &intel_815_driver, &intel_810_driver },
2301 { PCI_DEVICE_ID_INTEL_82820_HB, 0, 0, "i820", &intel_820_driver, NULL },
2302 { PCI_DEVICE_ID_INTEL_82820_UP_HB, 0, 0, "i820", &intel_820_driver, NULL },
2303 { PCI_DEVICE_ID_INTEL_82830_HB, PCI_DEVICE_ID_INTEL_82830_CGC, 0, "830M",
Wang Zhenyu9614ece2007-05-30 09:45:58 +08002304 &intel_830mp_driver, &intel_830_driver },
Wang Zhenyu88889852007-06-14 10:01:04 +08002305 { PCI_DEVICE_ID_INTEL_82840_HB, 0, 0, "i840", &intel_840_driver, NULL },
2306 { PCI_DEVICE_ID_INTEL_82845_HB, 0, 0, "845G", &intel_845_driver, NULL },
2307 { PCI_DEVICE_ID_INTEL_82845G_HB, PCI_DEVICE_ID_INTEL_82845G_IG, 0, "830M",
Wang Zhenyu9614ece2007-05-30 09:45:58 +08002308 &intel_845_driver, &intel_830_driver },
Wang Zhenyu88889852007-06-14 10:01:04 +08002309 { PCI_DEVICE_ID_INTEL_82850_HB, 0, 0, "i850", &intel_850_driver, NULL },
Stefan Husemann347486b2009-04-13 14:40:10 -07002310 { PCI_DEVICE_ID_INTEL_82854_HB, PCI_DEVICE_ID_INTEL_82854_IG, 0, "854",
2311 &intel_845_driver, &intel_830_driver },
Wang Zhenyu88889852007-06-14 10:01:04 +08002312 { PCI_DEVICE_ID_INTEL_82855PM_HB, 0, 0, "855PM", &intel_845_driver, NULL },
2313 { PCI_DEVICE_ID_INTEL_82855GM_HB, PCI_DEVICE_ID_INTEL_82855GM_IG, 0, "855GM",
Wang Zhenyu9614ece2007-05-30 09:45:58 +08002314 &intel_845_driver, &intel_830_driver },
Wang Zhenyu88889852007-06-14 10:01:04 +08002315 { PCI_DEVICE_ID_INTEL_82860_HB, 0, 0, "i860", &intel_860_driver, NULL },
2316 { PCI_DEVICE_ID_INTEL_82865_HB, PCI_DEVICE_ID_INTEL_82865_IG, 0, "865",
Wang Zhenyu9614ece2007-05-30 09:45:58 +08002317 &intel_845_driver, &intel_830_driver },
Wang Zhenyu88889852007-06-14 10:01:04 +08002318 { PCI_DEVICE_ID_INTEL_82875_HB, 0, 0, "i875", &intel_845_driver, NULL },
Carlos Martíne914a362008-01-24 10:34:09 +10002319 { PCI_DEVICE_ID_INTEL_E7221_HB, PCI_DEVICE_ID_INTEL_E7221_IG, 0, "E7221 (i915)",
2320 NULL, &intel_915_driver },
Wang Zhenyu88889852007-06-14 10:01:04 +08002321 { PCI_DEVICE_ID_INTEL_82915G_HB, PCI_DEVICE_ID_INTEL_82915G_IG, 0, "915G",
Wang Zhenyu47d46372007-06-21 13:43:18 +08002322 NULL, &intel_915_driver },
Wang Zhenyu88889852007-06-14 10:01:04 +08002323 { PCI_DEVICE_ID_INTEL_82915GM_HB, PCI_DEVICE_ID_INTEL_82915GM_IG, 0, "915GM",
Wang Zhenyu47d46372007-06-21 13:43:18 +08002324 NULL, &intel_915_driver },
Wang Zhenyu88889852007-06-14 10:01:04 +08002325 { PCI_DEVICE_ID_INTEL_82945G_HB, PCI_DEVICE_ID_INTEL_82945G_IG, 0, "945G",
Wang Zhenyu47d46372007-06-21 13:43:18 +08002326 NULL, &intel_915_driver },
Zhenyu Wangdde47872007-07-26 09:18:09 +08002327 { PCI_DEVICE_ID_INTEL_82945GM_HB, PCI_DEVICE_ID_INTEL_82945GM_IG, 0, "945GM",
Wang Zhenyu47d46372007-06-21 13:43:18 +08002328 NULL, &intel_915_driver },
Zhenyu Wangdde47872007-07-26 09:18:09 +08002329 { PCI_DEVICE_ID_INTEL_82945GME_HB, PCI_DEVICE_ID_INTEL_82945GME_IG, 0, "945GME",
Wang Zhenyu47d46372007-06-21 13:43:18 +08002330 NULL, &intel_915_driver },
Wang Zhenyu88889852007-06-14 10:01:04 +08002331 { PCI_DEVICE_ID_INTEL_82946GZ_HB, PCI_DEVICE_ID_INTEL_82946GZ_IG, 0, "946GZ",
Wang Zhenyu47d46372007-06-21 13:43:18 +08002332 NULL, &intel_i965_driver },
Zhenyu Wang9119f852008-01-23 15:49:26 +10002333 { PCI_DEVICE_ID_INTEL_82G35_HB, PCI_DEVICE_ID_INTEL_82G35_IG, 0, "G35",
Wang Zhenyu47d46372007-06-21 13:43:18 +08002334 NULL, &intel_i965_driver },
Wang Zhenyu88889852007-06-14 10:01:04 +08002335 { PCI_DEVICE_ID_INTEL_82965Q_HB, PCI_DEVICE_ID_INTEL_82965Q_IG, 0, "965Q",
Wang Zhenyu47d46372007-06-21 13:43:18 +08002336 NULL, &intel_i965_driver },
Wang Zhenyu88889852007-06-14 10:01:04 +08002337 { PCI_DEVICE_ID_INTEL_82965G_HB, PCI_DEVICE_ID_INTEL_82965G_IG, 0, "965G",
Wang Zhenyu47d46372007-06-21 13:43:18 +08002338 NULL, &intel_i965_driver },
Zhenyu Wangdde47872007-07-26 09:18:09 +08002339 { PCI_DEVICE_ID_INTEL_82965GM_HB, PCI_DEVICE_ID_INTEL_82965GM_IG, 0, "965GM",
Wang Zhenyu47d46372007-06-21 13:43:18 +08002340 NULL, &intel_i965_driver },
Zhenyu Wangdde47872007-07-26 09:18:09 +08002341 { PCI_DEVICE_ID_INTEL_82965GME_HB, PCI_DEVICE_ID_INTEL_82965GME_IG, 0, "965GME/GLE",
Wang Zhenyu47d46372007-06-21 13:43:18 +08002342 NULL, &intel_i965_driver },
Wang Zhenyu88889852007-06-14 10:01:04 +08002343 { PCI_DEVICE_ID_INTEL_7505_0, 0, 0, "E7505", &intel_7505_driver, NULL },
2344 { PCI_DEVICE_ID_INTEL_7205_0, 0, 0, "E7205", &intel_7505_driver, NULL },
2345 { PCI_DEVICE_ID_INTEL_G33_HB, PCI_DEVICE_ID_INTEL_G33_IG, 0, "G33",
Wang Zhenyu47d46372007-06-21 13:43:18 +08002346 NULL, &intel_g33_driver },
Wang Zhenyu88889852007-06-14 10:01:04 +08002347 { PCI_DEVICE_ID_INTEL_Q35_HB, PCI_DEVICE_ID_INTEL_Q35_IG, 0, "Q35",
Wang Zhenyu47d46372007-06-21 13:43:18 +08002348 NULL, &intel_g33_driver },
Wang Zhenyu88889852007-06-14 10:01:04 +08002349 { PCI_DEVICE_ID_INTEL_Q33_HB, PCI_DEVICE_ID_INTEL_Q33_IG, 0, "Q33",
Wang Zhenyu47d46372007-06-21 13:43:18 +08002350 NULL, &intel_g33_driver },
Adam Jackson107f5172009-12-03 17:14:41 -05002351 { PCI_DEVICE_ID_INTEL_PINEVIEW_M_HB, PCI_DEVICE_ID_INTEL_PINEVIEW_M_IG, 0, "Pineview",
Shaohua Li21778322009-02-23 15:19:16 +08002352 NULL, &intel_g33_driver },
Adam Jackson107f5172009-12-03 17:14:41 -05002353 { PCI_DEVICE_ID_INTEL_PINEVIEW_HB, PCI_DEVICE_ID_INTEL_PINEVIEW_IG, 0, "Pineview",
Shaohua Li21778322009-02-23 15:19:16 +08002354 NULL, &intel_g33_driver },
Zhenyu Wang99d32bd2008-07-30 12:26:50 -07002355 { PCI_DEVICE_ID_INTEL_GM45_HB, PCI_DEVICE_ID_INTEL_GM45_IG, 0,
Adam Jackson107f5172009-12-03 17:14:41 -05002356 "GM45", NULL, &intel_i965_driver },
2357 { PCI_DEVICE_ID_INTEL_EAGLELAKE_HB, PCI_DEVICE_ID_INTEL_EAGLELAKE_IG, 0,
2358 "Eaglelake", NULL, &intel_i965_driver },
Zhenyu Wang25ce77a2008-06-19 14:17:58 +10002359 { PCI_DEVICE_ID_INTEL_Q45_HB, PCI_DEVICE_ID_INTEL_Q45_IG, 0,
2360 "Q45/Q43", NULL, &intel_i965_driver },
2361 { PCI_DEVICE_ID_INTEL_G45_HB, PCI_DEVICE_ID_INTEL_G45_IG, 0,
2362 "G45/G43", NULL, &intel_i965_driver },
Fabian Henze38d8a952009-09-08 00:59:58 +08002363 { PCI_DEVICE_ID_INTEL_B43_HB, PCI_DEVICE_ID_INTEL_B43_IG, 0,
2364 "B43", NULL, &intel_i965_driver },
Zhenyu Wanga50ccc62008-11-17 14:39:00 +08002365 { PCI_DEVICE_ID_INTEL_G41_HB, PCI_DEVICE_ID_INTEL_G41_IG, 0,
2366 "G41", NULL, &intel_i965_driver },
Adam Jackson107f5172009-12-03 17:14:41 -05002367 { PCI_DEVICE_ID_INTEL_IRONLAKE_D_HB, PCI_DEVICE_ID_INTEL_IRONLAKE_D_IG, 0,
2368 "Ironlake/D", NULL, &intel_i965_driver },
2369 { PCI_DEVICE_ID_INTEL_IRONLAKE_M_HB, PCI_DEVICE_ID_INTEL_IRONLAKE_M_IG, 0,
2370 "Ironlake/M", NULL, &intel_i965_driver },
2371 { PCI_DEVICE_ID_INTEL_IRONLAKE_MA_HB, PCI_DEVICE_ID_INTEL_IRONLAKE_M_IG, 0,
2372 "Ironlake/MA", NULL, &intel_i965_driver },
Wang Zhenyu88889852007-06-14 10:01:04 +08002373 { 0, 0, 0, NULL, NULL, NULL }
Wang Zhenyu9614ece2007-05-30 09:45:58 +08002374};
2375
Linus Torvalds1da177e2005-04-16 15:20:36 -07002376static int __devinit agp_intel_probe(struct pci_dev *pdev,
2377 const struct pci_device_id *ent)
2378{
2379 struct agp_bridge_data *bridge;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002380 u8 cap_ptr = 0;
2381 struct resource *r;
Wang Zhenyu9614ece2007-05-30 09:45:58 +08002382 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002383
2384 cap_ptr = pci_find_capability(pdev, PCI_CAP_ID_AGP);
2385
2386 bridge = agp_alloc_bridge();
2387 if (!bridge)
2388 return -ENOMEM;
2389
Wang Zhenyu9614ece2007-05-30 09:45:58 +08002390 for (i = 0; intel_agp_chipsets[i].name != NULL; i++) {
2391 /* In case that multiple models of gfx chip may
2392 stand on same host bridge type, this can be
2393 sure we detect the right IGD. */
Wang Zhenyu88889852007-06-14 10:01:04 +08002394 if (pdev->device == intel_agp_chipsets[i].chip_id) {
2395 if ((intel_agp_chipsets[i].gmch_chip_id != 0) &&
2396 find_gmch(intel_agp_chipsets[i].gmch_chip_id)) {
2397 bridge->driver =
2398 intel_agp_chipsets[i].gmch_driver;
2399 break;
2400 } else if (intel_agp_chipsets[i].multi_gmch_chip) {
2401 continue;
2402 } else {
2403 bridge->driver = intel_agp_chipsets[i].driver;
2404 break;
2405 }
2406 }
Wang Zhenyu9614ece2007-05-30 09:45:58 +08002407 }
2408
2409 if (intel_agp_chipsets[i].name == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002410 if (cap_ptr)
Bjorn Helgaase3cf6952008-07-30 12:26:51 -07002411 dev_warn(&pdev->dev, "unsupported Intel chipset [%04x/%04x]\n",
2412 pdev->vendor, pdev->device);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002413 agp_put_bridge(bridge);
2414 return -ENODEV;
Wang Zhenyu9614ece2007-05-30 09:45:58 +08002415 }
2416
Wang Zhenyu9614ece2007-05-30 09:45:58 +08002417 if (bridge->driver == NULL) {
Wang Zhenyu47d46372007-06-21 13:43:18 +08002418 /* bridge has no AGP and no IGD detected */
2419 if (cap_ptr)
Bjorn Helgaase3cf6952008-07-30 12:26:51 -07002420 dev_warn(&pdev->dev, "can't find bridge device (chip_id: %04x)\n",
2421 intel_agp_chipsets[i].gmch_chip_id);
Wang Zhenyu9614ece2007-05-30 09:45:58 +08002422 agp_put_bridge(bridge);
2423 return -ENODEV;
Dave Airlief011ae72008-01-25 11:23:04 +10002424 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002425
2426 bridge->dev = pdev;
2427 bridge->capndx = cap_ptr;
Wang Zhenyuc4ca8812007-05-30 09:40:46 +08002428 bridge->dev_private_data = &intel_private;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002429
Bjorn Helgaase3cf6952008-07-30 12:26:51 -07002430 dev_info(&pdev->dev, "Intel %s Chipset\n", intel_agp_chipsets[i].name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002431
2432 /*
2433 * The following fixes the case where the BIOS has "forgotten" to
2434 * provide an address range for the GART.
2435 * 20030610 - hamish@zot.org
2436 */
2437 r = &pdev->resource[0];
2438 if (!r->start && r->end) {
Dave Jones6a92a4e2006-02-28 00:54:25 -05002439 if (pci_assign_resource(pdev, 0)) {
Bjorn Helgaase3cf6952008-07-30 12:26:51 -07002440 dev_err(&pdev->dev, "can't assign resource 0\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002441 agp_put_bridge(bridge);
2442 return -ENODEV;
2443 }
2444 }
2445
2446 /*
2447 * If the device has not been properly setup, the following will catch
2448 * the problem and should stop the system from crashing.
2449 * 20030610 - hamish@zot.org
2450 */
2451 if (pci_enable_device(pdev)) {
Bjorn Helgaase3cf6952008-07-30 12:26:51 -07002452 dev_err(&pdev->dev, "can't enable PCI device\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002453 agp_put_bridge(bridge);
2454 return -ENODEV;
2455 }
2456
2457 /* Fill in the mode register */
2458 if (cap_ptr) {
2459 pci_read_config_dword(pdev,
2460 bridge->capndx+PCI_AGP_STATUS,
2461 &bridge->mode);
2462 }
2463
2464 pci_set_drvdata(pdev, bridge);
2465 return agp_add_bridge(bridge);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002466}
2467
2468static void __devexit agp_intel_remove(struct pci_dev *pdev)
2469{
2470 struct agp_bridge_data *bridge = pci_get_drvdata(pdev);
2471
2472 agp_remove_bridge(bridge);
2473
Wang Zhenyuc4ca8812007-05-30 09:40:46 +08002474 if (intel_private.pcidev)
2475 pci_dev_put(intel_private.pcidev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002476
2477 agp_put_bridge(bridge);
2478}
2479
Alexey Dobriyan85be7d62006-08-12 02:02:02 +04002480#ifdef CONFIG_PM
Linus Torvalds1da177e2005-04-16 15:20:36 -07002481static int agp_intel_resume(struct pci_dev *pdev)
2482{
2483 struct agp_bridge_data *bridge = pci_get_drvdata(pdev);
Keith Packarda8c84df2008-07-31 15:48:07 +10002484 int ret_val;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002485
Linus Torvalds1da177e2005-04-16 15:20:36 -07002486 if (bridge->driver == &intel_generic_driver)
2487 intel_configure();
2488 else if (bridge->driver == &intel_850_driver)
2489 intel_850_configure();
2490 else if (bridge->driver == &intel_845_driver)
2491 intel_845_configure();
2492 else if (bridge->driver == &intel_830mp_driver)
2493 intel_830mp_configure();
2494 else if (bridge->driver == &intel_915_driver)
2495 intel_i915_configure();
2496 else if (bridge->driver == &intel_830_driver)
2497 intel_i830_configure();
2498 else if (bridge->driver == &intel_810_driver)
2499 intel_i810_configure();
Dave Jones08da3f42006-09-10 21:09:26 -04002500 else if (bridge->driver == &intel_i965_driver)
2501 intel_i915_configure();
Linus Torvalds1da177e2005-04-16 15:20:36 -07002502
Keith Packarda8c84df2008-07-31 15:48:07 +10002503 ret_val = agp_rebind_memory();
2504 if (ret_val != 0)
2505 return ret_val;
2506
Linus Torvalds1da177e2005-04-16 15:20:36 -07002507 return 0;
2508}
Alexey Dobriyan85be7d62006-08-12 02:02:02 +04002509#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07002510
2511static struct pci_device_id agp_intel_pci_table[] = {
2512#define ID(x) \
2513 { \
2514 .class = (PCI_CLASS_BRIDGE_HOST << 8), \
2515 .class_mask = ~0, \
2516 .vendor = PCI_VENDOR_ID_INTEL, \
2517 .device = x, \
2518 .subvendor = PCI_ANY_ID, \
2519 .subdevice = PCI_ANY_ID, \
2520 }
2521 ID(PCI_DEVICE_ID_INTEL_82443LX_0),
2522 ID(PCI_DEVICE_ID_INTEL_82443BX_0),
2523 ID(PCI_DEVICE_ID_INTEL_82443GX_0),
2524 ID(PCI_DEVICE_ID_INTEL_82810_MC1),
2525 ID(PCI_DEVICE_ID_INTEL_82810_MC3),
2526 ID(PCI_DEVICE_ID_INTEL_82810E_MC),
2527 ID(PCI_DEVICE_ID_INTEL_82815_MC),
2528 ID(PCI_DEVICE_ID_INTEL_82820_HB),
2529 ID(PCI_DEVICE_ID_INTEL_82820_UP_HB),
2530 ID(PCI_DEVICE_ID_INTEL_82830_HB),
2531 ID(PCI_DEVICE_ID_INTEL_82840_HB),
2532 ID(PCI_DEVICE_ID_INTEL_82845_HB),
2533 ID(PCI_DEVICE_ID_INTEL_82845G_HB),
2534 ID(PCI_DEVICE_ID_INTEL_82850_HB),
Stefan Husemann347486b2009-04-13 14:40:10 -07002535 ID(PCI_DEVICE_ID_INTEL_82854_HB),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002536 ID(PCI_DEVICE_ID_INTEL_82855PM_HB),
2537 ID(PCI_DEVICE_ID_INTEL_82855GM_HB),
2538 ID(PCI_DEVICE_ID_INTEL_82860_HB),
2539 ID(PCI_DEVICE_ID_INTEL_82865_HB),
2540 ID(PCI_DEVICE_ID_INTEL_82875_HB),
2541 ID(PCI_DEVICE_ID_INTEL_7505_0),
2542 ID(PCI_DEVICE_ID_INTEL_7205_0),
Carlos Martíne914a362008-01-24 10:34:09 +10002543 ID(PCI_DEVICE_ID_INTEL_E7221_HB),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002544 ID(PCI_DEVICE_ID_INTEL_82915G_HB),
2545 ID(PCI_DEVICE_ID_INTEL_82915GM_HB),
Alan Hourihaned0de98f2005-05-31 19:50:49 +01002546 ID(PCI_DEVICE_ID_INTEL_82945G_HB),
Alan Hourihane3b0e8ea2006-01-19 14:08:40 +00002547 ID(PCI_DEVICE_ID_INTEL_82945GM_HB),
Zhenyu Wangdde47872007-07-26 09:18:09 +08002548 ID(PCI_DEVICE_ID_INTEL_82945GME_HB),
Adam Jackson107f5172009-12-03 17:14:41 -05002549 ID(PCI_DEVICE_ID_INTEL_PINEVIEW_M_HB),
2550 ID(PCI_DEVICE_ID_INTEL_PINEVIEW_HB),
Eric Anholt65c25aa2006-09-06 11:57:18 -04002551 ID(PCI_DEVICE_ID_INTEL_82946GZ_HB),
Zhenyu Wang9119f852008-01-23 15:49:26 +10002552 ID(PCI_DEVICE_ID_INTEL_82G35_HB),
Eric Anholt65c25aa2006-09-06 11:57:18 -04002553 ID(PCI_DEVICE_ID_INTEL_82965Q_HB),
2554 ID(PCI_DEVICE_ID_INTEL_82965G_HB),
Wang Zhenyu4598af32007-04-09 08:51:36 +08002555 ID(PCI_DEVICE_ID_INTEL_82965GM_HB),
Zhenyu Wangdde47872007-07-26 09:18:09 +08002556 ID(PCI_DEVICE_ID_INTEL_82965GME_HB),
Wang Zhenyu874808c62007-06-06 11:16:25 +08002557 ID(PCI_DEVICE_ID_INTEL_G33_HB),
2558 ID(PCI_DEVICE_ID_INTEL_Q35_HB),
2559 ID(PCI_DEVICE_ID_INTEL_Q33_HB),
Zhenyu Wang99d32bd2008-07-30 12:26:50 -07002560 ID(PCI_DEVICE_ID_INTEL_GM45_HB),
Adam Jackson107f5172009-12-03 17:14:41 -05002561 ID(PCI_DEVICE_ID_INTEL_EAGLELAKE_HB),
Zhenyu Wang25ce77a2008-06-19 14:17:58 +10002562 ID(PCI_DEVICE_ID_INTEL_Q45_HB),
2563 ID(PCI_DEVICE_ID_INTEL_G45_HB),
Zhenyu Wanga50ccc62008-11-17 14:39:00 +08002564 ID(PCI_DEVICE_ID_INTEL_G41_HB),
Fabian Henze38d8a952009-09-08 00:59:58 +08002565 ID(PCI_DEVICE_ID_INTEL_B43_HB),
Adam Jackson107f5172009-12-03 17:14:41 -05002566 ID(PCI_DEVICE_ID_INTEL_IRONLAKE_D_HB),
2567 ID(PCI_DEVICE_ID_INTEL_IRONLAKE_M_HB),
2568 ID(PCI_DEVICE_ID_INTEL_IRONLAKE_MA_HB),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002569 { }
2570};
2571
2572MODULE_DEVICE_TABLE(pci, agp_intel_pci_table);
2573
2574static struct pci_driver agp_intel_pci_driver = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002575 .name = "agpgart-intel",
2576 .id_table = agp_intel_pci_table,
2577 .probe = agp_intel_probe,
2578 .remove = __devexit_p(agp_intel_remove),
Alexey Dobriyan85be7d62006-08-12 02:02:02 +04002579#ifdef CONFIG_PM
Linus Torvalds1da177e2005-04-16 15:20:36 -07002580 .resume = agp_intel_resume,
Alexey Dobriyan85be7d62006-08-12 02:02:02 +04002581#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07002582};
2583
2584static int __init agp_intel_init(void)
2585{
2586 if (agp_off)
2587 return -EINVAL;
2588 return pci_register_driver(&agp_intel_pci_driver);
2589}
2590
2591static void __exit agp_intel_cleanup(void)
2592{
2593 pci_unregister_driver(&agp_intel_pci_driver);
2594}
2595
2596module_init(agp_intel_init);
2597module_exit(agp_intel_cleanup);
2598
Dave Jonesf4432c52008-10-20 13:31:45 -04002599MODULE_AUTHOR("Dave Jones <davej@redhat.com>");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002600MODULE_LICENSE("GPL and additional rights");