aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGavin Shan <gwshan@linux.vnet.ibm.com>2016-10-14 15:26:06 +1100
committerStewart Smith <stewart@linux.vnet.ibm.com>2016-10-17 10:33:57 +1100
commit5f3720f2c8ad6c423493be06e6f84418c511ce39 (patch)
tree392b7870cba62d15822656bf8db4b535a046bc45
parent51931bad325e3feba934eaf95b422deeb24cf4e5 (diff)
downloadskiboot-5f3720f2c8ad6c423493be06e6f84418c511ce39.zip
skiboot-5f3720f2c8ad6c423493be06e6f84418c511ce39.tar.gz
skiboot-5f3720f2c8ad6c423493be06e6f84418c511ce39.tar.bz2
hw/phb3: Disable surprise link down event on PCI slots
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@linux.vnet.ibm.com> Signed-off-by: Stewart Smith <stewart@linux.vnet.ibm.com>
-rw-r--r--core/pci-slot.c24
-rw-r--r--hw/phb3.c57
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;