diff mbox

PCI: Clear error bits after changing MPS

Message ID 1441946194-22437-1-git-send-email-gwshan@linux.vnet.ibm.com
State Accepted
Headers show

Commit Message

Gavin Shan Sept. 11, 2015, 4:36 a.m. UTC
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>
---
 core/pci.c | 22 +++++++++++++++++++---
 1 file changed, 19 insertions(+), 3 deletions(-)

Comments

Stewart Smith Sept. 15, 2015, 7:23 a.m. UTC | #1
Gavin Shan <gwshan@linux.vnet.ibm.com> writes:
> 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>

Thanks, merged at c34905c
diff mbox

Patch

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;
 }