* @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;
 }