Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

powerpc/eeh: Disable automatically blocked PCI config

pcibios_set_pcie_reset_state() could be called to complete
reset request when passing through PCI device, flag
EEH_PE_ISOLATED is set before saving the PCI config sapce.
On some Broadcom adapters, EEH_PE_CFG_BLOCKED is automatically
set when the flag EEH_PE_ISOLATED is marked. It caused bogus
data saved from the PCI config space, which will be restored
to the PCI adapter after the reset. Eventually, the hardware
can't work with corrupted data in PCI config space.

The patch fixes the issue with eeh_pe_state_mark_no_cfg(), which
doesn't set EEH_PE_CFG_BLOCKED when seeing EEH_PE_ISOLATED on the
PE, in order to avoid the bogus data saved and restored to the PCI
config space.

Reported-by: Rajanikanth H. Adaveeshaiah <rajanikanth.ha@in.ibm.com>
Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>

authored by

Gavin Shan and committed by
Michael Ellerman
39bfd715 dd497154

+25 -2
+1
arch/powerpc/include/asm/ppc-pci.h
··· 61 61 int rtas_read_config(struct pci_dn *, int where, int size, u32 *val); 62 62 void eeh_pe_state_mark(struct eeh_pe *pe, int state); 63 63 void eeh_pe_state_clear(struct eeh_pe *pe, int state); 64 + void eeh_pe_state_mark_with_cfg(struct eeh_pe *pe, int state); 64 65 void eeh_pe_dev_mode_mark(struct eeh_pe *pe, int mode); 65 66 66 67 void eeh_sysfs_add_device(struct pci_dev *pdev);
+2 -2
arch/powerpc/kernel/eeh.c
··· 750 750 eeh_pe_state_clear(pe, EEH_PE_ISOLATED); 751 751 break; 752 752 case pcie_hot_reset: 753 - eeh_pe_state_mark(pe, EEH_PE_ISOLATED); 753 + eeh_pe_state_mark_with_cfg(pe, EEH_PE_ISOLATED); 754 754 eeh_ops->set_option(pe, EEH_OPT_FREEZE_PE); 755 755 eeh_pe_dev_traverse(pe, eeh_disable_and_save_dev_state, dev); 756 756 eeh_pe_state_mark(pe, EEH_PE_CFG_BLOCKED); 757 757 eeh_ops->reset(pe, EEH_RESET_HOT); 758 758 break; 759 759 case pcie_warm_reset: 760 - eeh_pe_state_mark(pe, EEH_PE_ISOLATED); 760 + eeh_pe_state_mark_with_cfg(pe, EEH_PE_ISOLATED); 761 761 eeh_ops->set_option(pe, EEH_OPT_FREEZE_PE); 762 762 eeh_pe_dev_traverse(pe, eeh_disable_and_save_dev_state, dev); 763 763 eeh_pe_state_mark(pe, EEH_PE_CFG_BLOCKED);
+22
arch/powerpc/kernel/eeh_pe.c
··· 657 657 eeh_pe_traverse(pe, __eeh_pe_state_clear, &state); 658 658 } 659 659 660 + /** 661 + * eeh_pe_state_mark_with_cfg - Mark PE state with unblocked config space 662 + * @pe: PE 663 + * @state: PE state to be set 664 + * 665 + * Set specified flag to PE and its child PEs. The PCI config space 666 + * of some PEs is blocked automatically when EEH_PE_ISOLATED is set, 667 + * which isn't needed in some situations. The function allows to set 668 + * the specified flag to indicated PEs without blocking their PCI 669 + * config space. 670 + */ 671 + void eeh_pe_state_mark_with_cfg(struct eeh_pe *pe, int state) 672 + { 673 + eeh_pe_traverse(pe, __eeh_pe_state_mark, &state); 674 + if (!(state & EEH_PE_ISOLATED)) 675 + return; 676 + 677 + /* Clear EEH_PE_CFG_BLOCKED, which might be set just now */ 678 + state = EEH_PE_CFG_BLOCKED; 679 + eeh_pe_traverse(pe, __eeh_pe_state_clear, &state); 680 + } 681 + 660 682 /* 661 683 * Some PCI bridges (e.g. PLX bridges) have primary/secondary 662 684 * buses assigned explicitly by firmware, and we probably have