diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/char/agp/amd64-agp.c |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'drivers/char/agp/amd64-agp.c')
-rw-r--r-- | drivers/char/agp/amd64-agp.c | 761 |
1 files changed, 761 insertions, 0 deletions
diff --git a/drivers/char/agp/amd64-agp.c b/drivers/char/agp/amd64-agp.c new file mode 100644 index 000000000000..905f0629c44f --- /dev/null +++ b/drivers/char/agp/amd64-agp.c | |||
@@ -0,0 +1,761 @@ | |||
1 | /* | ||
2 | * Copyright 2001-2003 SuSE Labs. | ||
3 | * Distributed under the GNU public license, v2. | ||
4 | * | ||
5 | * This is a GART driver for the AMD Opteron/Athlon64 on-CPU northbridge. | ||
6 | * It also includes support for the AMD 8151 AGP bridge, | ||
7 | * although it doesn't actually do much, as all the real | ||
8 | * work is done in the northbridge(s). | ||
9 | */ | ||
10 | |||
11 | #include <linux/config.h> | ||
12 | #include <linux/module.h> | ||
13 | #include <linux/pci.h> | ||
14 | #include <linux/init.h> | ||
15 | #include <linux/agp_backend.h> | ||
16 | #include "agp.h" | ||
17 | |||
18 | /* Will need to be increased if AMD64 ever goes >8-way. */ | ||
19 | #define MAX_HAMMER_GARTS 8 | ||
20 | |||
21 | /* PTE bits. */ | ||
22 | #define GPTE_VALID 1 | ||
23 | #define GPTE_COHERENT 2 | ||
24 | |||
25 | /* Aperture control register bits. */ | ||
26 | #define GARTEN (1<<0) | ||
27 | #define DISGARTCPU (1<<4) | ||
28 | #define DISGARTIO (1<<5) | ||
29 | |||
30 | /* GART cache control register bits. */ | ||
31 | #define INVGART (1<<0) | ||
32 | #define GARTPTEERR (1<<1) | ||
33 | |||
34 | /* K8 On-cpu GART registers */ | ||
35 | #define AMD64_GARTAPERTURECTL 0x90 | ||
36 | #define AMD64_GARTAPERTUREBASE 0x94 | ||
37 | #define AMD64_GARTTABLEBASE 0x98 | ||
38 | #define AMD64_GARTCACHECTL 0x9c | ||
39 | #define AMD64_GARTEN (1<<0) | ||
40 | |||
41 | /* NVIDIA K8 registers */ | ||
42 | #define NVIDIA_X86_64_0_APBASE 0x10 | ||
43 | #define NVIDIA_X86_64_1_APBASE1 0x50 | ||
44 | #define NVIDIA_X86_64_1_APLIMIT1 0x54 | ||
45 | #define NVIDIA_X86_64_1_APSIZE 0xa8 | ||
46 | #define NVIDIA_X86_64_1_APBASE2 0xd8 | ||
47 | #define NVIDIA_X86_64_1_APLIMIT2 0xdc | ||
48 | |||
49 | /* ULi K8 registers */ | ||
50 | #define ULI_X86_64_BASE_ADDR 0x10 | ||
51 | #define ULI_X86_64_HTT_FEA_REG 0x50 | ||
52 | #define ULI_X86_64_ENU_SCR_REG 0x54 | ||
53 | |||
54 | static int nr_garts; | ||
55 | static struct pci_dev * hammers[MAX_HAMMER_GARTS]; | ||
56 | |||
57 | static struct resource *aperture_resource; | ||
58 | static int __initdata agp_try_unsupported; | ||
59 | |||
60 | static int gart_iterator; | ||
61 | #define for_each_nb() for(gart_iterator=0;gart_iterator<nr_garts;gart_iterator++) | ||
62 | |||
63 | static void flush_amd64_tlb(struct pci_dev *dev) | ||
64 | { | ||
65 | u32 tmp; | ||
66 | |||
67 | pci_read_config_dword (dev, AMD64_GARTCACHECTL, &tmp); | ||
68 | tmp |= INVGART; | ||
69 | pci_write_config_dword (dev, AMD64_GARTCACHECTL, tmp); | ||
70 | } | ||
71 | |||
72 | static void amd64_tlbflush(struct agp_memory *temp) | ||
73 | { | ||
74 | for_each_nb() | ||
75 | flush_amd64_tlb(hammers[gart_iterator]); | ||
76 | } | ||
77 | |||
78 | static int amd64_insert_memory(struct agp_memory *mem, off_t pg_start, int type) | ||
79 | { | ||
80 | int i, j, num_entries; | ||
81 | long long tmp; | ||
82 | u32 pte; | ||
83 | |||
84 | num_entries = agp_num_entries(); | ||
85 | |||
86 | if (type != 0 || mem->type != 0) | ||
87 | return -EINVAL; | ||
88 | |||
89 | /* Make sure we can fit the range in the gatt table. */ | ||
90 | /* FIXME: could wrap */ | ||
91 | if (((unsigned long)pg_start + mem->page_count) > num_entries) | ||
92 | return -EINVAL; | ||
93 | |||
94 | j = pg_start; | ||
95 | |||
96 | /* gatt table should be empty. */ | ||
97 | while (j < (pg_start + mem->page_count)) { | ||
98 | if (!PGE_EMPTY(agp_bridge, readl(agp_bridge->gatt_table+j))) | ||
99 | return -EBUSY; | ||
100 | j++; | ||
101 | } | ||
102 | |||
103 | if (mem->is_flushed == FALSE) { | ||
104 | global_cache_flush(); | ||
105 | mem->is_flushed = TRUE; | ||
106 | } | ||
107 | |||
108 | for (i = 0, j = pg_start; i < mem->page_count; i++, j++) { | ||
109 | tmp = agp_bridge->driver->mask_memory(agp_bridge, | ||
110 | mem->memory[i], mem->type); | ||
111 | |||
112 | BUG_ON(tmp & 0xffffff0000000ffcULL); | ||
113 | pte = (tmp & 0x000000ff00000000ULL) >> 28; | ||
114 | pte |=(tmp & 0x00000000fffff000ULL); | ||
115 | pte |= GPTE_VALID | GPTE_COHERENT; | ||
116 | |||
117 | writel(pte, agp_bridge->gatt_table+j); | ||
118 | readl(agp_bridge->gatt_table+j); /* PCI Posting. */ | ||
119 | } | ||
120 | amd64_tlbflush(mem); | ||
121 | return 0; | ||
122 | } | ||
123 | |||
124 | /* | ||
125 | * This hack alters the order element according | ||
126 | * to the size of a long. It sucks. I totally disown this, even | ||
127 | * though it does appear to work for the most part. | ||
128 | */ | ||
129 | static struct aper_size_info_32 amd64_aperture_sizes[7] = | ||
130 | { | ||
131 | {32, 8192, 3+(sizeof(long)/8), 0 }, | ||
132 | {64, 16384, 4+(sizeof(long)/8), 1<<1 }, | ||
133 | {128, 32768, 5+(sizeof(long)/8), 1<<2 }, | ||
134 | {256, 65536, 6+(sizeof(long)/8), 1<<1 | 1<<2 }, | ||
135 | {512, 131072, 7+(sizeof(long)/8), 1<<3 }, | ||
136 | {1024, 262144, 8+(sizeof(long)/8), 1<<1 | 1<<3}, | ||
137 | {2048, 524288, 9+(sizeof(long)/8), 1<<2 | 1<<3} | ||
138 | }; | ||
139 | |||
140 | |||
141 | /* | ||
142 | * Get the current Aperture size from the x86-64. | ||
143 | * Note, that there may be multiple x86-64's, but we just return | ||
144 | * the value from the first one we find. The set_size functions | ||
145 | * keep the rest coherent anyway. Or at least should do. | ||
146 | */ | ||
147 | static int amd64_fetch_size(void) | ||
148 | { | ||
149 | struct pci_dev *dev; | ||
150 | int i; | ||
151 | u32 temp; | ||
152 | struct aper_size_info_32 *values; | ||
153 | |||
154 | dev = hammers[0]; | ||
155 | if (dev==NULL) | ||
156 | return 0; | ||
157 | |||
158 | pci_read_config_dword(dev, AMD64_GARTAPERTURECTL, &temp); | ||
159 | temp = (temp & 0xe); | ||
160 | values = A_SIZE_32(amd64_aperture_sizes); | ||
161 | |||
162 | for (i = 0; i < agp_bridge->driver->num_aperture_sizes; i++) { | ||
163 | if (temp == values[i].size_value) { | ||
164 | agp_bridge->previous_size = | ||
165 | agp_bridge->current_size = (void *) (values + i); | ||
166 | |||
167 | agp_bridge->aperture_size_idx = i; | ||
168 | return values[i].size; | ||
169 | } | ||
170 | } | ||
171 | return 0; | ||
172 | } | ||
173 | |||
174 | /* | ||
175 | * In a multiprocessor x86-64 system, this function gets | ||
176 | * called once for each CPU. | ||
177 | */ | ||
178 | static u64 amd64_configure (struct pci_dev *hammer, u64 gatt_table) | ||
179 | { | ||
180 | u64 aperturebase; | ||
181 | u32 tmp; | ||
182 | u64 addr, aper_base; | ||
183 | |||
184 | /* Address to map to */ | ||
185 | pci_read_config_dword (hammer, AMD64_GARTAPERTUREBASE, &tmp); | ||
186 | aperturebase = tmp << 25; | ||
187 | aper_base = (aperturebase & PCI_BASE_ADDRESS_MEM_MASK); | ||
188 | |||
189 | /* address of the mappings table */ | ||
190 | addr = (u64) gatt_table; | ||
191 | addr >>= 12; | ||
192 | tmp = (u32) addr<<4; | ||
193 | tmp &= ~0xf; | ||
194 | pci_write_config_dword (hammer, AMD64_GARTTABLEBASE, tmp); | ||
195 | |||
196 | /* Enable GART translation for this hammer. */ | ||
197 | pci_read_config_dword(hammer, AMD64_GARTAPERTURECTL, &tmp); | ||
198 | tmp |= GARTEN; | ||
199 | tmp &= ~(DISGARTCPU | DISGARTIO); | ||
200 | pci_write_config_dword(hammer, AMD64_GARTAPERTURECTL, tmp); | ||
201 | |||
202 | /* keep CPU's coherent. */ | ||
203 | flush_amd64_tlb (hammer); | ||
204 | |||
205 | return aper_base; | ||
206 | } | ||
207 | |||
208 | |||
209 | static struct aper_size_info_32 amd_8151_sizes[7] = | ||
210 | { | ||
211 | {2048, 524288, 9, 0x00000000 }, /* 0 0 0 0 0 0 */ | ||
212 | {1024, 262144, 8, 0x00000400 }, /* 1 0 0 0 0 0 */ | ||
213 | {512, 131072, 7, 0x00000600 }, /* 1 1 0 0 0 0 */ | ||
214 | {256, 65536, 6, 0x00000700 }, /* 1 1 1 0 0 0 */ | ||
215 | {128, 32768, 5, 0x00000720 }, /* 1 1 1 1 0 0 */ | ||
216 | {64, 16384, 4, 0x00000730 }, /* 1 1 1 1 1 0 */ | ||
217 | {32, 8192, 3, 0x00000738 } /* 1 1 1 1 1 1 */ | ||
218 | }; | ||
219 | |||
220 | static int amd_8151_configure(void) | ||
221 | { | ||
222 | unsigned long gatt_bus = virt_to_phys(agp_bridge->gatt_table_real); | ||
223 | |||
224 | /* Configure AGP regs in each x86-64 host bridge. */ | ||
225 | for_each_nb() { | ||
226 | agp_bridge->gart_bus_addr = | ||
227 | amd64_configure(hammers[gart_iterator],gatt_bus); | ||
228 | } | ||
229 | return 0; | ||
230 | } | ||
231 | |||
232 | |||
233 | static void amd64_cleanup(void) | ||
234 | { | ||
235 | u32 tmp; | ||
236 | |||
237 | for_each_nb() { | ||
238 | /* disable gart translation */ | ||
239 | pci_read_config_dword (hammers[gart_iterator], AMD64_GARTAPERTURECTL, &tmp); | ||
240 | tmp &= ~AMD64_GARTEN; | ||
241 | pci_write_config_dword (hammers[gart_iterator], AMD64_GARTAPERTURECTL, tmp); | ||
242 | } | ||
243 | } | ||
244 | |||
245 | |||
246 | struct agp_bridge_driver amd_8151_driver = { | ||
247 | .owner = THIS_MODULE, | ||
248 | .aperture_sizes = amd_8151_sizes, | ||
249 | .size_type = U32_APER_SIZE, | ||
250 | .num_aperture_sizes = 7, | ||
251 | .configure = amd_8151_configure, | ||
252 | .fetch_size = amd64_fetch_size, | ||
253 | .cleanup = amd64_cleanup, | ||
254 | .tlb_flush = amd64_tlbflush, | ||
255 | .mask_memory = agp_generic_mask_memory, | ||
256 | .masks = NULL, | ||
257 | .agp_enable = agp_generic_enable, | ||
258 | .cache_flush = global_cache_flush, | ||
259 | .create_gatt_table = agp_generic_create_gatt_table, | ||
260 | .free_gatt_table = agp_generic_free_gatt_table, | ||
261 | .insert_memory = amd64_insert_memory, | ||
262 | .remove_memory = agp_generic_remove_memory, | ||
263 | .alloc_by_type = agp_generic_alloc_by_type, | ||
264 | .free_by_type = agp_generic_free_by_type, | ||
265 | .agp_alloc_page = agp_generic_alloc_page, | ||
266 | .agp_destroy_page = agp_generic_destroy_page, | ||
267 | }; | ||
268 | |||
269 | /* Some basic sanity checks for the aperture. */ | ||
270 | static int __devinit aperture_valid(u64 aper, u32 size) | ||
271 | { | ||
272 | u32 pfn, c; | ||
273 | if (aper == 0) { | ||
274 | printk(KERN_ERR PFX "No aperture\n"); | ||
275 | return 0; | ||
276 | } | ||
277 | if (size < 32*1024*1024) { | ||
278 | printk(KERN_ERR PFX "Aperture too small (%d MB)\n", size>>20); | ||
279 | return 0; | ||
280 | } | ||
281 | if (aper + size > 0xffffffff) { | ||
282 | printk(KERN_ERR PFX "Aperture out of bounds\n"); | ||
283 | return 0; | ||
284 | } | ||
285 | pfn = aper >> PAGE_SHIFT; | ||
286 | for (c = 0; c < size/PAGE_SIZE; c++) { | ||
287 | if (!pfn_valid(pfn + c)) | ||
288 | break; | ||
289 | if (!PageReserved(pfn_to_page(pfn + c))) { | ||
290 | printk(KERN_ERR PFX "Aperture pointing to RAM\n"); | ||
291 | return 0; | ||
292 | } | ||
293 | } | ||
294 | |||
295 | /* Request the Aperture. This catches cases when someone else | ||
296 | already put a mapping in there - happens with some very broken BIOS | ||
297 | |||
298 | Maybe better to use pci_assign_resource/pci_enable_device instead | ||
299 | trusting the bridges? */ | ||
300 | if (!aperture_resource && | ||
301 | !(aperture_resource = request_mem_region(aper, size, "aperture"))) { | ||
302 | printk(KERN_ERR PFX "Aperture conflicts with PCI mapping.\n"); | ||
303 | return 0; | ||
304 | } | ||
305 | return 1; | ||
306 | } | ||
307 | |||
308 | /* | ||
309 | * W*s centric BIOS sometimes only set up the aperture in the AGP | ||
310 | * bridge, not the northbridge. On AMD64 this is handled early | ||
311 | * in aperture.c, but when GART_IOMMU is not enabled or we run | ||
312 | * on a 32bit kernel this needs to be redone. | ||
313 | * Unfortunately it is impossible to fix the aperture here because it's too late | ||
314 | * to allocate that much memory. But at least error out cleanly instead of | ||
315 | * crashing. | ||
316 | */ | ||
317 | static __devinit int fix_northbridge(struct pci_dev *nb, struct pci_dev *agp, | ||
318 | u16 cap) | ||
319 | { | ||
320 | u32 aper_low, aper_hi; | ||
321 | u64 aper, nb_aper; | ||
322 | int order = 0; | ||
323 | u32 nb_order, nb_base; | ||
324 | u16 apsize; | ||
325 | |||
326 | pci_read_config_dword(nb, 0x90, &nb_order); | ||
327 | nb_order = (nb_order >> 1) & 7; | ||
328 | pci_read_config_dword(nb, 0x94, &nb_base); | ||
329 | nb_aper = nb_base << 25; | ||
330 | if (aperture_valid(nb_aper, (32*1024*1024)<<nb_order)) { | ||
331 | return 0; | ||
332 | } | ||
333 | |||
334 | /* Northbridge seems to contain crap. Try the AGP bridge. */ | ||
335 | |||
336 | pci_read_config_word(agp, cap+0x14, &apsize); | ||
337 | if (apsize == 0xffff) | ||
338 | return -1; | ||
339 | |||
340 | apsize &= 0xfff; | ||
341 | /* Some BIOS use weird encodings not in the AGPv3 table. */ | ||
342 | if (apsize & 0xff) | ||
343 | apsize |= 0xf00; | ||
344 | order = 7 - hweight16(apsize); | ||
345 | |||
346 | pci_read_config_dword(agp, 0x10, &aper_low); | ||
347 | pci_read_config_dword(agp, 0x14, &aper_hi); | ||
348 | aper = (aper_low & ~((1<<22)-1)) | ((u64)aper_hi << 32); | ||
349 | printk(KERN_INFO PFX "Aperture from AGP @ %Lx size %u MB\n", aper, 32 << order); | ||
350 | if (order < 0 || !aperture_valid(aper, (32*1024*1024)<<order)) | ||
351 | return -1; | ||
352 | |||
353 | pci_write_config_dword(nb, 0x90, order << 1); | ||
354 | pci_write_config_dword(nb, 0x94, aper >> 25); | ||
355 | |||
356 | return 0; | ||
357 | } | ||
358 | |||
359 | static __devinit int cache_nbs (struct pci_dev *pdev, u32 cap_ptr) | ||
360 | { | ||
361 | struct pci_dev *loop_dev = NULL; | ||
362 | int i = 0; | ||
363 | |||
364 | /* cache pci_devs of northbridges. */ | ||
365 | while ((loop_dev = pci_get_device(PCI_VENDOR_ID_AMD, 0x1103, loop_dev)) | ||
366 | != NULL) { | ||
367 | if (i == MAX_HAMMER_GARTS) { | ||
368 | printk(KERN_ERR PFX "Too many northbridges for AGP\n"); | ||
369 | return -1; | ||
370 | } | ||
371 | if (fix_northbridge(loop_dev, pdev, cap_ptr) < 0) { | ||
372 | printk(KERN_ERR PFX "No usable aperture found.\n"); | ||
373 | #ifdef __x86_64__ | ||
374 | /* should port this to i386 */ | ||
375 | printk(KERN_ERR PFX "Consider rebooting with iommu=memaper=2 to get a good aperture.\n"); | ||
376 | #endif | ||
377 | return -1; | ||
378 | } | ||
379 | hammers[i++] = loop_dev; | ||
380 | } | ||
381 | nr_garts = i; | ||
382 | return i == 0 ? -1 : 0; | ||
383 | } | ||
384 | |||
385 | /* Handle AMD 8151 quirks */ | ||
386 | static void __devinit amd8151_init(struct pci_dev *pdev, struct agp_bridge_data *bridge) | ||
387 | { | ||
388 | char *revstring; | ||
389 | u8 rev_id; | ||
390 | |||
391 | pci_read_config_byte(pdev, PCI_REVISION_ID, &rev_id); | ||
392 | switch (rev_id) { | ||
393 | case 0x01: revstring="A0"; break; | ||
394 | case 0x02: revstring="A1"; break; | ||
395 | case 0x11: revstring="B0"; break; | ||
396 | case 0x12: revstring="B1"; break; | ||
397 | case 0x13: revstring="B2"; break; | ||
398 | case 0x14: revstring="B3"; break; | ||
399 | default: revstring="??"; break; | ||
400 | } | ||
401 | |||
402 | printk (KERN_INFO PFX "Detected AMD 8151 AGP Bridge rev %s\n", revstring); | ||
403 | |||
404 | /* | ||
405 | * Work around errata. | ||
406 | * Chips before B2 stepping incorrectly reporting v3.5 | ||
407 | */ | ||
408 | if (rev_id < 0x13) { | ||
409 | printk (KERN_INFO PFX "Correcting AGP revision (reports 3.5, is really 3.0)\n"); | ||
410 | bridge->major_version = 3; | ||
411 | bridge->minor_version = 0; | ||
412 | } | ||
413 | } | ||
414 | |||
415 | |||
416 | static struct aper_size_info_32 uli_sizes[7] = | ||
417 | { | ||
418 | {256, 65536, 6, 10}, | ||
419 | {128, 32768, 5, 9}, | ||
420 | {64, 16384, 4, 8}, | ||
421 | {32, 8192, 3, 7}, | ||
422 | {16, 4096, 2, 6}, | ||
423 | {8, 2048, 1, 4}, | ||
424 | {4, 1024, 0, 3} | ||
425 | }; | ||
426 | static int __devinit uli_agp_init(struct pci_dev *pdev) | ||
427 | { | ||
428 | u32 httfea,baseaddr,enuscr; | ||
429 | struct pci_dev *dev1; | ||
430 | int i; | ||
431 | unsigned size = amd64_fetch_size(); | ||
432 | printk(KERN_INFO "Setting up ULi AGP. \n"); | ||
433 | dev1 = pci_find_slot ((unsigned int)pdev->bus->number,PCI_DEVFN(0,0)); | ||
434 | if (dev1 == NULL) { | ||
435 | printk(KERN_INFO PFX "Detected a ULi chipset, " | ||
436 | "but could not fine the secondary device.\n"); | ||
437 | return -ENODEV; | ||
438 | } | ||
439 | |||
440 | for (i = 0; i < ARRAY_SIZE(uli_sizes); i++) | ||
441 | if (uli_sizes[i].size == size) | ||
442 | break; | ||
443 | |||
444 | if (i == ARRAY_SIZE(uli_sizes)) { | ||
445 | printk(KERN_INFO PFX "No ULi size found for %d\n", size); | ||
446 | return -ENODEV; | ||
447 | } | ||
448 | |||
449 | /* shadow x86-64 registers into ULi registers */ | ||
450 | pci_read_config_dword (hammers[0], AMD64_GARTAPERTUREBASE, &httfea); | ||
451 | |||
452 | /* if x86-64 aperture base is beyond 4G, exit here */ | ||
453 | if ((httfea & 0x7fff) >> (32 - 25)) | ||
454 | return -ENODEV; | ||
455 | |||
456 | httfea = (httfea& 0x7fff) << 25; | ||
457 | |||
458 | pci_read_config_dword(pdev, ULI_X86_64_BASE_ADDR, &baseaddr); | ||
459 | baseaddr&= ~PCI_BASE_ADDRESS_MEM_MASK; | ||
460 | baseaddr|= httfea; | ||
461 | pci_write_config_dword(pdev, ULI_X86_64_BASE_ADDR, baseaddr); | ||
462 | |||
463 | enuscr= httfea+ (size * 1024 * 1024) - 1; | ||
464 | pci_write_config_dword(dev1, ULI_X86_64_HTT_FEA_REG, httfea); | ||
465 | pci_write_config_dword(dev1, ULI_X86_64_ENU_SCR_REG, enuscr); | ||
466 | return 0; | ||
467 | } | ||
468 | |||
469 | |||
470 | static struct aper_size_info_32 nforce3_sizes[5] = | ||
471 | { | ||
472 | {512, 131072, 7, 0x00000000 }, | ||
473 | {256, 65536, 6, 0x00000008 }, | ||
474 | {128, 32768, 5, 0x0000000C }, | ||
475 | {64, 16384, 4, 0x0000000E }, | ||
476 | {32, 8192, 3, 0x0000000F } | ||
477 | }; | ||
478 | |||
479 | /* Handle shadow device of the Nvidia NForce3 */ | ||
480 | /* CHECK-ME original 2.4 version set up some IORRs. Check if that is needed. */ | ||
481 | static int __devinit nforce3_agp_init(struct pci_dev *pdev) | ||
482 | { | ||
483 | u32 tmp, apbase, apbar, aplimit; | ||
484 | struct pci_dev *dev1; | ||
485 | int i; | ||
486 | unsigned size = amd64_fetch_size(); | ||
487 | |||
488 | printk(KERN_INFO PFX "Setting up Nforce3 AGP.\n"); | ||
489 | |||
490 | dev1 = pci_find_slot((unsigned int)pdev->bus->number, PCI_DEVFN(11, 0)); | ||
491 | if (dev1 == NULL) { | ||
492 | printk(KERN_INFO PFX "agpgart: Detected an NVIDIA " | ||
493 | "nForce3 chipset, but could not find " | ||
494 | "the secondary device.\n"); | ||
495 | return -ENODEV; | ||
496 | } | ||
497 | |||
498 | for (i = 0; i < ARRAY_SIZE(nforce3_sizes); i++) | ||
499 | if (nforce3_sizes[i].size == size) | ||
500 | break; | ||
501 | |||
502 | if (i == ARRAY_SIZE(nforce3_sizes)) { | ||
503 | printk(KERN_INFO PFX "No NForce3 size found for %d\n", size); | ||
504 | return -ENODEV; | ||
505 | } | ||
506 | |||
507 | pci_read_config_dword(dev1, NVIDIA_X86_64_1_APSIZE, &tmp); | ||
508 | tmp &= ~(0xf); | ||
509 | tmp |= nforce3_sizes[i].size_value; | ||
510 | pci_write_config_dword(dev1, NVIDIA_X86_64_1_APSIZE, tmp); | ||
511 | |||
512 | /* shadow x86-64 registers into NVIDIA registers */ | ||
513 | pci_read_config_dword (hammers[0], AMD64_GARTAPERTUREBASE, &apbase); | ||
514 | |||
515 | /* if x86-64 aperture base is beyond 4G, exit here */ | ||
516 | if ( (apbase & 0x7fff) >> (32 - 25) ) | ||
517 | return -ENODEV; | ||
518 | |||
519 | apbase = (apbase & 0x7fff) << 25; | ||
520 | |||
521 | pci_read_config_dword(pdev, NVIDIA_X86_64_0_APBASE, &apbar); | ||
522 | apbar &= ~PCI_BASE_ADDRESS_MEM_MASK; | ||
523 | apbar |= apbase; | ||
524 | pci_write_config_dword(pdev, NVIDIA_X86_64_0_APBASE, apbar); | ||
525 | |||
526 | aplimit = apbase + (size * 1024 * 1024) - 1; | ||
527 | pci_write_config_dword(dev1, NVIDIA_X86_64_1_APBASE1, apbase); | ||
528 | pci_write_config_dword(dev1, NVIDIA_X86_64_1_APLIMIT1, aplimit); | ||
529 | pci_write_config_dword(dev1, NVIDIA_X86_64_1_APBASE2, apbase); | ||
530 | pci_write_config_dword(dev1, NVIDIA_X86_64_1_APLIMIT2, aplimit); | ||
531 | |||
532 | return 0; | ||
533 | } | ||
534 | |||
535 | static int __devinit agp_amd64_probe(struct pci_dev *pdev, | ||
536 | const struct pci_device_id *ent) | ||
537 | { | ||
538 | struct agp_bridge_data *bridge; | ||
539 | u8 cap_ptr; | ||
540 | |||
541 | cap_ptr = pci_find_capability(pdev, PCI_CAP_ID_AGP); | ||
542 | if (!cap_ptr) | ||
543 | return -ENODEV; | ||
544 | |||
545 | /* Could check for AGPv3 here */ | ||
546 | |||
547 | bridge = agp_alloc_bridge(); | ||
548 | if (!bridge) | ||
549 | return -ENOMEM; | ||
550 | |||
551 | if (pdev->vendor == PCI_VENDOR_ID_AMD && | ||
552 | pdev->device == PCI_DEVICE_ID_AMD_8151_0) { | ||
553 | amd8151_init(pdev, bridge); | ||
554 | } else { | ||
555 | printk(KERN_INFO PFX "Detected AGP bridge %x\n", pdev->devfn); | ||
556 | } | ||
557 | |||
558 | bridge->driver = &amd_8151_driver; | ||
559 | bridge->dev = pdev; | ||
560 | bridge->capndx = cap_ptr; | ||
561 | |||
562 | /* Fill in the mode register */ | ||
563 | pci_read_config_dword(pdev, bridge->capndx+PCI_AGP_STATUS, &bridge->mode); | ||
564 | |||
565 | if (cache_nbs(pdev, cap_ptr) == -1) { | ||
566 | agp_put_bridge(bridge); | ||
567 | return -ENODEV; | ||
568 | } | ||
569 | |||
570 | if (pdev->vendor == PCI_VENDOR_ID_NVIDIA) { | ||
571 | int ret = nforce3_agp_init(pdev); | ||
572 | if (ret) { | ||
573 | agp_put_bridge(bridge); | ||
574 | return ret; | ||
575 | } | ||
576 | } | ||
577 | |||
578 | if (pdev->vendor == PCI_VENDOR_ID_AL) { | ||
579 | int ret = uli_agp_init(pdev); | ||
580 | if (ret) { | ||
581 | agp_put_bridge(bridge); | ||
582 | return ret; | ||
583 | } | ||
584 | } | ||
585 | |||
586 | pci_set_drvdata(pdev, bridge); | ||
587 | return agp_add_bridge(bridge); | ||
588 | } | ||
589 | |||
590 | static void __devexit agp_amd64_remove(struct pci_dev *pdev) | ||
591 | { | ||
592 | struct agp_bridge_data *bridge = pci_get_drvdata(pdev); | ||
593 | |||
594 | release_mem_region(virt_to_phys(bridge->gatt_table_real), | ||
595 | amd64_aperture_sizes[bridge->aperture_size_idx].size); | ||
596 | agp_remove_bridge(bridge); | ||
597 | agp_put_bridge(bridge); | ||
598 | } | ||
599 | |||
600 | static struct pci_device_id agp_amd64_pci_table[] = { | ||
601 | { | ||
602 | .class = (PCI_CLASS_BRIDGE_HOST << 8), | ||
603 | .class_mask = ~0, | ||
604 | .vendor = PCI_VENDOR_ID_AMD, | ||
605 | .device = PCI_DEVICE_ID_AMD_8151_0, | ||
606 | .subvendor = PCI_ANY_ID, | ||
607 | .subdevice = PCI_ANY_ID, | ||
608 | }, | ||
609 | /* ULi M1689 */ | ||
610 | { | ||
611 | .class = (PCI_CLASS_BRIDGE_HOST << 8), | ||
612 | .class_mask = ~0, | ||
613 | .vendor = PCI_VENDOR_ID_AL, | ||
614 | .device = PCI_DEVICE_ID_AL_M1689, | ||
615 | .subvendor = PCI_ANY_ID, | ||
616 | .subdevice = PCI_ANY_ID, | ||
617 | }, | ||
618 | /* VIA K8T800Pro */ | ||
619 | { | ||
620 | .class = (PCI_CLASS_BRIDGE_HOST << 8), | ||
621 | .class_mask = ~0, | ||
622 | .vendor = PCI_VENDOR_ID_VIA, | ||
623 | .device = PCI_DEVICE_ID_VIA_K8T800PRO_0, | ||
624 | .subvendor = PCI_ANY_ID, | ||
625 | .subdevice = PCI_ANY_ID, | ||
626 | }, | ||
627 | /* VIA K8T800 */ | ||
628 | { | ||
629 | .class = (PCI_CLASS_BRIDGE_HOST << 8), | ||
630 | .class_mask = ~0, | ||
631 | .vendor = PCI_VENDOR_ID_VIA, | ||
632 | .device = PCI_DEVICE_ID_VIA_8385_0, | ||
633 | .subvendor = PCI_ANY_ID, | ||
634 | .subdevice = PCI_ANY_ID, | ||
635 | }, | ||
636 | /* VIA K8M800 / K8N800 */ | ||
637 | { | ||
638 | .class = (PCI_CLASS_BRIDGE_HOST << 8), | ||
639 | .class_mask = ~0, | ||
640 | .vendor = PCI_VENDOR_ID_VIA, | ||
641 | .device = PCI_DEVICE_ID_VIA_8380_0, | ||
642 | .subvendor = PCI_ANY_ID, | ||
643 | .subdevice = PCI_ANY_ID, | ||
644 | }, | ||
645 | /* VIA K8T890 */ | ||
646 | { | ||
647 | .class = (PCI_CLASS_BRIDGE_HOST << 8), | ||
648 | .class_mask = ~0, | ||
649 | .vendor = PCI_VENDOR_ID_VIA, | ||
650 | .device = PCI_DEVICE_ID_VIA_3238_0, | ||
651 | .subvendor = PCI_ANY_ID, | ||
652 | .subdevice = PCI_ANY_ID, | ||
653 | }, | ||
654 | /* VIA K8T800/K8M800/K8N800 */ | ||
655 | { | ||
656 | .class = (PCI_CLASS_BRIDGE_HOST << 8), | ||
657 | .class_mask = ~0, | ||
658 | .vendor = PCI_VENDOR_ID_VIA, | ||
659 | .device = PCI_DEVICE_ID_VIA_838X_1, | ||
660 | .subvendor = PCI_ANY_ID, | ||
661 | .subdevice = PCI_ANY_ID, | ||
662 | }, | ||
663 | /* NForce3 */ | ||
664 | { | ||
665 | .class = (PCI_CLASS_BRIDGE_HOST << 8), | ||
666 | .class_mask = ~0, | ||
667 | .vendor = PCI_VENDOR_ID_NVIDIA, | ||
668 | .device = PCI_DEVICE_ID_NVIDIA_NFORCE3, | ||
669 | .subvendor = PCI_ANY_ID, | ||
670 | .subdevice = PCI_ANY_ID, | ||
671 | }, | ||
672 | { | ||
673 | .class = (PCI_CLASS_BRIDGE_HOST << 8), | ||
674 | .class_mask = ~0, | ||
675 | .vendor = PCI_VENDOR_ID_NVIDIA, | ||
676 | .device = PCI_DEVICE_ID_NVIDIA_NFORCE3S, | ||
677 | .subvendor = PCI_ANY_ID, | ||
678 | .subdevice = PCI_ANY_ID, | ||
679 | }, | ||
680 | /* SIS 755 */ | ||
681 | { | ||
682 | .class = (PCI_CLASS_BRIDGE_HOST << 8), | ||
683 | .class_mask = ~0, | ||
684 | .vendor = PCI_VENDOR_ID_SI, | ||
685 | .device = PCI_DEVICE_ID_SI_755, | ||
686 | .subvendor = PCI_ANY_ID, | ||
687 | .subdevice = PCI_ANY_ID, | ||
688 | }, | ||
689 | { } | ||
690 | }; | ||
691 | |||
692 | MODULE_DEVICE_TABLE(pci, agp_amd64_pci_table); | ||
693 | |||
694 | static struct pci_driver agp_amd64_pci_driver = { | ||
695 | .name = "agpgart-amd64", | ||
696 | .id_table = agp_amd64_pci_table, | ||
697 | .probe = agp_amd64_probe, | ||
698 | .remove = agp_amd64_remove, | ||
699 | }; | ||
700 | |||
701 | |||
702 | /* Not static due to IOMMU code calling it early. */ | ||
703 | int __init agp_amd64_init(void) | ||
704 | { | ||
705 | int err = 0; | ||
706 | static struct pci_device_id amd64nb[] = { | ||
707 | { PCI_DEVICE(PCI_VENDOR_ID_AMD, 0x1103) }, | ||
708 | { }, | ||
709 | }; | ||
710 | |||
711 | if (agp_off) | ||
712 | return -EINVAL; | ||
713 | if (pci_register_driver(&agp_amd64_pci_driver) > 0) { | ||
714 | struct pci_dev *dev; | ||
715 | if (!agp_try_unsupported && !agp_try_unsupported_boot) { | ||
716 | printk(KERN_INFO PFX "No supported AGP bridge found.\n"); | ||
717 | #ifdef MODULE | ||
718 | printk(KERN_INFO PFX "You can try agp_try_unsupported=1\n"); | ||
719 | #else | ||
720 | printk(KERN_INFO PFX "You can boot with agp=try_unsupported\n"); | ||
721 | #endif | ||
722 | return -ENODEV; | ||
723 | } | ||
724 | |||
725 | /* First check that we have at least one AMD64 NB */ | ||
726 | if (!pci_dev_present(amd64nb)) | ||
727 | return -ENODEV; | ||
728 | |||
729 | /* Look for any AGP bridge */ | ||
730 | dev = NULL; | ||
731 | err = -ENODEV; | ||
732 | for_each_pci_dev(dev) { | ||
733 | if (!pci_find_capability(dev, PCI_CAP_ID_AGP)) | ||
734 | continue; | ||
735 | /* Only one bridge supported right now */ | ||
736 | if (agp_amd64_probe(dev, NULL) == 0) { | ||
737 | err = 0; | ||
738 | break; | ||
739 | } | ||
740 | } | ||
741 | } | ||
742 | return err; | ||
743 | } | ||
744 | |||
745 | static void __exit agp_amd64_cleanup(void) | ||
746 | { | ||
747 | if (aperture_resource) | ||
748 | release_resource(aperture_resource); | ||
749 | pci_unregister_driver(&agp_amd64_pci_driver); | ||
750 | } | ||
751 | |||
752 | /* On AMD64 the PCI driver needs to initialize this driver early | ||
753 | for the IOMMU, so it has to be called via a backdoor. */ | ||
754 | #ifndef CONFIG_GART_IOMMU | ||
755 | module_init(agp_amd64_init); | ||
756 | module_exit(agp_amd64_cleanup); | ||
757 | #endif | ||
758 | |||
759 | MODULE_AUTHOR("Dave Jones <davej@codemonkey.org.uk>, Andi Kleen"); | ||
760 | module_param(agp_try_unsupported, bool, 0); | ||
761 | MODULE_LICENSE("GPL"); | ||