Commit 404079c8 authored by Gavin Shan's avatar Gavin Shan Committed by Michael Ellerman

powerpc/eeh: Clear frozen state on passing device

When passing through device, its PE might have been put into frozen
state. One obvious example would be: the passed PE is forced to be
offline because of hitting maximal allowed EEH errors in userland.
In that case, the frozen state won't be cleared and then the PE is
returned back to host, which might not have chance detecting and
recovering from it.

The patch adds more check when passing through device and clear the
PE frozen state if necessary.
Signed-off-by: default avatarGavin Shan <gwshan@linux.vnet.ibm.com>
Signed-off-by: default avatarMichael Ellerman <mpe@ellerman.id.au>
parent 316233ff
...@@ -1150,6 +1150,8 @@ void eeh_remove_device(struct pci_dev *dev) ...@@ -1150,6 +1150,8 @@ void eeh_remove_device(struct pci_dev *dev)
int eeh_dev_open(struct pci_dev *pdev) int eeh_dev_open(struct pci_dev *pdev)
{ {
struct eeh_dev *edev; struct eeh_dev *edev;
int flag = (EEH_STATE_MMIO_ACTIVE | EEH_STATE_DMA_ACTIVE);
int ret = -ENODEV;
mutex_lock(&eeh_dev_mutex); mutex_lock(&eeh_dev_mutex);
...@@ -1162,6 +1164,38 @@ int eeh_dev_open(struct pci_dev *pdev) ...@@ -1162,6 +1164,38 @@ int eeh_dev_open(struct pci_dev *pdev)
if (!edev || !edev->pe) if (!edev || !edev->pe)
goto out; goto out;
/*
* The PE might have been put into frozen state, but we
* didn't detect that yet. The passed through PCI devices
* in frozen PE won't work properly. Clear the frozen state
* in advance.
*/
ret = eeh_ops->get_state(edev->pe, NULL);
if (ret > 0 && ret != EEH_STATE_NOT_SUPPORT &&
(ret & flag) != flag) {
ret = eeh_ops->set_option(edev->pe, EEH_OPT_THAW_MMIO);
if (ret) {
pr_warn("%s: Failure %d enabling MMIO "
"for PHB#%x-PE#%x\n",
__func__, ret, edev->phb->global_number,
edev->pe->addr);
goto out;
}
ret = eeh_ops->set_option(edev->pe, EEH_OPT_THAW_DMA);
if (ret) {
pr_warn("%s: Failure %d enabling DMA "
"for PHB#%x-PE#%x\n",
__func__, ret, edev->phb->global_number,
edev->pe->addr);
goto out;
}
}
/* Clear software isolated state */
if (edev->pe->state & EEH_PE_ISOLATED)
eeh_pe_state_clear(edev->pe, EEH_PE_ISOLATED);
/* Increase PE's pass through count */ /* Increase PE's pass through count */
atomic_inc(&edev->pe->pass_dev_cnt); atomic_inc(&edev->pe->pass_dev_cnt);
mutex_unlock(&eeh_dev_mutex); mutex_unlock(&eeh_dev_mutex);
...@@ -1169,7 +1203,7 @@ int eeh_dev_open(struct pci_dev *pdev) ...@@ -1169,7 +1203,7 @@ int eeh_dev_open(struct pci_dev *pdev)
return 0; return 0;
out: out:
mutex_unlock(&eeh_dev_mutex); mutex_unlock(&eeh_dev_mutex);
return -ENODEV; return ret;
} }
EXPORT_SYMBOL_GPL(eeh_dev_open); EXPORT_SYMBOL_GPL(eeh_dev_open);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment