PCI: Unify device inaccessible
authorKeith Busch <keith.busch@intel.com>
Thu, 20 Sep 2018 16:27:16 +0000 (10:27 -0600)
committerBjorn Helgaas <bhelgaas@google.com>
Tue, 2 Oct 2018 21:04:40 +0000 (16:04 -0500)
Bring surprise removals and permanent failures together so we no longer
need separate flags.  The implementation enforces that error handling will
not be able to override a surprise removal's permanent channel failure.

Signed-off-by: Keith Busch <keith.busch@intel.com>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Reviewed-by: Sinan Kaya <okaya@kernel.org>
drivers/pci/pci.h
drivers/pci/pcie/err.c

index 9b279805489f7be055ca3a318773afd46e14852f..eb3125decffe14df261817c98138ad3a5b363ff7 100644 (file)
@@ -295,21 +295,71 @@ struct pci_sriov {
        bool            drivers_autoprobe; /* Auto probing of VFs by driver */
 };
 
-/* pci_dev priv_flags */
-#define PCI_DEV_DISCONNECTED 0
-#define PCI_DEV_ADDED 1
+/**
+ * pci_dev_set_io_state - Set the new error state if possible.
+ *
+ * @dev - pci device to set new error_state
+ * @new - the state we want dev to be in
+ *
+ * Must be called with device_lock held.
+ *
+ * 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;
+
+       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;
+       case pci_channel_io_frozen:
+               switch (dev->error_state) {
+               case pci_channel_io_frozen:
+               case pci_channel_io_normal:
+                       changed = true;
+                       break;
+               }
+               break;
+       case pci_channel_io_normal:
+               switch (dev->error_state) {
+               case pci_channel_io_frozen:
+               case pci_channel_io_normal:
+                       changed = true;
+                       break;
+               }
+               break;
+       }
+       if (changed)
+               dev->error_state = new;
+       return changed;
+}
 
 static inline int pci_dev_set_disconnected(struct pci_dev *dev, void *unused)
 {
-       set_bit(PCI_DEV_DISCONNECTED, &dev->priv_flags);
+       device_lock(&dev->dev);
+       pci_dev_set_io_state(dev, pci_channel_io_perm_failure);
+       device_unlock(&dev->dev);
+
        return 0;
 }
 
 static inline bool pci_dev_is_disconnected(const struct pci_dev *dev)
 {
-       return test_bit(PCI_DEV_DISCONNECTED, &dev->priv_flags);
+       return dev->error_state == pci_channel_io_perm_failure;
 }
 
+/* pci_dev priv_flags */
+#define PCI_DEV_ADDED 0
+
 static inline void pci_dev_assign_added(struct pci_dev *dev, bool added)
 {
        assign_bit(PCI_DEV_ADDED, &dev->priv_flags, added);
index 31e8a4314384440e4e4dfe7c843425e1e11cfd44..4da2a62b4f77821ab696cddbc6fdc5058f0d9496 100644 (file)
@@ -52,9 +52,8 @@ static int report_error_detected(struct pci_dev *dev,
        const struct pci_error_handlers *err_handler;
 
        device_lock(&dev->dev);
-       dev->error_state = state;
-
-       if (!dev->driver ||
+       if (!pci_dev_set_io_state(dev, state) ||
+               !dev->driver ||
                !dev->driver->err_handler ||
                !dev->driver->err_handler->error_detected) {
                /*
@@ -130,9 +129,8 @@ static int report_resume(struct pci_dev *dev, void *data)
        const struct pci_error_handlers *err_handler;
 
        device_lock(&dev->dev);
-       dev->error_state = pci_channel_io_normal;
-
-       if (!dev->driver ||
+       if (!pci_dev_set_io_state(dev, pci_channel_io_normal) ||
+               !dev->driver ||
                !dev->driver->err_handler ||
                !dev->driver->err_handler->resume)
                goto out;