|
@@ -127,6 +127,9 @@ static int __init pcie_port_pm_setup(char *str)
|
|
|
}
|
|
|
__setup("pcie_port_pm=", pcie_port_pm_setup);
|
|
|
|
|
|
+/* Time to wait after a reset for device to become responsive */
|
|
|
+#define PCIE_RESET_READY_POLL_MS 60000
|
|
|
+
|
|
|
/**
|
|
|
* pci_bus_max_busnr - returns maximum PCI bus number of given bus' children
|
|
|
* @bus: pointer to PCI bus structure to search
|
|
@@ -3969,20 +3972,13 @@ int pci_wait_for_pending_transaction(struct pci_dev *dev)
|
|
|
}
|
|
|
EXPORT_SYMBOL(pci_wait_for_pending_transaction);
|
|
|
|
|
|
-static void pci_flr_wait(struct pci_dev *dev)
|
|
|
+static int pci_dev_wait(struct pci_dev *dev, char *reset_type, int timeout)
|
|
|
{
|
|
|
- int delay = 1, timeout = 60000;
|
|
|
+ int delay = 1;
|
|
|
u32 id;
|
|
|
|
|
|
/*
|
|
|
- * Per PCIe r3.1, sec 6.6.2, a device must complete an FLR within
|
|
|
- * 100ms, but may silently discard requests while the FLR is in
|
|
|
- * progress. Wait 100ms before trying to access the device.
|
|
|
- */
|
|
|
- msleep(100);
|
|
|
-
|
|
|
- /*
|
|
|
- * After 100ms, the device should not silently discard config
|
|
|
+ * After reset, the device should not silently discard config
|
|
|
* requests, but it may still indicate that it needs more time by
|
|
|
* responding to them with CRS completions. The Root Port will
|
|
|
* generally synthesize ~0 data to complete the read (except when
|
|
@@ -3996,14 +3992,14 @@ static void pci_flr_wait(struct pci_dev *dev)
|
|
|
pci_read_config_dword(dev, PCI_COMMAND, &id);
|
|
|
while (id == ~0) {
|
|
|
if (delay > timeout) {
|
|
|
- pci_warn(dev, "not ready %dms after FLR; giving up\n",
|
|
|
- 100 + delay - 1);
|
|
|
- return;
|
|
|
+ pci_warn(dev, "not ready %dms after %s; giving up\n",
|
|
|
+ delay - 1, reset_type);
|
|
|
+ return -ENOTTY;
|
|
|
}
|
|
|
|
|
|
if (delay > 1000)
|
|
|
- pci_info(dev, "not ready %dms after FLR; waiting\n",
|
|
|
- 100 + delay - 1);
|
|
|
+ pci_info(dev, "not ready %dms after %s; waiting\n",
|
|
|
+ delay - 1, reset_type);
|
|
|
|
|
|
msleep(delay);
|
|
|
delay *= 2;
|
|
@@ -4011,7 +4007,10 @@ static void pci_flr_wait(struct pci_dev *dev)
|
|
|
}
|
|
|
|
|
|
if (delay > 1000)
|
|
|
- pci_info(dev, "ready %dms after FLR\n", 100 + delay - 1);
|
|
|
+ pci_info(dev, "ready %dms after %s\n", delay - 1,
|
|
|
+ reset_type);
|
|
|
+
|
|
|
+ return 0;
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -4040,13 +4039,21 @@ static bool pcie_has_flr(struct pci_dev *dev)
|
|
|
* device supports FLR before calling this function, e.g. by using the
|
|
|
* pcie_has_flr() helper.
|
|
|
*/
|
|
|
-void pcie_flr(struct pci_dev *dev)
|
|
|
+int pcie_flr(struct pci_dev *dev)
|
|
|
{
|
|
|
if (!pci_wait_for_pending_transaction(dev))
|
|
|
pci_err(dev, "timed out waiting for pending transaction; performing function level reset anyway\n");
|
|
|
|
|
|
pcie_capability_set_word(dev, PCI_EXP_DEVCTL, PCI_EXP_DEVCTL_BCR_FLR);
|
|
|
- pci_flr_wait(dev);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Per PCIe r4.0, sec 6.6.2, a device must complete an FLR within
|
|
|
+ * 100ms, but may silently discard requests while the FLR is in
|
|
|
+ * progress. Wait 100ms before trying to access the device.
|
|
|
+ */
|
|
|
+ msleep(100);
|
|
|
+
|
|
|
+ return pci_dev_wait(dev, "FLR", PCIE_RESET_READY_POLL_MS);
|
|
|
}
|
|
|
EXPORT_SYMBOL_GPL(pcie_flr);
|
|
|
|
|
@@ -4079,8 +4086,16 @@ static int pci_af_flr(struct pci_dev *dev, int probe)
|
|
|
pci_err(dev, "timed out waiting for pending transaction; performing AF function level reset anyway\n");
|
|
|
|
|
|
pci_write_config_byte(dev, pos + PCI_AF_CTRL, PCI_AF_CTRL_FLR);
|
|
|
- pci_flr_wait(dev);
|
|
|
- return 0;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Per Advanced Capabilities for Conventional PCI ECN, 13 April 2006,
|
|
|
+ * updated 27 July 2006; a device must complete an FLR within
|
|
|
+ * 100ms, but may silently discard requests while the FLR is in
|
|
|
+ * progress. Wait 100ms before trying to access the device.
|
|
|
+ */
|
|
|
+ msleep(100);
|
|
|
+
|
|
|
+ return pci_dev_wait(dev, "AF_FLR", PCIE_RESET_READY_POLL_MS);
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -4125,7 +4140,7 @@ static int pci_pm_reset(struct pci_dev *dev, int probe)
|
|
|
pci_write_config_word(dev, dev->pm_cap + PCI_PM_CTRL, csr);
|
|
|
pci_dev_d3_sleep(dev);
|
|
|
|
|
|
- return 0;
|
|
|
+ return pci_dev_wait(dev, "PM D3->D0", PCIE_RESET_READY_POLL_MS);
|
|
|
}
|
|
|
|
|
|
void pci_reset_secondary_bus(struct pci_dev *dev)
|
|
@@ -4167,9 +4182,11 @@ void __weak pcibios_reset_secondary_bus(struct pci_dev *dev)
|
|
|
* Use the bridge control register to assert reset on the secondary bus.
|
|
|
* Devices on the secondary bus are left in power-on state.
|
|
|
*/
|
|
|
-void pci_reset_bridge_secondary_bus(struct pci_dev *dev)
|
|
|
+int pci_reset_bridge_secondary_bus(struct pci_dev *dev)
|
|
|
{
|
|
|
pcibios_reset_secondary_bus(dev);
|
|
|
+
|
|
|
+ return pci_dev_wait(dev, "bus reset", PCIE_RESET_READY_POLL_MS);
|
|
|
}
|
|
|
EXPORT_SYMBOL_GPL(pci_reset_bridge_secondary_bus);
|
|
|
|
|
@@ -4332,8 +4349,9 @@ int __pci_reset_function_locked(struct pci_dev *dev)
|
|
|
if (rc != -ENOTTY)
|
|
|
return rc;
|
|
|
if (pcie_has_flr(dev)) {
|
|
|
- pcie_flr(dev);
|
|
|
- return 0;
|
|
|
+ rc = pcie_flr(dev);
|
|
|
+ if (rc != -ENOTTY)
|
|
|
+ return rc;
|
|
|
}
|
|
|
rc = pci_af_flr(dev, 0);
|
|
|
if (rc != -ENOTTY)
|
|
@@ -4403,9 +4421,8 @@ int pci_reset_function(struct pci_dev *dev)
|
|
|
{
|
|
|
int rc;
|
|
|
|
|
|
- rc = pci_probe_reset_function(dev);
|
|
|
- if (rc)
|
|
|
- return rc;
|
|
|
+ if (!dev->reset_fn)
|
|
|
+ return -ENOTTY;
|
|
|
|
|
|
pci_dev_lock(dev);
|
|
|
pci_dev_save_and_disable(dev);
|
|
@@ -4440,9 +4457,8 @@ int pci_reset_function_locked(struct pci_dev *dev)
|
|
|
{
|
|
|
int rc;
|
|
|
|
|
|
- rc = pci_probe_reset_function(dev);
|
|
|
- if (rc)
|
|
|
- return rc;
|
|
|
+ if (!dev->reset_fn)
|
|
|
+ return -ENOTTY;
|
|
|
|
|
|
pci_dev_save_and_disable(dev);
|
|
|
|
|
@@ -4464,18 +4480,17 @@ int pci_try_reset_function(struct pci_dev *dev)
|
|
|
{
|
|
|
int rc;
|
|
|
|
|
|
- rc = pci_probe_reset_function(dev);
|
|
|
- if (rc)
|
|
|
- return rc;
|
|
|
+ if (!dev->reset_fn)
|
|
|
+ return -ENOTTY;
|
|
|
|
|
|
if (!pci_dev_trylock(dev))
|
|
|
return -EAGAIN;
|
|
|
|
|
|
pci_dev_save_and_disable(dev);
|
|
|
rc = __pci_reset_function_locked(dev);
|
|
|
+ pci_dev_restore(dev);
|
|
|
pci_dev_unlock(dev);
|
|
|
|
|
|
- pci_dev_restore(dev);
|
|
|
return rc;
|
|
|
}
|
|
|
EXPORT_SYMBOL_GPL(pci_try_reset_function);
|
|
@@ -4683,7 +4698,9 @@ static void pci_slot_restore(struct pci_slot *slot)
|
|
|
list_for_each_entry(dev, &slot->bus->devices, bus_list) {
|
|
|
if (!dev->slot || dev->slot != slot)
|
|
|
continue;
|
|
|
+ pci_dev_lock(dev);
|
|
|
pci_dev_restore(dev);
|
|
|
+ pci_dev_unlock(dev);
|
|
|
if (dev->subordinate)
|
|
|
pci_bus_restore(dev->subordinate);
|
|
|
}
|