[Skiboot] [PATCH v2 8/9] hw/phb3: Disable surprise link down event on PCI slots

Gavin Shan gwshan at linux.vnet.ibm.com
Thu Oct 13 12:16:52 AEDT 2016


This masks surprise link down event on RC or downtream ports
if the PCI slots behind them support PCI surprise hotplug. The
event should be handled by PCI hotplug driver instead of EEH
subsystem.

Signed-off-by: Gavin Shan <gwshan at linux.vnet.ibm.com>
---
 core/pci-slot.c | 24 +++++++++++++++---------
 hw/phb3.c       | 57 +++++++++++++++++++++++++++++++++++++++++++++++++--------
 2 files changed, 64 insertions(+), 17 deletions(-)

diff --git a/core/pci-slot.c b/core/pci-slot.c
index 721b2d9..aa4bea6 100644
--- a/core/pci-slot.c
+++ b/core/pci-slot.c
@@ -38,15 +38,21 @@ static void pci_slot_prepare_link_change(struct pci_slot *slot, bool up)
 	if (pci_has_cap(pd, PCIECAP_ID_AER, true)) {
 		aercap = pci_cap(pd, PCIECAP_ID_AER, true);
 
-		/* Link down error */
-		pci_cfg_read32(phb, pd->bdfn, aercap + PCIECAP_AER_UE_MASK,
-			       &mask);
-		if (up)
-			mask &= ~PCIECAP_AER_UE_MASK_SURPRISE_DOWN;
-		else
-			mask |= PCIECAP_AER_UE_MASK_SURPRISE_DOWN;
-		pci_cfg_write32(phb, pd->bdfn, aercap + PCIECAP_AER_UE_MASK,
-				mask);
+		/* Mask link surprise down event. The event is always
+		 * masked when the associated PCI slot supports PCI
+		 * surprise hotplug. We needn't toggle it when the link
+		 * bounces caused by reset and just keep it always masked.
+		 */
+		if (!pd->slot || !pd->slot->surprise_pluggable) {
+			pci_cfg_read32(phb, pd->bdfn,
+				       aercap + PCIECAP_AER_UE_MASK, &mask);
+			if (up)
+				mask &= ~PCIECAP_AER_UE_MASK_SURPRISE_DOWN;
+			else
+				mask |= PCIECAP_AER_UE_MASK_SURPRISE_DOWN;
+			pci_cfg_write32(phb, pd->bdfn,
+					aercap + PCIECAP_AER_UE_MASK, mask);
+		}
 
 		/* Receiver error */
 		pci_cfg_read32(phb, pd->bdfn, aercap + PCIECAP_AER_CE_MASK,
diff --git a/hw/phb3.c b/hw/phb3.c
index 2a05fcc..35bc73a 100644
--- a/hw/phb3.c
+++ b/hw/phb3.c
@@ -279,10 +279,18 @@ static int64_t phb3_get_reserved_pe_number(struct phb *phb __unused)
 static void phb3_root_port_init(struct phb *phb, struct pci_device *dev,
 				int ecap, int aercap)
 {
+	struct phb3 *p = phb_to_phb3(phb);
 	uint16_t bdfn = dev->bdfn;
 	uint16_t val16;
 	uint32_t val32;
 
+	/* Mask UTL link down event if root slot supports surprise
+	 * hotplug as the event should be handled by hotplug driver
+	 * instead of EEH subsystem.
+	 */
+	if (dev->slot && dev->slot->surprise_pluggable)
+		out_be64(p->regs + UTL_PCIE_PORT_IRQ_EN, 0xad42800000000000);
+
 	/* Enable SERR and parity checking */
 	pci_cfg_read16(phb, bdfn, PCI_CFG_CMD, &val16);
 	val16 |= (PCI_CFG_CMD_SERR_EN | PCI_CFG_CMD_PERR_RESP);
@@ -299,12 +307,18 @@ static void phb3_root_port_init(struct phb *phb, struct pci_device *dev,
 
 	if (!aercap) return;
 
-	/* Mask various unrecoverable errors */
+	/* Mask various unrecoverable errors. The link surprise down
+	 * event should be masked when its PCI slot support surprise
+	 * hotplug. The link surprise down event should be handled by
+	 * PCI hotplug driver instead of EEH subsystem.
+	 */
 	pci_cfg_read32(phb, bdfn, aercap + PCIECAP_AER_UE_MASK, &val32);
 	val32 |= (PCIECAP_AER_UE_MASK_POISON_TLP |
 		  PCIECAP_AER_UE_MASK_COMPL_TIMEOUT |
 		  PCIECAP_AER_UE_MASK_COMPL_ABORT |
 		  PCIECAP_AER_UE_MASK_ECRC);
+	if (dev->slot && dev->slot->surprise_pluggable)
+		val32 |= PCIECAP_AER_UE_MASK_SURPRISE_DOWN;
 	pci_cfg_write32(phb, bdfn, aercap + PCIECAP_AER_UE_MASK, val32);
 
 	/* Report various unrecoverable errors as fatal errors */
@@ -368,9 +382,18 @@ static void phb3_switch_port_init(struct phb *phb,
 	val16 &= ~PCICAP_EXP_DEVCTL_CE_REPORT;
 	pci_cfg_write16(phb, bdfn, ecap + PCICAP_EXP_DEVCTL, val16);
 
-	/* Unmask all unrecoverable errors */
+	/* Unmask all unrecoverable errors for upstream port. For
+	 * downstream port, the surprise link down is masked because
+	 * it should be handled by hotplug driver instead of EEH
+	 * subsystem.
+	 */
 	if (!aercap) return;
-	pci_cfg_write32(phb, bdfn, aercap + PCIECAP_AER_UE_MASK, 0x0);
+	if (dev->dev_type == PCIE_TYPE_SWITCH_DNPORT &&
+	    dev->slot && dev->slot->surprise_pluggable)
+		pci_cfg_write32(phb, bdfn, aercap + PCIECAP_AER_UE_MASK,
+				PCIECAP_AER_UE_MASK_SURPRISE_DOWN);
+	else
+		pci_cfg_write32(phb, bdfn, aercap + PCIECAP_AER_UE_MASK, 0x0);
 
 	/* Severity of unrecoverable errors */
 	if (dev->dev_type == PCIE_TYPE_SWITCH_UPPORT)
@@ -1963,13 +1986,22 @@ static void phb3_prepare_link_change(struct pci_slot *slot,
 				     bool is_up)
 {
 	struct phb3 *p = phb_to_phb3(slot->phb);
+	struct pci_device *pd = slot->pd;
 	uint32_t reg32;
 
 	p->has_link = is_up;
 	if (!is_up) {
-		/* Mask PCIE port interrupts */
-		out_be64(p->regs + UTL_PCIE_PORT_IRQ_EN,
-			 0xad42800000000000);
+		if (!pd || !pd->slot || !pd->slot->surprise_pluggable) {
+			/* Mask PCIE port interrupts */
+			out_be64(p->regs + UTL_PCIE_PORT_IRQ_EN,
+				 0xad42800000000000);
+
+			pci_cfg_read32(&p->phb, 0,
+				       p->aercap + PCIECAP_AER_UE_MASK, &reg32);
+			reg32 |= PCIECAP_AER_UE_MASK_SURPRISE_DOWN;
+			pci_cfg_write32(&p->phb, 0,
+					p->aercap + PCIECAP_AER_UE_MASK, reg32);
+                }
 
 		/* Mask AER receiver error */
 		phb3_pcicfg_read32(&p->phb, 0,
@@ -1996,8 +2028,17 @@ static void phb3_prepare_link_change(struct pci_slot *slot,
 		/* Clear spurrious errors and enable PCIE port interrupts */
 		out_be64(p->regs + UTL_PCIE_PORT_STATUS,
 			 0xffdfffffffffffff);
-		out_be64(p->regs + UTL_PCIE_PORT_IRQ_EN,
-			 0xad52800000000000);
+
+		if (!pd || !pd->slot || !pd->slot->surprise_pluggable) {
+			out_be64(p->regs + UTL_PCIE_PORT_IRQ_EN,
+				 0xad52800000000000);
+
+			pci_cfg_read32(&p->phb, 0,
+				       p->aercap + PCIECAP_AER_UE_MASK, &reg32);
+			reg32 &= ~PCIECAP_AER_UE_MASK_SURPRISE_DOWN;
+			pci_cfg_write32(&p->phb, 0,
+					p->aercap + PCIECAP_AER_UE_MASK, reg32);
+		}
 
 		/* Don't block PCI-CFG */
 		p->flags &= ~PHB3_CFG_BLOCKED;
-- 
2.1.0



More information about the Skiboot mailing list