Branch data Line data Source code
1 : : // SPDX-License-Identifier: (GPL-2.0 OR MIT)
2 : : /*
3 : : * Copyright (c) 2018 Synopsys, Inc. and/or its affiliates.
4 : : * stmmac XGMAC support.
5 : : */
6 : :
7 : : #include <linux/stmmac.h>
8 : : #include "common.h"
9 : : #include "dwxgmac2.h"
10 : :
11 : 0 : static int dwxgmac2_get_tx_status(void *data, struct stmmac_extra_stats *x,
12 : : struct dma_desc *p, void __iomem *ioaddr)
13 : : {
14 : 0 : unsigned int tdes3 = le32_to_cpu(p->des3);
15 : 0 : int ret = tx_done;
16 : :
17 [ # # ]: 0 : if (unlikely(tdes3 & XGMAC_TDES3_OWN))
18 : : return tx_dma_own;
19 [ # # ]: 0 : if (likely(!(tdes3 & XGMAC_TDES3_LD)))
20 : 0 : return tx_not_ls;
21 : :
22 : : return ret;
23 : : }
24 : :
25 : 0 : static int dwxgmac2_get_rx_status(void *data, struct stmmac_extra_stats *x,
26 : : struct dma_desc *p)
27 : : {
28 : 0 : unsigned int rdes3 = le32_to_cpu(p->des3);
29 : :
30 [ # # ]: 0 : if (unlikely(rdes3 & XGMAC_RDES3_OWN))
31 : : return dma_own;
32 [ # # ]: 0 : if (unlikely(rdes3 & XGMAC_RDES3_CTXT))
33 : : return discard_frame;
34 [ # # ]: 0 : if (likely(!(rdes3 & XGMAC_RDES3_LD)))
35 : : return rx_not_ls;
36 [ # # ]: 0 : if (unlikely((rdes3 & XGMAC_RDES3_ES) && (rdes3 & XGMAC_RDES3_LD)))
37 : 0 : return discard_frame;
38 : :
39 : : return good_frame;
40 : : }
41 : :
42 : 0 : static int dwxgmac2_get_tx_len(struct dma_desc *p)
43 : : {
44 : 0 : return (le32_to_cpu(p->des2) & XGMAC_TDES2_B1L);
45 : : }
46 : :
47 : 0 : static int dwxgmac2_get_tx_owner(struct dma_desc *p)
48 : : {
49 : 0 : return (le32_to_cpu(p->des3) & XGMAC_TDES3_OWN) > 0;
50 : : }
51 : :
52 : 0 : static void dwxgmac2_set_tx_owner(struct dma_desc *p)
53 : : {
54 : 0 : p->des3 |= cpu_to_le32(XGMAC_TDES3_OWN);
55 : 0 : }
56 : :
57 : 0 : static void dwxgmac2_set_rx_owner(struct dma_desc *p, int disable_rx_ic)
58 : : {
59 : 0 : p->des3 |= cpu_to_le32(XGMAC_RDES3_OWN);
60 : :
61 [ # # ]: 0 : if (!disable_rx_ic)
62 : 0 : p->des3 |= cpu_to_le32(XGMAC_RDES3_IOC);
63 : 0 : }
64 : :
65 : 0 : static int dwxgmac2_get_tx_ls(struct dma_desc *p)
66 : : {
67 : 0 : return (le32_to_cpu(p->des3) & XGMAC_RDES3_LD) > 0;
68 : : }
69 : :
70 : 0 : static int dwxgmac2_get_rx_frame_len(struct dma_desc *p, int rx_coe)
71 : : {
72 : 0 : return (le32_to_cpu(p->des3) & XGMAC_RDES3_PL);
73 : : }
74 : :
75 : 0 : static void dwxgmac2_enable_tx_timestamp(struct dma_desc *p)
76 : : {
77 : 0 : p->des2 |= cpu_to_le32(XGMAC_TDES2_TTSE);
78 : 0 : }
79 : :
80 : 0 : static int dwxgmac2_get_tx_timestamp_status(struct dma_desc *p)
81 : : {
82 : 0 : return 0; /* Not supported */
83 : : }
84 : :
85 : 0 : static inline void dwxgmac2_get_timestamp(void *desc, u32 ats, u64 *ts)
86 : : {
87 : 0 : struct dma_desc *p = (struct dma_desc *)desc;
88 : 0 : u64 ns = 0;
89 : :
90 : 0 : ns += le32_to_cpu(p->des1) * 1000000000ULL;
91 : 0 : ns += le32_to_cpu(p->des0);
92 : :
93 : 0 : *ts = ns;
94 : 0 : }
95 : :
96 : 0 : static int dwxgmac2_rx_check_timestamp(void *desc)
97 : : {
98 : 0 : struct dma_desc *p = (struct dma_desc *)desc;
99 : 0 : unsigned int rdes3 = le32_to_cpu(p->des3);
100 : 0 : bool desc_valid, ts_valid;
101 : :
102 : 0 : dma_rmb();
103 : :
104 [ # # # # ]: 0 : desc_valid = !(rdes3 & XGMAC_RDES3_OWN) && (rdes3 & XGMAC_RDES3_CTXT);
105 : 0 : ts_valid = !(rdes3 & XGMAC_RDES3_TSD) && (rdes3 & XGMAC_RDES3_TSA);
106 : :
107 [ # # # # ]: 0 : if (likely(desc_valid && ts_valid)) {
108 [ # # # # ]: 0 : if ((p->des0 == 0xffffffff) && (p->des1 == 0xffffffff))
109 : : return -EINVAL;
110 : 0 : return 0;
111 : : }
112 : :
113 : : return -EINVAL;
114 : : }
115 : :
116 : 0 : static int dwxgmac2_get_rx_timestamp_status(void *desc, void *next_desc,
117 : : u32 ats)
118 : : {
119 : 0 : struct dma_desc *p = (struct dma_desc *)desc;
120 : 0 : unsigned int rdes3 = le32_to_cpu(p->des3);
121 : 0 : int ret = -EBUSY;
122 : :
123 [ # # ]: 0 : if (likely(rdes3 & XGMAC_RDES3_CDA))
124 : 0 : ret = dwxgmac2_rx_check_timestamp(next_desc);
125 : :
126 : 0 : return !ret;
127 : : }
128 : :
129 : 0 : static void dwxgmac2_init_rx_desc(struct dma_desc *p, int disable_rx_ic,
130 : : int mode, int end, int bfsize)
131 : : {
132 [ # # ]: 0 : dwxgmac2_set_rx_owner(p, disable_rx_ic);
133 : 0 : }
134 : :
135 : 0 : static void dwxgmac2_init_tx_desc(struct dma_desc *p, int mode, int end)
136 : : {
137 : 0 : p->des0 = 0;
138 : 0 : p->des1 = 0;
139 : 0 : p->des2 = 0;
140 : 0 : p->des3 = 0;
141 : 0 : }
142 : :
143 : 0 : static void dwxgmac2_prepare_tx_desc(struct dma_desc *p, int is_fs, int len,
144 : : bool csum_flag, int mode, bool tx_own,
145 : : bool ls, unsigned int tot_pkt_len)
146 : : {
147 : 0 : unsigned int tdes3 = le32_to_cpu(p->des3);
148 : :
149 : 0 : p->des2 |= cpu_to_le32(len & XGMAC_TDES2_B1L);
150 : :
151 : 0 : tdes3 |= tot_pkt_len & XGMAC_TDES3_FL;
152 [ # # ]: 0 : if (is_fs)
153 : 0 : tdes3 |= XGMAC_TDES3_FD;
154 : : else
155 : 0 : tdes3 &= ~XGMAC_TDES3_FD;
156 : :
157 [ # # ]: 0 : if (csum_flag)
158 : 0 : tdes3 |= 0x3 << XGMAC_TDES3_CIC_SHIFT;
159 : : else
160 : 0 : tdes3 &= ~XGMAC_TDES3_CIC;
161 : :
162 [ # # ]: 0 : if (ls)
163 : 0 : tdes3 |= XGMAC_TDES3_LD;
164 : : else
165 : 0 : tdes3 &= ~XGMAC_TDES3_LD;
166 : :
167 : : /* Finally set the OWN bit. Later the DMA will start! */
168 [ # # ]: 0 : if (tx_own)
169 : 0 : tdes3 |= XGMAC_TDES3_OWN;
170 : :
171 [ # # # # ]: 0 : if (is_fs && tx_own)
172 : : /* When the own bit, for the first frame, has to be set, all
173 : : * descriptors for the same frame has to be set before, to
174 : : * avoid race condition.
175 : : */
176 : 0 : dma_wmb();
177 : :
178 : 0 : p->des3 = cpu_to_le32(tdes3);
179 : 0 : }
180 : :
181 : 0 : static void dwxgmac2_prepare_tso_tx_desc(struct dma_desc *p, int is_fs,
182 : : int len1, int len2, bool tx_own,
183 : : bool ls, unsigned int tcphdrlen,
184 : : unsigned int tcppayloadlen)
185 : : {
186 : 0 : unsigned int tdes3 = le32_to_cpu(p->des3);
187 : :
188 [ # # ]: 0 : if (len1)
189 : 0 : p->des2 |= cpu_to_le32(len1 & XGMAC_TDES2_B1L);
190 [ # # ]: 0 : if (len2)
191 : 0 : p->des2 |= cpu_to_le32((len2 << XGMAC_TDES2_B2L_SHIFT) &
192 : : XGMAC_TDES2_B2L);
193 [ # # ]: 0 : if (is_fs) {
194 : 0 : tdes3 |= XGMAC_TDES3_FD | XGMAC_TDES3_TSE;
195 : 0 : tdes3 |= (tcphdrlen << XGMAC_TDES3_THL_SHIFT) &
196 : : XGMAC_TDES3_THL;
197 : 0 : tdes3 |= tcppayloadlen & XGMAC_TDES3_TPL;
198 : : } else {
199 : 0 : tdes3 &= ~XGMAC_TDES3_FD;
200 : : }
201 : :
202 [ # # ]: 0 : if (ls)
203 : 0 : tdes3 |= XGMAC_TDES3_LD;
204 : : else
205 : 0 : tdes3 &= ~XGMAC_TDES3_LD;
206 : :
207 : : /* Finally set the OWN bit. Later the DMA will start! */
208 [ # # ]: 0 : if (tx_own)
209 : 0 : tdes3 |= XGMAC_TDES3_OWN;
210 : :
211 [ # # # # ]: 0 : if (is_fs && tx_own)
212 : : /* When the own bit, for the first frame, has to be set, all
213 : : * descriptors for the same frame has to be set before, to
214 : : * avoid race condition.
215 : : */
216 : 0 : dma_wmb();
217 : :
218 : 0 : p->des3 = cpu_to_le32(tdes3);
219 : 0 : }
220 : :
221 : 0 : static void dwxgmac2_release_tx_desc(struct dma_desc *p, int mode)
222 : : {
223 : 0 : p->des0 = 0;
224 : 0 : p->des1 = 0;
225 : 0 : p->des2 = 0;
226 : 0 : p->des3 = 0;
227 : 0 : }
228 : :
229 : 0 : static void dwxgmac2_set_tx_ic(struct dma_desc *p)
230 : : {
231 : 0 : p->des2 |= cpu_to_le32(XGMAC_TDES2_IOC);
232 : 0 : }
233 : :
234 : 0 : static void dwxgmac2_set_mss(struct dma_desc *p, unsigned int mss)
235 : : {
236 : 0 : p->des0 = 0;
237 : 0 : p->des1 = 0;
238 : 0 : p->des2 = cpu_to_le32(mss);
239 : 0 : p->des3 = cpu_to_le32(XGMAC_TDES3_CTXT | XGMAC_TDES3_TCMSSV);
240 : 0 : }
241 : :
242 : 0 : static void dwxgmac2_get_addr(struct dma_desc *p, unsigned int *addr)
243 : : {
244 : 0 : *addr = le32_to_cpu(p->des0);
245 : 0 : }
246 : :
247 : 0 : static void dwxgmac2_set_addr(struct dma_desc *p, dma_addr_t addr)
248 : : {
249 : 0 : p->des0 = cpu_to_le32(lower_32_bits(addr));
250 : 0 : p->des1 = cpu_to_le32(upper_32_bits(addr));
251 : 0 : }
252 : :
253 : 0 : static void dwxgmac2_clear(struct dma_desc *p)
254 : : {
255 : 0 : p->des0 = 0;
256 : 0 : p->des1 = 0;
257 : 0 : p->des2 = 0;
258 : 0 : p->des3 = 0;
259 : 0 : }
260 : :
261 : 0 : static int dwxgmac2_get_rx_hash(struct dma_desc *p, u32 *hash,
262 : : enum pkt_hash_types *type)
263 : : {
264 : 0 : unsigned int rdes3 = le32_to_cpu(p->des3);
265 : 0 : u32 ptype;
266 : :
267 [ # # ]: 0 : if (rdes3 & XGMAC_RDES3_RSV) {
268 : 0 : ptype = (rdes3 & XGMAC_RDES3_L34T) >> XGMAC_RDES3_L34T_SHIFT;
269 : :
270 [ # # ]: 0 : switch (ptype) {
271 : 0 : case XGMAC_L34T_IP4TCP:
272 : : case XGMAC_L34T_IP4UDP:
273 : : case XGMAC_L34T_IP6TCP:
274 : : case XGMAC_L34T_IP6UDP:
275 : 0 : *type = PKT_HASH_TYPE_L4;
276 : 0 : break;
277 : 0 : default:
278 : 0 : *type = PKT_HASH_TYPE_L3;
279 : 0 : break;
280 : : }
281 : :
282 : 0 : *hash = le32_to_cpu(p->des1);
283 : 0 : return 0;
284 : : }
285 : :
286 : : return -EINVAL;
287 : : }
288 : :
289 : 0 : static int dwxgmac2_get_rx_header_len(struct dma_desc *p, unsigned int *len)
290 : : {
291 [ # # ]: 0 : if (le32_to_cpu(p->des3) & XGMAC_RDES3_L34T)
292 : 0 : *len = le32_to_cpu(p->des2) & XGMAC_RDES2_HL;
293 : 0 : return 0;
294 : : }
295 : :
296 : 0 : static void dwxgmac2_set_sec_addr(struct dma_desc *p, dma_addr_t addr)
297 : : {
298 : 0 : p->des2 = cpu_to_le32(lower_32_bits(addr));
299 : 0 : p->des3 = cpu_to_le32(upper_32_bits(addr));
300 : 0 : }
301 : :
302 : 0 : static void dwxgmac2_set_sarc(struct dma_desc *p, u32 sarc_type)
303 : : {
304 : 0 : sarc_type <<= XGMAC_TDES3_SAIC_SHIFT;
305 : :
306 : 0 : p->des3 |= cpu_to_le32(sarc_type & XGMAC_TDES3_SAIC);
307 : 0 : }
308 : :
309 : 0 : static void dwxgmac2_set_vlan_tag(struct dma_desc *p, u16 tag, u16 inner_tag,
310 : : u32 inner_type)
311 : : {
312 : 0 : p->des0 = 0;
313 : 0 : p->des1 = 0;
314 : 0 : p->des2 = 0;
315 : 0 : p->des3 = 0;
316 : :
317 : : /* Inner VLAN */
318 [ # # ]: 0 : if (inner_type) {
319 : 0 : u32 des = inner_tag << XGMAC_TDES2_IVT_SHIFT;
320 : :
321 : 0 : des &= XGMAC_TDES2_IVT;
322 : 0 : p->des2 = cpu_to_le32(des);
323 : :
324 : 0 : des = inner_type << XGMAC_TDES3_IVTIR_SHIFT;
325 : 0 : des &= XGMAC_TDES3_IVTIR;
326 : 0 : p->des3 = cpu_to_le32(des | XGMAC_TDES3_IVLTV);
327 : : }
328 : :
329 : : /* Outer VLAN */
330 : 0 : p->des3 |= cpu_to_le32(tag & XGMAC_TDES3_VT);
331 : 0 : p->des3 |= cpu_to_le32(XGMAC_TDES3_VLTV);
332 : :
333 : 0 : p->des3 |= cpu_to_le32(XGMAC_TDES3_CTXT);
334 : 0 : }
335 : :
336 : 0 : static void dwxgmac2_set_vlan(struct dma_desc *p, u32 type)
337 : : {
338 : 0 : type <<= XGMAC_TDES2_VTIR_SHIFT;
339 : 0 : p->des2 |= cpu_to_le32(type & XGMAC_TDES2_VTIR);
340 : 0 : }
341 : :
342 : 0 : static void dwxgmac2_set_tbs(struct dma_edesc *p, u32 sec, u32 nsec)
343 : : {
344 : 0 : p->des4 = cpu_to_le32((sec & XGMAC_TDES0_LT) | XGMAC_TDES0_LTV);
345 : 0 : p->des5 = cpu_to_le32(nsec & XGMAC_TDES1_LT);
346 : 0 : p->des6 = 0;
347 : 0 : p->des7 = 0;
348 : 0 : }
349 : :
350 : : const struct stmmac_desc_ops dwxgmac210_desc_ops = {
351 : : .tx_status = dwxgmac2_get_tx_status,
352 : : .rx_status = dwxgmac2_get_rx_status,
353 : : .get_tx_len = dwxgmac2_get_tx_len,
354 : : .get_tx_owner = dwxgmac2_get_tx_owner,
355 : : .set_tx_owner = dwxgmac2_set_tx_owner,
356 : : .set_rx_owner = dwxgmac2_set_rx_owner,
357 : : .get_tx_ls = dwxgmac2_get_tx_ls,
358 : : .get_rx_frame_len = dwxgmac2_get_rx_frame_len,
359 : : .enable_tx_timestamp = dwxgmac2_enable_tx_timestamp,
360 : : .get_tx_timestamp_status = dwxgmac2_get_tx_timestamp_status,
361 : : .get_rx_timestamp_status = dwxgmac2_get_rx_timestamp_status,
362 : : .get_timestamp = dwxgmac2_get_timestamp,
363 : : .set_tx_ic = dwxgmac2_set_tx_ic,
364 : : .prepare_tx_desc = dwxgmac2_prepare_tx_desc,
365 : : .prepare_tso_tx_desc = dwxgmac2_prepare_tso_tx_desc,
366 : : .release_tx_desc = dwxgmac2_release_tx_desc,
367 : : .init_rx_desc = dwxgmac2_init_rx_desc,
368 : : .init_tx_desc = dwxgmac2_init_tx_desc,
369 : : .set_mss = dwxgmac2_set_mss,
370 : : .get_addr = dwxgmac2_get_addr,
371 : : .set_addr = dwxgmac2_set_addr,
372 : : .clear = dwxgmac2_clear,
373 : : .get_rx_hash = dwxgmac2_get_rx_hash,
374 : : .get_rx_header_len = dwxgmac2_get_rx_header_len,
375 : : .set_sec_addr = dwxgmac2_set_sec_addr,
376 : : .set_sarc = dwxgmac2_set_sarc,
377 : : .set_vlan_tag = dwxgmac2_set_vlan_tag,
378 : : .set_vlan = dwxgmac2_set_vlan,
379 : : .set_tbs = dwxgmac2_set_tbs,
380 : : };
|