aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGavin Shan <gwshan@linux.vnet.ibm.com>2015-04-30 19:14:11 -0400
committerMichael Ellerman <mpe@ellerman.id.au>2015-04-30 23:52:09 -0400
commit1ae79b78bc52b910a224f3795122538516e07b5f (patch)
treed934d597c7c63219901eec7ab644d960ed48b7a7
parentf32393c943e297b8ae180c8f83d81a156c7d0412 (diff)
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>
-rw-r--r--arch/powerpc/kernel/eeh.c5
1 files changed, 4 insertions, 1 deletions
diff --git a/arch/powerpc/kernel/eeh.c b/arch/powerpc/kernel/eeh.c
index 44b480e3a5af..fa046ca6d0fa 100644
--- a/arch/powerpc/kernel/eeh.c
+++ b/arch/powerpc/kernel/eeh.c
@@ -749,21 +749,24 @@ int pcibios_set_pcie_reset_state(struct pci_dev *dev, enum pcie_reset_state stat
749 eeh_unfreeze_pe(pe, false); 749 eeh_unfreeze_pe(pe, false);
750 eeh_pe_state_clear(pe, EEH_PE_CFG_BLOCKED); 750 eeh_pe_state_clear(pe, EEH_PE_CFG_BLOCKED);
751 eeh_pe_dev_traverse(pe, eeh_restore_dev_state, dev); 751 eeh_pe_dev_traverse(pe, eeh_restore_dev_state, dev);
752 eeh_pe_state_clear(pe, EEH_PE_ISOLATED);
752 break; 753 break;
753 case pcie_hot_reset: 754 case pcie_hot_reset:
755 eeh_pe_state_mark(pe, EEH_PE_ISOLATED);
754 eeh_ops->set_option(pe, EEH_OPT_FREEZE_PE); 756 eeh_ops->set_option(pe, EEH_OPT_FREEZE_PE);
755 eeh_pe_dev_traverse(pe, eeh_disable_and_save_dev_state, dev); 757 eeh_pe_dev_traverse(pe, eeh_disable_and_save_dev_state, dev);
756 eeh_pe_state_mark(pe, EEH_PE_CFG_BLOCKED); 758 eeh_pe_state_mark(pe, EEH_PE_CFG_BLOCKED);
757 eeh_ops->reset(pe, EEH_RESET_HOT); 759 eeh_ops->reset(pe, EEH_RESET_HOT);
758 break; 760 break;
759 case pcie_warm_reset: 761 case pcie_warm_reset:
762 eeh_pe_state_mark(pe, EEH_PE_ISOLATED);
760 eeh_ops->set_option(pe, EEH_OPT_FREEZE_PE); 763 eeh_ops->set_option(pe, EEH_OPT_FREEZE_PE);
761 eeh_pe_dev_traverse(pe, eeh_disable_and_save_dev_state, dev); 764 eeh_pe_dev_traverse(pe, eeh_disable_and_save_dev_state, dev);
762 eeh_pe_state_mark(pe, EEH_PE_CFG_BLOCKED); 765 eeh_pe_state_mark(pe, EEH_PE_CFG_BLOCKED);
763 eeh_ops->reset(pe, EEH_RESET_FUNDAMENTAL); 766 eeh_ops->reset(pe, EEH_RESET_FUNDAMENTAL);
764 break; 767 break;
765 default: 768 default:
766 eeh_pe_state_clear(pe, EEH_PE_CFG_BLOCKED); 769 eeh_pe_state_clear(pe, EEH_PE_ISOLATED | EEH_PE_CFG_BLOCKED);
767 return -EINVAL; 770 return -EINVAL;
768 }; 771 };
769 772