diff options
Diffstat (limited to 'arch/x86/pci/acpi.c')
-rw-r--r-- | arch/x86/pci/acpi.c | 93 |
1 files changed, 93 insertions, 0 deletions
diff --git a/arch/x86/pci/acpi.c b/arch/x86/pci/acpi.c index 052f1d78a562..a4f43054bc79 100644 --- a/arch/x86/pci/acpi.c +++ b/arch/x86/pci/acpi.c @@ -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)) |