xref: /linux/arch/x86/kernel/aperture_64.c (revision 63ecd3b13d5cf07959a2315ec62a7c62e20df114)
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