xref: /openbmc/linux/drivers/net/ethernet/stmicro/stmmac/enh_desc.c (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
14fa9c49fSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
27ac6653aSJeff Kirsher /*******************************************************************************
37ac6653aSJeff Kirsher   This contains the functions to handle the enhanced descriptors.
47ac6653aSJeff Kirsher 
5293e4365SGiuseppe Cavallaro   Copyright (C) 2007-2014  STMicroelectronics Ltd
67ac6653aSJeff Kirsher 
77ac6653aSJeff Kirsher 
87ac6653aSJeff Kirsher   Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
97ac6653aSJeff Kirsher *******************************************************************************/
107ac6653aSJeff Kirsher 
1138912bdbSDeepak SIKRI #include <linux/stmmac.h>
127ac6653aSJeff Kirsher #include "common.h"
13286a8372SGiuseppe CAVALLARO #include "descs_com.h"
147ac6653aSJeff Kirsher 
enh_desc_get_tx_status(struct stmmac_extra_stats * x,struct dma_desc * p,void __iomem * ioaddr)15*133466c3SJisheng Zhang static int enh_desc_get_tx_status(struct stmmac_extra_stats *x,
167ac6653aSJeff Kirsher 				  struct dma_desc *p, void __iomem *ioaddr)
177ac6653aSJeff Kirsher {
18f8be0d78SMichael Weiser 	unsigned int tdes0 = le32_to_cpu(p->des0);
19c363b658SFabrice Gasnier 	int ret = tx_done;
20c363b658SFabrice Gasnier 
21c363b658SFabrice Gasnier 	/* Get tx owner first */
22c363b658SFabrice Gasnier 	if (unlikely(tdes0 & ETDES0_OWN))
23c363b658SFabrice Gasnier 		return tx_dma_own;
24c363b658SFabrice Gasnier 
25c363b658SFabrice Gasnier 	/* Verify tx error by looking at the last segment. */
26c363b658SFabrice Gasnier 	if (likely(!(tdes0 & ETDES0_LAST_SEGMENT)))
27c363b658SFabrice Gasnier 		return tx_not_ls;
287ac6653aSJeff Kirsher 
29293e4365SGiuseppe Cavallaro 	if (unlikely(tdes0 & ETDES0_ERROR_SUMMARY)) {
30293e4365SGiuseppe Cavallaro 		if (unlikely(tdes0 & ETDES0_JABBER_TIMEOUT))
317ac6653aSJeff Kirsher 			x->tx_jabber++;
327ac6653aSJeff Kirsher 
33293e4365SGiuseppe Cavallaro 		if (unlikely(tdes0 & ETDES0_FRAME_FLUSHED)) {
347ac6653aSJeff Kirsher 			x->tx_frame_flushed++;
357ac6653aSJeff Kirsher 			dwmac_dma_flush_tx_fifo(ioaddr);
367ac6653aSJeff Kirsher 		}
377ac6653aSJeff Kirsher 
38293e4365SGiuseppe Cavallaro 		if (unlikely(tdes0 & ETDES0_LOSS_CARRIER)) {
397ac6653aSJeff Kirsher 			x->tx_losscarrier++;
407ac6653aSJeff Kirsher 		}
41293e4365SGiuseppe Cavallaro 		if (unlikely(tdes0 & ETDES0_NO_CARRIER)) {
427ac6653aSJeff Kirsher 			x->tx_carrier++;
437ac6653aSJeff Kirsher 		}
44293e4365SGiuseppe Cavallaro 		if (unlikely((tdes0 & ETDES0_LATE_COLLISION) ||
45293e4365SGiuseppe Cavallaro 			     (tdes0 & ETDES0_EXCESSIVE_COLLISIONS)))
46*133466c3SJisheng Zhang 			x->tx_collision +=
47293e4365SGiuseppe Cavallaro 				(tdes0 & ETDES0_COLLISION_COUNT_MASK) >> 3;
4883d7af64SGiuseppe CAVALLARO 
49293e4365SGiuseppe Cavallaro 		if (unlikely(tdes0 & ETDES0_EXCESSIVE_DEFERRAL))
507ac6653aSJeff Kirsher 			x->tx_deferred++;
517ac6653aSJeff Kirsher 
52293e4365SGiuseppe Cavallaro 		if (unlikely(tdes0 & ETDES0_UNDERFLOW_ERROR)) {
537ac6653aSJeff Kirsher 			dwmac_dma_flush_tx_fifo(ioaddr);
547ac6653aSJeff Kirsher 			x->tx_underflow++;
557ac6653aSJeff Kirsher 		}
567ac6653aSJeff Kirsher 
57293e4365SGiuseppe Cavallaro 		if (unlikely(tdes0 & ETDES0_IP_HEADER_ERROR))
587ac6653aSJeff Kirsher 			x->tx_ip_header_error++;
597ac6653aSJeff Kirsher 
60293e4365SGiuseppe Cavallaro 		if (unlikely(tdes0 & ETDES0_PAYLOAD_ERROR)) {
617ac6653aSJeff Kirsher 			x->tx_payload_error++;
627ac6653aSJeff Kirsher 			dwmac_dma_flush_tx_fifo(ioaddr);
637ac6653aSJeff Kirsher 		}
647ac6653aSJeff Kirsher 
65c363b658SFabrice Gasnier 		ret = tx_err;
667ac6653aSJeff Kirsher 	}
677ac6653aSJeff Kirsher 
68293e4365SGiuseppe Cavallaro 	if (unlikely(tdes0 & ETDES0_DEFERRED))
697ac6653aSJeff Kirsher 		x->tx_deferred++;
7083d7af64SGiuseppe CAVALLARO 
717ac6653aSJeff Kirsher #ifdef STMMAC_VLAN_TAG_USED
72293e4365SGiuseppe Cavallaro 	if (tdes0 & ETDES0_VLAN_FRAME)
737ac6653aSJeff Kirsher 		x->tx_vlan++;
747ac6653aSJeff Kirsher #endif
757ac6653aSJeff Kirsher 
767ac6653aSJeff Kirsher 	return ret;
777ac6653aSJeff Kirsher }
787ac6653aSJeff Kirsher 
enh_desc_get_tx_len(struct dma_desc * p)797ac6653aSJeff Kirsher static int enh_desc_get_tx_len(struct dma_desc *p)
807ac6653aSJeff Kirsher {
81f8be0d78SMichael Weiser 	return (le32_to_cpu(p->des1) & ETDES1_BUFFER1_SIZE_MASK);
827ac6653aSJeff Kirsher }
837ac6653aSJeff Kirsher 
enh_desc_coe_rdes0(int ipc_err,int type,int payload_err)847ac6653aSJeff Kirsher static int enh_desc_coe_rdes0(int ipc_err, int type, int payload_err)
857ac6653aSJeff Kirsher {
867ac6653aSJeff Kirsher 	int ret = good_frame;
877ac6653aSJeff Kirsher 	u32 status = (type << 2 | ipc_err << 1 | payload_err) & 0x7;
887ac6653aSJeff Kirsher 
897ac6653aSJeff Kirsher 	/* bits 5 7 0 | Frame status
907ac6653aSJeff Kirsher 	 * ----------------------------------------------------------
917ac6653aSJeff Kirsher 	 *      0 0 0 | IEEE 802.3 Type frame (length < 1536 octects)
927ac6653aSJeff Kirsher 	 *      1 0 0 | IPv4/6 No CSUM errorS.
937ac6653aSJeff Kirsher 	 *      1 0 1 | IPv4/6 CSUM PAYLOAD error
947ac6653aSJeff Kirsher 	 *      1 1 0 | IPv4/6 CSUM IP HR error
957ac6653aSJeff Kirsher 	 *      1 1 1 | IPv4/6 IP PAYLOAD AND HEADER errorS
967ac6653aSJeff Kirsher 	 *      0 0 1 | IPv4/6 unsupported IP PAYLOAD
977ac6653aSJeff Kirsher 	 *      0 1 1 | COE bypassed.. no IPv4/6 frame
987ac6653aSJeff Kirsher 	 *      0 1 0 | Reserved.
997ac6653aSJeff Kirsher 	 */
10083d7af64SGiuseppe CAVALLARO 	if (status == 0x0)
1017ac6653aSJeff Kirsher 		ret = llc_snap;
10283d7af64SGiuseppe CAVALLARO 	else if (status == 0x4)
1037ac6653aSJeff Kirsher 		ret = good_frame;
10483d7af64SGiuseppe CAVALLARO 	else if (status == 0x5)
1057ac6653aSJeff Kirsher 		ret = csum_none;
10683d7af64SGiuseppe CAVALLARO 	else if (status == 0x6)
1077ac6653aSJeff Kirsher 		ret = csum_none;
10883d7af64SGiuseppe CAVALLARO 	else if (status == 0x7)
1097ac6653aSJeff Kirsher 		ret = csum_none;
11083d7af64SGiuseppe CAVALLARO 	else if (status == 0x1)
1117ac6653aSJeff Kirsher 		ret = discard_frame;
11283d7af64SGiuseppe CAVALLARO 	else if (status == 0x3)
1137ac6653aSJeff Kirsher 		ret = discard_frame;
1147ac6653aSJeff Kirsher 	return ret;
1157ac6653aSJeff Kirsher }
1167ac6653aSJeff Kirsher 
enh_desc_get_ext_status(struct stmmac_extra_stats * x,struct dma_extended_desc * p)117*133466c3SJisheng Zhang static void enh_desc_get_ext_status(struct stmmac_extra_stats *x,
118c24602efSGiuseppe CAVALLARO 				    struct dma_extended_desc *p)
119c24602efSGiuseppe CAVALLARO {
120f8be0d78SMichael Weiser 	unsigned int rdes0 = le32_to_cpu(p->basic.des0);
121f8be0d78SMichael Weiser 	unsigned int rdes4 = le32_to_cpu(p->des4);
122293e4365SGiuseppe Cavallaro 
123293e4365SGiuseppe Cavallaro 	if (unlikely(rdes0 & ERDES0_RX_MAC_ADDR)) {
124293e4365SGiuseppe Cavallaro 		int message_type = (rdes4 & ERDES4_MSG_TYPE_MASK) >> 8;
125293e4365SGiuseppe Cavallaro 
126293e4365SGiuseppe Cavallaro 		if (rdes4 & ERDES4_IP_HDR_ERR)
127c24602efSGiuseppe CAVALLARO 			x->ip_hdr_err++;
128293e4365SGiuseppe Cavallaro 		if (rdes4 & ERDES4_IP_PAYLOAD_ERR)
129c24602efSGiuseppe CAVALLARO 			x->ip_payload_err++;
130293e4365SGiuseppe Cavallaro 		if (rdes4 & ERDES4_IP_CSUM_BYPASSED)
131c24602efSGiuseppe CAVALLARO 			x->ip_csum_bypassed++;
132293e4365SGiuseppe Cavallaro 		if (rdes4 & ERDES4_IPV4_PKT_RCVD)
133c24602efSGiuseppe CAVALLARO 			x->ipv4_pkt_rcvd++;
134293e4365SGiuseppe Cavallaro 		if (rdes4 & ERDES4_IPV6_PKT_RCVD)
135c24602efSGiuseppe CAVALLARO 			x->ipv6_pkt_rcvd++;
136ee112c12SGiuseppe CAVALLARO 
137ee112c12SGiuseppe CAVALLARO 		if (message_type == RDES_EXT_NO_PTP)
138ee112c12SGiuseppe CAVALLARO 			x->no_ptp_rx_msg_type_ext++;
139ee112c12SGiuseppe CAVALLARO 		else if (message_type == RDES_EXT_SYNC)
140ee112c12SGiuseppe CAVALLARO 			x->ptp_rx_msg_type_sync++;
141293e4365SGiuseppe Cavallaro 		else if (message_type == RDES_EXT_FOLLOW_UP)
142ee112c12SGiuseppe CAVALLARO 			x->ptp_rx_msg_type_follow_up++;
143293e4365SGiuseppe Cavallaro 		else if (message_type == RDES_EXT_DELAY_REQ)
144ee112c12SGiuseppe CAVALLARO 			x->ptp_rx_msg_type_delay_req++;
145293e4365SGiuseppe Cavallaro 		else if (message_type == RDES_EXT_DELAY_RESP)
146ee112c12SGiuseppe CAVALLARO 			x->ptp_rx_msg_type_delay_resp++;
147293e4365SGiuseppe Cavallaro 		else if (message_type == RDES_EXT_PDELAY_REQ)
148ee112c12SGiuseppe CAVALLARO 			x->ptp_rx_msg_type_pdelay_req++;
149293e4365SGiuseppe Cavallaro 		else if (message_type == RDES_EXT_PDELAY_RESP)
150ee112c12SGiuseppe CAVALLARO 			x->ptp_rx_msg_type_pdelay_resp++;
151293e4365SGiuseppe Cavallaro 		else if (message_type == RDES_EXT_PDELAY_FOLLOW_UP)
152ee112c12SGiuseppe CAVALLARO 			x->ptp_rx_msg_type_pdelay_follow_up++;
153ee112c12SGiuseppe CAVALLARO 		else if (message_type == RDES_PTP_ANNOUNCE)
154ee112c12SGiuseppe CAVALLARO 			x->ptp_rx_msg_type_announce++;
155ee112c12SGiuseppe CAVALLARO 		else if (message_type == RDES_PTP_MANAGEMENT)
156ee112c12SGiuseppe CAVALLARO 			x->ptp_rx_msg_type_management++;
157ee112c12SGiuseppe CAVALLARO 		else if (message_type == RDES_PTP_PKT_RESERVED_TYPE)
158ee112c12SGiuseppe CAVALLARO 			x->ptp_rx_msg_pkt_reserved_type++;
159ee112c12SGiuseppe CAVALLARO 
160293e4365SGiuseppe Cavallaro 		if (rdes4 & ERDES4_PTP_FRAME_TYPE)
161c24602efSGiuseppe CAVALLARO 			x->ptp_frame_type++;
162293e4365SGiuseppe Cavallaro 		if (rdes4 & ERDES4_PTP_VER)
163c24602efSGiuseppe CAVALLARO 			x->ptp_ver++;
164293e4365SGiuseppe Cavallaro 		if (rdes4 & ERDES4_TIMESTAMP_DROPPED)
165c24602efSGiuseppe CAVALLARO 			x->timestamp_dropped++;
166293e4365SGiuseppe Cavallaro 		if (rdes4 & ERDES4_AV_PKT_RCVD)
167c24602efSGiuseppe CAVALLARO 			x->av_pkt_rcvd++;
168293e4365SGiuseppe Cavallaro 		if (rdes4 & ERDES4_AV_TAGGED_PKT_RCVD)
169c24602efSGiuseppe CAVALLARO 			x->av_tagged_pkt_rcvd++;
170293e4365SGiuseppe Cavallaro 		if ((rdes4 & ERDES4_VLAN_TAG_PRI_VAL_MASK) >> 18)
171c24602efSGiuseppe CAVALLARO 			x->vlan_tag_priority_val++;
172293e4365SGiuseppe Cavallaro 		if (rdes4 & ERDES4_L3_FILTER_MATCH)
173c24602efSGiuseppe CAVALLARO 			x->l3_filter_match++;
174293e4365SGiuseppe Cavallaro 		if (rdes4 & ERDES4_L4_FILTER_MATCH)
175c24602efSGiuseppe CAVALLARO 			x->l4_filter_match++;
176293e4365SGiuseppe Cavallaro 		if ((rdes4 & ERDES4_L3_L4_FILT_NO_MATCH_MASK) >> 26)
177c24602efSGiuseppe CAVALLARO 			x->l3_l4_filter_no_match++;
178c24602efSGiuseppe CAVALLARO 	}
179c24602efSGiuseppe CAVALLARO }
180c24602efSGiuseppe CAVALLARO 
enh_desc_get_rx_status(struct stmmac_extra_stats * x,struct dma_desc * p)181*133466c3SJisheng Zhang static int enh_desc_get_rx_status(struct stmmac_extra_stats *x,
1827ac6653aSJeff Kirsher 				  struct dma_desc *p)
1837ac6653aSJeff Kirsher {
184f8be0d78SMichael Weiser 	unsigned int rdes0 = le32_to_cpu(p->des0);
185293e4365SGiuseppe Cavallaro 	int ret = good_frame;
1867ac6653aSJeff Kirsher 
187c1fa3212SFabrice Gasnier 	if (unlikely(rdes0 & RDES0_OWN))
188c1fa3212SFabrice Gasnier 		return dma_own;
189c1fa3212SFabrice Gasnier 
1908ac0c24fSAaro Koskinen 	if (unlikely(!(rdes0 & RDES0_LAST_DESCRIPTOR))) {
191*133466c3SJisheng Zhang 		x->rx_length++;
1928ac0c24fSAaro Koskinen 		return discard_frame;
1938ac0c24fSAaro Koskinen 	}
1948ac0c24fSAaro Koskinen 
195293e4365SGiuseppe Cavallaro 	if (unlikely(rdes0 & RDES0_ERROR_SUMMARY)) {
196293e4365SGiuseppe Cavallaro 		if (unlikely(rdes0 & RDES0_DESCRIPTOR_ERROR)) {
1977ac6653aSJeff Kirsher 			x->rx_desc++;
198*133466c3SJisheng Zhang 			x->rx_length++;
1997ac6653aSJeff Kirsher 		}
200293e4365SGiuseppe Cavallaro 		if (unlikely(rdes0 & RDES0_OVERFLOW_ERROR))
2017ac6653aSJeff Kirsher 			x->rx_gmac_overflow++;
2027ac6653aSJeff Kirsher 
203293e4365SGiuseppe Cavallaro 		if (unlikely(rdes0 & RDES0_IPC_CSUM_ERROR))
20483d7af64SGiuseppe CAVALLARO 			pr_err("\tIPC Csum Error/Giant frame\n");
2057ac6653aSJeff Kirsher 
206293e4365SGiuseppe Cavallaro 		if (unlikely(rdes0 & RDES0_COLLISION))
207*133466c3SJisheng Zhang 			x->rx_collision++;
208293e4365SGiuseppe Cavallaro 		if (unlikely(rdes0 & RDES0_RECEIVE_WATCHDOG))
2097ac6653aSJeff Kirsher 			x->rx_watchdog++;
21083d7af64SGiuseppe CAVALLARO 
211293e4365SGiuseppe Cavallaro 		if (unlikely(rdes0 & RDES0_MII_ERROR))	/* GMII */
2127ac6653aSJeff Kirsher 			x->rx_mii++;
21383d7af64SGiuseppe CAVALLARO 
214293e4365SGiuseppe Cavallaro 		if (unlikely(rdes0 & RDES0_CRC_ERROR)) {
215e0a76606SLABBE Corentin 			x->rx_crc_errors++;
2167ac6653aSJeff Kirsher 		}
2177ac6653aSJeff Kirsher 		ret = discard_frame;
2187ac6653aSJeff Kirsher 	}
2197ac6653aSJeff Kirsher 
2207ac6653aSJeff Kirsher 	/* After a payload csum error, the ES bit is set.
2217ac6653aSJeff Kirsher 	 * It doesn't match with the information reported into the databook.
2227ac6653aSJeff Kirsher 	 * At any rate, we need to understand if the CSUM hw computation is ok
2237ac6653aSJeff Kirsher 	 * and report this info to the upper layers. */
2241b746ce8SAaro Koskinen 	if (likely(ret == good_frame))
225293e4365SGiuseppe Cavallaro 		ret = enh_desc_coe_rdes0(!!(rdes0 & RDES0_IPC_CSUM_ERROR),
226293e4365SGiuseppe Cavallaro 					 !!(rdes0 & RDES0_FRAME_TYPE),
227293e4365SGiuseppe Cavallaro 					 !!(rdes0 & ERDES0_RX_MAC_ADDR));
2287ac6653aSJeff Kirsher 
229293e4365SGiuseppe Cavallaro 	if (unlikely(rdes0 & RDES0_DRIBBLING))
2301cc5a735SGiuseppe CAVALLARO 		x->dribbling_bit++;
23183d7af64SGiuseppe CAVALLARO 
232293e4365SGiuseppe Cavallaro 	if (unlikely(rdes0 & RDES0_SA_FILTER_FAIL)) {
2337ac6653aSJeff Kirsher 		x->sa_rx_filter_fail++;
2347ac6653aSJeff Kirsher 		ret = discard_frame;
2357ac6653aSJeff Kirsher 	}
236293e4365SGiuseppe Cavallaro 	if (unlikely(rdes0 & RDES0_DA_FILTER_FAIL)) {
2377ac6653aSJeff Kirsher 		x->da_rx_filter_fail++;
2387ac6653aSJeff Kirsher 		ret = discard_frame;
2397ac6653aSJeff Kirsher 	}
240293e4365SGiuseppe Cavallaro 	if (unlikely(rdes0 & RDES0_LENGTH_ERROR)) {
2417ac6653aSJeff Kirsher 		x->rx_length++;
2427ac6653aSJeff Kirsher 		ret = discard_frame;
2437ac6653aSJeff Kirsher 	}
2447ac6653aSJeff Kirsher #ifdef STMMAC_VLAN_TAG_USED
245293e4365SGiuseppe Cavallaro 	if (rdes0 & RDES0_VLAN_TAG)
2467ac6653aSJeff Kirsher 		x->rx_vlan++;
2477ac6653aSJeff Kirsher #endif
248c24602efSGiuseppe CAVALLARO 
2497ac6653aSJeff Kirsher 	return ret;
2507ac6653aSJeff Kirsher }
2517ac6653aSJeff Kirsher 
enh_desc_init_rx_desc(struct dma_desc * p,int disable_rx_ic,int mode,int end,int bfsize)252c24602efSGiuseppe CAVALLARO static void enh_desc_init_rx_desc(struct dma_desc *p, int disable_rx_ic,
253583e6361SAaro Koskinen 				  int mode, int end, int bfsize)
2547ac6653aSJeff Kirsher {
255583e6361SAaro Koskinen 	int bfsize1;
256583e6361SAaro Koskinen 
257f8be0d78SMichael Weiser 	p->des0 |= cpu_to_le32(RDES0_OWN);
258583e6361SAaro Koskinen 
259583e6361SAaro Koskinen 	bfsize1 = min(bfsize, BUF_SIZE_8KiB);
260583e6361SAaro Koskinen 	p->des1 |= cpu_to_le32(bfsize1 & ERDES1_BUFFER1_SIZE_MASK);
261286a8372SGiuseppe CAVALLARO 
2624a7d666aSGiuseppe CAVALLARO 	if (mode == STMMAC_CHAIN_MODE)
263293e4365SGiuseppe Cavallaro 		ehn_desc_rx_set_on_chain(p);
2644a7d666aSGiuseppe CAVALLARO 	else
265583e6361SAaro Koskinen 		ehn_desc_rx_set_on_ring(p, end, bfsize);
266286a8372SGiuseppe CAVALLARO 
2677ac6653aSJeff Kirsher 	if (disable_rx_ic)
268f8be0d78SMichael Weiser 		p->des1 |= cpu_to_le32(ERDES1_DISABLE_IC);
2697ac6653aSJeff Kirsher }
2707ac6653aSJeff Kirsher 
enh_desc_init_tx_desc(struct dma_desc * p,int mode,int end)271c24602efSGiuseppe CAVALLARO static void enh_desc_init_tx_desc(struct dma_desc *p, int mode, int end)
2727ac6653aSJeff Kirsher {
273f8be0d78SMichael Weiser 	p->des0 &= cpu_to_le32(~ETDES0_OWN);
2744a7d666aSGiuseppe CAVALLARO 	if (mode == STMMAC_CHAIN_MODE)
275293e4365SGiuseppe Cavallaro 		enh_desc_end_tx_desc_on_chain(p);
2764a7d666aSGiuseppe CAVALLARO 	else
277293e4365SGiuseppe Cavallaro 		enh_desc_end_tx_desc_on_ring(p, end);
2787ac6653aSJeff Kirsher }
2797ac6653aSJeff Kirsher 
enh_desc_get_tx_owner(struct dma_desc * p)2807ac6653aSJeff Kirsher static int enh_desc_get_tx_owner(struct dma_desc *p)
2817ac6653aSJeff Kirsher {
282f8be0d78SMichael Weiser 	return (le32_to_cpu(p->des0) & ETDES0_OWN) >> 31;
2837ac6653aSJeff Kirsher }
2847ac6653aSJeff Kirsher 
enh_desc_set_tx_owner(struct dma_desc * p)2857ac6653aSJeff Kirsher static void enh_desc_set_tx_owner(struct dma_desc *p)
2867ac6653aSJeff Kirsher {
287f8be0d78SMichael Weiser 	p->des0 |= cpu_to_le32(ETDES0_OWN);
2887ac6653aSJeff Kirsher }
2897ac6653aSJeff Kirsher 
enh_desc_set_rx_owner(struct dma_desc * p,int disable_rx_ic)290357951cdSJose Abreu static void enh_desc_set_rx_owner(struct dma_desc *p, int disable_rx_ic)
2917ac6653aSJeff Kirsher {
292f8be0d78SMichael Weiser 	p->des0 |= cpu_to_le32(RDES0_OWN);
2937ac6653aSJeff Kirsher }
2947ac6653aSJeff Kirsher 
enh_desc_get_tx_ls(struct dma_desc * p)2957ac6653aSJeff Kirsher static int enh_desc_get_tx_ls(struct dma_desc *p)
2967ac6653aSJeff Kirsher {
297f8be0d78SMichael Weiser 	return (le32_to_cpu(p->des0) & ETDES0_LAST_SEGMENT) >> 29;
2987ac6653aSJeff Kirsher }
2997ac6653aSJeff Kirsher 
enh_desc_release_tx_desc(struct dma_desc * p,int mode)3004a7d666aSGiuseppe CAVALLARO static void enh_desc_release_tx_desc(struct dma_desc *p, int mode)
3017ac6653aSJeff Kirsher {
302f8be0d78SMichael Weiser 	int ter = (le32_to_cpu(p->des0) & ETDES0_END_RING) >> 21;
3037ac6653aSJeff Kirsher 
3047ac6653aSJeff Kirsher 	memset(p, 0, offsetof(struct dma_desc, des2));
3054a7d666aSGiuseppe CAVALLARO 	if (mode == STMMAC_CHAIN_MODE)
306293e4365SGiuseppe Cavallaro 		enh_desc_end_tx_desc_on_chain(p);
3074a7d666aSGiuseppe CAVALLARO 	else
3084a7d666aSGiuseppe CAVALLARO 		enh_desc_end_tx_desc_on_ring(p, ter);
3097ac6653aSJeff Kirsher }
3107ac6653aSJeff Kirsher 
enh_desc_prepare_tx_desc(struct dma_desc * p,int is_fs,int len,bool csum_flag,int mode,bool tx_own,bool ls,unsigned int tot_pkt_len)3117ac6653aSJeff Kirsher static void enh_desc_prepare_tx_desc(struct dma_desc *p, int is_fs, int len,
312be434d50SGiuseppe Cavallaro 				     bool csum_flag, int mode, bool tx_own,
313fe6af0e1SNiklas Cassel 				     bool ls, unsigned int tot_pkt_len)
3147ac6653aSJeff Kirsher {
315f8be0d78SMichael Weiser 	unsigned int tdes0 = le32_to_cpu(p->des0);
316293e4365SGiuseppe Cavallaro 
3170e80bdc9SGiuseppe Cavallaro 	if (mode == STMMAC_CHAIN_MODE)
3180e80bdc9SGiuseppe Cavallaro 		enh_set_tx_desc_len_on_chain(p, len);
3190e80bdc9SGiuseppe Cavallaro 	else
3200e80bdc9SGiuseppe Cavallaro 		enh_set_tx_desc_len_on_ring(p, len);
3210e80bdc9SGiuseppe Cavallaro 
322293e4365SGiuseppe Cavallaro 	if (is_fs)
323293e4365SGiuseppe Cavallaro 		tdes0 |= ETDES0_FIRST_SEGMENT;
324293e4365SGiuseppe Cavallaro 	else
325293e4365SGiuseppe Cavallaro 		tdes0 &= ~ETDES0_FIRST_SEGMENT;
326293e4365SGiuseppe Cavallaro 
327293e4365SGiuseppe Cavallaro 	if (likely(csum_flag))
328293e4365SGiuseppe Cavallaro 		tdes0 |= (TX_CIC_FULL << ETDES0_CHECKSUM_INSERTION_SHIFT);
329293e4365SGiuseppe Cavallaro 	else
330293e4365SGiuseppe Cavallaro 		tdes0 &= ~(TX_CIC_FULL << ETDES0_CHECKSUM_INSERTION_SHIFT);
331293e4365SGiuseppe Cavallaro 
3320e80bdc9SGiuseppe Cavallaro 	if (ls)
3330e80bdc9SGiuseppe Cavallaro 		tdes0 |= ETDES0_LAST_SEGMENT;
3340e80bdc9SGiuseppe Cavallaro 
3350e80bdc9SGiuseppe Cavallaro 	/* Finally set the OWN bit. Later the DMA will start! */
336be434d50SGiuseppe Cavallaro 	if (tx_own)
337be434d50SGiuseppe Cavallaro 		tdes0 |= ETDES0_OWN;
338be434d50SGiuseppe Cavallaro 
339d8f8b954SNiklas Cassel 	if (is_fs && tx_own)
340be434d50SGiuseppe Cavallaro 		/* When the own bit, for the first frame, has to be set, all
341be434d50SGiuseppe Cavallaro 		 * descriptors for the same frame has to be set before, to
342be434d50SGiuseppe Cavallaro 		 * avoid race condition.
343be434d50SGiuseppe Cavallaro 		 */
344ad688cdbSPavel Machek 		dma_wmb();
345be434d50SGiuseppe Cavallaro 
346f8be0d78SMichael Weiser 	p->des0 = cpu_to_le32(tdes0);
3477ac6653aSJeff Kirsher }
3487ac6653aSJeff Kirsher 
enh_desc_set_tx_ic(struct dma_desc * p)3490e80bdc9SGiuseppe Cavallaro static void enh_desc_set_tx_ic(struct dma_desc *p)
3507ac6653aSJeff Kirsher {
351f8be0d78SMichael Weiser 	p->des0 |= cpu_to_le32(ETDES0_INTERRUPT);
3527ac6653aSJeff Kirsher }
3537ac6653aSJeff Kirsher 
enh_desc_get_rx_frame_len(struct dma_desc * p,int rx_coe_type)35438912bdbSDeepak SIKRI static int enh_desc_get_rx_frame_len(struct dma_desc *p, int rx_coe_type)
3557ac6653aSJeff Kirsher {
356293e4365SGiuseppe Cavallaro 	unsigned int csum = 0;
35738912bdbSDeepak SIKRI 	/* The type-1 checksum offload engines append the checksum at
35838912bdbSDeepak SIKRI 	 * the end of frame and the two bytes of checksum are added in
35938912bdbSDeepak SIKRI 	 * the length.
36038912bdbSDeepak SIKRI 	 * Adjust for that in the framelen for type-1 checksum offload
361293e4365SGiuseppe Cavallaro 	 * engines.
362293e4365SGiuseppe Cavallaro 	 */
36338912bdbSDeepak SIKRI 	if (rx_coe_type == STMMAC_RX_COE_TYPE1)
364293e4365SGiuseppe Cavallaro 		csum = 2;
365293e4365SGiuseppe Cavallaro 
366f8be0d78SMichael Weiser 	return (((le32_to_cpu(p->des0) & RDES0_FRAME_LEN_MASK)
367f8be0d78SMichael Weiser 				>> RDES0_FRAME_LEN_SHIFT) - csum);
3687ac6653aSJeff Kirsher }
3697ac6653aSJeff Kirsher 
enh_desc_enable_tx_timestamp(struct dma_desc * p)370891434b1SRayagond Kokatanur static void enh_desc_enable_tx_timestamp(struct dma_desc *p)
371891434b1SRayagond Kokatanur {
372f8be0d78SMichael Weiser 	p->des0 |= cpu_to_le32(ETDES0_TIME_STAMP_ENABLE);
373891434b1SRayagond Kokatanur }
374891434b1SRayagond Kokatanur 
enh_desc_get_tx_timestamp_status(struct dma_desc * p)375891434b1SRayagond Kokatanur static int enh_desc_get_tx_timestamp_status(struct dma_desc *p)
376891434b1SRayagond Kokatanur {
377f8be0d78SMichael Weiser 	return (le32_to_cpu(p->des0) & ETDES0_TIME_STAMP_STATUS) >> 17;
378891434b1SRayagond Kokatanur }
379891434b1SRayagond Kokatanur 
enh_desc_get_timestamp(void * desc,u32 ats,u64 * ts)38042de047dSJose Abreu static void enh_desc_get_timestamp(void *desc, u32 ats, u64 *ts)
381891434b1SRayagond Kokatanur {
382891434b1SRayagond Kokatanur 	u64 ns;
383891434b1SRayagond Kokatanur 
384891434b1SRayagond Kokatanur 	if (ats) {
385891434b1SRayagond Kokatanur 		struct dma_extended_desc *p = (struct dma_extended_desc *)desc;
386f8be0d78SMichael Weiser 		ns = le32_to_cpu(p->des6);
387891434b1SRayagond Kokatanur 		/* convert high/sec time stamp value to nanosecond */
388f8be0d78SMichael Weiser 		ns += le32_to_cpu(p->des7) * 1000000000ULL;
389891434b1SRayagond Kokatanur 	} else {
390891434b1SRayagond Kokatanur 		struct dma_desc *p = (struct dma_desc *)desc;
391f8be0d78SMichael Weiser 		ns = le32_to_cpu(p->des2);
392f8be0d78SMichael Weiser 		ns += le32_to_cpu(p->des3) * 1000000000ULL;
393891434b1SRayagond Kokatanur 	}
394891434b1SRayagond Kokatanur 
39542de047dSJose Abreu 	*ts = ns;
396891434b1SRayagond Kokatanur }
397891434b1SRayagond Kokatanur 
enh_desc_get_rx_timestamp_status(void * desc,void * next_desc,u32 ats)398a1762456SFredrik Hallenberg static int enh_desc_get_rx_timestamp_status(void *desc, void *next_desc,
399a1762456SFredrik Hallenberg 					    u32 ats)
400891434b1SRayagond Kokatanur {
401891434b1SRayagond Kokatanur 	if (ats) {
402891434b1SRayagond Kokatanur 		struct dma_extended_desc *p = (struct dma_extended_desc *)desc;
403f8be0d78SMichael Weiser 		return (le32_to_cpu(p->basic.des0) & RDES0_IPC_CSUM_ERROR) >> 7;
404891434b1SRayagond Kokatanur 	} else {
405891434b1SRayagond Kokatanur 		struct dma_desc *p = (struct dma_desc *)desc;
406f8be0d78SMichael Weiser 		if ((le32_to_cpu(p->des2) == 0xffffffff) &&
407f8be0d78SMichael Weiser 		    (le32_to_cpu(p->des3) == 0xffffffff))
408891434b1SRayagond Kokatanur 			/* timestamp is corrupted, hence don't store it */
409891434b1SRayagond Kokatanur 			return 0;
410891434b1SRayagond Kokatanur 		else
411891434b1SRayagond Kokatanur 			return 1;
412891434b1SRayagond Kokatanur 	}
413891434b1SRayagond Kokatanur }
414891434b1SRayagond Kokatanur 
enh_desc_display_ring(void * head,unsigned int size,bool rx,dma_addr_t dma_rx_phy,unsigned int desc_size)415bfaf91caSJoakim Zhang static void enh_desc_display_ring(void *head, unsigned int size, bool rx,
416bfaf91caSJoakim Zhang 				  dma_addr_t dma_rx_phy, unsigned int desc_size)
417d0225e7dSAlexandre TORGUE {
418d0225e7dSAlexandre TORGUE 	struct dma_extended_desc *ep = (struct dma_extended_desc *)head;
419bfaf91caSJoakim Zhang 	dma_addr_t dma_addr;
420d0225e7dSAlexandre TORGUE 	int i;
421d0225e7dSAlexandre TORGUE 
422d0225e7dSAlexandre TORGUE 	pr_info("Extended %s descriptor ring:\n", rx ? "RX" : "TX");
423d0225e7dSAlexandre TORGUE 
424d0225e7dSAlexandre TORGUE 	for (i = 0; i < size; i++) {
425d0225e7dSAlexandre TORGUE 		u64 x;
426bfaf91caSJoakim Zhang 		dma_addr = dma_rx_phy + i * sizeof(*ep);
427d0225e7dSAlexandre TORGUE 
428d0225e7dSAlexandre TORGUE 		x = *(u64 *)ep;
429bfaf91caSJoakim Zhang 		pr_info("%03d [%pad]: 0x%x 0x%x 0x%x 0x%x\n",
430bfaf91caSJoakim Zhang 			i, &dma_addr,
431d0225e7dSAlexandre TORGUE 			(unsigned int)x, (unsigned int)(x >> 32),
432d0225e7dSAlexandre TORGUE 			ep->basic.des2, ep->basic.des3);
433d0225e7dSAlexandre TORGUE 		ep++;
434d0225e7dSAlexandre TORGUE 	}
435d0225e7dSAlexandre TORGUE 	pr_info("\n");
436d0225e7dSAlexandre TORGUE }
437d0225e7dSAlexandre TORGUE 
enh_desc_set_addr(struct dma_desc * p,dma_addr_t addr)4386844171dSJose Abreu static void enh_desc_set_addr(struct dma_desc *p, dma_addr_t addr)
4396844171dSJose Abreu {
4406844171dSJose Abreu 	p->des2 = cpu_to_le32(addr);
4416844171dSJose Abreu }
4426844171dSJose Abreu 
enh_desc_clear(struct dma_desc * p)44344c67f85SJose Abreu static void enh_desc_clear(struct dma_desc *p)
44444c67f85SJose Abreu {
44544c67f85SJose Abreu 	p->des2 = 0;
44644c67f85SJose Abreu }
44744c67f85SJose Abreu 
4487ac6653aSJeff Kirsher const struct stmmac_desc_ops enh_desc_ops = {
4497ac6653aSJeff Kirsher 	.tx_status = enh_desc_get_tx_status,
4507ac6653aSJeff Kirsher 	.rx_status = enh_desc_get_rx_status,
4517ac6653aSJeff Kirsher 	.get_tx_len = enh_desc_get_tx_len,
4527ac6653aSJeff Kirsher 	.init_rx_desc = enh_desc_init_rx_desc,
4537ac6653aSJeff Kirsher 	.init_tx_desc = enh_desc_init_tx_desc,
4547ac6653aSJeff Kirsher 	.get_tx_owner = enh_desc_get_tx_owner,
4557ac6653aSJeff Kirsher 	.release_tx_desc = enh_desc_release_tx_desc,
4567ac6653aSJeff Kirsher 	.prepare_tx_desc = enh_desc_prepare_tx_desc,
4570e80bdc9SGiuseppe Cavallaro 	.set_tx_ic = enh_desc_set_tx_ic,
4587ac6653aSJeff Kirsher 	.get_tx_ls = enh_desc_get_tx_ls,
4597ac6653aSJeff Kirsher 	.set_tx_owner = enh_desc_set_tx_owner,
4607ac6653aSJeff Kirsher 	.set_rx_owner = enh_desc_set_rx_owner,
4617ac6653aSJeff Kirsher 	.get_rx_frame_len = enh_desc_get_rx_frame_len,
462c24602efSGiuseppe CAVALLARO 	.rx_extended_status = enh_desc_get_ext_status,
463891434b1SRayagond Kokatanur 	.enable_tx_timestamp = enh_desc_enable_tx_timestamp,
464891434b1SRayagond Kokatanur 	.get_tx_timestamp_status = enh_desc_get_tx_timestamp_status,
465891434b1SRayagond Kokatanur 	.get_timestamp = enh_desc_get_timestamp,
466891434b1SRayagond Kokatanur 	.get_rx_timestamp_status = enh_desc_get_rx_timestamp_status,
467d0225e7dSAlexandre TORGUE 	.display_ring = enh_desc_display_ring,
4686844171dSJose Abreu 	.set_addr = enh_desc_set_addr,
46944c67f85SJose Abreu 	.clear = enh_desc_clear,
4707ac6653aSJeff Kirsher };
471