From 3f8c4959fc18e477801386a625e726c59f52a2c4 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Mon, 3 Mar 2025 15:02:17 -0600 Subject: [PATCH 1/5] PCI: Enable Configuration RRS SV early Following a reset, a Function may respond to Config Requests with Request Retry Status (RRS) Completion Status to indicate that it is temporarily unable to process the Request, but will be able to process the Request in the future (PCIe r6.0, sec 2.3.1). If the Configuration RRS Software Visibility feature is enabled and a Root Complex receives RRS for a config read of the Vendor ID, the Root Complex completes the Request to the host by returning PCI_VENDOR_ID_PCI_SIG, 0x0001 (sec 2.3.2). The Config RRS SV feature applies only to Root Ports and is not directly related to pci_scan_bridge_extend(). Move the RRS SV enable to set_pcie_port_type() where we handle other PCIe-specific configuration. Link: https://lore.kernel.org/r/20250303210217.199504-1-helgaas@kernel.org Signed-off-by: Bjorn Helgaas --- drivers/pci/probe.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index b6536ed599c3..0b013b196d00 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -1373,8 +1373,6 @@ static int pci_scan_bridge_extend(struct pci_bus *bus, struct pci_dev *dev, pci_write_config_word(dev, PCI_BRIDGE_CONTROL, bctl & ~PCI_BRIDGE_CTL_MASTER_ABORT); - pci_enable_rrs_sv(dev); - if ((secondary || subordinate) && !pcibios_assign_all_busses() && !is_cardbus && !broken) { unsigned int cmax, buses; @@ -1615,6 +1613,11 @@ void set_pcie_port_type(struct pci_dev *pdev) pdev->pcie_cap = pos; pci_read_config_word(pdev, pos + PCI_EXP_FLAGS, ®16); pdev->pcie_flags_reg = reg16; + + type = pci_pcie_type(pdev); + if (type == PCI_EXP_TYPE_ROOT_PORT) + pci_enable_rrs_sv(pdev); + pci_read_config_dword(pdev, pos + PCI_EXP_DEVCAP, &pdev->devcap); pdev->pcie_mpss = FIELD_GET(PCI_EXP_DEVCAP_PAYLOAD, pdev->devcap); @@ -1631,7 +1634,6 @@ void set_pcie_port_type(struct pci_dev *pdev) * correctly so detect impossible configurations here and correct * the port type accordingly. */ - type = pci_pcie_type(pdev); if (type == PCI_EXP_TYPE_DOWNSTREAM) { /* * If pdev claims to be downstream port but the parent From a7eb9124d92be1330afd18c98e4f28f297b50cb8 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Fri, 14 Feb 2025 18:03:01 -0600 Subject: [PATCH 2/5] PCI: Cache offset of Resizable BAR capability MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously most resizable BAR interfaces (pci_rebar_get_possible_sizes(), pci_rebar_set_size(), etc) as well as pci_restore_state() searched config space for a Resizable BAR capability. Most devices don't have such a capability, so this is wasted effort, especially for pci_restore_state(). Search for a Resizable BAR capability once at enumeration-time and cache the offset so we don't have to search every time we need it. No functional change intended. Link: https://lore.kernel.org/r/20250215000301.175097-3-helgaas@kernel.org Signed-off-by: Bjorn Helgaas Reviewed-by: Ilpo Järvinen --- drivers/pci/pci.c | 9 +++++++-- drivers/pci/pci.h | 1 + drivers/pci/probe.c | 1 + include/linux/pci.h | 1 + 4 files changed, 10 insertions(+), 2 deletions(-) diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 869d204a70a3..cda4d9af50b5 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -1871,7 +1871,7 @@ static void pci_restore_rebar_state(struct pci_dev *pdev) unsigned int pos, nbars, i; u32 ctrl; - pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_REBAR); + pos = pdev->rebar_cap; if (!pos) return; @@ -3718,6 +3718,11 @@ void pci_acs_init(struct pci_dev *dev) pci_enable_acs(dev); } +void pci_rebar_init(struct pci_dev *pdev) +{ + pdev->rebar_cap = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_REBAR); +} + /** * pci_rebar_find_pos - find position of resize ctrl reg for BAR * @pdev: PCI device @@ -3732,7 +3737,7 @@ static int pci_rebar_find_pos(struct pci_dev *pdev, int bar) unsigned int pos, nbars, i; u32 ctrl; - pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_REBAR); + pos = pdev->rebar_cap; if (!pos) return -ENOTSUPP; diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index 01e51db8d285..d7b46ddfd6d2 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -799,6 +799,7 @@ static inline int acpi_get_rc_resources(struct device *dev, const char *hid, } #endif +void pci_rebar_init(struct pci_dev *pdev); int pci_rebar_get_current_size(struct pci_dev *pdev, int bar); int pci_rebar_set_size(struct pci_dev *pdev, int bar, int size); static inline u64 pci_rebar_size_to_bytes(int size) diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 0b013b196d00..5f04b8d9c736 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -2566,6 +2566,7 @@ static void pci_init_capabilities(struct pci_dev *dev) pci_rcec_init(dev); /* Root Complex Event Collector */ pci_doe_init(dev); /* Data Object Exchange */ pci_tph_init(dev); /* TLP Processing Hints */ + pci_rebar_init(dev); /* Resizable BAR */ pcie_report_downtraining(dev); pci_init_reset_methods(dev); diff --git a/include/linux/pci.h b/include/linux/pci.h index 47b31ad724fa..9e5bbd996c83 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -353,6 +353,7 @@ struct pci_dev { struct pci_dev *rcec; /* Associated RCEC device */ #endif u32 devcap; /* PCIe Device Capabilities */ + u16 rebar_cap; /* Resizable BAR capability offset */ u8 pcie_cap; /* PCIe capability offset */ u8 msi_cap; /* MSI capability offset */ u8 msix_cap; /* MSI-X capability offset */ From 804443c1f27883926de94c849d91f5b7d7d696e9 Mon Sep 17 00:00:00 2001 From: Ma Ke Date: Tue, 25 Feb 2025 10:14:40 +0800 Subject: [PATCH 3/5] PCI: Fix reference leak in pci_register_host_bridge() If device_register() fails, call put_device() to give up the reference to avoid a memory leak, per the comment at device_register(). Found by code review. Link: https://lore.kernel.org/r/20250225021440.3130264-1-make24@iscas.ac.cn Fixes: 37d6a0a6f470 ("PCI: Add pci_register_host_bridge() interface") Signed-off-by: Ma Ke [bhelgaas: squash Dan Carpenter's double free fix from https://lore.kernel.org/r/db806a6c-a91b-4e5a-a84b-6b7e01bdac85@stanley.mountain] Signed-off-by: Bjorn Helgaas Cc: stable@vger.kernel.org --- drivers/pci/probe.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 5f04b8d9c736..dc37a3c0a977 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -953,6 +953,7 @@ static int pci_register_host_bridge(struct pci_host_bridge *bridge) resource_size_t offset, next_offset; LIST_HEAD(resources); struct resource *res, *next_res; + bool bus_registered = false; char addr[64], *fmt; const char *name; int err; @@ -1017,6 +1018,7 @@ static int pci_register_host_bridge(struct pci_host_bridge *bridge) name = dev_name(&bus->dev); err = device_register(&bus->dev); + bus_registered = true; if (err) goto unregister; @@ -1103,12 +1105,15 @@ static int pci_register_host_bridge(struct pci_host_bridge *bridge) unregister: put_device(&bridge->dev); device_del(&bridge->dev); - free: #ifdef CONFIG_PCI_DOMAINS_GENERIC pci_bus_release_domain_nr(parent, bus->domain_nr); #endif - kfree(bus); + if (bus_registered) + put_device(&bus->dev); + else + kfree(bus); + return err; } From 1f2768b6a3ee77a295106e3a5d68458064923ede Mon Sep 17 00:00:00 2001 From: Ma Ke Date: Sun, 2 Feb 2025 14:23:57 +0800 Subject: [PATCH 4/5] PCI: Fix reference leak in pci_alloc_child_bus() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If device_register(&child->dev) fails, call put_device() to explicitly release child->dev, per the comment at device_register(). Found by code review. Link: https://lore.kernel.org/r/20250202062357.872971-1-make24@iscas.ac.cn Fixes: 4f535093cf8f ("PCI: Put pci_dev in device tree as early as possible") Signed-off-by: Ma Ke Signed-off-by: Bjorn Helgaas Reviewed-by: Ilpo Järvinen Cc: stable@vger.kernel.org --- drivers/pci/probe.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index dc37a3c0a977..088131a74d7d 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -1222,7 +1222,10 @@ static struct pci_bus *pci_alloc_child_bus(struct pci_bus *parent, add_dev: pci_set_bus_msi_domain(child); ret = device_register(&child->dev); - WARN_ON(ret < 0); + if (WARN_ON(ret < 0)) { + put_device(&child->dev); + return NULL; + } pcibios_add_bus(child); From 6e8d06e5096c80cbf41313b4a204f43071ca42be Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 7 Mar 2025 11:46:34 +0300 Subject: [PATCH 5/5] PCI: Remove stray put_device() in pci_register_host_bridge() This put_device() was accidentally left over from when we changed the code from using device_register() to calling device_add(). Delete it. Link: https://lore.kernel.org/r/55b24870-89fb-4c91-b85d-744e35db53c2@stanley.mountain Fixes: 9885440b16b8 ("PCI: Fix pci_host_bridge struct device release/free handling") Signed-off-by: Dan Carpenter Signed-off-by: Bjorn Helgaas --- drivers/pci/probe.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 088131a74d7d..1448f65cc191 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -996,10 +996,9 @@ static int pci_register_host_bridge(struct pci_host_bridge *bridge) /* Temporarily move resources off the list */ list_splice_init(&bridge->windows, &resources); err = device_add(&bridge->dev); - if (err) { - put_device(&bridge->dev); + if (err) goto free; - } + bus->bridge = get_device(&bridge->dev); device_enable_async_suspend(bus->bridge); pci_set_bus_of_node(bus);