diff options
author | kaloz <kaloz@3c298f89-4303-0410-b956-a3cf2f4a3e73> | 2012-09-27 08:05:19 +0000 |
---|---|---|
committer | kaloz <kaloz@3c298f89-4303-0410-b956-a3cf2f4a3e73> | 2012-09-27 08:05:19 +0000 |
commit | b966239c03ed9650a3c751ba2de545ae73b03b41 (patch) | |
tree | 62f947097b9f46a3be6e73a48c7c4e673ce5f6f4 /target/linux | |
parent | c5fa20650a4a63ad92a8d70643ee85e9c37ebbb5 (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
Diffstat (limited to 'target/linux')
-rw-r--r-- | target/linux/cns3xxx/patches-3.3/108-cns3xxx_pcie-abort.patch | 128 |
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 000000000..788b620a8 --- /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; + } + |