1 | // SPDX-License-Identifier: GPL-2.0 |
2 | #include <linux/ioport.h> |
3 | #include <linux/printk.h> |
4 | #include <asm/e820/api.h> |
5 | #include <asm/pci_x86.h> |
6 | |
7 | static void resource_clip(struct resource *res, resource_size_t start, |
8 | resource_size_t end) |
9 | { |
10 | resource_size_t low = 0, high = 0; |
11 | |
12 | if (res->end < start || res->start > end) |
13 | return; /* no conflict */ |
14 | |
15 | if (res->start < start) |
16 | low = start - res->start; |
17 | |
18 | if (res->end > end) |
19 | high = res->end - end; |
20 | |
21 | /* Keep the area above or below the conflict, whichever is larger */ |
22 | if (low > high) |
23 | res->end = start - 1; |
24 | else |
25 | res->start = end + 1; |
26 | } |
27 | |
28 | static void remove_e820_regions(struct resource *avail) |
29 | { |
30 | int i; |
31 | struct e820_entry *entry; |
32 | u64 e820_start, e820_end; |
33 | struct resource orig = *avail; |
34 | |
35 | if (!pci_use_e820) |
36 | return; |
37 | |
38 | for (i = 0; i < e820_table->nr_entries; i++) { |
39 | entry = &e820_table->entries[i]; |
40 | e820_start = entry->addr; |
41 | e820_end = entry->addr + entry->size - 1; |
42 | |
43 | resource_clip(res: avail, start: e820_start, end: e820_end); |
44 | if (orig.start != avail->start || orig.end != avail->end) { |
45 | pr_info("resource: avoiding allocation from e820 entry [mem %#010Lx-%#010Lx]\n" , |
46 | e820_start, e820_end); |
47 | if (avail->end > avail->start) |
48 | /* |
49 | * Use %pa instead of %pR because "avail" |
50 | * is typically IORESOURCE_UNSET, so %pR |
51 | * shows the size instead of addresses. |
52 | */ |
53 | pr_info("resource: remaining [mem %pa-%pa] available\n" , |
54 | &avail->start, &avail->end); |
55 | orig = *avail; |
56 | } |
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(res: avail, BIOS_ROM_BASE, BIOS_ROM_END); |
69 | |
70 | remove_e820_regions(avail); |
71 | } |
72 | } |
73 | |