powerpc/eeh: Fix race condition in pcibios_set_pcie_reset_state()
When asserting reset in pcibios_set_pcie_reset_state(), the PE
is enforced to (hardware) frozen state in order to drop unexpected
PCI transactions (except PCI config read/write) automatically by
hardware during reset, which would cause recursive EEH error.
However, the (software) frozen state EEH_PE_ISOLATED is missed.
When users get 0xFF from PCI config or MMIO read, EEH_PE_ISOLATED
is set in PE state retrival backend. Unfortunately, nobody (the
reset handler or the EEH recovery functinality in host) will clear
EEH_PE_ISOLATED when the PE has been passed through to guest.
The patch sets and clears EEH_PE_ISOLATED properly during reset
in function pcibios_set_pcie_reset_state() to fix the issue.
Fixes: 28158cd
("Enhance pcibios_set_pcie_reset_state()")
Reported-by: Carol L. Soto <clsoto@us.ibm.com>
Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com>
Tested-by: Carol L. Soto <clsoto@us.ibm.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
This commit is contained in:
Родитель
f32393c943
Коммит
1ae79b78bc
|
@ -749,21 +749,24 @@ int pcibios_set_pcie_reset_state(struct pci_dev *dev, enum pcie_reset_state stat
|
||||||
eeh_unfreeze_pe(pe, false);
|
eeh_unfreeze_pe(pe, false);
|
||||||
eeh_pe_state_clear(pe, EEH_PE_CFG_BLOCKED);
|
eeh_pe_state_clear(pe, EEH_PE_CFG_BLOCKED);
|
||||||
eeh_pe_dev_traverse(pe, eeh_restore_dev_state, dev);
|
eeh_pe_dev_traverse(pe, eeh_restore_dev_state, dev);
|
||||||
|
eeh_pe_state_clear(pe, EEH_PE_ISOLATED);
|
||||||
break;
|
break;
|
||||||
case pcie_hot_reset:
|
case pcie_hot_reset:
|
||||||
|
eeh_pe_state_mark(pe, EEH_PE_ISOLATED);
|
||||||
eeh_ops->set_option(pe, EEH_OPT_FREEZE_PE);
|
eeh_ops->set_option(pe, EEH_OPT_FREEZE_PE);
|
||||||
eeh_pe_dev_traverse(pe, eeh_disable_and_save_dev_state, dev);
|
eeh_pe_dev_traverse(pe, eeh_disable_and_save_dev_state, dev);
|
||||||
eeh_pe_state_mark(pe, EEH_PE_CFG_BLOCKED);
|
eeh_pe_state_mark(pe, EEH_PE_CFG_BLOCKED);
|
||||||
eeh_ops->reset(pe, EEH_RESET_HOT);
|
eeh_ops->reset(pe, EEH_RESET_HOT);
|
||||||
break;
|
break;
|
||||||
case pcie_warm_reset:
|
case pcie_warm_reset:
|
||||||
|
eeh_pe_state_mark(pe, EEH_PE_ISOLATED);
|
||||||
eeh_ops->set_option(pe, EEH_OPT_FREEZE_PE);
|
eeh_ops->set_option(pe, EEH_OPT_FREEZE_PE);
|
||||||
eeh_pe_dev_traverse(pe, eeh_disable_and_save_dev_state, dev);
|
eeh_pe_dev_traverse(pe, eeh_disable_and_save_dev_state, dev);
|
||||||
eeh_pe_state_mark(pe, EEH_PE_CFG_BLOCKED);
|
eeh_pe_state_mark(pe, EEH_PE_CFG_BLOCKED);
|
||||||
eeh_ops->reset(pe, EEH_RESET_FUNDAMENTAL);
|
eeh_ops->reset(pe, EEH_RESET_FUNDAMENTAL);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
eeh_pe_state_clear(pe, EEH_PE_CFG_BLOCKED);
|
eeh_pe_state_clear(pe, EEH_PE_ISOLATED | EEH_PE_CFG_BLOCKED);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче