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