net/virtio: move VLAN tag insertion to Tx prepare
[dpdk.git] / drivers / net / virtio / virtio_rxtx.c
index 60fa3aa..dcce39e 100644 (file)
@@ -62,13 +62,13 @@ vq_ring_free_chain(struct virtqueue *vq, uint16_t desc_idx)
        struct vq_desc_extra *dxp;
        uint16_t desc_idx_last = desc_idx;
 
-       dp  = &vq->vq_ring.desc[desc_idx];
+       dp  = &vq->vq_split.ring.desc[desc_idx];
        dxp = &vq->vq_descx[desc_idx];
        vq->vq_free_cnt = (uint16_t)(vq->vq_free_cnt + dxp->ndescs);
        if ((dp->flags & VRING_DESC_F_INDIRECT) == 0) {
                while (dp->flags & VRING_DESC_F_NEXT) {
                        desc_idx_last = dp->next;
-                       dp = &vq->vq_ring.desc[dp->next];
+                       dp = &vq->vq_split.ring.desc[dp->next];
                }
        }
        dxp->ndescs = 0;
@@ -81,7 +81,7 @@ vq_ring_free_chain(struct virtqueue *vq, uint16_t desc_idx)
        if (vq->vq_desc_tail_idx == VQ_RING_DESC_CHAIN_END) {
                vq->vq_desc_head_idx = desc_idx;
        } else {
-               dp_tail = &vq->vq_ring.desc[vq->vq_desc_tail_idx];
+               dp_tail = &vq->vq_split.ring.desc[vq->vq_desc_tail_idx];
                dp_tail->next = desc_idx;
        }
 
