1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
230919b0bSBjorn Helgaas #include <linux/ioport.h>
3a2b36ffbSHans de Goede #include <linux/printk.h>
466441bd3SIngo Molnar #include <asm/e820/api.h>
5a2b36ffbSHans de Goede #include <asm/pci_x86.h>
630919b0bSBjorn Helgaas
resource_clip(struct resource * res,resource_size_t start,resource_size_t end)74dc2287cSBjorn Helgaas static void resource_clip(struct resource *res, resource_size_t start,
84dc2287cSBjorn Helgaas resource_size_t end)
94dc2287cSBjorn Helgaas {
104dc2287cSBjorn Helgaas resource_size_t low = 0, high = 0;
114dc2287cSBjorn Helgaas
124dc2287cSBjorn Helgaas if (res->end < start || res->start > end)
134dc2287cSBjorn Helgaas return; /* no conflict */
144dc2287cSBjorn Helgaas
154dc2287cSBjorn Helgaas if (res->start < start)
164dc2287cSBjorn Helgaas low = start - res->start;
174dc2287cSBjorn Helgaas
184dc2287cSBjorn Helgaas if (res->end > end)
194dc2287cSBjorn Helgaas high = res->end - end;
204dc2287cSBjorn Helgaas
214dc2287cSBjorn Helgaas /* Keep the area above or below the conflict, whichever is larger */
224dc2287cSBjorn Helgaas if (low > high)
234dc2287cSBjorn Helgaas res->end = start - 1;
244dc2287cSBjorn Helgaas else
254dc2287cSBjorn Helgaas res->start = end + 1;
264dc2287cSBjorn Helgaas }
274dc2287cSBjorn Helgaas
remove_e820_regions(struct resource * avail)28a2b36ffbSHans de Goede static void remove_e820_regions(struct resource *avail)
294dc2287cSBjorn Helgaas {
303eb616b2SHans de Goede int i;
318ec67d97SIngo Molnar struct e820_entry *entry;
3293d256cdSBjorn Helgaas u64 e820_start, e820_end;
3331bf0f43SBjorn Helgaas struct resource orig = *avail;
344dc2287cSBjorn Helgaas
35a2b36ffbSHans de Goede if (!pci_use_e820)
364c5e242dSBjorn Helgaas return;
374c5e242dSBjorn Helgaas
38bf495573SIngo Molnar for (i = 0; i < e820_table->nr_entries; i++) {
39bf495573SIngo Molnar entry = &e820_table->entries[i];
4093d256cdSBjorn Helgaas e820_start = entry->addr;
4193d256cdSBjorn Helgaas e820_end = entry->addr + entry->size - 1;
424dc2287cSBjorn Helgaas
4393d256cdSBjorn Helgaas resource_clip(avail, e820_start, e820_end);
4431bf0f43SBjorn Helgaas if (orig.start != avail->start || orig.end != avail->end) {
45*00904bf6SBjorn Helgaas pr_info("resource: avoiding allocation from e820 entry [mem %#010Lx-%#010Lx]\n",
46*00904bf6SBjorn Helgaas e820_start, e820_end);
47*00904bf6SBjorn Helgaas if (avail->end > avail->start)
48*00904bf6SBjorn Helgaas /*
49*00904bf6SBjorn Helgaas * Use %pa instead of %pR because "avail"
50*00904bf6SBjorn Helgaas * is typically IORESOURCE_UNSET, so %pR
51*00904bf6SBjorn Helgaas * shows the size instead of addresses.
52*00904bf6SBjorn Helgaas */
53*00904bf6SBjorn Helgaas pr_info("resource: remaining [mem %pa-%pa] available\n",
54*00904bf6SBjorn Helgaas &avail->start, &avail->end);
5531bf0f43SBjorn Helgaas orig = *avail;
5631bf0f43SBjorn Helgaas }
574dc2287cSBjorn Helgaas }
584dc2287cSBjorn Helgaas }
594dc2287cSBjorn Helgaas
arch_remove_reservations(struct resource * avail)6030919b0bSBjorn Helgaas void arch_remove_reservations(struct resource *avail)
6130919b0bSBjorn Helgaas {
62cbace46aSChristoph Schulz /*
63cbace46aSChristoph Schulz * Trim out BIOS area (high 2MB) and E820 regions. We do not remove
64cbace46aSChristoph Schulz * the low 1MB unconditionally, as this area is needed for some ISA
65cbace46aSChristoph Schulz * cards requiring a memory range, e.g. the i82365 PCMCIA controller.
66cbace46aSChristoph Schulz */
67a2b36ffbSHans de Goede if (avail->flags & IORESOURCE_MEM) {
68a2c606d5SBjorn Helgaas resource_clip(avail, BIOS_ROM_BASE, BIOS_ROM_END);
69a2b36ffbSHans de Goede
70a2b36ffbSHans de Goede remove_e820_regions(avail);
71a2b36ffbSHans de Goede }
7230919b0bSBjorn Helgaas }
73