aboutsummaryrefslogtreecommitdiff
path: root/hw
diff options
context:
space:
mode:
authorMichael Neuling <mikey@neuling.org>2017-07-26 20:50:00 +1000
committerStewart Smith <stewart@linux.vnet.ibm.com>2017-07-28 14:03:59 +1000
commit5a8c57b6f2fcb46f1cac1840062a542c597996f9 (patch)
tree69bac7a91ca47300e194da61c75052ad98aa2aef /hw
parentfb64fdbc253b5b6b301c0680ec5eb040ae52f54d (diff)
downloadskiboot-5a8c57b6f2fcb46f1cac1840062a542c597996f9.zip
skiboot-5a8c57b6f2fcb46f1cac1840062a542c597996f9.tar.gz
skiboot-5a8c57b6f2fcb46f1cac1840062a542c597996f9.tar.bz2
phb4: Only clear some PHB config space registers on errors
Currently on error we clear the entire PHB config space. This is a problem as the PCIe Maximum Payload Size (MPS) negotiation may have already occurred. Clearing MPS in the PHB back to a default of 128 bytes will result an error for a device which already has a larger MPS configured. This will manifest itself as error due to a malformed TLP packet. ie. phbPblErrorStatus bit 41 = "Malformed TLP error" This has been seen after kexec on with some adapters. This fixes the problem by only clearing a subset of registers on a phb error. Reported-by: Rob Lippert <rlippert@google.com> Signed-off-by: Michael Neuling <mikey@neuling.org> Signed-off-by: Stewart Smith <stewart@linux.vnet.ibm.com>
Diffstat (limited to 'hw')
-rw-r--r--hw/phb4.c51
1 files changed, 32 insertions, 19 deletions
diff --git a/hw/phb4.c b/hw/phb4.c
index cdc02ca..8a4d055 100644
--- a/hw/phb4.c
+++ b/hw/phb4.c
@@ -120,7 +120,6 @@
#define DISABLE_ERR_INTS
static void phb4_init_hw(struct phb4 *p, bool first_init);
-static bool phb4_init_rc_cfg(struct phb4 *p);
#define PHBDBG(p, fmt, a...) prlog(PR_DEBUG, "PHB#%04x[%d:%d]: " fmt, \
(p)->phb.opal_id, (p)->chip_id, \
@@ -1792,6 +1791,34 @@ static int64_t phb4_get_msi_64(struct phb *phb,
return OPAL_SUCCESS;
}
+static void phb4_rc_err_clear(struct phb4 *p)
+{
+ /* Init_47 - Clear errors */
+ phb4_pcicfg_write16(&p->phb, 0, PCI_CFG_SECONDARY_STATUS, 0xffff);
+
+ if (p->ecap <= 0)
+ return;
+
+ phb4_pcicfg_write16(&p->phb, 0, p->ecap + PCICAP_EXP_DEVSTAT,
+ PCICAP_EXP_DEVSTAT_CE |
+ PCICAP_EXP_DEVSTAT_NFE |
+ PCICAP_EXP_DEVSTAT_FE |
+ PCICAP_EXP_DEVSTAT_UE);
+
+ if (p->aercap <= 0)
+ return;
+
+ /* Clear all UE status */
+ phb4_pcicfg_write32(&p->phb, 0, p->aercap + PCIECAP_AER_UE_STATUS,
+ 0xffffffff);
+ /* Clear all CE status */
+ phb4_pcicfg_write32(&p->phb, 0, p->aercap + PCIECAP_AER_CE_STATUS,
+ 0xffffffff);
+ /* Clear root error status */
+ phb4_pcicfg_write32(&p->phb, 0, p->aercap + PCIECAP_AER_RERR_STA,
+ 0xffffffff);
+}
+
/*
* The function can be called during error recovery for all classes of
* errors. This is new to PHB4; previous revisions had separate
@@ -1808,8 +1835,7 @@ static void phb4_err_clear(struct phb4 *p)
/* Rec 1: Acquire the PCI config lock (we don't need to do this) */
/* Rec 2...15: Clear error status in RC config space */
- /* Reset steps are the same as the init sequence */
- phb4_init_rc_cfg(p);
+ phb4_rc_err_clear(p);
/* Rec 16/17: Clear PBL errors */
val64 = phb4_read_reg(p, PHB_PBL_ERR_STATUS);
@@ -3667,7 +3693,7 @@ static bool phb4_init_rc_cfg(struct phb4 *p)
phb4_pcicfg_write32(&p->phb, 0, PCI_CFG_PRIMARY_BUS, 0x00ff0100);
/* Init_47 - Clear errors */
- phb4_pcicfg_write16(&p->phb, 0, PCI_CFG_SECONDARY_STATUS, 0xffff);
+ /* see phb4_rc_err_clear() called below */
/* Init_48
*
@@ -3693,12 +3719,6 @@ static bool phb4_init_rc_cfg(struct phb4 *p)
ecap = p->ecap;
}
- phb4_pcicfg_write16(&p->phb, 0, ecap + PCICAP_EXP_DEVSTAT,
- PCICAP_EXP_DEVSTAT_CE |
- PCICAP_EXP_DEVSTAT_NFE |
- PCICAP_EXP_DEVSTAT_FE |
- PCICAP_EXP_DEVSTAT_UE);
-
phb4_pcicfg_write16(&p->phb, 0, ecap + PCICAP_EXP_DEVCTL,
PCICAP_EXP_DEVCTL_CE_REPORT |
PCICAP_EXP_DEVCTL_NFE_REPORT |
@@ -3726,25 +3746,18 @@ static bool phb4_init_rc_cfg(struct phb4 *p)
aercap = p->aercap;
}
- /* Clear all UE status */
- phb4_pcicfg_write32(&p->phb, 0, aercap + PCIECAP_AER_UE_STATUS,
- 0xffffffff);
/* Disable some error reporting as per the PHB4 spec */
phb4_pcicfg_write32(&p->phb, 0, aercap + PCIECAP_AER_UE_MASK,
PCIECAP_AER_UE_POISON_TLP |
PCIECAP_AER_UE_COMPL_TIMEOUT |
PCIECAP_AER_UE_COMPL_ABORT);
- /* Clear all CE status */
- phb4_pcicfg_write32(&p->phb, 0, aercap + PCIECAP_AER_CE_STATUS,
- 0xffffffff);
/* Enable ECRC generation & checking */
phb4_pcicfg_write32(&p->phb, 0, aercap + PCIECAP_AER_CAPCTL,
PCIECAP_AER_CAPCTL_ECRCG_EN |
PCIECAP_AER_CAPCTL_ECRCC_EN);
- /* Clear root error status */
- phb4_pcicfg_write32(&p->phb, 0, aercap + PCIECAP_AER_RERR_STA,
- 0xffffffff);
+
+ phb4_rc_err_clear(p);
return true;
}