From patchwork Mon Jul 5 10:46:13 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Maciej W. Rozycki" X-Patchwork-Id: 12358791 X-Patchwork-Delegate: bhelgaas@google.com Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-15.3 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,USER_AGENT_SANE_1 autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 1360AC07E99 for ; Mon, 5 Jul 2021 10:46:16 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id EF4D461447 for ; Mon, 5 Jul 2021 10:46:15 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230482AbhGEKsv (ORCPT ); Mon, 5 Jul 2021 06:48:51 -0400 Received: from angie.orcam.me.uk ([78.133.224.34]:60282 "EHLO angie.orcam.me.uk" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230168AbhGEKsv (ORCPT ); Mon, 5 Jul 2021 06:48:51 -0400 Received: by angie.orcam.me.uk (Postfix, from userid 500) id 82FE092009C; Mon, 5 Jul 2021 12:46:13 +0200 (CEST) Received: from localhost (localhost [127.0.0.1]) by angie.orcam.me.uk (Postfix) with ESMTP id 7BD6092009B; Mon, 5 Jul 2021 12:46:13 +0200 (CEST) Date: Mon, 5 Jul 2021 12:46:13 +0200 (CEST) From: "Maciej W. Rozycki" To: Nikolai Zhubr , Bjorn Helgaas , Thomas Gleixner , Ingo Molnar , Borislav Petkov , "H. Peter Anvin" cc: Arnd Bergmann , x86@kernel.org, linux-pci@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH] x86/PCI: Handle PIRQ routing tables with no router device given Message-ID: User-Agent: Alpine 2.21 (DEB 202 2017-01-01) MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: linux-pci@vger.kernel.org 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. Signed-off-by: Maciej W. Rozycki --- arch/x86/pci/irq.c | 63 ++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 43 insertions(+), 20 deletions(-) linux-x86-pirq-router-nodev.diff Index: linux-macro-ide-tty/arch/x86/pci/irq.c =================================================================== --- linux-macro-ide-tty.orig/arch/x86/pci/irq.c +++ linux-macro-ide-tty/arch/x86/pci/irq.c @@ -908,10 +908,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) { @@ -930,27 +952,28 @@ 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 (pirq_try_router(r, rt, dev)) + pirq_router_dev = dev; + } else { + 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 */ }