@@ -118,7 +118,7 @@ virtqueue_dequeue_burst_rx_packed(struct virtqueue *vq,
        struct vring_packed_desc *desc;
        uint16_t i;
 
-       desc = vq->ring_packed.desc_packed;
+       desc = vq->vq_packed.ring.desc;
 
        for (i = 0; i < num; i++) {
                used_idx = vq->vq_used_cons_idx;
@@ -141,7 +141,7 @@ virtqueue_dequeue_burst_rx_packed(struct virtqueue *vq,
                vq->vq_used_cons_idx++;
                if (vq->vq_used_cons_idx >= vq->vq_nentries) {
                        vq->vq_used_cons_idx -= vq->vq_nentries;
-                       vq->used_wrap_counter ^= 1;
+                       vq->vq_packed.used_wrap_counter ^= 1;
                }
        }
 
@@ -160,7 +160,7 @@ virtqueue_dequeue_burst_rx(struct virtqueue *vq, struct rte_mbuf **rx_pkts,
        /*  Caller does the check */
        for (i = 0; i < num ; i++) {
                used_idx = (uint16_t)(vq->vq_used_cons_idx & (vq->vq_nentries - 1));
-               uep = &vq->vq_ring.used->ring[used_idx];
+               uep = &vq->vq_split.ring.used->ring[used_idx];
                desc_idx = (uint16_t) uep->id;
                len[i] = uep->len;
                cookie = (struct rte_mbuf *)vq->vq_descx[desc_idx].cookie;
@@ -199,7 +199,7 @@ virtqueue_dequeue_rx_inorder(struct virtqueue *vq,
        for (i = 0; i < num; i++) {
                used_idx = vq->vq_used_cons_idx & (vq->vq_nentries - 1);
                /* Desc idx same as used idx */
-               uep = &vq->vq_ring.used->ring[used_idx];
+               uep = &vq->vq_split.ring.used->ring[used_idx];
                len[i] = uep->len;
                cookie = (struct rte_mbuf *)vq->vq_descx[used_idx].cookie;
 
@@ -229,7 +229,7 @@ virtio_xmit_cleanup_inorder_packed(struct virtqueue *vq, int num)
 {
        uint16_t used_idx, id, curr_id, free_cnt = 0;
        uint16_t size = vq->vq_nentries;
-       struct vring_packed_desc *desc = vq->ring_packed.desc_packed;
+       struct vring_packed_desc *desc = vq->vq_packed.ring.desc;
        struct vq_desc_extra *dxp;
 
        used_idx = vq->vq_used_cons_idx;
@@ -244,7 +244,7 @@ virtio_xmit_cleanup_inorder_packed(struct virtqueue *vq, int num)
                        num -= dxp->ndescs;
                        if (used_idx >= size) {
                                used_idx -= size;
-                               vq->used_wrap_counter ^= 1;
+                               vq->vq_packed.used_wrap_counter ^= 1;
                        }
                        if (dxp->cookie != NULL) {
                                rte_pktmbuf_free(dxp->cookie);
@@ -261,7 +261,7 @@ virtio_xmit_cleanup_normal_packed(struct virtqueue *vq, int num)
 {
        uint16_t used_idx, id;
        uint16_t size = vq->vq_nentries;
-       struct vring_packed_desc *desc = vq->ring_packed.desc_packed;
+       struct vring_packed_desc *desc = vq->vq_packed.ring.desc;
        struct vq_desc_extra *dxp;
 
        used_idx = vq->vq_used_cons_idx;
@@ -272,7 +272,7 @@ virtio_xmit_cleanup_normal_packed(struct virtqueue *vq, int num)
                vq->vq_used_cons_idx += dxp->ndescs;
                if (vq->vq_used_cons_idx >= size) {
                        vq->vq_used_cons_idx -= size;
-                       vq->used_wrap_counter ^= 1;
+                       vq->vq_packed.used_wrap_counter ^= 1;
                }
                vq_ring_free_id_packed(vq, id);
                if (dxp->cookie != NULL) {
@@ -302,7 +302,7 @@ virtio_xmit_cleanup(struct virtqueue *vq, uint16_t num)
                struct vq_desc_extra *dxp;
 
                used_idx = (uint16_t)(vq->vq_used_cons_idx & (vq->vq_nentries - 1));
-               uep = &vq->vq_ring.used->ring[used_idx];
+               uep = &vq->vq_split.ring.used->ring[used_idx];
 
                desc_idx = (uint16_t) uep->id;
                dxp = &vq->vq_descx[desc_idx];
@@ -356,7 +356,7 @@ virtqueue_enqueue_refill_inorder(struct virtqueue *vq,
                return -EMSGSIZE;
 
        head_idx = vq->vq_desc_head_idx & (vq->vq_nentries - 1);
-       start_dp = vq->vq_ring.desc;
+       start_dp = vq->vq_split.ring.desc;
 
        while (i < num) {
                idx = head_idx & (vq->vq_nentries - 1);
@@ -389,7 +389,7 @@ virtqueue_enqueue_recv_refill(struct virtqueue *vq, struct rte_mbuf **cookie,
 {
        struct vq_desc_extra *dxp;
        struct virtio_hw *hw = vq->hw;
-       struct vring_desc *start_dp = vq->vq_ring.desc;
+       struct vring_desc *start_dp = vq->vq_split.ring.desc;
        uint16_t idx, i;
 
        if (unlikely(vq->vq_free_cnt == 0))
@@ -430,8 +430,8 @@ static inline int
 virtqueue_enqueue_recv_refill_packed(struct virtqueue *vq,
                                     struct rte_mbuf **cookie, uint16_t num)
 {
-       struct vring_packed_desc *start_dp = vq->ring_packed.desc_packed;
-       uint16_t flags = VRING_DESC_F_WRITE | vq->avail_used_flags;
+       struct vring_packed_desc *start_dp = vq->vq_packed.ring.desc;
+       uint16_t flags = vq->vq_packed.cached_flags;
        struct virtio_hw *hw = vq->hw;
        struct vq_desc_extra *dxp;
        uint16_t idx;
@@ -460,11 +460,9 @@ virtqueue_enqueue_recv_refill_packed(struct virtqueue *vq,
                start_dp[idx].flags = flags;
                if (++vq->vq_avail_idx >= vq->vq_nentries) {
                        vq->vq_avail_idx -= vq->vq_nentries;
-                       vq->avail_wrap_counter ^= 1;
-                       vq->avail_used_flags =
-                               VRING_DESC_F_AVAIL(vq->avail_wrap_counter) |
-                               VRING_DESC_F_USED(!vq->avail_wrap_counter);
-                       flags = VRING_DESC_F_WRITE | vq->avail_used_flags;
+                       vq->vq_packed.cached_flags ^=
+                               VRING_PACKED_DESC_F_AVAIL_USED;
+                       flags = vq->vq_packed.cached_flags;
                }
        }
        vq->vq_free_cnt = (uint16_t)(vq->vq_free_cnt - num);
@@ -481,13 +479,14 @@ virtio_tso_fix_cksum(struct rte_mbuf *m)
        /* common case: header is not fragmented */
        if (likely(rte_pktmbuf_data_len(m) >= m->l2_len + m->l3_len +
                        m->l4_len)) {
-               struct ipv4_hdr *iph;
-               struct ipv6_hdr *ip6h;
-               struct tcp_hdr *th;
+               struct rte_ipv4_hdr *iph;
+               struct rte_ipv6_hdr *ip6h;
+               struct rte_tcp_hdr *th;
                uint16_t prev_cksum, new_cksum, ip_len, ip_paylen;
                uint32_t tmp;
 
-               iph = rte_pktmbuf_mtod_offset(m, struct ipv4_hdr *, m->l2_len);
+               iph = rte_pktmbuf_mtod_offset(m,
+                                       struct rte_ipv4_hdr *, m->l2_len);
                th = RTE_PTR_ADD(iph, m->l3_len);
                if ((iph->version_ihl >> 4) == 4) {
                        iph->hdr_checksum = 0;
@@ -496,7 +495,7 @@ virtio_tso_fix_cksum(struct rte_mbuf *m)
                        ip_paylen = rte_cpu_to_be_16(rte_be_to_cpu_16(ip_len) -
                                m->l3_len);
                } else {
-                       ip6h = (struct ipv6_hdr *)iph;
+                       ip6h = (struct rte_ipv6_hdr *)iph;
                        ip_paylen = ip6h->payload_len;
                }
 
@@ -540,14 +539,14 @@ virtqueue_xmit_offload(struct virtio_net_hdr *hdr,
                switch (cookie->ol_flags & PKT_TX_L4_MASK) {
                case PKT_TX_UDP_CKSUM:
                        hdr->csum_start = cookie->l2_len + cookie->l3_len;
-                       hdr->csum_offset = offsetof(struct udp_hdr,
+                       hdr->csum_offset = offsetof(struct rte_udp_hdr,
                                dgram_cksum);
                        hdr->flags = VIRTIO_NET_HDR_F_NEEDS_CSUM;
                        break;
 
                case PKT_TX_TCP_CKSUM:
                        hdr->csum_start = cookie->l2_len + cookie->l3_len;
-                       hdr->csum_offset = offsetof(struct tcp_hdr, cksum);
+                       hdr->csum_offset = offsetof(struct rte_tcp_hdr, cksum);
                        hdr->flags = VIRTIO_NET_HDR_F_NEEDS_CSUM;
                        break;
 
@@ -560,7 +559,6 @@ virtqueue_xmit_offload(struct virtio_net_hdr *hdr,
 
                /* TCP Segmentation Offload */
                if (cookie->ol_flags & PKT_TX_TCP_SEG) {
-                       virtio_tso_fix_cksum(cookie);
                        hdr->gso_type = (cookie->ol_flags & PKT_TX_IPV6) ?
                                VIRTIO_NET_HDR_GSO_TCPV6 :
                                VIRTIO_NET_HDR_GSO_TCPV4;
@@ -591,7 +589,7 @@ virtqueue_enqueue_xmit_inorder(struct virtnet_tx *txvq,
        uint16_t i = 0;
 
        idx = vq->vq_desc_head_idx;
-       start_dp = vq->vq_ring.desc;
+       start_dp = vq->vq_split.ring.desc;
 
        while (i < num) {
                idx = idx & (vq->vq_nentries - 1);
@@ -623,6 +621,60 @@ virtqueue_enqueue_xmit_inorder(struct virtnet_tx *txvq,
        vq->vq_desc_head_idx = idx & (vq->vq_nentries - 1);
 }
 
+static inline void
+virtqueue_enqueue_xmit_packed_fast(struct virtnet_tx *txvq,
+                                  struct rte_mbuf *cookie,
+                                  int in_order)
+{
+       struct virtqueue *vq = txvq->vq;
+       struct vring_packed_desc *dp;
+       struct vq_desc_extra *dxp;
+       uint16_t idx, id, flags;
+       uint16_t head_size = vq->hw->vtnet_hdr_size;
+       struct virtio_net_hdr *hdr;
+
+       id = in_order ? vq->vq_avail_idx : vq->vq_desc_head_idx;
+       idx = vq->vq_avail_idx;
+       dp = &vq->vq_packed.ring.desc[idx];
+
+       dxp = &vq->vq_descx[id];
+       dxp->ndescs = 1;
+       dxp->cookie = cookie;
+
+       flags = vq->vq_packed.cached_flags;
+
+       /* prepend cannot fail, checked by caller */
+       hdr = (struct virtio_net_hdr *)
+               rte_pktmbuf_prepend(cookie, head_size);
+       cookie->pkt_len -= head_size;
+
+       /* if offload disabled, hdr is not zeroed yet, do it now */
+       if (!vq->hw->has_tx_offload)
+               virtqueue_clear_net_hdr(hdr);
+       else
+               virtqueue_xmit_offload(hdr, cookie, true);
+
+       dp->addr = VIRTIO_MBUF_DATA_DMA_ADDR(cookie, vq);
+       dp->len  = cookie->data_len;
+       dp->id   = id;
+
+       if (++vq->vq_avail_idx >= vq->vq_nentries) {
+               vq->vq_avail_idx -= vq->vq_nentries;
+               vq->vq_packed.cached_flags ^= VRING_PACKED_DESC_F_AVAIL_USED;
+       }
+
+       vq->vq_free_cnt--;
+
+       if (!in_order) {
+               vq->vq_desc_head_idx = dxp->next;
+               if (vq->vq_desc_head_idx == VQ_RING_DESC_CHAIN_END)
+                       vq->vq_desc_tail_idx = VQ_RING_DESC_CHAIN_END;
+       }
+
+       virtio_wmb(vq->hw->weak_barriers);
+       dp->flags = flags;
+}
+
 static inline void
 virtqueue_enqueue_xmit_packed(struct virtnet_tx *txvq, struct rte_mbuf *cookie,
                              uint16_t needed, int can_push, int in_order)
@@ -645,11 +697,11 @@ virtqueue_enqueue_xmit_packed(struct virtnet_tx *txvq, struct rte_mbuf *cookie,
        head_idx = vq->vq_avail_idx;
        idx = head_idx;
        prev = head_idx;
-       start_dp = vq->ring_packed.desc_packed;
+       start_dp = vq->vq_packed.ring.desc;
 
-       head_dp = &vq->ring_packed.desc_packed[idx];
+       head_dp = &vq->vq_packed.ring.desc[idx];
        head_flags = cookie->next ? VRING_DESC_F_NEXT : 0;
-       head_flags |= vq->avail_used_flags;
+       head_flags |= vq->vq_packed.cached_flags;
 
        if (can_push) {
                /* prepend cannot fail, checked by caller */
@@ -674,10 +726,8 @@ virtqueue_enqueue_xmit_packed(struct virtnet_tx *txvq, struct rte_mbuf *cookie,
                idx++;
                if (idx >= vq->vq_nentries) {
                        idx -= vq->vq_nentries;
-                       vq->avail_wrap_counter ^= 1;
-                       vq->avail_used_flags =
-                               VRING_DESC_F_AVAIL(vq->avail_wrap_counter) |
-                               VRING_DESC_F_USED(!vq->avail_wrap_counter);
+                       vq->vq_packed.cached_flags ^=
+                               VRING_PACKED_DESC_F_AVAIL_USED;
                }
        }
 
@@ -690,17 +740,15 @@ virtqueue_enqueue_xmit_packed(struct virtnet_tx *txvq, struct rte_mbuf *cookie,
                start_dp[idx].len  = cookie->data_len;
                if (likely(idx != head_idx)) {
                        flags = cookie->next ? VRING_DESC_F_NEXT : 0;
-                       flags |= vq->avail_used_flags;
+                       flags |= vq->vq_packed.cached_flags;
                        start_dp[idx].flags = flags;
                }
                prev = idx;
                idx++;
                if (idx >= vq->vq_nentries) {
                        idx -= vq->vq_nentries;
-                       vq->avail_wrap_counter ^= 1;
-                       vq->avail_used_flags =
-                               VRING_DESC_F_AVAIL(vq->avail_wrap_counter) |
-                               VRING_DESC_F_USED(!vq->avail_wrap_counter);
+                       vq->vq_packed.cached_flags ^=
+                               VRING_PACKED_DESC_F_AVAIL_USED;
                }
        } while ((cookie = cookie->next) != NULL);
 
@@ -742,7 +790,7 @@ virtqueue_enqueue_xmit(struct virtnet_tx *txvq, struct rte_mbuf *cookie,
        dxp->cookie = (void *)cookie;
        dxp->ndescs = needed;
 
-       start_dp = vq->vq_ring.desc;
+       start_dp = vq->vq_split.ring.desc;
 
        if (can_push) {
                /* prepend cannot fail, checked by caller */
@@ -795,7 +843,7 @@ virtqueue_enqueue_xmit(struct virtnet_tx *txvq, struct rte_mbuf *cookie,
        } while ((cookie = cookie->next) != NULL);
 
        if (use_indirect)
-               idx = vq->vq_ring.desc[head_idx].next;
+               idx = vq->vq_split.ring.desc[head_idx].next;
 
        vq->vq_free_cnt = (uint16_t)(vq->vq_free_cnt - needed);
 
@@ -841,11 +889,6 @@ virtio_dev_rx_queue_setup(struct rte_eth_dev *dev,
        rxvq = &vq->rxq;
        rxvq->queue_id = queue_idx;
        rxvq->mpool = mp;
-       if (rxvq->mpool == NULL) {
-               rte_exit(EXIT_FAILURE,
-                       "Cannot allocate mbufs for rx virtqueue");
-       }
-
        dev->data->rx_queues[queue_idx] = rxvq;
 
        return 0;
@@ -870,8 +913,8 @@ virtio_dev_rx_queue_setup_finish(struct rte_eth_dev *dev, uint16_t queue_idx)
        if (hw->use_simple_rx) {
                for (desc_idx = 0; desc_idx < vq->vq_nentries;
                     desc_idx++) {
-                       vq->vq_ring.avail->ring[desc_idx] = desc_idx;
-                       vq->vq_ring.desc[desc_idx].flags =
+                       vq->vq_split.ring.avail->ring[desc_idx] = desc_idx;
+                       vq->vq_split.ring.desc[desc_idx].flags =
                                VRING_DESC_F_WRITE;
                }
 
@@ -1001,7 +1044,7 @@ virtio_dev_tx_queue_setup_finish(struct rte_eth_dev *dev,
 
        if (!vtpci_packed_queue(hw)) {
                if (hw->use_inorder_tx)
-                       vq->vq_ring.desc[vq->vq_nentries - 1].next = 0;
+                       vq->vq_split.ring.desc[vq->vq_nentries - 1].next = 0;
        }
 
        VIRTQUEUE_DUMP(vq);
@@ -1044,7 +1087,7 @@ static inline void
 virtio_update_packet_stats(struct virtnet_stats *stats, struct rte_mbuf *mbuf)
 {
        uint32_t s = mbuf->pkt_len;
-       struct ether_addr *ea;
+       struct rte_ether_addr *ea;
 
        stats->bytes += s;
 
@@ -1061,13 +1104,13 @@ virtio_update_packet_stats(struct virtnet_stats *stats, struct rte_mbuf *mbuf)
                        stats->size_bins[0]++;
                else if (s < 1519)
                        stats->size_bins[6]++;
-               else if (s >= 1519)
+               else
                        stats->size_bins[7]++;
        }
 
-       ea = rte_pktmbuf_mtod(mbuf, struct ether_addr *);
-       if (is_multicast_ether_addr(ea)) {
-               if (is_broadcast_ether_addr(ea))
+       ea = rte_pktmbuf_mtod(mbuf, struct rte_ether_addr *);
+       if (rte_is_multicast_ether_addr(ea)) {
+               if (rte_is_broadcast_ether_addr(ea))
                        stats->broadcast++;
                else
                        stats->multicast++;
@@ -1162,7 +1205,7 @@ virtio_recv_pkts(void *rx_queue, struct rte_mbuf **rx_pkts, uint16_t nb_pkts)
        struct virtnet_rx *rxvq = rx_queue;
        struct virtqueue *vq = rxvq->vq;
        struct virtio_hw *hw = vq->hw;
-       struct rte_mbuf *rxm, *new_mbuf;
+       struct rte_mbuf *rxm;
        uint16_t nb_used, num, nb_rx;
        uint32_t len[VIRTIO_MBUF_BURST_SZ];
        struct rte_mbuf *rcv_pkts[VIRTIO_MBUF_BURST_SZ];
@@ -1196,7 +1239,7 @@ virtio_recv_pkts(void *rx_queue, struct rte_mbuf **rx_pkts, uint16_t nb_pkts)
 
                PMD_RX_LOG(DEBUG, "packet len:%d", len[i]);
 
-               if (unlikely(len[i] < hdr_size + ETHER_HDR_LEN)) {
+               if (unlikely(len[i] < hdr_size + RTE_ETHER_HDR_LEN)) {
                        PMD_RX_LOG(ERR, "Packet drop");
                        nb_enqueued++;
                        virtio_discard_rxbuf(vq, rxm);
@@ -1232,20 +1275,24 @@ virtio_recv_pkts(void *rx_queue, struct rte_mbuf **rx_pkts, uint16_t nb_pkts)
        rxvq->stats.packets += nb_rx;
 
        /* Allocate new mbuf for the used descriptor */
-       while (likely(!virtqueue_full(vq))) {
-               new_mbuf = rte_mbuf_raw_alloc(rxvq->mpool);
-               if (unlikely(new_mbuf == NULL)) {
-                       struct rte_eth_dev *dev
-                               = &rte_eth_devices[rxvq->port_id];
-                       dev->data->rx_mbuf_alloc_failed++;
-                       break;
-               }
-               error = virtqueue_enqueue_recv_refill(vq, &new_mbuf, 1);
-               if (unlikely(error)) {
-                       rte_pktmbuf_free(new_mbuf);
-                       break;
+       if (likely(!virtqueue_full(vq))) {
+               uint16_t free_cnt = vq->vq_free_cnt;
+               struct rte_mbuf *new_pkts[free_cnt];
+
+               if (likely(rte_pktmbuf_alloc_bulk(rxvq->mpool, new_pkts,
+                                               free_cnt) == 0)) {
+                       error = virtqueue_enqueue_recv_refill(vq, new_pkts,
+                                       free_cnt);
+                       if (unlikely(error)) {
+                               for (i = 0; i < free_cnt; i++)
+                                       rte_pktmbuf_free(new_pkts[i]);
+                       }
+                       nb_enqueued += free_cnt;
+               } else {
+                       struct rte_eth_dev *dev =
+                               &rte_eth_devices[rxvq->port_id];
+                       dev->data->rx_mbuf_alloc_failed += free_cnt;
                }
-               nb_enqueued++;
        }
 
        if (likely(nb_enqueued)) {
@@ -1267,7 +1314,7 @@ virtio_recv_pkts_packed(void *rx_queue, struct rte_mbuf **rx_pkts,
        struct virtnet_rx *rxvq = rx_queue;
        struct virtqueue *vq = rxvq->vq;
        struct virtio_hw *hw = vq->hw;
-       struct rte_mbuf *rxm, *new_mbuf;
+       struct rte_mbuf *rxm;
        uint16_t num, nb_rx;
        uint32_t len[VIRTIO_MBUF_BURST_SZ];
        struct rte_mbuf *rcv_pkts[VIRTIO_MBUF_BURST_SZ];
@@ -1295,7 +1342,7 @@ virtio_recv_pkts_packed(void *rx_queue, struct rte_mbuf **rx_pkts,
 
                PMD_RX_LOG(DEBUG, "packet len:%d", len[i]);
 
-               if (unlikely(len[i] < hdr_size + ETHER_HDR_LEN)) {
+               if (unlikely(len[i] < hdr_size + RTE_ETHER_HDR_LEN)) {
                        PMD_RX_LOG(ERR, "Packet drop");
                        nb_enqueued++;
                        virtio_discard_rxbuf(vq, rxm);
@@ -1331,20 +1378,24 @@ virtio_recv_pkts_packed(void *rx_queue, struct rte_mbuf **rx_pkts,
        rxvq->stats.packets += nb_rx;
 
        /* Allocate new mbuf for the used descriptor */
-       while (likely(!virtqueue_full(vq))) {
-               new_mbuf = rte_mbuf_raw_alloc(rxvq->mpool);
-               if (unlikely(new_mbuf == NULL)) {
+       if (likely(!virtqueue_full(vq))) {
+               uint16_t free_cnt = vq->vq_free_cnt;
+               struct rte_mbuf *new_pkts[free_cnt];
+
+               if (likely(rte_pktmbuf_alloc_bulk(rxvq->mpool, new_pkts,
+                                               free_cnt) == 0)) {
+                       error = virtqueue_enqueue_recv_refill_packed(vq,
+                                       new_pkts, free_cnt);
+                       if (unlikely(error)) {
+                               for (i = 0; i < free_cnt; i++)
+                                       rte_pktmbuf_free(new_pkts[i]);
+                       }
+                       nb_enqueued += free_cnt;
+               } else {
                        struct rte_eth_dev *dev =
                                &rte_eth_devices[rxvq->port_id];
-                       dev->data->rx_mbuf_alloc_failed++;
-                       break;
-               }
-               error = virtqueue_enqueue_recv_refill_packed(vq, &new_mbuf, 1);
-               if (unlikely(error)) {
-                       rte_pktmbuf_free(new_mbuf);
-                       break;
+                       dev->data->rx_mbuf_alloc_failed += free_cnt;
                }
-               nb_enqueued++;
        }
 
        if (likely(nb_enqueued)) {
@@ -1367,7 +1418,7 @@ virtio_recv_pkts_inorder(void *rx_queue,
        struct virtqueue *vq = rxvq->vq;
        struct virtio_hw *hw = vq->hw;
        struct rte_mbuf *rxm;
-       struct rte_mbuf *prev;
+       struct rte_mbuf *prev = NULL;
        uint16_t nb_used, num, nb_rx;
        uint32_t len[VIRTIO_MBUF_BURST_SZ];
        struct rte_mbuf *rcv_pkts[VIRTIO_MBUF_BURST_SZ];
@@ -1405,7 +1456,7 @@ virtio_recv_pkts_inorder(void *rx_queue,
 
                rxm = rcv_pkts[i];
 
-               if (unlikely(len[i] < hdr_size + ETHER_HDR_LEN)) {
+               if (unlikely(len[i] < hdr_size + RTE_ETHER_HDR_LEN)) {
                        PMD_RX_LOG(ERR, "Packet drop");
                        nb_enqueued++;
                        virtio_discard_rxbuf_inorder(vq, rxm);
@@ -1459,11 +1510,8 @@ virtio_recv_pkts_inorder(void *rx_queue,
                        rxm->data_len = (uint16_t)(len[i]);
 
                        rx_pkts[nb_rx]->pkt_len += (uint32_t)(len[i]);
-                       rx_pkts[nb_rx]->data_len += (uint16_t)(len[i]);
-
-                       if (prev)
-                               prev->next = rxm;
 
+                       prev->next = rxm;
                        prev = rxm;
                        seg_res -= 1;
                }
@@ -1479,7 +1527,6 @@ virtio_recv_pkts_inorder(void *rx_queue,
                uint16_t rcv_cnt = RTE_MIN((uint16_t)seg_res,
                                        VIRTIO_MBUF_BURST_SZ);
 
-               prev = rcv_pkts[nb_rx];
                if (likely(VIRTQUEUE_NUSED(vq) >= rcv_cnt)) {
                        virtio_rmb(hw->weak_barriers);
                        num = virtqueue_dequeue_rx_inorder(vq, rcv_pkts, len,
@@ -1496,7 +1543,6 @@ virtio_recv_pkts_inorder(void *rx_queue,
                                prev->next = rxm;
                                prev = rxm;
                                rx_pkts[nb_rx]->pkt_len += len[extra_idx];
-                               rx_pkts[nb_rx]->data_len += len[extra_idx];
                                extra_idx += 1;
                        };
                        seg_res -= rcv_cnt;
@@ -1559,7 +1605,7 @@ virtio_recv_mergeable_pkts(void *rx_queue,
        struct virtqueue *vq = rxvq->vq;
        struct virtio_hw *hw = vq->hw;
        struct rte_mbuf *rxm;
-       struct rte_mbuf *prev;
+       struct rte_mbuf *prev = NULL;
        uint16_t nb_used, num, nb_rx = 0;
        uint32_t len[VIRTIO_MBUF_BURST_SZ];
        struct rte_mbuf *rcv_pkts[VIRTIO_MBUF_BURST_SZ];
@@ -1597,7 +1643,7 @@ virtio_recv_mergeable_pkts(void *rx_queue,
 
                rxm = rcv_pkts[i];
 
-               if (unlikely(len[i] < hdr_size + ETHER_HDR_LEN)) {
+               if (unlikely(len[i] < hdr_size + RTE_ETHER_HDR_LEN)) {
                        PMD_RX_LOG(ERR, "Packet drop");
                        nb_enqueued++;
                        virtio_discard_rxbuf(vq, rxm);
@@ -1646,11 +1692,8 @@ virtio_recv_mergeable_pkts(void *rx_queue,
                        rxm->data_len = (uint16_t)(len[i]);
 
                        rx_pkts[nb_rx]->pkt_len += (uint32_t)(len[i]);
-                       rx_pkts[nb_rx]->data_len += (uint16_t)(len[i]);
-
-                       if (prev)
-                               prev->next = rxm;
 
+                       prev->next = rxm;
                        prev = rxm;
                        seg_res -= 1;
                }
@@ -1666,7 +1709,6 @@ virtio_recv_mergeable_pkts(void *rx_queue,
                uint16_t rcv_cnt = RTE_MIN((uint16_t)seg_res,
                                        VIRTIO_MBUF_BURST_SZ);
 
-               prev = rcv_pkts[nb_rx];
                if (likely(VIRTQUEUE_NUSED(vq) >= rcv_cnt)) {
                        virtio_rmb(hw->weak_barriers);
                        num = virtqueue_dequeue_burst_rx(vq, rcv_pkts, len,
@@ -1683,7 +1725,6 @@ virtio_recv_mergeable_pkts(void *rx_queue,
                                prev->next = rxm;
                                prev = rxm;
                                rx_pkts[nb_rx]->pkt_len += len[extra_idx];
-                               rx_pkts[nb_rx]->data_len += len[extra_idx];
                                extra_idx += 1;
                        };
                        seg_res -= rcv_cnt;
@@ -1776,7 +1817,7 @@ virtio_recv_mergeable_pkts_packed(void *rx_queue,
 
                rxm = rcv_pkts[i];
 
-               if (unlikely(len[i] < hdr_size + ETHER_HDR_LEN)) {
+               if (unlikely(len[i] < hdr_size + RTE_ETHER_HDR_LEN)) {
                        PMD_RX_LOG(ERR, "Packet drop");
                        nb_enqueued++;
                        virtio_discard_rxbuf(vq, rxm);
@@ -1824,11 +1865,8 @@ virtio_recv_mergeable_pkts_packed(void *rx_queue,
                        rxm->data_len = (uint16_t)(len[i]);
 
                        rx_pkts[nb_rx]->pkt_len += (uint32_t)(len[i]);
-                       rx_pkts[nb_rx]->data_len += (uint16_t)(len[i]);
-
-                       if (prev)
-                               prev->next = rxm;
 
+                       prev->next = rxm;
                        prev = rxm;
                        seg_res -= 1;
                }
@@ -1861,7 +1899,6 @@ virtio_recv_mergeable_pkts_packed(void *rx_queue,
                                prev->next = rxm;
                                prev = rxm;
                                rx_pkts[nb_rx]->pkt_len += len[extra_idx];
-                               rx_pkts[nb_rx]->data_len += len[extra_idx];
                                extra_idx += 1;
                        }
                        seg_res -= rcv_cnt;
@@ -1872,8 +1909,7 @@ virtio_recv_mergeable_pkts_packed(void *rx_queue,
                } else {
                        PMD_RX_LOG(ERR,
                                        "No enough segments for packet.");
-                       if (prev)
-                               virtio_discard_rxbuf(vq, prev);
+                       virtio_discard_rxbuf(vq, prev);
                        rxvq->stats.errors++;
                        break;
                }
@@ -1912,6 +1948,51 @@ virtio_recv_mergeable_pkts_packed(void *rx_queue,
        return nb_rx;
 }
 
+uint16_t
+virtio_xmit_pkts_prepare(void *tx_queue __rte_unused, struct rte_mbuf **tx_pkts,
+                       uint16_t nb_pkts)
+{
+       uint16_t nb_tx;
+       int error;
+
+       for (nb_tx = 0; nb_tx < nb_pkts; nb_tx++) {
+               struct rte_mbuf *m = tx_pkts[nb_tx];
+
+#ifdef RTE_LIBRTE_ETHDEV_DEBUG
+               error = rte_validate_tx_offload(m);
+               if (unlikely(error)) {
+                       rte_errno = -error;
+                       break;
+               }
+#endif
+
+               /* Do VLAN tag insertion */
+               if (unlikely(m->ol_flags & PKT_TX_VLAN_PKT)) {
+                       error = rte_vlan_insert(&m);
+                       /* rte_vlan_insert() may change pointer
+                        * even in the case of failure
+                        */
+                       tx_pkts[nb_tx] = m;
+
+                       if (unlikely(error)) {
+                               rte_errno = -error;
+                               break;
+                       }
+               }
+
+               error = rte_net_intel_cksum_prepare(m);
+               if (unlikely(error)) {
+                       rte_errno = -error;
+                       break;
+               }
+
+               if (m->ol_flags & PKT_TX_TCP_SEG)
+                       virtio_tso_fix_cksum(m);
+       }
+
+       return nb_tx;
+}
+
 uint16_t
 virtio_xmit_pkts_packed(void *tx_queue, struct rte_mbuf **tx_pkts,
                        uint16_t nb_pkts)
@@ -1922,7 +2003,6 @@ virtio_xmit_pkts_packed(void *tx_queue, struct rte_mbuf **tx_pkts,
        uint16_t hdr_size = hw->vtnet_hdr_size;
        uint16_t nb_tx = 0;
        bool in_order = hw->use_inorder_tx;
-       int error;
 
        if (unlikely(hw->started == 0 && tx_pkts != hw->inject_pkts))
                return nb_tx;
@@ -1940,15 +2020,6 @@ virtio_xmit_pkts_packed(void *tx_queue, struct rte_mbuf **tx_pkts,
                struct rte_mbuf *txm = tx_pkts[nb_tx];
                int can_push = 0, slots, need;
 
-               /* Do VLAN tag insertion */
-               if (unlikely(txm->ol_flags & PKT_TX_VLAN_PKT)) {
-                       error = rte_vlan_insert(&txm);
-                       if (unlikely(error)) {
-                               rte_pktmbuf_free(txm);
-                               continue;
-                       }
-               }
-
                /* optimize ring usage */
                if ((vtpci_with_feature(hw, VIRTIO_F_ANY_LAYOUT) ||
                      vtpci_with_feature(hw, VIRTIO_F_VERSION_1)) &&
@@ -1979,8 +2050,11 @@ virtio_xmit_pkts_packed(void *tx_queue, struct rte_mbuf **tx_pkts,
                }
 
                /* Enqueue Packet buffers */
-               virtqueue_enqueue_xmit_packed(txvq, txm, slots, can_push,
-                                             in_order);
+               if (can_push)
+                       virtqueue_enqueue_xmit_packed_fast(txvq, txm, in_order);
+               else
+                       virtqueue_enqueue_xmit_packed(txvq, txm, slots, 0,
+                                                     in_order);
 
                virtio_update_packet_stats(&txvq->stats, txm);
        }
@@ -2005,7 +2079,6 @@ virtio_xmit_pkts(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkts)
        struct virtio_hw *hw = vq->hw;
        uint16_t hdr_size = hw->vtnet_hdr_size;
        uint16_t nb_used, nb_tx = 0;
-       int error;
 
        if (unlikely(hw->started == 0 && tx_pkts != hw->inject_pkts))
                return nb_tx;
@@ -2024,15 +2097,6 @@ virtio_xmit_pkts(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkts)
                struct rte_mbuf *txm = tx_pkts[nb_tx];
                int can_push = 0, use_indirect = 0, slots, need;
 
-               /* Do VLAN tag insertion */
-               if (unlikely(txm->ol_flags & PKT_TX_VLAN_PKT)) {
-                       error = rte_vlan_insert(&txm);
-                       if (unlikely(error)) {
-                               rte_pktmbuf_free(txm);
-                               continue;
-                       }
-               }
-
                /* optimize ring usage */
                if ((vtpci_with_feature(hw, VIRTIO_F_ANY_LAYOUT) ||
                      vtpci_with_feature(hw, VIRTIO_F_VERSION_1)) &&
@@ -2102,7 +2166,6 @@ virtio_xmit_pkts_inorder(void *tx_queue,
        uint16_t hdr_size = hw->vtnet_hdr_size;
        uint16_t nb_used, nb_avail, nb_tx = 0, nb_inorder_pkts = 0;
        struct rte_mbuf *inorder_pkts[nb_pkts];
-       int error;
 
        if (unlikely(hw->started == 0 && tx_pkts != hw->inject_pkts))
                return nb_tx;
@@ -2127,15 +2190,6 @@ virtio_xmit_pkts_inorder(void *tx_queue,
                struct rte_mbuf *txm = tx_pkts[nb_tx];
                int slots, need;
 
-               /* Do VLAN tag insertion */
-               if (unlikely(txm->ol_flags & PKT_TX_VLAN_PKT)) {
-                       error = rte_vlan_insert(&txm);
-                       if (unlikely(error)) {
-                               rte_pktmbuf_free(txm);
-                               continue;
-                       }
-               }
-
                /* optimize ring usage */
                if ((vtpci_with_feature(hw, VIRTIO_F_ANY_LAYOUT) ||
                     vtpci_with_feature(hw, VIRTIO_F_VERSION_1)) &&