OpenWrt – Rev 1

Subversion Repositories:
Rev:
--- a/arch/arm/mach-cns3xxx/pcie.c
+++ b/arch/arm/mach-cns3xxx/pcie.c
@@ -86,6 +86,79 @@ static void __iomem *cns3xxx_pci_map_bus
        return base + where + (devfn << 12);
 }
 
+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) {
+               void __iomem *host_base;
+               u32 sreg, ereg;
+
+               host_base = (void __iomem *) 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__,
+                               pci_domain_nr(bus), 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)
 {
@@ -95,6 +168,11 @@ static int cns3xxx_pci_read_config(struc
 
        ret = pci_generic_config_read(bus, devfn, where, size, val);
 
+       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 (ret == PCIBIOS_SUCCESSFUL && !bus->number && !devfn &&
            (where & 0xffc) == PCI_CLASS_REVISION)
                /*
@@ -257,8 +335,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;
 }