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