xref: /linux/drivers/net/ethernet/stmicro/stmmac/enh_desc.c (revision 3ad0876554cafa368f574d4d408468510543e9ff)
1 /*******************************************************************************
2   This contains the functions to handle the enhanced descriptors.
3 
4   Copyright (C) 2007-2014  STMicroelectronics Ltd
5 
6   This program is free software; you can redistribute it and/or modify it
7   under the terms and conditions of the GNU General Public License,
8   version 2, as published by the Free Software Foundation.
9 
10   This program is distributed in the hope it will be useful, but WITHOUT
11   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
13   more details.
14 
15   The full GNU General Public License is included in this distribution in
16   the file called "COPYING".
17 
18   Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
19 *******************************************************************************/
20 
21 #include <linux/stmmac.h>
22 #include "common.h"
23 #include "descs_com.h"
24 
25 static int enh_desc_get_tx_status(void *data, struct stmmac_extra_stats *x,
26 				  struct dma_desc *p, void __iomem *ioaddr)
27 {
28 	struct net_device_stats *stats = (struct net_device_stats *)data;
29 	unsigned int tdes0 = le32_to_cpu(p->des0);
30 	int ret = tx_done;
31 
32 	/* Get tx owner first */
33 	if (unlikely(tdes0 & ETDES0_OWN))
34 		return tx_dma_own;
35 
36 	/* Verify tx error by looking at the last segment. */
37 	if (likely(!(tdes0 & ETDES0_LAST_SEGMENT)))
38 		return tx_not_ls;
39 
40 	if (unlikely(tdes0 & ETDES0_ERROR_SUMMARY)) {
41 		if (unlikely(tdes0 & ETDES0_JABBER_TIMEOUT))
42 			x->tx_jabber++;
43 
44 		if (unlikely(tdes0 & ETDES0_FRAME_FLUSHED)) {
45 			x->tx_frame_flushed++;
46 			dwmac_dma_flush_tx_fifo(ioaddr);
47 		}
48 
49 		if (unlikely(tdes0 & ETDES0_LOSS_CARRIER)) {
50 			x->tx_losscarrier++;
51 			stats->tx_carrier_errors++;
52 		}
53 		if (unlikely(tdes0 & ETDES0_NO_CARRIER)) {
54 			x->tx_carrier++;
55 			stats->tx_carrier_errors++;
56 		}
57 		if (unlikely((tdes0 & ETDES0_LATE_COLLISION) ||
58 			     (tdes0 & ETDES0_EXCESSIVE_COLLISIONS)))
59 			stats->collisions +=
60 				(tdes0 & ETDES0_COLLISION_COUNT_MASK) >> 3;
61 
62 		if (unlikely(tdes0 & ETDES0_EXCESSIVE_DEFERRAL))
63 			x->tx_deferred++;
64 
65 		if (unlikely(tdes0 & ETDES0_UNDERFLOW_ERROR)) {
66 			dwmac_dma_flush_tx_fifo(ioaddr);
67 			x->tx_underflow++;
68 		}
69 
70 		if (unlikely(tdes0 & ETDES0_IP_HEADER_ERROR))
71 			x->tx_ip_header_error++;
72 
73 		if (unlikely(tdes0 & ETDES0_PAYLOAD_ERROR)) {
74 			x->tx_payload_error++;
75 			dwmac_dma_flush_tx_fifo(ioaddr);
76 		}
77 
78 		ret = tx_err;
79 	}
80 
81 	if (unlikely(tdes0 & ETDES0_DEFERRED))
82 		x->tx_deferred++;
83 
84 #ifdef STMMAC_VLAN_TAG_USED
85 	if (tdes0 & ETDES0_VLAN_FRAME)
86 		x->tx_vlan++;
87 #endif
88 
89 	return ret;
90 }
91 
92 static int enh_desc_get_tx_len(struct dma_desc *p)
93 {
94 	return (le32_to_cpu(p->des1) & ETDES1_BUFFER1_SIZE_MASK);
95 }
96 
97 static int enh_desc_coe_rdes0(int ipc_err, int type, int payload_err)
98 {
99 	int ret = good_frame;
100 	u32 status = (type << 2 | ipc_err << 1 | payload_err) & 0x7;
101 
102 	/* bits 5 7 0 | Frame status
103 	 * ----------------------------------------------------------
104 	 *      0 0 0 | IEEE 802.3 Type frame (length < 1536 octects)
105 	 *      1 0 0 | IPv4/6 No CSUM errorS.
106 	 *      1 0 1 | IPv4/6 CSUM PAYLOAD error
107 	 *      1 1 0 | IPv4/6 CSUM IP HR error
108 	 *      1 1 1 | IPv4/6 IP PAYLOAD AND HEADER errorS
109 	 *      0 0 1 | IPv4/6 unsupported IP PAYLOAD
110 	 *      0 1 1 | COE bypassed.. no IPv4/6 frame
111 	 *      0 1 0 | Reserved.
112 	 */
113 	if (status == 0x0)
114 		ret = llc_snap;
115 	else if (status == 0x4)
116 		ret = good_frame;
117 	else if (status == 0x5)
118 		ret = csum_none;
119 	else if (status == 0x6)
120 		ret = csum_none;
121 	else if (status == 0x7)
122 		ret = csum_none;
123 	else if (status == 0x1)
124 		ret = discard_frame;
125 	else if (status == 0x3)
126 		ret = discard_frame;
127 	return ret;
128 }
129 
130 static void enh_desc_get_ext_status(void *data, struct stmmac_extra_stats *x,
131 				    struct dma_extended_desc *p)
132 {
133 	unsigned int rdes0 = le32_to_cpu(p->basic.des0);
134 	unsigned int rdes4 = le32_to_cpu(p->des4);
135 
136 	if (unlikely(rdes0 & ERDES0_RX_MAC_ADDR)) {
137 		int message_type = (rdes4 & ERDES4_MSG_TYPE_MASK) >> 8;
138 
139 		if (rdes4 & ERDES4_IP_HDR_ERR)
140 			x->ip_hdr_err++;
141 		if (rdes4 & ERDES4_IP_PAYLOAD_ERR)
142 			x->ip_payload_err++;
143 		if (rdes4 & ERDES4_IP_CSUM_BYPASSED)
144 			x->ip_csum_bypassed++;
145 		if (rdes4 & ERDES4_IPV4_PKT_RCVD)
146 			x->ipv4_pkt_rcvd++;
147 		if (rdes4 & ERDES4_IPV6_PKT_RCVD)
148 			x->ipv6_pkt_rcvd++;
149 
150 		if (message_type == RDES_EXT_NO_PTP)
151 			x->no_ptp_rx_msg_type_ext++;
152 		else if (message_type == RDES_EXT_SYNC)
153 			x->ptp_rx_msg_type_sync++;
154 		else if (message_type == RDES_EXT_FOLLOW_UP)
155 			x->ptp_rx_msg_type_follow_up++;
156 		else if (message_type == RDES_EXT_DELAY_REQ)
157 			x->ptp_rx_msg_type_delay_req++;
158 		else if (message_type == RDES_EXT_DELAY_RESP)
159 			x->ptp_rx_msg_type_delay_resp++;
160 		else if (message_type == RDES_EXT_PDELAY_REQ)
161 			x->ptp_rx_msg_type_pdelay_req++;
162 		else if (message_type == RDES_EXT_PDELAY_RESP)
163 			x->ptp_rx_msg_type_pdelay_resp++;
164 		else if (message_type == RDES_EXT_PDELAY_FOLLOW_UP)
165 			x->ptp_rx_msg_type_pdelay_follow_up++;
166 		else if (message_type == RDES_PTP_ANNOUNCE)
167 			x->ptp_rx_msg_type_announce++;
168 		else if (message_type == RDES_PTP_MANAGEMENT)
169 			x->ptp_rx_msg_type_management++;
170 		else if (message_type == RDES_PTP_PKT_RESERVED_TYPE)
171 			x->ptp_rx_msg_pkt_reserved_type++;
172 
173 		if (rdes4 & ERDES4_PTP_FRAME_TYPE)
174 			x->ptp_frame_type++;
175 		if (rdes4 & ERDES4_PTP_VER)
176 			x->ptp_ver++;
177 		if (rdes4 & ERDES4_TIMESTAMP_DROPPED)
178 			x->timestamp_dropped++;
179 		if (rdes4 & ERDES4_AV_PKT_RCVD)
180 			x->av_pkt_rcvd++;
181 		if (rdes4 & ERDES4_AV_TAGGED_PKT_RCVD)
182 			x->av_tagged_pkt_rcvd++;
183 		if ((rdes4 & ERDES4_VLAN_TAG_PRI_VAL_MASK) >> 18)
184 			x->vlan_tag_priority_val++;
185 		if (rdes4 & ERDES4_L3_FILTER_MATCH)
186 			x->l3_filter_match++;
187 		if (rdes4 & ERDES4_L4_FILTER_MATCH)
188 			x->l4_filter_match++;
189 		if ((rdes4 & ERDES4_L3_L4_FILT_NO_MATCH_MASK) >> 26)
190 			x->l3_l4_filter_no_match++;
191 	}
192 }
193 
194 static int enh_desc_get_rx_status(void *data, struct stmmac_extra_stats *x,
195 				  struct dma_desc *p)
196 {
197 	struct net_device_stats *stats = (struct net_device_stats *)data;
198 	unsigned int rdes0 = le32_to_cpu(p->des0);
199 	int ret = good_frame;
200 
201 	if (unlikely(rdes0 & RDES0_OWN))
202 		return dma_own;
203 
204 	if (unlikely(rdes0 & RDES0_ERROR_SUMMARY)) {
205 		if (unlikely(rdes0 & RDES0_DESCRIPTOR_ERROR)) {
206 			x->rx_desc++;
207 			stats->rx_length_errors++;
208 		}
209 		if (unlikely(rdes0 & RDES0_OVERFLOW_ERROR))
210 			x->rx_gmac_overflow++;
211 
212 		if (unlikely(rdes0 & RDES0_IPC_CSUM_ERROR))
213 			pr_err("\tIPC Csum Error/Giant frame\n");
214 
215 		if (unlikely(rdes0 & RDES0_COLLISION))
216 			stats->collisions++;
217 		if (unlikely(rdes0 & RDES0_RECEIVE_WATCHDOG))
218 			x->rx_watchdog++;
219 
220 		if (unlikely(rdes0 & RDES0_MII_ERROR))	/* GMII */
221 			x->rx_mii++;
222 
223 		if (unlikely(rdes0 & RDES0_CRC_ERROR)) {
224 			x->rx_crc_errors++;
225 			stats->rx_crc_errors++;
226 		}
227 		ret = discard_frame;
228 	}
229 
230 	/* After a payload csum error, the ES bit is set.
231 	 * It doesn't match with the information reported into the databook.
232 	 * At any rate, we need to understand if the CSUM hw computation is ok
233 	 * and report this info to the upper layers. */
234 	ret = enh_desc_coe_rdes0(!!(rdes0 & RDES0_IPC_CSUM_ERROR),
235 				 !!(rdes0 & RDES0_FRAME_TYPE),
236 				 !!(rdes0 & ERDES0_RX_MAC_ADDR));
237 
238 	if (unlikely(rdes0 & RDES0_DRIBBLING))
239 		x->dribbling_bit++;
240 
241 	if (unlikely(rdes0 & RDES0_SA_FILTER_FAIL)) {
242 		x->sa_rx_filter_fail++;
243 		ret = discard_frame;
244 	}
245 	if (unlikely(rdes0 & RDES0_DA_FILTER_FAIL)) {
246 		x->da_rx_filter_fail++;
247 		ret = discard_frame;
248 	}
249 	if (unlikely(rdes0 & RDES0_LENGTH_ERROR)) {
250 		x->rx_length++;
251 		ret = discard_frame;
252 	}
253 #ifdef STMMAC_VLAN_TAG_USED
254 	if (rdes0 & RDES0_VLAN_TAG)
255 		x->rx_vlan++;
256 #endif
257 
258 	return ret;
259 }
260 
261 static void enh_desc_init_rx_desc(struct dma_desc *p, int disable_rx_ic,
262 				  int mode, int end)
263 {
264 	p->des0 |= cpu_to_le32(RDES0_OWN);
265 	p->des1 |= cpu_to_le32((BUF_SIZE_8KiB - 1) & ERDES1_BUFFER1_SIZE_MASK);
266 
267 	if (mode == STMMAC_CHAIN_MODE)
268 		ehn_desc_rx_set_on_chain(p);
269 	else
270 		ehn_desc_rx_set_on_ring(p, end);
271 
272 	if (disable_rx_ic)
273 		p->des1 |= cpu_to_le32(ERDES1_DISABLE_IC);
274 }
275 
276 static void enh_desc_init_tx_desc(struct dma_desc *p, int mode, int end)
277 {
278 	p->des0 &= cpu_to_le32(~ETDES0_OWN);
279 	if (mode == STMMAC_CHAIN_MODE)
280 		enh_desc_end_tx_desc_on_chain(p);
281 	else
282 		enh_desc_end_tx_desc_on_ring(p, end);
283 }
284 
285 static int enh_desc_get_tx_owner(struct dma_desc *p)
286 {
287 	return (le32_to_cpu(p->des0) & ETDES0_OWN) >> 31;
288 }
289 
290 static void enh_desc_set_tx_owner(struct dma_desc *p)
291 {
292 	p->des0 |= cpu_to_le32(ETDES0_OWN);
293 }
294 
295 static void enh_desc_set_rx_owner(struct dma_desc *p)
296 {
297 	p->des0 |= cpu_to_le32(RDES0_OWN);
298 }
299 
300 static int enh_desc_get_tx_ls(struct dma_desc *p)
301 {
302 	return (le32_to_cpu(p->des0) & ETDES0_LAST_SEGMENT) >> 29;
303 }
304 
305 static void enh_desc_release_tx_desc(struct dma_desc *p, int mode)
306 {
307 	int ter = (le32_to_cpu(p->des0) & ETDES0_END_RING) >> 21;
308 
309 	memset(p, 0, offsetof(struct dma_desc, des2));
310 	if (mode == STMMAC_CHAIN_MODE)
311 		enh_desc_end_tx_desc_on_chain(p);
312 	else
313 		enh_desc_end_tx_desc_on_ring(p, ter);
314 }
315 
316 static void enh_desc_prepare_tx_desc(struct dma_desc *p, int is_fs, int len,
317 				     bool csum_flag, int mode, bool tx_own,
318 				     bool ls, unsigned int tot_pkt_len)
319 {
320 	unsigned int tdes0 = le32_to_cpu(p->des0);
321 
322 	if (mode == STMMAC_CHAIN_MODE)
323 		enh_set_tx_desc_len_on_chain(p, len);
324 	else
325 		enh_set_tx_desc_len_on_ring(p, len);
326 
327 	if (is_fs)
328 		tdes0 |= ETDES0_FIRST_SEGMENT;
329 	else
330 		tdes0 &= ~ETDES0_FIRST_SEGMENT;
331 
332 	if (likely(csum_flag))
333 		tdes0 |= (TX_CIC_FULL << ETDES0_CHECKSUM_INSERTION_SHIFT);
334 	else
335 		tdes0 &= ~(TX_CIC_FULL << ETDES0_CHECKSUM_INSERTION_SHIFT);
336 
337 	if (ls)
338 		tdes0 |= ETDES0_LAST_SEGMENT;
339 
340 	/* Finally set the OWN bit. Later the DMA will start! */
341 	if (tx_own)
342 		tdes0 |= ETDES0_OWN;
343 
344 	if (is_fs && tx_own)
345 		/* When the own bit, for the first frame, has to be set, all
346 		 * descriptors for the same frame has to be set before, to
347 		 * avoid race condition.
348 		 */
349 		dma_wmb();
350 
351 	p->des0 = cpu_to_le32(tdes0);
352 }
353 
354 static void enh_desc_set_tx_ic(struct dma_desc *p)
355 {
356 	p->des0 |= cpu_to_le32(ETDES0_INTERRUPT);
357 }
358 
359 static int enh_desc_get_rx_frame_len(struct dma_desc *p, int rx_coe_type)
360 {
361 	unsigned int csum = 0;
362 	/* The type-1 checksum offload engines append the checksum at
363 	 * the end of frame and the two bytes of checksum are added in
364 	 * the length.
365 	 * Adjust for that in the framelen for type-1 checksum offload
366 	 * engines.
367 	 */
368 	if (rx_coe_type == STMMAC_RX_COE_TYPE1)
369 		csum = 2;
370 
371 	return (((le32_to_cpu(p->des0) & RDES0_FRAME_LEN_MASK)
372 				>> RDES0_FRAME_LEN_SHIFT) - csum);
373 }
374 
375 static void enh_desc_enable_tx_timestamp(struct dma_desc *p)
376 {
377 	p->des0 |= cpu_to_le32(ETDES0_TIME_STAMP_ENABLE);
378 }
379 
380 static int enh_desc_get_tx_timestamp_status(struct dma_desc *p)
381 {
382 	return (le32_to_cpu(p->des0) & ETDES0_TIME_STAMP_STATUS) >> 17;
383 }
384 
385 static u64 enh_desc_get_timestamp(void *desc, u32 ats)
386 {
387 	u64 ns;
388 
389 	if (ats) {
390 		struct dma_extended_desc *p = (struct dma_extended_desc *)desc;
391 		ns = le32_to_cpu(p->des6);
392 		/* convert high/sec time stamp value to nanosecond */
393 		ns += le32_to_cpu(p->des7) * 1000000000ULL;
394 	} else {
395 		struct dma_desc *p = (struct dma_desc *)desc;
396 		ns = le32_to_cpu(p->des2);
397 		ns += le32_to_cpu(p->des3) * 1000000000ULL;
398 	}
399 
400 	return ns;
401 }
402 
403 static int enh_desc_get_rx_timestamp_status(void *desc, void *next_desc,
404 					    u32 ats)
405 {
406 	if (ats) {
407 		struct dma_extended_desc *p = (struct dma_extended_desc *)desc;
408 		return (le32_to_cpu(p->basic.des0) & RDES0_IPC_CSUM_ERROR) >> 7;
409 	} else {
410 		struct dma_desc *p = (struct dma_desc *)desc;
411 		if ((le32_to_cpu(p->des2) == 0xffffffff) &&
412 		    (le32_to_cpu(p->des3) == 0xffffffff))
413 			/* timestamp is corrupted, hence don't store it */
414 			return 0;
415 		else
416 			return 1;
417 	}
418 }
419 
420 static void enh_desc_display_ring(void *head, unsigned int size, bool rx)
421 {
422 	struct dma_extended_desc *ep = (struct dma_extended_desc *)head;
423 	int i;
424 
425 	pr_info("Extended %s descriptor ring:\n", rx ? "RX" : "TX");
426 
427 	for (i = 0; i < size; i++) {
428 		u64 x;
429 
430 		x = *(u64 *)ep;
431 		pr_info("%03d [0x%x]: 0x%x 0x%x 0x%x 0x%x\n",
432 			i, (unsigned int)virt_to_phys(ep),
433 			(unsigned int)x, (unsigned int)(x >> 32),
434 			ep->basic.des2, ep->basic.des3);
435 		ep++;
436 	}
437 	pr_info("\n");
438 }
439 
440 const struct stmmac_desc_ops enh_desc_ops = {
441 	.tx_status = enh_desc_get_tx_status,
442 	.rx_status = enh_desc_get_rx_status,
443 	.get_tx_len = enh_desc_get_tx_len,
444 	.init_rx_desc = enh_desc_init_rx_desc,
445 	.init_tx_desc = enh_desc_init_tx_desc,
446 	.get_tx_owner = enh_desc_get_tx_owner,
447 	.release_tx_desc = enh_desc_release_tx_desc,
448 	.prepare_tx_desc = enh_desc_prepare_tx_desc,
449 	.set_tx_ic = enh_desc_set_tx_ic,
450 	.get_tx_ls = enh_desc_get_tx_ls,
451 	.set_tx_owner = enh_desc_set_tx_owner,
452 	.set_rx_owner = enh_desc_set_rx_owner,
453 	.get_rx_frame_len = enh_desc_get_rx_frame_len,
454 	.rx_extended_status = enh_desc_get_ext_status,
455 	.enable_tx_timestamp = enh_desc_enable_tx_timestamp,
456 	.get_tx_timestamp_status = enh_desc_get_tx_timestamp_status,
457 	.get_timestamp = enh_desc_get_timestamp,
458 	.get_rx_timestamp_status = enh_desc_get_rx_timestamp_status,
459 	.display_ring = enh_desc_display_ring,
460 };
461