blob: a195ef06ec5553e7c9f3fa7eb12fbb4078bd826c [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 */
12#include <linux/config.h>
13#include <linux/kernel.h>
14#include <linux/types.h>
15#include <linux/init.h>
16#include <linux/bootmem.h>
17#include <linux/mmzone.h>
18#include <linux/pci_ids.h>
19#include <linux/pci.h>
20#include <linux/bitops.h>
21#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
Andrew Morton42442ed2005-06-08 15:49:25 -070037/* This code runs before the PCI subsystem is initialized, so just
38 access the northbridge directly. */
Linus Torvalds1da177e2005-04-16 15:20:36 -070039
40static u32 __init allocate_aperture(void)
41{
Linus Torvalds1da177e2005-04-16 15:20:36 -070042 pg_data_t *nd0 = NODE_DATA(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070043 u32 aper_size;
44 void *p;
45
46 if (fallback_aper_order > 7)
47 fallback_aper_order = 7;
48 aper_size = (32 * 1024 * 1024) << fallback_aper_order;
49
50 /*
Andrew Morton42442ed2005-06-08 15:49:25 -070051 * Aperture has to be naturally aligned. This means an 2GB aperture won't
52 * have much chances to find a place in the lower 4GB of memory.
53 * Unfortunately we cannot move it up because that would make the
54 * IOMMU useless.
Linus Torvalds1da177e2005-04-16 15:20:36 -070055 */
56 p = __alloc_bootmem_node(nd0, aper_size, aper_size, 0);
57 if (!p || __pa(p)+aper_size > 0xffffffff) {
58 printk("Cannot allocate aperture memory hole (%p,%uK)\n",
59 p, aper_size>>10);
60 if (p)
Jon Masonc912c2d2006-03-25 16:31:19 +010061 free_bootmem_node(nd0, __pa(p), aper_size);
Linus Torvalds1da177e2005-04-16 15:20:36 -070062 return 0;
63 }
Andrew Morton42442ed2005-06-08 15:49:25 -070064 printk("Mapping aperture over %d KB of RAM @ %lx\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -070065 aper_size >> 10, __pa(p));
66 return (u32)__pa(p);
67}
68
Andi Kleena32073b2006-06-26 13:56:40 +020069static int __init aperture_valid(u64 aper_base, u32 aper_size)
Linus Torvalds1da177e2005-04-16 15:20:36 -070070{
71 if (!aper_base)
72 return 0;
73 if (aper_size < 64*1024*1024) {
Andi Kleena32073b2006-06-26 13:56:40 +020074 printk("Aperture too small (%d MB)\n", aper_size>>20);
Linus Torvalds1da177e2005-04-16 15:20:36 -070075 return 0;
76 }
77 if (aper_base + aper_size >= 0xffffffff) {
Andi Kleena32073b2006-06-26 13:56:40 +020078 printk("Aperture beyond 4GB. Ignoring.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -070079 return 0;
80 }
Arjan van de Veneee5a9f2006-04-07 19:49:24 +020081 if (e820_any_mapped(aper_base, aper_base + aper_size, E820_RAM)) {
Andi Kleena32073b2006-06-26 13:56:40 +020082 printk("Aperture pointing to e820 RAM. Ignoring.\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -070083 return 0;
84 }
85 return 1;
86}
87
Andrew Morton42442ed2005-06-08 15:49:25 -070088/* Find a PCI capability */
Linus Torvalds1da177e2005-04-16 15:20:36 -070089static __u32 __init find_cap(int num, int slot, int func, int cap)
90{
91 u8 pos;
92 int bytes;
93 if (!(read_pci_config_16(num,slot,func,PCI_STATUS) & PCI_STATUS_CAP_LIST))
94 return 0;
95 pos = read_pci_config_byte(num,slot,func,PCI_CAPABILITY_LIST);
96 for (bytes = 0; bytes < 48 && pos >= 0x40; bytes++) {
97 u8 id;
98 pos &= ~3;
99 id = read_pci_config_byte(num,slot,func,pos+PCI_CAP_LIST_ID);
100 if (id == 0xff)
101 break;
102 if (id == cap)
103 return pos;
104 pos = read_pci_config_byte(num,slot,func,pos+PCI_CAP_LIST_NEXT);
105 }
106 return 0;
107}
108
109/* Read a standard AGPv3 bridge header */
110static __u32 __init read_agp(int num, int slot, int func, int cap, u32 *order)
111{
112 u32 apsize;
113 u32 apsizereg;
114 int nbits;
115 u32 aper_low, aper_hi;
116 u64 aper;
117
118 printk("AGP bridge at %02x:%02x:%02x\n", num, slot, func);
119 apsizereg = read_pci_config_16(num,slot,func, cap + 0x14);
120 if (apsizereg == 0xffffffff) {
121 printk("APSIZE in AGP bridge unreadable\n");
122 return 0;
123 }
124
125 apsize = apsizereg & 0xfff;
126 /* Some BIOS use weird encodings not in the AGPv3 table. */
127 if (apsize & 0xff)
128 apsize |= 0xf00;
129 nbits = hweight16(apsize);
130 *order = 7 - nbits;
131 if ((int)*order < 0) /* < 32MB */
132 *order = 0;
133
134 aper_low = read_pci_config(num,slot,func, 0x10);
135 aper_hi = read_pci_config(num,slot,func,0x14);
136 aper = (aper_low & ~((1<<22)-1)) | ((u64)aper_hi << 32);
137
138 printk("Aperture from AGP @ %Lx size %u MB (APSIZE %x)\n",
139 aper, 32 << *order, apsizereg);
140
Andi Kleena32073b2006-06-26 13:56:40 +0200141 if (!aperture_valid(aper, (32*1024*1024) << *order))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700142 return 0;
143 return (u32)aper;
144}
145
146/* Look for an AGP bridge. Windows only expects the aperture in the
147 AGP bridge and some BIOS forget to initialize the Northbridge too.
148 Work around this here.
149
150 Do an PCI bus scan by hand because we're running before the PCI
151 subsystem.
152
153 All K8 AGP bridges are AGPv3 compliant, so we can do this scan
154 generically. It's probably overkill to always scan all slots because
155 the AGP bridges should be always an own bus on the HT hierarchy,
156 but do it here for future safety. */
157static __u32 __init search_agp_bridge(u32 *order, int *valid_agp)
158{
159 int num, slot, func;
160
161 /* Poor man's PCI discovery */
Navin Boppuri9c01dda2006-03-25 16:31:40 +0100162 for (num = 0; num < 256; num++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700163 for (slot = 0; slot < 32; slot++) {
164 for (func = 0; func < 8; func++) {
165 u32 class, cap;
166 u8 type;
167 class = read_pci_config(num,slot,func,
168 PCI_CLASS_REVISION);
169 if (class == 0xffffffff)
170 break;
171
172 switch (class >> 16) {
173 case PCI_CLASS_BRIDGE_HOST:
174 case PCI_CLASS_BRIDGE_OTHER: /* needed? */
175 /* AGP bridge? */
176 cap = find_cap(num,slot,func,PCI_CAP_ID_AGP);
177 if (!cap)
178 break;
179 *valid_agp = 1;
180 return read_agp(num,slot,func,cap,order);
181 }
182
183 /* No multi-function device? */
184 type = read_pci_config_byte(num,slot,func,
185 PCI_HEADER_TYPE);
186 if (!(type & 0x80))
187 break;
188 }
189 }
190 }
191 printk("No AGP bridge found\n");
192 return 0;
193}
194
195void __init iommu_hole_init(void)
196{
197 int fix, num;
Andi Kleen50895c52005-11-05 17:25:53 +0100198 u32 aper_size, aper_alloc = 0, aper_order = 0, last_aper_order = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700199 u64 aper_base, last_aper_base = 0;
200 int valid_agp = 0;
201
202 if (iommu_aperture_disabled || !fix_aperture)
203 return;
204
205 printk("Checking aperture...\n");
206
207 fix = 0;
208 for (num = 24; num < 32; num++) {
Andi Kleena32073b2006-06-26 13:56:40 +0200209 if (!early_is_k8_nb(read_pci_config(0, num, 3, 0x00)))
210 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700211
Jon Mason8d4f6b92006-06-26 13:58:05 +0200212 iommu_detected = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700213 iommu_aperture = 1;
214
215 aper_order = (read_pci_config(0, num, 3, 0x90) >> 1) & 7;
216 aper_size = (32 * 1024 * 1024) << aper_order;
217 aper_base = read_pci_config(0, num, 3, 0x94) & 0x7fff;
218 aper_base <<= 25;
219
220 printk("CPU %d: aperture @ %Lx size %u MB\n", num-24,
221 aper_base, aper_size>>20);
222
Andi Kleena32073b2006-06-26 13:56:40 +0200223 if (!aperture_valid(aper_base, aper_size)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700224 fix = 1;
225 break;
226 }
227
228 if ((last_aper_order && aper_order != last_aper_order) ||
229 (last_aper_base && aper_base != last_aper_base)) {
230 fix = 1;
231 break;
232 }
233 last_aper_order = aper_order;
234 last_aper_base = aper_base;
235 }
236
237 if (!fix && !fallback_aper_force)
238 return;
239
240 if (!fallback_aper_force)
241 aper_alloc = search_agp_bridge(&aper_order, &valid_agp);
242
243 if (aper_alloc) {
244 /* Got the aperture from the AGP bridge */
Andi Kleen63f02fd2005-09-12 18:49:24 +0200245 } else if (swiotlb && !valid_agp) {
246 /* Do nothing */
Jon Mason60b08c62006-02-26 04:18:22 +0100247 } else if ((!no_iommu && end_pfn > MAX_DMA32_PFN) ||
Linus Torvalds1da177e2005-04-16 15:20:36 -0700248 force_iommu ||
249 valid_agp ||
250 fallback_aper_force) {
251 printk("Your BIOS doesn't leave a aperture memory hole\n");
252 printk("Please enable the IOMMU option in the BIOS setup\n");
Andrew Morton42442ed2005-06-08 15:49:25 -0700253 printk("This costs you %d MB of RAM\n",
254 32 << fallback_aper_order);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700255
256 aper_order = fallback_aper_order;
257 aper_alloc = allocate_aperture();
258 if (!aper_alloc) {
259 /* Could disable AGP and IOMMU here, but it's probably
260 not worth it. But the later users cannot deal with
261 bad apertures and turning on the aperture over memory
262 causes very strange problems, so it's better to
263 panic early. */
264 panic("Not enough memory for aperture");
265 }
266 } else {
267 return;
268 }
269
270 /* Fix up the north bridges */
271 for (num = 24; num < 32; num++) {
Andi Kleena32073b2006-06-26 13:56:40 +0200272 if (!early_is_k8_nb(read_pci_config(0, num, 3, 0x00)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700273 continue;
274
275 /* Don't enable translation yet. That is done later.
276 Assume this BIOS didn't initialise the GART so
277 just overwrite all previous bits */
278 write_pci_config(0, num, 3, 0x90, aper_order<<1);
279 write_pci_config(0, num, 3, 0x94, aper_alloc>>25);
280 }
281}