Skip to content

Commit

Permalink
PCI: Unify device inaccessible
Browse files Browse the repository at this point in the history
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 <[email protected]>
Signed-off-by: Bjorn Helgaas <[email protected]>
Reviewed-by: Sinan Kaya <[email protected]>
  • Loading branch information
Keith Busch authored and bjorn-helgaas committed Oct 2, 2018
1 parent 7b42d97 commit a6bd101
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 11 deletions.
60 changes: 55 additions & 5 deletions drivers/pci/pci.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
10 changes: 4 additions & 6 deletions drivers/pci/pcie/err.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
/*
Expand Down Expand Up @@ -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;
Expand Down

0 comments on commit a6bd101

Please sign in to comment.