[PATCH] x86_64: Rename e820_mapped to e820_any_mapped
[linux-2.6/linux-acpi-2.6/ibm-acpi-2.6.git] / arch / x86_64 / kernel / aperture.c
blob70b9d21ed675b1aabe1874d785fa5f0b98e3b87d
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 $
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>
26 #include <asm/dma.h>
28 int iommu_aperture;
29 int iommu_aperture_disabled __initdata = 0;
30 int iommu_aperture_allowed __initdata = 0;
32 int fallback_aper_order __initdata = 1; /* 64MB */
33 int fallback_aper_force __initdata = 0;
35 int fix_aperture __initdata = 1;
37 /* This code runs before the PCI subsystem is initialized, so just
38 access the northbridge directly. */
40 #define NB_ID_3 (PCI_VENDOR_ID_AMD | (0x1103<<16))
42 static u32 __init allocate_aperture(void)
44 pg_data_t *nd0 = NODE_DATA(0);
45 u32 aper_size;
46 void *p;
48 if (fallback_aper_order > 7)
49 fallback_aper_order = 7;
50 aper_size = (32 * 1024 * 1024) << fallback_aper_order;
52 /*
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.
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)
63 free_bootmem_node(nd0, __pa(p), aper_size);
64 return 0;
66 printk("Mapping aperture over %d KB of RAM @ %lx\n",
67 aper_size >> 10, __pa(p));
68 return (u32)__pa(p);
71 static int __init aperture_valid(char *name, u64 aper_base, u32 aper_size)
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;
79 if (aper_base + aper_size >= 0xffffffff) {
80 printk("Aperture from %s beyond 4GB. Ignoring.\n",name);
81 return 0;
83 if (e820_any_mapped(aper_base, aper_base + aper_size, E820_RAM)) {
84 printk("Aperture from %s pointing to e820 RAM. Ignoring.\n",name);
85 return 0;
87 return 1;
90 /* Find a PCI capability */
91 static __u32 __init find_cap(int num, int slot, int func, int cap)
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);
108 return 0;
111 /* Read a standard AGPv3 bridge header */
112 static __u32 __init read_agp(int num, int slot, int func, int cap, u32 *order)
114 u32 apsize;
115 u32 apsizereg;
116 int nbits;
117 u32 aper_low, aper_hi;
118 u64 aper;
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;
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;
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);
140 printk("Aperture from AGP @ %Lx size %u MB (APSIZE %x)\n",
141 aper, 32 << *order, apsizereg);
143 if (!aperture_valid("AGP bridge", aper, (32*1024*1024) << *order))
144 return 0;
145 return (u32)aper;
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.
152 Do an PCI bus scan by hand because we're running before the PCI
153 subsystem.
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)
161 int num, slot, func;
163 /* Poor man's PCI discovery */
164 for (num = 0; num < 256; num++) {
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;
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);
185 /* No multi-function device? */
186 type = read_pci_config_byte(num,slot,func,
187 PCI_HEADER_TYPE);
188 if (!(type & 0x80))
189 break;
193 printk("No AGP bridge found\n");
194 return 0;
197 void __init iommu_hole_init(void)
199 int fix, num;
200 u32 aper_size, aper_alloc = 0, aper_order = 0, last_aper_order = 0;
201 u64 aper_base, last_aper_base = 0;
202 int valid_agp = 0;
204 if (iommu_aperture_disabled || !fix_aperture)
205 return;
207 printk("Checking aperture...\n");
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;
215 iommu_aperture = 1;
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;
222 printk("CPU %d: aperture @ %Lx size %u MB\n", num-24,
223 aper_base, aper_size>>20);
225 sprintf(name, "northbridge cpu %d", num-24);
227 if (!aperture_valid(name, aper_base, aper_size)) {
228 fix = 1;
229 break;
232 if ((last_aper_order && aper_order != last_aper_order) ||
233 (last_aper_base && aper_base != last_aper_base)) {
234 fix = 1;
235 break;
237 last_aper_order = aper_order;
238 last_aper_base = aper_base;
241 if (!fix && !fallback_aper_force)
242 return;
244 if (!fallback_aper_force)
245 aper_alloc = search_agp_bridge(&aper_order, &valid_agp);
247 if (aper_alloc) {
248 /* Got the aperture from the AGP bridge */
249 } else if (swiotlb && !valid_agp) {
250 /* Do nothing */
251 } else if ((!no_iommu && end_pfn > MAX_DMA32_PFN) ||
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");
257 printk("This costs you %d MB of RAM\n",
258 32 << fallback_aper_order);
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");
270 } else {
271 return;
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;
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);