xref: /linux/arch/x86/kernel/aperture_64.c (revision 06d07429858317ded2db7986113a9e0129cd599b)
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>
17ffc8599aSKairui Song #include <linux/kcore.h>
18250c2277SThomas Gleixner #include <linux/types.h>
19250c2277SThomas Gleixner #include <linux/init.h>
2032e3f2b0SYinghai Lu #include <linux/memblock.h>
21250c2277SThomas Gleixner #include <linux/mmzone.h>
22250c2277SThomas Gleixner #include <linux/pci_ids.h>
23250c2277SThomas Gleixner #include <linux/pci.h>
24250c2277SThomas Gleixner #include <linux/bitops.h>
252050d45dSPavel Machek #include <linux/suspend.h>
2666441bd3SIngo Molnar #include <asm/e820/api.h>
27250c2277SThomas Gleixner #include <asm/io.h>
2846a7fa27SFUJITA Tomonori #include <asm/iommu.h>
29395624fcSJoerg Roedel #include <asm/gart.h>
30250c2277SThomas Gleixner #include <asm/pci-direct.h>
31250c2277SThomas Gleixner #include <asm/dma.h>
3223ac4ae8SAndreas Herrmann #include <asm/amd_nb.h>
33de957628SFUJITA Tomonori #include <asm/x86_init.h>
342a3e83c6SJiri Bohac #include <linux/crash_dump.h>
35250c2277SThomas Gleixner 
36c387aa3aSJoerg Roedel /*
37c387aa3aSJoerg Roedel  * Using 512M as goal, in case kexec will load kernel_big
38c387aa3aSJoerg Roedel  * that will do the on-position decompress, and could overlap with
393163600cSJason Wang  * the gart aperture that is used.
40c387aa3aSJoerg Roedel  * Sequence:
41c387aa3aSJoerg Roedel  * kernel_small
42c387aa3aSJoerg Roedel  * ==> kexec (with kdump trigger path or gart still enabled)
43c387aa3aSJoerg Roedel  * ==> kernel_small (gart area become e820_reserved)
44c387aa3aSJoerg Roedel  * ==> kexec (with kdump trigger path or gart still enabled)
45c387aa3aSJoerg Roedel  * ==> kerne_big (uncompressed size will be big than 64M or 128M)
46c387aa3aSJoerg Roedel  * So don't use 512M below as gart iommu, leave the space for kernel
47c387aa3aSJoerg Roedel  * code for safe.
48c387aa3aSJoerg Roedel  */
49c387aa3aSJoerg Roedel #define GART_MIN_ADDR	(512ULL << 20)
50c387aa3aSJoerg Roedel #define GART_MAX_ADDR	(1ULL   << 32)
51c387aa3aSJoerg Roedel 
520440d4c0SJoerg Roedel int gart_iommu_aperture;
537de6a4cdSPavel Machek int gart_iommu_aperture_disabled __initdata;
547de6a4cdSPavel Machek int gart_iommu_aperture_allowed __initdata;
55250c2277SThomas Gleixner 
56250c2277SThomas Gleixner int fallback_aper_order __initdata = 1; /* 64MB */
577de6a4cdSPavel Machek int fallback_aper_force __initdata;
58250c2277SThomas Gleixner 
59250c2277SThomas Gleixner int fix_aperture __initdata = 1;
60250c2277SThomas Gleixner 
61ffc8599aSKairui Song #if defined(CONFIG_PROC_VMCORE) || defined(CONFIG_PROC_KCORE)
622a3e83c6SJiri Bohac /*
632a3e83c6SJiri Bohac  * If the first kernel maps the aperture over e820 RAM, the kdump kernel will
642a3e83c6SJiri Bohac  * use the same range because it will remain configured in the northbridge.
652a3e83c6SJiri Bohac  * Trying to dump this area via /proc/vmcore may crash the machine, so exclude
662a3e83c6SJiri Bohac  * it from vmcore.
672a3e83c6SJiri Bohac  */
682a3e83c6SJiri Bohac static unsigned long aperture_pfn_start, aperture_page_count;
692a3e83c6SJiri Bohac 
gart_mem_pfn_is_ram(unsigned long pfn)70ffc8599aSKairui Song static int gart_mem_pfn_is_ram(unsigned long pfn)
712a3e83c6SJiri Bohac {
722a3e83c6SJiri Bohac 	return likely((pfn < aperture_pfn_start) ||
732a3e83c6SJiri Bohac 		      (pfn >= aperture_pfn_start + aperture_page_count));
742a3e83c6SJiri Bohac }
752a3e83c6SJiri Bohac 
76cc5f2704SDavid Hildenbrand #ifdef CONFIG_PROC_VMCORE
gart_oldmem_pfn_is_ram(struct vmcore_cb * cb,unsigned long pfn)77cc5f2704SDavid Hildenbrand static bool gart_oldmem_pfn_is_ram(struct vmcore_cb *cb, unsigned long pfn)
78cc5f2704SDavid Hildenbrand {
79cc5f2704SDavid Hildenbrand 	return !!gart_mem_pfn_is_ram(pfn);
80cc5f2704SDavid Hildenbrand }
81cc5f2704SDavid Hildenbrand 
82cc5f2704SDavid Hildenbrand static struct vmcore_cb gart_vmcore_cb = {
83cc5f2704SDavid Hildenbrand 	.pfn_is_ram = gart_oldmem_pfn_is_ram,
84cc5f2704SDavid Hildenbrand };
85cc5f2704SDavid Hildenbrand #endif
86cc5f2704SDavid Hildenbrand 
exclude_from_core(u64 aper_base,u32 aper_order)87ffc8599aSKairui Song static void __init exclude_from_core(u64 aper_base, u32 aper_order)
882a3e83c6SJiri Bohac {
892a3e83c6SJiri Bohac 	aperture_pfn_start = aper_base >> PAGE_SHIFT;
902a3e83c6SJiri Bohac 	aperture_page_count = (32 * 1024 * 1024) << aper_order >> PAGE_SHIFT;
91ffc8599aSKairui Song #ifdef CONFIG_PROC_VMCORE
92cc5f2704SDavid Hildenbrand 	register_vmcore_cb(&gart_vmcore_cb);
93ffc8599aSKairui Song #endif
94ffc8599aSKairui Song #ifdef CONFIG_PROC_KCORE
95ffc8599aSKairui Song 	WARN_ON(register_mem_pfn_is_ram(&gart_mem_pfn_is_ram));
96ffc8599aSKairui Song #endif
972a3e83c6SJiri Bohac }
982a3e83c6SJiri Bohac #else
exclude_from_core(u64 aper_base,u32 aper_order)99ffc8599aSKairui Song static void exclude_from_core(u64 aper_base, u32 aper_order)
1002a3e83c6SJiri Bohac {
1012a3e83c6SJiri Bohac }
1022a3e83c6SJiri Bohac #endif
1032a3e83c6SJiri Bohac 
104250c2277SThomas Gleixner /* This code runs before the PCI subsystem is initialized, so just
105250c2277SThomas Gleixner    access the northbridge directly. */
106250c2277SThomas Gleixner 
allocate_aperture(void)107250c2277SThomas Gleixner static u32 __init allocate_aperture(void)
108250c2277SThomas Gleixner {
109250c2277SThomas Gleixner 	u32 aper_size;
11032e3f2b0SYinghai Lu 	unsigned long addr;
111250c2277SThomas Gleixner 
1127677b2efSYinghai Lu 	/* aper_size should <= 1G */
1137677b2efSYinghai Lu 	if (fallback_aper_order > 5)
1147677b2efSYinghai Lu 		fallback_aper_order = 5;
115250c2277SThomas Gleixner 	aper_size = (32 * 1024 * 1024) << fallback_aper_order;
116250c2277SThomas Gleixner 
117250c2277SThomas Gleixner 	/*
118c140df97SIngo Molnar 	 * Aperture has to be naturally aligned. This means a 2GB aperture
119c140df97SIngo Molnar 	 * won't have much chance of finding a place in the lower 4GB of
120c140df97SIngo Molnar 	 * memory. Unfortunately we cannot move it up because that would
121c140df97SIngo Molnar 	 * make the IOMMU useless.
122250c2277SThomas Gleixner 	 */
123a7259df7SMike Rapoport 	addr = memblock_phys_alloc_range(aper_size, aper_size,
124a7259df7SMike Rapoport 					 GART_MIN_ADDR, GART_MAX_ADDR);
12526bfc540SWang YanQing 	if (!addr) {
126c96ec953SBjorn Helgaas 		pr_err("Cannot allocate aperture memory hole [mem %#010lx-%#010lx] (%uKB)\n",
127c96ec953SBjorn Helgaas 		       addr, addr + aper_size - 1, aper_size >> 10);
12832e3f2b0SYinghai Lu 		return 0;
12932e3f2b0SYinghai Lu 	}
130c96ec953SBjorn Helgaas 	pr_info("Mapping aperture over RAM [mem %#010lx-%#010lx] (%uKB)\n",
131c96ec953SBjorn Helgaas 		addr, addr + aper_size - 1, aper_size >> 10);
13232e3f2b0SYinghai Lu 	register_nosave_region(addr >> PAGE_SHIFT,
13332e3f2b0SYinghai Lu 			       (addr+aper_size) >> PAGE_SHIFT);
134c140df97SIngo Molnar 
13532e3f2b0SYinghai Lu 	return (u32)addr;
136250c2277SThomas Gleixner }
137250c2277SThomas Gleixner 
138250c2277SThomas Gleixner 
139250c2277SThomas Gleixner /* Find a PCI capability */
find_cap(int bus,int slot,int func,int cap)140dd564d0cSPavel Machek static u32 __init find_cap(int bus, int slot, int func, int cap)
141250c2277SThomas Gleixner {
142250c2277SThomas Gleixner 	int bytes;
143c140df97SIngo Molnar 	u8 pos;
144c140df97SIngo Molnar 
14555c0d721SYinghai Lu 	if (!(read_pci_config_16(bus, slot, func, PCI_STATUS) &
146c140df97SIngo Molnar 						PCI_STATUS_CAP_LIST))
147250c2277SThomas Gleixner 		return 0;
148c140df97SIngo Molnar 
14955c0d721SYinghai Lu 	pos = read_pci_config_byte(bus, slot, func, PCI_CAPABILITY_LIST);
150250c2277SThomas Gleixner 	for (bytes = 0; bytes < 48 && pos >= 0x40; bytes++) {
151250c2277SThomas Gleixner 		u8 id;
152c140df97SIngo Molnar 
153250c2277SThomas Gleixner 		pos &= ~3;
15455c0d721SYinghai Lu 		id = read_pci_config_byte(bus, slot, func, pos+PCI_CAP_LIST_ID);
155250c2277SThomas Gleixner 		if (id == 0xff)
156250c2277SThomas Gleixner 			break;
157250c2277SThomas Gleixner 		if (id == cap)
158250c2277SThomas Gleixner 			return pos;
15955c0d721SYinghai Lu 		pos = read_pci_config_byte(bus, slot, func,
160c140df97SIngo Molnar 						pos+PCI_CAP_LIST_NEXT);
161250c2277SThomas Gleixner 	}
162250c2277SThomas Gleixner 	return 0;
163250c2277SThomas Gleixner }
164250c2277SThomas Gleixner 
165250c2277SThomas Gleixner /* Read a standard AGPv3 bridge header */
read_agp(int bus,int slot,int func,int cap,u32 * order)166dd564d0cSPavel Machek static u32 __init read_agp(int bus, int slot, int func, int cap, u32 *order)
167250c2277SThomas Gleixner {
168250c2277SThomas Gleixner 	u32 apsize;
169250c2277SThomas Gleixner 	u32 apsizereg;
170250c2277SThomas Gleixner 	int nbits;
171250c2277SThomas Gleixner 	u32 aper_low, aper_hi;
172250c2277SThomas Gleixner 	u64 aper;
1731edc1ab3SYinghai Lu 	u32 old_order;
174250c2277SThomas Gleixner 
175c96ec953SBjorn Helgaas 	pr_info("pci 0000:%02x:%02x:%02x: AGP bridge\n", bus, slot, func);
17655c0d721SYinghai Lu 	apsizereg = read_pci_config_16(bus, slot, func, cap + 0x14);
177250c2277SThomas Gleixner 	if (apsizereg == 0xffffffff) {
178c96ec953SBjorn Helgaas 		pr_err("pci 0000:%02x:%02x.%d: APSIZE unreadable\n",
179c96ec953SBjorn Helgaas 		       bus, slot, func);
180250c2277SThomas Gleixner 		return 0;
181250c2277SThomas Gleixner 	}
182250c2277SThomas Gleixner 
1831edc1ab3SYinghai Lu 	/* old_order could be the value from NB gart setting */
1841edc1ab3SYinghai Lu 	old_order = *order;
1851edc1ab3SYinghai Lu 
186250c2277SThomas Gleixner 	apsize = apsizereg & 0xfff;
187250c2277SThomas Gleixner 	/* Some BIOS use weird encodings not in the AGPv3 table. */
188250c2277SThomas Gleixner 	if (apsize & 0xff)
189250c2277SThomas Gleixner 		apsize |= 0xf00;
190250c2277SThomas Gleixner 	nbits = hweight16(apsize);
191250c2277SThomas Gleixner 	*order = 7 - nbits;
192250c2277SThomas Gleixner 	if ((int)*order < 0) /* < 32MB */
193250c2277SThomas Gleixner 		*order = 0;
194250c2277SThomas Gleixner 
19555c0d721SYinghai Lu 	aper_low = read_pci_config(bus, slot, func, 0x10);
19655c0d721SYinghai Lu 	aper_hi = read_pci_config(bus, slot, func, 0x14);
197250c2277SThomas Gleixner 	aper = (aper_low & ~((1<<22)-1)) | ((u64)aper_hi << 32);
198250c2277SThomas Gleixner 
1991edc1ab3SYinghai Lu 	/*
2001edc1ab3SYinghai Lu 	 * On some sick chips, APSIZE is 0. It means it wants 4G
2011edc1ab3SYinghai Lu 	 * so let double check that order, and lets trust AMD NB settings:
2021edc1ab3SYinghai Lu 	 */
203c96ec953SBjorn Helgaas 	pr_info("pci 0000:%02x:%02x.%d: AGP aperture [bus addr %#010Lx-%#010Lx] (old size %uMB)\n",
204c96ec953SBjorn Helgaas 		bus, slot, func, aper, aper + (32ULL << (old_order + 20)) - 1,
205c96ec953SBjorn Helgaas 		32 << old_order);
2068c9fd91aSYinghai Lu 	if (aper + (32ULL<<(20 + *order)) > 0x100000000ULL) {
207c96ec953SBjorn Helgaas 		pr_info("pci 0000:%02x:%02x.%d: AGP aperture size %uMB (APSIZE %#x) is not right, using settings from NB\n",
208c96ec953SBjorn Helgaas 			bus, slot, func, 32 << *order, apsizereg);
2091edc1ab3SYinghai Lu 		*order = old_order;
2101edc1ab3SYinghai Lu 	}
2111edc1ab3SYinghai Lu 
212c96ec953SBjorn Helgaas 	pr_info("pci 0000:%02x:%02x.%d: AGP aperture [bus addr %#010Lx-%#010Lx] (%uMB, APSIZE %#x)\n",
213c96ec953SBjorn Helgaas 		bus, slot, func, aper, aper + (32ULL << (*order + 20)) - 1,
214a5d3244aSBjorn Helgaas 		32 << *order, apsizereg);
215250c2277SThomas Gleixner 
2168c9fd91aSYinghai Lu 	if (!aperture_valid(aper, (32*1024*1024) << *order, 32<<20))
217250c2277SThomas Gleixner 		return 0;
218250c2277SThomas Gleixner 	return (u32)aper;
219250c2277SThomas Gleixner }
220250c2277SThomas Gleixner 
221c140df97SIngo Molnar /*
222c140df97SIngo Molnar  * Look for an AGP bridge. Windows only expects the aperture in the
223c140df97SIngo Molnar  * AGP bridge and some BIOS forget to initialize the Northbridge too.
224c140df97SIngo Molnar  * Work around this here.
225c140df97SIngo Molnar  *
226c140df97SIngo Molnar  * Do an PCI bus scan by hand because we're running before the PCI
227c140df97SIngo Molnar  * subsystem.
228c140df97SIngo Molnar  *
229eec1d4faSHans Rosenfeld  * All AMD AGP bridges are AGPv3 compliant, so we can do this scan
230c140df97SIngo Molnar  * generically. It's probably overkill to always scan all slots because
231c140df97SIngo Molnar  * the AGP bridges should be always an own bus on the HT hierarchy,
232c140df97SIngo Molnar  * but do it here for future safety.
233c140df97SIngo Molnar  */
search_agp_bridge(u32 * order,int * valid_agp)234dd564d0cSPavel Machek static u32 __init search_agp_bridge(u32 *order, int *valid_agp)
235250c2277SThomas Gleixner {
23655c0d721SYinghai Lu 	int bus, slot, func;
237250c2277SThomas Gleixner 
238250c2277SThomas Gleixner 	/* Poor man's PCI discovery */
23955c0d721SYinghai Lu 	for (bus = 0; bus < 256; bus++) {
240250c2277SThomas Gleixner 		for (slot = 0; slot < 32; slot++) {
241250c2277SThomas Gleixner 			for (func = 0; func < 8; func++) {
242250c2277SThomas Gleixner 				u32 class, cap;
243250c2277SThomas Gleixner 				u8 type;
24455c0d721SYinghai Lu 				class = read_pci_config(bus, slot, func,
245250c2277SThomas Gleixner 							PCI_CLASS_REVISION);
246250c2277SThomas Gleixner 				if (class == 0xffffffff)
247250c2277SThomas Gleixner 					break;
248250c2277SThomas Gleixner 
249250c2277SThomas Gleixner 				switch (class >> 16) {
250250c2277SThomas Gleixner 				case PCI_CLASS_BRIDGE_HOST:
251250c2277SThomas Gleixner 				case PCI_CLASS_BRIDGE_OTHER: /* needed? */
252250c2277SThomas Gleixner 					/* AGP bridge? */
25355c0d721SYinghai Lu 					cap = find_cap(bus, slot, func,
254c140df97SIngo Molnar 							PCI_CAP_ID_AGP);
255250c2277SThomas Gleixner 					if (!cap)
256250c2277SThomas Gleixner 						break;
257250c2277SThomas Gleixner 					*valid_agp = 1;
25855c0d721SYinghai Lu 					return read_agp(bus, slot, func, cap,
259c140df97SIngo Molnar 							order);
260250c2277SThomas Gleixner 				}
261250c2277SThomas Gleixner 
26255c0d721SYinghai Lu 				type = read_pci_config_byte(bus, slot, func,
263250c2277SThomas Gleixner 							       PCI_HEADER_TYPE);
264*197e0da1SIlpo Järvinen 				if (!(type & PCI_HEADER_TYPE_MFD))
265250c2277SThomas Gleixner 					break;
266250c2277SThomas Gleixner 			}
267250c2277SThomas Gleixner 		}
268250c2277SThomas Gleixner 	}
269a5d3244aSBjorn Helgaas 	pr_info("No AGP bridge found\n");
270c140df97SIngo Molnar 
271250c2277SThomas Gleixner 	return 0;
272250c2277SThomas Gleixner }
273250c2277SThomas Gleixner 
2744cc7ecb7SKees Cook static bool gart_fix_e820 __initdata = true;
275aaf23042SYinghai Lu 
parse_gart_mem(char * p)276aaf23042SYinghai Lu static int __init parse_gart_mem(char *p)
277aaf23042SYinghai Lu {
2784cc7ecb7SKees Cook 	return kstrtobool(p, &gart_fix_e820);
279aaf23042SYinghai Lu }
280aaf23042SYinghai Lu early_param("gart_fix_e820", parse_gart_mem);
281aaf23042SYinghai Lu 
28263ecd3b1SBorislav Petkov /*
28363ecd3b1SBorislav Petkov  * With kexec/kdump, if the first kernel doesn't shut down the GART and the
28463ecd3b1SBorislav Petkov  * second kernel allocates a different GART region, there might be two
28563ecd3b1SBorislav Petkov  * overlapping GART regions present:
28663ecd3b1SBorislav Petkov  *
28763ecd3b1SBorislav Petkov  * - the first still used by the GART initialized in the first kernel.
28863ecd3b1SBorislav Petkov  * - (sub-)set of it used as normal RAM by the second kernel.
28963ecd3b1SBorislav Petkov  *
29063ecd3b1SBorislav Petkov  * which leads to memory corruptions and a kernel panic eventually.
29163ecd3b1SBorislav Petkov  *
29263ecd3b1SBorislav Petkov  * This can also happen if the BIOS has forgotten to mark the GART region
29363ecd3b1SBorislav Petkov  * as reserved.
29463ecd3b1SBorislav Petkov  *
29563ecd3b1SBorislav Petkov  * Try to update the e820 map to mark that new region as reserved.
29663ecd3b1SBorislav Petkov  */
early_gart_iommu_check(void)297aaf23042SYinghai Lu void __init early_gart_iommu_check(void)
298aaf23042SYinghai Lu {
299fa10ba64SAndi Kleen 	u32 agp_aper_order = 0;
300f3eee542SYinghai Lu 	int i, fix, slot, valid_agp = 0;
301aaf23042SYinghai Lu 	u32 ctl;
302aaf23042SYinghai Lu 	u32 aper_size = 0, aper_order = 0, last_aper_order = 0;
303aaf23042SYinghai Lu 	u64 aper_base = 0, last_aper_base = 0;
304fa5b8a30SPavel Machek 	int aper_enabled = 0, last_aper_enabled = 0, last_valid = 0;
305aaf23042SYinghai Lu 
3061b457429SAravind Gopalakrishnan 	if (!amd_gart_present())
3071b457429SAravind Gopalakrishnan 		return;
3081b457429SAravind Gopalakrishnan 
309aaf23042SYinghai Lu 	if (!early_pci_allowed())
310aaf23042SYinghai Lu 		return;
311aaf23042SYinghai Lu 
312fa5b8a30SPavel Machek 	/* This is mostly duplicate of iommu_hole_init */
313fa10ba64SAndi Kleen 	search_agp_bridge(&agp_aper_order, &valid_agp);
314f3eee542SYinghai Lu 
315aaf23042SYinghai Lu 	fix = 0;
31624d9b70bSJan Beulich 	for (i = 0; amd_nb_bus_dev_ranges[i].dev_limit; i++) {
31755c0d721SYinghai Lu 		int bus;
31855c0d721SYinghai Lu 		int dev_base, dev_limit;
31955c0d721SYinghai Lu 
32024d9b70bSJan Beulich 		bus = amd_nb_bus_dev_ranges[i].bus;
32124d9b70bSJan Beulich 		dev_base = amd_nb_bus_dev_ranges[i].dev_base;
32224d9b70bSJan Beulich 		dev_limit = amd_nb_bus_dev_ranges[i].dev_limit;
32355c0d721SYinghai Lu 
32455c0d721SYinghai Lu 		for (slot = dev_base; slot < dev_limit; slot++) {
325eec1d4faSHans Rosenfeld 			if (!early_is_amd_nb(read_pci_config(bus, slot, 3, 0x00)))
326aaf23042SYinghai Lu 				continue;
327aaf23042SYinghai Lu 
32855c0d721SYinghai Lu 			ctl = read_pci_config(bus, slot, 3, AMD64_GARTAPERTURECTL);
32957ab43e3SBorislav Petkov 			aper_enabled = ctl & GARTEN;
330aaf23042SYinghai Lu 			aper_order = (ctl >> 1) & 7;
331aaf23042SYinghai Lu 			aper_size = (32 * 1024 * 1024) << aper_order;
33255c0d721SYinghai Lu 			aper_base = read_pci_config(bus, slot, 3, AMD64_GARTAPERTUREBASE) & 0x7fff;
333aaf23042SYinghai Lu 			aper_base <<= 25;
334aaf23042SYinghai Lu 
335fa5b8a30SPavel Machek 			if (last_valid) {
336fa5b8a30SPavel Machek 				if ((aper_order != last_aper_order) ||
337fa5b8a30SPavel Machek 				    (aper_base != last_aper_base) ||
338fa5b8a30SPavel Machek 				    (aper_enabled != last_aper_enabled)) {
339aaf23042SYinghai Lu 					fix = 1;
340fa5b8a30SPavel Machek 					break;
341aaf23042SYinghai Lu 				}
34255c0d721SYinghai Lu 			}
343aaf23042SYinghai Lu 
344fa5b8a30SPavel Machek 			last_aper_order = aper_order;
345fa5b8a30SPavel Machek 			last_aper_base = aper_base;
346fa5b8a30SPavel Machek 			last_aper_enabled = aper_enabled;
347fa5b8a30SPavel Machek 			last_valid = 1;
348fa5b8a30SPavel Machek 		}
349fa5b8a30SPavel Machek 	}
350fa5b8a30SPavel Machek 
351aaf23042SYinghai Lu 	if (!fix && !aper_enabled)
352aaf23042SYinghai Lu 		return;
353aaf23042SYinghai Lu 
354aaf23042SYinghai Lu 	if (!aper_base || !aper_size || aper_base + aper_size > 0x100000000UL)
355aaf23042SYinghai Lu 		fix = 1;
356aaf23042SYinghai Lu 
357aaf23042SYinghai Lu 	if (gart_fix_e820 && !fix && aper_enabled) {
3583bce64f0SIngo Molnar 		if (e820__mapped_any(aper_base, aper_base + aper_size,
35909821ff1SIngo Molnar 				    E820_TYPE_RAM)) {
3600abbc78aSPavel Machek 			/* reserve it, so we can reuse it in second kernel */
361c96ec953SBjorn Helgaas 			pr_info("e820: reserve [mem %#010Lx-%#010Lx] for GART\n",
362c96ec953SBjorn Helgaas 				aper_base, aper_base + aper_size - 1);
36309821ff1SIngo Molnar 			e820__range_add(aper_base, aper_size, E820_TYPE_RESERVED);
3646464d294SIngo Molnar 			e820__update_table_print();
365aaf23042SYinghai Lu 		}
366aaf23042SYinghai Lu 	}
367aaf23042SYinghai Lu 
368f3eee542SYinghai Lu 	if (valid_agp)
3694f384f8bSPavel Machek 		return;
3704f384f8bSPavel Machek 
371f3eee542SYinghai Lu 	/* disable them all at first */
37224d9b70bSJan Beulich 	for (i = 0; i < amd_nb_bus_dev_ranges[i].dev_limit; i++) {
37355c0d721SYinghai Lu 		int bus;
37455c0d721SYinghai Lu 		int dev_base, dev_limit;
37555c0d721SYinghai Lu 
37624d9b70bSJan Beulich 		bus = amd_nb_bus_dev_ranges[i].bus;
37724d9b70bSJan Beulich 		dev_base = amd_nb_bus_dev_ranges[i].dev_base;
37824d9b70bSJan Beulich 		dev_limit = amd_nb_bus_dev_ranges[i].dev_limit;
37955c0d721SYinghai Lu 
38055c0d721SYinghai Lu 		for (slot = dev_base; slot < dev_limit; slot++) {
381eec1d4faSHans Rosenfeld 			if (!early_is_amd_nb(read_pci_config(bus, slot, 3, 0x00)))
382aaf23042SYinghai Lu 				continue;
383aaf23042SYinghai Lu 
38455c0d721SYinghai Lu 			ctl = read_pci_config(bus, slot, 3, AMD64_GARTAPERTURECTL);
38557ab43e3SBorislav Petkov 			ctl &= ~GARTEN;
38655c0d721SYinghai Lu 			write_pci_config(bus, slot, 3, AMD64_GARTAPERTURECTL, ctl);
38755c0d721SYinghai Lu 		}
388aaf23042SYinghai Lu 	}
389aaf23042SYinghai Lu 
390aaf23042SYinghai Lu }
391aaf23042SYinghai Lu 
3928c9fd91aSYinghai Lu static int __initdata printed_gart_size_msg;
3938c9fd91aSYinghai Lu 
gart_iommu_hole_init(void)39478013eaaSChristoph Hellwig void __init gart_iommu_hole_init(void)
395250c2277SThomas Gleixner {
3968c9fd91aSYinghai Lu 	u32 agp_aper_base = 0, agp_aper_order = 0;
397250c2277SThomas Gleixner 	u32 aper_size, aper_alloc = 0, aper_order = 0, last_aper_order = 0;
398250c2277SThomas Gleixner 	u64 aper_base, last_aper_base = 0;
39955c0d721SYinghai Lu 	int fix, slot, valid_agp = 0;
40055c0d721SYinghai Lu 	int i, node;
401250c2277SThomas Gleixner 
4021b457429SAravind Gopalakrishnan 	if (!amd_gart_present())
40378013eaaSChristoph Hellwig 		return;
4041b457429SAravind Gopalakrishnan 
4050440d4c0SJoerg Roedel 	if (gart_iommu_aperture_disabled || !fix_aperture ||
4060440d4c0SJoerg Roedel 	    !early_pci_allowed())
40778013eaaSChristoph Hellwig 		return;
408250c2277SThomas Gleixner 
409a5d3244aSBjorn Helgaas 	pr_info("Checking aperture...\n");
410250c2277SThomas Gleixner 
4118c9fd91aSYinghai Lu 	if (!fallback_aper_force)
4128c9fd91aSYinghai Lu 		agp_aper_base = search_agp_bridge(&agp_aper_order, &valid_agp);
4138c9fd91aSYinghai Lu 
414250c2277SThomas Gleixner 	fix = 0;
41547db4c3eSYinghai Lu 	node = 0;
41624d9b70bSJan Beulich 	for (i = 0; i < amd_nb_bus_dev_ranges[i].dev_limit; i++) {
41755c0d721SYinghai Lu 		int bus;
41855c0d721SYinghai Lu 		int dev_base, dev_limit;
4194b83873dSJoerg Roedel 		u32 ctl;
42055c0d721SYinghai Lu 
42124d9b70bSJan Beulich 		bus = amd_nb_bus_dev_ranges[i].bus;
42224d9b70bSJan Beulich 		dev_base = amd_nb_bus_dev_ranges[i].dev_base;
42324d9b70bSJan Beulich 		dev_limit = amd_nb_bus_dev_ranges[i].dev_limit;
42455c0d721SYinghai Lu 
42555c0d721SYinghai Lu 		for (slot = dev_base; slot < dev_limit; slot++) {
426eec1d4faSHans Rosenfeld 			if (!early_is_amd_nb(read_pci_config(bus, slot, 3, 0x00)))
427250c2277SThomas Gleixner 				continue;
428250c2277SThomas Gleixner 
429250c2277SThomas Gleixner 			iommu_detected = 1;
4300440d4c0SJoerg Roedel 			gart_iommu_aperture = 1;
431de957628SFUJITA Tomonori 			x86_init.iommu.iommu_init = gart_iommu_init;
432250c2277SThomas Gleixner 
4334b83873dSJoerg Roedel 			ctl = read_pci_config(bus, slot, 3,
4344b83873dSJoerg Roedel 					      AMD64_GARTAPERTURECTL);
4354b83873dSJoerg Roedel 
4364b83873dSJoerg Roedel 			/*
4374b83873dSJoerg Roedel 			 * Before we do anything else disable the GART. It may
4384b83873dSJoerg Roedel 			 * still be enabled if we boot into a crash-kernel here.
4394b83873dSJoerg Roedel 			 * Reconfiguring the GART while it is enabled could have
4404b83873dSJoerg Roedel 			 * unknown side-effects.
4414b83873dSJoerg Roedel 			 */
4424b83873dSJoerg Roedel 			ctl &= ~GARTEN;
4434b83873dSJoerg Roedel 			write_pci_config(bus, slot, 3, AMD64_GARTAPERTURECTL, ctl);
4444b83873dSJoerg Roedel 
4454b83873dSJoerg Roedel 			aper_order = (ctl >> 1) & 7;
446250c2277SThomas Gleixner 			aper_size = (32 * 1024 * 1024) << aper_order;
44755c0d721SYinghai Lu 			aper_base = read_pci_config(bus, slot, 3, AMD64_GARTAPERTUREBASE) & 0x7fff;
448250c2277SThomas Gleixner 			aper_base <<= 25;
449250c2277SThomas Gleixner 
450c96ec953SBjorn Helgaas 			pr_info("Node %d: aperture [bus addr %#010Lx-%#010Lx] (%uMB)\n",
451c96ec953SBjorn Helgaas 				node, aper_base, aper_base + aper_size - 1,
452c96ec953SBjorn Helgaas 				aper_size >> 20);
45347db4c3eSYinghai Lu 			node++;
454250c2277SThomas Gleixner 
4558c9fd91aSYinghai Lu 			if (!aperture_valid(aper_base, aper_size, 64<<20)) {
4568c9fd91aSYinghai Lu 				if (valid_agp && agp_aper_base &&
4578c9fd91aSYinghai Lu 				    agp_aper_base == aper_base &&
4588c9fd91aSYinghai Lu 				    agp_aper_order == aper_order) {
4598c9fd91aSYinghai Lu 					/* the same between two setting from NB and agp */
460c987d12fSYinghai Lu 					if (!no_iommu &&
461c987d12fSYinghai Lu 					    max_pfn > MAX_DMA32_PFN &&
462c987d12fSYinghai Lu 					    !printed_gart_size_msg) {
463c96ec953SBjorn Helgaas 						pr_err("you are using iommu with agp, but GART size is less than 64MB\n");
464a5d3244aSBjorn Helgaas 						pr_err("please increase GART size in your BIOS setup\n");
465a5d3244aSBjorn Helgaas 						pr_err("if BIOS doesn't have that option, contact your HW vendor!\n");
4668c9fd91aSYinghai Lu 						printed_gart_size_msg = 1;
4678c9fd91aSYinghai Lu 					}
4688c9fd91aSYinghai Lu 				} else {
469250c2277SThomas Gleixner 					fix = 1;
47055c0d721SYinghai Lu 					goto out;
471250c2277SThomas Gleixner 				}
4728c9fd91aSYinghai Lu 			}
473250c2277SThomas Gleixner 
474250c2277SThomas Gleixner 			if ((last_aper_order && aper_order != last_aper_order) ||
475250c2277SThomas Gleixner 			    (last_aper_base && aper_base != last_aper_base)) {
476250c2277SThomas Gleixner 				fix = 1;
47755c0d721SYinghai Lu 				goto out;
478250c2277SThomas Gleixner 			}
479250c2277SThomas Gleixner 			last_aper_order = aper_order;
480250c2277SThomas Gleixner 			last_aper_base = aper_base;
481250c2277SThomas Gleixner 		}
48255c0d721SYinghai Lu 	}
483250c2277SThomas Gleixner 
48455c0d721SYinghai Lu out:
485250c2277SThomas Gleixner 	if (!fix && !fallback_aper_force) {
4862a3e83c6SJiri Bohac 		if (last_aper_base) {
4872a3e83c6SJiri Bohac 			/*
4882a3e83c6SJiri Bohac 			 * If this is the kdump kernel, the first kernel
4892a3e83c6SJiri Bohac 			 * may have allocated the range over its e820 RAM
4902a3e83c6SJiri Bohac 			 * and fixed up the northbridge
4912a3e83c6SJiri Bohac 			 */
492ffc8599aSKairui Song 			exclude_from_core(last_aper_base, last_aper_order);
4932a3e83c6SJiri Bohac 		}
49478013eaaSChristoph Hellwig 		return;
495250c2277SThomas Gleixner 	}
496250c2277SThomas Gleixner 
4978c9fd91aSYinghai Lu 	if (!fallback_aper_force) {
4988c9fd91aSYinghai Lu 		aper_alloc = agp_aper_base;
4998c9fd91aSYinghai Lu 		aper_order = agp_aper_order;
5008c9fd91aSYinghai Lu 	}
501250c2277SThomas Gleixner 
502250c2277SThomas Gleixner 	if (aper_alloc) {
503250c2277SThomas Gleixner 		/* Got the aperture from the AGP bridge */
504c987d12fSYinghai Lu 	} else if ((!no_iommu && max_pfn > MAX_DMA32_PFN) ||
505250c2277SThomas Gleixner 		   force_iommu ||
506250c2277SThomas Gleixner 		   valid_agp ||
507250c2277SThomas Gleixner 		   fallback_aper_force) {
5081b457429SAravind Gopalakrishnan 		pr_info("Your BIOS doesn't leave an aperture memory hole\n");
509a5d3244aSBjorn Helgaas 		pr_info("Please enable the IOMMU option in the BIOS setup\n");
510a5d3244aSBjorn Helgaas 		pr_info("This costs you %dMB of RAM\n",
511250c2277SThomas Gleixner 			32 << fallback_aper_order);
512250c2277SThomas Gleixner 
513250c2277SThomas Gleixner 		aper_order = fallback_aper_order;
514250c2277SThomas Gleixner 		aper_alloc = allocate_aperture();
515250c2277SThomas Gleixner 		if (!aper_alloc) {
516c140df97SIngo Molnar 			/*
517c140df97SIngo Molnar 			 * Could disable AGP and IOMMU here, but it's
518c140df97SIngo Molnar 			 * probably not worth it. But the later users
519c140df97SIngo Molnar 			 * cannot deal with bad apertures and turning
520c140df97SIngo Molnar 			 * on the aperture over memory causes very
521c140df97SIngo Molnar 			 * strange problems, so it's better to panic
522c140df97SIngo Molnar 			 * early.
523c140df97SIngo Molnar 			 */
524250c2277SThomas Gleixner 			panic("Not enough memory for aperture");
525250c2277SThomas Gleixner 		}
526250c2277SThomas Gleixner 	} else {
52778013eaaSChristoph Hellwig 		return;
528250c2277SThomas Gleixner 	}
529250c2277SThomas Gleixner 
5302a3e83c6SJiri Bohac 	/*
5312a3e83c6SJiri Bohac 	 * If this is the kdump kernel _and_ the first kernel did not
5322a3e83c6SJiri Bohac 	 * configure the aperture in the northbridge, this range may
5332a3e83c6SJiri Bohac 	 * overlap with the first kernel's memory. We can't access the
5342a3e83c6SJiri Bohac 	 * range through vmcore even though it should be part of the dump.
5352a3e83c6SJiri Bohac 	 */
536ffc8599aSKairui Song 	exclude_from_core(aper_alloc, aper_order);
5372a3e83c6SJiri Bohac 
538250c2277SThomas Gleixner 	/* Fix up the north bridges */
53924d9b70bSJan Beulich 	for (i = 0; i < amd_nb_bus_dev_ranges[i].dev_limit; i++) {
540260133abSBorislav Petkov 		int bus, dev_base, dev_limit;
541260133abSBorislav Petkov 
542260133abSBorislav Petkov 		/*
543260133abSBorislav Petkov 		 * Don't enable translation yet but enable GART IO and CPU
544260133abSBorislav Petkov 		 * accesses and set DISTLBWALKPRB since GART table memory is UC.
545260133abSBorislav Petkov 		 */
546c34151a7SJoerg Roedel 		u32 ctl = aper_order << 1;
54755c0d721SYinghai Lu 
54824d9b70bSJan Beulich 		bus = amd_nb_bus_dev_ranges[i].bus;
54924d9b70bSJan Beulich 		dev_base = amd_nb_bus_dev_ranges[i].dev_base;
55024d9b70bSJan Beulich 		dev_limit = amd_nb_bus_dev_ranges[i].dev_limit;
55155c0d721SYinghai Lu 		for (slot = dev_base; slot < dev_limit; slot++) {
552eec1d4faSHans Rosenfeld 			if (!early_is_amd_nb(read_pci_config(bus, slot, 3, 0x00)))
553250c2277SThomas Gleixner 				continue;
554250c2277SThomas Gleixner 
555260133abSBorislav Petkov 			write_pci_config(bus, slot, 3, AMD64_GARTAPERTURECTL, ctl);
55655c0d721SYinghai Lu 			write_pci_config(bus, slot, 3, AMD64_GARTAPERTUREBASE, aper_alloc >> 25);
55755c0d721SYinghai Lu 		}
558250c2277SThomas Gleixner 	}
5596703f6d1SRafael J. Wysocki 
5606703f6d1SRafael J. Wysocki 	set_up_gart_resume(aper_order, aper_alloc);
561250c2277SThomas Gleixner }
562