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