Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright(c) 2010-2015 Intel Corporation
3 : : */
4 : :
5 : : #include <sys/queue.h>
6 : :
7 : : #include <stdio.h>
8 : : #include <stdlib.h>
9 : : #include <string.h>
10 : : #include <errno.h>
11 : : #include <stdint.h>
12 : : #include <stdarg.h>
13 : : #include <unistd.h>
14 : : #include <inttypes.h>
15 : :
16 : : #include <rte_byteorder.h>
17 : : #include <rte_common.h>
18 : : #include <rte_cycles.h>
19 : : #include <rte_log.h>
20 : : #include <rte_debug.h>
21 : : #include <rte_interrupts.h>
22 : : #include <rte_pci.h>
23 : : #include <rte_memory.h>
24 : : #include <rte_memzone.h>
25 : : #include <rte_launch.h>
26 : : #include <rte_eal.h>
27 : : #include <rte_per_lcore.h>
28 : : #include <rte_lcore.h>
29 : : #include <rte_atomic.h>
30 : : #include <rte_branch_prediction.h>
31 : : #include <rte_mempool.h>
32 : : #include <rte_malloc.h>
33 : : #include <rte_mbuf.h>
34 : : #include <rte_ether.h>
35 : : #include <ethdev_driver.h>
36 : : #include <rte_prefetch.h>
37 : : #include <rte_ip.h>
38 : : #include <rte_udp.h>
39 : : #include <rte_tcp.h>
40 : : #include <rte_sctp.h>
41 : : #include <rte_string_fns.h>
42 : : #include <rte_errno.h>
43 : : #include <rte_net.h>
44 : :
45 : : #include "base/vmxnet3_defs.h"
46 : : #include "vmxnet3_ring.h"
47 : :
48 : : #include "vmxnet3_logs.h"
49 : : #include "vmxnet3_ethdev.h"
50 : :
51 : : #define VMXNET3_TX_OFFLOAD_MASK (RTE_MBUF_F_TX_VLAN | \
52 : : RTE_MBUF_F_TX_IPV6 | \
53 : : RTE_MBUF_F_TX_IPV4 | \
54 : : RTE_MBUF_F_TX_L4_MASK | \
55 : : RTE_MBUF_F_TX_TCP_SEG)
56 : :
57 : : #define VMXNET3_TX_OFFLOAD_NOTSUP_MASK \
58 : : (RTE_MBUF_F_TX_OFFLOAD_MASK ^ VMXNET3_TX_OFFLOAD_MASK)
59 : :
60 : : static int vmxnet3_post_rx_bufs(vmxnet3_rx_queue_t*, uint8_t);
61 : : static void vmxnet3_tq_tx_complete(vmxnet3_tx_queue_t *);
62 : :
63 : : static void
64 : 0 : vmxnet3_tx_cmd_ring_release_mbufs(vmxnet3_cmd_ring_t *ring)
65 : : {
66 [ # # ]: 0 : while (ring->next2comp != ring->next2fill) {
67 : : /* No need to worry about desc ownership, device is quiesced by now. */
68 : 0 : vmxnet3_buf_info_t *buf_info = ring->buf_info + ring->next2comp;
69 : :
70 [ # # ]: 0 : if (buf_info->m) {
71 : 0 : rte_pktmbuf_free(buf_info->m);
72 : 0 : buf_info->m = NULL;
73 : 0 : buf_info->bufPA = 0;
74 : 0 : buf_info->len = 0;
75 : : }
76 : : vmxnet3_cmd_ring_adv_next2comp(ring);
77 : : }
78 : 0 : }
79 : :
80 : : static void
81 : 0 : vmxnet3_rx_cmd_ring_release_mbufs(vmxnet3_cmd_ring_t *ring)
82 : : {
83 : : uint32_t i;
84 : :
85 [ # # ]: 0 : for (i = 0; i < ring->size; i++) {
86 : : /* No need to worry about desc ownership, device is quiesced by now. */
87 : 0 : vmxnet3_buf_info_t *buf_info = &ring->buf_info[i];
88 : :
89 [ # # ]: 0 : if (buf_info->m) {
90 : : rte_pktmbuf_free_seg(buf_info->m);
91 : 0 : buf_info->m = NULL;
92 : 0 : buf_info->bufPA = 0;
93 : 0 : buf_info->len = 0;
94 : : }
95 : : vmxnet3_cmd_ring_adv_next2comp(ring);
96 : : }
97 : 0 : }
98 : :
99 : : static void
100 : : vmxnet3_cmd_ring_release(vmxnet3_cmd_ring_t *ring)
101 : : {
102 : 0 : rte_free(ring->buf_info);
103 : 0 : ring->buf_info = NULL;
104 : : }
105 : :
106 : : void
107 : 0 : vmxnet3_dev_tx_queue_release(struct rte_eth_dev *dev, uint16_t qid)
108 : : {
109 : 0 : vmxnet3_tx_queue_t *tq = dev->data->tx_queues[qid];
110 : :
111 [ # # ]: 0 : if (tq != NULL) {
112 : : /* Release mbufs */
113 : 0 : vmxnet3_tx_cmd_ring_release_mbufs(&tq->cmd_ring);
114 : : /* Release the cmd_ring */
115 : : vmxnet3_cmd_ring_release(&tq->cmd_ring);
116 : : /* Release the memzone */
117 : 0 : rte_memzone_free(tq->mz);
118 : : /* Release the queue */
119 : 0 : rte_free(tq);
120 : : }
121 : 0 : }
122 : :
123 : : void
124 : 0 : vmxnet3_dev_rx_queue_release(struct rte_eth_dev *dev, uint16_t qid)
125 : : {
126 : : int i;
127 : 0 : vmxnet3_rx_queue_t *rq = dev->data->rx_queues[qid];
128 : :
129 [ # # ]: 0 : if (rq != NULL) {
130 : : /* Release mbufs */
131 [ # # ]: 0 : for (i = 0; i < VMXNET3_RX_CMDRING_SIZE; i++)
132 : 0 : vmxnet3_rx_cmd_ring_release_mbufs(&rq->cmd_ring[i]);
133 : :
134 : : /* Release both the cmd_rings */
135 [ # # ]: 0 : for (i = 0; i < VMXNET3_RX_CMDRING_SIZE; i++)
136 : : vmxnet3_cmd_ring_release(&rq->cmd_ring[i]);
137 : :
138 : : /* Release the memzone */
139 : 0 : rte_memzone_free(rq->mz);
140 : :
141 : : /* Release the queue */
142 : 0 : rte_free(rq);
143 : : }
144 : 0 : }
145 : :
146 : : static void
147 : 0 : vmxnet3_dev_tx_queue_reset(void *txq)
148 : : {
149 : : vmxnet3_tx_queue_t *tq = txq;
150 : 0 : struct vmxnet3_cmd_ring *ring = &tq->cmd_ring;
151 : : struct vmxnet3_comp_ring *comp_ring = &tq->comp_ring;
152 : : struct vmxnet3_data_ring *data_ring = &tq->data_ring;
153 : : int size;
154 : :
155 [ # # ]: 0 : if (tq != NULL) {
156 : : /* Release the cmd_ring mbufs */
157 : 0 : vmxnet3_tx_cmd_ring_release_mbufs(&tq->cmd_ring);
158 : : }
159 : :
160 : : /* Tx vmxnet rings structure initialization*/
161 : 0 : ring->next2fill = 0;
162 : 0 : ring->next2comp = 0;
163 : 0 : ring->gen = VMXNET3_INIT_GEN;
164 : 0 : comp_ring->next2proc = 0;
165 : 0 : comp_ring->gen = VMXNET3_INIT_GEN;
166 : :
167 : 0 : size = sizeof(struct Vmxnet3_TxDesc) * ring->size;
168 : 0 : size += sizeof(struct Vmxnet3_TxCompDesc) * comp_ring->size;
169 : 0 : size += tq->txdata_desc_size * data_ring->size;
170 : :
171 : 0 : memset(ring->base, 0, size);
172 : 0 : }
173 : :
174 : : static void
175 : 0 : vmxnet3_dev_rx_queue_reset(void *rxq)
176 : : {
177 : : int i;
178 : : vmxnet3_rx_queue_t *rq = rxq;
179 : 0 : struct vmxnet3_hw *hw = rq->hw;
180 : : struct vmxnet3_cmd_ring *ring0, *ring1;
181 : : struct vmxnet3_comp_ring *comp_ring;
182 : : struct vmxnet3_rx_data_ring *data_ring = &rq->data_ring;
183 : : int size;
184 : :
185 : : /* Release both the cmd_rings mbufs */
186 [ # # ]: 0 : for (i = 0; i < VMXNET3_RX_CMDRING_SIZE; i++)
187 : 0 : vmxnet3_rx_cmd_ring_release_mbufs(&rq->cmd_ring[i]);
188 : :
189 : : ring0 = &rq->cmd_ring[0];
190 : : ring1 = &rq->cmd_ring[1];
191 : : comp_ring = &rq->comp_ring;
192 : :
193 : : /* Rx vmxnet rings structure initialization */
194 : 0 : ring0->next2fill = 0;
195 : 0 : ring1->next2fill = 0;
196 : 0 : ring0->next2comp = 0;
197 : 0 : ring1->next2comp = 0;
198 : 0 : ring0->gen = VMXNET3_INIT_GEN;
199 : 0 : ring1->gen = VMXNET3_INIT_GEN;
200 : 0 : comp_ring->next2proc = 0;
201 : 0 : comp_ring->gen = VMXNET3_INIT_GEN;
202 : :
203 : 0 : size = sizeof(struct Vmxnet3_RxDesc) * (ring0->size + ring1->size);
204 : 0 : size += sizeof(struct Vmxnet3_RxCompDesc) * comp_ring->size;
205 [ # # # # ]: 0 : if (VMXNET3_VERSION_GE_3(hw) && rq->data_desc_size)
206 : 0 : size += rq->data_desc_size * data_ring->size;
207 : :
208 : 0 : memset(ring0->base, 0, size);
209 : 0 : }
210 : :
211 : : void
212 : 0 : vmxnet3_dev_clear_queues(struct rte_eth_dev *dev)
213 : : {
214 : : unsigned i;
215 : :
216 : 0 : PMD_INIT_FUNC_TRACE();
217 : :
218 [ # # ]: 0 : for (i = 0; i < dev->data->nb_tx_queues; i++) {
219 : 0 : struct vmxnet3_tx_queue *txq = dev->data->tx_queues[i];
220 : :
221 [ # # ]: 0 : if (txq != NULL) {
222 : 0 : txq->stopped = TRUE;
223 : 0 : vmxnet3_dev_tx_queue_reset(txq);
224 : : }
225 : : }
226 : :
227 [ # # ]: 0 : for (i = 0; i < dev->data->nb_rx_queues; i++) {
228 : 0 : struct vmxnet3_rx_queue *rxq = dev->data->rx_queues[i];
229 : :
230 [ # # ]: 0 : if (rxq != NULL) {
231 : 0 : rxq->stopped = TRUE;
232 : 0 : vmxnet3_dev_rx_queue_reset(rxq);
233 : : }
234 : : }
235 : 0 : }
236 : :
237 : : static int
238 : 0 : vmxnet3_unmap_pkt(uint16_t eop_idx, vmxnet3_tx_queue_t *txq)
239 : : {
240 : : int completed = 0;
241 : : struct rte_mbuf *mbuf;
242 : :
243 : : /* Release cmd_ring descriptor and free mbuf */
244 : : RTE_ASSERT(txq->cmd_ring.base[eop_idx].txd.eop == 1);
245 : :
246 : 0 : mbuf = txq->cmd_ring.buf_info[eop_idx].m;
247 [ # # ]: 0 : if (mbuf == NULL)
248 : 0 : rte_panic("EOP desc does not point to a valid mbuf");
249 : 0 : rte_pktmbuf_free(mbuf);
250 : :
251 : 0 : txq->cmd_ring.buf_info[eop_idx].m = NULL;
252 : :
253 [ # # ]: 0 : while (txq->cmd_ring.next2comp != eop_idx) {
254 : : /* no out-of-order completion */
255 : : RTE_ASSERT(txq->cmd_ring.base[txq->cmd_ring.next2comp].txd.cq == 0);
256 : : vmxnet3_cmd_ring_adv_next2comp(&txq->cmd_ring);
257 : 0 : completed++;
258 : : }
259 : :
260 : : /* Mark the txd for which tcd was generated as completed */
261 : : vmxnet3_cmd_ring_adv_next2comp(&txq->cmd_ring);
262 : :
263 : 0 : return completed + 1;
264 : : }
265 : :
266 : : static void
267 : 0 : vmxnet3_tq_tx_complete(vmxnet3_tx_queue_t *txq)
268 : : {
269 : : int completed = 0;
270 : : vmxnet3_comp_ring_t *comp_ring = &txq->comp_ring;
271 : 0 : struct Vmxnet3_TxCompDesc *tcd = (struct Vmxnet3_TxCompDesc *)
272 : 0 : (comp_ring->base + comp_ring->next2proc);
273 : :
274 [ # # ]: 0 : while (tcd->gen == comp_ring->gen) {
275 : 0 : completed += vmxnet3_unmap_pkt(tcd->txdIdx, txq);
276 : :
277 : : vmxnet3_comp_ring_adv_next2proc(comp_ring);
278 : 0 : tcd = (struct Vmxnet3_TxCompDesc *)(comp_ring->base +
279 : 0 : comp_ring->next2proc);
280 : : }
281 : :
282 : : PMD_TX_LOG(DEBUG, "Processed %d tx comps & command descs.", completed);
283 : :
284 : : /* To avoid compiler warnings when not in DEBUG mode. */
285 : : RTE_SET_USED(completed);
286 : 0 : }
287 : :
288 : : uint16_t
289 : 0 : vmxnet3_prep_pkts(__rte_unused void *tx_queue, struct rte_mbuf **tx_pkts,
290 : : uint16_t nb_pkts)
291 : : {
292 : : int32_t ret;
293 : : uint32_t i;
294 : : uint64_t ol_flags;
295 : : struct rte_mbuf *m;
296 : :
297 [ # # ]: 0 : for (i = 0; i != nb_pkts; i++) {
298 : 0 : m = tx_pkts[i];
299 : 0 : ol_flags = m->ol_flags;
300 : :
301 : : /* Non-TSO packet cannot occupy more than
302 : : * VMXNET3_MAX_TXD_PER_PKT TX descriptors.
303 : : */
304 [ # # ]: 0 : if ((ol_flags & RTE_MBUF_F_TX_TCP_SEG) == 0 &&
305 [ # # ]: 0 : m->nb_segs > VMXNET3_MAX_TXD_PER_PKT) {
306 : 0 : rte_errno = EINVAL;
307 : 0 : return i;
308 : : }
309 : : /* TSO packet cannot occupy more than
310 : : * VMXNET3_MAX_TSO_TXD_PER_PKT TX descriptors.
311 : : */
312 [ # # ]: 0 : if ((ol_flags & RTE_MBUF_F_TX_TCP_SEG) != 0 &&
313 [ # # ]: 0 : m->nb_segs > VMXNET3_MAX_TSO_TXD_PER_PKT) {
314 : 0 : rte_errno = EINVAL;
315 : 0 : return i;
316 : : }
317 : :
318 : : /* check that only supported TX offloads are requested. */
319 [ # # ]: 0 : if ((ol_flags & VMXNET3_TX_OFFLOAD_NOTSUP_MASK) != 0 ||
320 [ # # ]: 0 : (ol_flags & RTE_MBUF_F_TX_L4_MASK) ==
321 : : RTE_MBUF_F_TX_SCTP_CKSUM) {
322 : 0 : rte_errno = ENOTSUP;
323 : 0 : return i;
324 : : }
325 : :
326 : : #ifdef RTE_LIBRTE_ETHDEV_DEBUG
327 : : ret = rte_validate_tx_offload(m);
328 : : if (ret != 0) {
329 : : rte_errno = -ret;
330 : : return i;
331 : : }
332 : : #endif
333 : : ret = rte_net_intel_cksum_prepare(m);
334 [ # # ]: 0 : if (ret != 0) {
335 : 0 : rte_errno = -ret;
336 : 0 : return i;
337 : : }
338 : : }
339 : :
340 : 0 : return i;
341 : : }
342 : :
343 : : uint16_t
344 : 0 : vmxnet3_xmit_pkts(void *tx_queue, struct rte_mbuf **tx_pkts,
345 : : uint16_t nb_pkts)
346 : : {
347 : : uint16_t nb_tx;
348 : : vmxnet3_tx_queue_t *txq = tx_queue;
349 : 0 : struct vmxnet3_hw *hw = txq->hw;
350 : 0 : Vmxnet3_TxQueueCtrl *txq_ctrl = &txq->shared->ctrl;
351 : 0 : uint32_t deferred = rte_le_to_cpu_32(txq_ctrl->txNumDeferred);
352 : :
353 [ # # ]: 0 : if (unlikely(txq->stopped)) {
354 : : PMD_TX_LOG(DEBUG, "Tx queue is stopped.");
355 : : return 0;
356 : : }
357 : :
358 : : /* Free up the comp_descriptors aggressively */
359 : 0 : vmxnet3_tq_tx_complete(txq);
360 : :
361 : : nb_tx = 0;
362 [ # # ]: 0 : while (nb_tx < nb_pkts) {
363 : : Vmxnet3_GenericDesc *gdesc = NULL;
364 : : vmxnet3_buf_info_t *tbi = NULL;
365 : : uint32_t first2fill, avail, dw2;
366 : 0 : struct rte_mbuf *txm = tx_pkts[nb_tx];
367 : : struct rte_mbuf *m_seg = txm;
368 : : int copy_size = 0;
369 : 0 : bool tso = (txm->ol_flags & RTE_MBUF_F_TX_TCP_SEG) != 0;
370 : : /* # of descriptors needed for a packet. */
371 [ # # ]: 0 : unsigned count = txm->nb_segs;
372 : :
373 : : avail = vmxnet3_cmd_ring_desc_avail(&txq->cmd_ring);
374 [ # # ]: 0 : if (count > avail) {
375 : : /* Is command ring full? */
376 [ # # ]: 0 : if (unlikely(avail == 0)) {
377 : : PMD_TX_LOG(DEBUG, "No free ring descriptors");
378 : 0 : txq->stats.tx_ring_full++;
379 : 0 : txq->stats.drop_total += (nb_pkts - nb_tx);
380 : 0 : break;
381 : : }
382 : :
383 : : /* Command ring is not full but cannot handle the
384 : : * multi-segmented packet. Let's try the next packet
385 : : * in this case.
386 : : */
387 : : PMD_TX_LOG(DEBUG, "Running out of ring descriptors "
388 : : "(avail %d needed %d)", avail, count);
389 : 0 : txq->stats.drop_total++;
390 [ # # ]: 0 : if (tso)
391 : 0 : txq->stats.drop_tso++;
392 : 0 : rte_pktmbuf_free(txm);
393 : 0 : nb_tx++;
394 : 0 : continue;
395 : : }
396 : :
397 : : /* Drop non-TSO or TSO packet that is excessively fragmented */
398 [ # # # # ]: 0 : if (unlikely((!tso && count > VMXNET3_MAX_TXD_PER_PKT) ||
399 : : (tso && count > VMXNET3_MAX_TSO_TXD_PER_PKT))) {
400 : : PMD_TX_LOG(ERR, "Non-TSO or TSO packet cannot occupy more than "
401 : : "%d or %d tx descriptors respectively. Packet dropped.",
402 : : VMXNET3_MAX_TXD_PER_PKT, VMXNET3_MAX_TSO_TXD_PER_PKT);
403 : 0 : txq->stats.drop_too_many_segs++;
404 : 0 : txq->stats.drop_total++;
405 : 0 : rte_pktmbuf_free(txm);
406 : 0 : nb_tx++;
407 : 0 : continue;
408 : : }
409 : :
410 : : /* Skip empty packets */
411 [ # # ]: 0 : if (unlikely(rte_pktmbuf_pkt_len(txm) == 0)) {
412 : 0 : txq->stats.drop_total++;
413 : 0 : rte_pktmbuf_free(txm);
414 : 0 : nb_tx++;
415 : 0 : continue;
416 : : }
417 : :
418 [ # # ]: 0 : if (txm->nb_segs == 1 &&
419 [ # # ]: 0 : rte_pktmbuf_pkt_len(txm) <= txq->txdata_desc_size) {
420 : : struct Vmxnet3_TxDataDesc *tdd;
421 : :
422 : 0 : tdd = (struct Vmxnet3_TxDataDesc *)
423 : 0 : ((uint8 *)txq->data_ring.base +
424 : 0 : txq->cmd_ring.next2fill *
425 : : txq->txdata_desc_size);
426 : 0 : copy_size = rte_pktmbuf_pkt_len(txm);
427 [ # # ]: 0 : rte_memcpy(tdd->data, rte_pktmbuf_mtod(txm, char *), copy_size);
428 : : }
429 : :
430 : : /* use the previous gen bit for the SOP desc */
431 : 0 : dw2 = (txq->cmd_ring.gen ^ 0x1) << VMXNET3_TXD_GEN_SHIFT;
432 : 0 : first2fill = txq->cmd_ring.next2fill;
433 : : do {
434 : : /* Skip empty segments */
435 [ # # ]: 0 : if (unlikely(m_seg->data_len == 0))
436 : 0 : continue;
437 : :
438 : : /* Remember the transmit buffer for cleanup */
439 : 0 : tbi = txq->cmd_ring.buf_info + txq->cmd_ring.next2fill;
440 : :
441 : : /* NB: the following assumes that VMXNET3 maximum
442 : : * transmit buffer size (16K) is greater than
443 : : * maximum size of mbuf segment size.
444 : : */
445 : 0 : gdesc = txq->cmd_ring.base + txq->cmd_ring.next2fill;
446 : :
447 [ # # ]: 0 : if (copy_size) {
448 : 0 : uint64 offset =
449 : : (uint64)txq->cmd_ring.next2fill *
450 : 0 : txq->txdata_desc_size;
451 : 0 : gdesc->txd.addr =
452 : 0 : rte_cpu_to_le_64(txq->data_ring.basePA +
453 : : offset);
454 : : } else {
455 : 0 : gdesc->txd.addr = rte_mbuf_data_iova(m_seg);
456 : : }
457 : :
458 : 0 : gdesc->dword[2] = dw2 | m_seg->data_len;
459 [ # # ]: 0 : gdesc->dword[3] = 0;
460 : :
461 : : /* move to the next2fill descriptor */
462 : : vmxnet3_cmd_ring_adv_next2fill(&txq->cmd_ring);
463 : :
464 : : /* use the right gen for non-SOP desc */
465 : 0 : dw2 = txq->cmd_ring.gen << VMXNET3_TXD_GEN_SHIFT;
466 [ # # ]: 0 : } while ((m_seg = m_seg->next) != NULL);
467 : : /* We must have executed the complete preceding loop at least
468 : : * once without skipping an empty segment, as we can't have
469 : : * a packet with only empty segments.
470 : : * Thus, tbi and gdesc have been initialized.
471 : : */
472 : :
473 : : /* set the last buf_info for the pkt */
474 : 0 : tbi->m = txm;
475 : : /* Update the EOP descriptor */
476 : 0 : gdesc->dword[3] |= VMXNET3_TXD_EOP | VMXNET3_TXD_CQ;
477 : :
478 : : /* Add VLAN tag if present */
479 : 0 : gdesc = txq->cmd_ring.base + first2fill;
480 [ # # ]: 0 : if (txm->ol_flags & RTE_MBUF_F_TX_VLAN) {
481 : 0 : gdesc->txd.ti = 1;
482 : 0 : gdesc->txd.tci = txm->vlan_tci;
483 : : }
484 : :
485 [ # # ]: 0 : if (tso) {
486 : 0 : uint16_t mss = txm->tso_segsz;
487 : :
488 : : RTE_ASSERT(mss > 0);
489 : :
490 : 0 : gdesc->txd.hlen = txm->l2_len + txm->l3_len + txm->l4_len;
491 : 0 : gdesc->txd.om = VMXNET3_OM_TSO;
492 : 0 : gdesc->txd.msscof = mss;
493 : :
494 : 0 : deferred += (rte_pktmbuf_pkt_len(txm) - gdesc->txd.hlen + mss - 1) / mss;
495 [ # # ]: 0 : } else if (txm->ol_flags & RTE_MBUF_F_TX_L4_MASK) {
496 : 0 : gdesc->txd.om = VMXNET3_OM_CSUM;
497 : 0 : gdesc->txd.hlen = txm->l2_len + txm->l3_len;
498 : :
499 [ # # # ]: 0 : switch (txm->ol_flags & RTE_MBUF_F_TX_L4_MASK) {
500 : 0 : case RTE_MBUF_F_TX_TCP_CKSUM:
501 : 0 : gdesc->txd.msscof = gdesc->txd.hlen +
502 : : offsetof(struct rte_tcp_hdr, cksum);
503 : 0 : break;
504 : 0 : case RTE_MBUF_F_TX_UDP_CKSUM:
505 : 0 : gdesc->txd.msscof = gdesc->txd.hlen +
506 : : offsetof(struct rte_udp_hdr,
507 : : dgram_cksum);
508 : 0 : break;
509 : 0 : default:
510 : : PMD_TX_LOG(WARNING, "requested cksum offload not supported %#llx",
511 : : txm->ol_flags & RTE_MBUF_F_TX_L4_MASK);
512 : 0 : abort();
513 : : }
514 : 0 : deferred++;
515 : : } else {
516 : 0 : gdesc->txd.hlen = 0;
517 : 0 : gdesc->txd.om = VMXNET3_OM_NONE;
518 : 0 : gdesc->txd.msscof = 0;
519 : 0 : deferred++;
520 : : }
521 : :
522 : : /* flip the GEN bit on the SOP */
523 : 0 : rte_compiler_barrier();
524 : 0 : gdesc->dword[2] ^= VMXNET3_TXD_GEN;
525 : :
526 : 0 : txq_ctrl->txNumDeferred = rte_cpu_to_le_32(deferred);
527 : 0 : nb_tx++;
528 : : }
529 : :
530 : : PMD_TX_LOG(DEBUG, "vmxnet3 txThreshold: %u", rte_le_to_cpu_32(txq_ctrl->txThreshold));
531 : :
532 [ # # ]: 0 : if (deferred >= rte_le_to_cpu_32(txq_ctrl->txThreshold)) {
533 : 0 : txq_ctrl->txNumDeferred = 0;
534 : : /* Notify vSwitch that packets are available. */
535 : 0 : VMXNET3_WRITE_BAR0_REG(hw, (hw->tx_prod_offset + txq->queue_id * VMXNET3_REG_ALIGN),
536 : : txq->cmd_ring.next2fill);
537 : : }
538 : :
539 : : return nb_tx;
540 : : }
541 : :
542 : : static inline void
543 : 0 : vmxnet3_renew_desc(vmxnet3_rx_queue_t *rxq, uint8_t ring_id,
544 : : struct rte_mbuf *mbuf)
545 : : {
546 : : uint32_t val;
547 : 0 : struct vmxnet3_cmd_ring *ring = &rxq->cmd_ring[ring_id];
548 : 0 : struct Vmxnet3_RxDesc *rxd =
549 : 0 : (struct Vmxnet3_RxDesc *)(ring->base + ring->next2fill);
550 : 0 : vmxnet3_buf_info_t *buf_info = &ring->buf_info[ring->next2fill];
551 : :
552 [ # # ]: 0 : if (ring_id == 0) {
553 : : /* Usually: One HEAD type buf per packet
554 : : * val = (ring->next2fill % rxq->hw->bufs_per_pkt) ?
555 : : * VMXNET3_RXD_BTYPE_BODY : VMXNET3_RXD_BTYPE_HEAD;
556 : : */
557 : :
558 : : /* We use single packet buffer so all heads here */
559 : : val = VMXNET3_RXD_BTYPE_HEAD;
560 : : } else {
561 : : /* All BODY type buffers for 2nd ring */
562 : : val = VMXNET3_RXD_BTYPE_BODY;
563 : : }
564 : :
565 : : /*
566 : : * Load mbuf pointer into buf_info[ring_size]
567 : : * buf_info structure is equivalent to cookie for virtio-virtqueue
568 : : */
569 : 0 : buf_info->m = mbuf;
570 [ # # ]: 0 : buf_info->len = (uint16_t)(mbuf->buf_len - RTE_PKTMBUF_HEADROOM);
571 : 0 : buf_info->bufPA = rte_mbuf_data_iova_default(mbuf);
572 : :
573 : : /* Load Rx Descriptor with the buffer's GPA */
574 : 0 : rxd->addr = buf_info->bufPA;
575 : :
576 : : /* After this point rxd->addr MUST not be NULL */
577 : 0 : rxd->btype = val;
578 : 0 : rxd->len = buf_info->len;
579 : : /* Flip gen bit at the end to change ownership */
580 [ # # ]: 0 : rxd->gen = ring->gen;
581 : :
582 : : vmxnet3_cmd_ring_adv_next2fill(ring);
583 : 0 : }
584 : : /*
585 : : * Allocates mbufs and clusters. Post rx descriptors with buffer details
586 : : * so that device can receive packets in those buffers.
587 : : * Ring layout:
588 : : * Among the two rings, 1st ring contains buffers of type 0 and type 1.
589 : : * bufs_per_pkt is set such that for non-LRO cases all the buffers required
590 : : * by a frame will fit in 1st ring (1st buf of type0 and rest of type1).
591 : : * 2nd ring contains buffers of type 1 alone. Second ring mostly be used
592 : : * only for LRO.
593 : : */
594 : : static int
595 : 0 : vmxnet3_post_rx_bufs(vmxnet3_rx_queue_t *rxq, uint8_t ring_id)
596 : : {
597 : : int err = 0;
598 : : uint32_t i = 0;
599 : 0 : struct vmxnet3_cmd_ring *ring = &rxq->cmd_ring[ring_id];
600 : :
601 [ # # ]: 0 : while (vmxnet3_cmd_ring_desc_avail(ring) > 0) {
602 : : struct rte_mbuf *mbuf;
603 : :
604 : : /* Allocate blank mbuf for the current Rx Descriptor */
605 : 0 : mbuf = rte_mbuf_raw_alloc(rxq->mp);
606 [ # # ]: 0 : if (unlikely(mbuf == NULL)) {
607 : : PMD_RX_LOG(ERR, "Error allocating mbuf");
608 : 0 : rxq->stats.rx_buf_alloc_failure++;
609 : : err = ENOMEM;
610 : 0 : break;
611 : : }
612 : :
613 : 0 : vmxnet3_renew_desc(rxq, ring_id, mbuf);
614 : 0 : i++;
615 : : }
616 : :
617 : : /* Return error only if no buffers are posted at present */
618 [ # # ]: 0 : if (vmxnet3_cmd_ring_desc_avail(ring) >= (ring->size - 1))
619 : 0 : return -err;
620 : : else
621 : 0 : return i;
622 : : }
623 : :
624 : : /* MSS not provided by vmxnet3, guess one with available information */
625 : : static uint16_t
626 : 0 : vmxnet3_guess_mss(struct vmxnet3_hw *hw, const Vmxnet3_RxCompDesc *rcd,
627 : : struct rte_mbuf *rxm)
628 : : {
629 : : uint32_t hlen, slen;
630 : : struct rte_ipv4_hdr *ipv4_hdr;
631 : : struct rte_ipv6_hdr *ipv6_hdr;
632 : : struct rte_tcp_hdr *tcp_hdr;
633 : : char *ptr;
634 : : uint8_t segs;
635 : :
636 : : RTE_ASSERT(rcd->tcp);
637 : :
638 : 0 : ptr = rte_pktmbuf_mtod(rxm, char *);
639 : 0 : slen = rte_pktmbuf_data_len(rxm);
640 : 0 : hlen = sizeof(struct rte_ether_hdr);
641 : :
642 [ # # ]: 0 : if (rcd->v4) {
643 [ # # ]: 0 : if (unlikely(slen < hlen + sizeof(struct rte_ipv4_hdr)))
644 : 0 : return hw->mtu - sizeof(struct rte_ipv4_hdr)
645 : 0 : - sizeof(struct rte_tcp_hdr);
646 : :
647 : 0 : ipv4_hdr = (struct rte_ipv4_hdr *)(ptr + hlen);
648 : 0 : hlen += rte_ipv4_hdr_len(ipv4_hdr);
649 [ # # ]: 0 : } else if (rcd->v6) {
650 [ # # ]: 0 : if (unlikely(slen < hlen + sizeof(struct rte_ipv6_hdr)))
651 : 0 : return hw->mtu - sizeof(struct rte_ipv6_hdr) -
652 : : sizeof(struct rte_tcp_hdr);
653 : :
654 : 0 : ipv6_hdr = (struct rte_ipv6_hdr *)(ptr + hlen);
655 : 0 : hlen += sizeof(struct rte_ipv6_hdr);
656 [ # # ]: 0 : if (unlikely(ipv6_hdr->proto != IPPROTO_TCP)) {
657 : : int frag;
658 : :
659 : 0 : rte_net_skip_ip6_ext(ipv6_hdr->proto, rxm,
660 : : &hlen, &frag);
661 : : }
662 : : }
663 : :
664 [ # # ]: 0 : if (unlikely(slen < hlen + sizeof(struct rte_tcp_hdr)))
665 : 0 : return hw->mtu - hlen - sizeof(struct rte_tcp_hdr) +
666 : : sizeof(struct rte_ether_hdr);
667 : :
668 : 0 : tcp_hdr = (struct rte_tcp_hdr *)(ptr + hlen);
669 [ # # ]: 0 : hlen += (tcp_hdr->data_off & 0xf0) >> 2;
670 : :
671 : 0 : segs = *vmxnet3_segs_dynfield(rxm);
672 [ # # ]: 0 : if (segs > 1)
673 : 0 : return (rte_pktmbuf_pkt_len(rxm) - hlen + segs - 1) / segs;
674 : : else
675 : 0 : return hw->mtu - hlen + sizeof(struct rte_ether_hdr);
676 : : }
677 : :
678 : : /* Receive side checksum and other offloads */
679 : : static inline void
680 : 0 : vmxnet3_rx_offload(struct vmxnet3_hw *hw, const Vmxnet3_RxCompDesc *rcd,
681 : : struct rte_mbuf *rxm, const uint8_t sop)
682 : : {
683 : 0 : uint64_t ol_flags = rxm->ol_flags;
684 : 0 : uint32_t packet_type = rxm->packet_type;
685 : :
686 : : /* Offloads set in sop */
687 [ # # ]: 0 : if (sop) {
688 : : /* Set packet type */
689 : 0 : packet_type |= RTE_PTYPE_L2_ETHER;
690 : :
691 : : /* Check large packet receive */
692 [ # # ]: 0 : if (VMXNET3_VERSION_GE_2(hw) &&
693 [ # # ]: 0 : rcd->type == VMXNET3_CDTYPE_RXCOMP_LRO) {
694 : : const Vmxnet3_RxCompDescExt *rcde =
695 : : (const Vmxnet3_RxCompDescExt *)rcd;
696 : :
697 : 0 : rxm->tso_segsz = rcde->mss;
698 : 0 : *vmxnet3_segs_dynfield(rxm) = rcde->segCnt;
699 : 0 : ol_flags |= RTE_MBUF_F_RX_LRO;
700 : : }
701 : : } else { /* Offloads set in eop */
702 : : /* Check for RSS */
703 [ # # ]: 0 : if (rcd->rssType != VMXNET3_RCD_RSS_TYPE_NONE) {
704 : 0 : ol_flags |= RTE_MBUF_F_RX_RSS_HASH;
705 : 0 : rxm->hash.rss = rcd->rssHash;
706 : : }
707 : :
708 : : /* Check for hardware stripped VLAN tag */
709 [ # # ]: 0 : if (rcd->ts) {
710 : 0 : ol_flags |= (RTE_MBUF_F_RX_VLAN | RTE_MBUF_F_RX_VLAN_STRIPPED);
711 : 0 : rxm->vlan_tci = rte_le_to_cpu_16((uint16_t)rcd->tci);
712 : : }
713 : :
714 : : /* Check packet type, checksum errors, etc. */
715 [ # # ]: 0 : if (rcd->cnc) {
716 : : ol_flags |= RTE_MBUF_F_RX_L4_CKSUM_UNKNOWN;
717 : :
718 [ # # ]: 0 : if (rcd->v4) {
719 : 0 : packet_type |= RTE_PTYPE_L3_IPV4_EXT_UNKNOWN;
720 [ # # ]: 0 : if (rcd->tcp)
721 : 0 : packet_type |= RTE_PTYPE_L4_TCP;
722 [ # # ]: 0 : else if (rcd->udp)
723 : 0 : packet_type |= RTE_PTYPE_L4_UDP;
724 [ # # ]: 0 : } else if (rcd->v6) {
725 : 0 : packet_type |= RTE_PTYPE_L3_IPV6_EXT_UNKNOWN;
726 [ # # ]: 0 : if (rcd->tcp)
727 : 0 : packet_type |= RTE_PTYPE_L4_TCP;
728 [ # # ]: 0 : else if (rcd->udp)
729 : 0 : packet_type |= RTE_PTYPE_L4_UDP;
730 : : } else {
731 : : packet_type |= RTE_PTYPE_UNKNOWN;
732 : : }
733 : :
734 : : } else {
735 [ # # ]: 0 : if (rcd->v4) {
736 : 0 : packet_type |= RTE_PTYPE_L3_IPV4_EXT_UNKNOWN;
737 : :
738 [ # # ]: 0 : if (rcd->ipc)
739 : 0 : ol_flags |= RTE_MBUF_F_RX_IP_CKSUM_GOOD;
740 : : else
741 : 0 : ol_flags |= RTE_MBUF_F_RX_IP_CKSUM_BAD;
742 : :
743 [ # # ]: 0 : if (rcd->tuc) {
744 : 0 : ol_flags |= RTE_MBUF_F_RX_L4_CKSUM_GOOD;
745 [ # # ]: 0 : if (rcd->tcp)
746 : 0 : packet_type |= RTE_PTYPE_L4_TCP;
747 : : else
748 : 0 : packet_type |= RTE_PTYPE_L4_UDP;
749 : : } else {
750 [ # # ]: 0 : if (rcd->tcp) {
751 : 0 : packet_type |= RTE_PTYPE_L4_TCP;
752 : 0 : ol_flags |= RTE_MBUF_F_RX_L4_CKSUM_BAD;
753 [ # # ]: 0 : } else if (rcd->udp) {
754 : 0 : packet_type |= RTE_PTYPE_L4_UDP;
755 : 0 : ol_flags |= RTE_MBUF_F_RX_L4_CKSUM_BAD;
756 : : }
757 : : }
758 [ # # ]: 0 : } else if (rcd->v6) {
759 : 0 : packet_type |= RTE_PTYPE_L3_IPV6_EXT_UNKNOWN;
760 : :
761 [ # # ]: 0 : if (rcd->tuc) {
762 : 0 : ol_flags |= RTE_MBUF_F_RX_L4_CKSUM_GOOD;
763 [ # # ]: 0 : if (rcd->tcp)
764 : 0 : packet_type |= RTE_PTYPE_L4_TCP;
765 : : else
766 : 0 : packet_type |= RTE_PTYPE_L4_UDP;
767 : : } else {
768 [ # # ]: 0 : if (rcd->tcp) {
769 : 0 : packet_type |= RTE_PTYPE_L4_TCP;
770 : 0 : ol_flags |= RTE_MBUF_F_RX_L4_CKSUM_BAD;
771 [ # # ]: 0 : } else if (rcd->udp) {
772 : 0 : packet_type |= RTE_PTYPE_L4_UDP;
773 : 0 : ol_flags |= RTE_MBUF_F_RX_L4_CKSUM_BAD;
774 : : }
775 : : }
776 : : } else {
777 : : packet_type |= RTE_PTYPE_UNKNOWN;
778 : : }
779 : :
780 : : /* Old variants of vmxnet3 do not provide MSS */
781 [ # # # # ]: 0 : if ((ol_flags & RTE_MBUF_F_RX_LRO) && rxm->tso_segsz == 0)
782 : 0 : rxm->tso_segsz = vmxnet3_guess_mss(hw,
783 : : rcd, rxm);
784 : : }
785 : : }
786 : :
787 : 0 : rxm->ol_flags = ol_flags;
788 : 0 : rxm->packet_type = packet_type;
789 : 0 : }
790 : :
791 : : /*
792 : : * Process the Rx Completion Ring of given vmxnet3_rx_queue
793 : : * for nb_pkts burst and return the number of packets received
794 : : */
795 : : uint16_t
796 : 0 : vmxnet3_recv_pkts(void *rx_queue, struct rte_mbuf **rx_pkts, uint16_t nb_pkts)
797 : : {
798 : : uint16_t nb_rx;
799 : : uint32_t nb_rxd, idx;
800 : : uint8_t ring_idx;
801 : : vmxnet3_rx_queue_t *rxq;
802 : : Vmxnet3_RxCompDesc *rcd;
803 : : vmxnet3_buf_info_t *rbi;
804 : : Vmxnet3_RxDesc *rxd;
805 : : struct rte_mbuf *rxm = NULL;
806 : : struct vmxnet3_hw *hw;
807 : :
808 : : nb_rx = 0;
809 : : ring_idx = 0;
810 : : nb_rxd = 0;
811 : : idx = 0;
812 : :
813 : : rxq = rx_queue;
814 : 0 : hw = rxq->hw;
815 : :
816 : 0 : rcd = &rxq->comp_ring.base[rxq->comp_ring.next2proc].rcd;
817 : :
818 [ # # ]: 0 : if (unlikely(rxq->stopped)) {
819 : : PMD_RX_LOG(DEBUG, "Rx queue is stopped.");
820 : : return 0;
821 : : }
822 : :
823 [ # # ]: 0 : while (rcd->gen == rxq->comp_ring.gen) {
824 : : struct rte_mbuf *newm;
825 : :
826 [ # # ]: 0 : if (nb_rx >= nb_pkts)
827 : : break;
828 : :
829 : 0 : newm = rte_mbuf_raw_alloc(rxq->mp);
830 [ # # ]: 0 : if (unlikely(newm == NULL)) {
831 : : PMD_RX_LOG(ERR, "Error allocating mbuf");
832 : 0 : rxq->stats.rx_buf_alloc_failure++;
833 : 0 : break;
834 : : }
835 : :
836 : 0 : idx = rcd->rxdIdx;
837 [ # # ]: 0 : ring_idx = vmxnet3_get_ring_idx(hw, rcd->rqID);
838 : 0 : rxd = (Vmxnet3_RxDesc *)rxq->cmd_ring[ring_idx].base + idx;
839 : : RTE_SET_USED(rxd); /* used only for assert when enabled */
840 : 0 : rbi = rxq->cmd_ring[ring_idx].buf_info + idx;
841 : :
842 : : PMD_RX_LOG(DEBUG, "rxd idx: %d ring idx: %d.", idx, ring_idx);
843 : :
844 : : RTE_ASSERT(rcd->len <= rxd->len);
845 : : RTE_ASSERT(rbi->m);
846 : :
847 : : /* Get the packet buffer pointer from buf_info */
848 : 0 : rxm = rbi->m;
849 : :
850 : : /* Clear descriptor associated buf_info to be reused */
851 : 0 : rbi->m = NULL;
852 : 0 : rbi->bufPA = 0;
853 : :
854 : : /* Update the index that we received a packet */
855 : 0 : rxq->cmd_ring[ring_idx].next2comp = idx;
856 : :
857 : : /* For RCD with EOP set, check if there is frame error */
858 [ # # # # ]: 0 : if (unlikely(rcd->eop && rcd->err)) {
859 : 0 : rxq->stats.drop_total++;
860 : 0 : rxq->stats.drop_err++;
861 : :
862 [ # # ]: 0 : if (!rcd->fcs) {
863 : 0 : rxq->stats.drop_fcs++;
864 : : PMD_RX_LOG(ERR, "Recv packet dropped due to frame err.");
865 : : }
866 : : PMD_RX_LOG(ERR, "Error in received packet rcd#:%d rxd:%d",
867 : : (int)(rcd - (struct Vmxnet3_RxCompDesc *)
868 : : rxq->comp_ring.base), rcd->rxdIdx);
869 : : rte_pktmbuf_free_seg(rxm);
870 [ # # ]: 0 : if (rxq->start_seg) {
871 : : struct rte_mbuf *start = rxq->start_seg;
872 : :
873 : 0 : rxq->start_seg = NULL;
874 : 0 : rte_pktmbuf_free(start);
875 : : }
876 : 0 : goto rcd_done;
877 : : }
878 : :
879 : : /* Initialize newly received packet buffer */
880 : 0 : rxm->port = rxq->port_id;
881 : 0 : rxm->nb_segs = 1;
882 : 0 : rxm->next = NULL;
883 : 0 : rxm->pkt_len = (uint16_t)rcd->len;
884 : 0 : rxm->data_len = (uint16_t)rcd->len;
885 : 0 : rxm->data_off = RTE_PKTMBUF_HEADROOM;
886 : 0 : rxm->ol_flags = 0;
887 : 0 : rxm->vlan_tci = 0;
888 : 0 : rxm->packet_type = 0;
889 : :
890 : : /*
891 : : * If this is the first buffer of the received packet,
892 : : * set the pointer to the first mbuf of the packet
893 : : * Otherwise, update the total length and the number of segments
894 : : * of the current scattered packet, and update the pointer to
895 : : * the last mbuf of the current packet.
896 : : */
897 [ # # ]: 0 : if (rcd->sop) {
898 : : RTE_ASSERT(rxd->btype == VMXNET3_RXD_BTYPE_HEAD);
899 : :
900 [ # # ]: 0 : if (unlikely(rcd->len == 0)) {
901 : : RTE_ASSERT(rcd->eop);
902 : :
903 : : PMD_RX_LOG(DEBUG,
904 : : "Rx buf was skipped. rxring[%d][%d])",
905 : : ring_idx, idx);
906 : : rte_pktmbuf_free_seg(rxm);
907 : 0 : goto rcd_done;
908 : : }
909 : :
910 [ # # ]: 0 : if (vmxnet3_rx_data_ring(hw, rcd->rqID)) {
911 : 0 : uint8_t *rdd = rxq->data_ring.base +
912 : 0 : idx * rxq->data_desc_size;
913 : :
914 : : RTE_ASSERT(VMXNET3_VERSION_GE_3(hw));
915 [ # # ]: 0 : rte_memcpy(rte_pktmbuf_mtod(rxm, char *),
916 : : rdd, rcd->len);
917 : : }
918 : :
919 : 0 : rxq->start_seg = rxm;
920 : 0 : rxq->last_seg = rxm;
921 : 0 : vmxnet3_rx_offload(hw, rcd, rxm, 1);
922 : : } else {
923 : 0 : struct rte_mbuf *start = rxq->start_seg;
924 : :
925 : : RTE_ASSERT(rxd->btype == VMXNET3_RXD_BTYPE_BODY);
926 : :
927 [ # # # # ]: 0 : if (likely(start && rxm->data_len > 0)) {
928 : 0 : start->pkt_len += rxm->data_len;
929 : 0 : start->nb_segs++;
930 : :
931 : 0 : rxq->last_seg->next = rxm;
932 : 0 : rxq->last_seg = rxm;
933 : : } else {
934 : : PMD_RX_LOG(ERR, "Error received empty or out of order frame.");
935 : 0 : rxq->stats.drop_total++;
936 [ # # ]: 0 : rxq->stats.drop_err++;
937 : :
938 : : rte_pktmbuf_free_seg(rxm);
939 : : }
940 : : }
941 : :
942 [ # # ]: 0 : if (rcd->eop) {
943 : 0 : struct rte_mbuf *start = rxq->start_seg;
944 : :
945 : 0 : vmxnet3_rx_offload(hw, rcd, start, 0);
946 : 0 : rx_pkts[nb_rx++] = start;
947 : 0 : rxq->start_seg = NULL;
948 : : }
949 : :
950 : 0 : rcd_done:
951 : : rxq->cmd_ring[ring_idx].next2comp = idx;
952 [ # # ]: 0 : VMXNET3_INC_RING_IDX_ONLY(rxq->cmd_ring[ring_idx].next2comp,
953 : : rxq->cmd_ring[ring_idx].size);
954 : :
955 : : /* It's time to renew descriptors */
956 : 0 : vmxnet3_renew_desc(rxq, ring_idx, newm);
957 [ # # # # ]: 0 : if (unlikely(rxq->shared->ctrl.updateRxProd &&
958 : : (rxq->cmd_ring[ring_idx].next2fill & 0xf) == 0)) {
959 : 0 : VMXNET3_WRITE_BAR0_REG(hw, hw->rx_prod_offset[ring_idx] +
960 : : (rxq->queue_id * VMXNET3_REG_ALIGN),
961 : : rxq->cmd_ring[ring_idx].next2fill);
962 : : }
963 : :
964 : : /* Advance to the next descriptor in comp_ring */
965 : : vmxnet3_comp_ring_adv_next2proc(&rxq->comp_ring);
966 : :
967 : 0 : rcd = &rxq->comp_ring.base[rxq->comp_ring.next2proc].rcd;
968 : 0 : nb_rxd++;
969 [ # # ]: 0 : if (nb_rxd > rxq->cmd_ring[0].size) {
970 : : PMD_RX_LOG(ERR, "Used up quota of receiving packets,"
971 : : " relinquish control.");
972 : : break;
973 : : }
974 : : }
975 : :
976 [ # # ]: 0 : if (unlikely(nb_rxd == 0)) {
977 : : uint32_t avail;
978 : : uint32_t posted = 0;
979 [ # # ]: 0 : for (ring_idx = 0; ring_idx < VMXNET3_RX_CMDRING_SIZE; ring_idx++) {
980 [ # # ]: 0 : avail = vmxnet3_cmd_ring_desc_avail(&rxq->cmd_ring[ring_idx]);
981 [ # # ]: 0 : if (unlikely(avail > 0)) {
982 : : /* try to alloc new buf and renew descriptors */
983 [ # # ]: 0 : if (vmxnet3_post_rx_bufs(rxq, ring_idx) > 0)
984 : 0 : posted |= (1 << ring_idx);
985 : : }
986 : : }
987 [ # # ]: 0 : if (unlikely(rxq->shared->ctrl.updateRxProd)) {
988 [ # # ]: 0 : for (ring_idx = 0; ring_idx < VMXNET3_RX_CMDRING_SIZE; ring_idx++) {
989 [ # # ]: 0 : if (posted & (1 << ring_idx))
990 : 0 : VMXNET3_WRITE_BAR0_REG(hw, hw->rx_prod_offset[ring_idx] +
991 : : (rxq->queue_id * VMXNET3_REG_ALIGN),
992 : : rxq->cmd_ring[ring_idx].next2fill);
993 : : }
994 : : }
995 : : }
996 : :
997 : : return nb_rx;
998 : : }
999 : :
1000 : : int
1001 : 0 : vmxnet3_dev_rx_queue_count(void *rx_queue)
1002 : : {
1003 : : const vmxnet3_rx_queue_t *rxq;
1004 : : const Vmxnet3_RxCompDesc *rcd;
1005 : : uint32_t idx, nb_rxd = 0;
1006 : : uint8_t gen;
1007 : :
1008 : : rxq = rx_queue;
1009 [ # # ]: 0 : if (unlikely(rxq->stopped)) {
1010 : : PMD_RX_LOG(DEBUG, "Rx queue is stopped.");
1011 : : return 0;
1012 : : }
1013 : :
1014 : 0 : gen = rxq->comp_ring.gen;
1015 : 0 : idx = rxq->comp_ring.next2proc;
1016 : 0 : rcd = &rxq->comp_ring.base[idx].rcd;
1017 [ # # ]: 0 : while (rcd->gen == gen) {
1018 [ # # ]: 0 : if (rcd->eop)
1019 : 0 : ++nb_rxd;
1020 [ # # ]: 0 : if (++idx == rxq->comp_ring.size) {
1021 : : idx = 0;
1022 : 0 : gen ^= 1;
1023 : : }
1024 : 0 : rcd = &rxq->comp_ring.base[idx].rcd;
1025 : : }
1026 : :
1027 : 0 : return nb_rxd;
1028 : : }
1029 : :
1030 : : int
1031 : 0 : vmxnet3_dev_tx_queue_setup(struct rte_eth_dev *dev,
1032 : : uint16_t queue_idx,
1033 : : uint16_t nb_desc,
1034 : : unsigned int socket_id,
1035 : : const struct rte_eth_txconf *tx_conf __rte_unused)
1036 : : {
1037 : 0 : struct vmxnet3_hw *hw = dev->data->dev_private;
1038 : : const struct rte_memzone *mz;
1039 : : struct vmxnet3_tx_queue *txq;
1040 : : struct vmxnet3_cmd_ring *ring;
1041 : : struct vmxnet3_comp_ring *comp_ring;
1042 : : struct vmxnet3_data_ring *data_ring;
1043 : : int size;
1044 : :
1045 : 0 : PMD_INIT_FUNC_TRACE();
1046 : :
1047 : 0 : txq = rte_zmalloc("ethdev_tx_queue", sizeof(struct vmxnet3_tx_queue),
1048 : : RTE_CACHE_LINE_SIZE);
1049 [ # # ]: 0 : if (txq == NULL) {
1050 : 0 : PMD_INIT_LOG(ERR, "Can not allocate tx queue structure");
1051 : 0 : return -ENOMEM;
1052 : : }
1053 : :
1054 : 0 : txq->queue_id = queue_idx;
1055 : 0 : txq->port_id = dev->data->port_id;
1056 : 0 : txq->shared = NULL; /* set in vmxnet3_setup_driver_shared() */
1057 : 0 : txq->hw = hw;
1058 : 0 : txq->qid = queue_idx;
1059 : 0 : txq->stopped = TRUE;
1060 : 0 : txq->txdata_desc_size = hw->txdata_desc_size;
1061 : :
1062 : : ring = &txq->cmd_ring;
1063 : : comp_ring = &txq->comp_ring;
1064 : : data_ring = &txq->data_ring;
1065 : :
1066 : : /* Tx vmxnet ring length should be between 512-4096 */
1067 [ # # ]: 0 : if (nb_desc < VMXNET3_DEF_TX_RING_SIZE) {
1068 : 0 : PMD_INIT_LOG(ERR, "VMXNET3 Tx Ring Size Min: %u",
1069 : : VMXNET3_DEF_TX_RING_SIZE);
1070 : 0 : return -EINVAL;
1071 [ # # ]: 0 : } else if (nb_desc > VMXNET3_TX_RING_MAX_SIZE) {
1072 : 0 : PMD_INIT_LOG(ERR, "VMXNET3 Tx Ring Size Max: %u",
1073 : : VMXNET3_TX_RING_MAX_SIZE);
1074 : 0 : return -EINVAL;
1075 : : } else {
1076 : 0 : ring->size = nb_desc;
1077 [ # # ]: 0 : if (VMXNET3_VERSION_GE_7(hw))
1078 : 0 : ring->size = rte_align32prevpow2(nb_desc);
1079 : 0 : ring->size &= ~VMXNET3_RING_SIZE_MASK;
1080 : : }
1081 : 0 : comp_ring->size = data_ring->size = ring->size;
1082 : :
1083 : : /* Tx vmxnet rings structure initialization*/
1084 : 0 : ring->next2fill = 0;
1085 : 0 : ring->next2comp = 0;
1086 : 0 : ring->gen = VMXNET3_INIT_GEN;
1087 : 0 : comp_ring->next2proc = 0;
1088 : 0 : comp_ring->gen = VMXNET3_INIT_GEN;
1089 : :
1090 : 0 : size = sizeof(struct Vmxnet3_TxDesc) * ring->size;
1091 : 0 : size += sizeof(struct Vmxnet3_TxCompDesc) * comp_ring->size;
1092 : 0 : size += txq->txdata_desc_size * data_ring->size;
1093 : :
1094 : 0 : mz = rte_eth_dma_zone_reserve(dev, "txdesc", queue_idx, size,
1095 : : VMXNET3_RING_BA_ALIGN, socket_id);
1096 [ # # ]: 0 : if (mz == NULL) {
1097 : 0 : PMD_INIT_LOG(ERR, "ERROR: Creating queue descriptors zone");
1098 : 0 : return -ENOMEM;
1099 : : }
1100 : 0 : txq->mz = mz;
1101 : 0 : memset(mz->addr, 0, mz->len);
1102 : :
1103 : : /* cmd_ring initialization */
1104 : 0 : ring->base = mz->addr;
1105 : 0 : ring->basePA = mz->iova;
1106 : :
1107 : : /* comp_ring initialization */
1108 : 0 : comp_ring->base = ring->base + ring->size;
1109 : 0 : comp_ring->basePA = ring->basePA +
1110 : : (sizeof(struct Vmxnet3_TxDesc) * ring->size);
1111 : :
1112 : : /* data_ring initialization */
1113 : 0 : data_ring->base = (Vmxnet3_TxDataDesc *)(comp_ring->base + comp_ring->size);
1114 : 0 : data_ring->basePA = comp_ring->basePA +
1115 : : (sizeof(struct Vmxnet3_TxCompDesc) * comp_ring->size);
1116 : :
1117 : : /* cmd_ring0 buf_info allocation */
1118 : 0 : ring->buf_info = rte_zmalloc("tx_ring_buf_info",
1119 : : ring->size * sizeof(vmxnet3_buf_info_t), RTE_CACHE_LINE_SIZE);
1120 [ # # ]: 0 : if (ring->buf_info == NULL) {
1121 : 0 : PMD_INIT_LOG(ERR, "ERROR: Creating tx_buf_info structure");
1122 : 0 : return -ENOMEM;
1123 : : }
1124 : :
1125 : : /* Update the data portion with txq */
1126 : 0 : dev->data->tx_queues[queue_idx] = txq;
1127 : :
1128 : 0 : return 0;
1129 : : }
1130 : :
1131 : : int
1132 : 0 : vmxnet3_dev_rx_queue_setup(struct rte_eth_dev *dev,
1133 : : uint16_t queue_idx,
1134 : : uint16_t nb_desc,
1135 : : unsigned int socket_id,
1136 : : __rte_unused const struct rte_eth_rxconf *rx_conf,
1137 : : struct rte_mempool *mp)
1138 : : {
1139 : : const struct rte_memzone *mz;
1140 : : struct vmxnet3_rx_queue *rxq;
1141 : 0 : struct vmxnet3_hw *hw = dev->data->dev_private;
1142 : : struct vmxnet3_cmd_ring *ring0, *ring1, *ring;
1143 : : struct vmxnet3_comp_ring *comp_ring;
1144 : : struct vmxnet3_rx_data_ring *data_ring;
1145 : : int size;
1146 : : uint8_t i;
1147 : : char mem_name[32];
1148 : :
1149 : 0 : PMD_INIT_FUNC_TRACE();
1150 : :
1151 : 0 : rxq = rte_zmalloc("ethdev_rx_queue", sizeof(struct vmxnet3_rx_queue),
1152 : : RTE_CACHE_LINE_SIZE);
1153 [ # # ]: 0 : if (rxq == NULL) {
1154 : 0 : PMD_INIT_LOG(ERR, "Can not allocate rx queue structure");
1155 : 0 : return -ENOMEM;
1156 : : }
1157 : :
1158 [ # # ]: 0 : rxq->mp = mp;
1159 : : /* Remember buffer size for initialization in dev start. */
1160 : 0 : hw->rxdata_buf_size =
1161 : 0 : rte_pktmbuf_data_room_size(mp) - RTE_PKTMBUF_HEADROOM;
1162 : 0 : rxq->queue_id = queue_idx;
1163 : 0 : rxq->port_id = dev->data->port_id;
1164 : 0 : rxq->shared = NULL; /* set in vmxnet3_setup_driver_shared() */
1165 : 0 : rxq->hw = hw;
1166 : 0 : rxq->qid1 = queue_idx;
1167 : 0 : rxq->qid2 = queue_idx + hw->num_rx_queues;
1168 : 0 : rxq->data_ring_qid = queue_idx + 2 * hw->num_rx_queues;
1169 : 0 : rxq->data_desc_size = hw->rxdata_desc_size;
1170 : 0 : rxq->stopped = TRUE;
1171 : :
1172 : : ring0 = &rxq->cmd_ring[0];
1173 : : ring1 = &rxq->cmd_ring[1];
1174 : : comp_ring = &rxq->comp_ring;
1175 : : data_ring = &rxq->data_ring;
1176 : :
1177 : : /* Rx vmxnet rings length should be between 256-4096 */
1178 [ # # ]: 0 : if (nb_desc < VMXNET3_DEF_RX_RING_SIZE) {
1179 : 0 : PMD_INIT_LOG(ERR, "VMXNET3 Rx Ring Size Min: 256");
1180 : 0 : return -EINVAL;
1181 [ # # ]: 0 : } else if (nb_desc > VMXNET3_RX_RING_MAX_SIZE) {
1182 : 0 : PMD_INIT_LOG(ERR, "VMXNET3 Rx Ring Size Max: 4096");
1183 : 0 : return -EINVAL;
1184 : : } else {
1185 : 0 : ring0->size = nb_desc;
1186 [ # # ]: 0 : if (VMXNET3_VERSION_GE_7(hw))
1187 : 0 : ring0->size = rte_align32prevpow2(nb_desc);
1188 : 0 : ring0->size &= ~VMXNET3_RING_SIZE_MASK;
1189 : 0 : ring1->size = ring0->size;
1190 : : }
1191 : :
1192 : 0 : comp_ring->size = ring0->size + ring1->size;
1193 : 0 : data_ring->size = ring0->size;
1194 : :
1195 : : /* Rx vmxnet rings structure initialization */
1196 : 0 : ring0->next2fill = 0;
1197 : 0 : ring1->next2fill = 0;
1198 : 0 : ring0->next2comp = 0;
1199 : 0 : ring1->next2comp = 0;
1200 : 0 : ring0->gen = VMXNET3_INIT_GEN;
1201 : 0 : ring1->gen = VMXNET3_INIT_GEN;
1202 : 0 : comp_ring->next2proc = 0;
1203 : 0 : comp_ring->gen = VMXNET3_INIT_GEN;
1204 : :
1205 : 0 : size = sizeof(struct Vmxnet3_RxDesc) * (ring0->size + ring1->size);
1206 : 0 : size += sizeof(struct Vmxnet3_RxCompDesc) * comp_ring->size;
1207 [ # # # # ]: 0 : if (VMXNET3_VERSION_GE_3(hw) && rxq->data_desc_size)
1208 : 0 : size += rxq->data_desc_size * data_ring->size;
1209 : :
1210 : 0 : mz = rte_eth_dma_zone_reserve(dev, "rxdesc", queue_idx, size,
1211 : : VMXNET3_RING_BA_ALIGN, socket_id);
1212 [ # # ]: 0 : if (mz == NULL) {
1213 : 0 : PMD_INIT_LOG(ERR, "ERROR: Creating queue descriptors zone");
1214 : 0 : return -ENOMEM;
1215 : : }
1216 : 0 : rxq->mz = mz;
1217 [ # # ]: 0 : memset(mz->addr, 0, mz->len);
1218 : :
1219 : : /* cmd_ring0 initialization */
1220 : 0 : ring0->base = mz->addr;
1221 : 0 : ring0->basePA = mz->iova;
1222 : :
1223 : : /* cmd_ring1 initialization */
1224 : 0 : ring1->base = ring0->base + ring0->size;
1225 : 0 : ring1->basePA = ring0->basePA + sizeof(struct Vmxnet3_RxDesc) * ring0->size;
1226 : :
1227 : : /* comp_ring initialization */
1228 : 0 : comp_ring->base = ring1->base + ring1->size;
1229 : 0 : comp_ring->basePA = ring1->basePA + sizeof(struct Vmxnet3_RxDesc) *
1230 : : ring1->size;
1231 : :
1232 : : /* data_ring initialization */
1233 [ # # # # ]: 0 : if (VMXNET3_VERSION_GE_3(hw) && rxq->data_desc_size) {
1234 : 0 : data_ring->base =
1235 : 0 : (uint8_t *)(comp_ring->base + comp_ring->size);
1236 : 0 : data_ring->basePA = comp_ring->basePA +
1237 : : sizeof(struct Vmxnet3_RxCompDesc) * comp_ring->size;
1238 : : }
1239 : :
1240 : : /* cmd_ring0-cmd_ring1 buf_info allocation */
1241 [ # # ]: 0 : for (i = 0; i < VMXNET3_RX_CMDRING_SIZE; i++) {
1242 : :
1243 : 0 : ring = &rxq->cmd_ring[i];
1244 : 0 : ring->rid = i;
1245 : : snprintf(mem_name, sizeof(mem_name), "rx_ring_%d_buf_info", i);
1246 : :
1247 : 0 : ring->buf_info = rte_zmalloc(mem_name,
1248 : 0 : ring->size * sizeof(vmxnet3_buf_info_t),
1249 : : RTE_CACHE_LINE_SIZE);
1250 [ # # ]: 0 : if (ring->buf_info == NULL) {
1251 : 0 : PMD_INIT_LOG(ERR, "ERROR: Creating rx_buf_info structure");
1252 : 0 : return -ENOMEM;
1253 : : }
1254 : : }
1255 : :
1256 : : /* Update the data portion with rxq */
1257 : 0 : dev->data->rx_queues[queue_idx] = rxq;
1258 : :
1259 : 0 : return 0;
1260 : : }
1261 : :
1262 : : /*
1263 : : * Initializes Receive Unit
1264 : : * Load mbufs in rx queue in advance
1265 : : */
1266 : : int
1267 : 0 : vmxnet3_dev_rxtx_init(struct rte_eth_dev *dev)
1268 : : {
1269 : 0 : struct vmxnet3_hw *hw = dev->data->dev_private;
1270 : :
1271 : : int i, ret;
1272 : : uint8_t j;
1273 : :
1274 : 0 : PMD_INIT_FUNC_TRACE();
1275 : :
1276 [ # # ]: 0 : for (i = 0; i < hw->num_rx_queues; i++) {
1277 : 0 : vmxnet3_rx_queue_t *rxq = dev->data->rx_queues[i];
1278 : :
1279 [ # # ]: 0 : for (j = 0; j < VMXNET3_RX_CMDRING_SIZE; j++) {
1280 : : /* Passing 0 as alloc_num will allocate full ring */
1281 : 0 : ret = vmxnet3_post_rx_bufs(rxq, j);
1282 : :
1283 : : /* Zero number of descriptors in the configuration of the RX queue */
1284 [ # # ]: 0 : if (ret == 0) {
1285 : 0 : PMD_INIT_LOG(ERR,
1286 : : "Invalid configuration in Rx queue: %d, buffers ring: %d",
1287 : : i, j);
1288 : 0 : return -EINVAL;
1289 : : }
1290 : : /* Return the error number */
1291 [ # # ]: 0 : if (ret < 0) {
1292 : 0 : PMD_INIT_LOG(ERR, "Posting Rxq: %d buffers ring: %d", i, j);
1293 : 0 : return ret;
1294 : : }
1295 : : /*
1296 : : * Updating device with the index:next2fill to fill the
1297 : : * mbufs for coming packets.
1298 : : */
1299 [ # # ]: 0 : if (unlikely(rxq->shared->ctrl.updateRxProd)) {
1300 : 0 : VMXNET3_WRITE_BAR0_REG(hw, hw->rx_prod_offset[j] +
1301 : : (rxq->queue_id * VMXNET3_REG_ALIGN),
1302 : : rxq->cmd_ring[j].next2fill);
1303 : : }
1304 : : }
1305 : 0 : rxq->stopped = FALSE;
1306 : 0 : rxq->start_seg = NULL;
1307 : : }
1308 : :
1309 [ # # ]: 0 : for (i = 0; i < dev->data->nb_tx_queues; i++) {
1310 : 0 : struct vmxnet3_tx_queue *txq = dev->data->tx_queues[i];
1311 : :
1312 : 0 : txq->stopped = FALSE;
1313 : : }
1314 : :
1315 : : return 0;
1316 : : }
1317 : :
1318 : : static uint8_t rss_intel_key[40] = {
1319 : : 0x6D, 0x5A, 0x56, 0xDA, 0x25, 0x5B, 0x0E, 0xC2,
1320 : : 0x41, 0x67, 0x25, 0x3D, 0x43, 0xA3, 0x8F, 0xB0,
1321 : : 0xD0, 0xCA, 0x2B, 0xCB, 0xAE, 0x7B, 0x30, 0xB4,
1322 : : 0x77, 0xCB, 0x2D, 0xA3, 0x80, 0x30, 0xF2, 0x0C,
1323 : : 0x6A, 0x42, 0xB7, 0x3B, 0xBE, 0xAC, 0x01, 0xFA,
1324 : : };
1325 : :
1326 : : /*
1327 : : * Additional RSS configurations based on vmxnet v4+ APIs
1328 : : */
1329 : : int
1330 : 0 : vmxnet3_v4_rss_configure(struct rte_eth_dev *dev)
1331 : : {
1332 : 0 : struct vmxnet3_hw *hw = dev->data->dev_private;
1333 : 0 : Vmxnet3_DriverShared *shared = hw->shared;
1334 : : Vmxnet3_CmdInfo *cmdInfo = &shared->cu.cmdInfo;
1335 : : struct rte_eth_rss_conf *port_rss_conf;
1336 : : uint64_t rss_hf;
1337 : : uint32_t ret;
1338 : :
1339 : 0 : PMD_INIT_FUNC_TRACE();
1340 : :
1341 : 0 : cmdInfo->setRSSFields = 0;
1342 : 0 : port_rss_conf = &dev->data->dev_conf.rx_adv_conf.rss_conf;
1343 : :
1344 [ # # ]: 0 : if ((port_rss_conf->rss_hf & VMXNET3_MANDATORY_V4_RSS) !=
1345 : : VMXNET3_MANDATORY_V4_RSS) {
1346 : 0 : PMD_INIT_LOG(WARNING, "RSS: IPv4/6 TCP is required for vmxnet3 v4 RSS,"
1347 : : "automatically setting it");
1348 : 0 : port_rss_conf->rss_hf |= VMXNET3_MANDATORY_V4_RSS;
1349 : : }
1350 : :
1351 : 0 : rss_hf = port_rss_conf->rss_hf &
1352 : : (VMXNET3_V4_RSS_MASK | VMXNET3_RSS_OFFLOAD_ALL);
1353 : :
1354 [ # # ]: 0 : if (rss_hf & RTE_ETH_RSS_NONFRAG_IPV4_TCP)
1355 : 0 : cmdInfo->setRSSFields |= VMXNET3_RSS_FIELDS_TCPIP4;
1356 [ # # ]: 0 : if (rss_hf & RTE_ETH_RSS_NONFRAG_IPV6_TCP)
1357 : 0 : cmdInfo->setRSSFields |= VMXNET3_RSS_FIELDS_TCPIP6;
1358 [ # # ]: 0 : if (rss_hf & RTE_ETH_RSS_NONFRAG_IPV4_UDP)
1359 : 0 : cmdInfo->setRSSFields |= VMXNET3_RSS_FIELDS_UDPIP4;
1360 [ # # ]: 0 : if (rss_hf & RTE_ETH_RSS_NONFRAG_IPV6_UDP)
1361 : 0 : cmdInfo->setRSSFields |= VMXNET3_RSS_FIELDS_UDPIP6;
1362 : :
1363 : 0 : VMXNET3_WRITE_BAR1_REG(hw, VMXNET3_REG_CMD,
1364 : : VMXNET3_CMD_SET_RSS_FIELDS);
1365 : 0 : ret = VMXNET3_READ_BAR1_REG(hw, VMXNET3_REG_CMD);
1366 : :
1367 [ # # ]: 0 : if (ret != VMXNET3_SUCCESS) {
1368 : 0 : PMD_DRV_LOG(ERR, "Set RSS fields (v4) failed: %d", ret);
1369 : : }
1370 : :
1371 : 0 : return ret;
1372 : : }
1373 : :
1374 : : /*
1375 : : * Configure RSS feature
1376 : : */
1377 : : int
1378 : 0 : vmxnet3_rss_configure(struct rte_eth_dev *dev)
1379 : : {
1380 : 0 : struct vmxnet3_hw *hw = dev->data->dev_private;
1381 : : struct VMXNET3_RSSConf *dev_rss_conf;
1382 : : struct rte_eth_rss_conf *port_rss_conf;
1383 : : uint64_t rss_hf;
1384 : : uint8_t i, j;
1385 : :
1386 : 0 : PMD_INIT_FUNC_TRACE();
1387 : :
1388 : 0 : dev_rss_conf = hw->rss_conf;
1389 : 0 : port_rss_conf = &dev->data->dev_conf.rx_adv_conf.rss_conf;
1390 : :
1391 : : /* loading hashFunc */
1392 : 0 : dev_rss_conf->hashFunc = VMXNET3_RSS_HASH_FUNC_TOEPLITZ;
1393 : : /* loading hashKeySize */
1394 : 0 : dev_rss_conf->hashKeySize = VMXNET3_RSS_MAX_KEY_SIZE;
1395 : : /* loading indTableSize: Must not exceed VMXNET3_RSS_MAX_IND_TABLE_SIZE (128)*/
1396 [ # # ]: 0 : dev_rss_conf->indTableSize = (uint16_t)((MAX_RX_QUEUES(hw)) * 4);
1397 : :
1398 [ # # ]: 0 : if (port_rss_conf->rss_key == NULL) {
1399 : : /* Default hash key */
1400 : 0 : port_rss_conf->rss_key = rss_intel_key;
1401 : : }
1402 : :
1403 : : /* loading hashKey */
1404 : 0 : memcpy(&dev_rss_conf->hashKey[0], port_rss_conf->rss_key,
1405 : : dev_rss_conf->hashKeySize);
1406 : :
1407 : : /* loading indTable */
1408 [ # # ]: 0 : for (i = 0, j = 0; i < dev_rss_conf->indTableSize; i++, j++) {
1409 [ # # ]: 0 : if (j == dev->data->nb_rx_queues)
1410 : : j = 0;
1411 : 0 : dev_rss_conf->indTable[i] = j;
1412 : : }
1413 : :
1414 : : /* loading hashType */
1415 : 0 : dev_rss_conf->hashType = 0;
1416 : 0 : rss_hf = port_rss_conf->rss_hf & VMXNET3_RSS_OFFLOAD_ALL;
1417 [ # # ]: 0 : if (rss_hf & RTE_ETH_RSS_IPV4)
1418 : 0 : dev_rss_conf->hashType |= VMXNET3_RSS_HASH_TYPE_IPV4;
1419 [ # # ]: 0 : if (rss_hf & RTE_ETH_RSS_NONFRAG_IPV4_TCP)
1420 : 0 : dev_rss_conf->hashType |= VMXNET3_RSS_HASH_TYPE_TCP_IPV4;
1421 [ # # ]: 0 : if (rss_hf & RTE_ETH_RSS_IPV6)
1422 : 0 : dev_rss_conf->hashType |= VMXNET3_RSS_HASH_TYPE_IPV6;
1423 [ # # ]: 0 : if (rss_hf & RTE_ETH_RSS_NONFRAG_IPV6_TCP)
1424 : 0 : dev_rss_conf->hashType |= VMXNET3_RSS_HASH_TYPE_TCP_IPV6;
1425 : :
1426 : 0 : return VMXNET3_SUCCESS;
1427 : : }
|