88a5152a5efa955e831536ccd2cc5a0c0193ef01
[dpdk.git] / drivers / net / thunderx / nicvf_rxtx.c
1 /*
2  *   BSD LICENSE
3  *
4  *   Copyright (C) Cavium networks Ltd. 2016.
5  *
6  *   Redistribution and use in source and binary forms, with or without
7  *   modification, are permitted provided that the following conditions
8  *   are met:
9  *
10  *     * Redistributions of source code must retain the above copyright
11  *       notice, this list of conditions and the following disclaimer.
12  *     * Redistributions in binary form must reproduce the above copyright
13  *       notice, this list of conditions and the following disclaimer in
14  *       the documentation and/or other materials provided with the
15  *       distribution.
16  *     * Neither the name of Cavium networks nor the names of its
17  *       contributors may be used to endorse or promote products derived
18  *       from this software without specific prior written permission.
19  *
20  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32
33 #include <unistd.h>
34 #include <stdint.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37
38 #include <rte_atomic.h>
39 #include <rte_branch_prediction.h>
40 #include <rte_byteorder.h>
41 #include <rte_common.h>
42 #include <rte_cycles.h>
43 #include <rte_errno.h>
44 #include <rte_ethdev.h>
45 #include <rte_ether.h>
46 #include <rte_log.h>
47 #include <rte_mbuf.h>
48 #include <rte_prefetch.h>
49
50 #include "base/nicvf_plat.h"
51
52 #include "nicvf_ethdev.h"
53 #include "nicvf_rxtx.h"
54 #include "nicvf_logs.h"
55
56 static inline void __hot
57 fill_sq_desc_header(union sq_entry_t *entry, struct rte_mbuf *pkt)
58 {
59         /* Local variable sqe to avoid read from sq desc memory*/
60         union sq_entry_t sqe;
61         uint64_t ol_flags;
62
63         /* Fill SQ header descriptor */
64         sqe.buff[0] = 0;
65         sqe.hdr.subdesc_type = SQ_DESC_TYPE_HEADER;
66         /* Number of sub-descriptors following this one */
67         sqe.hdr.subdesc_cnt = pkt->nb_segs;
68         sqe.hdr.tot_len = pkt->pkt_len;
69
70         ol_flags = pkt->ol_flags & NICVF_TX_OFFLOAD_MASK;
71         if (unlikely(ol_flags)) {
72                 /* L4 cksum */
73                 if (ol_flags & PKT_TX_TCP_CKSUM)
74                         sqe.hdr.csum_l4 = SEND_L4_CSUM_TCP;
75                 else if (ol_flags & PKT_TX_UDP_CKSUM)
76                         sqe.hdr.csum_l4 = SEND_L4_CSUM_UDP;
77                 else
78                         sqe.hdr.csum_l4 = SEND_L4_CSUM_DISABLE;
79                 sqe.hdr.l4_offset = pkt->l3_len + pkt->l2_len;
80
81                 /* L3 cksum */
82                 if (ol_flags & PKT_TX_IP_CKSUM) {
83                         sqe.hdr.csum_l3 = 1;
84                         sqe.hdr.l3_offset = pkt->l2_len;
85                 }
86         }
87
88         entry->buff[0] = sqe.buff[0];
89 }
90
91 void __hot
92 nicvf_single_pool_free_xmited_buffers(struct nicvf_txq *sq)
93 {
94         int j = 0;
95         uint32_t curr_head;
96         uint32_t head = sq->head;
97         struct rte_mbuf **txbuffs = sq->txbuffs;
98         void *obj_p[NICVF_MAX_TX_FREE_THRESH] __rte_cache_aligned;
99
100         curr_head = nicvf_addr_read(sq->sq_head) >> 4;
101         while (head != curr_head) {
102                 if (txbuffs[head])
103                         obj_p[j++] = txbuffs[head];
104
105                 head = (head + 1) & sq->qlen_mask;
106         }
107
108         rte_mempool_put_bulk(sq->pool, obj_p, j);
109         sq->head = curr_head;
110         sq->xmit_bufs -= j;
111         NICVF_TX_ASSERT(sq->xmit_bufs >= 0);
112 }
113
114 void __hot
115 nicvf_multi_pool_free_xmited_buffers(struct nicvf_txq *sq)
116 {
117         uint32_t n = 0;
118         uint32_t curr_head;
119         uint32_t head = sq->head;
120         struct rte_mbuf **txbuffs = sq->txbuffs;
121
122         curr_head = nicvf_addr_read(sq->sq_head) >> 4;
123         while (head != curr_head) {
124                 if (txbuffs[head]) {
125                         rte_pktmbuf_free_seg(txbuffs[head]);
126                         n++;
127                 }
128
129                 head = (head + 1) & sq->qlen_mask;
130         }
131
132         sq->head = curr_head;
133         sq->xmit_bufs -= n;
134         NICVF_TX_ASSERT(sq->xmit_bufs >= 0);
135 }
136
137 static inline uint32_t __hot
138 nicvf_free_tx_desc(struct nicvf_txq *sq)
139 {
140         return ((sq->head - sq->tail - 1) & sq->qlen_mask);
141 }
142
143 /* Send Header + Packet */
144 #define TX_DESC_PER_PKT 2
145
146 static inline uint32_t __hot
147 nicvf_free_xmitted_buffers(struct nicvf_txq *sq, struct rte_mbuf **tx_pkts,
148                             uint16_t nb_pkts)
149 {
150         uint32_t free_desc = nicvf_free_tx_desc(sq);
151
152         if (free_desc < nb_pkts * TX_DESC_PER_PKT ||
153                         sq->xmit_bufs > sq->tx_free_thresh) {
154                 if (unlikely(sq->pool == NULL))
155                         sq->pool = tx_pkts[0]->pool;
156
157                 sq->pool_free(sq);
158                 /* Freed now, let see the number of free descs again */
159                 free_desc = nicvf_free_tx_desc(sq);
160         }
161         return free_desc;
162 }
163
164 uint16_t __hot
165 nicvf_xmit_pkts(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkts)
166 {
167         int i;
168         uint32_t free_desc;
169         uint32_t tail;
170         struct nicvf_txq *sq = tx_queue;
171         union sq_entry_t *desc_ptr = sq->desc;
172         struct rte_mbuf **txbuffs = sq->txbuffs;
173         struct rte_mbuf *pkt;
174         uint32_t qlen_mask = sq->qlen_mask;
175
176         tail = sq->tail;
177         free_desc = nicvf_free_xmitted_buffers(sq, tx_pkts, nb_pkts);
178
179         for (i = 0; i < nb_pkts && (int)free_desc >= TX_DESC_PER_PKT; i++) {
180                 pkt = tx_pkts[i];
181
182                 txbuffs[tail] = NULL;
183                 fill_sq_desc_header(desc_ptr + tail, pkt);
184                 tail = (tail + 1) & qlen_mask;
185
186                 txbuffs[tail] = pkt;
187                 fill_sq_desc_gather(desc_ptr + tail, pkt);
188                 tail = (tail + 1) & qlen_mask;
189                 free_desc -= TX_DESC_PER_PKT;
190         }
191
192         sq->tail = tail;
193         sq->xmit_bufs += i;
194         rte_wmb();
195
196         /* Inform HW to xmit the packets */
197         nicvf_addr_write(sq->sq_door, i * TX_DESC_PER_PKT);
198         return i;
199 }
200
201 uint16_t __hot
202 nicvf_xmit_pkts_multiseg(void *tx_queue, struct rte_mbuf **tx_pkts,
203                          uint16_t nb_pkts)
204 {
205         int i, k;
206         uint32_t used_desc, next_used_desc, used_bufs, free_desc, tail;
207         struct nicvf_txq *sq = tx_queue;
208         union sq_entry_t *desc_ptr = sq->desc;
209         struct rte_mbuf **txbuffs = sq->txbuffs;
210         struct rte_mbuf *pkt, *seg;
211         uint32_t qlen_mask = sq->qlen_mask;
212         uint16_t nb_segs;
213
214         tail = sq->tail;
215         used_desc = 0;
216         used_bufs = 0;
217
218         free_desc = nicvf_free_xmitted_buffers(sq, tx_pkts, nb_pkts);
219
220         for (i = 0; i < nb_pkts; i++) {
221                 pkt = tx_pkts[i];
222
223                 nb_segs = pkt->nb_segs;
224
225                 next_used_desc = used_desc + nb_segs + 1;
226                 if (next_used_desc > free_desc)
227                         break;
228                 used_desc = next_used_desc;
229                 used_bufs += nb_segs;
230
231                 txbuffs[tail] = NULL;
232                 fill_sq_desc_header(desc_ptr + tail, pkt);
233                 tail = (tail + 1) & qlen_mask;
234
235                 txbuffs[tail] = pkt;
236                 fill_sq_desc_gather(desc_ptr + tail, pkt);
237                 tail = (tail + 1) & qlen_mask;
238
239                 seg = pkt->next;
240                 for (k = 1; k < nb_segs; k++) {
241                         txbuffs[tail] = seg;
242                         fill_sq_desc_gather(desc_ptr + tail, seg);
243                         tail = (tail + 1) & qlen_mask;
244                         seg = seg->next;
245                 }
246         }
247
248         sq->tail = tail;
249         sq->xmit_bufs += used_bufs;
250         rte_wmb();
251
252         /* Inform HW to xmit the packets */
253         nicvf_addr_write(sq->sq_door, used_desc);
254         return nb_pkts;
255 }