1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0 2250c2277SThomas Gleixner /* 3250c2277SThomas Gleixner * Firmware replacement code. 4250c2277SThomas Gleixner * 58caac563SPavel Machek * Work around broken BIOSes that don't set an aperture, only set the 68caac563SPavel Machek * aperture in the AGP bridge, or set too small aperture. 78caac563SPavel Machek * 8250c2277SThomas Gleixner * If all fails map the aperture over some low memory. This is cheaper than 9250c2277SThomas Gleixner * doing bounce buffering. The memory is lost. This is done at early boot 10250c2277SThomas Gleixner * because only the bootmem allocator can allocate 32+MB. 11250c2277SThomas Gleixner * 12250c2277SThomas Gleixner * Copyright 2002 Andi Kleen, SuSE Labs. 13250c2277SThomas Gleixner */ 14a5d3244aSBjorn Helgaas #define pr_fmt(fmt) "AGP: " fmt 15a5d3244aSBjorn Helgaas 16250c2277SThomas Gleixner #include <linux/kernel.h> 17250c2277SThomas Gleixner #include <linux/types.h> 18250c2277SThomas Gleixner #include <linux/init.h> 1932e3f2b0SYinghai Lu #include <linux/memblock.h> 20250c2277SThomas Gleixner #include <linux/mmzone.h> 21250c2277SThomas Gleixner #include <linux/pci_ids.h> 22250c2277SThomas Gleixner #include <linux/pci.h> 23250c2277SThomas Gleixner #include <linux/bitops.h> 242050d45dSPavel Machek #include <linux/suspend.h> 2566441bd3SIngo Molnar #include <asm/e820/api.h> 26250c2277SThomas Gleixner #include <asm/io.h> 2746a7fa27SFUJITA Tomonori #include <asm/iommu.h> 28395624fcSJoerg Roedel #include <asm/gart.h> 29250c2277SThomas Gleixner #include <asm/pci-direct.h> 30250c2277SThomas Gleixner #include <asm/dma.h> 3123ac4ae8SAndreas Herrmann #include <asm/amd_nb.h> 32de957628SFUJITA Tomonori #include <asm/x86_init.h> 332a3e83c6SJiri Bohac #include <linux/crash_dump.h> 34250c2277SThomas Gleixner 35c387aa3aSJoerg Roedel /* 36c387aa3aSJoerg Roedel * Using 512M as goal, in case kexec will load kernel_big 37c387aa3aSJoerg Roedel * that will do the on-position decompress, and could overlap with 38c387aa3aSJoerg Roedel * with the gart aperture that is used. 39c387aa3aSJoerg Roedel * Sequence: 40c387aa3aSJoerg Roedel * kernel_small 41c387aa3aSJoerg Roedel * ==> kexec (with kdump trigger path or gart still enabled) 42c387aa3aSJoerg Roedel * ==> kernel_small (gart area become e820_reserved) 43c387aa3aSJoerg Roedel * ==> kexec (with kdump trigger path or gart still enabled) 44c387aa3aSJoerg Roedel * ==> kerne_big (uncompressed size will be big than 64M or 128M) 45c387aa3aSJoerg Roedel * So don't use 512M below as gart iommu, leave the space for kernel 46c387aa3aSJoerg Roedel * code for safe. 47c387aa3aSJoerg Roedel */ 48c387aa3aSJoerg Roedel #define GART_MIN_ADDR (512ULL << 20) 49c387aa3aSJoerg Roedel #define GART_MAX_ADDR (1ULL << 32) 50c387aa3aSJoerg Roedel 510440d4c0SJoerg Roedel int gart_iommu_aperture; 527de6a4cdSPavel Machek int gart_iommu_aperture_disabled __initdata; 537de6a4cdSPavel Machek int gart_iommu_aperture_allowed __initdata; 54250c2277SThomas Gleixner 55250c2277SThomas Gleixner int fallback_aper_order __initdata = 1; /* 64MB */ 567de6a4cdSPavel Machek int fallback_aper_force __initdata; 57250c2277SThomas Gleixner 58250c2277SThomas Gleixner int fix_aperture __initdata = 1; 59250c2277SThomas Gleixner 602a3e83c6SJiri Bohac #ifdef CONFIG_PROC_VMCORE 612a3e83c6SJiri Bohac /* 622a3e83c6SJiri Bohac * If the first kernel maps the aperture over e820 RAM, the kdump kernel will 632a3e83c6SJiri Bohac * use the same range because it will remain configured in the northbridge. 642a3e83c6SJiri Bohac * Trying to dump this area via /proc/vmcore may crash the machine, so exclude 652a3e83c6SJiri Bohac * it from vmcore. 662a3e83c6SJiri Bohac */ 672a3e83c6SJiri Bohac static unsigned long aperture_pfn_start, aperture_page_count; 682a3e83c6SJiri Bohac 692a3e83c6SJiri Bohac static int gart_oldmem_pfn_is_ram(unsigned long pfn) 702a3e83c6SJiri Bohac { 712a3e83c6SJiri Bohac return likely((pfn < aperture_pfn_start) || 722a3e83c6SJiri Bohac (pfn >= aperture_pfn_start + aperture_page_count)); 732a3e83c6SJiri Bohac } 742a3e83c6SJiri Bohac 752a3e83c6SJiri Bohac static void exclude_from_vmcore(u64 aper_base, u32 aper_order) 762a3e83c6SJiri Bohac { 772a3e83c6SJiri Bohac aperture_pfn_start = aper_base >> PAGE_SHIFT; 782a3e83c6SJiri Bohac aperture_page_count = (32 * 1024 * 1024) << aper_order >> PAGE_SHIFT; 792a3e83c6SJiri Bohac WARN_ON(register_oldmem_pfn_is_ram(&gart_oldmem_pfn_is_ram)); 802a3e83c6SJiri Bohac } 812a3e83c6SJiri Bohac #else 822a3e83c6SJiri Bohac static void exclude_from_vmcore(u64 aper_base, u32 aper_order) 832a3e83c6SJiri Bohac { 842a3e83c6SJiri Bohac } 852a3e83c6SJiri Bohac #endif 862a3e83c6SJiri Bohac 87250c2277SThomas Gleixner /* This code runs before the PCI subsystem is initialized, so just 88250c2277SThomas Gleixner access the northbridge directly. */ 89250c2277SThomas Gleixner 90250c2277SThomas Gleixner static u32 __init allocate_aperture(void) 91250c2277SThomas Gleixner { 92250c2277SThomas Gleixner u32 aper_size; 9332e3f2b0SYinghai Lu unsigned long addr; 94250c2277SThomas Gleixner 957677b2efSYinghai Lu /* aper_size should <= 1G */ 967677b2efSYinghai Lu if (fallback_aper_order > 5) 977677b2efSYinghai Lu fallback_aper_order = 5; 98250c2277SThomas Gleixner aper_size = (32 * 1024 * 1024) << fallback_aper_order; 99250c2277SThomas Gleixner 100250c2277SThomas Gleixner /* 101c140df97SIngo Molnar * Aperture has to be naturally aligned. This means a 2GB aperture 102c140df97SIngo Molnar * won't have much chance of finding a place in the lower 4GB of 103c140df97SIngo Molnar * memory. Unfortunately we cannot move it up because that would 104c140df97SIngo Molnar * make the IOMMU useless. 105250c2277SThomas Gleixner */ 106c387aa3aSJoerg Roedel addr = memblock_find_in_range(GART_MIN_ADDR, GART_MAX_ADDR, 107c387aa3aSJoerg Roedel aper_size, aper_size); 10826bfc540SWang YanQing if (!addr) { 109c96ec953SBjorn Helgaas pr_err("Cannot allocate aperture memory hole [mem %#010lx-%#010lx] (%uKB)\n", 110c96ec953SBjorn Helgaas addr, addr + aper_size - 1, aper_size >> 10); 11132e3f2b0SYinghai Lu return 0; 11232e3f2b0SYinghai Lu } 11324aa0788STejun Heo memblock_reserve(addr, aper_size); 114c96ec953SBjorn Helgaas pr_info("Mapping aperture over RAM [mem %#010lx-%#010lx] (%uKB)\n", 115c96ec953SBjorn Helgaas addr, addr + aper_size - 1, aper_size >> 10); 11632e3f2b0SYinghai Lu register_nosave_region(addr >> PAGE_SHIFT, 11732e3f2b0SYinghai Lu (addr+aper_size) >> PAGE_SHIFT); 118c140df97SIngo Molnar 11932e3f2b0SYinghai Lu return (u32)addr; 120250c2277SThomas Gleixner } 121250c2277SThomas Gleixner 122250c2277SThomas Gleixner 123250c2277SThomas Gleixner /* Find a PCI capability */ 124dd564d0cSPavel Machek static u32 __init find_cap(int bus, int slot, int func, int cap) 125250c2277SThomas Gleixner { 126250c2277SThomas Gleixner int bytes; 127c140df97SIngo Molnar u8 pos; 128c140df97SIngo Molnar 12955c0d721SYinghai Lu if (!(read_pci_config_16(bus, slot, func, PCI_STATUS) & 130c140df97SIngo Molnar PCI_STATUS_CAP_LIST)) 131250c2277SThomas Gleixner return 0; 132c140df97SIngo Molnar 13355c0d721SYinghai Lu pos = read_pci_config_byte(bus, slot, func, PCI_CAPABILITY_LIST); 134250c2277SThomas Gleixner for (bytes = 0; bytes < 48 && pos >= 0x40; bytes++) { 135250c2277SThomas Gleixner u8 id; 136c140df97SIngo Molnar 137250c2277SThomas Gleixner pos &= ~3; 13855c0d721SYinghai Lu id = read_pci_config_byte(bus, slot, func, pos+PCI_CAP_LIST_ID); 139250c2277SThomas Gleixner if (id == 0xff) 140250c2277SThomas Gleixner break; 141250c2277SThomas Gleixner if (id == cap) 142250c2277SThomas Gleixner return pos; 14355c0d721SYinghai Lu pos = read_pci_config_byte(bus, slot, func, 144c140df97SIngo Molnar pos+PCI_CAP_LIST_NEXT); 145250c2277SThomas Gleixner } 146250c2277SThomas Gleixner return 0; 147250c2277SThomas Gleixner } 148250c2277SThomas Gleixner 149250c2277SThomas Gleixner /* Read a standard AGPv3 bridge header */ 150dd564d0cSPavel Machek static u32 __init read_agp(int bus, int slot, int func, int cap, u32 *order) 151250c2277SThomas Gleixner { 152250c2277SThomas Gleixner u32 apsize; 153250c2277SThomas Gleixner u32 apsizereg; 154250c2277SThomas Gleixner int nbits; 155250c2277SThomas Gleixner u32 aper_low, aper_hi; 156250c2277SThomas Gleixner u64 aper; 1571edc1ab3SYinghai Lu u32 old_order; 158250c2277SThomas Gleixner 159c96ec953SBjorn Helgaas pr_info("pci 0000:%02x:%02x:%02x: AGP bridge\n", bus, slot, func); 16055c0d721SYinghai Lu apsizereg = read_pci_config_16(bus, slot, func, cap + 0x14); 161250c2277SThomas Gleixner if (apsizereg == 0xffffffff) { 162c96ec953SBjorn Helgaas pr_err("pci 0000:%02x:%02x.%d: APSIZE unreadable\n", 163c96ec953SBjorn Helgaas bus, slot, func); 164250c2277SThomas Gleixner return 0; 165250c2277SThomas Gleixner } 166250c2277SThomas Gleixner 1671edc1ab3SYinghai Lu /* old_order could be the value from NB gart setting */ 1681edc1ab3SYinghai Lu old_order = *order; 1691edc1ab3SYinghai Lu 170250c2277SThomas Gleixner apsize = apsizereg & 0xfff; 171250c2277SThomas Gleixner /* Some BIOS use weird encodings not in the AGPv3 table. */ 172250c2277SThomas Gleixner if (apsize & 0xff) 173250c2277SThomas Gleixner apsize |= 0xf00; 174250c2277SThomas Gleixner nbits = hweight16(apsize); 175250c2277SThomas Gleixner *order = 7 - nbits; 176250c2277SThomas Gleixner if ((int)*order < 0) /* < 32MB */ 177250c2277SThomas Gleixner *order = 0; 178250c2277SThomas Gleixner 17955c0d721SYinghai Lu aper_low = read_pci_config(bus, slot, func, 0x10); 18055c0d721SYinghai Lu aper_hi = read_pci_config(bus, slot, func, 0x14); 181250c2277SThomas Gleixner aper = (aper_low & ~((1<<22)-1)) | ((u64)aper_hi << 32); 182250c2277SThomas Gleixner 1831edc1ab3SYinghai Lu /* 1841edc1ab3SYinghai Lu * On some sick chips, APSIZE is 0. It means it wants 4G 1851edc1ab3SYinghai Lu * so let double check that order, and lets trust AMD NB settings: 1861edc1ab3SYinghai Lu */ 187c96ec953SBjorn Helgaas pr_info("pci 0000:%02x:%02x.%d: AGP aperture [bus addr %#010Lx-%#010Lx] (old size %uMB)\n", 188c96ec953SBjorn Helgaas bus, slot, func, aper, aper + (32ULL << (old_order + 20)) - 1, 189c96ec953SBjorn Helgaas 32 << old_order); 1908c9fd91aSYinghai Lu if (aper + (32ULL<<(20 + *order)) > 0x100000000ULL) { 191c96ec953SBjorn Helgaas pr_info("pci 0000:%02x:%02x.%d: AGP aperture size %uMB (APSIZE %#x) is not right, using settings from NB\n", 192c96ec953SBjorn Helgaas bus, slot, func, 32 << *order, apsizereg); 1931edc1ab3SYinghai Lu *order = old_order; 1941edc1ab3SYinghai Lu } 1951edc1ab3SYinghai Lu 196c96ec953SBjorn Helgaas pr_info("pci 0000:%02x:%02x.%d: AGP aperture [bus addr %#010Lx-%#010Lx] (%uMB, APSIZE %#x)\n", 197c96ec953SBjorn Helgaas bus, slot, func, aper, aper + (32ULL << (*order + 20)) - 1, 198a5d3244aSBjorn Helgaas 32 << *order, apsizereg); 199250c2277SThomas Gleixner 2008c9fd91aSYinghai Lu if (!aperture_valid(aper, (32*1024*1024) << *order, 32<<20)) 201250c2277SThomas Gleixner return 0; 202250c2277SThomas Gleixner return (u32)aper; 203250c2277SThomas Gleixner } 204250c2277SThomas Gleixner 205c140df97SIngo Molnar /* 206c140df97SIngo Molnar * Look for an AGP bridge. Windows only expects the aperture in the 207c140df97SIngo Molnar * AGP bridge and some BIOS forget to initialize the Northbridge too. 208c140df97SIngo Molnar * Work around this here. 209c140df97SIngo Molnar * 210c140df97SIngo Molnar * Do an PCI bus scan by hand because we're running before the PCI 211c140df97SIngo Molnar * subsystem. 212c140df97SIngo Molnar * 213eec1d4faSHans Rosenfeld * All AMD AGP bridges are AGPv3 compliant, so we can do this scan 214c140df97SIngo Molnar * generically. It's probably overkill to always scan all slots because 215c140df97SIngo Molnar * the AGP bridges should be always an own bus on the HT hierarchy, 216c140df97SIngo Molnar * but do it here for future safety. 217c140df97SIngo Molnar */ 218dd564d0cSPavel Machek static u32 __init search_agp_bridge(u32 *order, int *valid_agp) 219250c2277SThomas Gleixner { 22055c0d721SYinghai Lu int bus, slot, func; 221250c2277SThomas Gleixner 222250c2277SThomas Gleixner /* Poor man's PCI discovery */ 22355c0d721SYinghai Lu for (bus = 0; bus < 256; bus++) { 224250c2277SThomas Gleixner for (slot = 0; slot < 32; slot++) { 225250c2277SThomas Gleixner for (func = 0; func < 8; func++) { 226250c2277SThomas Gleixner u32 class, cap; 227250c2277SThomas Gleixner u8 type; 22855c0d721SYinghai Lu class = read_pci_config(bus, slot, func, 229250c2277SThomas Gleixner PCI_CLASS_REVISION); 230250c2277SThomas Gleixner if (class == 0xffffffff) 231250c2277SThomas Gleixner break; 232250c2277SThomas Gleixner 233250c2277SThomas Gleixner switch (class >> 16) { 234250c2277SThomas Gleixner case PCI_CLASS_BRIDGE_HOST: 235250c2277SThomas Gleixner case PCI_CLASS_BRIDGE_OTHER: /* needed? */ 236250c2277SThomas Gleixner /* AGP bridge? */ 23755c0d721SYinghai Lu cap = find_cap(bus, slot, func, 238c140df97SIngo Molnar PCI_CAP_ID_AGP); 239250c2277SThomas Gleixner if (!cap) 240250c2277SThomas Gleixner break; 241250c2277SThomas Gleixner *valid_agp = 1; 24255c0d721SYinghai Lu return read_agp(bus, slot, func, cap, 243c140df97SIngo Molnar order); 244250c2277SThomas Gleixner } 245250c2277SThomas Gleixner 246250c2277SThomas Gleixner /* No multi-function device? */ 24755c0d721SYinghai Lu type = read_pci_config_byte(bus, slot, func, 248250c2277SThomas Gleixner PCI_HEADER_TYPE); 249250c2277SThomas Gleixner if (!(type & 0x80)) 250250c2277SThomas Gleixner break; 251250c2277SThomas Gleixner } 252250c2277SThomas Gleixner } 253250c2277SThomas Gleixner } 254a5d3244aSBjorn Helgaas pr_info("No AGP bridge found\n"); 255c140df97SIngo Molnar 256250c2277SThomas Gleixner return 0; 257250c2277SThomas Gleixner } 258250c2277SThomas Gleixner 2594cc7ecb7SKees Cook static bool gart_fix_e820 __initdata = true; 260aaf23042SYinghai Lu 261aaf23042SYinghai Lu static int __init parse_gart_mem(char *p) 262aaf23042SYinghai Lu { 2634cc7ecb7SKees Cook return kstrtobool(p, &gart_fix_e820); 264aaf23042SYinghai Lu } 265aaf23042SYinghai Lu early_param("gart_fix_e820", parse_gart_mem); 266aaf23042SYinghai Lu 267*63ecd3b1SBorislav Petkov /* 268*63ecd3b1SBorislav Petkov * With kexec/kdump, if the first kernel doesn't shut down the GART and the 269*63ecd3b1SBorislav Petkov * second kernel allocates a different GART region, there might be two 270*63ecd3b1SBorislav Petkov * overlapping GART regions present: 271*63ecd3b1SBorislav Petkov * 272*63ecd3b1SBorislav Petkov * - the first still used by the GART initialized in the first kernel. 273*63ecd3b1SBorislav Petkov * - (sub-)set of it used as normal RAM by the second kernel. 274*63ecd3b1SBorislav Petkov * 275*63ecd3b1SBorislav Petkov * which leads to memory corruptions and a kernel panic eventually. 276*63ecd3b1SBorislav Petkov * 277*63ecd3b1SBorislav Petkov * This can also happen if the BIOS has forgotten to mark the GART region 278*63ecd3b1SBorislav Petkov * as reserved. 279*63ecd3b1SBorislav Petkov * 280*63ecd3b1SBorislav Petkov * Try to update the e820 map to mark that new region as reserved. 281*63ecd3b1SBorislav Petkov */ 282aaf23042SYinghai Lu void __init early_gart_iommu_check(void) 283aaf23042SYinghai Lu { 284fa10ba64SAndi Kleen u32 agp_aper_order = 0; 285f3eee542SYinghai Lu int i, fix, slot, valid_agp = 0; 286aaf23042SYinghai Lu u32 ctl; 287aaf23042SYinghai Lu u32 aper_size = 0, aper_order = 0, last_aper_order = 0; 288aaf23042SYinghai Lu u64 aper_base = 0, last_aper_base = 0; 289fa5b8a30SPavel Machek int aper_enabled = 0, last_aper_enabled = 0, last_valid = 0; 290aaf23042SYinghai Lu 2911b457429SAravind Gopalakrishnan if (!amd_gart_present()) 2921b457429SAravind Gopalakrishnan return; 2931b457429SAravind Gopalakrishnan 294aaf23042SYinghai Lu if (!early_pci_allowed()) 295aaf23042SYinghai Lu return; 296aaf23042SYinghai Lu 297fa5b8a30SPavel Machek /* This is mostly duplicate of iommu_hole_init */ 298fa10ba64SAndi Kleen search_agp_bridge(&agp_aper_order, &valid_agp); 299f3eee542SYinghai Lu 300aaf23042SYinghai Lu fix = 0; 30124d9b70bSJan Beulich for (i = 0; amd_nb_bus_dev_ranges[i].dev_limit; i++) { 30255c0d721SYinghai Lu int bus; 30355c0d721SYinghai Lu int dev_base, dev_limit; 30455c0d721SYinghai Lu 30524d9b70bSJan Beulich bus = amd_nb_bus_dev_ranges[i].bus; 30624d9b70bSJan Beulich dev_base = amd_nb_bus_dev_ranges[i].dev_base; 30724d9b70bSJan Beulich dev_limit = amd_nb_bus_dev_ranges[i].dev_limit; 30855c0d721SYinghai Lu 30955c0d721SYinghai Lu for (slot = dev_base; slot < dev_limit; slot++) { 310eec1d4faSHans Rosenfeld if (!early_is_amd_nb(read_pci_config(bus, slot, 3, 0x00))) 311aaf23042SYinghai Lu continue; 312aaf23042SYinghai Lu 31355c0d721SYinghai Lu ctl = read_pci_config(bus, slot, 3, AMD64_GARTAPERTURECTL); 31457ab43e3SBorislav Petkov aper_enabled = ctl & GARTEN; 315aaf23042SYinghai Lu aper_order = (ctl >> 1) & 7; 316aaf23042SYinghai Lu aper_size = (32 * 1024 * 1024) << aper_order; 31755c0d721SYinghai Lu aper_base = read_pci_config(bus, slot, 3, AMD64_GARTAPERTUREBASE) & 0x7fff; 318aaf23042SYinghai Lu aper_base <<= 25; 319aaf23042SYinghai Lu 320fa5b8a30SPavel Machek if (last_valid) { 321fa5b8a30SPavel Machek if ((aper_order != last_aper_order) || 322fa5b8a30SPavel Machek (aper_base != last_aper_base) || 323fa5b8a30SPavel Machek (aper_enabled != last_aper_enabled)) { 324aaf23042SYinghai Lu fix = 1; 325fa5b8a30SPavel Machek break; 326aaf23042SYinghai Lu } 32755c0d721SYinghai Lu } 328aaf23042SYinghai Lu 329fa5b8a30SPavel Machek last_aper_order = aper_order; 330fa5b8a30SPavel Machek last_aper_base = aper_base; 331fa5b8a30SPavel Machek last_aper_enabled = aper_enabled; 332fa5b8a30SPavel Machek last_valid = 1; 333fa5b8a30SPavel Machek } 334fa5b8a30SPavel Machek } 335fa5b8a30SPavel Machek 336aaf23042SYinghai Lu if (!fix && !aper_enabled) 337aaf23042SYinghai Lu return; 338aaf23042SYinghai Lu 339aaf23042SYinghai Lu if (!aper_base || !aper_size || aper_base + aper_size > 0x100000000UL) 340aaf23042SYinghai Lu fix = 1; 341aaf23042SYinghai Lu 342aaf23042SYinghai Lu if (gart_fix_e820 && !fix && aper_enabled) { 3433bce64f0SIngo Molnar if (e820__mapped_any(aper_base, aper_base + aper_size, 34409821ff1SIngo Molnar E820_TYPE_RAM)) { 3450abbc78aSPavel Machek /* reserve it, so we can reuse it in second kernel */ 346c96ec953SBjorn Helgaas pr_info("e820: reserve [mem %#010Lx-%#010Lx] for GART\n", 347c96ec953SBjorn Helgaas aper_base, aper_base + aper_size - 1); 34809821ff1SIngo Molnar e820__range_add(aper_base, aper_size, E820_TYPE_RESERVED); 3496464d294SIngo Molnar e820__update_table_print(); 350aaf23042SYinghai Lu } 351aaf23042SYinghai Lu } 352aaf23042SYinghai Lu 353f3eee542SYinghai Lu if (valid_agp) 3544f384f8bSPavel Machek return; 3554f384f8bSPavel Machek 356f3eee542SYinghai Lu /* disable them all at first */ 35724d9b70bSJan Beulich for (i = 0; i < amd_nb_bus_dev_ranges[i].dev_limit; i++) { 35855c0d721SYinghai Lu int bus; 35955c0d721SYinghai Lu int dev_base, dev_limit; 36055c0d721SYinghai Lu 36124d9b70bSJan Beulich bus = amd_nb_bus_dev_ranges[i].bus; 36224d9b70bSJan Beulich dev_base = amd_nb_bus_dev_ranges[i].dev_base; 36324d9b70bSJan Beulich dev_limit = amd_nb_bus_dev_ranges[i].dev_limit; 36455c0d721SYinghai Lu 36555c0d721SYinghai Lu for (slot = dev_base; slot < dev_limit; slot++) { 366eec1d4faSHans Rosenfeld if (!early_is_amd_nb(read_pci_config(bus, slot, 3, 0x00))) 367aaf23042SYinghai Lu continue; 368aaf23042SYinghai Lu 36955c0d721SYinghai Lu ctl = read_pci_config(bus, slot, 3, AMD64_GARTAPERTURECTL); 37057ab43e3SBorislav Petkov ctl &= ~GARTEN; 37155c0d721SYinghai Lu write_pci_config(bus, slot, 3, AMD64_GARTAPERTURECTL, ctl); 37255c0d721SYinghai Lu } 373aaf23042SYinghai Lu } 374aaf23042SYinghai Lu 375aaf23042SYinghai Lu } 376aaf23042SYinghai Lu 3778c9fd91aSYinghai Lu static int __initdata printed_gart_size_msg; 3788c9fd91aSYinghai Lu 379480125baSKonrad Rzeszutek Wilk int __init gart_iommu_hole_init(void) 380250c2277SThomas Gleixner { 3818c9fd91aSYinghai Lu u32 agp_aper_base = 0, agp_aper_order = 0; 382250c2277SThomas Gleixner u32 aper_size, aper_alloc = 0, aper_order = 0, last_aper_order = 0; 383250c2277SThomas Gleixner u64 aper_base, last_aper_base = 0; 38455c0d721SYinghai Lu int fix, slot, valid_agp = 0; 38555c0d721SYinghai Lu int i, node; 386250c2277SThomas Gleixner 3871b457429SAravind Gopalakrishnan if (!amd_gart_present()) 3881b457429SAravind Gopalakrishnan return -ENODEV; 3891b457429SAravind Gopalakrishnan 3900440d4c0SJoerg Roedel if (gart_iommu_aperture_disabled || !fix_aperture || 3910440d4c0SJoerg Roedel !early_pci_allowed()) 392480125baSKonrad Rzeszutek Wilk return -ENODEV; 393250c2277SThomas Gleixner 394a5d3244aSBjorn Helgaas pr_info("Checking aperture...\n"); 395250c2277SThomas Gleixner 3968c9fd91aSYinghai Lu if (!fallback_aper_force) 3978c9fd91aSYinghai Lu agp_aper_base = search_agp_bridge(&agp_aper_order, &valid_agp); 3988c9fd91aSYinghai Lu 399250c2277SThomas Gleixner fix = 0; 40047db4c3eSYinghai Lu node = 0; 40124d9b70bSJan Beulich for (i = 0; i < amd_nb_bus_dev_ranges[i].dev_limit; i++) { 40255c0d721SYinghai Lu int bus; 40355c0d721SYinghai Lu int dev_base, dev_limit; 4044b83873dSJoerg Roedel u32 ctl; 40555c0d721SYinghai Lu 40624d9b70bSJan Beulich bus = amd_nb_bus_dev_ranges[i].bus; 40724d9b70bSJan Beulich dev_base = amd_nb_bus_dev_ranges[i].dev_base; 40824d9b70bSJan Beulich dev_limit = amd_nb_bus_dev_ranges[i].dev_limit; 40955c0d721SYinghai Lu 41055c0d721SYinghai Lu for (slot = dev_base; slot < dev_limit; slot++) { 411eec1d4faSHans Rosenfeld if (!early_is_amd_nb(read_pci_config(bus, slot, 3, 0x00))) 412250c2277SThomas Gleixner continue; 413250c2277SThomas Gleixner 414250c2277SThomas Gleixner iommu_detected = 1; 4150440d4c0SJoerg Roedel gart_iommu_aperture = 1; 416de957628SFUJITA Tomonori x86_init.iommu.iommu_init = gart_iommu_init; 417250c2277SThomas Gleixner 4184b83873dSJoerg Roedel ctl = read_pci_config(bus, slot, 3, 4194b83873dSJoerg Roedel AMD64_GARTAPERTURECTL); 4204b83873dSJoerg Roedel 4214b83873dSJoerg Roedel /* 4224b83873dSJoerg Roedel * Before we do anything else disable the GART. It may 4234b83873dSJoerg Roedel * still be enabled if we boot into a crash-kernel here. 4244b83873dSJoerg Roedel * Reconfiguring the GART while it is enabled could have 4254b83873dSJoerg Roedel * unknown side-effects. 4264b83873dSJoerg Roedel */ 4274b83873dSJoerg Roedel ctl &= ~GARTEN; 4284b83873dSJoerg Roedel write_pci_config(bus, slot, 3, AMD64_GARTAPERTURECTL, ctl); 4294b83873dSJoerg Roedel 4304b83873dSJoerg Roedel aper_order = (ctl >> 1) & 7; 431250c2277SThomas Gleixner aper_size = (32 * 1024 * 1024) << aper_order; 43255c0d721SYinghai Lu aper_base = read_pci_config(bus, slot, 3, AMD64_GARTAPERTUREBASE) & 0x7fff; 433250c2277SThomas Gleixner aper_base <<= 25; 434250c2277SThomas Gleixner 435c96ec953SBjorn Helgaas pr_info("Node %d: aperture [bus addr %#010Lx-%#010Lx] (%uMB)\n", 436c96ec953SBjorn Helgaas node, aper_base, aper_base + aper_size - 1, 437c96ec953SBjorn Helgaas aper_size >> 20); 43847db4c3eSYinghai Lu node++; 439250c2277SThomas Gleixner 4408c9fd91aSYinghai Lu if (!aperture_valid(aper_base, aper_size, 64<<20)) { 4418c9fd91aSYinghai Lu if (valid_agp && agp_aper_base && 4428c9fd91aSYinghai Lu agp_aper_base == aper_base && 4438c9fd91aSYinghai Lu agp_aper_order == aper_order) { 4448c9fd91aSYinghai Lu /* the same between two setting from NB and agp */ 445c987d12fSYinghai Lu if (!no_iommu && 446c987d12fSYinghai Lu max_pfn > MAX_DMA32_PFN && 447c987d12fSYinghai Lu !printed_gart_size_msg) { 448c96ec953SBjorn Helgaas pr_err("you are using iommu with agp, but GART size is less than 64MB\n"); 449a5d3244aSBjorn Helgaas pr_err("please increase GART size in your BIOS setup\n"); 450a5d3244aSBjorn Helgaas pr_err("if BIOS doesn't have that option, contact your HW vendor!\n"); 4518c9fd91aSYinghai Lu printed_gart_size_msg = 1; 4528c9fd91aSYinghai Lu } 4538c9fd91aSYinghai Lu } else { 454250c2277SThomas Gleixner fix = 1; 45555c0d721SYinghai Lu goto out; 456250c2277SThomas Gleixner } 4578c9fd91aSYinghai Lu } 458250c2277SThomas Gleixner 459250c2277SThomas Gleixner if ((last_aper_order && aper_order != last_aper_order) || 460250c2277SThomas Gleixner (last_aper_base && aper_base != last_aper_base)) { 461250c2277SThomas Gleixner fix = 1; 46255c0d721SYinghai Lu goto out; 463250c2277SThomas Gleixner } 464250c2277SThomas Gleixner last_aper_order = aper_order; 465250c2277SThomas Gleixner last_aper_base = aper_base; 466250c2277SThomas Gleixner } 46755c0d721SYinghai Lu } 468250c2277SThomas Gleixner 46955c0d721SYinghai Lu out: 470250c2277SThomas Gleixner if (!fix && !fallback_aper_force) { 4712a3e83c6SJiri Bohac if (last_aper_base) { 4722a3e83c6SJiri Bohac /* 4732a3e83c6SJiri Bohac * If this is the kdump kernel, the first kernel 4742a3e83c6SJiri Bohac * may have allocated the range over its e820 RAM 4752a3e83c6SJiri Bohac * and fixed up the northbridge 4762a3e83c6SJiri Bohac */ 4772a3e83c6SJiri Bohac exclude_from_vmcore(last_aper_base, last_aper_order); 4782a3e83c6SJiri Bohac 479480125baSKonrad Rzeszutek Wilk return 1; 4802a3e83c6SJiri Bohac } 481480125baSKonrad Rzeszutek Wilk return 0; 482250c2277SThomas Gleixner } 483250c2277SThomas Gleixner 4848c9fd91aSYinghai Lu if (!fallback_aper_force) { 4858c9fd91aSYinghai Lu aper_alloc = agp_aper_base; 4868c9fd91aSYinghai Lu aper_order = agp_aper_order; 4878c9fd91aSYinghai Lu } 488250c2277SThomas Gleixner 489250c2277SThomas Gleixner if (aper_alloc) { 490250c2277SThomas Gleixner /* Got the aperture from the AGP bridge */ 491c987d12fSYinghai Lu } else if ((!no_iommu && max_pfn > MAX_DMA32_PFN) || 492250c2277SThomas Gleixner force_iommu || 493250c2277SThomas Gleixner valid_agp || 494250c2277SThomas Gleixner fallback_aper_force) { 4951b457429SAravind Gopalakrishnan pr_info("Your BIOS doesn't leave an aperture memory hole\n"); 496a5d3244aSBjorn Helgaas pr_info("Please enable the IOMMU option in the BIOS setup\n"); 497a5d3244aSBjorn Helgaas pr_info("This costs you %dMB of RAM\n", 498250c2277SThomas Gleixner 32 << fallback_aper_order); 499250c2277SThomas Gleixner 500250c2277SThomas Gleixner aper_order = fallback_aper_order; 501250c2277SThomas Gleixner aper_alloc = allocate_aperture(); 502250c2277SThomas Gleixner if (!aper_alloc) { 503c140df97SIngo Molnar /* 504c140df97SIngo Molnar * Could disable AGP and IOMMU here, but it's 505c140df97SIngo Molnar * probably not worth it. But the later users 506c140df97SIngo Molnar * cannot deal with bad apertures and turning 507c140df97SIngo Molnar * on the aperture over memory causes very 508c140df97SIngo Molnar * strange problems, so it's better to panic 509c140df97SIngo Molnar * early. 510c140df97SIngo Molnar */ 511250c2277SThomas Gleixner panic("Not enough memory for aperture"); 512250c2277SThomas Gleixner } 513250c2277SThomas Gleixner } else { 514480125baSKonrad Rzeszutek Wilk return 0; 515250c2277SThomas Gleixner } 516250c2277SThomas Gleixner 5172a3e83c6SJiri Bohac /* 5182a3e83c6SJiri Bohac * If this is the kdump kernel _and_ the first kernel did not 5192a3e83c6SJiri Bohac * configure the aperture in the northbridge, this range may 5202a3e83c6SJiri Bohac * overlap with the first kernel's memory. We can't access the 5212a3e83c6SJiri Bohac * range through vmcore even though it should be part of the dump. 5222a3e83c6SJiri Bohac */ 5232a3e83c6SJiri Bohac exclude_from_vmcore(aper_alloc, aper_order); 5242a3e83c6SJiri Bohac 525250c2277SThomas Gleixner /* Fix up the north bridges */ 52624d9b70bSJan Beulich for (i = 0; i < amd_nb_bus_dev_ranges[i].dev_limit; i++) { 527260133abSBorislav Petkov int bus, dev_base, dev_limit; 528260133abSBorislav Petkov 529260133abSBorislav Petkov /* 530260133abSBorislav Petkov * Don't enable translation yet but enable GART IO and CPU 531260133abSBorislav Petkov * accesses and set DISTLBWALKPRB since GART table memory is UC. 532260133abSBorislav Petkov */ 533c34151a7SJoerg Roedel u32 ctl = aper_order << 1; 53455c0d721SYinghai Lu 53524d9b70bSJan Beulich bus = amd_nb_bus_dev_ranges[i].bus; 53624d9b70bSJan Beulich dev_base = amd_nb_bus_dev_ranges[i].dev_base; 53724d9b70bSJan Beulich dev_limit = amd_nb_bus_dev_ranges[i].dev_limit; 53855c0d721SYinghai Lu for (slot = dev_base; slot < dev_limit; slot++) { 539eec1d4faSHans Rosenfeld if (!early_is_amd_nb(read_pci_config(bus, slot, 3, 0x00))) 540250c2277SThomas Gleixner continue; 541250c2277SThomas Gleixner 542260133abSBorislav Petkov write_pci_config(bus, slot, 3, AMD64_GARTAPERTURECTL, ctl); 54355c0d721SYinghai Lu write_pci_config(bus, slot, 3, AMD64_GARTAPERTUREBASE, aper_alloc >> 25); 54455c0d721SYinghai Lu } 545250c2277SThomas Gleixner } 5466703f6d1SRafael J. Wysocki 5476703f6d1SRafael J. Wysocki set_up_gart_resume(aper_order, aper_alloc); 548480125baSKonrad Rzeszutek Wilk 549480125baSKonrad Rzeszutek Wilk return 1; 550250c2277SThomas Gleixner } 551