summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorkaloz <kaloz@3c298f89-4303-0410-b956-a3cf2f4a3e73>2012-09-27 08:05:19 +0000
committerkaloz <kaloz@3c298f89-4303-0410-b956-a3cf2f4a3e73>2012-09-27 08:05:19 +0000
commitb966239c03ed9650a3c751ba2de545ae73b03b41 (patch)
tree62f947097b9f46a3be6e73a48c7c4e673ce5f6f4
parentc5fa20650a4a63ad92a8d70643ee85e9c37ebbb5 (diff)
[cns3xxx]: fix pcie abort handling
Signed-off-by: Tim Harvey <tharvey@gateworks.com> git-svn-id: svn://svn.openwrt.org/openwrt/trunk@33564 3c298f89-4303-0410-b956-a3cf2f4a3e73
-rw-r--r--target/linux/cns3xxx/patches-3.3/108-cns3xxx_pcie-abort.patch128
1 files changed, 128 insertions, 0 deletions
diff --git a/target/linux/cns3xxx/patches-3.3/108-cns3xxx_pcie-abort.patch b/target/linux/cns3xxx/patches-3.3/108-cns3xxx_pcie-abort.patch
new file mode 100644
index 0000000000..788b620a83
--- /dev/null
+++ b/target/linux/cns3xxx/patches-3.3/108-cns3xxx_pcie-abort.patch
@@ -0,0 +1,128 @@
+--- a/arch/arm/mach-cns3xxx/pcie.c
++++ b/arch/arm/mach-cns3xxx/pcie.c
+@@ -92,6 +92,78 @@ static void __iomem *cns3xxx_pci_cfg_bas
+ return base + offset;
+ }
+
++static inline int check_master_abort(struct pci_bus *bus, unsigned int devfn, int where)
++{
++ struct cns3xxx_pcie *cnspci = pbus_to_cnspci(bus);
++
++ /* check PCI-compatible status register after access */
++ if (cnspci->linked) {
++ u32 host_base, sreg, ereg;
++
++ host_base = cnspci->cfg_bases[CNS3XXX_HOST_TYPE].virtual;
++ sreg = __raw_readw(host_base + 0x6) & 0xF900;
++ ereg = __raw_readl(host_base + 0x104); // Uncorrectable Error Status Reg
++
++ if (sreg | ereg) {
++ /* SREG:
++ * BIT15 - Detected Parity Error
++ * BIT14 - Signaled System Error
++ * BIT13 - Received Master Abort
++ * BIT12 - Received Target Abort
++ * BIT11 - Signaled Target Abort
++ * BIT08 - Master Data Parity Error
++ *
++ * EREG:
++ * BIT20 - Unsupported Request
++ * BIT19 - ECRC
++ * BIT18 - Malformed TLP
++ * BIT17 - Receiver Overflow
++ * BIT16 - Unexpected Completion
++ * BIT15 - Completer Abort
++ * BIT14 - Completion Timeout
++ * BIT13 - Flow Control Protocol Error
++ * BIT12 - Poisoned TLP
++ * BIT04 - Data Link Protocol Error
++ *
++ * TODO: see Documentation/pci-error-recovery.txt
++ * implement error_detected handler
++ */
++/*
++ printk("pci error: %04d:%02x:%02x.%02x sreg=0x%04x ereg=0x%08x", pci_domain_nr(bus), bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn), sreg, ereg);
++ if (sreg & BIT(15)) printk(" <PERR");
++ if (sreg & BIT(14)) printk(" >SERR");
++ if (sreg & BIT(13)) printk(" <MABRT");
++ if (sreg & BIT(12)) printk(" <TABRT");
++ if (sreg & BIT(11)) printk(" >TABRT");
++ if (sreg & BIT( 8)) printk(" MPERR");
++
++ if (ereg & BIT(20)) printk(" Unsup");
++ if (ereg & BIT(19)) printk(" ECRC");
++ if (ereg & BIT(18)) printk(" MTLP");
++ if (ereg & BIT(17)) printk(" OFLOW");
++ if (ereg & BIT(16)) printk(" Unex");
++ if (ereg & BIT(15)) printk(" ABRT");
++ if (ereg & BIT(14)) printk(" COMPTO");
++ if (ereg & BIT(13)) printk(" FLOW");
++ if (ereg & BIT(12)) printk(" PTLP");
++ if (ereg & BIT( 4)) printk(" DLINK");
++ printk("\n");
++*/
++ pr_debug("%s failed port%d sreg=0x%04x\n", __func__,
++ cnspci->hw_pci.domain, sreg);
++
++ /* make sure the status bits are reset */
++ __raw_writew(sreg, host_base + 6);
++ __raw_writel(ereg, host_base + 0x104);
++ return 1;
++ }
++ }
++ else
++ return 1;
++
++ return 0;
++}
++
+ static int cns3xxx_pci_read_config(struct pci_bus *bus, unsigned int devfn,
+ int where, int size, u32 *val)
+ {
+@@ -108,6 +180,11 @@ static int cns3xxx_pci_read_config(struc
+
+ v = __raw_readl(base);
+
++ if (check_master_abort(bus, devfn, where)) {
++ printk(KERN_ERR "pci error: %04d:%02x:%02x.%02x %02x(%d)= master_abort on read\n", pci_domain_nr(bus), bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn), where, size);
++ return PCIBIOS_DEVICE_NOT_FOUND;
++ }
++
+ if (bus->number == 0 && devfn == 0 &&
+ (where & 0xffc) == PCI_CLASS_REVISION) {
+ /*
+@@ -137,11 +214,19 @@ static int cns3xxx_pci_write_config(stru
+ return PCIBIOS_SUCCESSFUL;
+
+ v = __raw_readl(base);
++ if (check_master_abort(bus, devfn, where)) {
++ printk(KERN_ERR "pci error: %04d:%02x:%02x.%02x %02x(%d)=0x%08x master_abort on read\n", pci_domain_nr(bus), bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn), where, size, val);
++ return PCIBIOS_DEVICE_NOT_FOUND;
++ }
+
+ v &= ~(mask << shift);
+ v |= (val & mask) << shift;
+
+ __raw_writel(v, base);
++ if (check_master_abort(bus, devfn, where)) {
++ printk(KERN_ERR "pci error: %04d:%02x:%02x.%02x %02x(%d)=0x%08x master_abort on write\n", pci_domain_nr(bus), bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn), where, size, val);
++ return PCIBIOS_DEVICE_NOT_FOUND;
++ }
+
+ return PCIBIOS_SUCCESSFUL;
+ }
+@@ -360,8 +445,14 @@ static void __init cns3xxx_pcie_hw_init(
+ static int cns3xxx_pcie_abort_handler(unsigned long addr, unsigned int fsr,
+ struct pt_regs *regs)
+ {
++#if 0
++/* R14_ABORT = PC+4 for XSCALE but not ARM11MPCORE
++ * ignore imprecise aborts and use PCI-compatible Status register to
++ * determine errors instead
++ */
+ if (fsr & (1 << 10))
+ regs->ARM_pc += 4;
++#endif
+ return 0;
+ }
+