// SPDX-License-Identifier: GPL-2.0 /* * Firmware replacement code. * * Work around broken BIOSes that don't set an aperture, only set the * aperture in the AGP bridge, or set too small aperture. * * If all fails map the aperture over some low memory. This is cheaper than * doing bounce buffering. The memory is lost. This is done at early boot * because only the bootmem allocator can allocate 32+MB. * * Copyright 2002 Andi Kleen, SuSE Labs. */ #define pr_fmt(fmt) … #include <linux/kernel.h> #include <linux/kcore.h> #include <linux/types.h> #include <linux/init.h> #include <linux/memblock.h> #include <linux/mmzone.h> #include <linux/pci_ids.h> #include <linux/pci.h> #include <linux/bitops.h> #include <linux/suspend.h> #include <asm/e820/api.h> #include <asm/io.h> #include <asm/iommu.h> #include <asm/gart.h> #include <asm/pci-direct.h> #include <asm/dma.h> #include <asm/amd_nb.h> #include <asm/x86_init.h> #include <linux/crash_dump.h> /* * Using 512M as goal, in case kexec will load kernel_big * that will do the on-position decompress, and could overlap with * the gart aperture that is used. * Sequence: * kernel_small * ==> kexec (with kdump trigger path or gart still enabled) * ==> kernel_small (gart area become e820_reserved) * ==> kexec (with kdump trigger path or gart still enabled) * ==> kerne_big (uncompressed size will be big than 64M or 128M) * So don't use 512M below as gart iommu, leave the space for kernel * code for safe. */ #define GART_MIN_ADDR … #define GART_MAX_ADDR … int gart_iommu_aperture; int gart_iommu_aperture_disabled __initdata; int gart_iommu_aperture_allowed __initdata; int fallback_aper_order __initdata = …; /* 64MB */ int fallback_aper_force __initdata; int fix_aperture __initdata = …; #if defined(CONFIG_PROC_VMCORE) || defined(CONFIG_PROC_KCORE) /* * If the first kernel maps the aperture over e820 RAM, the kdump kernel will * use the same range because it will remain configured in the northbridge. * Trying to dump this area via /proc/vmcore may crash the machine, so exclude * it from vmcore. */ static unsigned long aperture_pfn_start, aperture_page_count; static int gart_mem_pfn_is_ram(unsigned long pfn) { … } #ifdef CONFIG_PROC_VMCORE static bool gart_oldmem_pfn_is_ram(struct vmcore_cb *cb, unsigned long pfn) { … } static struct vmcore_cb gart_vmcore_cb = …; #endif static void __init exclude_from_core(u64 aper_base, u32 aper_order) { … } #else static void exclude_from_core(u64 aper_base, u32 aper_order) { } #endif /* This code runs before the PCI subsystem is initialized, so just access the northbridge directly. */ static u32 __init allocate_aperture(void) { … } /* Find a PCI capability */ static u32 __init find_cap(int bus, int slot, int func, int cap) { … } /* Read a standard AGPv3 bridge header */ static u32 __init read_agp(int bus, int slot, int func, int cap, u32 *order) { … } /* * Look for an AGP bridge. Windows only expects the aperture in the * AGP bridge and some BIOS forget to initialize the Northbridge too. * Work around this here. * * Do an PCI bus scan by hand because we're running before the PCI * subsystem. * * All AMD AGP bridges are AGPv3 compliant, so we can do this scan * generically. It's probably overkill to always scan all slots because * the AGP bridges should be always an own bus on the HT hierarchy, * but do it here for future safety. */ static u32 __init search_agp_bridge(u32 *order, int *valid_agp) { … } static bool gart_fix_e820 __initdata = …; static int __init parse_gart_mem(char *p) { … } early_param(…); /* * With kexec/kdump, if the first kernel doesn't shut down the GART and the * second kernel allocates a different GART region, there might be two * overlapping GART regions present: * * - the first still used by the GART initialized in the first kernel. * - (sub-)set of it used as normal RAM by the second kernel. * * which leads to memory corruptions and a kernel panic eventually. * * This can also happen if the BIOS has forgotten to mark the GART region * as reserved. * * Try to update the e820 map to mark that new region as reserved. */ void __init early_gart_iommu_check(void) { … } static int __initdata printed_gart_size_msg; void __init gart_iommu_hole_init(void) { … }