Commit f1bde278 authored by Bjorn Helgaas's avatar Bjorn Helgaas
Browse files

Merge branch 'pci/resource'

- Clip only host bridge windows for E820 regions and log what is clipped
  (Bjorn Helgaas)

- Add kernel cmdline options to use/ignore E820 reserved regions (Hans de
  Goede)

- Disable E820 reserved region clipping for IdeaPads, Yoga, Yoga Slip, Acer
  Spin 5, Clevo Barebone systems where clipping leaves no usable address
  space for touchpads, Thunderbolt devices, etc (Hans de Goede)

- Disable E820 reserved region clipping by default starting in 2023 (Hans
  de Goede)

* pci/resource:
  x86/PCI: Disable E820 reserved region clipping starting in 2023
  x86/PCI: Disable E820 reserved region clipping via quirks
  x86/PCI: Add kernel cmdline options to use/ignore E820 reserved regions
  x86/PCI: Clip only host bridge windows for E820 regions
  x86: Log resource clipping for E820 regions
  x86/PCI: Eliminate remove_e820_regions() common subexpressions
parents 6b5e9bdc 0ae084d5
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -4066,6 +4066,15 @@
				please report a bug.
		nocrs		[X86] Ignore PCI host bridge windows from ACPI.
				If you need to use this, please report a bug.
		use_e820	[X86] Use E820 reservations to exclude parts of
				PCI host bridge windows. This is a workaround
				for BIOS defects in host bridge _CRS methods.
				If you need to use this, please report a bug to
				<linux-pci@vger.kernel.org>.
		no_e820		[X86] Ignore E820 reservations for PCI host
				bridge windows. This is the default on modern
				hardware. If you need to use this, please report
				a bug to <linux-pci@vger.kernel.org>.
		routeirq	Do IRQ routing for all PCI devices.
				This is normally done in pci_enable_device(),
				so this option is a temporary workaround
+5 −0
Original line number Diff line number Diff line
@@ -4,6 +4,9 @@

#include <asm/e820/types.h>

struct device;
struct resource;

extern struct e820_table *e820_table;
extern struct e820_table *e820_table_kexec;
extern struct e820_table *e820_table_firmware;
@@ -43,6 +46,8 @@ extern void e820__register_nosave_regions(unsigned long limit_pfn);

extern int  e820__get_entry_type(u64 start, u64 end);

extern void remove_e820_regions(struct device *dev, struct resource *avail);

/*
 * Returns true iff the specified range [start,end) is completely contained inside
 * the ISA region.
+2 −0
Original line number Diff line number Diff line
@@ -42,6 +42,8 @@ do { \
#define PCI_ROOT_NO_CRS		0x100000
#define PCI_NOASSIGN_BARS	0x200000
#define PCI_BIG_ROOT_WINDOW	0x400000
#define PCI_USE_E820		0x800000
#define PCI_NO_E820		0x1000000

extern unsigned int pci_probe;
extern unsigned long pirq_table_addr;
+17 −8
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0
#include <linux/dev_printk.h>
#include <linux/ioport.h>
#include <asm/e820/api.h>

@@ -23,16 +24,27 @@ static void resource_clip(struct resource *res, resource_size_t start,
		res->start = end + 1;
}

static void remove_e820_regions(struct resource *avail)
void remove_e820_regions(struct device *dev, struct resource *avail)
{
	int i;
	struct e820_entry *entry;
	u64 e820_start, e820_end;
	struct resource orig = *avail;

	if (!(avail->flags & IORESOURCE_MEM))
		return;

	for (i = 0; i < e820_table->nr_entries; i++) {
		entry = &e820_table->entries[i];

		resource_clip(avail, entry->addr,
			      entry->addr + entry->size - 1);
		e820_start = entry->addr;
		e820_end = entry->addr + entry->size - 1;

		resource_clip(avail, e820_start, e820_end);
		if (orig.start != avail->start || orig.end != avail->end) {
			dev_info(dev, "clipped %pR to %pR for e820 entry [mem %#010Lx-%#010Lx]\n",
				 &orig, avail, e820_start, e820_end);
			orig = *avail;
		}
	}
}

@@ -43,9 +55,6 @@ void arch_remove_reservations(struct resource *avail)
	 * the low 1MB unconditionally, as this area is needed for some ISA
	 * cards requiring a memory range, e.g. the i82365 PCMCIA controller.
	 */
	if (avail->flags & IORESOURCE_MEM) {
	if (avail->flags & IORESOURCE_MEM)
		resource_clip(avail, BIOS_ROM_BASE, BIOS_ROM_END);

		remove_e820_regions(avail);
	}
}
+93 −0
Original line number Diff line number Diff line
@@ -8,6 +8,7 @@
#include <linux/pci-acpi.h>
#include <asm/numa.h>
#include <asm/pci_x86.h>
#include <asm/e820/api.h>

struct pci_root_info {
	struct acpi_pci_root_info common;
@@ -19,6 +20,7 @@ struct pci_root_info {
#endif
};

static bool pci_use_e820 = true;
static bool pci_use_crs = true;
static bool pci_ignore_seg;

@@ -41,6 +43,14 @@ static int __init set_ignore_seg(const struct dmi_system_id *id)
	return 0;
}

