aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGavin Shan <gwshan@linux.vnet.ibm.com>2014-04-09 11:43:59 +1000
committerEli Qiao <taget@linux.vnet.ibm.com>2014-04-14 10:12:34 +0800
commit699e0a732f49ec2758e2c4abb0a586fa7d12c090 (patch)
tree9c0c28dbab77760ee7dd73b9900f368ab33f73ba
parenta76cb901d67f6c7737d12bbdcadd9fe4a312a339 (diff)
downloadpowerkvm-699e0a732f49ec2758e2c4abb0a586fa7d12c090.tar.gz
powerpc/eeh: Make the delay for PE reset unified
Basically, we have 3 types of resets to fulfil PE reset: fundamental, hot and PHB reset. For the later 2 cases, we need PCI bus reset hold and settlement delay as specified by PCI spec. PowerNV and pSeries platforms are running on top of different firmware and some of the delays have been covered by underly firmware (PowerNV). The patch makes the delays unified to be done in backend, instead of EEH core. Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com> Acked-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
-rw-r--r--arch/powerpc/include/asm/eeh.h10
-rw-r--r--arch/powerpc/kernel/eeh.c14
-rw-r--r--arch/powerpc/platforms/powernv/eeh-ioda.c12
-rw-r--r--arch/powerpc/platforms/pseries/eeh_pseries.c10
4 files changed, 30 insertions, 16 deletions
diff --git a/arch/powerpc/include/asm/eeh.h b/arch/powerpc/include/asm/eeh.h
index 2841ecac4c47e8..b76f58c124ca04 100644
--- a/arch/powerpc/include/asm/eeh.h
+++ b/arch/powerpc/include/asm/eeh.h
@@ -39,6 +39,16 @@ struct device_node;
#define EEH_PROBE_MODE_DEVTREE 0x8 /* From device tree */
/*
+ * Delay for PE reset, all in ms
+ *
+ * PCI specification has reset hold time of 100 milliseconds.
+ * We have 250 milliseconds here. The PCI bus settlement time
+ * is specified as 1.5 seconds and we have 1.8 seconds.
+ */
+#define EEH_PE_RST_HOLD_TIME 250
+#define EEH_PE_RST_SETTLE_TIME 1800
+
+/*
* The struct is used to trace PE related EEH functionality.
* In theory, there will have one instance of the struct to
* be created against particular PE. In nature, PEs corelate
diff --git a/arch/powerpc/kernel/eeh.c b/arch/powerpc/kernel/eeh.c
index ee879bfe75a421..cc85c467151e2b 100644
--- a/arch/powerpc/kernel/eeh.c
+++ b/arch/powerpc/kernel/eeh.c
@@ -576,15 +576,12 @@ int pcibios_set_pcie_reset_state(struct pci_dev *dev, enum pcie_reset_state stat
switch (state) {
case pcie_deassert_reset:
eeh_ops->reset(pe, EEH_RESET_DEACTIVATE);
- msleep(EEH_PE_RESET_HOLD_TIME);
break;
case pcie_hot_reset:
eeh_ops->reset(pe, EEH_RESET_HOT);
- msleep(EEH_PE_RESET_HOLD_TIME);
break;
case pcie_warm_reset:
eeh_ops->reset(pe, EEH_RESET_FUNDAMENTAL);
- msleep(EEH_PE_RESET_SETTLE_TIME);
break;
default:
return -EINVAL;
@@ -639,18 +636,7 @@ static void eeh_reset_pe_once(struct eeh_pe *pe)
else
eeh_ops->reset(pe, EEH_RESET_HOT);
- /* The PCI bus requires that the reset be held high for at least
- * a 100 milliseconds. We wait a bit longer 'just in case'.
- */
- msleep(EEH_PE_RESET_HOLD_TIME);
-
eeh_ops->reset(pe, EEH_RESET_DEACTIVATE);
-
- /* After a PCI slot has been reset, the PCI Express spec requires
- * a 1.5 second idle time for the bus to stabilize, before starting
- * up traffic.
- */
- msleep(EEH_PE_RESET_SETTLE_TIME);
}
/**
diff --git a/arch/powerpc/platforms/powernv/eeh-ioda.c b/arch/powerpc/platforms/powernv/eeh-ioda.c
index 977b4731e872f5..9dec968bbe0678 100644
--- a/arch/powerpc/platforms/powernv/eeh-ioda.c
+++ b/arch/powerpc/platforms/powernv/eeh-ioda.c
@@ -417,9 +417,13 @@ static int ioda_eeh_phb_reset(struct pci_controller *hose, int option)
/*
* Poll state of the PHB until the request is done
- * successfully.
+ * successfully. The PHB reset is usually PHB complete
+ * reset followed by hot reset on root bus. So we also
+ * need the PCI bus settlement delay.
*/
rc = ioda_eeh_phb_poll(phb);
+ if (option == EEH_RESET_DEACTIVATE)
+ msleep(EEH_PE_RST_SETTLE_TIME);
out:
if (rc != OPAL_SUCCESS)
return -EIO;
@@ -457,6 +461,8 @@ static int ioda_eeh_root_reset(struct pci_controller *hose, int option)
/* Poll state of the PHB until the request is done */
rc = ioda_eeh_phb_poll(phb);
+ if (option == EEH_RESET_DEACTIVATE)
+ msleep(EEH_PE_RST_SETTLE_TIME);
out:
if (rc != OPAL_SUCCESS)
return -EIO;
@@ -480,11 +486,15 @@ static int ioda_eeh_bridge_reset(struct pci_dev *dev, int option)
eeh_ops->read_config(dn, PCI_BRIDGE_CONTROL, 2, &ctrl);
ctrl |= PCI_BRIDGE_CTL_BUS_RESET;
eeh_ops->write_config(dn, PCI_BRIDGE_CONTROL, 2, ctrl);
+
+ msleep(EEH_PE_RST_HOLD_TIME);
break;
case EEH_RESET_DEACTIVATE:
eeh_ops->read_config(dn, PCI_BRIDGE_CONTROL, 2, &ctrl);
ctrl &= ~PCI_BRIDGE_CTL_BUS_RESET;
eeh_ops->write_config(dn, PCI_BRIDGE_CONTROL, 2, ctrl);
+
+ msleep(EEH_PE_RST_SETTLE_TIME);
break;
}
diff --git a/arch/powerpc/platforms/pseries/eeh_pseries.c b/arch/powerpc/platforms/pseries/eeh_pseries.c
index 75045454efed2d..4e68a05950bae3 100644
--- a/arch/powerpc/platforms/pseries/eeh_pseries.c
+++ b/arch/powerpc/platforms/pseries/eeh_pseries.c
@@ -529,11 +529,19 @@ static int pseries_eeh_reset(struct eeh_pe *pe, int option)
/* If fundamental-reset not supported, try hot-reset */
if (option == EEH_RESET_FUNDAMENTAL &&
ret == -8) {
+ option = EEH_RESET_HOT;
ret = rtas_call(ibm_set_slot_reset, 4, 1, NULL,
config_addr, BUID_HI(pe->phb->buid),
- BUID_LO(pe->phb->buid), EEH_RESET_HOT);
+ BUID_LO(pe->phb->buid), option);
}
+ /* We need reset hold or settlement delay */
+ if (option == EEH_RESET_FUNDAMENTAL ||
+ option == EEH_RESET_HOT)
+ msleep(EEH_PE_RST_HOLD_TIME);
+ else
+ msleep(EEH_PE_RST_SETTLE_TIME);
+
return ret;
}