Skip to contentSkip to conversation

x86: boot interrupt reroute fix

PATCH Superseded Stefan Assmann 2 participants 6 messages Nov 18, 2010

Subsystems (4)

v1 of 2 Superseded Latest is v2 →

lore
Share & tools
lore
#0 lore raw

cover x86: boot interrupt reroute fix

During the 2.6.29 merge parts of e1d3a90846b40ad3160bf4b648d36c6badad39ac got lost because of other ACPI changes. This patchset gets the reroute code working again with the current ACPI code. As suggested by Ingo Molnar, the boot interrupt reroute code has been split into its own file.
Therefore some smaller changes to the ACPI and PCI code are necessary to allow the boot interrupt reroute code to access required structures and functionality. In detail, the reroute code requires access to:
- struct acpi_prt_entry
- pci_find_upstream_pcie_bridge()

Additionally to not change any information in the global acpi_prt_list it is desirable to have acpi_pci_irq_find_prt_entry() return a pointer to a copy of a struct acpi_prt_entry instead of pointer into the global acpi_prt_list. The callers of acpi_pci_irq_find_prt_entry() have been updated to free the allocated structure as well.

By request of Bjorn Helgaas I've created a bugzilla entry at
https://bugzilla.kernel.org/show_bug.cgi?id=21882
to gather information about the boot interrupt reroute problem.

#1 lore raw

PATCH 1/4 ACPI: move struct acpi_prt_entry to actbl1.h

From: Stefan Assmann <[email protected]>

Moving struct acpi_prt_entry from drivers/acpi/pci_irq.c to include/acpi/actbl1.h to make it available outside of pci_irq.c. This will allow the boot interrupt reroute code, and others, to operate with acpi_prt_entrys.

---
 drivers/acpi/pci_irq.c |    8 --------
 include/acpi/actbl1.h  |   10 ++++++++++
 2 files changed, 10 insertions(+), 8 deletions(-)
drivers/acpi/pci_irq.c +0 -8
index f907cfb..3bc2164 100644
@@ -45,14 +45,6 @@
 #define _COMPONENT		ACPI_PCI_COMPONENT
 ACPI_MODULE_NAME("pci_irq");
 
-struct acpi_prt_entry {
-	struct list_head	list;
-	struct acpi_pci_id	id;
-	u8			pin;
-	acpi_handle		link;
-	u32			index;		/* GSI, or link _CRS index */
-};
-
 static LIST_HEAD(acpi_prt_list);
 static DEFINE_SPINLOCK(acpi_prt_lock);
 
include/acpi/actbl1.h +10 -0
index c637b75..bbc46ed 100644
@@ -752,6 +752,16 @@ struct acpi_madt_local_x2apic_nmi {
 	u8 reserved[3];
 };
 
+/* _PRT entry */
+
+struct acpi_prt_entry {
+	struct list_head	list;
+	struct acpi_pci_id	id;
+	u8			pin;
+	acpi_handle		link;
+	u32			index;		/* GSI, or link _CRS index */
+};
+
 /*
  * Common flags fields for MADT subtables
  */
Signature · 1 line
1.7.1
#2 lore raw

PATCH 2/4 ACPI: make acpi_pci_irq_find_prt_entry return a copy of a prt_entry

In reply to Stefan Assmann

From: Stefan Assmann <[email protected]>

By returning a pointer to a copy of struct acpi_prt_entry in acpi_pci_irq_find_prt_entry() the calling code may modify the returned structure without altering entries in the global acpi_prt_list. Thus the changes to acpi_prt_entry by the boot interrupt reroute code won't change the original PRT entries.
Currently there are only two calls for acpi_pci_irq_find_prt_entry() and both are in acpi_pci_irq_lookup(). acpi_pci_irq_lookup() itself is used only by acpi_pci_irq_enable() and acpi_pci_irq_disable() so both are also updated to free the copy of struct acpi_prt_entry appropriately.

---
 drivers/acpi/pci_irq.c |   11 +++++++++--
 1 files changed, 9 insertions(+), 2 deletions(-)
drivers/acpi/pci_irq.c +9 -2
index 3bc2164..02202a2 100644
@@ -60,7 +60,7 @@ static inline char pin_name(int pin)
 static struct acpi_prt_entry *acpi_pci_irq_find_prt_entry(struct pci_dev *dev,
 							  int pin)
 {
-	struct acpi_prt_entry *entry;
+	struct acpi_prt_entry *entry, *entry_copy;
 	int segment = pci_domain_nr(dev->bus);
 	int bus = dev->bus->number;
 	int device = PCI_SLOT(dev->devfn);
@@ -72,7 +72,11 @@ static struct acpi_prt_entry *acpi_pci_irq_find_prt_entry(struct pci_dev *dev,
 		    && (device == entry->id.device)
 		    && (pin == entry->pin)) {
 			spin_unlock(&acpi_prt_lock);
-			return entry;
+			entry_copy = kzalloc(sizeof(struct acpi_prt_entry), GFP_KERNEL);
+			if (!entry_copy)
+				return NULL;
+			memcpy(entry_copy, entry, sizeof(struct acpi_prt_entry));
+			return entry_copy;
 		}
 	}
 	spin_unlock(&acpi_prt_lock);
@@ -384,6 +388,7 @@ int acpi_pci_irq_enable(struct pci_dev *dev)
 							 &link);
 		else
 			gsi = entry->index;
+		kfree(entry);
 	} else
 		gsi = -1;
 
@@ -453,6 +458,8 @@ void acpi_pci_irq_disable(struct pci_dev *dev)
 	else
 		gsi = entry->index;
 
+	if (entry)
+		kfree(entry);
 	/*
 	 * TBD: It might be worth clearing dev->irq by magic constant
 	 * (e.g. PCI_UNDEFINED_IRQ).
Signature · 1 line
1.7.1
#3 lore raw

PATCH 3/4 PCI: fix locking for pci_find_upstream_pcie_bridge and add declaration

In reply to Stefan Assmann

From: Stefan Assmann <[email protected]>

Add header declaration of pci_find_upstream_pcie_bridge to pci.h. This will allow the boot interrupt reroute code, and others, to make use of this implementation. Also pci_find_upstream_pcie_bridge should take the pci_bus_sem semaphore while reading global PCI structures, so update the locking as well.

---
 drivers/pci/search.c |    4 ++++
 include/linux/pci.h  |    3 +++
 2 files changed, 7 insertions(+), 0 deletions(-)
drivers/pci/search.c +4 -0
index 9d75dc8..c8159b0 100644
@@ -29,6 +29,8 @@ pci_find_upstream_pcie_bridge(struct pci_dev *pdev)
 
 	if (pci_is_pcie(pdev))
 		return NULL;
+
+	down_read(&pci_bus_sem);
 	while (1) {
 		if (pci_is_root_bus(pdev->bus))
 			break;
@@ -38,6 +40,7 @@ pci_find_upstream_pcie_bridge(struct pci_dev *pdev)
 			tmp = pdev;
 			continue;
 		}
+		up_read(&pci_bus_sem);
 		/* PCI device should connect to a PCIe bridge */
 		if (pdev->pcie_type != PCI_EXP_TYPE_PCI_BRIDGE) {
 			/* Busted hardware? */
@@ -46,6 +49,7 @@ pci_find_upstream_pcie_bridge(struct pci_dev *pdev)
 		}
 		return pdev;
 	}
+	up_read(&pci_bus_sem);
 
 	return tmp;
 }
include/linux/pci.h +3 -0
index 7454408..7acb6b2 100644
@@ -698,6 +698,7 @@ int pci_bus_find_ext_capability(struct pci_bus *bus, unsigned int devfn,
 int pci_find_ht_capability(struct pci_dev *dev, int ht_cap);
 int pci_find_next_ht_capability(struct pci_dev *dev, int pos, int ht_cap);
 struct pci_bus *pci_find_next_bus(const struct pci_bus *from);
+struct pci_dev *pci_find_upstream_pcie_bridge(struct pci_dev *pdev);
 
 struct pci_dev *pci_get_device(unsigned int vendor, unsigned int device,
 				struct pci_dev *from);
@@ -1208,6 +1209,8 @@ static inline void pci_unblock_user_cfg_access(struct pci_dev *dev)
 
 static inline struct pci_bus *pci_find_next_bus(const struct pci_bus *from)
 { return NULL; }
+static inline struct pci_dev *pci_find_upstream_pcie_bridge(struct pci_dev *pdev)
+{ return NULL; }
 
 static inline struct pci_dev *pci_get_slot(struct pci_bus *bus,
 						unsigned int devfn)
Signature · 1 line
1.7.1
Acked-by on v1 3/4
#4 lore raw

Re: [PATCH 3/4] PCI: fix locking for pci_find_upstream_pcie_bridge and add declaration

Quoted 9 lines · On Thu, 18 Nov 2010 08:52:28 -0500 Stefan Assmann <[email protected]> wrote:

From: Stefan Assmann <[email protected]>

Add header declaration of pci_find_upstream_pcie_bridge to pci.h. This will allow the boot interrupt reroute code, and others, to make use of this implementation. Also pci_find_upstream_pcie_bridge should take the pci_bus_sem semaphore while reading global PCI structures, so update the locking as well.

---

You should split this into two patches just to keep things separate, but other than that it looks fine. I assume this set will go through the ACPI tree, you can add my:

Signature · 1 line
Jesse Barnes, Intel Open Source Technology Center
#5 lore raw

PATCH 4/4 PCI, ACPI: re-add boot interrupt reroute code in separate files

In reply to Stefan Assmann

From: Stefan Assmann <[email protected]>

During the 2.6.29 merge major parts of e1d3a90846b40ad3160bf4b648d36c6badad39ac got lost because of other ACPI changes. As suggested by Ingo Molnar the missing boot interrupt reroute parts are re-added in a separate file. The code has been updated to be less ifdeffy and play along with the current ACPI code. The printks have been converted to dev_info(). Also the implementation of bridge_has_boot_interrupt_variant() has been dropped in favor to the existing pci_find_upstream_pcie_bridge().

By request of Bjorn Helgaas I've created a bugzilla entry at
https://bugzilla.kernel.org/show_bug.cgi?id=21882
to gather information about the boot interrupt reroute problem.

---
 arch/x86/include/asm/boot_irq.h |   28 +++++++++++++++++
 arch/x86/kernel/apic/Makefile   |    3 ++
 arch/x86/kernel/apic/boot_irq.c |   63 +++++++++++++++++++++++++++++++++++++++
 drivers/acpi/pci_irq.c          |    4 ++
 4 files changed, 98 insertions(+), 0 deletions(-)
 create mode 100644 arch/x86/include/asm/boot_irq.h
 create mode 100644 arch/x86/kernel/apic/boot_irq.c
arch/x86/include/asm/boot_irq.h new file +28 -0
new file mode 100644
index 0000000..0cc35e1
@@ -0,0 +1,28 @@
+#ifndef _ASM_X86_BOOT_IRQ_H
+#define _ASM_X86_BOOT_IRQ_H
+
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Workaround for boot interrupts that cannot be disabled in hardware: makes
+ * affected devices always use the boot interrupt, the original interrupt line
+ * for the device remains disabled.
+ */
+
+#include <linux/pci.h>
+#ifdef CONFIG_ACPI
+#include <linux/acpi.h>
+#endif /* CONFIG_ACPI */
+
+#ifdef CONFIG_X86_IO_APIC
+#ifdef CONFIG_ACPI
+extern struct acpi_prt_entry *boot_irq_reroute (struct pci_dev *dev, struct acpi_prt_entry *entry);
+#endif /* CONFIG_ACPI */
+#else
+static inline struct acpi_prt_entry *boot_irq_reroute (struct pci_dev *dev, struct acpi_prt_entry *entry)
+	{ return entry; }
+#endif /* CONFIG_X86_IO_APIC */
+
+#endif /* _ASM_X86_BOOT_IRQ_H */
arch/x86/kernel/apic/Makefile +3 -0
index 910f20b..4603b66 100644
@@ -9,6 +9,9 @@ endif
 obj-$(CONFIG_HARDLOCKUP_DETECTOR)	+= hw_nmi.o
 
 obj-$(CONFIG_X86_IO_APIC)	+= io_apic.o
+ifeq ($(CONFIG_ACPI),y)
+obj-$(CONFIG_X86_IO_APIC)	+= boot_irq.o
+endif
 obj-$(CONFIG_SMP)		+= ipi.o
 
 ifeq ($(CONFIG_X86_64),y)
arch/x86/kernel/apic/boot_irq.c new file +63 -0

63 lines not on this page · raw message

drivers/acpi/pci_irq.c +4 -0
index e1632b2..83eb5f6 100644
@@ -39,6 +39,7 @@
 #include <linux/slab.h>
 #include <acpi/acpi_bus.h>
 #include <acpi/acpi_drivers.h>
+#include <asm/boot_irq.h>
 
 #define PREFIX "ACPI: "
 
@@ -309,6 +310,9 @@ static struct acpi_prt_entry *acpi_pci_irq_lookup(struct pci_dev *dev, int pin)
 	if (entry) {
 		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found %s[%c] _PRT entry\n",
 				  pci_name(dev), pin_name(pin)));
+		if (!noioapicquirk)
+			entry = boot_irq_reroute(dev, entry);
+
 		return entry;
 	}
 
Signature · 1 line
1.7.3.2