diff mbox

[4/5] powerpc/powernv: Issue fundamental reset if required

Message ID 1416868727-5814-5-git-send-email-gwshan@linux.vnet.ibm.com (mailing list archive)
State Changes Requested
Headers show

Commit Message

Gavin Shan Nov. 24, 2014, 10:38 p.m. UTC
pnv_pci_reset_secondary_bus() is the backend for resetting the
secondary bus for the specified PCI bridge. We always issue hot
reset, which isn't enough for some devices who requires fundamental
reset explicitly. The patch switches to fundamental reset if the
devices ask for that.

Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com>
---
 arch/powerpc/platforms/powernv/eeh-ioda.c | 34 +++++++++++++++++++++++--------
 1 file changed, 25 insertions(+), 9 deletions(-)
diff mbox

Patch

diff --git a/arch/powerpc/platforms/powernv/eeh-ioda.c b/arch/powerpc/platforms/powernv/eeh-ioda.c
index d02a696..4bf2fb5 100644
--- a/arch/powerpc/platforms/powernv/eeh-ioda.c
+++ b/arch/powerpc/platforms/powernv/eeh-ioda.c
@@ -650,18 +650,34 @@  static int ioda_eeh_bridge_reset(struct pci_dev *dev, int option)
 	return 0;
 }
 
+static int pnv_pci_dev_reset_type(struct pci_dev *pdev, void *data)
+{
+	int *freset = data;
+
+	/*
+	 * Stop the iteration immediately if any one
+	 * PCI device requires fundamental reset
+	 */
+	*freset |= pdev->needs_freset;
+	return *freset;
+}
+
+/*
+ * When the function is called, there should have
+ * valid bridge. We don't need cover root bus here
+ */
 void pnv_pci_reset_secondary_bus(struct pci_dev *dev)
 {
-	struct pci_controller *hose;
+	int option = EEH_RESET_HOT;
+	int freset = 0;
 
-	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);
-	}
+	/* Need fundamental reset ? */
+	pci_walk_bus(dev->subordinate, pnv_pci_dev_reset_type, &freset);
+	if (freset)
+		option = EEH_RESET_FUNDAMENTAL;
+
+	ioda_eeh_bridge_reset(dev, option);
+	ioda_eeh_bridge_reset(dev, EEH_RESET_DEACTIVATE);
 }
 
 /**