From: Manivannan Sadhasivam Date: Thu, 12 Sep 2024 05:30:25 +0000 (+0530) Subject: PCI: Pass domain number to pci_bus_release_domain_nr() explicitly X-Git-Tag: v6.12-rc1~96^2~6^2 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=0cca961a026177af69044f10d6ae76d8ce043764;p=thirdparty%2Fkernel%2Flinux.git PCI: Pass domain number to pci_bus_release_domain_nr() explicitly 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 --- diff --git a/drivers/pci/endpoint/pci-epc-core.c b/drivers/pci/endpoint/pci-epc-core.c index 085a2de8b923d..17f0071092550 100644 --- a/drivers/pci/endpoint/pci-epc-core.c +++ b/drivers/pci/endpoint/pci-epc-core.c @@ -840,7 +840,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 e3a49f66982d5..b86693c917534 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -6801,16 +6801,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) @@ -6819,11 +6819,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 b14b9876c0303..e9e56bbb3b59d 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -1061,7 +1061,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 910387e5bdbf9..d2523fdf9bae4 100644 --- a/drivers/pci/remove.c +++ b/drivers/pci/remove.c @@ -163,7 +163,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 4cf89a4b4cbcf..37d97bef060f9 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -1884,7 +1884,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 */