All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v4 0/5] x86/PCI: Improve $PIR and add $IRT PIRQ routing support
@ 2022-03-31  7:10 Maciej W. Rozycki
  2022-03-31  7:10 ` [PATCH v4 1/5] x86/PCI: Add PIRQ routing table range checks Maciej W. Rozycki
                   ` (4 more replies)
  0 siblings, 5 replies; 12+ messages in thread
From: Maciej W. Rozycki @ 2022-03-31  7:10 UTC (permalink / raw)
  To: Bjorn Helgaas, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
	H. Peter Anvin
  Cc: Arnd Bergmann, Nikolai Zhubr, Michal Necasek, Dmitry Osipenko,
	Linus Torvalds, x86, linux-pci, linux-kernel

Hi,

 This is an updated patch series with a fix applied to what is now 3/5 for 
a bug that was reported by Dmitry (thanks!) having triggered with his 
x86-64 setup and then nailed down by Linus (also thanks!).  Additionally 
as suggested by Linus a fix has been added, for a preexisting problem with 
the routing table not being verified to stay whole within the BIOS memory 
range, that has become 1/5, expanding the whole series from 4 to 5 changes 
now.  In the course of that addition a couple of coding style issues have 
been consumed, shrinking what has now become 5/5.  The cover letter has 
been updated accordingly throughout.

 First 1/5 handles $PIR PIRQ routing tables that lack router device
information, fixing the inability to route interrupts with a system using 
the SiS85C497 ISA bridge.

 Then 2/5 adds support for the $IRT PIRQ routing table format invented by 
AMI before Microsoft has come up with its own $PIR format.  These formats 
are very similar to each other, but the $IRT format does not provide for 
router device information, so this change relies on 1/5.  It has turned 
out needed to route interrupts with a system using the ALi M1487 ISA Bus 
Controller device, discussed earlier on in a discussion thread around: 
<https://lore.kernel.org/linux-pci/61377A45.8030003@gmail.com/>.  This 
change has been verified with an artificially created $IRT table.

 Then 3/5 adds a range check for 

 Then 3/4 corrects our link value interpretation for said M1487 device 
according to Nikolai's findings with his system reported here: 
<https://lore.kernel.org/linux-pci/61428EDF.9030203@gmail.com/>.

 Finally 4/4 corrects a couple of coding style issues around though not 
immediately within code changed by 2/4 so as to make the style consistent.

 See individual change descriptions for further details.

 Credit to Michal (cc-ed) for helping me chase documentation for the
$IRT table format.

 Please apply.

  Maciej

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH v4 1/5] x86/PCI: Add PIRQ routing table range checks
  2022-03-31  7:10 [PATCH v4 0/5] x86/PCI: Improve $PIR and add $IRT PIRQ routing support Maciej W. Rozycki
@ 2022-03-31  7:10 ` Maciej W. Rozycki
  2022-04-10 10:54   ` [tip: x86/irq] " tip-bot2 for Maciej W. Rozycki
  2022-03-31  7:11 ` [PATCH v4 2/5] x86/PCI: Handle PIRQ routing tables with no router device given Maciej W. Rozycki
                   ` (3 subsequent siblings)
  4 siblings, 1 reply; 12+ messages in thread
From: Maciej W. Rozycki @ 2022-03-31  7:10 UTC (permalink / raw)
  To: Bjorn Helgaas, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
	H. Peter Anvin
  Cc: Arnd Bergmann, Nikolai Zhubr, Michal Necasek, Dmitry Osipenko,
	Linus Torvalds, x86, linux-pci, linux-kernel

Verify that the PCI IRQ Routing Table header as well as individual slot 
entries are all wholly contained within the BIOS memory area.  Do not 
even call the checksum calculator if the header would overrun the area 
and then bail out early if any slot would.

Signed-off-by: Maciej W. Rozycki <macro@orcam.me.uk>
---
New change in v4.
---
 arch/x86/pci/irq.c |   17 ++++++++++++-----
 1 file changed, 12 insertions(+), 5 deletions(-)

