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

Configure Feed

Select the types of activity you want to include in your feed.

powerpc/eeh: Fix stale cached primary bus

When PE is created, its primary bus is cached to pe->bus. At later
point, the cached primary bus is returned from eeh_pe_bus_get().
However, we could get stale cached primary bus and run into kernel
crash in one case: full hotplug as part of fenced PHB error recovery
releases all PCI busses under the PHB at unplugging time and recreate
them at plugging time. pe->bus is still dereferencing the PCI bus
that was released.

This adds another PE flag (EEH_PE_PRI_BUS) to represent the validity
of pe->bus. pe->bus is updated when its first child EEH device is
online and the flag is set. Before unplugging in full hotplug for
error recovery, the flag is cleared.

Fixes: 8cdb2833 ("powerpc/eeh: Trace PCI bus from PE")
Cc: stable@vger.kernel.org #v3.11+
Reported-by: Andrew Donnellan <andrew.donnellan@au1.ibm.com>
Reported-by: Pradipta Ghosh <pradghos@in.ibm.com>
Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com>
Tested-by: Andrew Donnellan <andrew.donnellan@au1.ibm.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>

authored by

Gavin Shan and committed by
Michael Ellerman
05ba75f8 126df08c

+9 -2
+1
arch/powerpc/include/asm/eeh.h
··· 81 81 #define EEH_PE_KEEP (1 << 8) /* Keep PE on hotplug */ 82 82 #define EEH_PE_CFG_RESTRICTED (1 << 9) /* Block config on error */ 83 83 #define EEH_PE_REMOVED (1 << 10) /* Removed permanently */ 84 + #define EEH_PE_PRI_BUS (1 << 11) /* Cached primary bus */ 84 85 85 86 struct eeh_pe { 86 87 int type; /* PE type: PHB/Bus/Device */
+3
arch/powerpc/kernel/eeh_driver.c
··· 564 564 */ 565 565 eeh_pe_state_mark(pe, EEH_PE_KEEP); 566 566 if (bus) { 567 + eeh_pe_state_clear(pe, EEH_PE_PRI_BUS); 567 568 pci_lock_rescan_remove(); 568 569 pcibios_remove_pci_devices(bus); 569 570 pci_unlock_rescan_remove(); ··· 804 803 * the their PCI config any more. 805 804 */ 806 805 if (frozen_bus) { 806 + eeh_pe_state_clear(pe, EEH_PE_PRI_BUS); 807 807 eeh_pe_dev_mode_mark(pe, EEH_DEV_REMOVED); 808 808 809 809 pci_lock_rescan_remove(); ··· 888 886 continue; 889 887 890 888 /* Notify all devices to be down */ 889 + eeh_pe_state_clear(pe, EEH_PE_PRI_BUS); 891 890 bus = eeh_pe_bus_get(phb_pe); 892 891 eeh_pe_dev_traverse(pe, 893 892 eeh_report_failure, NULL);
+1 -1
arch/powerpc/kernel/eeh_pe.c
··· 928 928 bus = pe->phb->bus; 929 929 } else if (pe->type & EEH_PE_BUS || 930 930 pe->type & EEH_PE_DEVICE) { 931 - if (pe->bus) { 931 + if (pe->state & EEH_PE_PRI_BUS) { 932 932 bus = pe->bus; 933 933 goto out; 934 934 }
+4 -1
arch/powerpc/platforms/powernv/eeh-powernv.c
··· 444 444 * PCI devices of the PE are expected to be removed prior 445 445 * to PE reset. 446 446 */ 447 - if (!edev->pe->bus) 447 + if (!(edev->pe->state & EEH_PE_PRI_BUS)) { 448 448 edev->pe->bus = pci_find_bus(hose->global_number, 449 449 pdn->busno); 450 + if (edev->pe->bus) 451 + edev->pe->state |= EEH_PE_PRI_BUS; 452 + } 450 453 451 454 /* 452 455 * Enable EEH explicitly so that we will do EEH check