From a02fd05661d73a8507dd70dd820e9b984490c545 Mon Sep 17 00:00:00 2001 From: Huacai Chen Date: Tue, 24 Jun 2025 14:29:27 +0800 Subject: [PATCH 1/5] PCI: Extend isolated function probing to LoongArch Like s390 and the jailhouse hypervisor, LoongArch's PCI architecture allows passing isolated PCI functions to a guest OS instance. So it is possible that there is a multi-function device without function 0 for the host or guest. Allow probing such functions by adding a IS_ENABLED(CONFIG_LOONGARCH) case in the hypervisor_isolated_pci_functions() helper. This is similar to commit 189c6c33ff42 ("PCI: Extend isolated function probing to s390"). Signed-off-by: Huacai Chen Signed-off-by: Bjorn Helgaas Cc: stable@vger.kernel.org Link: https://patch.msgid.link/20250624062927.4037734-1-chenhuacai@loongson.cn --- include/linux/hypervisor.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/linux/hypervisor.h b/include/linux/hypervisor.h index 9efbc54e35e5..be5417303ecf 100644 --- a/include/linux/hypervisor.h +++ b/include/linux/hypervisor.h @@ -37,6 +37,9 @@ static inline bool hypervisor_isolated_pci_functions(void) if (IS_ENABLED(CONFIG_S390)) return true; + if (IS_ENABLED(CONFIG_LOONGARCH)) + return true; + return jailhouse_paravirt(); } From 9989e0ca7462c62f93dbc62f684448aa2efb9226 Mon Sep 17 00:00:00 2001 From: Jiwei Sun Date: Thu, 23 Jan 2025 13:51:54 +0800 Subject: [PATCH 2/5] PCI: Fix link speed calculation on retrain failure MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When pcie_failed_link_retrain() fails to retrain, it tries to revert to the previous link speed. However it calculates that speed from the Link Control 2 register without masking out non-speed bits first. PCIE_LNKCTL2_TLS2SPEED() converts such incorrect values to PCI_SPEED_UNKNOWN (0xff), which in turn causes a WARN splat in pcie_set_target_speed(): pci 0000:00:01.1: [1022:14ed] type 01 class 0x060400 PCIe Root Port pci 0000:00:01.1: broken device, retraining non-functional downstream link at 2.5GT/s pci 0000:00:01.1: retraining failed WARNING: CPU: 1 PID: 1 at drivers/pci/pcie/bwctrl.c:168 pcie_set_target_speed RDX: 0000000000000001 RSI: 00000000000000ff RDI: ffff9acd82efa000 pcie_failed_link_retrain pci_device_add pci_scan_single_device Mask out the non-speed bits in PCIE_LNKCTL2_TLS2SPEED() and PCIE_LNKCAP_SLS2SPEED() so they don't incorrectly return PCI_SPEED_UNKNOWN. Fixes: de9a6c8d5dbf ("PCI/bwctrl: Add pcie_set_target_speed() to set PCIe Link Speed") Reported-by: Andrew Closes: https://lore.kernel.org/r/7iNzXbCGpf8yUMJZBQjLdbjPcXrEJqBxy5-bHfppz0ek-h4_-G93b1KUrm106r2VNF2FV_sSq0nENv4RsRIUGnlYZMlQr2ZD2NyB5sdj5aU=@protonmail.com/ Suggested-by: Maciej W. Rozycki Suggested-by: Ilpo Järvinen Signed-off-by: Jiwei Sun [bhelgaas: commit log, add details from https://lore.kernel.org/r/1c92ef6bcb314ee6977839b46b393282e4f52e74.1750684771.git.lukas@wunner.de] Signed-off-by: Bjorn Helgaas Reviewed-by: Ilpo Järvinen Cc: stable@vger.kernel.org # v6.13+ Link: https://patch.msgid.link/20250123055155.22648-2-sjiwei@163.com --- drivers/pci/pci.h | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index 12215ee72afb..a9d56acca52c 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -391,12 +391,14 @@ void pci_bus_put(struct pci_bus *bus); #define PCIE_LNKCAP_SLS2SPEED(lnkcap) \ ({ \ - ((lnkcap) == PCI_EXP_LNKCAP_SLS_64_0GB ? PCIE_SPEED_64_0GT : \ - (lnkcap) == PCI_EXP_LNKCAP_SLS_32_0GB ? PCIE_SPEED_32_0GT : \ - (lnkcap) == PCI_EXP_LNKCAP_SLS_16_0GB ? PCIE_SPEED_16_0GT : \ - (lnkcap) == PCI_EXP_LNKCAP_SLS_8_0GB ? PCIE_SPEED_8_0GT : \ - (lnkcap) == PCI_EXP_LNKCAP_SLS_5_0GB ? PCIE_SPEED_5_0GT : \ - (lnkcap) == PCI_EXP_LNKCAP_SLS_2_5GB ? PCIE_SPEED_2_5GT : \ + u32 lnkcap_sls = (lnkcap) & PCI_EXP_LNKCAP_SLS; \ + \ + (lnkcap_sls == PCI_EXP_LNKCAP_SLS_64_0GB ? PCIE_SPEED_64_0GT : \ + lnkcap_sls == PCI_EXP_LNKCAP_SLS_32_0GB ? PCIE_SPEED_32_0GT : \ + lnkcap_sls == PCI_EXP_LNKCAP_SLS_16_0GB ? PCIE_SPEED_16_0GT : \ + lnkcap_sls == PCI_EXP_LNKCAP_SLS_8_0GB ? PCIE_SPEED_8_0GT : \ + lnkcap_sls == PCI_EXP_LNKCAP_SLS_5_0GB ? PCIE_SPEED_5_0GT : \ + lnkcap_sls == PCI_EXP_LNKCAP_SLS_2_5GB ? PCIE_SPEED_2_5GT : \ PCI_SPEED_UNKNOWN); \ }) @@ -411,13 +413,17 @@ void pci_bus_put(struct pci_bus *bus); PCI_SPEED_UNKNOWN) #define PCIE_LNKCTL2_TLS2SPEED(lnkctl2) \ - ((lnkctl2) == PCI_EXP_LNKCTL2_TLS_64_0GT ? PCIE_SPEED_64_0GT : \ - (lnkctl2) == PCI_EXP_LNKCTL2_TLS_32_0GT ? PCIE_SPEED_32_0GT : \ - (lnkctl2) == PCI_EXP_LNKCTL2_TLS_16_0GT ? PCIE_SPEED_16_0GT : \ - (lnkctl2) == PCI_EXP_LNKCTL2_TLS_8_0GT ? PCIE_SPEED_8_0GT : \ - (lnkctl2) == PCI_EXP_LNKCTL2_TLS_5_0GT ? PCIE_SPEED_5_0GT : \ - (lnkctl2) == PCI_EXP_LNKCTL2_TLS_2_5GT ? PCIE_SPEED_2_5GT : \ - PCI_SPEED_UNKNOWN) +({ \ + u16 lnkctl2_tls = (lnkctl2) & PCI_EXP_LNKCTL2_TLS; \ + \ + (lnkctl2_tls == PCI_EXP_LNKCTL2_TLS_64_0GT ? PCIE_SPEED_64_0GT : \ + lnkctl2_tls == PCI_EXP_LNKCTL2_TLS_32_0GT ? PCIE_SPEED_32_0GT : \ + lnkctl2_tls == PCI_EXP_LNKCTL2_TLS_16_0GT ? PCIE_SPEED_16_0GT : \ + lnkctl2_tls == PCI_EXP_LNKCTL2_TLS_8_0GT ? PCIE_SPEED_8_0GT : \ + lnkctl2_tls == PCI_EXP_LNKCTL2_TLS_5_0GT ? PCIE_SPEED_5_0GT : \ + lnkctl2_tls == PCI_EXP_LNKCTL2_TLS_2_5GT ? PCIE_SPEED_2_5GT : \ + PCI_SPEED_UNKNOWN); \ +}) /* PCIe speed to Mb/s reduced by encoding overhead */ #define PCIE_SPEED2MBS_ENC(speed) \ From b85af48de3ece4e5bbdb2248a5360a409991cf67 Mon Sep 17 00:00:00 2001 From: Jiwei Sun Date: Thu, 23 Jan 2025 13:51:55 +0800 Subject: [PATCH 3/5] PCI: Adjust the position of reading the Link Control 2 register MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In a89c82249c37 ("PCI: Work around PCIe link training failures"), if the speed limit is set to 2.5 GT/s and the retraining is successful, an attempt will be made to lift the speed limit. One condition for lifting the speed limit is to check whether the link speed field of the Link Control 2 register is PCI_EXP_LNKCTL2_TLS_2_5GT. However, since de9a6c8d5dbf ("PCI/bwctrl: Add pcie_set_target_speed() to set PCIe Link Speed"), the `lnkctl2` local variable does not undergo any changes during the speed limit setting and retraining process. As a result, the code intended to lift the speed limit is not executed. To address this issue, adjust the position of the Link Control 2 register read operation in the code and place it before its use. Fixes: de9a6c8d5dbf ("PCI/bwctrl: Add pcie_set_target_speed() to set PCIe Link Speed") Suggested-by: Maciej W. Rozycki Suggested-by: Ilpo Järvinen Signed-off-by: Jiwei Sun Signed-off-by: Bjorn Helgaas Link: https://patch.msgid.link/20250123055155.22648-3-sjiwei@163.com --- drivers/pci/quirks.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index d7f4ee634263..db6e142b082d 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -105,13 +105,13 @@ int pcie_failed_link_retrain(struct pci_dev *dev) !pcie_cap_has_lnkctl2(dev) || !dev->link_active_reporting) return ret; - pcie_capability_read_word(dev, PCI_EXP_LNKCTL2, &lnkctl2); pcie_capability_read_word(dev, PCI_EXP_LNKSTA, &lnksta); if (!(lnksta & PCI_EXP_LNKSTA_DLLLA) && pcie_lbms_seen(dev, lnksta)) { - u16 oldlnkctl2 = lnkctl2; + u16 oldlnkctl2; pci_info(dev, "broken device, retraining non-functional downstream link at 2.5GT/s\n"); + pcie_capability_read_word(dev, PCI_EXP_LNKCTL2, &oldlnkctl2); ret = pcie_set_target_speed(dev, PCIE_SPEED_2_5GT, false); if (ret) { pci_info(dev, "retraining failed\n"); @@ -123,6 +123,8 @@ int pcie_failed_link_retrain(struct pci_dev *dev) pcie_capability_read_word(dev, PCI_EXP_LNKSTA, &lnksta); } + pcie_capability_read_word(dev, PCI_EXP_LNKCTL2, &lnkctl2); + if ((lnksta & PCI_EXP_LNKSTA_DLLLA) && (lnkctl2 & PCI_EXP_LNKCTL2_TLS) == PCI_EXP_LNKCTL2_TLS_2_5GT && pci_match_id(ids, dev)) { From 91703041697c9d2e8dffe5b3a159198ba0dd24e7 Mon Sep 17 00:00:00 2001 From: Lukas Wunner Date: Fri, 4 Jul 2025 09:38:33 +0200 Subject: [PATCH 4/5] PCI: Allow built-in drivers to use async initial probing The PCI core has historically not allowed built-in drivers to opt in to async initial probing: Drivers may set "PROBE_PREFER_ASYNCHRONOUS", but initial probing always happens synchronously. That's because the PCI core uses device_attach() instead of device_initial_probe(). Should a driver return -EPROBE_DEFER on initial probe, reprobing later on does honor the PROBE_PREFER_ASYNCHRONOUS setting. Modular drivers are also allowed to probe asynchronously, which is inconsistent. The choice of device_attach() is likely not deliberate: It was introduced in 2013 with commit 58d9a38f6fac ("PCI: Skip attaching driver in device_add()"), but asynchronous probing was added two years later with commit 765230b5f084 ("driver-core: add asynchronous probing support for drivers"). According to the kernel-doc of "enum probe_type", "the end goal is to switch the kernel to use asynchronous probing by default". To this end, use device_initial_probe() to allow asynchronous initial probing. The function returns void, making the return value check unnecessary. Initial PCI probing often takes on the order of seconds even on laptops, so this may speed up booting significantly. A small number of PCI drivers already opt in to asynchronous probing. Their maintainers (who are all cc'ed) should watch out for issues, now that asynchronous probing is not just allowed for deferred and modular probing, but also initial probing: hl_pci_driver drivers/accel/habanalabs/common/habanalabs_drv.c cxl_pci_driver drivers/cxl/pci.c quicki2c_driver drivers/hid/intel-thc-hid/intel-quicki2c/pci-quicki2c.c quickspi_driver drivers/hid/intel-thc-hid/intel-quickspi/pci-quickspi.c i801_driver drivers/i2c/busses/i2c-i801.c mei_me_driver drivers/misc/mei/pci-me.c mei_vsc_drv drivers/misc/mei/platform-vsc.c sdhci_driver drivers/mmc/host/sdhci-pci-core.c nvme_driver drivers/nvme/host/pci.c ehci_pci_driver drivers/usb/host/ehci-pci.c hvfb_pci_stub_driver drivers/video/fbdev/hyperv_fb.c All other driver maintainers may test asynchronous probing by specifying the command line parameter "driver_async_probe=drv_name1,drv_name2,...", and on success setting "probe_type = PROBE_PREFER_ASYNCHRONOUS" in the pci_driver struct. Signed-off-by: Lukas Wunner [bhelgaas: updated commit log per https://lore.kernel.org/r/aHYUh7WoDlhHckxd@wunner.de] Signed-off-by: Bjorn Helgaas Link: https://patch.msgid.link/53abe6f5ac7c631f95f5d061aa748b192eda0379.1751614426.git.lukas@wunner.de --- drivers/pci/bus.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/pci/bus.c b/drivers/pci/bus.c index 69048869ef1c..b77fd30bbfd9 100644 --- a/drivers/pci/bus.c +++ b/drivers/pci/bus.c @@ -341,7 +341,6 @@ void pci_bus_add_device(struct pci_dev *dev) { struct device_node *dn = dev->dev.of_node; struct platform_device *pdev; - int retval; /* * Can not put in pci_device_add yet because resources @@ -372,9 +371,7 @@ void pci_bus_add_device(struct pci_dev *dev) if (!dn || of_device_is_available(dn)) pci_dev_allow_binding(dev); - retval = device_attach(&dev->dev); - if (retval < 0 && retval != -EPROBE_DEFER) - pci_warn(dev, "device attach failed (%d)\n", retval); + device_initial_probe(&dev->dev); pci_dev_assign_added(dev); } From 5c0d0ee36f168f6962a710205436533be31c9a42 Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Tue, 22 Jul 2025 08:59:26 -0700 Subject: [PATCH 5/5] PCI: Support Immediate Readiness on devices without PM capabilities Query support for Immediate Readiness irrespective of whether or not the device supports PM capabilities, as nothing in the PCIe spec suggests that Immediate Readiness is in any way dependent on PM functionality. Fixes: d6112f8def51 ("PCI: Add support for Immediate Readiness") Signed-off-by: Sean Christopherson Signed-off-by: Bjorn Helgaas Cc: David Matlack Cc: Vipin Sharma Cc: Aaron Lewis Link: https://patch.msgid.link/20250722155926.352248-1-seanjc@google.com --- drivers/pci/pci.c | 4 ---- drivers/pci/probe.c | 10 ++++++++++ 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index e9448d55113b..d3b059067ba0 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -3205,7 +3205,6 @@ void pci_pm_power_up_and_verify_state(struct pci_dev *pci_dev) void pci_pm_init(struct pci_dev *dev) { int pm; - u16 status; u16 pmc; device_enable_async_suspend(&dev->dev); @@ -3266,9 +3265,6 @@ void pci_pm_init(struct pci_dev *dev) pci_pme_active(dev, false); } - pci_read_config_word(dev, PCI_STATUS, &status); - if (status & PCI_STATUS_IMM_READY) - dev->imm_ready = 1; pci_pm_power_up_and_verify_state(dev); pm_runtime_forbid(&dev->dev); pm_runtime_set_active(&dev->dev); diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 4b8693ec9e4c..1571d4b392a6 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -2595,6 +2595,15 @@ void pcie_report_downtraining(struct pci_dev *dev) __pcie_print_link_status(dev, false); } +static void pci_imm_ready_init(struct pci_dev *dev) +{ + u16 status; + + pci_read_config_word(dev, PCI_STATUS, &status); + if (status & PCI_STATUS_IMM_READY) + dev->imm_ready = 1; +} + static void pci_init_capabilities(struct pci_dev *dev) { pci_ea_init(dev); /* Enhanced Allocation */ @@ -2604,6 +2613,7 @@ static void pci_init_capabilities(struct pci_dev *dev) /* Buffers for saving PCIe and PCI-X capabilities */ pci_allocate_cap_save_buffers(dev); + pci_imm_ready_init(dev); /* Immediate Readiness */ pci_pm_init(dev); /* Power Management */ pci_vpd_init(dev); /* Vital Product Data */ pci_configure_ari(dev); /* Alternative Routing-ID Forwarding */