Sophie

Sophie

distrib > Mageia > 8 > armv7hl > media > core-backports-src > by-pkgid > 86df85306f5432b2595a0b00aaebc12d > files > 135

kernel-5.16.18-1.mga8.src.rpm

From 15bc3dc111d7f1444ebce32e1a610a1ad473fc75 Mon Sep 17 00:00:00 2001
From: Hans de Goede <hdegoede@redhat.com>
Date: Thu, 14 Oct 2021 20:39:42 +0200
Subject: x86/PCI: Ignore E820 reservations for bridge windows on newer systems
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Some firmware reports invalid PCI host bridge windows via the ACPI _CRS
method; see commit 4dc2287c1805 ("x86: avoid E820 regions when allocating
address space").  To work around this bug Linux, has excluded E820 reserved
addresses from the PCI host bridge window since 2010.

But some systems have E820 reservations that cover the entire PCI bridge
memory window, so all attempts to assign memory to PCI BARs fail. For
example, from a Lenovo IdeaPad 3 15IIL 81WE:

  [mem 0x000000004bc50000-0x00000000cfffffff] reserved
  pci_bus 0000:00: root bus resource [mem 0x65400000-0xbfffffff window]
  pci 0000:00:15.0: BAR 0: failed to assign [mem size 0x00001000 64bit]
  pci 0000:00:15.1: BAR 0: failed to assign [mem size 0x00001000 64bit]
  pci 0000:00:1f.5: BAR 0: failed to assign [mem size 0x00001000]

This appears to be legal because ACPI v6.3, sec 15, table 15-374, says
AddressRangeReserved means:

  This range of addresses is in use or reserved by the system and is not to
  be included in the allocatable memory pool of the operating system's
  memory manager.
  ...
  The address range is in use by a memory-mapped system device.

Furthermore, sec 15.2 says:

  Address ranges defined for baseboard memory-mapped I/O devices, such as
  APICs, are returned as reserved.

A PCI host bridge qualifies as a baseboard memory-mapped I/O device, and
its apertures are in use and certainly should not be included in the
general allocatable pool, so the fact that the PCI aperture is "reserved"
in E820 doesn't seem like a BIOS bug.

So it seems that the excluding of E820 reserved addresses is a mistake.
Ideally Linux would fully stop excluding E820 reserved addresses, but then
the old systems that needed 4dc2287c1805 would regress.

Keep the existing behavior for old systems (BIOS year < 2018), while
ignoring the E820 reservations for newer ones.

Also add "pci=no_e820" and "pci=use_e820" kernel parameters to allow
overriding the BIOS year heuristic.

Old systems are defined here as BIOS year < 2018.  This was chosen to make
sure that pci_use_e820 will not be set on the currently affected systems,
while at the same time also taking into account that the systems for which
the E820 checking was originally added may have received BIOS updates for
quite a while (esp. CVE related ones), giving them a more recent BIOS year
than 2010.

[bhelgaas: commit log]
BugLink: https://bugzilla.kernel.org/show_bug.cgi?id=206459
BugLink: https://bugzilla.redhat.com/show_bug.cgi?id=1868899
BugLink: https://bugzilla.redhat.com/show_bug.cgi?id=1871793
BugLink: https://bugs.launchpad.net/bugs/1878279
BugLink: https://bugs.launchpad.net/bugs/1931715
BugLink: https://bugs.launchpad.net/bugs/1932069
BugLink: https://bugs.launchpad.net/bugs/1921649
Link: https://lore.kernel.org/r/20211014183943.27717-2-hdegoede@redhat.com
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Reviewed-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Acked-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Cc: stable@vger.kernel.org
Cc: Benoit Grégoire <benoitg@coeus.ca>
Cc: Hui Wang <hui.wang@canonical.com>
---
 Documentation/admin-guide/kernel-parameters.txt | 10 ++++++++++
 arch/x86/include/asm/pci_x86.h                  | 13 +++++++++++++
 arch/x86/kernel/resource.c                      |  4 ++++
 arch/x86/pci/acpi.c                             | 24 ++++++++++++++++++++++++
 arch/x86/pci/common.c                           |  6 ++++++
 5 files changed, 57 insertions(+)

diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
index 91ba391f9b328..2366949cc8b47 100644
--- a/Documentation/admin-guide/kernel-parameters.txt
+++ b/Documentation/admin-guide/kernel-parameters.txt
@@ -3949,6 +3949,16 @@
 				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
+				systems from 2018 and later.  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
diff --git a/arch/x86/include/asm/pci_x86.h b/arch/x86/include/asm/pci_x86.h
index 490411dba438d..c5413d8007edd 100644
--- a/arch/x86/include/asm/pci_x86.h
+++ b/arch/x86/include/asm/pci_x86.h
@@ -5,7 +5,10 @@
  *	(c) 1999 Martin Mares <mj@ucw.cz>
  */
 
+#include <linux/errno.h>
+#include <linux/init.h>
 #include <linux/ioport.h>
+#include <linux/spinlock.h>
 
 #undef DEBUG
 
@@ -39,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;
@@ -64,6 +69,8 @@ void pcibios_scan_specific_bus(int busn);
 
 /* pci-irq.c */
 
+struct pci_dev;
+
 struct irq_info {
 	u8 bus, devfn;			/* Bus, device and function */
 	struct {
@@ -232,3 +239,9 @@ static inline void mmio_config_writel(void __iomem *pos, u32 val)
 # define x86_default_pci_init_irq	NULL
 # define x86_default_pci_fixup_irqs	NULL
 #endif
+
+#if defined(CONFIG_PCI) && defined(CONFIG_ACPI)
+extern bool pci_use_e820;
+#else
+#define pci_use_e820 false
+#endif
diff --git a/arch/x86/kernel/resource.c b/arch/x86/kernel/resource.c
index 9b9fb7882c206..e8dc9bc327bd7 100644
--- a/arch/x86/kernel/resource.c
+++ b/arch/x86/kernel/resource.c
@@ -1,6 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0
 #include <linux/ioport.h>
 #include <asm/e820/api.h>
+#include <asm/pci_x86.h>
 
 static void resource_clip(struct resource *res, resource_size_t start,
 			  resource_size_t end)
@@ -28,6 +29,9 @@ static void remove_e820_regions(struct resource *avail)
 	int i;
 	struct e820_entry *entry;
 
+	if (!pci_use_e820)
+		return;
+
 	for (i = 0; i < e820_table->nr_entries; i++) {
 		entry = &e820_table->entries[i];
 
diff --git a/arch/x86/pci/acpi.c b/arch/x86/pci/acpi.c
index 948656069cddd..c884fafed1b5d 100644
--- a/arch/x86/pci/acpi.c
+++ b/arch/x86/pci/acpi.c
@@ -21,6 +21,8 @@ struct pci_root_info {
 
 static bool pci_use_crs = true;
 static bool pci_ignore_seg = false;
+/* Consumed in arch/x86/kernel/resource.c */
+bool pci_use_e820 = false;
 
 static int __init set_use_crs(const struct dmi_system_id *id)
 {
@@ -160,6 +162,28 @@ 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");
+
+	/*
+	 * Some firmware reports PCI host bridge windows via ACPI _CRS that
+	 * contain addresses that don't work (see 4dc2287c1805 ("x86: avoid
+	 * E820 regions when allocating address space")).
+	 *
+	 * To work around those bugs, we excluded areas reserved in the
+	 * E820 map.  But that was a poor workaround, since firmware is
+	 * allowed to report *all* host bridge windows as reserved in E820.
+	 * Exclude those E820 areas for older systems and ignore E820 for
+	 * newer ones.
+	 */
+	if (year >= 0 && year < 2018)
+		pci_use_e820 = true;
+
+	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");
 }
 
 #ifdef	CONFIG_PCI_MMCONFIG
diff --git a/arch/x86/pci/common.c b/arch/x86/pci/common.c
index 3507f456fcd09..091ec7e94fcbe 100644
--- a/arch/x86/pci/common.c
+++ b/arch/x86/pci/common.c
@@ -595,6 +595,12 @@ char *__init pcibios_setup(char *str)
 	} else if (!strcmp(str, "nocrs")) {
 		pci_probe |= PCI_ROOT_NO_CRS;
 		return NULL;
+	} else if (!strcmp(str, "use_e820")) {
+		pci_probe |= PCI_USE_E820;
+		return NULL;
+	} else if (!strcmp(str, "no_e820")) {
+		pci_probe |= PCI_NO_E820;
+		return NULL;
 #ifdef CONFIG_PHYS_ADDR_T_64BIT
 	} else if (!strcmp(str, "big_root_window")) {
 		pci_probe |= PCI_BIG_ROOT_WINDOW;
-- 
cgit 1.2.3-1.el7