static int __init set_no_e820(const struct dmi_system_id *id)
{
	printk(KERN_INFO "PCI: %s detected: not clipping E820 regions from _CRS\n",
	       id->ident);
	pci_use_e820 = false;
	return 0;
}

static const struct dmi_system_id pci_crs_quirks[] __initconst = {
	/* http://bugzilla.kernel.org/show_bug.cgi?id=14183 */
	{
@@ -135,6 +145,51 @@ static const struct dmi_system_id pci_crs_quirks[] __initconst = {
			DMI_MATCH(DMI_PRODUCT_NAME, "HP xw9300 Workstation"),
		},
	},

	/*
	 * Many Lenovo models with "IIL" in their DMI_PRODUCT_VERSION have
	 * an E820 reserved region that covers the entire 32-bit host
	 * bridge memory window from _CRS.  Using the E820 region to clip
	 * _CRS means no space is available for hot-added or uninitialized
	 * PCI devices.  This typically breaks I2C controllers for touchpads
	 * and hot-added Thunderbolt devices.  See the commit log for
	 * models known to require this quirk and related bug reports.
	 */
	{
		.callback = set_no_e820,
		.ident = "Lenovo *IIL* product version",
		.matches = {
			DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
			DMI_MATCH(DMI_PRODUCT_VERSION, "IIL"),
		},
	},

	/*
	 * The Acer Spin 5 (SP513-54N) has the same E820 reservation covering
	 * the entire _CRS 32-bit window issue as the Lenovo *IIL* models.
	 * See https://bugs.launchpad.net/bugs/1884232
	 */
	{
		.callback = set_no_e820,
		.ident = "Acer Spin 5 (SP513-54N)",
		.matches = {
			DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
			DMI_MATCH(DMI_PRODUCT_NAME, "Spin SP513-54N"),
		},
	},

	/*
	 * Clevo X170KM-G barebones have the same E820 reservation covering
	 * the entire _CRS 32-bit window issue as the Lenovo *IIL* models.
	 * See https://bugzilla.kernel.org/show_bug.cgi?id=214259
	 */
	{
		.callback = set_no_e820,
		.ident = "Clevo X170KM-G Barebone",
		.matches = {
			DMI_MATCH(DMI_BOARD_NAME, "X170KM-G"),
		},
	},
	{}
};

@@ -145,6 +200,27 @@ void __init pci_acpi_crs_quirks(void)
	if (year >= 0 && year < 2008 && iomem_resource.end <= 0xffffffff)
		pci_use_crs = false;

	/*
	 * Some firmware includes unusable space (host bridge registers,
	 * hidden PCI device BARs, etc) in PCI host bridge _CRS.  This is a
	 * firmware defect, and 4dc2287c1805 ("x86: avoid E820 regions when
	 * allocating address space") has clipped out the unusable space in
	 * the past.
	 *
	 * But other firmware supplies E820 reserved regions that cover
	 * entire _CRS windows, so clipping throws away the entire window,
	 * leaving none for hot-added or uninitialized devices.  These E820
	 * entries are probably *not* a firmware defect, so disable the
	 * clipping by default for post-2022 machines.
	 *
	 * We already have quirks to disable clipping for pre-2023
	 * machines, and we'll likely need quirks to *enable* clipping for
	 * post-2022 machines that incorrectly include unusable space in
	 * _CRS.
	 */
	if (year >= 2023)
		pci_use_e820 = false;

	dmi_check_system(pci_crs_quirks);

	/*
@@ -160,6 +236,17 @@ void __init pci_acpi_crs_quirks(void)
	       "if necessary, use \"pci=%s\" and report a bug\n",
	       pci_use_crs ? "Using" : "Ignoring",
	       pci_use_crs ? "nocrs" : "use_crs");

	/* "pci=use_e820"/"pci=no_e820" on the kernel cmdline takes precedence */
	if (pci_probe & PCI_NO_E820)
		pci_use_e820 = false;
	else if (pci_probe & PCI_USE_E820)
		pci_use_e820 = true;

	printk(KERN_INFO "PCI: %s E820 reservations for host bridge windows\n",
	       pci_use_e820 ? "Using" : "Ignoring");
	if (pci_probe & (PCI_NO_E820 | PCI_USE_E820))
		printk(KERN_INFO "PCI: Please notify linux-pci@vger.kernel.org so future kernels can this automatically\n");
}

#ifdef	CONFIG_PCI_MMCONFIG
@@ -299,6 +386,12 @@ static int pci_acpi_root_prepare_resources(struct acpi_pci_root_info *ci)
	int status;

	status = acpi_pci_probe_root_resources(ci);

	if (pci_use_e820) {
		resource_list_for_each_entry(entry, &ci->resources)
			remove_e820_regions(&device->dev, entry->res);
	}

	if (pci_use_crs) {
		resource_list_for_each_entry_safe(entry, tmp, &ci->resources)
			if (resource_is_pcicfg_ioport(entry->res))
Loading