xref: /linux/arch/x86/kernel/resource.c (revision f68f2ff91512c199ec24883001245912afc17873)
1 // SPDX-License-Identifier: GPL-2.0
2 #include <linux/dmi.h>
3 #include <linux/ioport.h>
4 #include <asm/e820/api.h>
5 
6 static void resource_clip(struct resource *res, resource_size_t start,
7 			  resource_size_t end)
8 {
9 	resource_size_t low = 0, high = 0;
10 
11 	if (res->end < start || res->start > end)
12 		return;		/* no conflict */
13 
14 	if (res->start < start)
15 		low = start - res->start;
16 
17 	if (res->end > end)
18 		high = res->end - end;
19 
20 	/* Keep the area above or below the conflict, whichever is larger */
21 	if (low > high)
22 		res->end = start - 1;
23 	else
24 		res->start = end + 1;
25 }
26 
27 /*
28  * Some BIOS-es contain a bug where they add addresses which map to
29  * system RAM in the PCI host bridge window returned by the ACPI _CRS
30  * method, see commit 4dc2287c1805 ("x86: avoid E820 regions when
31  * allocating address space"). To avoid this Linux by default excludes
32  * E820 reservations when allocating addresses since 2010.
33  * In 2019 some systems have shown-up with E820 reservations which cover
34  * the entire _CRS returned PCI host bridge window, causing all attempts
35  * to assign memory to PCI BARs to fail if Linux uses E820 reservations.
36  *
37  * Ideally Linux would fully stop using E820 reservations, but then
38  * the old systems this was added for will regress.
39  * Instead keep the old behavior for old systems, while ignoring the
40  * E820 reservations for any systems from now on.
41  */
42 static void remove_e820_regions(struct resource *avail)
43 {
44 	int i, year = dmi_get_bios_year();
45 	struct e820_entry *entry;
46 
47 	if (year >= 2018)
48 		return;
49 
50 	pr_info_once("PCI: Removing E820 reservations from host bridge windows\n");
51 
52 	for (i = 0; i < e820_table->nr_entries; i++) {
53 		entry = &e820_table->entries[i];
54 
55 		resource_clip(avail, entry->addr,
56 			      entry->addr + entry->size - 1);
57 	}
58 }
59 
60 void arch_remove_reservations(struct resource *avail)
61 {
62 	/*
63 	 * Trim out BIOS area (high 2MB) and E820 regions. We do not remove
64 	 * the low 1MB unconditionally, as this area is needed for some ISA
65 	 * cards requiring a memory range, e.g. the i82365 PCMCIA controller.
66 	 */
67 	if (avail->flags & IORESOURCE_MEM) {
68 		resource_clip(avail, BIOS_ROM_BASE, BIOS_ROM_END);
69 
70 		remove_e820_regions(avail);
71 	}
72 }
73