Function pnv_pci_reset_secondary_bus() is used to reset specified PCI bus, which is leaded by root complex or PCI bridge. That means the function shouldn't be called on PCI root bus and the patch removes the logic for the case.
Also, some adapters may require fundamental reset to reload their firmwares. Otherwise, they will fail to load their firmwares and those adapters can't work properly after reset, as being reported in VFIO pass-through scenario. The patch checks the reset type required by the child adapters of the PCI bus and issue fundamental reset if necessary. Signed-off-by: Gavin Shan <gws...@linux.vnet.ibm.com> --- arch/powerpc/platforms/powernv/eeh-ioda.c | 34 +++++++++++++++++++++++-------- 1 file changed, 25 insertions(+), 9 deletions(-) diff --git a/arch/powerpc/platforms/powernv/eeh-ioda.c b/arch/powerpc/platforms/powernv/eeh-ioda.c index 78d94df..cf38781 100644 --- a/arch/powerpc/platforms/powernv/eeh-ioda.c +++ b/arch/powerpc/platforms/powernv/eeh-ioda.c @@ -636,18 +636,34 @@ static int ioda_eeh_bridge_reset(struct pci_dev *dev, int option) return (rc == OPAL_SUCCESS) ? 0 : -EIO; } -void pnv_pci_reset_secondary_bus(struct pci_dev *dev) +static int pnv_pci_dev_reset_type(struct pci_dev *pdev, void *data) { - struct pci_controller *hose; + int *freset = data; - if (pci_is_root_bus(dev->bus)) { - hose = pci_bus_to_host(dev->bus); - ioda_eeh_phb_reset(hose, EEH_RESET_HOT); - ioda_eeh_phb_reset(hose, EEH_RESET_DEACTIVATE); - } else { - ioda_eeh_bridge_reset(dev, EEH_RESET_HOT); - ioda_eeh_bridge_reset(dev, EEH_RESET_DEACTIVATE); + /* + * Stop the iteration immediately if any one PCI + * device requires fundamental reset + */ + *freset |= pdev->needs_freset; + return *freset; +} + +void pnv_pci_reset_secondary_bus(struct pci_dev *pdev) +{ + int option = EEH_RESET_HOT; + int freset = 0; + + /* Check if we need issue fundamental reset */ + if (pdev->subordinate) { + pci_walk_bus(pdev->subordinate, + pnv_pci_dev_reset_type, &freset); + if (freset) + option = EEH_RESET_FUNDAMENTAL; } + + /* Issue required reset type */ + ioda_eeh_bridge_reset(pdev, option); + ioda_eeh_bridge_reset(pdev, EEH_RESET_DEACTIVATE); } /** -- 1.8.3.2 _______________________________________________ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev