--- 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(" SERR"); + if (sreg & BIT(13)) 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_read32(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; }