@@ -1027,27 +1027,28 @@ void pci_wakeup_bus(struct pci_bus *bus)
pci_walk_bus(bus, pci_wakeup, NULL);
}
-static int pci_dev_wait(struct pci_dev *dev, enum pci_init_event event)
+/*
+ * Performs DWORD Configuration Reads at a specific offset until the value read
+ * (with mask applied) is not equal to bad_value.
+ */
+static inline int pci_dev_poll_until_not_equal(struct pci_dev *dev, int where,
+ u32 mask, u32 bad_value,
+ const char *event_name,
+ int timeout, int *waited,
+ u32 *final_value)
{
- const char *event_name = pci_init_event_name(event);
- int timeout = dev->reset_ready_poll_ms;
int delay = 1;
- u32 id;
+ u32 value;
- /*
- * 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
- * CRS SV is enabled and the read was for the Vendor ID; in that
- * case it synthesizes 0x0001 data).
- *
- * Wait for the device to return a non-CRS completion. Read the
- * Command register instead of Vendor ID so we don't have to
- * contend with the CRS SV value.
- */
- pci_read_config_dword(dev, PCI_COMMAND, &id);
- while (id == ~0) {
+ if (!event_name)
+ event_name = "<unknown event>";
+
+ if (waited)
+ delay = *waited + 1;
+
+ pci_read_config_dword(dev, where, &value);
+
+ while ((value & mask) == bad_value) {
if (delay > timeout) {
pci_warn(dev, "not ready %dms after %s; giving up\n",
delay - 1, event_name);
@@ -1060,16 +1061,44 @@ static int pci_dev_wait(struct pci_dev *dev, enum pci_init_event event)
msleep(delay);
delay *= 2;
- pci_read_config_dword(dev, PCI_COMMAND, &id);
+
+ pci_read_config_dword(dev, where, &value);
}
if (delay > 1000)
- pci_info(dev, "ready %dms after %s\n", delay - 1,
- event_name);
+ pci_info(dev, "ready %dms after %s\n", delay - 1, event_name);
+
+ if (waited)
+ *waited = delay - 1;
+
+ if (final_value)
+ *final_value = value;
return 0;
}
+static int pci_dev_wait(struct pci_dev *dev, enum pci_init_event event)
+{
+ const char *event_name = pci_init_event_name(event);
+ int timeout = dev->reset_ready_poll_ms;
+
+ /*
+ * 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
+ * CRS SV is enabled and the read was for the Vendor ID; in that
+ * case it synthesizes 0x0001 data).
+ *
+ * Wait for the device to return a non-CRS completion. Read the
+ * Command register instead of Vendor ID so we don't have to
+ * contend with the CRS SV value.
+ */
+ return pci_dev_poll_until_not_equal(dev, PCI_COMMAND, ~0, ~0,
+ event_name, timeout, NULL,
+ NULL);
+}
+
/**
* pci_power_up - Put the given device into D0
* @dev: PCI device to power up