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