Message ID | 20221113173442.5770-1-mat.jonczyk@o2.pl |
---|---|
State | New |
Headers |
Return-Path: <linux-kernel-owner@vger.kernel.org> Delivered-To: ouuuleilei@gmail.com Received: by 2002:a5d:6687:0:0:0:0:0 with SMTP id l7csp1772638wru; Sun, 13 Nov 2022 09:44:01 -0800 (PST) X-Google-Smtp-Source: AA0mqf5CbJdgFrzoxa66cfnDVPT5uyD5rc18AFTWq0MMUsGKLzVdqofGLd4brBjepTkr+575Cn3R X-Received: by 2002:a17:902:9695:b0:177:faf5:58c5 with SMTP id n21-20020a170902969500b00177faf558c5mr10822534plp.166.1668361441416; Sun, 13 Nov 2022 09:44:01 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1668361441; cv=none; d=google.com; s=arc-20160816; b=oWg1+x68Dw2kMkxq497hxqqSzmjripi3CZRZaLtikfqAgI+CNDLX77kvvTyt7fbSZl Ga0QSzeyH8h8lWlPsh7Gd11zD4vYtzAs4/GOU1XlWUdydNLQF8W+BUbv76G7zXTk+gn6 hRItvCn6UHlK9XcC88+zdF5bYbjWRVKjMXqG2rjXVyXaKb0vqOwD+sg6vpxb0LEVz/rA f3+ORzgsDrvjujeLmlr7jUsKoh0wYeWLLGzKU2mNgXpTKx/hh8ZyxRzxe1Dng/nuq0pr YXPbugfstu52afUhmkGbfMV0JaUF1szf++cck/iVkb+TQCdydIYdyelEyeBJKLeSrBBg VLow== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=JOXzz5c4GDKUxSgs3Q0u7I+VwUW/4AZN5La4/sOMeOQ=; b=GmHiHhzp+r4zNaKNZdD+YLH2LsxJF50+Vh6afcJ1+qWhXtsrZP5f4HdKGgZL9zwr9f u4r5L46o/RtnmG2sf8WvPCmKyl+xRWjItyvzzIEZSO0EoG87ZE/2pXnsZCnYob7sjL58 8xRDlZ8lGTSQ4qaEkXCctcagYzbTJ+jh68gQRwFteo+FvoC0aOtxKWTuLa75H2xxOwbA DOslzO5dx04t6E/BzGAh3JadoJlpqJ9NXiL9adqK58S6acs3Y+zHuZaX2An1zszaB2bp RssUcc4AIWFXuBRCPBt3VWmuc6eIKuBtZAKoVCcJRuQd+vxPE4VqTrWU56JqMzkRFeOH UW5Q== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass (test mode) header.i=@o2.pl header.s=1024a header.b=WC0xbcvY; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=o2.pl Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id 8-20020a631848000000b0046ec76d7a09si7826472pgy.665.2022.11.13.09.43.29; Sun, 13 Nov 2022 09:44:01 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass (test mode) header.i=@o2.pl header.s=1024a header.b=WC0xbcvY; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=o2.pl Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233522AbiKMRfY (ORCPT <rfc822;winker.wchi@gmail.com> + 99 others); Sun, 13 Nov 2022 12:35:24 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:46832 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232884AbiKMRfW (ORCPT <rfc822;linux-kernel@vger.kernel.org>); Sun, 13 Nov 2022 12:35:22 -0500 Received: from mx-out.tlen.pl (mx-out.tlen.pl [193.222.135.158]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id E73505F51 for <linux-kernel@vger.kernel.org>; Sun, 13 Nov 2022 09:35:19 -0800 (PST) Received: (wp-smtpd smtp.tlen.pl 24814 invoked from network); 13 Nov 2022 18:35:15 +0100 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=o2.pl; s=1024a; t=1668360915; bh=JOXzz5c4GDKUxSgs3Q0u7I+VwUW/4AZN5La4/sOMeOQ=; h=From:To:Cc:Subject; b=WC0xbcvYZ6vqfsxdP8OIhr2JqKrJ2gNa4huYRDw8R8qw+dA/sPBxOkNr21kWlSWeC RlpMOPzL9TD99IY8XIMT1YIdNmTgEGdNTu9+vo6YrqxDys183yNa89aILJanTZMbIF oavukyRWbzlUoQ50E+jJoW/Q7neUMThlHmKMXlXw= Received: from aaey149.neoplus.adsl.tpnet.pl (HELO localhost.localdomain) (mat.jonczyk@o2.pl@[83.4.128.149]) (envelope-sender <mat.jonczyk@o2.pl>) by smtp.tlen.pl (WP-SMTPD) with SMTP for <linux-kernel@vger.kernel.org>; 13 Nov 2022 18:35:15 +0100 From: =?utf-8?q?Mateusz_Jo=C5=84czyk?= <mat.jonczyk@o2.pl> To: linux-kernel@vger.kernel.org, linux-pci@vger.kernel.org, linux-acpi@vger.kernel.org, linux-i2c@vger.kernel.org Cc: =?utf-8?q?Mateusz_Jo=C5=84czyk?= <mat.jonczyk@o2.pl>, Bjorn Helgaas <bhelgaas@google.com>, "Rafael J. Wysocki" <rafael@kernel.org>, Len Brown <lenb@kernel.org>, Borislav Petkov <bp@suse.de>, Jean Delvare <jdelvare@suse.com> Subject: [PATCH v2] acpi,pci: warn about duplicate IRQ routing entries returned from _PRT Date: Sun, 13 Nov 2022 18:34:42 +0100 Message-Id: <20221113173442.5770-1-mat.jonczyk@o2.pl> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20221112200927.7255-1-mat.jonczyk@o2.pl> References: <20221112200927.7255-1-mat.jonczyk@o2.pl> MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-WP-MailID: 934e56db77df8ec1dea79e941e558262 X-WP-AV: skaner antywirusowy Poczty o2 X-WP-SPAM: NO 0000000 [kSOl] X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,FREEMAIL_FROM,RCVD_IN_MSPIKE_H2, SPF_HELO_NONE,SPF_PASS autolearn=unavailable autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: <linux-kernel.vger.kernel.org> X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1749322579360401888?= X-GMAIL-MSGID: =?utf-8?q?1749403766755799672?= |
Series |
[v2] acpi,pci: warn about duplicate IRQ routing entries returned from _PRT
|
|
Commit Message
Mateusz Jończyk
Nov. 13, 2022, 5:34 p.m. UTC
On some platforms, the ACPI _PRT function returns duplicate interrupt
routing entries. Linux uses the first matching entry, but sometimes the
second matching entry contains the correct interrupt vector.
Print a warning to dmesg if duplicate interrupt routing entries are
present, so that we could check how many models are affected.
This happens on a Dell Latitude E6500 laptop with the i2c-i801 Intel
SMBus controller. This controller was nonfunctional unless its interrupt
usage was disabled (using the "disable_features=0x10" module parameter).
After investigation, it turned out that the driver was using an
incorrect interrupt vector: in lspci output for this device there was:
Interrupt: pin B routed to IRQ 19
but after running i2cdetect (without using any i2c-i801 module
parameters) the following was logged to dmesg:
[...]
i801_smbus 0000:00:1f.3: Timeout waiting for interrupt!
i801_smbus 0000:00:1f.3: Transaction timeout
i801_smbus 0000:00:1f.3: Timeout waiting for interrupt!
i801_smbus 0000:00:1f.3: Transaction timeout
irq 17: nobody cared (try booting with the "irqpoll" option)
Existence of duplicate entries in a table returned by the _PRT method
was confirmed by disassembling the ACPI DSDT table.
Signed-off-by: Mateusz Jończyk <mat.jonczyk@o2.pl>
Cc: Bjorn Helgaas <bhelgaas@google.com>
Cc: "Rafael J. Wysocki" <rafael@kernel.org>
Cc: Len Brown <lenb@kernel.org>
Cc: Borislav Petkov <bp@suse.de>
Cc: Jean Delvare <jdelvare@suse.com>
--
v2: - add a newline at the end of the kernel log message,
- replace: "if (match == NULL)" -> "if (!match)"
- patch description tweaks.
Tested on two computers, including the affected Dell Latitude E6500 laptop.
drivers/acpi/pci_irq.c | 25 ++++++++++++++++++++++---
1 file changed, 22 insertions(+), 3 deletions(-)
base-commit: f0c4d9fc9cc9462659728d168387191387e903cc
Comments
Hi Mateusz, On Sun, 13 Nov 2022 18:34:42 +0100, Mateusz Jończyk wrote: > On some platforms, the ACPI _PRT function returns duplicate interrupt > routing entries. Linux uses the first matching entry, but sometimes the > second matching entry contains the correct interrupt vector. > > Print a warning to dmesg if duplicate interrupt routing entries are > present, so that we could check how many models are affected. Excellent idea. We want hardware manufacturers to fix such bugs in the firmware, and the best way for this to happen is to report them whenever they are encountered. > This happens on a Dell Latitude E6500 laptop with the i2c-i801 Intel > SMBus controller. This controller was nonfunctional unless its interrupt > usage was disabled (using the "disable_features=0x10" module parameter). > > After investigation, it turned out that the driver was using an > incorrect interrupt vector: in lspci output for this device there was: > Interrupt: pin B routed to IRQ 19 > but after running i2cdetect (without using any i2c-i801 module > parameters) the following was logged to dmesg: > > [...] > i801_smbus 0000:00:1f.3: Timeout waiting for interrupt! > i801_smbus 0000:00:1f.3: Transaction timeout > i801_smbus 0000:00:1f.3: Timeout waiting for interrupt! > i801_smbus 0000:00:1f.3: Transaction timeout > irq 17: nobody cared (try booting with the "irqpoll" option) > > Existence of duplicate entries in a table returned by the _PRT method > was confirmed by disassembling the ACPI DSDT table. Excuse a probably stupid question, but what would happen if we would plain ignore the IRQ routing information from ACPI in this case? Would we fallback to some pure-PCI routing logic which may have a chance to find the right IRQ routing (matching the second ACPI routing entry in this case)? > Signed-off-by: Mateusz Jończyk <mat.jonczyk@o2.pl> > Cc: Bjorn Helgaas <bhelgaas@google.com> > Cc: "Rafael J. Wysocki" <rafael@kernel.org> > Cc: Len Brown <lenb@kernel.org> > Cc: Borislav Petkov <bp@suse.de> > Cc: Jean Delvare <jdelvare@suse.com> > > -- > v2: - add a newline at the end of the kernel log message, > - replace: "if (match == NULL)" -> "if (!match)" > - patch description tweaks. > > Tested on two computers, including the affected Dell Latitude E6500 laptop. > > drivers/acpi/pci_irq.c | 25 ++++++++++++++++++++++--- > 1 file changed, 22 insertions(+), 3 deletions(-) > > diff --git a/drivers/acpi/pci_irq.c b/drivers/acpi/pci_irq.c > index 08e15774fb9f..a4e41b7b71ed 100644 > --- a/drivers/acpi/pci_irq.c > +++ b/drivers/acpi/pci_irq.c > @@ -203,6 +203,8 @@ static int acpi_pci_irq_find_prt_entry(struct pci_dev *dev, > struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; > struct acpi_pci_routing_table *entry; > acpi_handle handle = NULL; > + struct acpi_prt_entry *match = NULL; > + const char *match_int_source = NULL; > > if (dev->bus->bridge) > handle = ACPI_HANDLE(dev->bus->bridge); > @@ -219,13 +221,30 @@ static int acpi_pci_irq_find_prt_entry(struct pci_dev *dev, > > entry = buffer.pointer; > while (entry && (entry->length > 0)) { > - if (!acpi_pci_irq_check_entry(handle, dev, pin, > - entry, entry_ptr)) > - break; > + struct acpi_prt_entry *curr; > + > + if (!acpi_pci_irq_check_entry(handle, dev, pin, entry, &curr)) { > + if (!match) { > + match = curr; > + match_int_source = entry->source; > + } else { > + pr_warn(FW_BUG > + "ACPI _PRT returned duplicate IRQ routing entries for device " > + "%04x:%02x:%02x[INT%c]: %s[%d] and %s[%d].\n", The beginning of the string should be aligned with the opening parenthesis, and the string should be on a single line (this is a encouraged exception to the 80-column rule). I would also omit the tailing dot for consistency. > + curr->id.segment, curr->id.bus, curr->id.device, Is the IRQ per PCI device, or per PCI function? If the latter, then you should print "%02x.%x" instead of just "%02x", with the extra element being curr->id.function. > + pin_name(curr->pin), > + match_int_source, match->index, > + entry->source, curr->index); > + // we use the first matching entry nonetheless The rest of the file uses /* C89-style comments */ so I would stick to that for consistency. > + } > + } > + > entry = (struct acpi_pci_routing_table *) > ((unsigned long)entry + entry->length); > } > > + *entry_ptr = match; > + > kfree(buffer.pointer); > return 0; > } Reviewed-by: Jean Delvare <jdelvare@suse.de> Tested-by: Jean Delvare <jdelvare@suse.de> (Tested on a Dell OptiPlex 9020 not affected by the problem.)
Hello, W dniu 15.11.2022 o 09:36, Jean Delvare pisze: > Hi Mateusz, > > On Sun, 13 Nov 2022 18:34:42 +0100, Mateusz Jończyk wrote: >> On some platforms, the ACPI _PRT function returns duplicate interrupt >> routing entries. Linux uses the first matching entry, but sometimes the >> second matching entry contains the correct interrupt vector. >> >> Print a warning to dmesg if duplicate interrupt routing entries are >> present, so that we could check how many models are affected. > Excellent idea. We want hardware manufacturers to fix such bugs in the > firmware, and the best way for this to happen is to report them > whenever they are encountered. > >> This happens on a Dell Latitude E6500 laptop with the i2c-i801 Intel >> SMBus controller. This controller was nonfunctional unless its interrupt >> usage was disabled (using the "disable_features=0x10" module parameter). >> >> After investigation, it turned out that the driver was using an >> incorrect interrupt vector: in lspci output for this device there was: >> Interrupt: pin B routed to IRQ 19 >> but after running i2cdetect (without using any i2c-i801 module >> parameters) the following was logged to dmesg: >> >> [...] >> i801_smbus 0000:00:1f.3: Timeout waiting for interrupt! >> i801_smbus 0000:00:1f.3: Transaction timeout >> i801_smbus 0000:00:1f.3: Timeout waiting for interrupt! >> i801_smbus 0000:00:1f.3: Transaction timeout >> irq 17: nobody cared (try booting with the "irqpoll" option) >> >> Existence of duplicate entries in a table returned by the _PRT method >> was confirmed by disassembling the ACPI DSDT table. > Excuse a probably stupid question, but what would happen if we would > plain ignore the IRQ routing information from ACPI in this case? Would > we fallback to some pure-PCI routing logic which may have a chance to > find the right IRQ routing (matching the second ACPI routing entry in > this case)? From what I understand, the PCI IRQ routing information is not discoverable by probing the hardware (in the general case), it has to be obtained from the ACPI tables (or perhaps from the obsolete MP tables, also provided by firmware). See https://docs.kernel.org/PCI/acpi-info.html : > For example, there’s no standard hardware mechanism for enumerating PCI > host bridges, so the ACPI namespace must describe each host bridge, > the method for accessing PCI config space below it, the address space > windows the host bridge forwards to PCI (using _CRS), and the routing > of legacy INTx interrupts (using _PRT). (a PCI host bridge connects the CPU cores to the PCI bus, it is the root of the PCI device tree. This patch concerns the "legacy INTx interrupts" as above). In the case of this particular laptop, however, it should be possible to obtain the information by reading chipset registers, which are documented at https://www.intel.com/content/www/us/en/io/io-controller-hub-9-datasheet.html But this is difficult to implement in every case. >> Signed-off-by: Mateusz Jończyk <mat.jonczyk@o2.pl> >> Cc: Bjorn Helgaas <bhelgaas@google.com> >> Cc: "Rafael J. Wysocki" <rafael@kernel.org> >> Cc: Len Brown <lenb@kernel.org> >> Cc: Borislav Petkov <bp@suse.de> >> Cc: Jean Delvare <jdelvare@suse.com> >> >> -- >> v2: - add a newline at the end of the kernel log message, >> - replace: "if (match == NULL)" -> "if (!match)" >> - patch description tweaks. >> >> Tested on two computers, including the affected Dell Latitude E6500 laptop. >> >> drivers/acpi/pci_irq.c | 25 ++++++++++++++++++++++--- >> 1 file changed, 22 insertions(+), 3 deletions(-) >> >> diff --git a/drivers/acpi/pci_irq.c b/drivers/acpi/pci_irq.c >> index 08e15774fb9f..a4e41b7b71ed 100644 >> --- a/drivers/acpi/pci_irq.c >> +++ b/drivers/acpi/pci_irq.c >> @@ -203,6 +203,8 @@ static int acpi_pci_irq_find_prt_entry(struct pci_dev *dev, >> struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; >> struct acpi_pci_routing_table *entry; >> acpi_handle handle = NULL; >> + struct acpi_prt_entry *match = NULL; >> + const char *match_int_source = NULL; >> >> if (dev->bus->bridge) >> handle = ACPI_HANDLE(dev->bus->bridge); >> @@ -219,13 +221,30 @@ static int acpi_pci_irq_find_prt_entry(struct pci_dev *dev, >> >> entry = buffer.pointer; >> while (entry && (entry->length > 0)) { >> - if (!acpi_pci_irq_check_entry(handle, dev, pin, >> - entry, entry_ptr)) >> - break; >> + struct acpi_prt_entry *curr; >> + >> + if (!acpi_pci_irq_check_entry(handle, dev, pin, entry, &curr)) { >> + if (!match) { >> + match = curr; >> + match_int_source = entry->source; >> + } else { >> + pr_warn(FW_BUG >> + "ACPI _PRT returned duplicate IRQ routing entries for device " >> + "%04x:%02x:%02x[INT%c]: %s[%d] and %s[%d].\n", > The beginning of the string should be aligned with the opening > parenthesis, and the string should be on a single line (this is a > encouraged exception to the 80-column rule). I would also omit the > tailing dot for consistency. OK >> + curr->id.segment, curr->id.bus, curr->id.device, > Is the IRQ per PCI device, or per PCI function? If the latter, then you > should print "%02x.%x" instead of just "%02x", with the extra element > being curr->id.function. This is per PCI device. [snip] > Reviewed-by: Jean Delvare <jdelvare@suse.de> > Tested-by: Jean Delvare <jdelvare@suse.de> > > (Tested on a Dell OptiPlex 9020 not affected by the problem.) > Thank you for reviewing. Greetings, Mateusz
diff --git a/drivers/acpi/pci_irq.c b/drivers/acpi/pci_irq.c index 08e15774fb9f..a4e41b7b71ed 100644 --- a/drivers/acpi/pci_irq.c +++ b/drivers/acpi/pci_irq.c @@ -203,6 +203,8 @@ static int acpi_pci_irq_find_prt_entry(struct pci_dev *dev, struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; struct acpi_pci_routing_table *entry; acpi_handle handle = NULL; + struct acpi_prt_entry *match = NULL; + const char *match_int_source = NULL; if (dev->bus->bridge) handle = ACPI_HANDLE(dev->bus->bridge); @@ -219,13 +221,30 @@ static int acpi_pci_irq_find_prt_entry(struct pci_dev *dev, entry = buffer.pointer; while (entry && (entry->length > 0)) { - if (!acpi_pci_irq_check_entry(handle, dev, pin, - entry, entry_ptr)) - break; + struct acpi_prt_entry *curr; + + if (!acpi_pci_irq_check_entry(handle, dev, pin, entry, &curr)) { + if (!match) { + match = curr; + match_int_source = entry->source; + } else { + pr_warn(FW_BUG + "ACPI _PRT returned duplicate IRQ routing entries for device " + "%04x:%02x:%02x[INT%c]: %s[%d] and %s[%d].\n", + curr->id.segment, curr->id.bus, curr->id.device, + pin_name(curr->pin), + match_int_source, match->index, + entry->source, curr->index); + // we use the first matching entry nonetheless + } + } + entry = (struct acpi_pci_routing_table *) ((unsigned long)entry + entry->length); } + *entry_ptr = match; + kfree(buffer.pointer); return 0; }