blob: b487396c4c5bc4e8e3310a9702e03ea5b4e88ed9 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * Firmware replacement code.
3 *
4 * Work around broken BIOSes that don't set an aperture or only set the
5 * aperture in the AGP bridge.
6 * If all fails map the aperture over some low memory. This is cheaper than
7 * doing bounce buffering. The memory is lost. This is done at early boot
8 * because only the bootmem allocator can allocate 32+MB.
9 *
10 * Copyright 2002 Andi Kleen, SuSE Labs.
Linus Torvalds1da177e2005-04-16 15:20:36 -070011 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070012#include <linux/kernel.h>
13#include <linux/types.h>
14#include <linux/init.h>
15#include <linux/bootmem.h>
16#include <linux/mmzone.h>
17#include <linux/pci_ids.h>
18#include <linux/pci.h>
19#include <linux/bitops.h>
Aaron Durbin56dd6692006-09-26 10:52:40 +020020#include <linux/ioport.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070021#include <asm/e820.h>
22#include <asm/io.h>
23#include <asm/proto.h>
24#include <asm/pci-direct.h>
Andi Kleenca8642f2006-01-11 22:44:27 +010025#include <asm/dma.h>
Andi Kleena32073b2006-06-26 13:56:40 +020026#include <asm/k8.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070027
28int iommu_aperture;
29int iommu_aperture_disabled __initdata = 0;
30int iommu_aperture_allowed __initdata = 0;
31
32int fallback_aper_order __initdata = 1; /* 64MB */
33int fallback_aper_force __initdata = 0;
34
35int fix_aperture __initdata = 1;
36
Aaron Durbin56dd6692006-09-26 10:52:40 +020037static struct resource gart_resource = {
38 .name = "GART",
39 .flags = IORESOURCE_MEM,
40};
41
42static void __init insert_aperture_resource(u32 aper_base, u32 aper_size)
43{
44 gart_resource.start = aper_base;
45 gart_resource.end = aper_base + aper_size - 1;
46 insert_resource(&iomem_resource, &gart_resource);
47}
48
Andrew Morton42442ed2005-06-08 15:49:25 -070049/* This code runs before the PCI subsystem is initialized, so just
50 access the northbridge directly. */
Linus Torvalds1da177e2005-04-16 15:20:36 -070051
52static u32 __init allocate_aperture(void)
53{
Linus Torvalds1da177e2005-04-16 15:20:36 -070054 pg_data_t *nd0 = NODE_DATA(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070055 u32 aper_size;
56 void *p;
57
58 if (fallback_aper_order > 7)
59 fallback_aper_order = 7;
60 aper_size = (32 * 1024 * 1024) << fallback_aper_order;
61
62 /*
Andrew Morton42442ed2005-06-08 15:49:25 -070063 * Aperture has to be naturally aligned. This means an 2GB aperture won't
Adam Henleyd5d9ca62006-09-26 10:52:28 +020064 * have much chance of finding a place in the lower 4GB of memory.
Andrew Morton42442ed2005-06-08 15:49:25 -070065 * Unfortunately we cannot move it up because that would make the
66 * IOMMU useless.
Linus Torvalds1da177e2005-04-16 15:20:36 -070067 */
68 p = __alloc_bootmem_node(nd0, aper_size, aper_size, 0);
69 if (!p || __pa(p)+aper_size > 0xffffffff) {
70 printk("Cannot allocate aperture memory hole (%p,%uK)\n",
71 p, aper_size>>10);
72 if (p)
Jon Masonc912c2d2006-03-25 16:31:19 +010073 free_bootmem_node(nd0, __pa(p), aper_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -070074 return 0;
75 }
Andrew Morton42442ed2005-06-08 15:49:25 -070076 printk("Mapping aperture over %d KB of RAM @ %lx\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -070077 aper_size >> 10, __pa(p));
Aaron Durbin56dd6692006-09-26 10:52:40 +020078 insert_aperture_resource((u32)__pa(p), aper_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -070079 return (u32)__pa(p);
80}
81
Andi Kleena32073b2006-06-26 13:56:40 +020082static int __init aperture_valid(u64 aper_base, u32 aper_size)
Linus Torvalds1da177e2005-04-16 15:20:36 -070083{
84 if (!aper_base)
85 return 0;
86 if (aper_size < 64*1024*1024) {
Andi Kleena32073b2006-06-26 13:56:40 +020087 printk("Aperture too small (%d MB)\n", aper_size>>20);
Linus Torvalds1da177e2005-04-16 15:20:36 -070088 return 0;
89 }
90 if (aper_base + aper_size >= 0xffffffff) {
Andi Kleena32073b2006-06-26 13:56:40 +020091 printk("Aperture beyond 4GB. Ignoring.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -070092 return 0;
93 }
Arjan van de Veneee5a9f2006-04-07 19:49:24 +020094 if (e820_any_mapped(aper_base, aper_base + aper_size, E820_RAM)) {
Andi Kleena32073b2006-06-26 13:56:40 +020095 printk("Aperture pointing to e820 RAM. Ignoring.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -070096 return 0;
97 }
98 return 1;
99}
100
Andrew Morton42442ed2005-06-08 15:49:25 -0700101/* Find a PCI capability */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700102static __u32 __init find_cap(int num, int slot, int func, int cap)
103{
104 u8 pos;
105 int bytes;
106 if (!(read_pci_config_16(num,slot,func,PCI_STATUS) & PCI_STATUS_CAP_LIST))
107 return 0;
108 pos = read_pci_config_byte(num,slot,func,PCI_CAPABILITY_LIST);
109 for (bytes = 0; bytes < 48 && pos >= 0x40; bytes++) {
110 u8 id;
111 pos &= ~3;
112 id = read_pci_config_byte(num,slot,func,pos+PCI_CAP_LIST_ID);
113 if (id == 0xff)
114 break;
115 if (id == cap)
116 return pos;
117 pos = read_pci_config_byte(num,slot,func,pos+PCI_CAP_LIST_NEXT);
118 }
119 return 0;
120}
121
122/* Read a standard AGPv3 bridge header */
123static __u32 __init read_agp(int num, int slot, int func, int cap, u32 *order)
124{
125 u32 apsize;
126 u32 apsizereg;
127 int nbits;
128 u32 aper_low, aper_hi;
129 u64 aper;
130
131 printk("AGP bridge at %02x:%02x:%02x\n", num, slot, func);
132 apsizereg = read_pci_config_16(num,slot,func, cap + 0x14);
133 if (apsizereg == 0xffffffff) {
134 printk("APSIZE in AGP bridge unreadable\n");
135 return 0;
136 }
137
138 apsize = apsizereg & 0xfff;
139 /* Some BIOS use weird encodings not in the AGPv3 table. */
140 if (apsize & 0xff)
141 apsize |= 0xf00;
142 nbits = hweight16(apsize);
143 *order = 7 - nbits;
144 if ((int)*order < 0) /* < 32MB */
145 *order = 0;
146
147 aper_low = read_pci_config(num,slot,func, 0x10);
148 aper_hi = read_pci_config(num,slot,func,0x14);
149 aper = (aper_low & ~((1<<22)-1)) | ((u64)aper_hi << 32);
150
151 printk("Aperture from AGP @ %Lx size %u MB (APSIZE %x)\n",
152 aper, 32 << *order, apsizereg);
153
Andi Kleena32073b2006-06-26 13:56:40 +0200154 if (!aperture_valid(aper, (32*1024*1024) << *order))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700155 return 0;
156 return (u32)aper;
157}
158
159/* Look for an AGP bridge. Windows only expects the aperture in the
160 AGP bridge and some BIOS forget to initialize the Northbridge too.
161 Work around this here.
162
163 Do an PCI bus scan by hand because we're running before the PCI
164 subsystem.
165
166 All K8 AGP bridges are AGPv3 compliant, so we can do this scan
167 generically. It's probably overkill to always scan all slots because
168 the AGP bridges should be always an own bus on the HT hierarchy,
169 but do it here for future safety. */
170static __u32 __init search_agp_bridge(u32 *order, int *valid_agp)
171{
172 int num, slot, func;
173
174 /* Poor man's PCI discovery */
Navin Boppuri9c01dda2006-03-25 16:31:40 +0100175 for (num = 0; num < 256; num++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700176 for (slot = 0; slot < 32; slot++) {
177 for (func = 0; func < 8; func++) {
178 u32 class, cap;
179 u8 type;
180 class = read_pci_config(num,slot,func,
181 PCI_CLASS_REVISION);
182 if (class == 0xffffffff)
183 break;
184
185 switch (class >> 16) {
186 case PCI_CLASS_BRIDGE_HOST:
187 case PCI_CLASS_BRIDGE_OTHER: /* needed? */
188 /* AGP bridge? */
189 cap = find_cap(num,slot,func,PCI_CAP_ID_AGP);
190 if (!cap)
191 break;
192 *valid_agp = 1;
193 return read_agp(num,slot,func,cap,order);
194 }
195
196 /* No multi-function device? */
197 type = read_pci_config_byte(num,slot,func,
198 PCI_HEADER_TYPE);
199 if (!(type & 0x80))
200 break;
201 }
202 }
203 }
204 printk("No AGP bridge found\n");
205 return 0;
206}
207
208void __init iommu_hole_init(void)
209{
210 int fix, num;
Andi Kleen50895c52005-11-05 17:25:53 +0100211 u32 aper_size, aper_alloc = 0, aper_order = 0, last_aper_order = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700212 u64 aper_base, last_aper_base = 0;
213 int valid_agp = 0;
214
Andi Kleen0637a702006-09-26 10:52:41 +0200215 if (iommu_aperture_disabled || !fix_aperture || !early_pci_allowed())
Linus Torvalds1da177e2005-04-16 15:20:36 -0700216 return;
217
218 printk("Checking aperture...\n");
219
220 fix = 0;
221 for (num = 24; num < 32; num++) {
Andi Kleena32073b2006-06-26 13:56:40 +0200222 if (!early_is_k8_nb(read_pci_config(0, num, 3, 0x00)))
223 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700224
Jon Mason8d4f6b92006-06-26 13:58:05 +0200225 iommu_detected = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700226 iommu_aperture = 1;
227
228 aper_order = (read_pci_config(0, num, 3, 0x90) >> 1) & 7;
229 aper_size = (32 * 1024 * 1024) << aper_order;
230 aper_base = read_pci_config(0, num, 3, 0x94) & 0x7fff;
231 aper_base <<= 25;
232
233 printk("CPU %d: aperture @ %Lx size %u MB\n", num-24,
234 aper_base, aper_size>>20);
235
Andi Kleena32073b2006-06-26 13:56:40 +0200236 if (!aperture_valid(aper_base, aper_size)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237 fix = 1;
238 break;
239 }
240
241 if ((last_aper_order && aper_order != last_aper_order) ||
242 (last_aper_base && aper_base != last_aper_base)) {
243 fix = 1;
244 break;
245 }
246 last_aper_order = aper_order;
247 last_aper_base = aper_base;
248 }
249
Aaron Durbin56dd6692006-09-26 10:52:40 +0200250 if (!fix && !fallback_aper_force) {
251 if (last_aper_base) {
252 unsigned long n = (32 * 1024 * 1024) << last_aper_order;
253 insert_aperture_resource((u32)last_aper_base, n);
254 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700255 return;
Aaron Durbin56dd6692006-09-26 10:52:40 +0200256 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700257
258 if (!fallback_aper_force)
259 aper_alloc = search_agp_bridge(&aper_order, &valid_agp);
260
261 if (aper_alloc) {
262 /* Got the aperture from the AGP bridge */
Andi Kleen63f02fd2005-09-12 18:49:24 +0200263 } else if (swiotlb && !valid_agp) {
264 /* Do nothing */
Jon Mason60b08c62006-02-26 04:18:22 +0100265 } else if ((!no_iommu && end_pfn > MAX_DMA32_PFN) ||
Linus Torvalds1da177e2005-04-16 15:20:36 -0700266 force_iommu ||
267 valid_agp ||
268 fallback_aper_force) {
269 printk("Your BIOS doesn't leave a aperture memory hole\n");
270 printk("Please enable the IOMMU option in the BIOS setup\n");
Andrew Morton42442ed2005-06-08 15:49:25 -0700271 printk("This costs you %d MB of RAM\n",
272 32 << fallback_aper_order);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700273
274 aper_order = fallback_aper_order;
275 aper_alloc = allocate_aperture();
276 if (!aper_alloc) {
277 /* Could disable AGP and IOMMU here, but it's probably
278 not worth it. But the later users cannot deal with
279 bad apertures and turning on the aperture over memory
280 causes very strange problems, so it's better to
281 panic early. */
282 panic("Not enough memory for aperture");
283 }
284 } else {
285 return;
286 }
287
288 /* Fix up the north bridges */
289 for (num = 24; num < 32; num++) {
Andi Kleena32073b2006-06-26 13:56:40 +0200290 if (!early_is_k8_nb(read_pci_config(0, num, 3, 0x00)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291 continue;
292
293 /* Don't enable translation yet. That is done later.
294 Assume this BIOS didn't initialise the GART so
295 just overwrite all previous bits */
296 write_pci_config(0, num, 3, 0x90, aper_order<<1);
297 write_pci_config(0, num, 3, 0x94, aper_alloc>>25);
298 }
299}