powerpc/eeh_sysfs: Make clearing EEH_DEV_SYSFS saner
The eeh_sysfs_remove_device() function is supposed to clear the EEH_DEV_SYSFS flag since it indicates the EEH sysfs entries have been added for a pci_dev. When the sysfs files are removed eeh_remove_device() the eeh_dev and the pci_dev have already been de-associated. This then causes the pci_dev_to_eeh_dev() call in eeh_sysfs_remove_device() to return NULL so the flag can't be cleared from the still-live eeh_dev. This problem is worked around in the caller by clearing the flag manually. However, this behaviour doesn't make a whole lot of sense, so this patch fixes it by: a) Re-ordering eeh_remove_device() so that eeh_sysfs_remove_device() is called before de-associating the pci_dev and eeh_dev. b) Making eeh_sysfs_remove_device() emit a warning if there's no corresponding eeh_dev for a pci_dev. The paths where the sysfs files are only reachable if EEH was setup for the device for the device in the first place so hitting this warning indicates a programming error. Signed-off-by: Oliver O'Halloran <oohall@gmail.com> Reviewed-by: Sam Bobroff <sbobroff@linux.ibm.com> Tested-by: Sam Bobroff <sbobroff@linux.ibm.com> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au> Link: https://lore.kernel.org/r/20190715085612.8802-6-oohall@gmail.com
This commit is contained in:
Родитель
758b423275
Коммит
3489cdc417
|
@ -1191,7 +1191,6 @@ void eeh_add_device_late(struct pci_dev *dev)
|
|||
eeh_rmv_from_parent_pe(edev);
|
||||
eeh_addr_cache_rmv_dev(edev->pdev);
|
||||
eeh_sysfs_remove_device(edev->pdev);
|
||||
edev->mode &= ~EEH_DEV_SYSFS;
|
||||
|
||||
/*
|
||||
* We definitely should have the PCI device removed
|
||||
|
@ -1295,6 +1294,23 @@ void eeh_remove_device(struct pci_dev *dev)
|
|||
*/
|
||||
edev->pdev = NULL;
|
||||
|
||||
/*
|
||||
* eeh_sysfs_remove_device() uses pci_dev_to_eeh_dev() so we need to
|
||||
* remove the sysfs files before clearing dev.archdata.edev
|
||||
*/
|
||||
if (edev->mode & EEH_DEV_SYSFS)
|
||||
eeh_sysfs_remove_device(dev);
|
||||
|
||||
/*
|
||||
* We're removing from the PCI subsystem, that means
|
||||
* the PCI device driver can't support EEH or not
|
||||
* well. So we rely on hotplug completely to do recovery
|
||||
* for the specific PCI device.
|
||||
*/
|
||||
edev->mode |= EEH_DEV_NO_HANDLER;
|
||||
|
||||
eeh_addr_cache_rmv_dev(dev);
|
||||
|
||||
/*
|
||||
* The flag "in_error" is used to trace EEH devices for VFs
|
||||
* in error state or not. It's set in eeh_report_error(). If
|
||||
|
@ -1307,18 +1323,6 @@ void eeh_remove_device(struct pci_dev *dev)
|
|||
eeh_rmv_from_parent_pe(edev);
|
||||
else
|
||||
edev->mode |= EEH_DEV_DISCONNECTED;
|
||||
|
||||
/*
|
||||
* We're removing from the PCI subsystem, that means
|
||||
* the PCI device driver can't support EEH or not
|
||||
* well. So we rely on hotplug completely to do recovery
|
||||
* for the specific PCI device.
|
||||
*/
|
||||
edev->mode |= EEH_DEV_NO_HANDLER;
|
||||
|
||||
eeh_addr_cache_rmv_dev(dev);
|
||||
eeh_sysfs_remove_device(dev);
|
||||
edev->mode &= ~EEH_DEV_SYSFS;
|
||||
}
|
||||
|
||||
int eeh_unfreeze_pe(struct eeh_pe *pe)
|
||||
|
|
|
@ -159,22 +159,23 @@ void eeh_sysfs_remove_device(struct pci_dev *pdev)
|
|||
{
|
||||
struct eeh_dev *edev = pci_dev_to_eeh_dev(pdev);
|
||||
|
||||
if (!edev) {
|
||||
WARN_ON(eeh_enabled());
|
||||
return;
|
||||
}
|
||||
|
||||
edev->mode &= ~EEH_DEV_SYSFS;
|
||||
|
||||
/*
|
||||
* The parent directory might have been removed. We needn't
|
||||
* continue for that case.
|
||||
*/
|
||||
if (!pdev->dev.kobj.sd) {
|
||||
if (edev)
|
||||
edev->mode &= ~EEH_DEV_SYSFS;
|
||||
if (!pdev->dev.kobj.sd)
|
||||
return;
|
||||
}
|
||||
|
||||
device_remove_file(&pdev->dev, &dev_attr_eeh_mode);
|
||||
device_remove_file(&pdev->dev, &dev_attr_eeh_pe_config_addr);
|
||||
device_remove_file(&pdev->dev, &dev_attr_eeh_pe_state);
|
||||
|
||||
eeh_notify_resume_remove(pdev);
|
||||
|
||||
if (edev)
|
||||
edev->mode &= ~EEH_DEV_SYSFS;
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче