]>
Commit | Line | Data |
---|---|---|
4fa9c49f | 1 | // SPDX-License-Identifier: GPL-2.0-only |
56b106ae GC |
2 | /******************************************************************************* |
3 | This contains the functions to handle the normal descriptors. | |
4 | ||
5 | Copyright (C) 2007-2009 STMicroelectronics Ltd | |
6 | ||
56b106ae GC |
7 | |
8 | Author: Giuseppe Cavallaro <peppe.cavallaro@st.com> | |
9 | *******************************************************************************/ | |
10 | ||
38912bdb | 11 | #include <linux/stmmac.h> |
56b106ae | 12 | #include "common.h" |
286a8372 | 13 | #include "descs_com.h" |
56b106ae GC |
14 | |
15 | static int ndesc_get_tx_status(void *data, struct stmmac_extra_stats *x, | |
ad01b7d4 | 16 | struct dma_desc *p, void __iomem *ioaddr) |
56b106ae | 17 | { |
56b106ae | 18 | struct net_device_stats *stats = (struct net_device_stats *)data; |
f8be0d78 MW |
19 | unsigned int tdes0 = le32_to_cpu(p->des0); |
20 | unsigned int tdes1 = le32_to_cpu(p->des1); | |
c363b658 FG |
21 | int ret = tx_done; |
22 | ||
23 | /* Get tx owner first */ | |
24 | if (unlikely(tdes0 & TDES0_OWN)) | |
25 | return tx_dma_own; | |
26 | ||
27 | /* Verify tx error by looking at the last segment. */ | |
28 | if (likely(!(tdes1 & TDES1_LAST_SEGMENT))) | |
29 | return tx_not_ls; | |
56b106ae | 30 | |
293e4365 GC |
31 | if (unlikely(tdes0 & TDES0_ERROR_SUMMARY)) { |
32 | if (unlikely(tdes0 & TDES0_UNDERFLOW_ERROR)) { | |
56b106ae GC |
33 | x->tx_underflow++; |
34 | stats->tx_fifo_errors++; | |
35 | } | |
293e4365 | 36 | if (unlikely(tdes0 & TDES0_NO_CARRIER)) { |
56b106ae GC |
37 | x->tx_carrier++; |
38 | stats->tx_carrier_errors++; | |
39 | } | |
293e4365 | 40 | if (unlikely(tdes0 & TDES0_LOSS_CARRIER)) { |
56b106ae GC |
41 | x->tx_losscarrier++; |
42 | stats->tx_carrier_errors++; | |
43 | } | |
293e4365 GC |
44 | if (unlikely((tdes0 & TDES0_EXCESSIVE_DEFERRAL) || |
45 | (tdes0 & TDES0_EXCESSIVE_COLLISIONS) || | |
46 | (tdes0 & TDES0_LATE_COLLISION))) { | |
47 | unsigned int collisions; | |
48 | ||
49 | collisions = (tdes0 & TDES0_COLLISION_COUNT_MASK) >> 3; | |
50 | stats->collisions += collisions; | |
51 | } | |
c363b658 | 52 | ret = tx_err; |
56b106ae | 53 | } |
3c20f72f | 54 | |
293e4365 | 55 | if (tdes0 & TDES0_VLAN_FRAME) |
3c20f72f | 56 | x->tx_vlan++; |
3c20f72f | 57 | |
293e4365 | 58 | if (unlikely(tdes0 & TDES0_DEFERRED)) |
56b106ae GC |
59 | x->tx_deferred++; |
60 | ||
61 | return ret; | |
62 | } | |
63 | ||
64 | static int ndesc_get_tx_len(struct dma_desc *p) | |
65 | { | |
f8be0d78 | 66 | return (le32_to_cpu(p->des1) & RDES1_BUFFER1_SIZE_MASK); |
56b106ae GC |
67 | } |
68 | ||
69 | /* This function verifies if each incoming frame has some errors | |
70 | * and, if required, updates the multicast statistics. | |
3c20f72f GC |
71 | * In case of success, it returns good_frame because the GMAC device |
72 | * is supposed to be able to compute the csum in HW. */ | |
56b106ae GC |
73 | static int ndesc_get_rx_status(void *data, struct stmmac_extra_stats *x, |
74 | struct dma_desc *p) | |
75 | { | |
3c20f72f | 76 | int ret = good_frame; |
f8be0d78 | 77 | unsigned int rdes0 = le32_to_cpu(p->des0); |
56b106ae GC |
78 | struct net_device_stats *stats = (struct net_device_stats *)data; |
79 | ||
c1fa3212 FG |
80 | if (unlikely(rdes0 & RDES0_OWN)) |
81 | return dma_own; | |
82 | ||
293e4365 | 83 | if (unlikely(!(rdes0 & RDES0_LAST_DESCRIPTOR))) { |
56b106ae GC |
84 | stats->rx_length_errors++; |
85 | return discard_frame; | |
86 | } | |
87 | ||
293e4365 GC |
88 | if (unlikely(rdes0 & RDES0_ERROR_SUMMARY)) { |
89 | if (unlikely(rdes0 & RDES0_DESCRIPTOR_ERROR)) | |
56b106ae | 90 | x->rx_desc++; |
293e4365 | 91 | if (unlikely(rdes0 & RDES0_SA_FILTER_FAIL)) |
3c20f72f | 92 | x->sa_filter_fail++; |
293e4365 | 93 | if (unlikely(rdes0 & RDES0_OVERFLOW_ERROR)) |
3c20f72f | 94 | x->overflow_error++; |
293e4365 | 95 | if (unlikely(rdes0 & RDES0_IPC_CSUM_ERROR)) |
3c20f72f | 96 | x->ipc_csum_error++; |
293e4365 | 97 | if (unlikely(rdes0 & RDES0_COLLISION)) { |
56b106ae GC |
98 | x->rx_collision++; |
99 | stats->collisions++; | |
100 | } | |
293e4365 | 101 | if (unlikely(rdes0 & RDES0_CRC_ERROR)) { |
e0a76606 | 102 | x->rx_crc_errors++; |
56b106ae GC |
103 | stats->rx_crc_errors++; |
104 | } | |
105 | ret = discard_frame; | |
106 | } | |
293e4365 | 107 | if (unlikely(rdes0 & RDES0_DRIBBLING)) |
1cc5a735 | 108 | x->dribbling_bit++; |
56b106ae | 109 | |
293e4365 | 110 | if (unlikely(rdes0 & RDES0_LENGTH_ERROR)) { |
56b106ae GC |
111 | x->rx_length++; |
112 | ret = discard_frame; | |
113 | } | |
293e4365 | 114 | if (unlikely(rdes0 & RDES0_MII_ERROR)) { |
56b106ae GC |
115 | x->rx_mii++; |
116 | ret = discard_frame; | |
117 | } | |
3c20f72f | 118 | #ifdef STMMAC_VLAN_TAG_USED |
293e4365 | 119 | if (rdes0 & RDES0_VLAN_TAG) |
3c20f72f GC |
120 | x->vlan_tag++; |
121 | #endif | |
56b106ae GC |
122 | return ret; |
123 | } | |
124 | ||
c24602ef | 125 | static void ndesc_init_rx_desc(struct dma_desc *p, int disable_rx_ic, int mode, |
583e6361 | 126 | int end, int bfsize) |
56b106ae | 127 | { |
583e6361 AK |
128 | int bfsize1; |
129 | ||
f8be0d78 | 130 | p->des0 |= cpu_to_le32(RDES0_OWN); |
583e6361 AK |
131 | |
132 | bfsize1 = min(bfsize, BUF_SIZE_2KiB - 1); | |
f87db4db | 133 | p->des1 |= cpu_to_le32(bfsize1 & RDES1_BUFFER1_SIZE_MASK); |
c24602ef GC |
134 | |
135 | if (mode == STMMAC_CHAIN_MODE) | |
136 | ndesc_rx_set_on_chain(p, end); | |
137 | else | |
583e6361 | 138 | ndesc_rx_set_on_ring(p, end, bfsize); |
c24602ef GC |
139 | |
140 | if (disable_rx_ic) | |
f8be0d78 | 141 | p->des1 |= cpu_to_le32(RDES1_DISABLE_IC); |
56b106ae GC |
142 | } |
143 | ||
c24602ef | 144 | static void ndesc_init_tx_desc(struct dma_desc *p, int mode, int end) |
56b106ae | 145 | { |
f8be0d78 | 146 | p->des0 &= cpu_to_le32(~TDES0_OWN); |
c24602ef | 147 | if (mode == STMMAC_CHAIN_MODE) |
293e4365 | 148 | ndesc_tx_set_on_chain(p); |
c24602ef | 149 | else |
293e4365 | 150 | ndesc_end_tx_desc_on_ring(p, end); |
56b106ae GC |
151 | } |
152 | ||
153 | static int ndesc_get_tx_owner(struct dma_desc *p) | |
154 | { | |
f8be0d78 | 155 | return (le32_to_cpu(p->des0) & TDES0_OWN) >> 31; |
56b106ae GC |
156 | } |
157 | ||
56b106ae GC |
158 | static void ndesc_set_tx_owner(struct dma_desc *p) |
159 | { | |
f8be0d78 | 160 | p->des0 |= cpu_to_le32(TDES0_OWN); |
56b106ae GC |
161 | } |
162 | ||
357951cd | 163 | static void ndesc_set_rx_owner(struct dma_desc *p, int disable_rx_ic) |
56b106ae | 164 | { |
f8be0d78 | 165 | p->des0 |= cpu_to_le32(RDES0_OWN); |
56b106ae GC |
166 | } |
167 | ||
168 | static int ndesc_get_tx_ls(struct dma_desc *p) | |
169 | { | |
f8be0d78 | 170 | return (le32_to_cpu(p->des1) & TDES1_LAST_SEGMENT) >> 30; |
56b106ae GC |
171 | } |
172 | ||
4a7d666a | 173 | static void ndesc_release_tx_desc(struct dma_desc *p, int mode) |
56b106ae | 174 | { |
f8be0d78 | 175 | int ter = (le32_to_cpu(p->des1) & TDES1_END_RING) >> 25; |
56b106ae | 176 | |
b71c7aaa | 177 | memset(p, 0, offsetof(struct dma_desc, des2)); |
4a7d666a | 178 | if (mode == STMMAC_CHAIN_MODE) |
293e4365 | 179 | ndesc_tx_set_on_chain(p); |
4a7d666a GC |
180 | else |
181 | ndesc_end_tx_desc_on_ring(p, ter); | |
56b106ae GC |
182 | } |
183 | ||
184 | static void ndesc_prepare_tx_desc(struct dma_desc *p, int is_fs, int len, | |
be434d50 | 185 | bool csum_flag, int mode, bool tx_own, |
fe6af0e1 | 186 | bool ls, unsigned int tot_pkt_len) |
56b106ae | 187 | { |
f8be0d78 | 188 | unsigned int tdes1 = le32_to_cpu(p->des1); |
293e4365 GC |
189 | |
190 | if (is_fs) | |
191 | tdes1 |= TDES1_FIRST_SEGMENT; | |
192 | else | |
193 | tdes1 &= ~TDES1_FIRST_SEGMENT; | |
194 | ||
195 | if (likely(csum_flag)) | |
196 | tdes1 |= (TX_CIC_FULL) << TDES1_CHECKSUM_INSERTION_SHIFT; | |
197 | else | |
198 | tdes1 &= ~(TX_CIC_FULL << TDES1_CHECKSUM_INSERTION_SHIFT); | |
199 | ||
0e80bdc9 GC |
200 | if (ls) |
201 | tdes1 |= TDES1_LAST_SEGMENT; | |
202 | ||
f8be0d78 | 203 | p->des1 = cpu_to_le32(tdes1); |
a00e3ab6 GC |
204 | |
205 | if (mode == STMMAC_CHAIN_MODE) | |
206 | norm_set_tx_desc_len_on_chain(p, len); | |
207 | else | |
208 | norm_set_tx_desc_len_on_ring(p, len); | |
209 | ||
210 | if (tx_own) | |
f8be0d78 | 211 | p->des0 |= cpu_to_le32(TDES0_OWN); |
56b106ae GC |
212 | } |
213 | ||
0e80bdc9 | 214 | static void ndesc_set_tx_ic(struct dma_desc *p) |
56b106ae | 215 | { |
f8be0d78 | 216 | p->des1 |= cpu_to_le32(TDES1_INTERRUPT); |
56b106ae GC |
217 | } |
218 | ||
38912bdb | 219 | static int ndesc_get_rx_frame_len(struct dma_desc *p, int rx_coe_type) |
56b106ae | 220 | { |
293e4365 GC |
221 | unsigned int csum = 0; |
222 | ||
38912bdb DS |
223 | /* The type-1 checksum offload engines append the checksum at |
224 | * the end of frame and the two bytes of checksum are added in | |
225 | * the length. | |
226 | * Adjust for that in the framelen for type-1 checksum offload | |
293e4365 GC |
227 | * engines |
228 | */ | |
38912bdb | 229 | if (rx_coe_type == STMMAC_RX_COE_TYPE1) |
293e4365 GC |
230 | csum = 2; |
231 | ||
f8be0d78 MW |
232 | return (((le32_to_cpu(p->des0) & RDES0_FRAME_LEN_MASK) |
233 | >> RDES0_FRAME_LEN_SHIFT) - | |
293e4365 GC |
234 | csum); |
235 | ||
56b106ae GC |
236 | } |
237 | ||
891434b1 RK |
238 | static void ndesc_enable_tx_timestamp(struct dma_desc *p) |
239 | { | |
f8be0d78 | 240 | p->des1 |= cpu_to_le32(TDES1_TIME_STAMP_ENABLE); |
891434b1 RK |
241 | } |
242 | ||
243 | static int ndesc_get_tx_timestamp_status(struct dma_desc *p) | |
244 | { | |
f8be0d78 | 245 | return (le32_to_cpu(p->des0) & TDES0_TIME_STAMP_STATUS) >> 17; |
891434b1 RK |
246 | } |
247 | ||
42de047d | 248 | static void ndesc_get_timestamp(void *desc, u32 ats, u64 *ts) |
891434b1 RK |
249 | { |
250 | struct dma_desc *p = (struct dma_desc *)desc; | |
251 | u64 ns; | |
252 | ||
f8be0d78 | 253 | ns = le32_to_cpu(p->des2); |
891434b1 | 254 | /* convert high/sec time stamp value to nanosecond */ |
f8be0d78 | 255 | ns += le32_to_cpu(p->des3) * 1000000000ULL; |
891434b1 | 256 | |
42de047d | 257 | *ts = ns; |
891434b1 RK |
258 | } |
259 | ||
a1762456 | 260 | static int ndesc_get_rx_timestamp_status(void *desc, void *next_desc, u32 ats) |
891434b1 RK |
261 | { |
262 | struct dma_desc *p = (struct dma_desc *)desc; | |
263 | ||
f8be0d78 MW |
264 | if ((le32_to_cpu(p->des2) == 0xffffffff) && |
265 | (le32_to_cpu(p->des3) == 0xffffffff)) | |
891434b1 RK |
266 | /* timestamp is corrupted, hence don't store it */ |
267 | return 0; | |
268 | else | |
269 | return 1; | |
270 | } | |
271 | ||
bfaf91ca JZ |
272 | static void ndesc_display_ring(void *head, unsigned int size, bool rx, |
273 | dma_addr_t dma_rx_phy, unsigned int desc_size) | |
d0225e7d AT |
274 | { |
275 | struct dma_desc *p = (struct dma_desc *)head; | |
bfaf91ca | 276 | dma_addr_t dma_addr; |
d0225e7d AT |
277 | int i; |
278 | ||
279 | pr_info("%s descriptor ring:\n", rx ? "RX" : "TX"); | |
280 | ||
281 | for (i = 0; i < size; i++) { | |
282 | u64 x; | |
bfaf91ca | 283 | dma_addr = dma_rx_phy + i * sizeof(*p); |
d0225e7d AT |
284 | |
285 | x = *(u64 *)p; | |
bfaf91ca JZ |
286 | pr_info("%03d [%pad]: 0x%x 0x%x 0x%x 0x%x", |
287 | i, &dma_addr, | |
d0225e7d AT |
288 | (unsigned int)x, (unsigned int)(x >> 32), |
289 | p->des2, p->des3); | |
290 | p++; | |
291 | } | |
292 | pr_info("\n"); | |
293 | } | |
294 | ||
d2df9ea0 JA |
295 | static void ndesc_get_addr(struct dma_desc *p, unsigned int *addr) |
296 | { | |
297 | *addr = le32_to_cpu(p->des2); | |
298 | } | |
299 | ||
6844171d JA |
300 | static void ndesc_set_addr(struct dma_desc *p, dma_addr_t addr) |
301 | { | |
302 | p->des2 = cpu_to_le32(addr); | |
303 | } | |
304 | ||
44c67f85 JA |
305 | static void ndesc_clear(struct dma_desc *p) |
306 | { | |
307 | p->des2 = 0; | |
308 | } | |
309 | ||
cadb7924 | 310 | const struct stmmac_desc_ops ndesc_ops = { |
56b106ae GC |
311 | .tx_status = ndesc_get_tx_status, |
312 | .rx_status = ndesc_get_rx_status, | |
313 | .get_tx_len = ndesc_get_tx_len, | |
314 | .init_rx_desc = ndesc_init_rx_desc, | |
315 | .init_tx_desc = ndesc_init_tx_desc, | |
316 | .get_tx_owner = ndesc_get_tx_owner, | |
56b106ae GC |
317 | .release_tx_desc = ndesc_release_tx_desc, |
318 | .prepare_tx_desc = ndesc_prepare_tx_desc, | |
0e80bdc9 | 319 | .set_tx_ic = ndesc_set_tx_ic, |
56b106ae GC |
320 | .get_tx_ls = ndesc_get_tx_ls, |
321 | .set_tx_owner = ndesc_set_tx_owner, | |
322 | .set_rx_owner = ndesc_set_rx_owner, | |
323 | .get_rx_frame_len = ndesc_get_rx_frame_len, | |
891434b1 RK |
324 | .enable_tx_timestamp = ndesc_enable_tx_timestamp, |
325 | .get_tx_timestamp_status = ndesc_get_tx_timestamp_status, | |
326 | .get_timestamp = ndesc_get_timestamp, | |
327 | .get_rx_timestamp_status = ndesc_get_rx_timestamp_status, | |
d0225e7d | 328 | .display_ring = ndesc_display_ring, |
d2df9ea0 | 329 | .get_addr = ndesc_get_addr, |
6844171d | 330 | .set_addr = ndesc_set_addr, |
44c67f85 | 331 | .clear = ndesc_clear, |
56b106ae | 332 | }; |