aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/platforms/powernv
diff options
context:
space:
mode:
authorGavin Shan <gwshan@linux.vnet.ibm.com>2014-04-24 04:00:24 -0400
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2014-04-28 03:34:53 -0400
commitd92a208d086063ecc785b4588f74ab42268cbc4b (patch)
tree07189bb010c1d9443a0fee736268cfcbf965dfd3 /arch/powerpc/platforms/powernv
parent26833a5029b710b12f00607fa255ce86909836ad (diff)
powerpc/pci: Mask linkDown on resetting PCI bus
The problem was initially reported by Wendy who tried pass through IPR adapter, which was connected to PHB root port directly, to KVM based guest. When doing that, pci_reset_bridge_secondary_bus() was called by VFIO driver and linkDown was detected by the root port. That caused all PEs to be frozen. The patch fixes the issue by routing the reset for the secondary bus of root port to underly firmware. For that, one more weak function pci_reset_secondary_bus() is introduced so that the individual platforms can override that and do specific reset for bridge's secondary bus. Reported-by: Wendy Xiong <wenxiong@linux.vnet.ibm.com> Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Diffstat (limited to 'arch/powerpc/platforms/powernv')
-rw-r--r--arch/powerpc/platforms/powernv/eeh-ioda.c38
-rw-r--r--arch/powerpc/platforms/powernv/pci-ioda.c1
-rw-r--r--arch/powerpc/platforms/powernv/pci.h1
3 files changed, 38 insertions, 2 deletions
diff --git a/arch/powerpc/platforms/powernv/eeh-ioda.c b/arch/powerpc/platforms/powernv/eeh-ioda.c
index 268cd46af8f1..58ef80987eed 100644
--- a/arch/powerpc/platforms/powernv/eeh-ioda.c
+++ b/arch/powerpc/platforms/powernv/eeh-ioda.c
@@ -474,6 +474,8 @@ static int ioda_eeh_bridge_reset(struct pci_dev *dev, int option)
474 474
475{ 475{
476 struct device_node *dn = pci_device_to_OF_node(dev); 476 struct device_node *dn = pci_device_to_OF_node(dev);
477 struct eeh_dev *edev = of_node_to_eeh_dev(dn);
478 int aer = edev ? edev->aer_cap : 0;
477 u32 ctrl; 479 u32 ctrl;
478 480
479 pr_debug("%s: Reset PCI bus %04x:%02x with option %d\n", 481 pr_debug("%s: Reset PCI bus %04x:%02x with option %d\n",
@@ -483,24 +485,56 @@ static int ioda_eeh_bridge_reset(struct pci_dev *dev, int option)
483 switch (option) { 485 switch (option) {
484 case EEH_RESET_FUNDAMENTAL: 486 case EEH_RESET_FUNDAMENTAL:
485 case EEH_RESET_HOT: 487 case EEH_RESET_HOT:
488 /* Don't report linkDown event */
489 if (aer) {
490 eeh_ops->read_config(dn, aer + PCI_ERR_UNCOR_MASK,
491 4, &ctrl);
492 ctrl |= PCI_ERR_UNC_SURPDN;
493 eeh_ops->write_config(dn, aer + PCI_ERR_UNCOR_MASK,
494 4, ctrl);
495 }
496
486 eeh_ops->read_config(dn, PCI_BRIDGE_CONTROL, 2, &ctrl); 497 eeh_ops->read_config(dn, PCI_BRIDGE_CONTROL, 2, &ctrl);
487 ctrl |= PCI_BRIDGE_CTL_BUS_RESET; 498 ctrl |= PCI_BRIDGE_CTL_BUS_RESET;
488 eeh_ops->write_config(dn, PCI_BRIDGE_CONTROL, 2, ctrl); 499 eeh_ops->write_config(dn, PCI_BRIDGE_CONTROL, 2, ctrl);
489
490 msleep(EEH_PE_RST_HOLD_TIME); 500 msleep(EEH_PE_RST_HOLD_TIME);
501
491 break; 502 break;
492 case EEH_RESET_DEACTIVATE: 503 case EEH_RESET_DEACTIVATE:
493 eeh_ops->read_config(dn, PCI_BRIDGE_CONTROL, 2, &ctrl); 504 eeh_ops->read_config(dn, PCI_BRIDGE_CONTROL, 2, &ctrl);
494 ctrl &= ~PCI_BRIDGE_CTL_BUS_RESET; 505 ctrl &= ~PCI_BRIDGE_CTL_BUS_RESET;
495 eeh_ops->write_config(dn, PCI_BRIDGE_CONTROL, 2, ctrl); 506 eeh_ops->write_config(dn, PCI_BRIDGE_CONTROL, 2, ctrl);
496
497 msleep(EEH_PE_RST_SETTLE_TIME); 507 msleep(EEH_PE_RST_SETTLE_TIME);
508
509 /* Continue reporting linkDown event */
510 if (aer) {
511 eeh_ops->read_config(dn, aer + PCI_ERR_UNCOR_MASK,
512 4, &ctrl);
513 ctrl &= ~PCI_ERR_UNC_SURPDN;
514 eeh_ops->write_config(dn, aer + PCI_ERR_UNCOR_MASK,
515 4, ctrl);
516 }
517
498 break; 518 break;
499 } 519 }
500 520
501 return 0; 521 return 0;
502} 522}
503 523
524void pnv_pci_reset_secondary_bus(struct pci_dev *dev)
525{
526 struct pci_controller *hose;
527
528 if (pci_is_root_bus(dev->bus)) {
529 hose = pci_bus_to_host(dev->bus);
530 ioda_eeh_root_reset(hose, EEH_RESET_HOT);
531 ioda_eeh_root_reset(hose, EEH_RESET_DEACTIVATE);
532 } else {
533 ioda_eeh_bridge_reset(dev, EEH_RESET_HOT);
534 ioda_eeh_bridge_reset(dev, EEH_RESET_DEACTIVATE);
535 }
536}
537
504/** 538/**
505 * ioda_eeh_reset - Reset the indicated PE 539 * ioda_eeh_reset - Reset the indicated PE
506 * @pe: EEH PE 540 * @pe: EEH PE
diff --git a/arch/powerpc/platforms/powernv/pci-ioda.c b/arch/powerpc/platforms/powernv/pci-ioda.c
index 98824aa99173..a179ff00be3e 100644
--- a/arch/powerpc/platforms/powernv/pci-ioda.c
+++ b/arch/powerpc/platforms/powernv/pci-ioda.c
@@ -1386,6 +1386,7 @@ void __init pnv_pci_init_ioda_phb(struct device_node *np,
1386 ppc_md.pcibios_fixup = pnv_pci_ioda_fixup; 1386 ppc_md.pcibios_fixup = pnv_pci_ioda_fixup;
1387 ppc_md.pcibios_enable_device_hook = pnv_pci_enable_device_hook; 1387 ppc_md.pcibios_enable_device_hook = pnv_pci_enable_device_hook;
1388 ppc_md.pcibios_window_alignment = pnv_pci_window_alignment; 1388 ppc_md.pcibios_window_alignment = pnv_pci_window_alignment;
1389 ppc_md.pcibios_reset_secondary_bus = pnv_pci_reset_secondary_bus;
1389 pci_add_flags(PCI_REASSIGN_ALL_RSRC); 1390 pci_add_flags(PCI_REASSIGN_ALL_RSRC);
1390 1391
1391 /* Reset IODA tables to a clean state */ 1392 /* Reset IODA tables to a clean state */
diff --git a/arch/powerpc/platforms/powernv/pci.h b/arch/powerpc/platforms/powernv/pci.h
index 39ec6978e809..34a09740aad3 100644
--- a/arch/powerpc/platforms/powernv/pci.h
+++ b/arch/powerpc/platforms/powernv/pci.h
@@ -204,5 +204,6 @@ extern void pnv_pci_init_ioda_hub(struct device_node *np);
204extern void pnv_pci_init_ioda2_phb(struct device_node *np); 204extern void pnv_pci_init_ioda2_phb(struct device_node *np);
205extern void pnv_pci_ioda_tce_invalidate(struct iommu_table *tbl, 205extern void pnv_pci_ioda_tce_invalidate(struct iommu_table *tbl,
206 __be64 *startp, __be64 *endp, bool rm); 206 __be64 *startp, __be64 *endp, bool rm);
207extern void pnv_pci_reset_secondary_bus(struct pci_dev *dev);
207 208
208#endif /* __POWERNV_PCI_H */ 209#endif /* __POWERNV_PCI_H */