diff --git a/arch/powerpc/kernel/eeh.c b/arch/powerpc/kernel/eeh.c index 6b4690f315d3f9f722652f29f3db77a5b064f9e5..f5677684429e3cc0c84b52cf3d3918bd2c32dca9 100644 --- a/arch/powerpc/kernel/eeh.c +++ b/arch/powerpc/kernel/eeh.c @@ -1150,6 +1150,8 @@ void eeh_remove_device(struct pci_dev *dev) int eeh_dev_open(struct pci_dev *pdev) { struct eeh_dev *edev; + int flag = (EEH_STATE_MMIO_ACTIVE | EEH_STATE_DMA_ACTIVE); + int ret = -ENODEV; mutex_lock(&eeh_dev_mutex); @@ -1162,6 +1164,38 @@ int eeh_dev_open(struct pci_dev *pdev) if (!edev || !edev->pe) 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 */ atomic_inc(&edev->pe->pass_dev_cnt); mutex_unlock(&eeh_dev_mutex); @@ -1169,7 +1203,7 @@ int eeh_dev_open(struct pci_dev *pdev) return 0; out: mutex_unlock(&eeh_dev_mutex); - return -ENODEV; + return ret; } EXPORT_SYMBOL_GPL(eeh_dev_open);