linux-x86-pirq-range-check.diff
Index: linux-macro/arch/x86/pci/irq.c
===================================================================
--- linux-macro.orig/arch/x86/pci/irq.c
+++ linux-macro/arch/x86/pci/irq.c
@@ -68,7 +68,8 @@ void (*pcibios_disable_irq)(struct pci_d
  *  and perform checksum verification.
  */
 
-static inline struct irq_routing_table *pirq_check_routing_table(u8 *addr)
+static inline struct irq_routing_table *pirq_check_routing_table(u8 *addr,
+								 u8 *limit)
 {
 	struct irq_routing_table *rt;
 	int i;
@@ -78,7 +79,8 @@ static inline struct irq_routing_table *
 	if (rt->signature != PIRQ_SIGNATURE ||
 	    rt->version != PIRQ_VERSION ||
 	    rt->size % 16 ||
-	    rt->size < sizeof(struct irq_routing_table))
+	    rt->size < sizeof(struct irq_routing_table) ||
+	    (limit && rt->size > limit - addr))
 		return NULL;
 	sum = 0;
 	for (i = 0; i < rt->size; i++)
@@ -99,17 +101,22 @@ static inline struct irq_routing_table *
 
 static struct irq_routing_table * __init pirq_find_routing_table(void)
 {
+	u8 * const bios_start = (u8 *)__va(0xf0000);
+	u8 * const bios_end = (u8 *)__va(0x100000);
 	u8 *addr;
 	struct irq_routing_table *rt;
 
 	if (pirq_table_addr) {
-		rt = pirq_check_routing_table((u8 *) __va(pirq_table_addr));
+		rt = pirq_check_routing_table((u8 *)__va(pirq_table_addr),
+					      NULL);
 		if (rt)
 			return rt;
 		printk(KERN_WARNING "PCI: PIRQ table NOT found at pirqaddr\n");
 	}
-	for (addr = (u8 *) __va(0xf0000); addr < (u8 *) __va(0x100000); addr += 16) {
-		rt = pirq_check_routing_table(addr);
+	for (addr = bios_start;
+	     addr < bios_end - sizeof(struct irq_routing_table);
+	     addr += 16) {
+		rt = pirq_check_routing_table(addr, bios_end);
 		if (rt)
 			return rt;
 	}

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH v4 2/5] x86/PCI: Handle PIRQ routing tables with no router device given
  2022-03-31  7:10 [PATCH v4 0/5] x86/PCI: Improve $PIR and add $IRT PIRQ routing support Maciej W. Rozycki
  2022-03-31  7:10 ` [PATCH v4 1/5] x86/PCI: Add PIRQ routing table range checks Maciej W. Rozycki
@ 2022-03-31  7:11 ` Maciej W. Rozycki
  2022-04-10 10:54   ` [tip: x86/irq] " tip-bot2 for Maciej W. Rozycki
  2022-03-31  7:11 ` [PATCH v4 3/5] x86/PCI: Add $IRT PIRQ routing table support Maciej W. Rozycki
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 12+ messages in thread
From: Maciej W. Rozycki @ 2022-03-31  7:11 UTC (permalink / raw)
  To: Bjorn Helgaas, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
	H. Peter Anvin
  Cc: Arnd Bergmann, Nikolai Zhubr, Michal Necasek, Dmitry Osipenko,
	Linus Torvalds, x86, linux-pci, linux-kernel

PIRQ routing tables provided by the PCI BIOS usually specify the PCI 
vendor:device ID as well as the bus address of the device implementing 
the PIRQ router, e.g.:

PCI: Interrupt Routing Table found at 0xc00fde10
[...]
PCI: Attempting to find IRQ router for [8086:7000]
pci 0000:00:07.0: PIIX/ICH IRQ router [8086:7000]

however in some cases they do not, in which case we fail to match the 
router handler, e.g.:

PCI: Interrupt Routing Table found at 0xc00fdae0
[...]
PCI: Attempting to find IRQ router for [0000:0000]
PCI: Interrupt router not found at 00:00

This is because we always match the vendor:device ID and the bus address 
literally, even if they are all zeros.

Handle this case then and iterate over all PCI devices until we find a 
matching router handler if the vendor ID given by the routing table is 
the invalid value of zero:

PCI: Attempting to find IRQ router for [0000:0000]
PCI: Trying IRQ router for [1039:0496]
pci 0000:00:05.0: SiS85C497 IRQ router [1039:0496]

Signed-off-by: Maciej W. Rozycki <macro@orcam.me.uk>
Tested-by: Nikolai Zhubr <zhubr.2@gmail.com>
---
No change from v3.

Changes from v2:

- Document new output in the change description.

- Add Nikolai's Tested-by annotation.

Changes from v1:

- Preinitialise `dev' in `pirq_find_router' for `for_each_pci_dev'.

- Avoid calling `pirq_try_router' with null `dev'.
---
 arch/x86/pci/irq.c |   64 ++++++++++++++++++++++++++++++++++++-----------------
 1 file changed, 44 insertions(+), 20 deletions(-)

linux-x86-pirq-router-nodev.diff
Index: linux-macro/arch/x86/pci/irq.c
===================================================================
--- linux-macro.orig/arch/x86/pci/irq.c
+++ linux-macro/arch/x86/pci/irq.c
@@ -1182,10 +1182,32 @@ static struct pci_dev *pirq_router_dev;
  *	chipset" ?
  */
 
+static bool __init pirq_try_router(struct irq_router *r,
+				   struct irq_routing_table *rt,
+				   struct pci_dev *dev)
+{
+	struct irq_router_handler *h;
+
+	DBG(KERN_DEBUG "PCI: Trying IRQ router for [%04x:%04x]\n",
+	    dev->vendor, dev->device);
+
+	for (h = pirq_routers; h->vendor; h++) {
+		/* First look for a router match */
+		if (rt->rtr_vendor == h->vendor &&
+		    h->probe(r, dev, rt->rtr_device))
+			return true;
+		/* Fall back to a device match */
+		if (dev->vendor == h->vendor &&
+		    h->probe(r, dev, dev->device))
+			return true;
+	}
+	return false;
+}
+
 static void __init pirq_find_router(struct irq_router *r)
 {
 	struct irq_routing_table *rt = pirq_table;
-	struct irq_router_handler *h;
+	struct pci_dev *dev;
 
 #ifdef CONFIG_PCI_BIOS
 	if (!rt->signature) {
@@ -1204,27 +1226,29 @@ static void __init pirq_find_router(stru
 	DBG(KERN_DEBUG "PCI: Attempting to find IRQ router for [%04x:%04x]\n",
 	    rt->rtr_vendor, rt->rtr_device);
 
-	pirq_router_dev = pci_get_domain_bus_and_slot(0, rt->rtr_bus,
-						      rt->rtr_devfn);
-	if (!pirq_router_dev) {
-		DBG(KERN_DEBUG "PCI: Interrupt router not found at "
-			"%02x:%02x\n", rt->rtr_bus, rt->rtr_devfn);
-		return;
+	/* Use any vendor:device provided by the routing table or try all.  */
+	if (rt->rtr_vendor) {
+		dev = pci_get_domain_bus_and_slot(0, rt->rtr_bus,
+						  rt->rtr_devfn);
+		if (dev && pirq_try_router(r, rt, dev))
+			pirq_router_dev = dev;
+	} else {
+		dev = NULL;
+		for_each_pci_dev(dev) {
+			if (pirq_try_router(r, rt, dev)) {
+				pirq_router_dev = dev;
+				break;
+			}
+		}
 	}
 
-	for (h = pirq_routers; h->vendor; h++) {
-		/* First look for a router match */
-		if (rt->rtr_vendor == h->vendor &&
-			h->probe(r, pirq_router_dev, rt->rtr_device))
-			break;
-		/* Fall back to a device match */
-		if (pirq_router_dev->vendor == h->vendor &&
-			h->probe(r, pirq_router_dev, pirq_router_dev->device))
-			break;
-	}
-	dev_info(&pirq_router_dev->dev, "%s IRQ router [%04x:%04x]\n",
-		 pirq_router.name,
-		 pirq_router_dev->vendor, pirq_router_dev->device);
+	if (pirq_router_dev)
+		dev_info(&pirq_router_dev->dev, "%s IRQ router [%04x:%04x]\n",
+			 pirq_router.name,
+			 pirq_router_dev->vendor, pirq_router_dev->device);
+	else
+		DBG(KERN_DEBUG "PCI: Interrupt router not found at "
+		    "%02x:%02x\n", rt->rtr_bus, rt->rtr_devfn);
 
 	/* The device remains referenced for the kernel lifetime */
 }

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH v4 3/5] x86/PCI: Add $IRT PIRQ routing table support
  2022-03-31  7:10 [PATCH v4 0/5] x86/PCI: Improve $PIR and add $IRT PIRQ routing support Maciej W. Rozycki
  2022-03-31  7:10 ` [PATCH v4 1/5] x86/PCI: Add PIRQ routing table range checks Maciej W. Rozycki
  2022-03-31  7:11 ` [PATCH v4 2/5] x86/PCI: Handle PIRQ routing tables with no router device given Maciej W. Rozycki
@ 2022-03-31  7:11 ` Maciej W. Rozycki
  2022-03-31 20:57   ` Dmitry Osipenko
  2022-04-10 10:54   ` [tip: x86/irq] " tip-bot2 for Maciej W. Rozycki
  2022-03-31  7:11 ` [PATCH v4 4/5] x86/PCI: Fix ALi M1487 (IBC) PIRQ router link value interpretation Maciej W. Rozycki
  2022-03-31  7:11 ` [PATCH v4 5/5] x86/PCI: Fix coding style in PIRQ table verification Maciej W. Rozycki
  4 siblings, 2 replies; 12+ messages in thread
From: Maciej W. Rozycki @ 2022-03-31  7:11 UTC (permalink / raw)
  To: Bjorn Helgaas, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
	H. Peter Anvin
  Cc: Arnd Bergmann, Nikolai Zhubr, Michal Necasek, Dmitry Osipenko,
	Linus Torvalds, x86, linux-pci, linux-kernel

Handle the $IRT PCI IRQ Routing Table format used by AMI for its BCP 
(BIOS Configuration Program) external tool meant for tweaking BIOS 
structures without the need to rebuild it from sources[1].

The $IRT format has been invented by AMI before Microsoft has come up 
with its $PIR format and a $IRT table is therefore there in some systems 
that lack a $PIR table, such as the DataExpert EXP8449 mainboard based 
on the ALi FinALi 486 chipset (M1489/M1487), which predates DMI 2.0 and 
cannot therefore be easily identified at run time.

Unlike with the $PIR format there is no alignment guarantee as to the 
placement of the $IRT table, so scan the whole BIOS area bytewise.

Credit to Michal Necasek for helping me chase documentation for the 
format.

References:

[1] "What is BCP? - AMI", <https://www.ami.com/what-is-bcp/>

Signed-off-by: Maciej W. Rozycki <macro@orcam.me.uk>
Cc: Michal Necasek <mnecasek@yahoo.com>
---
Changes from v3:

- Correct the BIOS memory scan such as to verify that the PCI IRQ Routing
  Table header as well as individual slot entries are all wholly contained 
  within the BIOS memory area.

- Following commit 5224f7909617 ("treewide: Replace zero-length arrays 
  with flexible-array members") also make `slots' in `irt_routing_table' a 
  flexible-array member.

New change in v3.
---
 arch/x86/include/asm/pci_x86.h |    9 ++++
 arch/x86/pci/irq.c             |   76 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 85 insertions(+)

linux-x86-pirq-irt.diff
Index: linux-macro/arch/x86/include/asm/pci_x86.h
===================================================================
--- linux-macro.orig/arch/x86/include/asm/pci_x86.h
+++ linux-macro/arch/x86/include/asm/pci_x86.h
@@ -93,6 +93,15 @@ struct irq_routing_table {
 	struct irq_info slots[];
 } __attribute__((packed));
 
+struct irt_routing_table {
+	u32 signature;			/* IRT_SIGNATURE should be here */
+	u8 size;			/* Number of entries provided */
+	u8 used;			/* Number of entries actually used */
+	u16 exclusive_irqs;		/* IRQs devoted exclusively to
+					   PCI usage */
+	struct irq_info slots[];
+} __attribute__((packed));
+
 extern unsigned int pcibios_irq_mask;
 
 extern raw_spinlock_t pci_config_lock;
Index: linux-macro/arch/x86/pci/irq.c
===================================================================
--- linux-macro.orig/arch/x86/pci/irq.c
+++ linux-macro/arch/x86/pci/irq.c
@@ -25,6 +25,8 @@
 #define PIRQ_SIGNATURE	(('$' << 0) + ('P' << 8) + ('I' << 16) + ('R' << 24))
 #define PIRQ_VERSION 0x0100
 
+#define IRT_SIGNATURE	(('$' << 0) + ('I' << 8) + ('R' << 16) + ('T' << 24))
+
 static int broken_hp_bios_irq9;
 static int acer_tm360_irqrouting;
 
@@ -93,7 +95,74 @@ static inline struct irq_routing_table *
 	return NULL;
 }
 
+/*
+ * Handle the $IRT PCI IRQ Routing Table format used by AMI for its BCP
+ * (BIOS Configuration Program) external tool meant for tweaking BIOS
+ * structures without the need to rebuild it from sources.  The $IRT
+ * format has been invented by AMI before Microsoft has come up with its
+ * $PIR format and a $IRT table is therefore there in some systems that
+ * lack a $PIR table.
+ *
+ * It uses the same PCI BIOS 2.1 format for interrupt routing entries
+ * themselves but has a different simpler header prepended instead,
+ * occupying 8 bytes, where a `$IRT' signature is followed by one byte
+ * specifying the total number of interrupt routing entries allocated in
+ * the table, then one byte specifying the actual number of entries used
+ * (which the BCP tool can take advantage of when modifying the table),
+ * and finally a 16-bit word giving the IRQs devoted exclusively to PCI.
+ * Unlike with the $PIR table there is no alignment guarantee.
+ *
+ * Given the similarity of the two formats the $IRT one is trivial to
+ * convert to the $PIR one, which we do here, except that obviously we
+ * have no information as to the router device to use, but we can handle
+ * it by matching PCI device IDs actually seen on the bus against ones
+ * that our individual routers recognise.
+ *
+ * Reportedly there is another $IRT table format where a 16-bit word
+ * follows the header instead that points to interrupt routing entries
+ * in a $PIR table provided elsewhere.  In that case this code will not
+ * be reached though as the $PIR table will have been chosen instead.
+ */
+static inline struct irq_routing_table *pirq_convert_irt_table(u8 *addr,
+							       u8 *limit)
+{
+	struct irt_routing_table *ir;
+	struct irq_routing_table *rt;
+	u16 size;
+	u8 sum;
+	int i;
+
+	ir = (struct irt_routing_table *)addr;
+	if (ir->signature != IRT_SIGNATURE || !ir->used || ir->size < ir->used)
+		return NULL;
+
+	size = sizeof(*ir) + ir->used * sizeof(ir->slots[0]);
+	if (size > limit - addr)
+		return NULL;
+
+	DBG(KERN_DEBUG "PCI: $IRT Interrupt Routing Table found at 0x%lx\n",
+	    __pa(ir));
+
+	size = sizeof(*rt) + ir->used * sizeof(rt->slots[0]);
+	rt = kzalloc(size, GFP_KERNEL);
+	if (!rt)
+		return NULL;
+
+	rt->signature = PIRQ_SIGNATURE;
+	rt->version = PIRQ_VERSION;
+	rt->size = size;
+	rt->exclusive_irqs = ir->exclusive_irqs;
+	for (i = 0; i < ir->used; i++)
+		rt->slots[i] = ir->slots[i];
+
+	addr = (u8 *)rt;
+	sum = 0;
+	for (i = 0; i < size; i++)
+		sum += addr[i];
+	rt->checksum = -sum;
 
+	return rt;
+}
 
 /*
  *  Search 0xf0000 -- 0xfffff for the PCI IRQ Routing Table.
@@ -120,6 +189,13 @@ static struct irq_routing_table * __init
 		if (rt)
 			return rt;
 	}
+	for (addr = bios_start;
+	     addr < bios_end - sizeof(struct irt_routing_table);
+	     addr++) {
+		rt = pirq_convert_irt_table(addr, bios_end);
+		if (rt)
+			return rt;
+	}
 	return NULL;
 }
 

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH v4 4/5] x86/PCI: Fix ALi M1487 (IBC) PIRQ router link value interpretation
  2022-03-31  7:10 [PATCH v4 0/5] x86/PCI: Improve $PIR and add $IRT PIRQ routing support Maciej W. Rozycki
                   ` (2 preceding siblings ...)
  2022-03-31  7:11 ` [PATCH v4 3/5] x86/PCI: Add $IRT PIRQ routing table support Maciej W. Rozycki
@ 2022-03-31  7:11 ` Maciej W. Rozycki
  2022-04-10 10:54   ` [tip: x86/irq] " tip-bot2 for Maciej W. Rozycki
  2022-03-31  7:11 ` [PATCH v4 5/5] x86/PCI: Fix coding style in PIRQ table verification Maciej W. Rozycki
  4 siblings, 1 reply; 12+ messages in thread
From: Maciej W. Rozycki @ 2022-03-31  7:11 UTC (permalink / raw)
  To: Bjorn Helgaas, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
	H. Peter Anvin
  Cc: Arnd Bergmann, Nikolai Zhubr, Michal Necasek, Dmitry Osipenko,
	Linus Torvalds, x86, linux-pci, linux-kernel

Fix an issue with commit 1ce849c75534 ("x86/PCI: Add support for the ALi 
M1487 (IBC) PIRQ router") and correct ALi M1487 (IBC) PIRQ router link 
value (`pirq' cookie) interpretation according to findings in the BIOS.

Credit to Nikolai Zhubr for the detective work as to the bit layout.

Signed-off-by: Maciej W. Rozycki <macro@orcam.me.uk>
Cc: Nikolai Zhubr <zhubr.2@gmail.com>
Fixes: 1ce849c75534 ("x86/PCI: Add support for the ALi M1487 (IBC) PIRQ router")
Cc: stable@vger.kernel.org # v5.15+
---
No change from v3.

New change in v3.
---
 arch/x86/pci/irq.c |   19 ++++++++++++++++---
 1 file changed, 16 insertions(+), 3 deletions(-)

linux-x86-pirq-router-finali-link.diff
Index: linux-macro/arch/x86/pci/irq.c
===================================================================
--- linux-macro.orig/arch/x86/pci/irq.c
+++ linux-macro/arch/x86/pci/irq.c
@@ -337,6 +337,15 @@ static void write_pc_conf_nybble(u8 base
 	pc_conf_set(reg, x);
 }
 
+/*
+ * FinALi pirq rules are as follows:
+ *
+ * - bit 0 selects between INTx Routing Table Mapping Registers,
+ *
+ * - bit 3 selects the nibble within the INTx Routing Table Mapping Register,
+ *
+ * - bits 7:4 map to bits 3:0 of the PCI INTx Sensitivity Register.
+ */
 static int pirq_finali_get(struct pci_dev *router, struct pci_dev *dev,
 			   int pirq)
 {
@@ -344,11 +353,13 @@ static int pirq_finali_get(struct pci_de
 		0, 9, 3, 10, 4, 5, 7, 6, 0, 11, 0, 12, 0, 14, 0, 15
 	};
 	unsigned long flags;
+	u8 index;
 	u8 x;
 
+	index = (pirq & 1) << 1 | (pirq & 8) >> 3;
 	raw_spin_lock_irqsave(&pc_conf_lock, flags);
 	pc_conf_set(PC_CONF_FINALI_LOCK, PC_CONF_FINALI_LOCK_KEY);
-	x = irqmap[read_pc_conf_nybble(PC_CONF_FINALI_PCI_INTX_RT1, pirq - 1)];
+	x = irqmap[read_pc_conf_nybble(PC_CONF_FINALI_PCI_INTX_RT1, index)];
 	pc_conf_set(PC_CONF_FINALI_LOCK, 0);
 	raw_spin_unlock_irqrestore(&pc_conf_lock, flags);
 	return x;
@@ -362,13 +373,15 @@ static int pirq_finali_set(struct pci_de
 	};
 	u8 val = irqmap[irq];
 	unsigned long flags;
+	u8 index;
 
 	if (!val)
 		return 0;
 
+	index = (pirq & 1) << 1 | (pirq & 8) >> 3;
 	raw_spin_lock_irqsave(&pc_conf_lock, flags);
 	pc_conf_set(PC_CONF_FINALI_LOCK, PC_CONF_FINALI_LOCK_KEY);
-	write_pc_conf_nybble(PC_CONF_FINALI_PCI_INTX_RT1, pirq - 1, val);
+	write_pc_conf_nybble(PC_CONF_FINALI_PCI_INTX_RT1, index, val);
 	pc_conf_set(PC_CONF_FINALI_LOCK, 0);
 	raw_spin_unlock_irqrestore(&pc_conf_lock, flags);
 	return 1;
@@ -377,7 +390,7 @@ static int pirq_finali_set(struct pci_de
 static int pirq_finali_lvl(struct pci_dev *router, struct pci_dev *dev,
 			   int pirq, int irq)
 {
-	u8 mask = ~(1u << (pirq - 1));
+	u8 mask = ~((pirq & 0xf0u) >> 4);
 	unsigned long flags;
 	u8 trig;
 

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH v4 5/5] x86/PCI: Fix coding style in PIRQ table verification
  2022-03-31  7:10 [PATCH v4 0/5] x86/PCI: Improve $PIR and add $IRT PIRQ routing support Maciej W. Rozycki
                   ` (3 preceding siblings ...)
  2022-03-31  7:11 ` [PATCH v4 4/5] x86/PCI: Fix ALi M1487 (IBC) PIRQ router link value interpretation Maciej W. Rozycki
@ 2022-03-31  7:11 ` Maciej W. Rozycki
  2022-04-10 10:54   ` [tip: x86/irq] " tip-bot2 for Maciej W. Rozycki
  4 siblings, 1 reply; 12+ messages in thread
From: Maciej W. Rozycki @ 2022-03-31  7:11 UTC (permalink / raw)
  To: Bjorn Helgaas, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
	H. Peter Anvin
  Cc: Arnd Bergmann, Nikolai Zhubr, Michal Necasek, Dmitry Osipenko,
	Linus Torvalds, x86, linux-pci, linux-kernel

Remove an extraneous space with a cast in `pirq_check_routing_table'.

Signed-off-by: Maciej W. Rozycki <macro@orcam.me.uk>
---
Changes from v3:

- Remove parts obsoleted by 1/5.

New change in v3.
---
 arch/x86/pci/irq.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

Index: linux-macro/arch/x86/pci/irq.c
===================================================================
--- linux-macro.orig/arch/x86/pci/irq.c
+++ linux-macro/arch/x86/pci/irq.c
@@ -77,7 +77,7 @@ static inline struct irq_routing_table *
 	int i;
 	u8 sum;
 
-	rt = (struct irq_routing_table *) addr;
+	rt = (struct irq_routing_table *)addr;
 	if (rt->signature != PIRQ_SIGNATURE ||
 	    rt->version != PIRQ_VERSION ||
 	    rt->size % 16 ||

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH v4 3/5] x86/PCI: Add $IRT PIRQ routing table support
  2022-03-31  7:11 ` [PATCH v4 3/5] x86/PCI: Add $IRT PIRQ routing table support Maciej W. Rozycki
@ 2022-03-31 20:57   ` Dmitry Osipenko
  2022-04-10 10:54   ` [tip: x86/irq] " tip-bot2 for Maciej W. Rozycki
  1 sibling, 0 replies; 12+ messages in thread
From: Dmitry Osipenko @ 2022-03-31 20:57 UTC (permalink / raw)
  To: Maciej W. Rozycki, Bjorn Helgaas, Thomas Gleixner, Ingo Molnar,
	Borislav Petkov, H. Peter Anvin
  Cc: Arnd Bergmann, Nikolai Zhubr, Michal Necasek, Linus Torvalds,
	x86, linux-pci, linux-kernel

On 3/31/22 10:11, Maciej W. Rozycki wrote:
> Handle the $IRT PCI IRQ Routing Table format used by AMI for its BCP 
> (BIOS Configuration Program) external tool meant for tweaking BIOS 
> structures without the need to rebuild it from sources[1].
> 
> The $IRT format has been invented by AMI before Microsoft has come up 
> with its $PIR format and a $IRT table is therefore there in some systems 
> that lack a $PIR table, such as the DataExpert EXP8449 mainboard based 
> on the ALi FinALi 486 chipset (M1489/M1487), which predates DMI 2.0 and 
> cannot therefore be easily identified at run time.
> 
> Unlike with the $PIR format there is no alignment guarantee as to the 
> placement of the $IRT table, so scan the whole BIOS area bytewise.
> 
> Credit to Michal Necasek for helping me chase documentation for the 
> format.
> 
> References:
> 
> [1] "What is BCP? - AMI", <https://www.ami.com/what-is-bcp/>
> 
> Signed-off-by: Maciej W. Rozycki <macro@orcam.me.uk>
> Cc: Michal Necasek <mnecasek@yahoo.com>
> ---
> Changes from v3:
> 
> - Correct the BIOS memory scan such as to verify that the PCI IRQ Routing
>   Table header as well as individual slot entries are all wholly contained 
>   within the BIOS memory area.
> 
> - Following commit 5224f7909617 ("treewide: Replace zero-length arrays 
>   with flexible-array members") also make `slots' in `irt_routing_table' a 
>   flexible-array member.
> 
> New change in v3.
> ---
>  arch/x86/include/asm/pci_x86.h |    9 ++++
>  arch/x86/pci/irq.c             |   76 +++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 85 insertions(+)

Tested-by: Dmitry Osipenko <dmitry.osipenko@collabora.com> # crosvm

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [tip: x86/irq] x86/PCI: Fix coding style in PIRQ table verification
  2022-03-31  7:11 ` [PATCH v4 5/5] x86/PCI: Fix coding style in PIRQ table verification Maciej W. Rozycki
@ 2022-04-10 10:54   ` tip-bot2 for Maciej W. Rozycki
  0 siblings, 0 replies; 12+ messages in thread
From: tip-bot2 for Maciej W. Rozycki @ 2022-04-10 10:54 UTC (permalink / raw)
  To: linux-tip-commits; +Cc: Maciej W. Rozycki, Thomas Gleixner, x86, linux-kernel

The following commit has been merged into the x86/irq branch of tip:

Commit-ID:     c25f23459c117d950e657458b0d3dcaaf9039ec9
Gitweb:        https://git.kernel.org/tip/c25f23459c117d950e657458b0d3dcaaf9039ec9
Author:        Maciej W. Rozycki <macro@orcam.me.uk>
AuthorDate:    Thu, 31 Mar 2022 08:11:14 +01:00
Committer:     Thomas Gleixner <tglx@linutronix.de>
CommitterDate: Sun, 10 Apr 2022 12:48:15 +02:00

x86/PCI: Fix coding style in PIRQ table verification

Remove an extraneous space with a cast in `pirq_check_routing_table'.

Signed-off-by: Maciej W. Rozycki <macro@orcam.me.uk>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Link: https://lore.kernel.org/r/alpine.DEB.2.21.2203310017260.44113@angie.orcam.me.uk

---
 arch/x86/pci/irq.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/x86/pci/irq.c b/arch/x86/pci/irq.c
index ceac715..a498b84 100644
--- a/arch/x86/pci/irq.c
+++ b/arch/x86/pci/irq.c
@@ -77,7 +77,7 @@ static inline struct irq_routing_table *pirq_check_routing_table(u8 *addr,
 	int i;
 	u8 sum;
 
-	rt = (struct irq_routing_table *) addr;
+	rt = (struct irq_routing_table *)addr;
 	if (rt->signature != PIRQ_SIGNATURE ||
 	    rt->version != PIRQ_VERSION ||
 	    rt->size % 16 ||

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [tip: x86/irq] x86/PCI: Fix ALi M1487 (IBC) PIRQ router link value interpretation
  2022-03-31  7:11 ` [PATCH v4 4/5] x86/PCI: Fix ALi M1487 (IBC) PIRQ router link value interpretation Maciej W. Rozycki
@ 2022-04-10 10:54   ` tip-bot2 for Maciej W. Rozycki
  0 siblings, 0 replies; 12+ messages in thread
From: tip-bot2 for Maciej W. Rozycki @ 2022-04-10 10:54 UTC (permalink / raw)
  To: linux-tip-commits; +Cc: Maciej W. Rozycki, Thomas Gleixner, x86, linux-kernel

The following commit has been merged into the x86/irq branch of tip:

Commit-ID:     4969e223b109754c2340a26bba9b1cf44f0cba9b
Gitweb:        https://git.kernel.org/tip/4969e223b109754c2340a26bba9b1cf44f0cba9b
Author:        Maciej W. Rozycki <macro@orcam.me.uk>
AuthorDate:    Thu, 31 Mar 2022 08:11:10 +01:00
Committer:     Thomas Gleixner <tglx@linutronix.de>
CommitterDate: Sun, 10 Apr 2022 12:48:15 +02:00

x86/PCI: Fix ALi M1487 (IBC) PIRQ router link value interpretation

Fix an issue with commit 1ce849c75534 ("x86/PCI: Add support for the ALi 
M1487 (IBC) PIRQ router") and correct ALi M1487 (IBC) PIRQ router link 
value (`pirq' cookie) interpretation according to findings in the BIOS.

Credit to Nikolai Zhubr for the detective work as to the bit layout.

Fixes: 1ce849c75534 ("x86/PCI: Add support for the ALi M1487 (IBC) PIRQ router")
Signed-off-by: Maciej W. Rozycki <macro@orcam.me.uk>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Link: https://lore.kernel.org/r/alpine.DEB.2.21.2203310013270.44113@angie.orcam.me.uk

---
 arch/x86/pci/irq.c | 19 ++++++++++++++++---
 1 file changed, 16 insertions(+), 3 deletions(-)

diff --git a/arch/x86/pci/irq.c b/arch/x86/pci/irq.c
index 4a5e80f..ceac715 100644
--- a/arch/x86/pci/irq.c
+++ b/arch/x86/pci/irq.c
@@ -337,6 +337,15 @@ static void write_pc_conf_nybble(u8 base, u8 index, u8 val)
 	pc_conf_set(reg, x);
 }
 
+/*
+ * FinALi pirq rules are as follows:
+ *
+ * - bit 0 selects between INTx Routing Table Mapping Registers,
+ *
+ * - bit 3 selects the nibble within the INTx Routing Table Mapping Register,
+ *
+ * - bits 7:4 map to bits 3:0 of the PCI INTx Sensitivity Register.
+ */
 static int pirq_finali_get(struct pci_dev *router, struct pci_dev *dev,
 			   int pirq)
 {
@@ -344,11 +353,13 @@ static int pirq_finali_get(struct pci_dev *router, struct pci_dev *dev,
 		0, 9, 3, 10, 4, 5, 7, 6, 0, 11, 0, 12, 0, 14, 0, 15
 	};
 	unsigned long flags;
+	u8 index;
 	u8 x;
 
+	index = (pirq & 1) << 1 | (pirq & 8) >> 3;
 	raw_spin_lock_irqsave(&pc_conf_lock, flags);
 	pc_conf_set(PC_CONF_FINALI_LOCK, PC_CONF_FINALI_LOCK_KEY);
-	x = irqmap[read_pc_conf_nybble(PC_CONF_FINALI_PCI_INTX_RT1, pirq - 1)];
+	x = irqmap[read_pc_conf_nybble(PC_CONF_FINALI_PCI_INTX_RT1, index)];
 	pc_conf_set(PC_CONF_FINALI_LOCK, 0);
 	raw_spin_unlock_irqrestore(&pc_conf_lock, flags);
 	return x;
@@ -362,13 +373,15 @@ static int pirq_finali_set(struct pci_dev *router, struct pci_dev *dev,
 	};
 	u8 val = irqmap[irq];
 	unsigned long flags;
+	u8 index;
 
 	if (!val)
 		return 0;
 
+	index = (pirq & 1) << 1 | (pirq & 8) >> 3;
 	raw_spin_lock_irqsave(&pc_conf_lock, flags);
 	pc_conf_set(PC_CONF_FINALI_LOCK, PC_CONF_FINALI_LOCK_KEY);
-	write_pc_conf_nybble(PC_CONF_FINALI_PCI_INTX_RT1, pirq - 1, val);
+	write_pc_conf_nybble(PC_CONF_FINALI_PCI_INTX_RT1, index, val);
 	pc_conf_set(PC_CONF_FINALI_LOCK, 0);
 	raw_spin_unlock_irqrestore(&pc_conf_lock, flags);
 	return 1;
@@ -377,7 +390,7 @@ static int pirq_finali_set(struct pci_dev *router, struct pci_dev *dev,
 static int pirq_finali_lvl(struct pci_dev *router, struct pci_dev *dev,
 			   int pirq, int irq)
 {
-	u8 mask = ~(1u << (pirq - 1));
+	u8 mask = ~((pirq & 0xf0u) >> 4);
 	unsigned long flags;
 	u8 trig;
 

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [tip: x86/irq] x86/PCI: Add $IRT PIRQ routing table support
  2022-03-31  7:11 ` [PATCH v4 3/5] x86/PCI: Add $IRT PIRQ routing table support Maciej W. Rozycki
  2022-03-31 20:57   ` Dmitry Osipenko
@ 2022-04-10 10:54   ` tip-bot2 for Maciej W. Rozycki
  1 sibling, 0 replies; 12+ messages in thread
From: tip-bot2 for Maciej W. Rozycki @ 2022-04-10 10:54 UTC (permalink / raw)
  To: linux-tip-commits
  Cc: Maciej W. Rozycki, Thomas Gleixner, Dmitry Osipenko, x86, linux-kernel

The following commit has been merged into the x86/irq branch of tip:

Commit-ID:     b584db0c84db5ed9230356d5fa6610de55d297e6
Gitweb:        https://git.kernel.org/tip/b584db0c84db5ed9230356d5fa6610de55d297e6
Author:        Maciej W. Rozycki <macro@orcam.me.uk>
AuthorDate:    Thu, 31 Mar 2022 08:11:05 +01:00
Committer:     Thomas Gleixner <tglx@linutronix.de>
CommitterDate: Sun, 10 Apr 2022 12:48:14 +02:00

x86/PCI: Add $IRT PIRQ routing table support

Handle the $IRT PCI IRQ Routing Table format used by AMI for its BCP 
(BIOS Configuration Program) external tool meant for tweaking BIOS 
structures without the need to rebuild it from sources[1].

The $IRT format has been invented by AMI before Microsoft has come up 
with its $PIR format and a $IRT table is therefore there in some systems 
that lack a $PIR table, such as the DataExpert EXP8449 mainboard based 
on the ALi FinALi 486 chipset (M1489/M1487), which predates DMI 2.0 and 
cannot therefore be easily identified at run time.

Unlike with the $PIR format there is no alignment guarantee as to the 
placement of the $IRT table, so scan the whole BIOS area bytewise.

Credit to Michal Necasek for helping me chase documentation for the 
format.

References:

[1] "What is BCP? - AMI", <https://www.ami.com/what-is-bcp/>

Signed-off-by: Maciej W. Rozycki <macro@orcam.me.uk>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Tested-by: Dmitry Osipenko <dmitry.osipenko@collabora.com> # crosvm
Link: https://lore.kernel.org/r/alpine.DEB.2.21.2203302228410.9038@angie.orcam.me.uk

---
 arch/x86/include/asm/pci_x86.h |  9 ++++-
 arch/x86/pci/irq.c             | 76 +++++++++++++++++++++++++++++++++-
 2 files changed, 85 insertions(+)

diff --git a/arch/x86/include/asm/pci_x86.h b/arch/x86/include/asm/pci_x86.h
index a0627df..1307cd6 100644
--- a/arch/x86/include/asm/pci_x86.h
+++ b/arch/x86/include/asm/pci_x86.h
@@ -93,6 +93,15 @@ struct irq_routing_table {
 	struct irq_info slots[];
 } __attribute__((packed));
 
+struct irt_routing_table {
+	u32 signature;			/* IRT_SIGNATURE should be here */
+	u8 size;			/* Number of entries provided */
+	u8 used;			/* Number of entries actually used */
+	u16 exclusive_irqs;		/* IRQs devoted exclusively to
+					   PCI usage */
+	struct irq_info slots[];
+} __attribute__((packed));
+
 extern unsigned int pcibios_irq_mask;
 
 extern raw_spinlock_t pci_config_lock;
diff --git a/arch/x86/pci/irq.c b/arch/x86/pci/irq.c
index d4ecf88..4a5e80f 100644
--- a/arch/x86/pci/irq.c
+++ b/arch/x86/pci/irq.c
@@ -25,6 +25,8 @@
 #define PIRQ_SIGNATURE	(('$' << 0) + ('P' << 8) + ('I' << 16) + ('R' << 24))
 #define PIRQ_VERSION 0x0100
 
+#define IRT_SIGNATURE	(('$' << 0) + ('I' << 8) + ('R' << 16) + ('T' << 24))
+
 static int broken_hp_bios_irq9;
 static int acer_tm360_irqrouting;
 
@@ -93,7 +95,74 @@ static inline struct irq_routing_table *pirq_check_routing_table(u8 *addr,
 	return NULL;
 }
 
+/*
+ * Handle the $IRT PCI IRQ Routing Table format used by AMI for its BCP
+ * (BIOS Configuration Program) external tool meant for tweaking BIOS
+ * structures without the need to rebuild it from sources.  The $IRT
+ * format has been invented by AMI before Microsoft has come up with its
+ * $PIR format and a $IRT table is therefore there in some systems that
+ * lack a $PIR table.
+ *
+ * It uses the same PCI BIOS 2.1 format for interrupt routing entries
+ * themselves but has a different simpler header prepended instead,
+ * occupying 8 bytes, where a `$IRT' signature is followed by one byte
+ * specifying the total number of interrupt routing entries allocated in
+ * the table, then one byte specifying the actual number of entries used
+ * (which the BCP tool can take advantage of when modifying the table),
+ * and finally a 16-bit word giving the IRQs devoted exclusively to PCI.
+ * Unlike with the $PIR table there is no alignment guarantee.
+ *
+ * Given the similarity of the two formats the $IRT one is trivial to
+ * convert to the $PIR one, which we do here, except that obviously we
+ * have no information as to the router device to use, but we can handle
+ * it by matching PCI device IDs actually seen on the bus against ones
+ * that our individual routers recognise.
+ *
+ * Reportedly there is another $IRT table format where a 16-bit word
+ * follows the header instead that points to interrupt routing entries
+ * in a $PIR table provided elsewhere.  In that case this code will not
+ * be reached though as the $PIR table will have been chosen instead.
+ */
+static inline struct irq_routing_table *pirq_convert_irt_table(u8 *addr,
+							       u8 *limit)
+{
+	struct irt_routing_table *ir;
+	struct irq_routing_table *rt;
+	u16 size;
+	u8 sum;
+	int i;
+
+	ir = (struct irt_routing_table *)addr;
+	if (ir->signature != IRT_SIGNATURE || !ir->used || ir->size < ir->used)
+		return NULL;
+
+	size = sizeof(*ir) + ir->used * sizeof(ir->slots[0]);
+	if (size > limit - addr)
+		return NULL;
+
+	DBG(KERN_DEBUG "PCI: $IRT Interrupt Routing Table found at 0x%lx\n",
+	    __pa(ir));
+
+	size = sizeof(*rt) + ir->used * sizeof(rt->slots[0]);
+	rt = kzalloc(size, GFP_KERNEL);
+	if (!rt)
+		return NULL;
 
+	rt->signature = PIRQ_SIGNATURE;
+	rt->version = PIRQ_VERSION;
+	rt->size = size;
+	rt->exclusive_irqs = ir->exclusive_irqs;
+	for (i = 0; i < ir->used; i++)
+		rt->slots[i] = ir->slots[i];
+
+	addr = (u8 *)rt;
+	sum = 0;
+	for (i = 0; i < size; i++)
+		sum += addr[i];
+	rt->checksum = -sum;
+
+	return rt;
+}
 
 /*
  *  Search 0xf0000 -- 0xfffff for the PCI IRQ Routing Table.
@@ -120,6 +189,13 @@ static struct irq_routing_table * __init pirq_find_routing_table(void)
 		if (rt)
 			return rt;
 	}
+	for (addr = bios_start;
+	     addr < bios_end - sizeof(struct irt_routing_table);
+	     addr++) {
+		rt = pirq_convert_irt_table(addr, bios_end);
+		if (rt)
+			return rt;
+	}
 	return NULL;
 }
 

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [tip: x86/irq] x86/PCI: Handle PIRQ routing tables with no router device given
  2022-03-31  7:11 ` [PATCH v4 2/5] x86/PCI: Handle PIRQ routing tables with no router device given Maciej W. Rozycki
@ 2022-04-10 10:54   ` tip-bot2 for Maciej W. Rozycki
  0 siblings, 0 replies; 12+ messages in thread
From: tip-bot2 for Maciej W. Rozycki @ 2022-04-10 10:54 UTC (permalink / raw)
  To: linux-tip-commits
  Cc: Maciej W. Rozycki, Thomas Gleixner, Nikolai Zhubr, x86, linux-kernel

The following commit has been merged into the x86/irq branch of tip:

Commit-ID:     ac7cd5e16df8696c39e29b03dfedf069a025b822
Gitweb:        https://git.kernel.org/tip/ac7cd5e16df8696c39e29b03dfedf069a025b822
Author:        Maciej W. Rozycki <macro@orcam.me.uk>
AuthorDate:    Thu, 31 Mar 2022 08:11:01 +01:00
Committer:     Thomas Gleixner <tglx@linutronix.de>
CommitterDate: Sun, 10 Apr 2022 12:48:14 +02:00

x86/PCI: Handle PIRQ routing tables with no router device given

PIRQ routing tables provided by the PCI BIOS usually specify the PCI 
vendor:device ID as well as the bus address of the device implementing 
the PIRQ router, e.g.:

PCI: Interrupt Routing Table found at 0xc00fde10
[...]
PCI: Attempting to find IRQ router for [8086:7000]
pci 0000:00:07.0: PIIX/ICH IRQ router [8086:7000]

however in some cases they do not, in which case we fail to match the 
router handler, e.g.:

PCI: Interrupt Routing Table found at 0xc00fdae0
[...]
PCI: Attempting to find IRQ router for [0000:0000]
PCI: Interrupt router not found at 00:00

This is because we always match the vendor:device ID and the bus address 
literally, even if they are all zeros.

Handle this case then and iterate over all PCI devices until we find a 
matching router handler if the vendor ID given by the routing table is 
the invalid value of zero:

PCI: Attempting to find IRQ router for [0000:0000]
PCI: Trying IRQ router for [1039:0496]
pci 0000:00:05.0: SiS85C497 IRQ router [1039:0496]

Signed-off-by: Maciej W. Rozycki <macro@orcam.me.uk>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Tested-by: Nikolai Zhubr <zhubr.2@gmail.com>
Link: https://lore.kernel.org/r/alpine.DEB.2.21.2203302018570.9038@angie.orcam.me.uk

---
 arch/x86/pci/irq.c | 64 ++++++++++++++++++++++++++++++---------------
 1 file changed, 44 insertions(+), 20 deletions(-)

diff --git a/arch/x86/pci/irq.c b/arch/x86/pci/irq.c
index ef97b26..d4ecf88 100644
--- a/arch/x86/pci/irq.c
+++ b/arch/x86/pci/irq.c
@@ -1175,10 +1175,32 @@ static struct pci_dev *pirq_router_dev;
  *	chipset" ?
  */
 
+static bool __init pirq_try_router(struct irq_router *r,
+				   struct irq_routing_table *rt,
+				   struct pci_dev *dev)
+{
+	struct irq_router_handler *h;
+
+	DBG(KERN_DEBUG "PCI: Trying IRQ router for [%04x:%04x]\n",
+	    dev->vendor, dev->device);
+
+	for (h = pirq_routers; h->vendor; h++) {
+		/* First look for a router match */
+		if (rt->rtr_vendor == h->vendor &&
+		    h->probe(r, dev, rt->rtr_device))
+			return true;
+		/* Fall back to a device match */
+		if (dev->vendor == h->vendor &&
+		    h->probe(r, dev, dev->device))
+			return true;
+	}
+	return false;
+}
+
 static void __init pirq_find_router(struct irq_router *r)
 {
 	struct irq_routing_table *rt = pirq_table;
-	struct irq_router_handler *h;
+	struct pci_dev *dev;
 
 #ifdef CONFIG_PCI_BIOS
 	if (!rt->signature) {
@@ -1197,27 +1219,29 @@ static void __init pirq_find_router(struct irq_router *r)
 	DBG(KERN_DEBUG "PCI: Attempting to find IRQ router for [%04x:%04x]\n",
 	    rt->rtr_vendor, rt->rtr_device);
 
-	pirq_router_dev = pci_get_domain_bus_and_slot(0, rt->rtr_bus,
-						      rt->rtr_devfn);
-	if (!pirq_router_dev) {
-		DBG(KERN_DEBUG "PCI: Interrupt router not found at "
-			"%02x:%02x\n", rt->rtr_bus, rt->rtr_devfn);
-		return;
+	/* Use any vendor:device provided by the routing table or try all.  */
+	if (rt->rtr_vendor) {
+		dev = pci_get_domain_bus_and_slot(0, rt->rtr_bus,
+						  rt->rtr_devfn);
+		if (dev && pirq_try_router(r, rt, dev))
+			pirq_router_dev = dev;
+	} else {
+		dev = NULL;
+		for_each_pci_dev(dev) {
+			if (pirq_try_router(r, rt, dev)) {
+				pirq_router_dev = dev;
+				break;
+			}
+		}
 	}
 
-	for (h = pirq_routers; h->vendor; h++) {
-		/* First look for a router match */
-		if (rt->rtr_vendor == h->vendor &&
-			h->probe(r, pirq_router_dev, rt->rtr_device))
-			break;
-		/* Fall back to a device match */
-		if (pirq_router_dev->vendor == h->vendor &&
-			h->probe(r, pirq_router_dev, pirq_router_dev->device))
-			break;
-	}
-	dev_info(&pirq_router_dev->dev, "%s IRQ router [%04x:%04x]\n",
-		 pirq_router.name,
-		 pirq_router_dev->vendor, pirq_router_dev->device);
+	if (pirq_router_dev)
+		dev_info(&pirq_router_dev->dev, "%s IRQ router [%04x:%04x]\n",
+			 pirq_router.name,
+			 pirq_router_dev->vendor, pirq_router_dev->device);
+	else
+		DBG(KERN_DEBUG "PCI: Interrupt router not found at "
+		    "%02x:%02x\n", rt->rtr_bus, rt->rtr_devfn);
 
 	/* The device remains referenced for the kernel lifetime */
 }

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [tip: x86/irq] x86/PCI: Add PIRQ routing table range checks
  2022-03-31  7:10 ` [PATCH v4 1/5] x86/PCI: Add PIRQ routing table range checks Maciej W. Rozycki
@ 2022-04-10 10:54   ` tip-bot2 for Maciej W. Rozycki
  0 siblings, 0 replies; 12+ messages in thread
From: tip-bot2 for Maciej W. Rozycki @ 2022-04-10 10:54 UTC (permalink / raw)
  To: linux-tip-commits; +Cc: Maciej W. Rozycki, Thomas Gleixner, x86, linux-kernel

The following commit has been merged into the x86/irq branch of tip:

Commit-ID:     5d64089aa4a5bd3d7e00e3d6ddf4943dd34627b3
Gitweb:        https://git.kernel.org/tip/5d64089aa4a5bd3d7e00e3d6ddf4943dd34627b3
Author:        Maciej W. Rozycki <macro@orcam.me.uk>
AuthorDate:    Thu, 31 Mar 2022 08:10:55 +01:00
Committer:     Thomas Gleixner <tglx@linutronix.de>
CommitterDate: Sun, 10 Apr 2022 12:48:14 +02:00

x86/PCI: Add PIRQ routing table range checks

Verify that the PCI IRQ Routing Table header as well as individual slot 
entries are all wholly contained within the BIOS memory area.  Do not 
even call the checksum calculator if the header would overrun the area 
and then bail out early if any slot would.

Signed-off-by: Maciej W. Rozycki <macro@orcam.me.uk>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Link: https://lore.kernel.org/r/alpine.DEB.2.21.2203301735510.22465@angie.orcam.me.uk

---
 arch/x86/pci/irq.c | 17 ++++++++++++-----
 1 file changed, 12 insertions(+), 5 deletions(-)

diff --git a/arch/x86/pci/irq.c b/arch/x86/pci/irq.c
index 4b0e008..ef97b26 100644
--- a/arch/x86/pci/irq.c
+++ b/arch/x86/pci/irq.c
@@ -68,7 +68,8 @@ void (*pcibios_disable_irq)(struct pci_dev *dev) = pirq_disable_irq;
  *  and perform checksum verification.
  */
 
-static inline struct irq_routing_table *pirq_check_routing_table(u8 *addr)
+static inline struct irq_routing_table *pirq_check_routing_table(u8 *addr,
+								 u8 *limit)
 {
 	struct irq_routing_table *rt;
 	int i;
@@ -78,7 +79,8 @@ static inline struct irq_routing_table *pirq_check_routing_table(u8 *addr)
 	if (rt->signature != PIRQ_SIGNATURE ||
 	    rt->version != PIRQ_VERSION ||
 	    rt->size % 16 ||
-	    rt->size < sizeof(struct irq_routing_table))
+	    rt->size < sizeof(struct irq_routing_table) ||
+	    (limit && rt->size > limit - addr))
 		return NULL;
 	sum = 0;
 	for (i = 0; i < rt->size; i++)
@@ -99,17 +101,22 @@ static inline struct irq_routing_table *pirq_check_routing_table(u8 *addr)
 
 static struct irq_routing_table * __init pirq_find_routing_table(void)
 {
+	u8 * const bios_start = (u8 *)__va(0xf0000);
+	u8 * const bios_end = (u8 *)__va(0x100000);
 	u8 *addr;
 	struct irq_routing_table *rt;
 
 	if (pirq_table_addr) {
-		rt = pirq_check_routing_table((u8 *) __va(pirq_table_addr));
+		rt = pirq_check_routing_table((u8 *)__va(pirq_table_addr),
+					      NULL);
 		if (rt)
 			return rt;
 		printk(KERN_WARNING "PCI: PIRQ table NOT found at pirqaddr\n");
 	}
-	for (addr = (u8 *) __va(0xf0000); addr < (u8 *) __va(0x100000); addr += 16) {
-		rt = pirq_check_routing_table(addr);
+	for (addr = bios_start;
+	     addr < bios_end - sizeof(struct irq_routing_table);
+	     addr += 16) {
+		rt = pirq_check_routing_table(addr, bios_end);
 		if (rt)
 			return rt;
 	}

^ permalink raw reply related	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2022-04-10 10:54 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-03-31  7:10 [PATCH v4 0/5] x86/PCI: Improve $PIR and add $IRT PIRQ routing support Maciej W. Rozycki
2022-03-31  7:10 ` [PATCH v4 1/5] x86/PCI: Add PIRQ routing table range checks Maciej W. Rozycki
2022-04-10 10:54   ` [tip: x86/irq] " tip-bot2 for Maciej W. Rozycki
2022-03-31  7:11 ` [PATCH v4 2/5] x86/PCI: Handle PIRQ routing tables with no router device given Maciej W. Rozycki
2022-04-10 10:54   ` [tip: x86/irq] " tip-bot2 for Maciej W. Rozycki
2022-03-31  7:11 ` [PATCH v4 3/5] x86/PCI: Add $IRT PIRQ routing table support Maciej W. Rozycki
2022-03-31 20:57   ` Dmitry Osipenko
2022-04-10 10:54   ` [tip: x86/irq] " tip-bot2 for Maciej W. Rozycki
2022-03-31  7:11 ` [PATCH v4 4/5] x86/PCI: Fix ALi M1487 (IBC) PIRQ router link value interpretation Maciej W. Rozycki
2022-04-10 10:54   ` [tip: x86/irq] " tip-bot2 for Maciej W. Rozycki
2022-03-31  7:11 ` [PATCH v4 5/5] x86/PCI: Fix coding style in PIRQ table verification Maciej W. Rozycki
2022-04-10 10:54   ` [tip: x86/irq] " tip-bot2 for Maciej W. Rozycki

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.