Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
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. | |
1da177e4 | 11 | */ |
1da177e4 LT |
12 | #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> | |
56dd669a | 20 | #include <linux/ioport.h> |
1da177e4 LT |
21 | #include <asm/e820.h> |
22 | #include <asm/io.h> | |
f2cf8e08 | 23 | #include <asm/iommu.h> |
1da177e4 | 24 | #include <asm/pci-direct.h> |
ca8642f6 | 25 | #include <asm/dma.h> |
a32073bf | 26 | #include <asm/k8.h> |
1da177e4 LT |
27 | |
28 | int iommu_aperture; | |
29 | int iommu_aperture_disabled __initdata = 0; | |
30 | int iommu_aperture_allowed __initdata = 0; | |
31 | ||
32 | int fallback_aper_order __initdata = 1; /* 64MB */ | |
33 | int fallback_aper_force __initdata = 0; | |
34 | ||
35 | int fix_aperture __initdata = 1; | |
36 | ||
56dd669a AD |
37 | static struct resource gart_resource = { |
38 | .name = "GART", | |
39 | .flags = IORESOURCE_MEM, | |
40 | }; | |
41 | ||
42 | static 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 | ||
42442ed5 AM |
49 | /* This code runs before the PCI subsystem is initialized, so just |
50 | access the northbridge directly. */ | |
1da177e4 LT |
51 | |
52 | static u32 __init allocate_aperture(void) | |
53 | { | |
1da177e4 LT |
54 | u32 aper_size; |
55 | void *p; | |
56 | ||
57 | if (fallback_aper_order > 7) | |
58 | fallback_aper_order = 7; | |
59 | aper_size = (32 * 1024 * 1024) << fallback_aper_order; | |
60 | ||
61 | /* | |
42442ed5 | 62 | * Aperture has to be naturally aligned. This means an 2GB aperture won't |
d5d9ca6d | 63 | * have much chance of finding a place in the lower 4GB of memory. |
42442ed5 AM |
64 | * Unfortunately we cannot move it up because that would make the |
65 | * IOMMU useless. | |
1da177e4 | 66 | */ |
82d1bb72 | 67 | p = __alloc_bootmem_nopanic(aper_size, aper_size, 0); |
1da177e4 LT |
68 | if (!p || __pa(p)+aper_size > 0xffffffff) { |
69 | printk("Cannot allocate aperture memory hole (%p,%uK)\n", | |
70 | p, aper_size>>10); | |
71 | if (p) | |
82d1bb72 | 72 | free_bootmem(__pa(p), aper_size); |
1da177e4 LT |
73 | return 0; |
74 | } | |
42442ed5 | 75 | printk("Mapping aperture over %d KB of RAM @ %lx\n", |
1da177e4 | 76 | aper_size >> 10, __pa(p)); |
56dd669a | 77 | insert_aperture_resource((u32)__pa(p), aper_size); |
1da177e4 LT |
78 | return (u32)__pa(p); |
79 | } | |
80 | ||
a32073bf | 81 | static int __init aperture_valid(u64 aper_base, u32 aper_size) |
1da177e4 LT |
82 | { |
83 | if (!aper_base) | |
84 | return 0; | |
85 | if (aper_size < 64*1024*1024) { | |
a32073bf | 86 | printk("Aperture too small (%d MB)\n", aper_size>>20); |
1da177e4 LT |
87 | return 0; |
88 | } | |
547c5355 | 89 | if (aper_base + aper_size > 0x100000000UL) { |
a32073bf | 90 | printk("Aperture beyond 4GB. Ignoring.\n"); |
1da177e4 LT |
91 | return 0; |
92 | } | |
eee5a9fa | 93 | if (e820_any_mapped(aper_base, aper_base + aper_size, E820_RAM)) { |
a32073bf | 94 | printk("Aperture pointing to e820 RAM. Ignoring.\n"); |
1da177e4 LT |
95 | return 0; |
96 | } | |
97 | return 1; | |
98 | } | |
99 | ||
42442ed5 | 100 | /* Find a PCI capability */ |
1da177e4 LT |
101 | static __u32 __init find_cap(int num, int slot, int func, int cap) |
102 | { | |
103 | u8 pos; | |
104 | int bytes; | |
105 | if (!(read_pci_config_16(num,slot,func,PCI_STATUS) & PCI_STATUS_CAP_LIST)) | |
106 | return 0; | |
107 | pos = read_pci_config_byte(num,slot,func,PCI_CAPABILITY_LIST); | |
108 | for (bytes = 0; bytes < 48 && pos >= 0x40; bytes++) { | |
109 | u8 id; | |
110 | pos &= ~3; | |
111 | id = read_pci_config_byte(num,slot,func,pos+PCI_CAP_LIST_ID); | |
112 | if (id == 0xff) | |
113 | break; | |
114 | if (id == cap) | |
115 | return pos; | |
116 | pos = read_pci_config_byte(num,slot,func,pos+PCI_CAP_LIST_NEXT); | |
117 | } | |
118 | return 0; | |
119 | } | |
120 | ||
121 | /* Read a standard AGPv3 bridge header */ | |
122 | static __u32 __init read_agp(int num, int slot, int func, int cap, u32 *order) | |
123 | { | |
124 | u32 apsize; | |
125 | u32 apsizereg; | |
126 | int nbits; | |
127 | u32 aper_low, aper_hi; | |
128 | u64 aper; | |
129 | ||
130 | printk("AGP bridge at %02x:%02x:%02x\n", num, slot, func); | |
131 | apsizereg = read_pci_config_16(num,slot,func, cap + 0x14); | |
132 | if (apsizereg == 0xffffffff) { | |
133 | printk("APSIZE in AGP bridge unreadable\n"); | |
134 | return 0; | |
135 | } | |
136 | ||
137 | apsize = apsizereg & 0xfff; | |
138 | /* Some BIOS use weird encodings not in the AGPv3 table. */ | |
139 | if (apsize & 0xff) | |
140 | apsize |= 0xf00; | |
141 | nbits = hweight16(apsize); | |
142 | *order = 7 - nbits; | |
143 | if ((int)*order < 0) /* < 32MB */ | |
144 | *order = 0; | |
145 | ||
146 | aper_low = read_pci_config(num,slot,func, 0x10); | |
147 | aper_hi = read_pci_config(num,slot,func,0x14); | |
148 | aper = (aper_low & ~((1<<22)-1)) | ((u64)aper_hi << 32); | |
149 | ||
150 | printk("Aperture from AGP @ %Lx size %u MB (APSIZE %x)\n", | |
151 | aper, 32 << *order, apsizereg); | |
152 | ||
a32073bf | 153 | if (!aperture_valid(aper, (32*1024*1024) << *order)) |
1da177e4 LT |
154 | return 0; |
155 | return (u32)aper; | |
156 | } | |
157 | ||
158 | /* Look for an AGP bridge. Windows only expects the aperture in the | |
159 | AGP bridge and some BIOS forget to initialize the Northbridge too. | |
160 | Work around this here. | |
161 | ||
162 | Do an PCI bus scan by hand because we're running before the PCI | |
163 | subsystem. | |
164 | ||
165 | All K8 AGP bridges are AGPv3 compliant, so we can do this scan | |
166 | generically. It's probably overkill to always scan all slots because | |
167 | the AGP bridges should be always an own bus on the HT hierarchy, | |
168 | but do it here for future safety. */ | |
169 | static __u32 __init search_agp_bridge(u32 *order, int *valid_agp) | |
170 | { | |
171 | int num, slot, func; | |
172 | ||
173 | /* Poor man's PCI discovery */ | |
9c01dda0 | 174 | for (num = 0; num < 256; num++) { |
1da177e4 LT |
175 | for (slot = 0; slot < 32; slot++) { |
176 | for (func = 0; func < 8; func++) { | |
177 | u32 class, cap; | |
178 | u8 type; | |
179 | class = read_pci_config(num,slot,func, | |
180 | PCI_CLASS_REVISION); | |
181 | if (class == 0xffffffff) | |
182 | break; | |
183 | ||
184 | switch (class >> 16) { | |
185 | case PCI_CLASS_BRIDGE_HOST: | |
186 | case PCI_CLASS_BRIDGE_OTHER: /* needed? */ | |
187 | /* AGP bridge? */ | |
188 | cap = find_cap(num,slot,func,PCI_CAP_ID_AGP); | |
189 | if (!cap) | |
190 | break; | |
191 | *valid_agp = 1; | |
192 | return read_agp(num,slot,func,cap,order); | |
193 | } | |
194 | ||
195 | /* No multi-function device? */ | |
196 | type = read_pci_config_byte(num,slot,func, | |
197 | PCI_HEADER_TYPE); | |
198 | if (!(type & 0x80)) | |
199 | break; | |
200 | } | |
201 | } | |
202 | } | |
203 | printk("No AGP bridge found\n"); | |
204 | return 0; | |
205 | } | |
206 | ||
207 | void __init iommu_hole_init(void) | |
208 | { | |
209 | int fix, num; | |
50895c5d | 210 | u32 aper_size, aper_alloc = 0, aper_order = 0, last_aper_order = 0; |
1da177e4 LT |
211 | u64 aper_base, last_aper_base = 0; |
212 | int valid_agp = 0; | |
213 | ||
0637a70a | 214 | if (iommu_aperture_disabled || !fix_aperture || !early_pci_allowed()) |
1da177e4 LT |
215 | return; |
216 | ||
753811dc | 217 | printk(KERN_INFO "Checking aperture...\n"); |
1da177e4 LT |
218 | |
219 | fix = 0; | |
220 | for (num = 24; num < 32; num++) { | |
a32073bf AK |
221 | if (!early_is_k8_nb(read_pci_config(0, num, 3, 0x00))) |
222 | continue; | |
1da177e4 | 223 | |
8d4f6b93 | 224 | iommu_detected = 1; |
1da177e4 LT |
225 | iommu_aperture = 1; |
226 | ||
227 | aper_order = (read_pci_config(0, num, 3, 0x90) >> 1) & 7; | |
228 | aper_size = (32 * 1024 * 1024) << aper_order; | |
229 | aper_base = read_pci_config(0, num, 3, 0x94) & 0x7fff; | |
230 | aper_base <<= 25; | |
231 | ||
232 | printk("CPU %d: aperture @ %Lx size %u MB\n", num-24, | |
233 | aper_base, aper_size>>20); | |
234 | ||
a32073bf | 235 | if (!aperture_valid(aper_base, aper_size)) { |
1da177e4 LT |
236 | fix = 1; |
237 | break; | |
238 | } | |
239 | ||
240 | if ((last_aper_order && aper_order != last_aper_order) || | |
241 | (last_aper_base && aper_base != last_aper_base)) { | |
242 | fix = 1; | |
243 | break; | |
244 | } | |
245 | last_aper_order = aper_order; | |
246 | last_aper_base = aper_base; | |
247 | } | |
248 | ||
56dd669a AD |
249 | if (!fix && !fallback_aper_force) { |
250 | if (last_aper_base) { | |
251 | unsigned long n = (32 * 1024 * 1024) << last_aper_order; | |
252 | insert_aperture_resource((u32)last_aper_base, n); | |
253 | } | |
1da177e4 | 254 | return; |
56dd669a | 255 | } |
1da177e4 LT |
256 | |
257 | if (!fallback_aper_force) | |
258 | aper_alloc = search_agp_bridge(&aper_order, &valid_agp); | |
259 | ||
260 | if (aper_alloc) { | |
261 | /* Got the aperture from the AGP bridge */ | |
63f02fd7 AK |
262 | } else if (swiotlb && !valid_agp) { |
263 | /* Do nothing */ | |
60b08c67 | 264 | } else if ((!no_iommu && end_pfn > MAX_DMA32_PFN) || |
1da177e4 LT |
265 | force_iommu || |
266 | valid_agp || | |
267 | fallback_aper_force) { | |
268 | printk("Your BIOS doesn't leave a aperture memory hole\n"); | |
269 | printk("Please enable the IOMMU option in the BIOS setup\n"); | |
42442ed5 AM |
270 | printk("This costs you %d MB of RAM\n", |
271 | 32 << fallback_aper_order); | |
1da177e4 LT |
272 | |
273 | aper_order = fallback_aper_order; | |
274 | aper_alloc = allocate_aperture(); | |
275 | if (!aper_alloc) { | |
276 | /* Could disable AGP and IOMMU here, but it's probably | |
277 | not worth it. But the later users cannot deal with | |
278 | bad apertures and turning on the aperture over memory | |
279 | causes very strange problems, so it's better to | |
280 | panic early. */ | |
281 | panic("Not enough memory for aperture"); | |
282 | } | |
283 | } else { | |
284 | return; | |
285 | } | |
286 | ||
287 | /* Fix up the north bridges */ | |
288 | for (num = 24; num < 32; num++) { | |
a32073bf | 289 | if (!early_is_k8_nb(read_pci_config(0, num, 3, 0x00))) |
1da177e4 LT |
290 | continue; |
291 | ||
292 | /* Don't enable translation yet. That is done later. | |
293 | Assume this BIOS didn't initialise the GART so | |
294 | just overwrite all previous bits */ | |
295 | write_pci_config(0, num, 3, 0x90, aper_order<<1); | |
296 | write_pci_config(0, num, 3, 0x94, aper_alloc>>25); | |
297 | } | |
298 | } |