From aa23eae5b033f94ad89201141ab3e3c095c6d5b9 Mon Sep 17 00:00:00 2001 From: Manivannan Sadhasivam Date: Wed, 12 Mar 2025 22:51:00 +0900 Subject: [PATCH] PCI: Pass domain number to pci_bus_release_domain_nr() explicitly MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit BugLink: https://bugs.launchpad.net/bugs/2102118 commit 0cca961a026177af69044f10d6ae76d8ce043764 upstream. The pci_bus_release_domain_nr() API is supposed to free the domain number allocated by pci_bus_find_domain_nr(). Most of the callers of pci_bus_find_domain_nr(), store the domain number in pci_bus::domain_nr. As such, the pci_bus_release_domain_nr() implicitly frees the domain number by dereferencing 'struct pci_bus'. However, one of the callers of this API, the PCI endpoint subsystem, doesn't have 'struct pci_bus', so it only passes NULL. Due to this, the API will end up dereferencing the NULL pointer. To fix this issue, pass the domain number to this API explicitly. Since 'struct pci_bus' is not used for anything else other than extracting the domain number, it makes sense to pass the domain number directly. Fixes: 0328947c5032 ("PCI: endpoint: Assign PCI domain number for endpoint controllers") Closes: https://lore.kernel.org/linux-pci/c0c40ddb-bf64-4b22-9dd1-8dbb18aa2813@stanley.mountain Link: https://lore.kernel.org/linux-pci/20240912053025.25314-1-manivannan.sadhasivam@linaro.org Reported-by: Dan Carpenter Signed-off-by: Manivannan Sadhasivam [kwilczynski: commit log] Signed-off-by: Krzysztof WilczyƄski Signed-off-by: Greg Kroah-Hartman (cherry picked from commit a61c55fa3a8af128448a3c09574369d203b6a809 linux-6.11.y) [koichiroden: follow-up fix for a backport for LP#2097301, which acts as a prerequisite here] Signed-off-by: Koichiro Den Signed-off-by: Stefan Bader --- drivers/pci/endpoint/pci-epc-core.c | 2 +- drivers/pci/pci.c | 14 +++++++------- drivers/pci/probe.c | 2 +- drivers/pci/remove.c | 2 +- include/linux/pci.h | 2 +- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/drivers/pci/endpoint/pci-epc-core.c b/drivers/pci/endpoint/pci-epc-core.c index 7ef796e30a8d..aacdb8a84ac0 100644 --- a/drivers/pci/endpoint/pci-epc-core.c +++ b/drivers/pci/endpoint/pci-epc-core.c @@ -795,7 +795,7 @@ void pci_epc_destroy(struct pci_epc *epc) device_unregister(&epc->dev); #ifdef CONFIG_PCI_DOMAINS_GENERIC - pci_bus_release_domain_nr(NULL, &epc->dev); + pci_bus_release_domain_nr(&epc->dev, epc->domain_nr); #endif } EXPORT_SYMBOL_GPL(pci_epc_destroy); diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 2e144fd6fb4a..e671f8349c07 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -7042,16 +7042,16 @@ static int of_pci_bus_find_domain_nr(struct device *parent) return ida_alloc(&pci_domain_nr_dynamic_ida, GFP_KERNEL); } -static void of_pci_bus_release_domain_nr(struct pci_bus *bus, struct device *parent) +static void of_pci_bus_release_domain_nr(struct device *parent, int domain_nr) { - if (bus->domain_nr < 0) + if (domain_nr < 0) return; /* Release domain from IDA where it was allocated. */ - if (of_get_pci_domain_nr(parent->of_node) == bus->domain_nr) - ida_free(&pci_domain_nr_static_ida, bus->domain_nr); + if (of_get_pci_domain_nr(parent->of_node) == domain_nr) + ida_free(&pci_domain_nr_static_ida, domain_nr); else - ida_free(&pci_domain_nr_dynamic_ida, bus->domain_nr); + ida_free(&pci_domain_nr_dynamic_ida, domain_nr); } int pci_bus_find_domain_nr(struct pci_bus *bus, struct device *parent) @@ -7060,11 +7060,11 @@ int pci_bus_find_domain_nr(struct pci_bus *bus, struct device *parent) acpi_pci_bus_find_domain_nr(bus); } -void pci_bus_release_domain_nr(struct pci_bus *bus, struct device *parent) +void pci_bus_release_domain_nr(struct device *parent, int domain_nr) { if (!acpi_disabled) return; - of_pci_bus_release_domain_nr(bus, parent); + of_pci_bus_release_domain_nr(parent, domain_nr); } #endif diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index cda88523f8da..87ee74206dce 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -1090,7 +1090,7 @@ unregister: free: #ifdef CONFIG_PCI_DOMAINS_GENERIC - pci_bus_release_domain_nr(bus, parent); + pci_bus_release_domain_nr(parent, bus->domain_nr); #endif kfree(bus); return err; diff --git a/drivers/pci/remove.c b/drivers/pci/remove.c index d749ea8250d6..c4b79e1a9758 100644 --- a/drivers/pci/remove.c +++ b/drivers/pci/remove.c @@ -162,7 +162,7 @@ void pci_remove_root_bus(struct pci_bus *bus) #ifdef CONFIG_PCI_DOMAINS_GENERIC /* Release domain_nr if it was dynamically allocated */ if (host_bridge->domain_nr == PCI_DOMAIN_NR_NOT_SET) - pci_bus_release_domain_nr(bus, host_bridge->dev.parent); + pci_bus_release_domain_nr(host_bridge->dev.parent, bus->domain_nr); #endif pci_remove_bus(bus); diff --git a/include/linux/pci.h b/include/linux/pci.h index b28c03acc451..e9278cb523f0 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -1891,7 +1891,7 @@ static inline int acpi_pci_bus_find_domain_nr(struct pci_bus *bus) { return 0; } #endif int pci_bus_find_domain_nr(struct pci_bus *bus, struct device *parent); -void pci_bus_release_domain_nr(struct pci_bus *bus, struct device *parent); +void pci_bus_release_domain_nr(struct device *parent, int domain_nr); #endif /* Some architectures require additional setup to direct VGA traffic */