1250c2277SThomas Gleixner /* 2250c2277SThomas Gleixner * Firmware replacement code. 3250c2277SThomas Gleixner * 4250c2277SThomas Gleixner * Work around broken BIOSes that don't set an aperture or only set the 5250c2277SThomas Gleixner * aperture in the AGP bridge. 6250c2277SThomas Gleixner * If all fails map the aperture over some low memory. This is cheaper than 7250c2277SThomas Gleixner * doing bounce buffering. The memory is lost. This is done at early boot 8250c2277SThomas Gleixner * because only the bootmem allocator can allocate 32+MB. 9250c2277SThomas Gleixner * 10250c2277SThomas Gleixner * Copyright 2002 Andi Kleen, SuSE Labs. 11250c2277SThomas Gleixner */ 12250c2277SThomas Gleixner #include <linux/kernel.h> 13250c2277SThomas Gleixner #include <linux/types.h> 14250c2277SThomas Gleixner #include <linux/init.h> 15250c2277SThomas Gleixner #include <linux/bootmem.h> 16250c2277SThomas Gleixner #include <linux/mmzone.h> 17250c2277SThomas Gleixner #include <linux/pci_ids.h> 18250c2277SThomas Gleixner #include <linux/pci.h> 19250c2277SThomas Gleixner #include <linux/bitops.h> 20250c2277SThomas Gleixner #include <linux/ioport.h> 212050d45dSPavel Machek #include <linux/suspend.h> 22250c2277SThomas Gleixner #include <asm/e820.h> 23250c2277SThomas Gleixner #include <asm/io.h> 24395624fcSJoerg Roedel #include <asm/gart.h> 25250c2277SThomas Gleixner #include <asm/pci-direct.h> 26250c2277SThomas Gleixner #include <asm/dma.h> 27250c2277SThomas Gleixner #include <asm/k8.h> 28250c2277SThomas Gleixner 290440d4c0SJoerg Roedel int gart_iommu_aperture; 307de6a4cdSPavel Machek int gart_iommu_aperture_disabled __initdata; 317de6a4cdSPavel Machek int gart_iommu_aperture_allowed __initdata; 32250c2277SThomas Gleixner 33250c2277SThomas Gleixner int fallback_aper_order __initdata = 1; /* 64MB */ 347de6a4cdSPavel Machek int fallback_aper_force __initdata; 35250c2277SThomas Gleixner 36250c2277SThomas Gleixner int fix_aperture __initdata = 1; 37250c2277SThomas Gleixner 38*55c0d721SYinghai Lu struct bus_dev_range { 39*55c0d721SYinghai Lu int bus; 40*55c0d721SYinghai Lu int dev_base; 41*55c0d721SYinghai Lu int dev_limit; 42*55c0d721SYinghai Lu }; 43*55c0d721SYinghai Lu 44*55c0d721SYinghai Lu static struct bus_dev_range bus_dev_ranges[] __initdata = { 45*55c0d721SYinghai Lu { 0x00, 0x18, 0x20}, 46*55c0d721SYinghai Lu { 0xff, 0x00, 0x20}, 47*55c0d721SYinghai Lu { 0xfe, 0x00, 0x20} 48*55c0d721SYinghai Lu }; 49*55c0d721SYinghai Lu 50250c2277SThomas Gleixner static struct resource gart_resource = { 51250c2277SThomas Gleixner .name = "GART", 52250c2277SThomas Gleixner .flags = IORESOURCE_MEM, 53250c2277SThomas Gleixner }; 54250c2277SThomas Gleixner 55250c2277SThomas Gleixner static void __init insert_aperture_resource(u32 aper_base, u32 aper_size) 56250c2277SThomas Gleixner { 57250c2277SThomas Gleixner gart_resource.start = aper_base; 58250c2277SThomas Gleixner gart_resource.end = aper_base + aper_size - 1; 59250c2277SThomas Gleixner insert_resource(&iomem_resource, &gart_resource); 60250c2277SThomas Gleixner } 61250c2277SThomas Gleixner 62250c2277SThomas Gleixner /* This code runs before the PCI subsystem is initialized, so just 63250c2277SThomas Gleixner access the northbridge directly. */ 64250c2277SThomas Gleixner 65250c2277SThomas Gleixner static u32 __init allocate_aperture(void) 66250c2277SThomas Gleixner { 67250c2277SThomas Gleixner u32 aper_size; 68250c2277SThomas Gleixner void *p; 69250c2277SThomas Gleixner 707677b2efSYinghai Lu /* aper_size should <= 1G */ 717677b2efSYinghai Lu if (fallback_aper_order > 5) 727677b2efSYinghai Lu fallback_aper_order = 5; 73250c2277SThomas Gleixner aper_size = (32 * 1024 * 1024) << fallback_aper_order; 74250c2277SThomas Gleixner 75250c2277SThomas Gleixner /* 76c140df97SIngo Molnar * Aperture has to be naturally aligned. This means a 2GB aperture 77c140df97SIngo Molnar * won't have much chance of finding a place in the lower 4GB of 78c140df97SIngo Molnar * memory. Unfortunately we cannot move it up because that would 79c140df97SIngo Molnar * make the IOMMU useless. 80250c2277SThomas Gleixner */ 817677b2efSYinghai Lu /* 827677b2efSYinghai Lu * using 512M as goal, in case kexec will load kernel_big 837677b2efSYinghai Lu * that will do the on position decompress, and could overlap with 847677b2efSYinghai Lu * that positon with gart that is used. 857677b2efSYinghai Lu * sequende: 867677b2efSYinghai Lu * kernel_small 877677b2efSYinghai Lu * ==> kexec (with kdump trigger path or previous doesn't shutdown gart) 887677b2efSYinghai Lu * ==> kernel_small(gart area become e820_reserved) 897677b2efSYinghai Lu * ==> kexec (with kdump trigger path or previous doesn't shutdown gart) 907677b2efSYinghai Lu * ==> kerne_big (uncompressed size will be big than 64M or 128M) 917677b2efSYinghai Lu * so don't use 512M below as gart iommu, leave the space for kernel 927677b2efSYinghai Lu * code for safe 937677b2efSYinghai Lu */ 947677b2efSYinghai Lu p = __alloc_bootmem_nopanic(aper_size, aper_size, 512ULL<<20); 95250c2277SThomas Gleixner if (!p || __pa(p)+aper_size > 0xffffffff) { 9631183ba8SIngo Molnar printk(KERN_ERR 9731183ba8SIngo Molnar "Cannot allocate aperture memory hole (%p,%uK)\n", 98250c2277SThomas Gleixner p, aper_size>>10); 99250c2277SThomas Gleixner if (p) 100250c2277SThomas Gleixner free_bootmem(__pa(p), aper_size); 101250c2277SThomas Gleixner return 0; 102250c2277SThomas Gleixner } 10331183ba8SIngo Molnar printk(KERN_INFO "Mapping aperture over %d KB of RAM @ %lx\n", 104250c2277SThomas Gleixner aper_size >> 10, __pa(p)); 105250c2277SThomas Gleixner insert_aperture_resource((u32)__pa(p), aper_size); 1062050d45dSPavel Machek register_nosave_region((u32)__pa(p) >> PAGE_SHIFT, 1072050d45dSPavel Machek (u32)__pa(p+aper_size) >> PAGE_SHIFT); 108c140df97SIngo Molnar 109250c2277SThomas Gleixner return (u32)__pa(p); 110250c2277SThomas Gleixner } 111250c2277SThomas Gleixner 1128c9fd91aSYinghai Lu static int __init aperture_valid(u64 aper_base, u32 aper_size, u32 min_size) 113250c2277SThomas Gleixner { 114250c2277SThomas Gleixner if (!aper_base) 115250c2277SThomas Gleixner return 0; 11631183ba8SIngo Molnar 117250c2277SThomas Gleixner if (aper_base + aper_size > 0x100000000UL) { 11831183ba8SIngo Molnar printk(KERN_ERR "Aperture beyond 4GB. Ignoring.\n"); 119250c2277SThomas Gleixner return 0; 120250c2277SThomas Gleixner } 121250c2277SThomas Gleixner if (e820_any_mapped(aper_base, aper_base + aper_size, E820_RAM)) { 12231183ba8SIngo Molnar printk(KERN_ERR "Aperture pointing to e820 RAM. Ignoring.\n"); 123250c2277SThomas Gleixner return 0; 124250c2277SThomas Gleixner } 1258c9fd91aSYinghai Lu if (aper_size < min_size) { 1268c9fd91aSYinghai Lu printk(KERN_ERR "Aperture too small (%d MB) than (%d MB)\n", 1278c9fd91aSYinghai Lu aper_size>>20, min_size>>20); 128261a5ec3SYinghai Lu return 0; 129261a5ec3SYinghai Lu } 13031183ba8SIngo Molnar 131250c2277SThomas Gleixner return 1; 132250c2277SThomas Gleixner } 133250c2277SThomas Gleixner 134250c2277SThomas Gleixner /* Find a PCI capability */ 135*55c0d721SYinghai Lu static __u32 __init find_cap(int bus, int slot, int func, int cap) 136250c2277SThomas Gleixner { 137250c2277SThomas Gleixner int bytes; 138c140df97SIngo Molnar u8 pos; 139c140df97SIngo Molnar 140*55c0d721SYinghai Lu if (!(read_pci_config_16(bus, slot, func, PCI_STATUS) & 141c140df97SIngo Molnar PCI_STATUS_CAP_LIST)) 142250c2277SThomas Gleixner return 0; 143c140df97SIngo Molnar 144*55c0d721SYinghai Lu pos = read_pci_config_byte(bus, slot, func, PCI_CAPABILITY_LIST); 145250c2277SThomas Gleixner for (bytes = 0; bytes < 48 && pos >= 0x40; bytes++) { 146250c2277SThomas Gleixner u8 id; 147c140df97SIngo Molnar 148250c2277SThomas Gleixner pos &= ~3; 149*55c0d721SYinghai Lu id = read_pci_config_byte(bus, slot, func, pos+PCI_CAP_LIST_ID); 150250c2277SThomas Gleixner if (id == 0xff) 151250c2277SThomas Gleixner break; 152250c2277SThomas Gleixner if (id == cap) 153250c2277SThomas Gleixner return pos; 154*55c0d721SYinghai Lu pos = read_pci_config_byte(bus, slot, func, 155c140df97SIngo Molnar pos+PCI_CAP_LIST_NEXT); 156250c2277SThomas Gleixner } 157250c2277SThomas Gleixner return 0; 158250c2277SThomas Gleixner } 159250c2277SThomas Gleixner 160250c2277SThomas Gleixner /* Read a standard AGPv3 bridge header */ 161*55c0d721SYinghai Lu static __u32 __init read_agp(int bus, int slot, int func, int cap, u32 *order) 162250c2277SThomas Gleixner { 163250c2277SThomas Gleixner u32 apsize; 164250c2277SThomas Gleixner u32 apsizereg; 165250c2277SThomas Gleixner int nbits; 166250c2277SThomas Gleixner u32 aper_low, aper_hi; 167250c2277SThomas Gleixner u64 aper; 1681edc1ab3SYinghai Lu u32 old_order; 169250c2277SThomas Gleixner 170*55c0d721SYinghai Lu printk(KERN_INFO "AGP bridge at %02x:%02x:%02x\n", bus, slot, func); 171*55c0d721SYinghai Lu apsizereg = read_pci_config_16(bus, slot, func, cap + 0x14); 172250c2277SThomas Gleixner if (apsizereg == 0xffffffff) { 17331183ba8SIngo Molnar printk(KERN_ERR "APSIZE in AGP bridge unreadable\n"); 174250c2277SThomas Gleixner return 0; 175250c2277SThomas Gleixner } 176250c2277SThomas Gleixner 1771edc1ab3SYinghai Lu /* old_order could be the value from NB gart setting */ 1781edc1ab3SYinghai Lu old_order = *order; 1791edc1ab3SYinghai Lu 180250c2277SThomas Gleixner apsize = apsizereg & 0xfff; 181250c2277SThomas Gleixner /* Some BIOS use weird encodings not in the AGPv3 table. */ 182250c2277SThomas Gleixner if (apsize & 0xff) 183250c2277SThomas Gleixner apsize |= 0xf00; 184250c2277SThomas Gleixner nbits = hweight16(apsize); 185250c2277SThomas Gleixner *order = 7 - nbits; 186250c2277SThomas Gleixner if ((int)*order < 0) /* < 32MB */ 187250c2277SThomas Gleixner *order = 0; 188250c2277SThomas Gleixner 189*55c0d721SYinghai Lu aper_low = read_pci_config(bus, slot, func, 0x10); 190*55c0d721SYinghai Lu aper_hi = read_pci_config(bus, slot, func, 0x14); 191250c2277SThomas Gleixner aper = (aper_low & ~((1<<22)-1)) | ((u64)aper_hi << 32); 192250c2277SThomas Gleixner 1931edc1ab3SYinghai Lu /* 1941edc1ab3SYinghai Lu * On some sick chips, APSIZE is 0. It means it wants 4G 1951edc1ab3SYinghai Lu * so let double check that order, and lets trust AMD NB settings: 1961edc1ab3SYinghai Lu */ 1978c9fd91aSYinghai Lu printk(KERN_INFO "Aperture from AGP @ %Lx old size %u MB\n", 1988c9fd91aSYinghai Lu aper, 32 << old_order); 1998c9fd91aSYinghai Lu if (aper + (32ULL<<(20 + *order)) > 0x100000000ULL) { 2001edc1ab3SYinghai Lu printk(KERN_INFO "Aperture size %u MB (APSIZE %x) is not right, using settings from NB\n", 2011edc1ab3SYinghai Lu 32 << *order, apsizereg); 2021edc1ab3SYinghai Lu *order = old_order; 2031edc1ab3SYinghai Lu } 2041edc1ab3SYinghai Lu 20531183ba8SIngo Molnar printk(KERN_INFO "Aperture from AGP @ %Lx size %u MB (APSIZE %x)\n", 206250c2277SThomas Gleixner aper, 32 << *order, apsizereg); 207250c2277SThomas Gleixner 2088c9fd91aSYinghai Lu if (!aperture_valid(aper, (32*1024*1024) << *order, 32<<20)) 209250c2277SThomas Gleixner return 0; 210250c2277SThomas Gleixner return (u32)aper; 211250c2277SThomas Gleixner } 212250c2277SThomas Gleixner 213c140df97SIngo Molnar /* 214c140df97SIngo Molnar * Look for an AGP bridge. Windows only expects the aperture in the 215c140df97SIngo Molnar * AGP bridge and some BIOS forget to initialize the Northbridge too. 216c140df97SIngo Molnar * Work around this here. 217c140df97SIngo Molnar * 218c140df97SIngo Molnar * Do an PCI bus scan by hand because we're running before the PCI 219c140df97SIngo Molnar * subsystem. 220c140df97SIngo Molnar * 221c140df97SIngo Molnar * All K8 AGP bridges are AGPv3 compliant, so we can do this scan 222c140df97SIngo Molnar * generically. It's probably overkill to always scan all slots because 223c140df97SIngo Molnar * the AGP bridges should be always an own bus on the HT hierarchy, 224c140df97SIngo Molnar * but do it here for future safety. 225c140df97SIngo Molnar */ 226250c2277SThomas Gleixner static __u32 __init search_agp_bridge(u32 *order, int *valid_agp) 227250c2277SThomas Gleixner { 228*55c0d721SYinghai Lu int bus, slot, func; 229250c2277SThomas Gleixner 230250c2277SThomas Gleixner /* Poor man's PCI discovery */ 231*55c0d721SYinghai Lu for (bus = 0; bus < 256; bus++) { 232250c2277SThomas Gleixner for (slot = 0; slot < 32; slot++) { 233250c2277SThomas Gleixner for (func = 0; func < 8; func++) { 234250c2277SThomas Gleixner u32 class, cap; 235250c2277SThomas Gleixner u8 type; 236*55c0d721SYinghai Lu class = read_pci_config(bus, slot, func, 237250c2277SThomas Gleixner PCI_CLASS_REVISION); 238250c2277SThomas Gleixner if (class == 0xffffffff) 239250c2277SThomas Gleixner break; 240250c2277SThomas Gleixner 241250c2277SThomas Gleixner switch (class >> 16) { 242250c2277SThomas Gleixner case PCI_CLASS_BRIDGE_HOST: 243250c2277SThomas Gleixner case PCI_CLASS_BRIDGE_OTHER: /* needed? */ 244250c2277SThomas Gleixner /* AGP bridge? */ 245*55c0d721SYinghai Lu cap = find_cap(bus, slot, func, 246c140df97SIngo Molnar PCI_CAP_ID_AGP); 247250c2277SThomas Gleixner if (!cap) 248250c2277SThomas Gleixner break; 249250c2277SThomas Gleixner *valid_agp = 1; 250*55c0d721SYinghai Lu return read_agp(bus, slot, func, cap, 251c140df97SIngo Molnar order); 252250c2277SThomas Gleixner } 253250c2277SThomas Gleixner 254250c2277SThomas Gleixner /* No multi-function device? */ 255*55c0d721SYinghai Lu type = read_pci_config_byte(bus, slot, func, 256250c2277SThomas Gleixner PCI_HEADER_TYPE); 257250c2277SThomas Gleixner if (!(type & 0x80)) 258250c2277SThomas Gleixner break; 259250c2277SThomas Gleixner } 260250c2277SThomas Gleixner } 261250c2277SThomas Gleixner } 26231183ba8SIngo Molnar printk(KERN_INFO "No AGP bridge found\n"); 263c140df97SIngo Molnar 264250c2277SThomas Gleixner return 0; 265250c2277SThomas Gleixner } 266250c2277SThomas Gleixner 267aaf23042SYinghai Lu static int gart_fix_e820 __initdata = 1; 268aaf23042SYinghai Lu 269aaf23042SYinghai Lu static int __init parse_gart_mem(char *p) 270aaf23042SYinghai Lu { 271aaf23042SYinghai Lu if (!p) 272aaf23042SYinghai Lu return -EINVAL; 273aaf23042SYinghai Lu 274aaf23042SYinghai Lu if (!strncmp(p, "off", 3)) 275aaf23042SYinghai Lu gart_fix_e820 = 0; 276aaf23042SYinghai Lu else if (!strncmp(p, "on", 2)) 277aaf23042SYinghai Lu gart_fix_e820 = 1; 278aaf23042SYinghai Lu 279aaf23042SYinghai Lu return 0; 280aaf23042SYinghai Lu } 281aaf23042SYinghai Lu early_param("gart_fix_e820", parse_gart_mem); 282aaf23042SYinghai Lu 283aaf23042SYinghai Lu void __init early_gart_iommu_check(void) 284aaf23042SYinghai Lu { 285aaf23042SYinghai Lu /* 286aaf23042SYinghai Lu * in case it is enabled before, esp for kexec/kdump, 287aaf23042SYinghai Lu * previous kernel already enable that. memset called 288aaf23042SYinghai Lu * by allocate_aperture/__alloc_bootmem_nopanic cause restart. 289aaf23042SYinghai Lu * or second kernel have different position for GART hole. and new 290aaf23042SYinghai Lu * kernel could use hole as RAM that is still used by GART set by 291aaf23042SYinghai Lu * first kernel 292aaf23042SYinghai Lu * or BIOS forget to put that in reserved. 293aaf23042SYinghai Lu * try to update e820 to make that region as reserved. 294aaf23042SYinghai Lu */ 295*55c0d721SYinghai Lu int fix, slot; 296aaf23042SYinghai Lu u32 ctl; 297aaf23042SYinghai Lu u32 aper_size = 0, aper_order = 0, last_aper_order = 0; 298aaf23042SYinghai Lu u64 aper_base = 0, last_aper_base = 0; 299aaf23042SYinghai Lu int aper_enabled = 0, last_aper_enabled = 0; 300*55c0d721SYinghai Lu int i; 301aaf23042SYinghai Lu 302aaf23042SYinghai Lu if (!early_pci_allowed()) 303aaf23042SYinghai Lu return; 304aaf23042SYinghai Lu 305aaf23042SYinghai Lu fix = 0; 306*55c0d721SYinghai Lu for (i = 0; i < ARRAY_SIZE(bus_dev_ranges); i++) { 307*55c0d721SYinghai Lu int bus; 308*55c0d721SYinghai Lu int dev_base, dev_limit; 309*55c0d721SYinghai Lu 310*55c0d721SYinghai Lu bus = bus_dev_ranges[i].bus; 311*55c0d721SYinghai Lu dev_base = bus_dev_ranges[i].dev_base; 312*55c0d721SYinghai Lu dev_limit = bus_dev_ranges[i].dev_limit; 313*55c0d721SYinghai Lu 314*55c0d721SYinghai Lu for (slot = dev_base; slot < dev_limit; slot++) { 315*55c0d721SYinghai Lu if (!early_is_k8_nb(read_pci_config(bus, slot, 3, 0x00))) 316aaf23042SYinghai Lu continue; 317aaf23042SYinghai Lu 318*55c0d721SYinghai Lu ctl = read_pci_config(bus, slot, 3, AMD64_GARTAPERTURECTL); 319*55c0d721SYinghai Lu aper_enabled = ctl & AMD64_GARTEN; 320aaf23042SYinghai Lu aper_order = (ctl >> 1) & 7; 321aaf23042SYinghai Lu aper_size = (32 * 1024 * 1024) << aper_order; 322*55c0d721SYinghai Lu aper_base = read_pci_config(bus, slot, 3, AMD64_GARTAPERTUREBASE) & 0x7fff; 323aaf23042SYinghai Lu aper_base <<= 25; 324aaf23042SYinghai Lu 325aaf23042SYinghai Lu if ((last_aper_order && aper_order != last_aper_order) || 326aaf23042SYinghai Lu (last_aper_base && aper_base != last_aper_base) || 327aaf23042SYinghai Lu (last_aper_enabled && aper_enabled != last_aper_enabled)) { 328aaf23042SYinghai Lu fix = 1; 329*55c0d721SYinghai Lu goto out; 330aaf23042SYinghai Lu } 331aaf23042SYinghai Lu last_aper_order = aper_order; 332aaf23042SYinghai Lu last_aper_base = aper_base; 333aaf23042SYinghai Lu last_aper_enabled = aper_enabled; 334aaf23042SYinghai Lu } 335*55c0d721SYinghai Lu } 336aaf23042SYinghai Lu 337*55c0d721SYinghai Lu out: 338aaf23042SYinghai Lu if (!fix && !aper_enabled) 339aaf23042SYinghai Lu return; 340aaf23042SYinghai Lu 341aaf23042SYinghai Lu if (!aper_base || !aper_size || aper_base + aper_size > 0x100000000UL) 342aaf23042SYinghai Lu fix = 1; 343aaf23042SYinghai Lu 344aaf23042SYinghai Lu if (gart_fix_e820 && !fix && aper_enabled) { 3458c9fd91aSYinghai Lu if (!e820_all_mapped(aper_base, aper_base + aper_size, 3468c9fd91aSYinghai Lu E820_RESERVED)) { 347aaf23042SYinghai Lu /* reserved it, so we can resuse it in second kernel */ 348aaf23042SYinghai Lu printk(KERN_INFO "update e820 for GART\n"); 349aaf23042SYinghai Lu add_memory_region(aper_base, aper_size, E820_RESERVED); 350aaf23042SYinghai Lu update_e820(); 351aaf23042SYinghai Lu } 352aaf23042SYinghai Lu return; 353aaf23042SYinghai Lu } 354aaf23042SYinghai Lu 355aaf23042SYinghai Lu /* different nodes have different setting, disable them all at first*/ 356*55c0d721SYinghai Lu for (i = 0; i < ARRAY_SIZE(bus_dev_ranges); i++) { 357*55c0d721SYinghai Lu int bus; 358*55c0d721SYinghai Lu int dev_base, dev_limit; 359*55c0d721SYinghai Lu 360*55c0d721SYinghai Lu bus = bus_dev_ranges[i].bus; 361*55c0d721SYinghai Lu dev_base = bus_dev_ranges[i].dev_base; 362*55c0d721SYinghai Lu dev_limit = bus_dev_ranges[i].dev_limit; 363*55c0d721SYinghai Lu 364*55c0d721SYinghai Lu for (slot = dev_base; slot < dev_limit; slot++) { 365*55c0d721SYinghai Lu if (!early_is_k8_nb(read_pci_config(bus, slot, 3, 0x00))) 366aaf23042SYinghai Lu continue; 367aaf23042SYinghai Lu 368*55c0d721SYinghai Lu ctl = read_pci_config(bus, slot, 3, AMD64_GARTAPERTURECTL); 369*55c0d721SYinghai Lu ctl &= ~AMD64_GARTEN; 370*55c0d721SYinghai Lu write_pci_config(bus, slot, 3, AMD64_GARTAPERTURECTL, ctl); 371*55c0d721SYinghai Lu } 372aaf23042SYinghai Lu } 373aaf23042SYinghai Lu 374aaf23042SYinghai Lu } 375aaf23042SYinghai Lu 3768c9fd91aSYinghai Lu static int __initdata printed_gart_size_msg; 3778c9fd91aSYinghai Lu 3780440d4c0SJoerg Roedel void __init gart_iommu_hole_init(void) 379250c2277SThomas Gleixner { 3808c9fd91aSYinghai Lu u32 agp_aper_base = 0, agp_aper_order = 0; 381250c2277SThomas Gleixner u32 aper_size, aper_alloc = 0, aper_order = 0, last_aper_order = 0; 382250c2277SThomas Gleixner u64 aper_base, last_aper_base = 0; 383*55c0d721SYinghai Lu int fix, slot, valid_agp = 0; 384*55c0d721SYinghai Lu int i, node; 385250c2277SThomas Gleixner 3860440d4c0SJoerg Roedel if (gart_iommu_aperture_disabled || !fix_aperture || 3870440d4c0SJoerg Roedel !early_pci_allowed()) 388250c2277SThomas Gleixner return; 389250c2277SThomas Gleixner 390250c2277SThomas Gleixner printk(KERN_INFO "Checking aperture...\n"); 391250c2277SThomas Gleixner 3928c9fd91aSYinghai Lu if (!fallback_aper_force) 3938c9fd91aSYinghai Lu agp_aper_base = search_agp_bridge(&agp_aper_order, &valid_agp); 3948c9fd91aSYinghai Lu 395250c2277SThomas Gleixner fix = 0; 39647db4c3eSYinghai Lu node = 0; 397*55c0d721SYinghai Lu for (i = 0; i < ARRAY_SIZE(bus_dev_ranges); i++) { 398*55c0d721SYinghai Lu int bus; 399*55c0d721SYinghai Lu int dev_base, dev_limit; 400*55c0d721SYinghai Lu 401*55c0d721SYinghai Lu bus = bus_dev_ranges[i].bus; 402*55c0d721SYinghai Lu dev_base = bus_dev_ranges[i].dev_base; 403*55c0d721SYinghai Lu dev_limit = bus_dev_ranges[i].dev_limit; 404*55c0d721SYinghai Lu 405*55c0d721SYinghai Lu for (slot = dev_base; slot < dev_limit; slot++) { 406*55c0d721SYinghai Lu if (!early_is_k8_nb(read_pci_config(bus, slot, 3, 0x00))) 407250c2277SThomas Gleixner continue; 408250c2277SThomas Gleixner 409250c2277SThomas Gleixner iommu_detected = 1; 4100440d4c0SJoerg Roedel gart_iommu_aperture = 1; 411250c2277SThomas Gleixner 412*55c0d721SYinghai Lu aper_order = (read_pci_config(bus, slot, 3, AMD64_GARTAPERTURECTL) >> 1) & 7; 413250c2277SThomas Gleixner aper_size = (32 * 1024 * 1024) << aper_order; 414*55c0d721SYinghai Lu aper_base = read_pci_config(bus, slot, 3, AMD64_GARTAPERTUREBASE) & 0x7fff; 415250c2277SThomas Gleixner aper_base <<= 25; 416250c2277SThomas Gleixner 41747db4c3eSYinghai Lu printk(KERN_INFO "Node %d: aperture @ %Lx size %u MB\n", 41847db4c3eSYinghai Lu node, aper_base, aper_size >> 20); 41947db4c3eSYinghai Lu node++; 420250c2277SThomas Gleixner 4218c9fd91aSYinghai Lu if (!aperture_valid(aper_base, aper_size, 64<<20)) { 4228c9fd91aSYinghai Lu if (valid_agp && agp_aper_base && 4238c9fd91aSYinghai Lu agp_aper_base == aper_base && 4248c9fd91aSYinghai Lu agp_aper_order == aper_order) { 4258c9fd91aSYinghai Lu /* the same between two setting from NB and agp */ 4268c9fd91aSYinghai Lu if (!no_iommu && end_pfn > MAX_DMA32_PFN && !printed_gart_size_msg) { 4278c9fd91aSYinghai Lu printk(KERN_ERR "you are using iommu with agp, but GART size is less than 64M\n"); 4288c9fd91aSYinghai Lu printk(KERN_ERR "please increase GART size in your BIOS setup\n"); 4298c9fd91aSYinghai Lu printk(KERN_ERR "if BIOS doesn't have that option, contact your HW vendor!\n"); 4308c9fd91aSYinghai Lu printed_gart_size_msg = 1; 4318c9fd91aSYinghai Lu } 4328c9fd91aSYinghai Lu } else { 433250c2277SThomas Gleixner fix = 1; 434*55c0d721SYinghai Lu goto out; 435250c2277SThomas Gleixner } 4368c9fd91aSYinghai Lu } 437250c2277SThomas Gleixner 438250c2277SThomas Gleixner if ((last_aper_order && aper_order != last_aper_order) || 439250c2277SThomas Gleixner (last_aper_base && aper_base != last_aper_base)) { 440250c2277SThomas Gleixner fix = 1; 441*55c0d721SYinghai Lu goto out; 442250c2277SThomas Gleixner } 443250c2277SThomas Gleixner last_aper_order = aper_order; 444250c2277SThomas Gleixner last_aper_base = aper_base; 445250c2277SThomas Gleixner } 446*55c0d721SYinghai Lu } 447250c2277SThomas Gleixner 448*55c0d721SYinghai Lu out: 449250c2277SThomas Gleixner if (!fix && !fallback_aper_force) { 450250c2277SThomas Gleixner if (last_aper_base) { 451250c2277SThomas Gleixner unsigned long n = (32 * 1024 * 1024) << last_aper_order; 452c140df97SIngo Molnar 453250c2277SThomas Gleixner insert_aperture_resource((u32)last_aper_base, n); 454250c2277SThomas Gleixner } 455250c2277SThomas Gleixner return; 456250c2277SThomas Gleixner } 457250c2277SThomas Gleixner 4588c9fd91aSYinghai Lu if (!fallback_aper_force) { 4598c9fd91aSYinghai Lu aper_alloc = agp_aper_base; 4608c9fd91aSYinghai Lu aper_order = agp_aper_order; 4618c9fd91aSYinghai Lu } 462250c2277SThomas Gleixner 463250c2277SThomas Gleixner if (aper_alloc) { 464250c2277SThomas Gleixner /* Got the aperture from the AGP bridge */ 465250c2277SThomas Gleixner } else if (swiotlb && !valid_agp) { 466250c2277SThomas Gleixner /* Do nothing */ 467250c2277SThomas Gleixner } else if ((!no_iommu && end_pfn > MAX_DMA32_PFN) || 468250c2277SThomas Gleixner force_iommu || 469250c2277SThomas Gleixner valid_agp || 470250c2277SThomas Gleixner fallback_aper_force) { 47131183ba8SIngo Molnar printk(KERN_ERR 47231183ba8SIngo Molnar "Your BIOS doesn't leave a aperture memory hole\n"); 47331183ba8SIngo Molnar printk(KERN_ERR 47431183ba8SIngo Molnar "Please enable the IOMMU option in the BIOS setup\n"); 47531183ba8SIngo Molnar printk(KERN_ERR 47631183ba8SIngo Molnar "This costs you %d MB of RAM\n", 477250c2277SThomas Gleixner 32 << fallback_aper_order); 478250c2277SThomas Gleixner 479250c2277SThomas Gleixner aper_order = fallback_aper_order; 480250c2277SThomas Gleixner aper_alloc = allocate_aperture(); 481250c2277SThomas Gleixner if (!aper_alloc) { 482c140df97SIngo Molnar /* 483c140df97SIngo Molnar * Could disable AGP and IOMMU here, but it's 484c140df97SIngo Molnar * probably not worth it. But the later users 485c140df97SIngo Molnar * cannot deal with bad apertures and turning 486c140df97SIngo Molnar * on the aperture over memory causes very 487c140df97SIngo Molnar * strange problems, so it's better to panic 488c140df97SIngo Molnar * early. 489c140df97SIngo Molnar */ 490250c2277SThomas Gleixner panic("Not enough memory for aperture"); 491250c2277SThomas Gleixner } 492250c2277SThomas Gleixner } else { 493250c2277SThomas Gleixner return; 494250c2277SThomas Gleixner } 495250c2277SThomas Gleixner 496250c2277SThomas Gleixner /* Fix up the north bridges */ 497*55c0d721SYinghai Lu for (i = 0; i < ARRAY_SIZE(bus_dev_ranges); i++) { 498*55c0d721SYinghai Lu int bus; 499*55c0d721SYinghai Lu int dev_base, dev_limit; 500*55c0d721SYinghai Lu 501*55c0d721SYinghai Lu bus = bus_dev_ranges[i].bus; 502*55c0d721SYinghai Lu dev_base = bus_dev_ranges[i].dev_base; 503*55c0d721SYinghai Lu dev_limit = bus_dev_ranges[i].dev_limit; 504*55c0d721SYinghai Lu for (slot = dev_base; slot < dev_limit; slot++) { 505*55c0d721SYinghai Lu if (!early_is_k8_nb(read_pci_config(bus, slot, 3, 0x00))) 506250c2277SThomas Gleixner continue; 507250c2277SThomas Gleixner 508*55c0d721SYinghai Lu /* Don't enable translation yet. That is done later. 509*55c0d721SYinghai Lu Assume this BIOS didn't initialise the GART so 510*55c0d721SYinghai Lu just overwrite all previous bits */ 511*55c0d721SYinghai Lu write_pci_config(bus, slot, 3, AMD64_GARTAPERTURECTL, aper_order << 1); 512*55c0d721SYinghai Lu write_pci_config(bus, slot, 3, AMD64_GARTAPERTUREBASE, aper_alloc >> 25); 513*55c0d721SYinghai Lu } 514250c2277SThomas Gleixner } 515250c2277SThomas Gleixner } 516