87e747f9ba52cff90eff5b296139f832acb598cc
[dpdk.git] / drivers / net / octeontx2 / otx2_tx.h
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(C) 2019 Marvell International Ltd.
3  */
4
5 #ifndef __OTX2_TX_H__
6 #define __OTX2_TX_H__
7
8 #define NIX_TX_OFFLOAD_NONE             (0)
9 #define NIX_TX_OFFLOAD_L3_L4_CSUM_F     BIT(0)
10 #define NIX_TX_OFFLOAD_OL3_OL4_CSUM_F   BIT(1)
11 #define NIX_TX_OFFLOAD_VLAN_QINQ_F      BIT(2)
12 #define NIX_TX_OFFLOAD_MBUF_NOFF_F      BIT(3)
13 #define NIX_TX_OFFLOAD_TSTAMP_F         BIT(4)
14
15 /* Flags to control xmit_prepare function.
16  * Defining it from backwards to denote its been
17  * not used as offload flags to pick function
18  */
19 #define NIX_TX_MULTI_SEG_F              BIT(15)
20
21 #define NIX_TX_NEED_SEND_HDR_W1 \
22         (NIX_TX_OFFLOAD_L3_L4_CSUM_F | NIX_TX_OFFLOAD_OL3_OL4_CSUM_F |  \
23          NIX_TX_OFFLOAD_VLAN_QINQ_F)
24
25 #define NIX_TX_NEED_EXT_HDR \
26         (NIX_TX_OFFLOAD_VLAN_QINQ_F | NIX_TX_OFFLOAD_TSTAMP_F)
27
28 /* Function to determine no of tx subdesc required in case ext
29  * sub desc is enabled.
30  */
31 static __rte_always_inline int
32 otx2_nix_tx_ext_subs(const uint16_t flags)
33 {
34         return (flags & NIX_TX_OFFLOAD_TSTAMP_F) ? 2 :
35                 ((flags & NIX_TX_OFFLOAD_VLAN_QINQ_F) ? 1 : 0);
36 }
37
38 static __rte_always_inline void
39 otx2_nix_xmit_prepare_tstamp(uint64_t *cmd,  const uint64_t *send_mem_desc,
40                              const uint64_t ol_flags, const uint16_t no_segdw,
41                              const uint16_t flags)
42 {
43         if (flags & NIX_TX_OFFLOAD_TSTAMP_F) {
44                 struct nix_send_mem_s *send_mem;
45                 uint16_t off = (no_segdw - 1) << 1;
46
47                 send_mem = (struct nix_send_mem_s *)(cmd + off);
48                 if (flags & NIX_TX_MULTI_SEG_F)
49                         /* Retrieving the default desc values */
50                         cmd[off] = send_mem_desc[6];
51
52                 /* Packets for which PKT_TX_IEEE1588_TMST is not set, tx tstamp
53                  * should not be updated at tx tstamp registered address, rather
54                  * a dummy address which is eight bytes ahead would be updated
55                  */
56                 send_mem->addr = (rte_iova_t)((uint64_t *)send_mem_desc[7] +
57                                 !(ol_flags & PKT_TX_IEEE1588_TMST));
58         }
59 }
60
61 static __rte_always_inline uint64_t
62 otx2_pktmbuf_detach(struct rte_mbuf *m)
63 {
64         struct rte_mempool *mp = m->pool;
65         uint32_t mbuf_size, buf_len;
66         struct rte_mbuf *md;
67         uint16_t priv_size;
68         uint16_t refcount;
69
70         /* Update refcount of direct mbuf */
71         md = rte_mbuf_from_indirect(m);
72         refcount = rte_mbuf_refcnt_update(md, -1);
73
74         priv_size = rte_pktmbuf_priv_size(mp);
75         mbuf_size = (uint32_t)(sizeof(struct rte_mbuf) + priv_size);
76         buf_len = rte_pktmbuf_data_room_size(mp);
77
78         m->priv_size = priv_size;
79         m->buf_addr = (char *)m + mbuf_size;
80         m->buf_iova = rte_mempool_virt2iova(m) + mbuf_size;
81         m->buf_len = (uint16_t)buf_len;
82         rte_pktmbuf_reset_headroom(m);
83         m->data_len = 0;
84         m->ol_flags = 0;
85         m->next = NULL;
86         m->nb_segs = 1;
87
88         /* Now indirect mbuf is safe to free */
89         rte_pktmbuf_free(m);
90
91         if (refcount == 0) {
92                 rte_mbuf_refcnt_set(md, 1);
93                 md->data_len = 0;
94                 md->ol_flags = 0;
95                 md->next = NULL;
96                 md->nb_segs = 1;
97                 return 0;
98         } else {
99                 return 1;
100         }
101 }
102
103 static __rte_always_inline uint64_t
104 otx2_nix_prefree_seg(struct rte_mbuf *m)
105 {
106         if (likely(rte_mbuf_refcnt_read(m) == 1)) {
107                 if (!RTE_MBUF_DIRECT(m))
108                         return otx2_pktmbuf_detach(m);
109
110                 m->next = NULL;
111                 m->nb_segs = 1;
112                 return 0;
113         } else if (rte_mbuf_refcnt_update(m, -1) == 0) {
114                 if (!RTE_MBUF_DIRECT(m))
115                         return otx2_pktmbuf_detach(m);
116
117                 rte_mbuf_refcnt_set(m, 1);
118                 m->next = NULL;
119                 m->nb_segs = 1;
120                 return 0;
121         }
122
123         /* Mbuf is having refcount more than 1 so need not to be freed */
124         return 1;
125 }
126
127 static inline void
128 otx2_nix_xmit_prepare(struct rte_mbuf *m, uint64_t *cmd, const uint16_t flags)
129 {
130         struct nix_send_ext_s *send_hdr_ext;
131         struct nix_send_hdr_s *send_hdr;
132         uint64_t ol_flags = 0, mask;
133         union nix_send_hdr_w1_u w1;
134         union nix_send_sg_s *sg;
135
136         send_hdr = (struct nix_send_hdr_s *)cmd;
137         if (flags & NIX_TX_NEED_EXT_HDR) {
138                 send_hdr_ext = (struct nix_send_ext_s *)(cmd + 2);
139                 sg = (union nix_send_sg_s *)(cmd + 4);
140                 /* Clear previous markings */
141                 send_hdr_ext->w0.lso = 0;
142                 send_hdr_ext->w1.u = 0;
143         } else {
144                 sg = (union nix_send_sg_s *)(cmd + 2);
145         }
146
147         if (flags & NIX_TX_NEED_SEND_HDR_W1) {
148                 ol_flags = m->ol_flags;
149                 w1.u = 0;
150         }
151
152         if (!(flags & NIX_TX_MULTI_SEG_F)) {
153                 send_hdr->w0.total = m->data_len;
154                 send_hdr->w0.aura =
155                         npa_lf_aura_handle_to_aura(m->pool->pool_id);
156         }
157
158         /*
159          * L3type:  2 => IPV4
160          *          3 => IPV4 with csum
161          *          4 => IPV6
162          * L3type and L3ptr needs to be set for either
163          * L3 csum or L4 csum or LSO
164          *
165          */
166
167         if ((flags & NIX_TX_OFFLOAD_OL3_OL4_CSUM_F) &&
168             (flags & NIX_TX_OFFLOAD_L3_L4_CSUM_F)) {
169                 const uint8_t csum = !!(ol_flags & PKT_TX_OUTER_UDP_CKSUM);
170                 const uint8_t ol3type =
171                         ((!!(ol_flags & PKT_TX_OUTER_IPV4)) << 1) +
172                         ((!!(ol_flags & PKT_TX_OUTER_IPV6)) << 2) +
173                         !!(ol_flags & PKT_TX_OUTER_IP_CKSUM);
174
175                 /* Outer L3 */
176                 w1.ol3type = ol3type;
177                 mask = 0xffffull << ((!!ol3type) << 4);
178                 w1.ol3ptr = ~mask & m->outer_l2_len;
179                 w1.ol4ptr = ~mask & (w1.ol3ptr + m->outer_l3_len);
180
181                 /* Outer L4 */
182                 w1.ol4type = csum + (csum << 1);
183
184                 /* Inner L3 */
185                 w1.il3type = ((!!(ol_flags & PKT_TX_IPV4)) << 1) +
186                         ((!!(ol_flags & PKT_TX_IPV6)) << 2);
187                 w1.il3ptr = w1.ol4ptr + m->l2_len;
188                 w1.il4ptr = w1.il3ptr + m->l3_len;
189                 /* Increment it by 1 if it is IPV4 as 3 is with csum */
190                 w1.il3type = w1.il3type + !!(ol_flags & PKT_TX_IP_CKSUM);
191
192                 /* Inner L4 */
193                 w1.il4type =  (ol_flags & PKT_TX_L4_MASK) >> 52;
194
195                 /* In case of no tunnel header use only
196                  * shift IL3/IL4 fields a bit to use
197                  * OL3/OL4 for header checksum
198                  */
199                 mask = !ol3type;
200                 w1.u = ((w1.u & 0xFFFFFFFF00000000) >> (mask << 3)) |
201                         ((w1.u & 0X00000000FFFFFFFF) >> (mask << 4));
202
203         } else if (flags & NIX_TX_OFFLOAD_OL3_OL4_CSUM_F) {
204                 const uint8_t csum = !!(ol_flags & PKT_TX_OUTER_UDP_CKSUM);
205                 const uint8_t outer_l2_len = m->outer_l2_len;
206
207                 /* Outer L3 */
208                 w1.ol3ptr = outer_l2_len;
209                 w1.ol4ptr = outer_l2_len + m->outer_l3_len;
210                 /* Increment it by 1 if it is IPV4 as 3 is with csum */
211                 w1.ol3type = ((!!(ol_flags & PKT_TX_OUTER_IPV4)) << 1) +
212                         ((!!(ol_flags & PKT_TX_OUTER_IPV6)) << 2) +
213                         !!(ol_flags & PKT_TX_OUTER_IP_CKSUM);
214
215                 /* Outer L4 */
216                 w1.ol4type = csum + (csum << 1);
217
218         } else if (flags & NIX_TX_OFFLOAD_L3_L4_CSUM_F) {
219                 const uint8_t l2_len = m->l2_len;
220
221                 /* Always use OLXPTR and OLXTYPE when only
222                  * when one header is present
223                  */
224
225                 /* Inner L3 */
226                 w1.ol3ptr = l2_len;
227                 w1.ol4ptr = l2_len + m->l3_len;
228                 /* Increment it by 1 if it is IPV4 as 3 is with csum */
229                 w1.ol3type = ((!!(ol_flags & PKT_TX_IPV4)) << 1) +
230                         ((!!(ol_flags & PKT_TX_IPV6)) << 2) +
231                         !!(ol_flags & PKT_TX_IP_CKSUM);
232
233                 /* Inner L4 */
234                 w1.ol4type =  (ol_flags & PKT_TX_L4_MASK) >> 52;
235         }
236
237         if (flags & NIX_TX_NEED_EXT_HDR &&
238             flags & NIX_TX_OFFLOAD_VLAN_QINQ_F) {
239                 send_hdr_ext->w1.vlan1_ins_ena = !!(ol_flags & PKT_TX_VLAN);
240                 /* HW will update ptr after vlan0 update */
241                 send_hdr_ext->w1.vlan1_ins_ptr = 12;
242                 send_hdr_ext->w1.vlan1_ins_tci = m->vlan_tci;
243
244                 send_hdr_ext->w1.vlan0_ins_ena = !!(ol_flags & PKT_TX_QINQ);
245                 /* 2B before end of l2 header */
246                 send_hdr_ext->w1.vlan0_ins_ptr = 12;
247                 send_hdr_ext->w1.vlan0_ins_tci = m->vlan_tci_outer;
248         }
249
250         if (flags & NIX_TX_NEED_SEND_HDR_W1)
251                 send_hdr->w1.u = w1.u;
252
253         if (!(flags & NIX_TX_MULTI_SEG_F)) {
254                 sg->seg1_size = m->data_len;
255                 *(rte_iova_t *)(++sg) = rte_mbuf_data_iova(m);
256
257                 if (flags & NIX_TX_OFFLOAD_MBUF_NOFF_F) {
258                         /* DF bit = 1 if refcount of current mbuf or parent mbuf
259                          *              is greater than 1
260                          * DF bit = 0 otherwise
261                          */
262                         send_hdr->w0.df = otx2_nix_prefree_seg(m);
263                 }
264                 /* Mark mempool object as "put" since it is freed by NIX */
265                 if (!send_hdr->w0.df)
266                         __mempool_check_cookies(m->pool, (void **)&m, 1, 0);
267         }
268 }
269
270
271 static __rte_always_inline void
272 otx2_nix_xmit_one(uint64_t *cmd, void *lmt_addr,
273                   const rte_iova_t io_addr, const uint32_t flags)
274 {
275         uint64_t lmt_status;
276
277         do {
278                 otx2_lmt_mov(lmt_addr, cmd, otx2_nix_tx_ext_subs(flags));
279                 lmt_status = otx2_lmt_submit(io_addr);
280         } while (lmt_status == 0);
281 }
282
283 static __rte_always_inline uint16_t
284 otx2_nix_prepare_mseg(struct rte_mbuf *m, uint64_t *cmd, const uint16_t flags)
285 {
286         struct nix_send_hdr_s *send_hdr;
287         union nix_send_sg_s *sg;
288         struct rte_mbuf *m_next;
289         uint64_t *slist, sg_u;
290         uint64_t nb_segs;
291         uint64_t segdw;
292         uint8_t off, i;
293
294         send_hdr = (struct nix_send_hdr_s *)cmd;
295         send_hdr->w0.total = m->pkt_len;
296         send_hdr->w0.aura = npa_lf_aura_handle_to_aura(m->pool->pool_id);
297
298         if (flags & NIX_TX_NEED_EXT_HDR)
299                 off = 2;
300         else
301                 off = 0;
302
303         sg = (union nix_send_sg_s *)&cmd[2 + off];
304         /* Clear sg->u header before use */
305         sg->u &= 0xFC00000000000000;
306         sg_u = sg->u;
307         slist = &cmd[3 + off];
308
309         i = 0;
310         nb_segs = m->nb_segs;
311
312         /* Fill mbuf segments */
313         do {
314                 m_next = m->next;
315                 sg_u = sg_u | ((uint64_t)m->data_len << (i << 4));
316                 *slist = rte_mbuf_data_iova(m);
317                 /* Set invert df if buffer is not to be freed by H/W */
318                 if (flags & NIX_TX_OFFLOAD_MBUF_NOFF_F)
319                         sg_u |= (otx2_nix_prefree_seg(m) << (i + 55));
320                 /* Mark mempool object as "put" since it is freed by NIX */
321                 if (!(sg_u & (1ULL << (i + 55)))) {
322                         m->next = NULL;
323                         __mempool_check_cookies(m->pool, (void **)&m, 1, 0);
324                 }
325                 slist++;
326                 i++;
327                 nb_segs--;
328                 if (i > 2 && nb_segs) {
329                         i = 0;
330                         /* Next SG subdesc */
331                         *(uint64_t *)slist = sg_u & 0xFC00000000000000;
332                         sg->u = sg_u;
333                         sg->segs = 3;
334                         sg = (union nix_send_sg_s *)slist;
335                         sg_u = sg->u;
336                         slist++;
337                 }
338                 m = m_next;
339         } while (nb_segs);
340
341         sg->u = sg_u;
342         sg->segs = i;
343         segdw = (uint64_t *)slist - (uint64_t *)&cmd[2 + off];
344         /* Roundup extra dwords to multiple of 2 */
345         segdw = (segdw >> 1) + (segdw & 0x1);
346         /* Default dwords */
347         segdw += (off >> 1) + 1 + !!(flags & NIX_TX_OFFLOAD_TSTAMP_F);
348         send_hdr->w0.sizem1 = segdw - 1;
349
350         return segdw;
351 }
352
353 static __rte_always_inline void
354 otx2_nix_xmit_mseg_one(uint64_t *cmd, void *lmt_addr,
355                        rte_iova_t io_addr, uint16_t segdw)
356 {
357         uint64_t lmt_status;
358
359         do {
360                 otx2_lmt_mov_seg(lmt_addr, (const void *)cmd, segdw);
361                 lmt_status = otx2_lmt_submit(io_addr);
362         } while (lmt_status == 0);
363 }
364
365 #define L3L4CSUM_F   NIX_TX_OFFLOAD_L3_L4_CSUM_F
366 #define OL3OL4CSUM_F NIX_TX_OFFLOAD_OL3_OL4_CSUM_F
367 #define VLAN_F       NIX_TX_OFFLOAD_VLAN_QINQ_F
368 #define NOFF_F       NIX_TX_OFFLOAD_MBUF_NOFF_F
369 #define TSP_F        NIX_TX_OFFLOAD_TSTAMP_F
370
371 /* [TSTMP] [NOFF] [VLAN] [OL3OL4CSUM] [L3L4CSUM] */
372 #define NIX_TX_FASTPATH_MODES                                   \
373 T(no_offload,                           0, 0, 0, 0, 0,  4,      \
374                 NIX_TX_OFFLOAD_NONE)                            \
375 T(l3l4csum,                             0, 0, 0, 0, 1,  4,      \
376                 L3L4CSUM_F)                                     \
377 T(ol3ol4csum,                           0, 0, 0, 1, 0,  4,      \
378                 OL3OL4CSUM_F)                                   \
379 T(ol3ol4csum_l3l4csum,                  0, 0, 0, 1, 1,  4,      \
380                 OL3OL4CSUM_F | L3L4CSUM_F)                      \
381 T(vlan,                                 0, 0, 1, 0, 0,  6,      \
382                 VLAN_F)                                         \
383 T(vlan_l3l4csum,                        0, 0, 1, 0, 1,  6,      \
384                 VLAN_F | L3L4CSUM_F)                            \
385 T(vlan_ol3ol4csum,                      0, 0, 1, 1, 0,  6,      \
386                 VLAN_F | OL3OL4CSUM_F)                          \
387 T(vlan_ol3ol4csum_l3l4csum,             0, 0, 1, 1, 1,  6,      \
388                 VLAN_F | OL3OL4CSUM_F | L3L4CSUM_F)             \
389 T(noff,                                 0, 1, 0, 0, 0,  4,      \
390                 NOFF_F)                                         \
391 T(noff_l3l4csum,                        0, 1, 0, 0, 1,  4,      \
392                 NOFF_F | L3L4CSUM_F)                            \
393 T(noff_ol3ol4csum,                      0, 1, 0, 1, 0,  4,      \
394                 NOFF_F | OL3OL4CSUM_F)                          \
395 T(noff_ol3ol4csum_l3l4csum,             0, 1, 0, 1, 1,  4,      \
396                 NOFF_F | OL3OL4CSUM_F | L3L4CSUM_F)             \
397 T(noff_vlan,                            0, 1, 1, 0, 0,  6,      \
398                 NOFF_F | VLAN_F)                                \
399 T(noff_vlan_l3l4csum,                   0, 1, 1, 0, 1,  6,      \
400                 NOFF_F | VLAN_F | L3L4CSUM_F)                   \
401 T(noff_vlan_ol3ol4csum,                 0, 1, 1, 1, 0,  6,      \
402                 NOFF_F | VLAN_F | OL3OL4CSUM_F)                 \
403 T(noff_vlan_ol3ol4csum_l3l4csum,        0, 1, 1, 1, 1,  6,      \
404                 NOFF_F | VLAN_F | OL3OL4CSUM_F | L3L4CSUM_F)    \
405 T(ts,                                   1, 0, 0, 0, 0,  8,      \
406                 TSP_F)                                          \
407 T(ts_l3l4csum,                  1, 0, 0, 0, 1,  8,              \
408                 TSP_F | L3L4CSUM_F)                             \
409 T(ts_ol3ol4csum,                        1, 0, 0, 1, 0,  8,      \
410                 TSP_F | OL3OL4CSUM_F)                           \
411 T(ts_ol3ol4csum_l3l4csum,               1, 0, 0, 1, 1,  8,      \
412                 TSP_F | OL3OL4CSUM_F | L3L4CSUM_F)              \
413 T(ts_vlan,                              1, 0, 1, 0, 0,  8,      \
414                 TSP_F | VLAN_F)                                 \
415 T(ts_vlan_l3l4csum,                     1, 0, 1, 0, 1,  8,      \
416                 TSP_F | VLAN_F | L3L4CSUM_F)                    \
417 T(ts_vlan_ol3ol4csum,           1, 0, 1, 1, 0,  8,              \
418                 TSP_F | VLAN_F | OL3OL4CSUM_F)                  \
419 T(ts_vlan_ol3ol4csum_l3l4csum,  1, 0, 1, 1, 1,  8,              \
420                 TSP_F | VLAN_F | OL3OL4CSUM_F | L3L4CSUM_F)     \
421 T(ts_noff,                              1, 1, 0, 0, 0,  8,      \
422                 TSP_F | NOFF_F)                                 \
423 T(ts_noff_l3l4csum,                     1, 1, 0, 0, 1,  8,      \
424                 TSP_F | NOFF_F | L3L4CSUM_F)                    \
425 T(ts_noff_ol3ol4csum,           1, 1, 0, 1, 0,  8,              \
426                 TSP_F | NOFF_F | OL3OL4CSUM_F)                  \
427 T(ts_noff_ol3ol4csum_l3l4csum,  1, 1, 0, 1, 1,  8,              \
428                 TSP_F | NOFF_F | OL3OL4CSUM_F | L3L4CSUM_F)     \
429 T(ts_noff_vlan,                 1, 1, 1, 0, 0,  8,              \
430                 TSP_F | NOFF_F | VLAN_F)                        \
431 T(ts_noff_vlan_l3l4csum,                1, 1, 1, 0, 1,  8,      \
432                 TSP_F | NOFF_F | VLAN_F | L3L4CSUM_F)           \
433 T(ts_noff_vlan_ol3ol4csum,              1, 1, 1, 1, 0,  8,      \
434                 TSP_F | NOFF_F | VLAN_F | OL3OL4CSUM_F)         \
435 T(ts_noff_vlan_ol3ol4csum_l3l4csum,     1, 1, 1, 1, 1,  8,      \
436                 TSP_F | NOFF_F | VLAN_F | OL3OL4CSUM_F | L3L4CSUM_F)
437
438 #endif /* __OTX2_TX_H__ */