1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25#include <linux/stmmac.h>
26#include "common.h"
27#include "descs_com.h"
28
29static int ndesc_get_tx_status(void *data, struct stmmac_extra_stats *x,
30 struct dma_desc *p, void __iomem *ioaddr)
31{
32 struct net_device_stats *stats = (struct net_device_stats *)data;
33 unsigned int tdes0 = p->des0;
34 unsigned int tdes1 = p->des1;
35 int ret = tx_done;
36
37
38 if (unlikely(tdes0 & TDES0_OWN))
39 return tx_dma_own;
40
41
42 if (likely(!(tdes1 & TDES1_LAST_SEGMENT)))
43 return tx_not_ls;
44
45 if (unlikely(tdes0 & TDES0_ERROR_SUMMARY)) {
46 if (unlikely(tdes0 & TDES0_UNDERFLOW_ERROR)) {
47 x->tx_underflow++;
48 stats->tx_fifo_errors++;
49 }
50 if (unlikely(tdes0 & TDES0_NO_CARRIER)) {
51 x->tx_carrier++;
52 stats->tx_carrier_errors++;
53 }
54 if (unlikely(tdes0 & TDES0_LOSS_CARRIER)) {
55 x->tx_losscarrier++;
56 stats->tx_carrier_errors++;
57 }
58 if (unlikely((tdes0 & TDES0_EXCESSIVE_DEFERRAL) ||
59 (tdes0 & TDES0_EXCESSIVE_COLLISIONS) ||
60 (tdes0 & TDES0_LATE_COLLISION))) {
61 unsigned int collisions;
62
63 collisions = (tdes0 & TDES0_COLLISION_COUNT_MASK) >> 3;
64 stats->collisions += collisions;
65 }
66 ret = tx_err;
67 }
68
69 if (tdes0 & TDES0_VLAN_FRAME)
70 x->tx_vlan++;
71
72 if (unlikely(tdes0 & TDES0_DEFERRED))
73 x->tx_deferred++;
74
75 return ret;
76}
77
78static int ndesc_get_tx_len(struct dma_desc *p)
79{
80 return (p->des1 & RDES1_BUFFER1_SIZE_MASK);
81}
82
83
84
85
86
87static int ndesc_get_rx_status(void *data, struct stmmac_extra_stats *x,
88 struct dma_desc *p)
89{
90 int ret = good_frame;
91 unsigned int rdes0 = p->des0;
92 struct net_device_stats *stats = (struct net_device_stats *)data;
93
94 if (unlikely(rdes0 & RDES0_OWN))
95 return dma_own;
96
97 if (unlikely(!(rdes0 & RDES0_LAST_DESCRIPTOR))) {
98 pr_warn("%s: Oversized frame spanned multiple buffers\n",
99 __func__);
100 stats->rx_length_errors++;
101 return discard_frame;
102 }
103
104 if (unlikely(rdes0 & RDES0_ERROR_SUMMARY)) {
105 if (unlikely(rdes0 & RDES0_DESCRIPTOR_ERROR))
106 x->rx_desc++;
107 if (unlikely(rdes0 & RDES0_SA_FILTER_FAIL))
108 x->sa_filter_fail++;
109 if (unlikely(rdes0 & RDES0_OVERFLOW_ERROR))
110 x->overflow_error++;
111 if (unlikely(rdes0 & RDES0_IPC_CSUM_ERROR))
112 x->ipc_csum_error++;
113 if (unlikely(rdes0 & RDES0_COLLISION)) {
114 x->rx_collision++;
115 stats->collisions++;
116 }
117 if (unlikely(rdes0 & RDES0_CRC_ERROR)) {
118 x->rx_crc++;
119 stats->rx_crc_errors++;
120 }
121 ret = discard_frame;
122 }
123 if (unlikely(rdes0 & RDES0_DRIBBLING))
124 x->dribbling_bit++;
125
126 if (unlikely(rdes0 & RDES0_LENGTH_ERROR)) {
127 x->rx_length++;
128 ret = discard_frame;
129 }
130 if (unlikely(rdes0 & RDES0_MII_ERROR)) {
131 x->rx_mii++;
132 ret = discard_frame;
133 }
134#ifdef STMMAC_VLAN_TAG_USED
135 if (rdes0 & RDES0_VLAN_TAG)
136 x->vlan_tag++;
137#endif
138 return ret;
139}
140
141static void ndesc_init_rx_desc(struct dma_desc *p, int disable_rx_ic, int mode,
142 int end)
143{
144 p->des0 |= RDES0_OWN;
145 p->des1 |= (BUF_SIZE_2KiB - 1) & RDES1_BUFFER1_SIZE_MASK;
146
147 if (mode == STMMAC_CHAIN_MODE)
148 ndesc_rx_set_on_chain(p, end);
149 else
150 ndesc_rx_set_on_ring(p, end);
151
152 if (disable_rx_ic)
153 p->des1 |= RDES1_DISABLE_IC;
154}
155
156static void ndesc_init_tx_desc(struct dma_desc *p, int mode, int end)
157{
158 p->des0 &= ~TDES0_OWN;
159 if (mode == STMMAC_CHAIN_MODE)
160 ndesc_tx_set_on_chain(p);
161 else
162 ndesc_end_tx_desc_on_ring(p, end);
163}
164
165static int ndesc_get_tx_owner(struct dma_desc *p)
166{
167 return (p->des0 & TDES0_OWN) >> 31;
168}
169
170static void ndesc_set_tx_owner(struct dma_desc *p)
171{
172 p->des0 |= TDES0_OWN;
173}
174
175static void ndesc_set_rx_owner(struct dma_desc *p)
176{
177 p->des0 |= RDES0_OWN;
178}
179
180static int ndesc_get_tx_ls(struct dma_desc *p)
181{
182 return (p->des1 & TDES1_LAST_SEGMENT) >> 30;
183}
184
185static void ndesc_release_tx_desc(struct dma_desc *p, int mode)
186{
187 int ter = (p->des1 & TDES1_END_RING) >> 25;
188
189 memset(p, 0, offsetof(struct dma_desc, des2));
190 if (mode == STMMAC_CHAIN_MODE)
191 ndesc_tx_set_on_chain(p);
192 else
193 ndesc_end_tx_desc_on_ring(p, ter);
194}
195
196static void ndesc_prepare_tx_desc(struct dma_desc *p, int is_fs, int len,
197 bool csum_flag, int mode, bool tx_own,
198 bool ls)
199{
200 unsigned int tdes1 = p->des1;
201
202 if (is_fs)
203 tdes1 |= TDES1_FIRST_SEGMENT;
204 else
205 tdes1 &= ~TDES1_FIRST_SEGMENT;
206
207 if (likely(csum_flag))
208 tdes1 |= (TX_CIC_FULL) << TDES1_CHECKSUM_INSERTION_SHIFT;
209 else
210 tdes1 &= ~(TX_CIC_FULL << TDES1_CHECKSUM_INSERTION_SHIFT);
211
212 if (ls)
213 tdes1 |= TDES1_LAST_SEGMENT;
214
215 p->des1 = tdes1;
216
217 if (mode == STMMAC_CHAIN_MODE)
218 norm_set_tx_desc_len_on_chain(p, len);
219 else
220 norm_set_tx_desc_len_on_ring(p, len);
221
222 if (tx_own)
223 p->des0 |= TDES0_OWN;
224}
225
226static void ndesc_set_tx_ic(struct dma_desc *p)
227{
228 p->des1 |= TDES1_INTERRUPT;
229}
230
231static int ndesc_get_rx_frame_len(struct dma_desc *p, int rx_coe_type)
232{
233 unsigned int csum = 0;
234
235
236
237
238
239
240
241 if (rx_coe_type == STMMAC_RX_COE_TYPE1)
242 csum = 2;
243
244 return (((p->des0 & RDES0_FRAME_LEN_MASK) >> RDES0_FRAME_LEN_SHIFT) -
245 csum);
246
247}
248
249static void ndesc_enable_tx_timestamp(struct dma_desc *p)
250{
251 p->des1 |= TDES1_TIME_STAMP_ENABLE;
252}
253
254static int ndesc_get_tx_timestamp_status(struct dma_desc *p)
255{
256 return (p->des0 & TDES0_TIME_STAMP_STATUS) >> 17;
257}
258
259static u64 ndesc_get_timestamp(void *desc, u32 ats)
260{
261 struct dma_desc *p = (struct dma_desc *)desc;
262 u64 ns;
263
264 ns = p->des2;
265
266 ns += p->des3 * 1000000000ULL;
267
268 return ns;
269}
270
271static int ndesc_get_rx_timestamp_status(void *desc, u32 ats)
272{
273 struct dma_desc *p = (struct dma_desc *)desc;
274
275 if ((p->des2 == 0xffffffff) && (p->des3 == 0xffffffff))
276
277 return 0;
278 else
279 return 1;
280}
281
282const struct stmmac_desc_ops ndesc_ops = {
283 .tx_status = ndesc_get_tx_status,
284 .rx_status = ndesc_get_rx_status,
285 .get_tx_len = ndesc_get_tx_len,
286 .init_rx_desc = ndesc_init_rx_desc,
287 .init_tx_desc = ndesc_init_tx_desc,
288 .get_tx_owner = ndesc_get_tx_owner,
289 .release_tx_desc = ndesc_release_tx_desc,
290 .prepare_tx_desc = ndesc_prepare_tx_desc,
291 .set_tx_ic = ndesc_set_tx_ic,
292 .get_tx_ls = ndesc_get_tx_ls,
293 .set_tx_owner = ndesc_set_tx_owner,
294 .set_rx_owner = ndesc_set_rx_owner,
295 .get_rx_frame_len = ndesc_get_rx_frame_len,
296 .enable_tx_timestamp = ndesc_enable_tx_timestamp,
297 .get_tx_timestamp_status = ndesc_get_tx_timestamp_status,
298 .get_timestamp = ndesc_get_timestamp,
299 .get_rx_timestamp_status = ndesc_get_rx_timestamp_status,
300};
301