Merge tag 'pci-v6.3-changes' of git://git.kernel.org/pub/scm/linux/kernel/git/pci/pci
[linux-block.git] / drivers / pci / pci.h
index 9049d07d3aaece2ec2442884afc7d32a38172945..d2c08670a20ed77823e65a748365d15f0a0bf875 100644 (file)
@@ -64,6 +64,19 @@ struct pci_cap_saved_state *pci_find_saved_ext_cap(struct pci_dev *dev,
 #define PCI_PM_D3HOT_WAIT       10     /* msec */
 #define PCI_PM_D3COLD_WAIT      100    /* msec */
 
+/*
+ * Following exit from Conventional Reset, devices must be ready within 1 sec
+ * (PCIe r6.0 sec 6.6.1).  A D3cold to D0 transition implies a Conventional
+ * Reset (PCIe r6.0 sec 5.8).
+ */
+#define PCI_RESET_WAIT         1000    /* msec */
+/*
+ * Devices may extend the 1 sec period through Request Retry Status completions
+ * (PCIe r6.0 sec 2.3.1).  The spec does not provide an upper limit, but 60 sec
+ * ought to be enough for any device to become responsive.
+ */
+#define PCIE_RESET_READY_POLL_MS 60000 /* msec */
+
 void pci_update_current_state(struct pci_dev *dev, pci_power_t state);
 void pci_refresh_power_state(struct pci_dev *dev);
 int pci_power_up(struct pci_dev *dev);
@@ -86,8 +99,9 @@ void pci_msi_init(struct pci_dev *dev);
 void pci_msix_init(struct pci_dev *dev);
 bool pci_bridge_d3_possible(struct pci_dev *dev);
 void pci_bridge_d3_update(struct pci_dev *dev);
-void pci_bridge_wait_for_secondary_bus(struct pci_dev *dev);
 void pci_bridge_reconfigure_ltr(struct pci_dev *dev);
+int pci_bridge_wait_for_secondary_bus(struct pci_dev *dev, char *reset_type,
+                                     int timeout);
 
 static inline void pci_wakeup_event(struct pci_dev *dev)
 {
@@ -310,53 +324,36 @@ struct pci_sriov {
  * @dev: PCI device to set new error_state
  * @new: the state we want dev to be in
  *
- * Must be called with device_lock held.
+ * If the device is experiencing perm_failure, it has to remain in that state.
+ * Any other transition is allowed.
  *
  * Returns true if state has been changed to the requested state.
  */
 static inline bool pci_dev_set_io_state(struct pci_dev *dev,
                                        pci_channel_state_t new)
 {
-       bool changed = false;
+       pci_channel_state_t old;
 
-       device_lock_assert(&dev->dev);
        switch (new) {
        case pci_channel_io_perm_failure:
-               switch (dev->error_state) {
-               case pci_channel_io_frozen:
-               case pci_channel_io_normal:
-               case pci_channel_io_perm_failure:
-                       changed = true;
-                       break;
-               }
-               break;
+               xchg(&dev->error_state, pci_channel_io_perm_failure);
+               return true;
        case pci_channel_io_frozen:
-               switch (dev->error_state) {
-               case pci_channel_io_frozen:
-               case pci_channel_io_normal:
-                       changed = true;
-                       break;
-               }
-               break;
+               old = cmpxchg(&dev->error_state, pci_channel_io_normal,
+                             pci_channel_io_frozen);
+               return old != pci_channel_io_perm_failure;
        case pci_channel_io_normal:
-               switch (dev->error_state) {
-               case pci_channel_io_frozen:
-               case pci_channel_io_normal:
-                       changed = true;
-                       break;
-               }
-               break;
+               old = cmpxchg(&dev->error_state, pci_channel_io_frozen,
+                             pci_channel_io_normal);
+               return old != pci_channel_io_perm_failure;
+       default:
+               return false;
        }
-       if (changed)
-               dev->error_state = new;
-       return changed;
 }
 
 static inline int pci_dev_set_disconnected(struct pci_dev *dev, void *unused)
 {
-       device_lock(&dev->dev);
        pci_dev_set_io_state(dev, pci_channel_io_perm_failure);
-       device_unlock(&dev->dev);
 
        return 0;
 }