Received: by 2002:a05:6a10:f3d0:0:0:0:0 with SMTP id a16csp4614872pxv; Tue, 6 Jul 2021 05:22:12 -0700 (PDT) X-Google-Smtp-Source: ABdhPJzooA/+mnkJTB4MSzC2AozwS51Z9yrYT5OlOy0DGQbJNmoxGtgq24XslxfquBcJaeiKihD+ X-Received: by 2002:a17:906:99c2:: with SMTP id s2mr12446369ejn.16.1625574128380; Tue, 06 Jul 2021 05:22:08 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1625574128; cv=none; d=google.com; s=arc-20160816; b=h3kriChvX2H61Rb29BhPrYoU8LTWAHPbeaR//jojka5SOp9r0UkE8omL5YvJhN35tm 3vKPKUgiM+oW0ZuiZn8JwCimG33kS49GShVMHD+KSZySD6YS3Gzh2u1Cn7VDCh/5pNFI ULJybzwm4vXWLghbOrbVyZ9KdZz3fuqUoEA8pNXMz835LvJ50TmafGAVpmcrCJpcLfoX tfZonRzopDc2sXYbQzO6wrf3ytjcXd6mvjnUzMz3KBQ1W70hiqe5FvaoPsyoqWWTXmMy OT1d7pwp/dKz5agP2bPpZ7ZpscjoJV0NO2CNgjsaRr1heP+PlbN7ef5t+D6b3sSwTZbv kzxA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:mime-version:user-agent:message-id:subject:cc:to :from:date; bh=ysh3ncbDmZHeBD+4h6PQKoj5Oze5hEW60OnndGh7u+w=; b=hl8essvYbmh1BcC0l5gfS/nMqG8AE8+LVDbDTjXhgzPM+X8NakDOajooxfY61hu1cW cwVn1zRHBaeTuFhGIIpQLnVdHkZYlnqGD4wPjWpa7SeNc1ZBuemkwnwbFFOAa737coWZ ofpYqG/YpO+qOxlHEEJo9elTKX8rua51QkTQzBm35cGNLTnvyVSSYTJorPRlltUHggjv 3QM3sHrc8NA+IWVdMF+9hyKo4VXUDitDXDmo6BsOEk/P/TTD0RRx0HF6cKAopH128QHO V92k6lh1pB5tYg8F21G0QSdFbCcX12t038w2pVsgMi1/dc0PJidkDqAPAbekP/vD/uO5 uBIA== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id q18si14483611edd.415.2021.07.06.05.21.44; Tue, 06 Jul 2021 05:22:08 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; Authentication-Results: mx.google.com; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234087AbhGFMX0 (ORCPT + 99 others); Tue, 6 Jul 2021 08:23:26 -0400 Received: from angie.orcam.me.uk ([78.133.224.34]:60366 "EHLO angie.orcam.me.uk" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234232AbhGFLdW (ORCPT ); Tue, 6 Jul 2021 07:33:22 -0400 Received: by angie.orcam.me.uk (Postfix, from userid 500) id 2848992009C; Tue, 6 Jul 2021 13:30:41 +0200 (CEST) Received: from localhost (localhost [127.0.0.1]) by angie.orcam.me.uk (Postfix) with ESMTP id 20E3B92009B; Tue, 6 Jul 2021 13:30:41 +0200 (CEST) Date: Tue, 6 Jul 2021 13:30:41 +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 v2] 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 Content-Type: text/plain; charset=US-ASCII Precedence: bulk List-ID: X-Mailing-List: linux-kernel@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 --- 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-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,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 */ }