| From db2173198b9513f7add8009f225afa1f1c79bcc6 Mon Sep 17 00:00:00 2001 |
| From: Benjamin Herrenschmidt <benh@kernel.crashing.org> |
| Date: Fri, 17 Aug 2018 17:30:39 +1000 |
| Subject: powerpc/powernv/pci: Work around races in PCI bridge enabling |
| |
| From: Benjamin Herrenschmidt <benh@kernel.crashing.org> |
| |
| commit db2173198b9513f7add8009f225afa1f1c79bcc6 upstream. |
| |
| The generic code is racy when multiple children of a PCI bridge try to |
| enable it simultaneously. |
| |
| This leads to drivers trying to access a device through a |
| not-yet-enabled bridge, and this EEH errors under various |
| circumstances when using parallel driver probing. |
| |
| There is work going on to fix that properly in the PCI core but it |
| will take some time. |
| |
| x86 gets away with it because (outside of hotplug), the BIOS enables |
| all the bridges at boot time. |
| |
| This patch does the same thing on powernv by enabling all bridges that |
| have child devices at boot time, thus avoiding subsequent races. It's |
| suitable for backporting to stable and distros, while the proper PCI |
| fix will probably be significantly more invasive. |
| |
| Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> |
| Cc: stable@vger.kernel.org |
| Signed-off-by: Michael Ellerman <mpe@ellerman.id.au> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| arch/powerpc/platforms/powernv/pci-ioda.c | 37 ++++++++++++++++++++++++++++++ |
| 1 file changed, 37 insertions(+) |
| |
| --- a/arch/powerpc/platforms/powernv/pci-ioda.c |
| +++ b/arch/powerpc/platforms/powernv/pci-ioda.c |
| @@ -3286,12 +3286,49 @@ static void pnv_pci_ioda_create_dbgfs(vo |
| #endif /* CONFIG_DEBUG_FS */ |
| } |
| |
| +static void pnv_pci_enable_bridge(struct pci_bus *bus) |
| +{ |
| + struct pci_dev *dev = bus->self; |
| + struct pci_bus *child; |
| + |
| + /* Empty bus ? bail */ |
| + if (list_empty(&bus->devices)) |
| + return; |
| + |
| + /* |
| + * If there's a bridge associated with that bus enable it. This works |
| + * around races in the generic code if the enabling is done during |
| + * parallel probing. This can be removed once those races have been |
| + * fixed. |
| + */ |
| + if (dev) { |
| + int rc = pci_enable_device(dev); |
| + if (rc) |
| + pci_err(dev, "Error enabling bridge (%d)\n", rc); |
| + pci_set_master(dev); |
| + } |
| + |
| + /* Perform the same to child busses */ |
| + list_for_each_entry(child, &bus->children, node) |
| + pnv_pci_enable_bridge(child); |
| +} |
| + |
| +static void pnv_pci_enable_bridges(void) |
| +{ |
| + struct pci_controller *hose; |
| + |
| + list_for_each_entry(hose, &hose_list, list_node) |
| + pnv_pci_enable_bridge(hose->bus); |
| +} |
| + |
| static void pnv_pci_ioda_fixup(void) |
| { |
| pnv_pci_ioda_setup_PEs(); |
| pnv_pci_ioda_setup_iommu_api(); |
| pnv_pci_ioda_create_dbgfs(); |
| |
| + pnv_pci_enable_bridges(); |
| + |
| #ifdef CONFIG_EEH |
| eeh_init(); |
| eeh_addr_cache_build(); |