152b5a707SDavid Christensen /* SPDX-License-Identifier: BSD-3-Clause 252b5a707SDavid Christensen * Copyright(c) 2010-2015 Intel Corporation 352b5a707SDavid Christensen * Copyright(C) 2019 IBM Corporation 452b5a707SDavid Christensen */ 552b5a707SDavid Christensen 652b5a707SDavid Christensen #include <stdint.h> 752b5a707SDavid Christensen #include <stdio.h> 852b5a707SDavid Christensen #include <stdlib.h> 952b5a707SDavid Christensen #include <string.h> 1052b5a707SDavid Christensen #include <errno.h> 1152b5a707SDavid Christensen 12*f5bf02dfSOri Kam #include <rte_altivec.h> 1352b5a707SDavid Christensen #include <rte_byteorder.h> 1452b5a707SDavid Christensen #include <rte_branch_prediction.h> 1552b5a707SDavid Christensen #include <rte_cycles.h> 1652b5a707SDavid Christensen #include <rte_ether.h> 1752b5a707SDavid Christensen #include <rte_ethdev_driver.h> 1852b5a707SDavid Christensen #include <rte_errno.h> 1952b5a707SDavid Christensen #include <rte_memory.h> 2052b5a707SDavid Christensen #include <rte_mempool.h> 2152b5a707SDavid Christensen #include <rte_malloc.h> 2252b5a707SDavid Christensen #include <rte_mbuf.h> 2352b5a707SDavid Christensen #include <rte_prefetch.h> 2452b5a707SDavid Christensen #include <rte_string_fns.h> 2552b5a707SDavid Christensen 2652b5a707SDavid Christensen #include "virtio_rxtx_simple.h" 2752b5a707SDavid Christensen 2852b5a707SDavid Christensen #define RTE_VIRTIO_DESC_PER_LOOP 8 2952b5a707SDavid Christensen 3052b5a707SDavid Christensen /* virtio vPMD receive routine, only accept(nb_pkts >= RTE_VIRTIO_DESC_PER_LOOP) 3152b5a707SDavid Christensen * 3252b5a707SDavid Christensen * This routine is for non-mergeable RX, one desc for each guest buffer. 3352b5a707SDavid Christensen * This routine is based on the RX ring layout optimization. Each entry in the 3452b5a707SDavid Christensen * avail ring points to the desc with the same index in the desc ring and this 3552b5a707SDavid Christensen * will never be changed in the driver. 3652b5a707SDavid Christensen * 3752b5a707SDavid Christensen * - nb_pkts < RTE_VIRTIO_DESC_PER_LOOP, just return no packet 3852b5a707SDavid Christensen */ 3952b5a707SDavid Christensen uint16_t 4052b5a707SDavid Christensen virtio_recv_pkts_vec(void *rx_queue, struct rte_mbuf **rx_pkts, 4152b5a707SDavid Christensen uint16_t nb_pkts) 4252b5a707SDavid Christensen { 4352b5a707SDavid Christensen struct virtnet_rx *rxvq = rx_queue; 4452b5a707SDavid Christensen struct virtqueue *vq = rxvq->vq; 4552b5a707SDavid Christensen struct virtio_hw *hw = vq->hw; 46a44c4e1eSDavid Christensen uint16_t nb_used, nb_total; 4752b5a707SDavid Christensen uint16_t desc_idx; 4852b5a707SDavid Christensen struct vring_used_elem *rused; 4952b5a707SDavid Christensen struct rte_mbuf **sw_ring; 5052b5a707SDavid Christensen struct rte_mbuf **sw_ring_end; 5186d1afa1SDavid Christensen struct rte_mbuf **ref_rx_pkts; 5252b5a707SDavid Christensen uint16_t nb_pkts_received = 0; 5352b5a707SDavid Christensen const vector unsigned char zero = {0}; 5452b5a707SDavid Christensen 5552b5a707SDavid Christensen const vector unsigned char shuf_msk1 = { 5652b5a707SDavid Christensen 0xFF, 0xFF, 0xFF, 0xFF, /* packet type */ 5752b5a707SDavid Christensen 4, 5, 0xFF, 0xFF, /* vlan tci */ 5852b5a707SDavid Christensen 4, 5, /* dat len */ 5952b5a707SDavid Christensen 0xFF, 0xFF, /* vlan tci */ 6052b5a707SDavid Christensen 0xFF, 0xFF, 0xFF, 0xFF 6152b5a707SDavid Christensen }; 6252b5a707SDavid Christensen 6352b5a707SDavid Christensen const vector unsigned char shuf_msk2 = { 6452b5a707SDavid Christensen 0xFF, 0xFF, 0xFF, 0xFF, /* packet type */ 6552b5a707SDavid Christensen 12, 13, 0xFF, 0xFF, /* pkt len */ 6652b5a707SDavid Christensen 12, 13, /* dat len */ 6752b5a707SDavid Christensen 0xFF, 0xFF, /* vlan tci */ 6852b5a707SDavid Christensen 0xFF, 0xFF, 0xFF, 0xFF 6952b5a707SDavid Christensen }; 7052b5a707SDavid Christensen 7152b5a707SDavid Christensen /* 7252b5a707SDavid Christensen * Subtract the header length. 7352b5a707SDavid Christensen * In which case do we need the header length in used->len ? 7452b5a707SDavid Christensen */ 7552b5a707SDavid Christensen const vector unsigned short len_adjust = { 7652b5a707SDavid Christensen 0, 0, 7752b5a707SDavid Christensen (uint16_t)-vq->hw->vtnet_hdr_size, 0, 7852b5a707SDavid Christensen (uint16_t)-vq->hw->vtnet_hdr_size, 0, 7952b5a707SDavid Christensen 0, 0 8052b5a707SDavid Christensen }; 8152b5a707SDavid Christensen 8252b5a707SDavid Christensen if (unlikely(hw->started == 0)) 8352b5a707SDavid Christensen return nb_pkts_received; 8452b5a707SDavid Christensen 8552b5a707SDavid Christensen if (unlikely(nb_pkts < RTE_VIRTIO_DESC_PER_LOOP)) 8652b5a707SDavid Christensen return 0; 8752b5a707SDavid Christensen 8852b5a707SDavid Christensen nb_used = VIRTQUEUE_NUSED(vq); 8952b5a707SDavid Christensen 9052b5a707SDavid Christensen rte_compiler_barrier(); 9152b5a707SDavid Christensen 9252b5a707SDavid Christensen if (unlikely(nb_used == 0)) 9352b5a707SDavid Christensen return 0; 9452b5a707SDavid Christensen 9552b5a707SDavid Christensen nb_pkts = RTE_ALIGN_FLOOR(nb_pkts, RTE_VIRTIO_DESC_PER_LOOP); 9652b5a707SDavid Christensen nb_used = RTE_MIN(nb_used, nb_pkts); 9752b5a707SDavid Christensen 9852b5a707SDavid Christensen desc_idx = (uint16_t)(vq->vq_used_cons_idx & (vq->vq_nentries - 1)); 9952b5a707SDavid Christensen rused = &vq->vq_split.ring.used->ring[desc_idx]; 10052b5a707SDavid Christensen sw_ring = &vq->sw_ring[desc_idx]; 10152b5a707SDavid Christensen sw_ring_end = &vq->sw_ring[vq->vq_nentries]; 10252b5a707SDavid Christensen 10352b5a707SDavid Christensen rte_prefetch0(rused); 10452b5a707SDavid Christensen 10552b5a707SDavid Christensen if (vq->vq_free_cnt >= RTE_VIRTIO_VPMD_RX_REARM_THRESH) { 10652b5a707SDavid Christensen virtio_rxq_rearm_vec(rxvq); 10752b5a707SDavid Christensen if (unlikely(virtqueue_kick_prepare(vq))) 10852b5a707SDavid Christensen virtqueue_notify(vq); 10952b5a707SDavid Christensen } 11052b5a707SDavid Christensen 111a44c4e1eSDavid Christensen nb_total = nb_used; 11286d1afa1SDavid Christensen ref_rx_pkts = rx_pkts; 11352b5a707SDavid Christensen for (nb_pkts_received = 0; 114a44c4e1eSDavid Christensen nb_pkts_received < nb_total;) { 11552b5a707SDavid Christensen vector unsigned char desc[RTE_VIRTIO_DESC_PER_LOOP / 2]; 11652b5a707SDavid Christensen vector unsigned char mbp[RTE_VIRTIO_DESC_PER_LOOP / 2]; 11752b5a707SDavid Christensen vector unsigned char pkt_mb[RTE_VIRTIO_DESC_PER_LOOP]; 11852b5a707SDavid Christensen 11952b5a707SDavid Christensen mbp[0] = vec_vsx_ld(0, (unsigned char const *)(sw_ring + 0)); 12052b5a707SDavid Christensen desc[0] = vec_vsx_ld(0, (unsigned char const *)(rused + 0)); 12152b5a707SDavid Christensen *(vector unsigned char *)&rx_pkts[0] = mbp[0]; 12252b5a707SDavid Christensen 12352b5a707SDavid Christensen mbp[1] = vec_vsx_ld(0, (unsigned char const *)(sw_ring + 2)); 12452b5a707SDavid Christensen desc[1] = vec_vsx_ld(0, (unsigned char const *)(rused + 2)); 12552b5a707SDavid Christensen *(vector unsigned char *)&rx_pkts[2] = mbp[1]; 12652b5a707SDavid Christensen 12752b5a707SDavid Christensen mbp[2] = vec_vsx_ld(0, (unsigned char const *)(sw_ring + 4)); 12852b5a707SDavid Christensen desc[2] = vec_vsx_ld(0, (unsigned char const *)(rused + 4)); 12952b5a707SDavid Christensen *(vector unsigned char *)&rx_pkts[4] = mbp[2]; 13052b5a707SDavid Christensen 13152b5a707SDavid Christensen mbp[3] = vec_vsx_ld(0, (unsigned char const *)(sw_ring + 6)); 13252b5a707SDavid Christensen desc[3] = vec_vsx_ld(0, (unsigned char const *)(rused + 6)); 13352b5a707SDavid Christensen *(vector unsigned char *)&rx_pkts[6] = mbp[3]; 13452b5a707SDavid Christensen 13552b5a707SDavid Christensen pkt_mb[0] = vec_perm(desc[0], zero, shuf_msk1); 13652b5a707SDavid Christensen pkt_mb[1] = vec_perm(desc[0], zero, shuf_msk2); 13752b5a707SDavid Christensen pkt_mb[0] = (vector unsigned char) 13852b5a707SDavid Christensen ((vector unsigned short)pkt_mb[0] + len_adjust); 13952b5a707SDavid Christensen pkt_mb[1] = (vector unsigned char) 14052b5a707SDavid Christensen ((vector unsigned short)pkt_mb[1] + len_adjust); 14152b5a707SDavid Christensen *(vector unsigned char *)&rx_pkts[0]->rx_descriptor_fields1 = 14252b5a707SDavid Christensen pkt_mb[0]; 14352b5a707SDavid Christensen *(vector unsigned char *)&rx_pkts[1]->rx_descriptor_fields1 = 14452b5a707SDavid Christensen pkt_mb[1]; 14552b5a707SDavid Christensen 14652b5a707SDavid Christensen pkt_mb[2] = vec_perm(desc[1], zero, shuf_msk1); 14752b5a707SDavid Christensen pkt_mb[3] = vec_perm(desc[1], zero, shuf_msk2); 14852b5a707SDavid Christensen pkt_mb[2] = (vector unsigned char) 14952b5a707SDavid Christensen ((vector unsigned short)pkt_mb[2] + len_adjust); 15052b5a707SDavid Christensen pkt_mb[3] = (vector unsigned char) 15152b5a707SDavid Christensen ((vector unsigned short)pkt_mb[3] + len_adjust); 15252b5a707SDavid Christensen *(vector unsigned char *)&rx_pkts[2]->rx_descriptor_fields1 = 15352b5a707SDavid Christensen pkt_mb[2]; 15452b5a707SDavid Christensen *(vector unsigned char *)&rx_pkts[3]->rx_descriptor_fields1 = 15552b5a707SDavid Christensen pkt_mb[3]; 15652b5a707SDavid Christensen 15752b5a707SDavid Christensen pkt_mb[4] = vec_perm(desc[2], zero, shuf_msk1); 15852b5a707SDavid Christensen pkt_mb[5] = vec_perm(desc[2], zero, shuf_msk2); 15952b5a707SDavid Christensen pkt_mb[4] = (vector unsigned char) 16052b5a707SDavid Christensen ((vector unsigned short)pkt_mb[4] + len_adjust); 16152b5a707SDavid Christensen pkt_mb[5] = (vector unsigned char) 16252b5a707SDavid Christensen ((vector unsigned short)pkt_mb[5] + len_adjust); 16352b5a707SDavid Christensen *(vector unsigned char *)&rx_pkts[4]->rx_descriptor_fields1 = 16452b5a707SDavid Christensen pkt_mb[4]; 16552b5a707SDavid Christensen *(vector unsigned char *)&rx_pkts[5]->rx_descriptor_fields1 = 16652b5a707SDavid Christensen pkt_mb[5]; 16752b5a707SDavid Christensen 16852b5a707SDavid Christensen pkt_mb[6] = vec_perm(desc[3], zero, shuf_msk1); 16952b5a707SDavid Christensen pkt_mb[7] = vec_perm(desc[3], zero, shuf_msk2); 17052b5a707SDavid Christensen pkt_mb[6] = (vector unsigned char) 17152b5a707SDavid Christensen ((vector unsigned short)pkt_mb[6] + len_adjust); 17252b5a707SDavid Christensen pkt_mb[7] = (vector unsigned char) 17352b5a707SDavid Christensen ((vector unsigned short)pkt_mb[7] + len_adjust); 17452b5a707SDavid Christensen *(vector unsigned char *)&rx_pkts[6]->rx_descriptor_fields1 = 17552b5a707SDavid Christensen pkt_mb[6]; 17652b5a707SDavid Christensen *(vector unsigned char *)&rx_pkts[7]->rx_descriptor_fields1 = 17752b5a707SDavid Christensen pkt_mb[7]; 17852b5a707SDavid Christensen 17952b5a707SDavid Christensen if (unlikely(nb_used <= RTE_VIRTIO_DESC_PER_LOOP)) { 18052b5a707SDavid Christensen if (sw_ring + nb_used <= sw_ring_end) 18152b5a707SDavid Christensen nb_pkts_received += nb_used; 18252b5a707SDavid Christensen else 18352b5a707SDavid Christensen nb_pkts_received += sw_ring_end - sw_ring; 18452b5a707SDavid Christensen break; 18552b5a707SDavid Christensen } else { 18652b5a707SDavid Christensen if (unlikely(sw_ring + RTE_VIRTIO_DESC_PER_LOOP >= 18752b5a707SDavid Christensen sw_ring_end)) { 18852b5a707SDavid Christensen nb_pkts_received += sw_ring_end - sw_ring; 18952b5a707SDavid Christensen break; 19052b5a707SDavid Christensen } else { 19152b5a707SDavid Christensen nb_pkts_received += RTE_VIRTIO_DESC_PER_LOOP; 19252b5a707SDavid Christensen 19352b5a707SDavid Christensen rx_pkts += RTE_VIRTIO_DESC_PER_LOOP; 19452b5a707SDavid Christensen sw_ring += RTE_VIRTIO_DESC_PER_LOOP; 19552b5a707SDavid Christensen rused += RTE_VIRTIO_DESC_PER_LOOP; 19652b5a707SDavid Christensen nb_used -= RTE_VIRTIO_DESC_PER_LOOP; 19752b5a707SDavid Christensen } 19852b5a707SDavid Christensen } 19952b5a707SDavid Christensen } 20052b5a707SDavid Christensen 20152b5a707SDavid Christensen vq->vq_used_cons_idx += nb_pkts_received; 20252b5a707SDavid Christensen vq->vq_free_cnt += nb_pkts_received; 20352b5a707SDavid Christensen rxvq->stats.packets += nb_pkts_received; 20486d1afa1SDavid Christensen for (nb_used = 0; nb_used < nb_pkts_received; nb_used++) 20586d1afa1SDavid Christensen virtio_update_packet_stats(&rxvq->stats, ref_rx_pkts[nb_used]); 20686d1afa1SDavid Christensen 20752b5a707SDavid Christensen return nb_pkts_received; 20852b5a707SDavid Christensen } 209