aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/cns3xxx/patches-3.3/108-cns3xxx_pcie-abort.patch
blob: 788b620a838d5e7de789da2c42f69eebadb2299f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
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;
 }