PCI: Unify device inaccessible

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>
This commit is contained in:
Keith Busch 2018-09-20 10:27:16 -06:00 committed by Bjorn Helgaas
parent 7b42d97e99
commit a6bd101b8f
2 changed files with 59 additions and 11 deletions

View File

@ -295,21 +295,71 @@ struct pci_sriov {
bool drivers_autoprobe; /* Auto probing of VFs by driver */ bool drivers_autoprobe; /* Auto probing of VFs by driver */
}; };
/* pci_dev priv_flags */ /**
#define PCI_DEV_DISCONNECTED 0 * pci_dev_set_io_state - Set the new error state if possible.
#define PCI_DEV_ADDED 1 *
* @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) 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; return 0;
} }
static inline bool pci_dev_is_disconnected(const struct pci_dev *dev) 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) static inline void pci_dev_assign_added(struct pci_dev *dev, bool added)
{ {
assign_bit(PCI_DEV_ADDED, &dev->priv_flags, added); assign_bit(PCI_DEV_ADDED, &dev->priv_flags, added);

View File

@ -52,9 +52,8 @@ static int report_error_detected(struct pci_dev *dev,
const struct pci_error_handlers *err_handler; const struct pci_error_handlers *err_handler;
device_lock(&dev->dev); device_lock(&dev->dev);
dev->error_state = state; if (!pci_dev_set_io_state(dev, state) ||
!dev->driver ||
if (!dev->driver ||
!dev->driver->err_handler || !dev->driver->err_handler ||
!dev->driver->err_handler->error_detected) { !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; const struct pci_error_handlers *err_handler;
device_lock(&dev->dev); device_lock(&dev->dev);
dev->error_state = pci_channel_io_normal; if (!pci_dev_set_io_state(dev, pci_channel_io_normal) ||
!dev->driver ||
if (!dev->driver ||
!dev->driver->err_handler || !dev->driver->err_handler ||
!dev->driver->err_handler->resume) !dev->driver->err_handler->resume)
goto out; goto out;