aboutsummaryrefslogtreecommitdiff
path: root/core
diff options
context:
space:
mode:
authorGavin Shan <gwshan@linux.vnet.ibm.com>2015-09-11 14:36:34 +1000
committerStewart Smith <stewart@linux.vnet.ibm.com>2015-09-15 16:15:41 +1000
commitc34905c558bfd0773da0adf8b7f7d8bedea480a8 (patch)
treecdf2ed4aa9a169c7a6fe22c9c71609e363098b01 /core
parentef186c6ce6c9e730a91263aac38153e4257fb354 (diff)
downloadskiboot-c34905c558bfd0773da0adf8b7f7d8bedea480a8.zip
skiboot-c34905c558bfd0773da0adf8b7f7d8bedea480a8.tar.gz
skiboot-c34905c558bfd0773da0adf8b7f7d8bedea480a8.tar.bz2
PCI: Clear error bits after changing MPS
Chaning MPS on PCI upstream bridge might cause error bits set on downstream endpoints when system boots into Linux as below case shows: host# lspci -vvs 0001:06:00.0 0001:06:00.0 Ethernet controller: Broadcom Corporation \ NetXtreme II BCM57810 10 Gigabit Ethernet (rev 10) : DevSta: CorrErr+ UncorrErr- FatalErr- UnsuppReq+ AuxPwr- TransPend- : CESta: RxErr- BadTLP- BadDLLP- Rollover- Timeout- NonFatalErr+ This clears those error bits in AER and PCIe capability after MPS is changed. With the patch applied, no more error bits are seen. Reported-by: John Walthour <jwalthour@us.ibm.com> Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com> Signed-off-by: Stewart Smith <stewart@linux.vnet.ibm.com>
Diffstat (limited to 'core')
-rw-r--r--core/pci.c22
1 files changed, 19 insertions, 3 deletions
diff --git a/core/pci.c b/core/pci.c
index 26ed48c..6cfb3cb 100644
--- a/core/pci.c
+++ b/core/pci.c
@@ -609,20 +609,23 @@ static int pci_configure_mps(struct phb *phb,
struct pci_device *pd,
void *userdata __unused)
{
- uint32_t ecap, mps;
+ uint32_t ecap, aercap, mps;
uint16_t val;
assert(phb);
assert(pd);
- mps = phb->mps;
/* If the MPS isn't acceptable one, bail immediately */
+ mps = phb->mps;
if (mps < 128 || mps > 4096)
return 1;
+ /* Retrieve PCIe and AER capability */
+ ecap = pci_cap(pd, PCI_CFG_CAP_ID_EXP, false);
+ aercap = pci_cap(pd, PCIECAP_ID_AER, true);
+
/* PCIe device always has MPS capacity */
if (pd->mps) {
- ecap = pci_cap(pd, PCI_CFG_CAP_ID_EXP, false);
mps = ilog2(mps) - 7;
pci_cfg_read16(phb, pd->bdfn, ecap + PCICAP_EXP_DEVCTL, &val);
@@ -630,6 +633,19 @@ static int pci_configure_mps(struct phb *phb,
pci_cfg_write16(phb, pd->bdfn, ecap + PCICAP_EXP_DEVCTL, val);
}
+ /* Changing MPS on upstream PCI bridge might cause some error
+ * bits in PCIe and AER capability. To clear them to avoid
+ * confusion.
+ */
+ if (aercap) {
+ pci_cfg_write32(phb, pd->bdfn, aercap + PCIECAP_AER_UE_STATUS,
+ 0xffffffff);
+ pci_cfg_write32(phb, pd->bdfn, aercap + PCIECAP_AER_CE_STATUS,
+ 0xffffffff);
+ }
+ if (ecap)
+ pci_cfg_write16(phb, pd->bdfn, ecap + PCICAP_EXP_DEVSTAT, 0xf);
+
return 0;
}