Commit | Line | Data |
---|---|---|
8bf993a5 JA |
1 | // SPDX-License-Identifier: (GPL-2.0 OR MIT) |
2 | // Copyright (c) 2017 Synopsys, Inc. and/or its affiliates. | |
3 | // stmmac Support for 5.xx Ethernet QoS cores | |
4 | ||
5 | #include <linux/bitops.h> | |
6 | #include <linux/iopoll.h> | |
7 | #include "common.h" | |
8 | #include "dwmac4.h" | |
9 | #include "dwmac5.h" | |
10 | ||
11 | struct dwmac5_error_desc { | |
12 | bool valid; | |
13 | const char *desc; | |
14 | const char *detailed_desc; | |
15 | }; | |
16 | ||
17 | #define STAT_OFF(field) offsetof(struct stmmac_safety_stats, field) | |
18 | ||
19 | static void dwmac5_log_error(struct net_device *ndev, u32 value, bool corr, | |
20 | const char *module_name, const struct dwmac5_error_desc *desc, | |
21 | unsigned long field_offset, struct stmmac_safety_stats *stats) | |
22 | { | |
23 | unsigned long loc, mask; | |
24 | u8 *bptr = (u8 *)stats; | |
25 | unsigned long *ptr; | |
26 | ||
27 | ptr = (unsigned long *)(bptr + field_offset); | |
28 | ||
29 | mask = value; | |
30 | for_each_set_bit(loc, &mask, 32) { | |
31 | netdev_err(ndev, "Found %s error in %s: '%s: %s'\n", corr ? | |
32 | "correctable" : "uncorrectable", module_name, | |
33 | desc[loc].desc, desc[loc].detailed_desc); | |
34 | ||
35 | /* Update counters */ | |
36 | ptr[loc]++; | |
37 | } | |
38 | } | |
39 | ||
40 | static const struct dwmac5_error_desc dwmac5_mac_errors[32]= { | |
41 | { true, "ATPES", "Application Transmit Interface Parity Check Error" }, | |
42 | { true, "TPES", "TSO Data Path Parity Check Error" }, | |
43 | { true, "RDPES", "Read Descriptor Parity Check Error" }, | |
44 | { true, "MPES", "MTL Data Path Parity Check Error" }, | |
45 | { true, "MTSPES", "MTL TX Status Data Path Parity Check Error" }, | |
46 | { true, "ARPES", "Application Receive Interface Data Path Parity Check Error" }, | |
47 | { true, "CWPES", "CSR Write Data Path Parity Check Error" }, | |
48 | { true, "ASRPES", "AXI Slave Read Data Path Parity Check Error" }, | |
49 | { true, "TTES", "TX FSM Timeout Error" }, | |
50 | { true, "RTES", "RX FSM Timeout Error" }, | |
51 | { true, "CTES", "CSR FSM Timeout Error" }, | |
52 | { true, "ATES", "APP FSM Timeout Error" }, | |
53 | { true, "PTES", "PTP FSM Timeout Error" }, | |
54 | { true, "T125ES", "TX125 FSM Timeout Error" }, | |
55 | { true, "R125ES", "RX125 FSM Timeout Error" }, | |
56 | { true, "RVCTES", "REV MDC FSM Timeout Error" }, | |
57 | { true, "MSTTES", "Master Read/Write Timeout Error" }, | |
58 | { true, "SLVTES", "Slave Read/Write Timeout Error" }, | |
59 | { true, "ATITES", "Application Timeout on ATI Interface Error" }, | |
60 | { true, "ARITES", "Application Timeout on ARI Interface Error" }, | |
61 | { false, "UNKNOWN", "Unknown Error" }, /* 20 */ | |
62 | { false, "UNKNOWN", "Unknown Error" }, /* 21 */ | |
63 | { false, "UNKNOWN", "Unknown Error" }, /* 22 */ | |
64 | { false, "UNKNOWN", "Unknown Error" }, /* 23 */ | |
65 | { true, "FSMPES", "FSM State Parity Error" }, | |
66 | { false, "UNKNOWN", "Unknown Error" }, /* 25 */ | |
67 | { false, "UNKNOWN", "Unknown Error" }, /* 26 */ | |
68 | { false, "UNKNOWN", "Unknown Error" }, /* 27 */ | |
69 | { false, "UNKNOWN", "Unknown Error" }, /* 28 */ | |
70 | { false, "UNKNOWN", "Unknown Error" }, /* 29 */ | |
71 | { false, "UNKNOWN", "Unknown Error" }, /* 30 */ | |
72 | { false, "UNKNOWN", "Unknown Error" }, /* 31 */ | |
73 | }; | |
74 | ||
75 | static void dwmac5_handle_mac_err(struct net_device *ndev, | |
76 | void __iomem *ioaddr, bool correctable, | |
77 | struct stmmac_safety_stats *stats) | |
78 | { | |
79 | u32 value; | |
80 | ||
81 | value = readl(ioaddr + MAC_DPP_FSM_INT_STATUS); | |
82 | writel(value, ioaddr + MAC_DPP_FSM_INT_STATUS); | |
83 | ||
84 | dwmac5_log_error(ndev, value, correctable, "MAC", dwmac5_mac_errors, | |
85 | STAT_OFF(mac_errors), stats); | |
86 | } | |
87 | ||
88 | static const struct dwmac5_error_desc dwmac5_mtl_errors[32]= { | |
89 | { true, "TXCES", "MTL TX Memory Error" }, | |
90 | { true, "TXAMS", "MTL TX Memory Address Mismatch Error" }, | |
91 | { true, "TXUES", "MTL TX Memory Error" }, | |
92 | { false, "UNKNOWN", "Unknown Error" }, /* 3 */ | |
93 | { true, "RXCES", "MTL RX Memory Error" }, | |
94 | { true, "RXAMS", "MTL RX Memory Address Mismatch Error" }, | |
95 | { true, "RXUES", "MTL RX Memory Error" }, | |
96 | { false, "UNKNOWN", "Unknown Error" }, /* 7 */ | |
97 | { true, "ECES", "MTL EST Memory Error" }, | |
98 | { true, "EAMS", "MTL EST Memory Address Mismatch Error" }, | |
99 | { true, "EUES", "MTL EST Memory Error" }, | |
100 | { false, "UNKNOWN", "Unknown Error" }, /* 11 */ | |
101 | { true, "RPCES", "MTL RX Parser Memory Error" }, | |
102 | { true, "RPAMS", "MTL RX Parser Memory Address Mismatch Error" }, | |
103 | { true, "RPUES", "MTL RX Parser Memory Error" }, | |
104 | { false, "UNKNOWN", "Unknown Error" }, /* 15 */ | |
105 | { false, "UNKNOWN", "Unknown Error" }, /* 16 */ | |
106 | { false, "UNKNOWN", "Unknown Error" }, /* 17 */ | |
107 | { false, "UNKNOWN", "Unknown Error" }, /* 18 */ | |
108 | { false, "UNKNOWN", "Unknown Error" }, /* 19 */ | |
109 | { false, "UNKNOWN", "Unknown Error" }, /* 20 */ | |
110 | { false, "UNKNOWN", "Unknown Error" }, /* 21 */ | |
111 | { false, "UNKNOWN", "Unknown Error" }, /* 22 */ | |
112 | { false, "UNKNOWN", "Unknown Error" }, /* 23 */ | |
113 | { false, "UNKNOWN", "Unknown Error" }, /* 24 */ | |
114 | { false, "UNKNOWN", "Unknown Error" }, /* 25 */ | |
115 | { false, "UNKNOWN", "Unknown Error" }, /* 26 */ | |
116 | { false, "UNKNOWN", "Unknown Error" }, /* 27 */ | |
117 | { false, "UNKNOWN", "Unknown Error" }, /* 28 */ | |
118 | { false, "UNKNOWN", "Unknown Error" }, /* 29 */ | |
119 | { false, "UNKNOWN", "Unknown Error" }, /* 30 */ | |
120 | { false, "UNKNOWN", "Unknown Error" }, /* 31 */ | |
121 | }; | |
122 | ||
123 | static void dwmac5_handle_mtl_err(struct net_device *ndev, | |
124 | void __iomem *ioaddr, bool correctable, | |
125 | struct stmmac_safety_stats *stats) | |
126 | { | |
127 | u32 value; | |
128 | ||
129 | value = readl(ioaddr + MTL_ECC_INT_STATUS); | |
130 | writel(value, ioaddr + MTL_ECC_INT_STATUS); | |
131 | ||
132 | dwmac5_log_error(ndev, value, correctable, "MTL", dwmac5_mtl_errors, | |
133 | STAT_OFF(mtl_errors), stats); | |
134 | } | |
135 | ||
136 | static const struct dwmac5_error_desc dwmac5_dma_errors[32]= { | |
137 | { true, "TCES", "DMA TSO Memory Error" }, | |
138 | { true, "TAMS", "DMA TSO Memory Address Mismatch Error" }, | |
139 | { true, "TUES", "DMA TSO Memory Error" }, | |
140 | { false, "UNKNOWN", "Unknown Error" }, /* 3 */ | |
141 | { false, "UNKNOWN", "Unknown Error" }, /* 4 */ | |
142 | { false, "UNKNOWN", "Unknown Error" }, /* 5 */ | |
143 | { false, "UNKNOWN", "Unknown Error" }, /* 6 */ | |
144 | { false, "UNKNOWN", "Unknown Error" }, /* 7 */ | |
145 | { false, "UNKNOWN", "Unknown Error" }, /* 8 */ | |
146 | { false, "UNKNOWN", "Unknown Error" }, /* 9 */ | |
147 | { false, "UNKNOWN", "Unknown Error" }, /* 10 */ | |
148 | { false, "UNKNOWN", "Unknown Error" }, /* 11 */ | |
149 | { false, "UNKNOWN", "Unknown Error" }, /* 12 */ | |
150 | { false, "UNKNOWN", "Unknown Error" }, /* 13 */ | |
151 | { false, "UNKNOWN", "Unknown Error" }, /* 14 */ | |
152 | { false, "UNKNOWN", "Unknown Error" }, /* 15 */ | |
153 | { false, "UNKNOWN", "Unknown Error" }, /* 16 */ | |
154 | { false, "UNKNOWN", "Unknown Error" }, /* 17 */ | |
155 | { false, "UNKNOWN", "Unknown Error" }, /* 18 */ | |
156 | { false, "UNKNOWN", "Unknown Error" }, /* 19 */ | |
157 | { false, "UNKNOWN", "Unknown Error" }, /* 20 */ | |
158 | { false, "UNKNOWN", "Unknown Error" }, /* 21 */ | |
159 | { false, "UNKNOWN", "Unknown Error" }, /* 22 */ | |
160 | { false, "UNKNOWN", "Unknown Error" }, /* 23 */ | |
161 | { false, "UNKNOWN", "Unknown Error" }, /* 24 */ | |
162 | { false, "UNKNOWN", "Unknown Error" }, /* 25 */ | |
163 | { false, "UNKNOWN", "Unknown Error" }, /* 26 */ | |
164 | { false, "UNKNOWN", "Unknown Error" }, /* 27 */ | |
165 | { false, "UNKNOWN", "Unknown Error" }, /* 28 */ | |
166 | { false, "UNKNOWN", "Unknown Error" }, /* 29 */ | |
167 | { false, "UNKNOWN", "Unknown Error" }, /* 30 */ | |
168 | { false, "UNKNOWN", "Unknown Error" }, /* 31 */ | |
169 | }; | |
170 | ||
171 | static void dwmac5_handle_dma_err(struct net_device *ndev, | |
172 | void __iomem *ioaddr, bool correctable, | |
173 | struct stmmac_safety_stats *stats) | |
174 | { | |
175 | u32 value; | |
176 | ||
177 | value = readl(ioaddr + DMA_ECC_INT_STATUS); | |
178 | writel(value, ioaddr + DMA_ECC_INT_STATUS); | |
179 | ||
180 | dwmac5_log_error(ndev, value, correctable, "DMA", dwmac5_dma_errors, | |
181 | STAT_OFF(dma_errors), stats); | |
182 | } | |
183 | ||
184 | int dwmac5_safety_feat_config(void __iomem *ioaddr, unsigned int asp) | |
185 | { | |
186 | u32 value; | |
187 | ||
188 | if (!asp) | |
189 | return -EINVAL; | |
190 | ||
191 | /* 1. Enable Safety Features */ | |
192 | value = readl(ioaddr + MTL_ECC_CONTROL); | |
193 | value |= TSOEE; /* TSO ECC */ | |
194 | value |= MRXPEE; /* MTL RX Parser ECC */ | |
195 | value |= MESTEE; /* MTL EST ECC */ | |
196 | value |= MRXEE; /* MTL RX FIFO ECC */ | |
197 | value |= MTXEE; /* MTL TX FIFO ECC */ | |
198 | writel(value, ioaddr + MTL_ECC_CONTROL); | |
199 | ||
200 | /* 2. Enable MTL Safety Interrupts */ | |
201 | value = readl(ioaddr + MTL_ECC_INT_ENABLE); | |
202 | value |= RPCEIE; /* RX Parser Memory Correctable Error */ | |
203 | value |= ECEIE; /* EST Memory Correctable Error */ | |
204 | value |= RXCEIE; /* RX Memory Correctable Error */ | |
205 | value |= TXCEIE; /* TX Memory Correctable Error */ | |
206 | writel(value, ioaddr + MTL_ECC_INT_ENABLE); | |
207 | ||
208 | /* 3. Enable DMA Safety Interrupts */ | |
209 | value = readl(ioaddr + DMA_ECC_INT_ENABLE); | |
210 | value |= TCEIE; /* TSO Memory Correctable Error */ | |
211 | writel(value, ioaddr + DMA_ECC_INT_ENABLE); | |
212 | ||
213 | /* Only ECC Protection for External Memory feature is selected */ | |
214 | if (asp <= 0x1) | |
215 | return 0; | |
216 | ||
217 | /* 5. Enable Parity and Timeout for FSM */ | |
218 | value = readl(ioaddr + MAC_FSM_CONTROL); | |
219 | value |= PRTYEN; /* FSM Parity Feature */ | |
220 | value |= TMOUTEN; /* FSM Timeout Feature */ | |
221 | writel(value, ioaddr + MAC_FSM_CONTROL); | |
222 | ||
223 | /* 4. Enable Data Parity Protection */ | |
224 | value = readl(ioaddr + MTL_DPP_CONTROL); | |
225 | value |= EDPP; | |
226 | writel(value, ioaddr + MTL_DPP_CONTROL); | |
227 | ||
228 | /* | |
229 | * All the Automotive Safety features are selected without the "Parity | |
230 | * Port Enable for external interface" feature. | |
231 | */ | |
232 | if (asp <= 0x2) | |
233 | return 0; | |
234 | ||
235 | value |= EPSI; | |
236 | writel(value, ioaddr + MTL_DPP_CONTROL); | |
237 | return 0; | |
238 | } | |
239 | ||
240 | bool dwmac5_safety_feat_irq_status(struct net_device *ndev, | |
241 | void __iomem *ioaddr, unsigned int asp, | |
242 | struct stmmac_safety_stats *stats) | |
243 | { | |
244 | bool ret = false, err, corr; | |
245 | u32 mtl, dma; | |
246 | ||
247 | if (!asp) | |
248 | return false; | |
249 | ||
250 | mtl = readl(ioaddr + MTL_SAFETY_INT_STATUS); | |
251 | dma = readl(ioaddr + DMA_SAFETY_INT_STATUS); | |
252 | ||
253 | err = (mtl & MCSIS) || (dma & MCSIS); | |
254 | corr = false; | |
255 | if (err) { | |
256 | dwmac5_handle_mac_err(ndev, ioaddr, corr, stats); | |
257 | ret |= !corr; | |
258 | } | |
259 | ||
260 | err = (mtl & (MEUIS | MECIS)) || (dma & (MSUIS | MSCIS)); | |
261 | corr = (mtl & MECIS) || (dma & MSCIS); | |
262 | if (err) { | |
263 | dwmac5_handle_mtl_err(ndev, ioaddr, corr, stats); | |
264 | ret |= !corr; | |
265 | } | |
266 | ||
267 | err = dma & (DEUIS | DECIS); | |
268 | corr = dma & DECIS; | |
269 | if (err) { | |
270 | dwmac5_handle_dma_err(ndev, ioaddr, corr, stats); | |
271 | ret |= !corr; | |
272 | } | |
273 | ||
274 | return ret; | |
275 | } | |
276 | ||
277 | static const struct dwmac5_error { | |
278 | const struct dwmac5_error_desc *desc; | |
279 | } dwmac5_all_errors[] = { | |
280 | { dwmac5_mac_errors }, | |
281 | { dwmac5_mtl_errors }, | |
282 | { dwmac5_dma_errors }, | |
283 | }; | |
284 | ||
285 | const char *dwmac5_safety_feat_dump(struct stmmac_safety_stats *stats, | |
286 | int index, unsigned long *count) | |
287 | { | |
288 | int module = index / 32, offset = index % 32; | |
289 | unsigned long *ptr = (unsigned long *)stats; | |
290 | ||
291 | if (module >= ARRAY_SIZE(dwmac5_all_errors)) | |
292 | return NULL; | |
293 | if (!dwmac5_all_errors[module].desc[offset].valid) | |
294 | return NULL; | |
295 | if (count) | |
296 | *count = *(ptr + index); | |
297 | return dwmac5_all_errors[module].desc[offset].desc; | |
298 | } |