X-Git-Url: http://git.droids-corp.org/?a=blobdiff_plain;f=drivers%2Fnet%2Fvirtio%2Fvirtio_rxtx.c;h=27ead19fbe81d12b96186698d38933376b79e890;hb=8ac3591694e105d47968f5f29b8c19511f21e41c;hp=ebb86ef7005d5bf42ac89dcae97139cf0b73ab0c;hpb=9230ab8d791399179498d42dfd84981c5bba412a;p=dpdk.git diff --git a/drivers/net/virtio/virtio_rxtx.c b/drivers/net/virtio/virtio_rxtx.c index ebb86ef700..27ead19fbe 100644 --- a/drivers/net/virtio/virtio_rxtx.c +++ b/drivers/net/virtio/virtio_rxtx.c @@ -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,12 +118,13 @@ 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; if (!desc_is_used(&desc[used_idx], vq)) return i; + virtio_rmb(vq->hw->weak_barriers); len[i] = desc[used_idx].len; id = desc[used_idx].id; cookie = (struct rte_mbuf *)vq->vq_descx[id].cookie; @@ -140,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; } } @@ -159,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; @@ -198,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; @@ -223,24 +224,55 @@ virtqueue_dequeue_rx_inorder(struct virtqueue *vq, #define DEFAULT_TX_FREE_THRESH 32 #endif -/* Cleanup from completed transmits. */ static void -virtio_xmit_cleanup_packed(struct virtqueue *vq, int num) +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->vq_packed.ring.desc; + struct vq_desc_extra *dxp; + + used_idx = vq->vq_used_cons_idx; + while (num > 0 && desc_is_used(&desc[used_idx], vq)) { + virtio_rmb(vq->hw->weak_barriers); + id = desc[used_idx].id; + do { + curr_id = used_idx; + dxp = &vq->vq_descx[used_idx]; + used_idx += dxp->ndescs; + free_cnt += dxp->ndescs; + num -= dxp->ndescs; + if (used_idx >= size) { + used_idx -= size; + vq->vq_packed.used_wrap_counter ^= 1; + } + if (dxp->cookie != NULL) { + rte_pktmbuf_free(dxp->cookie); + dxp->cookie = NULL; + } + } while (curr_id != id); + } + vq->vq_used_cons_idx = used_idx; + vq->vq_free_cnt += free_cnt; +} + +static void +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; while (num-- && desc_is_used(&desc[used_idx], vq)) { - used_idx = vq->vq_used_cons_idx; + virtio_rmb(vq->hw->weak_barriers); id = desc[used_idx].id; dxp = &vq->vq_descx[id]; 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) { @@ -251,6 +283,16 @@ virtio_xmit_cleanup_packed(struct virtqueue *vq, int num) } } +/* Cleanup from completed transmits. */ +static inline void +virtio_xmit_cleanup_packed(struct virtqueue *vq, int num, int in_order) +{ + if (in_order) + virtio_xmit_cleanup_inorder_packed(vq, num); + else + virtio_xmit_cleanup_normal_packed(vq, num); +} + static void virtio_xmit_cleanup(struct virtqueue *vq, uint16_t num) { @@ -260,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]; @@ -278,7 +320,7 @@ virtio_xmit_cleanup(struct virtqueue *vq, uint16_t num) static void virtio_xmit_cleanup_inorder(struct virtqueue *vq, uint16_t num) { - uint16_t i, used_idx, desc_idx = 0, last_idx; + uint16_t i, idx = vq->vq_used_cons_idx; int16_t free_cnt = 0; struct vq_desc_extra *dxp = NULL; @@ -286,27 +328,16 @@ virtio_xmit_cleanup_inorder(struct virtqueue *vq, uint16_t num) return; for (i = 0; i < num; i++) { - struct vring_used_elem *uep; - - used_idx = vq->vq_used_cons_idx & (vq->vq_nentries - 1); - uep = &vq->vq_ring.used->ring[used_idx]; - desc_idx = (uint16_t)uep->id; - - dxp = &vq->vq_descx[desc_idx]; - vq->vq_used_cons_idx++; - + dxp = &vq->vq_descx[idx++ & (vq->vq_nentries - 1)]; + free_cnt += dxp->ndescs; if (dxp->cookie != NULL) { rte_pktmbuf_free(dxp->cookie); dxp->cookie = NULL; } } - last_idx = desc_idx + dxp->ndescs - 1; - free_cnt = last_idx - vq->vq_desc_tail_idx; - if (free_cnt <= 0) - free_cnt += vq->vq_nentries; - - vq_ring_free_inorder(vq, last_idx, free_cnt); + vq->vq_free_cnt += free_cnt; + vq->vq_used_cons_idx = idx; } static inline int @@ -325,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); @@ -358,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)) @@ -399,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; @@ -425,15 +456,13 @@ virtqueue_enqueue_recv_refill_packed(struct virtqueue *vq, vq->vq_desc_head_idx = dxp->next; if (vq->vq_desc_head_idx == VQ_RING_DESC_CHAIN_END) vq->vq_desc_tail_idx = vq->vq_desc_head_idx; - rte_smp_wmb(); + virtio_wmb(hw->weak_barriers); 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); @@ -450,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; @@ -465,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; } @@ -488,6 +518,15 @@ virtio_tso_fix_cksum(struct rte_mbuf *m) (var) = (val); \ } while (0) +#define virtqueue_clear_net_hdr(_hdr) do { \ + ASSIGN_UNLESS_EQUAL((_hdr)->csum_start, 0); \ + ASSIGN_UNLESS_EQUAL((_hdr)->csum_offset, 0); \ + ASSIGN_UNLESS_EQUAL((_hdr)->flags, 0); \ + ASSIGN_UNLESS_EQUAL((_hdr)->gso_type, 0); \ + ASSIGN_UNLESS_EQUAL((_hdr)->gso_size, 0); \ + ASSIGN_UNLESS_EQUAL((_hdr)->hdr_len, 0); \ +} while (0) + static inline void virtqueue_xmit_offload(struct virtio_net_hdr *hdr, struct rte_mbuf *cookie, @@ -500,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; @@ -520,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; @@ -551,11 +589,11 @@ 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); - dxp = &vq->vq_descx[idx]; + dxp = &vq->vq_descx[vq->vq_avail_idx & (vq->vq_nentries - 1)]; dxp->cookie = (void *)cookies[i]; dxp->ndescs = 1; @@ -563,18 +601,11 @@ virtqueue_enqueue_xmit_inorder(struct virtnet_tx *txvq, rte_pktmbuf_prepend(cookies[i], head_size); cookies[i]->pkt_len -= head_size; - /* if offload disabled, it is not zeroed below, do it now */ - if (!vq->hw->has_tx_offload) { - ASSIGN_UNLESS_EQUAL(hdr->csum_start, 0); - ASSIGN_UNLESS_EQUAL(hdr->csum_offset, 0); - ASSIGN_UNLESS_EQUAL(hdr->flags, 0); - ASSIGN_UNLESS_EQUAL(hdr->gso_type, 0); - ASSIGN_UNLESS_EQUAL(hdr->gso_size, 0); - ASSIGN_UNLESS_EQUAL(hdr->hdr_len, 0); - } - - virtqueue_xmit_offload(hdr, cookies[i], - vq->hw->has_tx_offload); + /* 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, cookies[i], true); start_dp[idx].addr = VIRTIO_MBUF_DATA_DMA_ADDR(cookies[i], vq); start_dp[idx].len = cookies[i]->data_len; @@ -590,9 +621,63 @@ 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) + uint16_t needed, int can_push, int in_order) { struct virtio_tx_region *txr = txvq->virtio_net_hdr_mz->addr; struct vq_desc_extra *dxp; @@ -603,7 +688,7 @@ virtqueue_enqueue_xmit_packed(struct virtnet_tx *txvq, struct rte_mbuf *cookie, struct virtio_net_hdr *hdr; uint16_t prev; - id = vq->vq_desc_head_idx; + id = in_order ? vq->vq_avail_idx : vq->vq_desc_head_idx; dxp = &vq->vq_descx[id]; dxp->ndescs = needed; @@ -612,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 */ @@ -628,14 +713,8 @@ virtqueue_enqueue_xmit_packed(struct virtnet_tx *txvq, struct rte_mbuf *cookie, cookie->pkt_len -= head_size; /* if offload disabled, it is not zeroed below, do it now */ - if (!vq->hw->has_tx_offload) { - ASSIGN_UNLESS_EQUAL(hdr->csum_start, 0); - ASSIGN_UNLESS_EQUAL(hdr->csum_offset, 0); - ASSIGN_UNLESS_EQUAL(hdr->flags, 0); - ASSIGN_UNLESS_EQUAL(hdr->gso_type, 0); - ASSIGN_UNLESS_EQUAL(hdr->gso_size, 0); - ASSIGN_UNLESS_EQUAL(hdr->hdr_len, 0); - } + if (!vq->hw->has_tx_offload) + virtqueue_clear_net_hdr(hdr); } else { /* setup first tx ring slot to point to header * stored in reserved region. @@ -647,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; } } @@ -663,31 +740,30 @@ 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); start_dp[prev].id = id; vq->vq_free_cnt = (uint16_t)(vq->vq_free_cnt - needed); - - 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; - vq->vq_avail_idx = idx; - rte_smp_wmb(); + 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); head_dp->flags = head_flags; } @@ -707,11 +783,14 @@ virtqueue_enqueue_xmit(struct virtnet_tx *txvq, struct rte_mbuf *cookie, head_idx = vq->vq_desc_head_idx; idx = head_idx; - dxp = &vq->vq_descx[idx]; + if (in_order) + dxp = &vq->vq_descx[vq->vq_avail_idx & (vq->vq_nentries - 1)]; + else + dxp = &vq->vq_descx[idx]; 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 */ @@ -723,14 +802,8 @@ virtqueue_enqueue_xmit(struct virtnet_tx *txvq, struct rte_mbuf *cookie, cookie->pkt_len -= head_size; /* if offload disabled, it is not zeroed below, do it now */ - if (!vq->hw->has_tx_offload) { - ASSIGN_UNLESS_EQUAL(hdr->csum_start, 0); - ASSIGN_UNLESS_EQUAL(hdr->csum_offset, 0); - ASSIGN_UNLESS_EQUAL(hdr->flags, 0); - ASSIGN_UNLESS_EQUAL(hdr->gso_type, 0); - ASSIGN_UNLESS_EQUAL(hdr->gso_size, 0); - ASSIGN_UNLESS_EQUAL(hdr->hdr_len, 0); - } + if (!vq->hw->has_tx_offload) + virtqueue_clear_net_hdr(hdr); } else if (use_indirect) { /* setup tx ring slot to point to indirect * descriptor list stored in reserved region. @@ -770,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); @@ -816,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; @@ -845,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; } @@ -976,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); @@ -1019,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; @@ -1036,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++; @@ -1137,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]; @@ -1171,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); @@ -1207,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)) { @@ -1242,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]; @@ -1270,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); @@ -1306,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)) { @@ -1342,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]; @@ -1380,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); @@ -1434,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; } @@ -1454,8 +1527,8 @@ 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, rcv_cnt); uint16_t extra_idx = 0; @@ -1470,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; @@ -1482,7 +1554,7 @@ virtio_recv_pkts_inorder(void *rx_queue, } else { PMD_RX_LOG(ERR, "No enough segments for packet."); - virtio_discard_rxbuf_inorder(vq, prev); + rte_pktmbuf_free(rx_pkts[nb_rx]); rxvq->stats.errors++; break; } @@ -1533,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]; @@ -1571,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); @@ -1620,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; } @@ -1640,8 +1709,8 @@ 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, rcv_cnt); uint16_t extra_idx = 0; @@ -1656,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; @@ -1668,7 +1736,7 @@ virtio_recv_mergeable_pkts(void *rx_queue, } else { PMD_RX_LOG(ERR, "No enough segments for packet."); - virtio_discard_rxbuf(vq, prev); + rte_pktmbuf_free(rx_pkts[nb_rx]); rxvq->stats.errors++; break; } @@ -1749,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); @@ -1797,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; } @@ -1816,39 +1881,33 @@ virtio_recv_mergeable_pkts_packed(void *rx_queue, while (seg_res != 0) { uint16_t rcv_cnt = RTE_MIN((uint16_t)seg_res, VIRTIO_MBUF_BURST_SZ); - if (likely(vq->vq_free_cnt >= rcv_cnt)) { - num = virtqueue_dequeue_burst_rx_packed(vq, rcv_pkts, - len, rcv_cnt); - uint16_t extra_idx = 0; + uint16_t extra_idx = 0; - rcv_cnt = num; + rcv_cnt = virtqueue_dequeue_burst_rx_packed(vq, rcv_pkts, + len, rcv_cnt); + if (unlikely(rcv_cnt == 0)) { + PMD_RX_LOG(ERR, "No enough segments for packet."); + rte_pktmbuf_free(rx_pkts[nb_rx]); + rxvq->stats.errors++; + break; + } - while (extra_idx < rcv_cnt) { - rxm = rcv_pkts[extra_idx]; + while (extra_idx < rcv_cnt) { + rxm = rcv_pkts[extra_idx]; - rxm->data_off = - RTE_PKTMBUF_HEADROOM - hdr_size; - rxm->pkt_len = (uint32_t)(len[extra_idx]); - rxm->data_len = (uint16_t)(len[extra_idx]); + rxm->data_off = RTE_PKTMBUF_HEADROOM - hdr_size; + rxm->pkt_len = (uint32_t)(len[extra_idx]); + rxm->data_len = (uint16_t)(len[extra_idx]); - 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; - if (!seg_res) { - virtio_rx_stats_updated(rxvq, rx_pkts[nb_rx]); - nb_rx++; - } - } else { - PMD_RX_LOG(ERR, - "No enough segments for packet."); - if (prev) - virtio_discard_rxbuf(vq, prev); - rxvq->stats.errors++; - break; + prev->next = rxm; + prev = rxm; + rx_pkts[nb_rx]->pkt_len += len[extra_idx]; + extra_idx += 1; + } + seg_res -= rcv_cnt; + if (!seg_res) { + virtio_rx_stats_updated(rxvq, rx_pkts[nb_rx]); + nb_rx++; } } @@ -1885,6 +1944,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) @@ -1894,7 +1998,7 @@ virtio_xmit_pkts_packed(void *tx_queue, struct rte_mbuf **tx_pkts, struct virtio_hw *hw = vq->hw; uint16_t hdr_size = hw->vtnet_hdr_size; uint16_t nb_tx = 0; - int error; + bool in_order = hw->use_inorder_tx; if (unlikely(hw->started == 0 && tx_pkts != hw->inject_pkts)) return nb_tx; @@ -1905,21 +2009,13 @@ virtio_xmit_pkts_packed(void *tx_queue, struct rte_mbuf **tx_pkts, PMD_TX_LOG(DEBUG, "%d packets to xmit", nb_pkts); if (nb_pkts > vq->vq_free_cnt) - virtio_xmit_cleanup_packed(vq, nb_pkts - vq->vq_free_cnt); + virtio_xmit_cleanup_packed(vq, nb_pkts - vq->vq_free_cnt, + in_order); for (nb_tx = 0; nb_tx < nb_pkts; nb_tx++) { 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)) && @@ -1940,9 +2036,7 @@ virtio_xmit_pkts_packed(void *tx_queue, struct rte_mbuf **tx_pkts, /* Positive value indicates it need free vring descriptors */ if (unlikely(need > 0)) { - virtio_rmb(hw->weak_barriers); - need = RTE_MIN(need, (int)nb_pkts); - virtio_xmit_cleanup_packed(vq, need); + virtio_xmit_cleanup_packed(vq, need, in_order); need = slots - vq->vq_free_cnt; if (unlikely(need > 0)) { PMD_TX_LOG(ERR, @@ -1952,7 +2046,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); + 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); } @@ -1977,7 +2075,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; @@ -1996,15 +2093,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)) && @@ -2074,7 +2162,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; @@ -2099,15 +2186,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)) &&