xref: /openbmc/linux/arch/x86/kernel/resource.c (revision 7ae9fb1b7ecbb5d85d07857943f677fd1a559b18)
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