xref: /dpdk/drivers/net/virtio/virtqueue.h (revision 8410c369b452439b75c27b76589b9ca84f3347ab)
15566a3e3SBruce Richardson /* SPDX-License-Identifier: BSD-3-Clause
25566a3e3SBruce Richardson  * Copyright(c) 2010-2014 Intel Corporation
36c3169a3SBruce Richardson  */
46c3169a3SBruce Richardson 
56c3169a3SBruce Richardson #ifndef _VIRTQUEUE_H_
66c3169a3SBruce Richardson #define _VIRTQUEUE_H_
76c3169a3SBruce Richardson 
86c3169a3SBruce Richardson #include <stdint.h>
96c3169a3SBruce Richardson 
106c3169a3SBruce Richardson #include <rte_atomic.h>
116c3169a3SBruce Richardson #include <rte_memory.h>
126c3169a3SBruce Richardson #include <rte_mempool.h>
1357f90f89SMarvin Liu #include <rte_net.h>
146c3169a3SBruce Richardson 
156c3169a3SBruce Richardson #include "virtio_pci.h"
166c3169a3SBruce Richardson #include "virtio_ring.h"
176c3169a3SBruce Richardson #include "virtio_logs.h"
18905a2469SYuanhan Liu #include "virtio_rxtx.h"
196c3169a3SBruce Richardson 
206c3169a3SBruce Richardson struct rte_mbuf;
216c3169a3SBruce Richardson 
2257f90f89SMarvin Liu #define DEFAULT_TX_FREE_THRESH 32
231982462eSMarvin Liu #define DEFAULT_RX_FREE_THRESH 32
241982462eSMarvin Liu 
2557f90f89SMarvin Liu #define VIRTIO_MBUF_BURST_SZ 64
266c3169a3SBruce Richardson /*
279230ab8dSIlya Maximets  * Per virtio_ring.h in Linux.
286c3169a3SBruce Richardson  *     For virtio_pci on SMP, we don't need to order with respect to MMIO
296c3169a3SBruce Richardson  *     accesses through relaxed memory I/O windows, so smp_mb() et al are
306c3169a3SBruce Richardson  *     sufficient.
316c3169a3SBruce Richardson  *
329230ab8dSIlya Maximets  *     For using virtio to talk to real devices (eg. vDPA) we do need real
339230ab8dSIlya Maximets  *     barriers.
346c3169a3SBruce Richardson  */
359230ab8dSIlya Maximets static inline void
369230ab8dSIlya Maximets virtio_mb(uint8_t weak_barriers)
379230ab8dSIlya Maximets {
389230ab8dSIlya Maximets 	if (weak_barriers)
399230ab8dSIlya Maximets 		rte_smp_mb();
409230ab8dSIlya Maximets 	else
419230ab8dSIlya Maximets 		rte_mb();
429230ab8dSIlya Maximets }
439230ab8dSIlya Maximets 
449230ab8dSIlya Maximets static inline void
459230ab8dSIlya Maximets virtio_rmb(uint8_t weak_barriers)
469230ab8dSIlya Maximets {
479230ab8dSIlya Maximets 	if (weak_barriers)
489230ab8dSIlya Maximets 		rte_smp_rmb();
499230ab8dSIlya Maximets 	else
50f0f5d844SPhil Yang 		rte_io_rmb();
519230ab8dSIlya Maximets }
529230ab8dSIlya Maximets 
539230ab8dSIlya Maximets static inline void
549230ab8dSIlya Maximets virtio_wmb(uint8_t weak_barriers)
559230ab8dSIlya Maximets {
569230ab8dSIlya Maximets 	if (weak_barriers)
579230ab8dSIlya Maximets 		rte_smp_wmb();
589230ab8dSIlya Maximets 	else
59f0f5d844SPhil Yang 		rte_io_wmb();
609230ab8dSIlya Maximets }
616c3169a3SBruce Richardson 
622c661d41SJoyce Kong static inline uint16_t
632c661d41SJoyce Kong virtqueue_fetch_flags_packed(struct vring_packed_desc *dp,
642c661d41SJoyce Kong 			      uint8_t weak_barriers)
652c661d41SJoyce Kong {
662c661d41SJoyce Kong 	uint16_t flags;
672c661d41SJoyce Kong 
682c661d41SJoyce Kong 	if (weak_barriers) {
692c661d41SJoyce Kong /* x86 prefers to using rte_smp_rmb over __atomic_load_n as it reports
702c661d41SJoyce Kong  * a better perf(~1.5%), which comes from the saved branch by the compiler.
71f0f5d844SPhil Yang  * The if and else branch are identical with the smp and io barriers both
722c661d41SJoyce Kong  * defined as compiler barriers on x86.
732c661d41SJoyce Kong  */
742c661d41SJoyce Kong #ifdef RTE_ARCH_X86_64
752c661d41SJoyce Kong 		flags = dp->flags;
762c661d41SJoyce Kong 		rte_smp_rmb();
772c661d41SJoyce Kong #else
782c661d41SJoyce Kong 		flags = __atomic_load_n(&dp->flags, __ATOMIC_ACQUIRE);
792c661d41SJoyce Kong #endif
802c661d41SJoyce Kong 	} else {
812c661d41SJoyce Kong 		flags = dp->flags;
82f0f5d844SPhil Yang 		rte_io_rmb();
832c661d41SJoyce Kong 	}
842c661d41SJoyce Kong 
852c661d41SJoyce Kong 	return flags;
862c661d41SJoyce Kong }
872c661d41SJoyce Kong 
886094557dSJoyce Kong static inline void
896094557dSJoyce Kong virtqueue_store_flags_packed(struct vring_packed_desc *dp,
906094557dSJoyce Kong 			      uint16_t flags, uint8_t weak_barriers)
916094557dSJoyce Kong {
926094557dSJoyce Kong 	if (weak_barriers) {
936094557dSJoyce Kong /* x86 prefers to using rte_smp_wmb over __atomic_store_n as it reports
946094557dSJoyce Kong  * a better perf(~1.5%), which comes from the saved branch by the compiler.
95f0f5d844SPhil Yang  * The if and else branch are identical with the smp and io barriers both
966094557dSJoyce Kong  * defined as compiler barriers on x86.
976094557dSJoyce Kong  */
986094557dSJoyce Kong #ifdef RTE_ARCH_X86_64
996094557dSJoyce Kong 		rte_smp_wmb();
1006094557dSJoyce Kong 		dp->flags = flags;
1016094557dSJoyce Kong #else
1026094557dSJoyce Kong 		__atomic_store_n(&dp->flags, flags, __ATOMIC_RELEASE);
1036094557dSJoyce Kong #endif
1046094557dSJoyce Kong 	} else {
105f0f5d844SPhil Yang 		rte_io_wmb();
1066094557dSJoyce Kong 		dp->flags = flags;
1076094557dSJoyce Kong 	}
1086094557dSJoyce Kong }
1096c3169a3SBruce Richardson #ifdef RTE_PMD_PACKET_PREFETCH
1106c3169a3SBruce Richardson #define rte_packet_prefetch(p)  rte_prefetch1(p)
1116c3169a3SBruce Richardson #else
1126c3169a3SBruce Richardson #define rte_packet_prefetch(p)  do {} while(0)
1136c3169a3SBruce Richardson #endif
1146c3169a3SBruce Richardson 
1156c3169a3SBruce Richardson #define VIRTQUEUE_MAX_NAME_SZ 32
1166c3169a3SBruce Richardson 
117f24f8f9fSJianfeng Tan #ifdef RTE_VIRTIO_USER
11825f80d10SOlivier Matz /**
11925f80d10SOlivier Matz  * Return the physical address (or virtual address in case of
12025f80d10SOlivier Matz  * virtio-user) of mbuf data buffer.
121260aae9aSJianfeng Tan  *
122260aae9aSJianfeng Tan  * The address is firstly casted to the word size (sizeof(uintptr_t))
123260aae9aSJianfeng Tan  * before casting it to uint64_t. This is to make it work with different
124260aae9aSJianfeng Tan  * combination of word size (64 bit and 32 bit) and virtio device
125260aae9aSJianfeng Tan  * (virtio-pci and virtio-user).
12625f80d10SOlivier Matz  */
127260aae9aSJianfeng Tan #define VIRTIO_MBUF_ADDR(mb, vq) \
128260aae9aSJianfeng Tan 	((uint64_t)(*(uintptr_t *)((uintptr_t)(mb) + (vq)->offset)))
12925f80d10SOlivier Matz #else
130455da545SSantosh Shukla #define VIRTIO_MBUF_ADDR(mb, vq) ((mb)->buf_iova)
13125f80d10SOlivier Matz #endif
13225f80d10SOlivier Matz 
13325f80d10SOlivier Matz /**
13425f80d10SOlivier Matz  * Return the physical address (or virtual address in case of
13525f80d10SOlivier Matz  * virtio-user) of mbuf data buffer, taking care of mbuf data offset
13625f80d10SOlivier Matz  */
13725f80d10SOlivier Matz #define VIRTIO_MBUF_DATA_DMA_ADDR(mb, vq) \
13825f80d10SOlivier Matz 	(VIRTIO_MBUF_ADDR(mb, vq) + (mb)->data_off)
139f24f8f9fSJianfeng Tan 
1406c3169a3SBruce Richardson #define VTNET_SQ_RQ_QUEUE_IDX 0
1416c3169a3SBruce Richardson #define VTNET_SQ_TQ_QUEUE_IDX 1
1426c3169a3SBruce Richardson #define VTNET_SQ_CQ_QUEUE_IDX 2
1436c3169a3SBruce Richardson 
1446c3169a3SBruce Richardson enum { VTNET_RQ = 0, VTNET_TQ = 1, VTNET_CQ = 2 };
1456c3169a3SBruce Richardson /**
1466c3169a3SBruce Richardson  * The maximum virtqueue size is 2^15. Use that value as the end of
1476c3169a3SBruce Richardson  * descriptor chain terminator since it will never be a valid index
1486c3169a3SBruce Richardson  * in the descriptor table. This is used to verify we are correctly
1496c3169a3SBruce Richardson  * handling vq_free_cnt.
1506c3169a3SBruce Richardson  */
1516c3169a3SBruce Richardson #define VQ_RING_DESC_CHAIN_END 32768
1526c3169a3SBruce Richardson 
1536c3169a3SBruce Richardson /**
1546c3169a3SBruce Richardson  * Control the RX mode, ie. promiscuous, allmulti, etc...
1556c3169a3SBruce Richardson  * All commands require an "out" sg entry containing a 1 byte
1566c3169a3SBruce Richardson  * state value, zero = disable, non-zero = enable.  Commands
1576c3169a3SBruce Richardson  * 0 and 1 are supported with the VIRTIO_NET_F_CTRL_RX feature.
1586c3169a3SBruce Richardson  * Commands 2-5 are added with VIRTIO_NET_F_CTRL_RX_EXTRA.
1596c3169a3SBruce Richardson  */
1606c3169a3SBruce Richardson #define VIRTIO_NET_CTRL_RX              0
1616c3169a3SBruce Richardson #define VIRTIO_NET_CTRL_RX_PROMISC      0
1626c3169a3SBruce Richardson #define VIRTIO_NET_CTRL_RX_ALLMULTI     1
1636c3169a3SBruce Richardson #define VIRTIO_NET_CTRL_RX_ALLUNI       2
1646c3169a3SBruce Richardson #define VIRTIO_NET_CTRL_RX_NOMULTI      3
1656c3169a3SBruce Richardson #define VIRTIO_NET_CTRL_RX_NOUNI        4
1666c3169a3SBruce Richardson #define VIRTIO_NET_CTRL_RX_NOBCAST      5
1676c3169a3SBruce Richardson 
1686c3169a3SBruce Richardson /**
1696c3169a3SBruce Richardson  * Control the MAC
1706c3169a3SBruce Richardson  *
1716c3169a3SBruce Richardson  * The MAC filter table is managed by the hypervisor, the guest should
1726c3169a3SBruce Richardson  * assume the size is infinite.  Filtering should be considered
1736c3169a3SBruce Richardson  * non-perfect, ie. based on hypervisor resources, the guest may
1746c3169a3SBruce Richardson  * received packets from sources not specified in the filter list.
1756c3169a3SBruce Richardson  *
1766c3169a3SBruce Richardson  * In addition to the class/cmd header, the TABLE_SET command requires
1776c3169a3SBruce Richardson  * two out scatterlists.  Each contains a 4 byte count of entries followed
1786c3169a3SBruce Richardson  * by a concatenated byte stream of the ETH_ALEN MAC addresses.  The
1796c3169a3SBruce Richardson  * first sg list contains unicast addresses, the second is for multicast.
1806c3169a3SBruce Richardson  * This functionality is present if the VIRTIO_NET_F_CTRL_RX feature
1816c3169a3SBruce Richardson  * is available.
1826c3169a3SBruce Richardson  *
1836c3169a3SBruce Richardson  * The ADDR_SET command requests one out scatterlist, it contains a
1846c3169a3SBruce Richardson  * 6 bytes MAC address. This functionality is present if the
1856c3169a3SBruce Richardson  * VIRTIO_NET_F_CTRL_MAC_ADDR feature is available.
1866c3169a3SBruce Richardson  */
1876c3169a3SBruce Richardson struct virtio_net_ctrl_mac {
1886c3169a3SBruce Richardson 	uint32_t entries;
18935b2d13fSOlivier Matz 	uint8_t macs[][RTE_ETHER_ADDR_LEN];
190ef5baf34SThomas Monjalon } __rte_packed;
1916c3169a3SBruce Richardson 
1926c3169a3SBruce Richardson #define VIRTIO_NET_CTRL_MAC    1
1936c3169a3SBruce Richardson #define VIRTIO_NET_CTRL_MAC_TABLE_SET        0
1946c3169a3SBruce Richardson #define VIRTIO_NET_CTRL_MAC_ADDR_SET         1
1956c3169a3SBruce Richardson 
1966c3169a3SBruce Richardson /**
1976c3169a3SBruce Richardson  * Control VLAN filtering
1986c3169a3SBruce Richardson  *
1996c3169a3SBruce Richardson  * The VLAN filter table is controlled via a simple ADD/DEL interface.
2006c3169a3SBruce Richardson  * VLAN IDs not added may be filtered by the hypervisor.  Del is the
2016c3169a3SBruce Richardson  * opposite of add.  Both commands expect an out entry containing a 2
2026c3169a3SBruce Richardson  * byte VLAN ID.  VLAN filtering is available with the
2036c3169a3SBruce Richardson  * VIRTIO_NET_F_CTRL_VLAN feature bit.
2046c3169a3SBruce Richardson  */
2056c3169a3SBruce Richardson #define VIRTIO_NET_CTRL_VLAN     2
2066c3169a3SBruce Richardson #define VIRTIO_NET_CTRL_VLAN_ADD 0
2076c3169a3SBruce Richardson #define VIRTIO_NET_CTRL_VLAN_DEL 1
2086c3169a3SBruce Richardson 
2097365504fSXiao Wang /*
2107365504fSXiao Wang  * Control link announce acknowledgement
2117365504fSXiao Wang  *
2127365504fSXiao Wang  * The command VIRTIO_NET_CTRL_ANNOUNCE_ACK is used to indicate that
2137365504fSXiao Wang  * driver has recevied the notification; device would clear the
2147365504fSXiao Wang  * VIRTIO_NET_S_ANNOUNCE bit in the status field after it receives
2157365504fSXiao Wang  * this command.
2167365504fSXiao Wang  */
2177365504fSXiao Wang #define VIRTIO_NET_CTRL_ANNOUNCE     3
2187365504fSXiao Wang #define VIRTIO_NET_CTRL_ANNOUNCE_ACK 0
2197365504fSXiao Wang 
2206c3169a3SBruce Richardson struct virtio_net_ctrl_hdr {
2216c3169a3SBruce Richardson 	uint8_t class;
2226c3169a3SBruce Richardson 	uint8_t cmd;
223ef5baf34SThomas Monjalon } __rte_packed;
2246c3169a3SBruce Richardson 
2256c3169a3SBruce Richardson typedef uint8_t virtio_net_ctrl_ack;
2266c3169a3SBruce Richardson 
2276c3169a3SBruce Richardson #define VIRTIO_NET_OK     0
2286c3169a3SBruce Richardson #define VIRTIO_NET_ERR    1
2296c3169a3SBruce Richardson 
2306c3169a3SBruce Richardson #define VIRTIO_MAX_CTRL_DATA 2048
2316c3169a3SBruce Richardson 
2326c3169a3SBruce Richardson struct virtio_pmd_ctrl {
2336c3169a3SBruce Richardson 	struct virtio_net_ctrl_hdr hdr;
2346c3169a3SBruce Richardson 	virtio_net_ctrl_ack status;
2356c3169a3SBruce Richardson 	uint8_t data[VIRTIO_MAX_CTRL_DATA];
2366c3169a3SBruce Richardson };
2376c3169a3SBruce Richardson 
23801ad44fdSHuawei Xie struct vq_desc_extra {
23901ad44fdSHuawei Xie 	void *cookie;
24001ad44fdSHuawei Xie 	uint16_t ndescs;
2414c3f5822SJens Freimann 	uint16_t next;
24201ad44fdSHuawei Xie };
24301ad44fdSHuawei Xie 
2446c3169a3SBruce Richardson struct virtqueue {
2456c3169a3SBruce Richardson 	struct virtio_hw  *hw; /**< virtio_hw structure pointer. */
246dfd33aa4STiwei Bie 	union {
247dfd33aa4STiwei Bie 		struct {
248dfd33aa4STiwei Bie 			/**< vring keeping desc, used and avail */
249dfd33aa4STiwei Bie 			struct vring ring;
250dfd33aa4STiwei Bie 		} vq_split;
251dfd33aa4STiwei Bie 
252dfd33aa4STiwei Bie 		struct {
253dfd33aa4STiwei Bie 			/**< vring keeping descs and events */
254dfd33aa4STiwei Bie 			struct vring_packed ring;
2554c3f5822SJens Freimann 			bool used_wrap_counter;
2568e148e49STiwei Bie 			uint16_t cached_flags; /**< cached flags for descs */
2574c3f5822SJens Freimann 			uint16_t event_flags_shadow;
258dfd33aa4STiwei Bie 		} vq_packed;
259dfd33aa4STiwei Bie 	};
2608e148e49STiwei Bie 
261dfd33aa4STiwei Bie 	uint16_t vq_used_cons_idx; /**< last consumed descriptor */
26201ad44fdSHuawei Xie 	uint16_t vq_nentries;  /**< vring desc numbers */
26301ad44fdSHuawei Xie 	uint16_t vq_free_cnt;  /**< num of desc available */
26401ad44fdSHuawei Xie 	uint16_t vq_avail_idx; /**< sync until needed */
26501ad44fdSHuawei Xie 	uint16_t vq_free_thresh; /**< free threshold */
2666c3169a3SBruce Richardson 
2676c3169a3SBruce Richardson 	void *vq_ring_virt_mem;  /**< linear address of vring*/
2686c3169a3SBruce Richardson 	unsigned int vq_ring_size;
26901ad44fdSHuawei Xie 
270905a2469SYuanhan Liu 	union {
271905a2469SYuanhan Liu 		struct virtnet_rx rxq;
272905a2469SYuanhan Liu 		struct virtnet_tx txq;
273905a2469SYuanhan Liu 		struct virtnet_ctl cq;
274905a2469SYuanhan Liu 	};
275905a2469SYuanhan Liu 
276df6e0a06SSantosh Shukla 	rte_iova_t vq_ring_mem; /**< physical address of vring,
277e8df94b8SJianfeng Tan 	                         * or virtual address for virtio_user. */
2786c3169a3SBruce Richardson 
2796c3169a3SBruce Richardson 	/**
2806c3169a3SBruce Richardson 	 * Head of the free chain in the descriptor table. If
2816c3169a3SBruce Richardson 	 * there are no free descriptors, this will be set to
2826c3169a3SBruce Richardson 	 * VQ_RING_DESC_CHAIN_END.
2836c3169a3SBruce Richardson 	 */
2846c3169a3SBruce Richardson 	uint16_t  vq_desc_head_idx;
2856c3169a3SBruce Richardson 	uint16_t  vq_desc_tail_idx;
28601ad44fdSHuawei Xie 	uint16_t  vq_queue_index;   /**< PCI queue index */
287f24f8f9fSJianfeng Tan 	uint16_t offset; /**< relative offset to obtain addr in mbuf */
2886ba1f63bSYuanhan Liu 	uint16_t  *notify_addr;
28901ad44fdSHuawei Xie 	struct rte_mbuf **sw_ring;  /**< RX software ring. */
29001ad44fdSHuawei Xie 	struct vq_desc_extra vq_descx[0];
2916c3169a3SBruce Richardson };
2926c3169a3SBruce Richardson 
2936c3169a3SBruce Richardson /* If multiqueue is provided by host, then we suppport it. */
2946c3169a3SBruce Richardson #define VIRTIO_NET_CTRL_MQ   4
2956c3169a3SBruce Richardson #define VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET        0
2966c3169a3SBruce Richardson #define VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MIN        1
2976c3169a3SBruce Richardson #define VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MAX        0x8000
2984a92b671SStephen Hemminger 
2996c3169a3SBruce Richardson /**
3006c3169a3SBruce Richardson  * This is the first element of the scatter-gather list.  If you don't
3016c3169a3SBruce Richardson  * specify GSO or CSUM features, you can simply ignore the header.
3026c3169a3SBruce Richardson  */
3036c3169a3SBruce Richardson struct virtio_net_hdr {
3046c3169a3SBruce Richardson #define VIRTIO_NET_HDR_F_NEEDS_CSUM 1    /**< Use csum_start,csum_offset*/
30596cb6711SOlivier Matz #define VIRTIO_NET_HDR_F_DATA_VALID 2    /**< Checksum is valid */
3066c3169a3SBruce Richardson 	uint8_t flags;
3076c3169a3SBruce Richardson #define VIRTIO_NET_HDR_GSO_NONE     0    /**< Not a GSO frame */
3086c3169a3SBruce Richardson #define VIRTIO_NET_HDR_GSO_TCPV4    1    /**< GSO frame, IPv4 TCP (TSO) */
3096c3169a3SBruce Richardson #define VIRTIO_NET_HDR_GSO_UDP      3    /**< GSO frame, IPv4 UDP (UFO) */
3106c3169a3SBruce Richardson #define VIRTIO_NET_HDR_GSO_TCPV6    4    /**< GSO frame, IPv6 TCP */
3116c3169a3SBruce Richardson #define VIRTIO_NET_HDR_GSO_ECN      0x80 /**< TCP has ECN set */
3126c3169a3SBruce Richardson 	uint8_t gso_type;
3136c3169a3SBruce Richardson 	uint16_t hdr_len;     /**< Ethernet + IP + tcp/udp hdrs */
3146c3169a3SBruce Richardson 	uint16_t gso_size;    /**< Bytes to append to hdr_len per frame */
3156c3169a3SBruce Richardson 	uint16_t csum_start;  /**< Position to start checksumming from */
3166c3169a3SBruce Richardson 	uint16_t csum_offset; /**< Offset after that to place checksum */
3176c3169a3SBruce Richardson };
3186c3169a3SBruce Richardson 
3196c3169a3SBruce Richardson /**
3206c3169a3SBruce Richardson  * This is the version of the header to use when the MRG_RXBUF
3216c3169a3SBruce Richardson  * feature has been negotiated.
3226c3169a3SBruce Richardson  */
3236c3169a3SBruce Richardson struct virtio_net_hdr_mrg_rxbuf {
3246c3169a3SBruce Richardson 	struct   virtio_net_hdr hdr;
3256c3169a3SBruce Richardson 	uint16_t num_buffers; /**< Number of merged rx buffers */
3266c3169a3SBruce Richardson };
3276c3169a3SBruce Richardson 
3286dc5de3aSStephen Hemminger /* Region reserved to allow for transmit header and indirect ring */
3296dc5de3aSStephen Hemminger #define VIRTIO_MAX_TX_INDIRECT 8
3306dc5de3aSStephen Hemminger struct virtio_tx_region {
3316dc5de3aSStephen Hemminger 	struct virtio_net_hdr_mrg_rxbuf tx_hdr;
332381f39ebSMarvin Liu 	union {
333381f39ebSMarvin Liu 		struct vring_desc tx_indir[VIRTIO_MAX_TX_INDIRECT];
334381f39ebSMarvin Liu 		struct vring_packed_desc
335381f39ebSMarvin Liu 			tx_packed_indir[VIRTIO_MAX_TX_INDIRECT];
336381f39ebSMarvin Liu 	} __rte_aligned(16);
3376dc5de3aSStephen Hemminger };
3386dc5de3aSStephen Hemminger 
339e9f4feb7SJens Freimann static inline int
3402923b8f9STiwei Bie desc_is_used(struct vring_packed_desc *desc, struct virtqueue *vq)
341e9f4feb7SJens Freimann {
342e9f4feb7SJens Freimann 	uint16_t used, avail, flags;
343e9f4feb7SJens Freimann 
3442c661d41SJoyce Kong 	flags = virtqueue_fetch_flags_packed(desc, vq->hw->weak_barriers);
34512e9e70cSTiwei Bie 	used = !!(flags & VRING_PACKED_DESC_F_USED);
34612e9e70cSTiwei Bie 	avail = !!(flags & VRING_PACKED_DESC_F_AVAIL);
347e9f4feb7SJens Freimann 
348dfd33aa4STiwei Bie 	return avail == used && used == vq->vq_packed.used_wrap_counter;
349a4270ea4SJens Freimann }
350a4270ea4SJens Freimann 
351e9f4feb7SJens Freimann static inline void
352e9f4feb7SJens Freimann vring_desc_init_packed(struct virtqueue *vq, int n)
353e9f4feb7SJens Freimann {
354e9f4feb7SJens Freimann 	int i;
355e9f4feb7SJens Freimann 	for (i = 0; i < n - 1; i++) {
3564cdc4d98STiwei Bie 		vq->vq_packed.ring.desc[i].id = i;
357e9f4feb7SJens Freimann 		vq->vq_descx[i].next = i + 1;
358e9f4feb7SJens Freimann 	}
3594cdc4d98STiwei Bie 	vq->vq_packed.ring.desc[i].id = i;
360e9f4feb7SJens Freimann 	vq->vq_descx[i].next = VQ_RING_DESC_CHAIN_END;
361e9f4feb7SJens Freimann }
362e9f4feb7SJens Freimann 
3636dc5de3aSStephen Hemminger /* Chain all the descriptors in the ring with an END */
3646dc5de3aSStephen Hemminger static inline void
365f803734bSJens Freimann vring_desc_init_split(struct vring_desc *dp, uint16_t n)
3666dc5de3aSStephen Hemminger {
3676dc5de3aSStephen Hemminger 	uint16_t i;
3686dc5de3aSStephen Hemminger 
3696dc5de3aSStephen Hemminger 	for (i = 0; i < n - 1; i++)
3706dc5de3aSStephen Hemminger 		dp[i].next = (uint16_t)(i + 1);
3716dc5de3aSStephen Hemminger 	dp[i].next = VQ_RING_DESC_CHAIN_END;
3726dc5de3aSStephen Hemminger }
3736dc5de3aSStephen Hemminger 
374381f39ebSMarvin Liu static inline void
375381f39ebSMarvin Liu vring_desc_init_indirect_packed(struct vring_packed_desc *dp, int n)
376381f39ebSMarvin Liu {
377381f39ebSMarvin Liu 	int i;
378381f39ebSMarvin Liu 	for (i = 0; i < n; i++) {
379381f39ebSMarvin Liu 		dp[i].id = (uint16_t)i;
380381f39ebSMarvin Liu 		dp[i].flags = VRING_DESC_F_WRITE;
381381f39ebSMarvin Liu 	}
382381f39ebSMarvin Liu }
383381f39ebSMarvin Liu 
3846c3169a3SBruce Richardson /**
38513cd890dSTiwei Bie  * Tell the backend not to interrupt us. Implementation for packed virtqueues.
3866c3169a3SBruce Richardson  */
387c056be23SJianfeng Tan static inline void
388e9f4feb7SJens Freimann virtqueue_disable_intr_packed(struct virtqueue *vq)
389e9f4feb7SJens Freimann {
390dfd33aa4STiwei Bie 	if (vq->vq_packed.event_flags_shadow != RING_EVENT_FLAGS_DISABLE) {
391dfd33aa4STiwei Bie 		vq->vq_packed.event_flags_shadow = RING_EVENT_FLAGS_DISABLE;
3924cdc4d98STiwei Bie 		vq->vq_packed.ring.driver->desc_event_flags =
393dfd33aa4STiwei Bie 			vq->vq_packed.event_flags_shadow;
394e9f4feb7SJens Freimann 	}
395c68fee95STiwei Bie }
396e9f4feb7SJens Freimann 
397e9f4feb7SJens Freimann /**
39813cd890dSTiwei Bie  * Tell the backend not to interrupt us. Implementation for split virtqueues.
39913cd890dSTiwei Bie  */
40013cd890dSTiwei Bie static inline void
40113cd890dSTiwei Bie virtqueue_disable_intr_split(struct virtqueue *vq)
40213cd890dSTiwei Bie {
40313cd890dSTiwei Bie 	vq->vq_split.ring.avail->flags |= VRING_AVAIL_F_NO_INTERRUPT;
40413cd890dSTiwei Bie }
40513cd890dSTiwei Bie 
40613cd890dSTiwei Bie /**
407e9f4feb7SJens Freimann  * Tell the backend not to interrupt us.
408e9f4feb7SJens Freimann  */
409e9f4feb7SJens Freimann static inline void
410c056be23SJianfeng Tan virtqueue_disable_intr(struct virtqueue *vq)
411c056be23SJianfeng Tan {
412e9f4feb7SJens Freimann 	if (vtpci_packed_queue(vq->hw))
413e9f4feb7SJens Freimann 		virtqueue_disable_intr_packed(vq);
414e9f4feb7SJens Freimann 	else
41513cd890dSTiwei Bie 		virtqueue_disable_intr_split(vq);
416c056be23SJianfeng Tan }
417c056be23SJianfeng Tan 
418c056be23SJianfeng Tan /**
419e9f4feb7SJens Freimann  * Tell the backend to interrupt. Implementation for packed virtqueues.
420e9f4feb7SJens Freimann  */
421e9f4feb7SJens Freimann static inline void
422e9f4feb7SJens Freimann virtqueue_enable_intr_packed(struct virtqueue *vq)
423e9f4feb7SJens Freimann {
424dfd33aa4STiwei Bie 	if (vq->vq_packed.event_flags_shadow == RING_EVENT_FLAGS_DISABLE) {
425dfd33aa4STiwei Bie 		vq->vq_packed.event_flags_shadow = RING_EVENT_FLAGS_ENABLE;
4264cdc4d98STiwei Bie 		vq->vq_packed.ring.driver->desc_event_flags =
427dfd33aa4STiwei Bie 			vq->vq_packed.event_flags_shadow;
428e9f4feb7SJens Freimann 	}
429e9f4feb7SJens Freimann }
430e9f4feb7SJens Freimann 
431e9f4feb7SJens Freimann /**
432e9f4feb7SJens Freimann  * Tell the backend to interrupt. Implementation for split virtqueues.
433e9f4feb7SJens Freimann  */
434e9f4feb7SJens Freimann static inline void
435e9f4feb7SJens Freimann virtqueue_enable_intr_split(struct virtqueue *vq)
436e9f4feb7SJens Freimann {
437dfd33aa4STiwei Bie 	vq->vq_split.ring.avail->flags &= (~VRING_AVAIL_F_NO_INTERRUPT);
438e9f4feb7SJens Freimann }
439e9f4feb7SJens Freimann 
440e9f4feb7SJens Freimann /**
441c056be23SJianfeng Tan  * Tell the backend to interrupt us.
442c056be23SJianfeng Tan  */
443c056be23SJianfeng Tan static inline void
444c056be23SJianfeng Tan virtqueue_enable_intr(struct virtqueue *vq)
445c056be23SJianfeng Tan {
446e9f4feb7SJens Freimann 	if (vtpci_packed_queue(vq->hw))
447e9f4feb7SJens Freimann 		virtqueue_enable_intr_packed(vq);
448e9f4feb7SJens Freimann 	else
449e9f4feb7SJens Freimann 		virtqueue_enable_intr_split(vq);
450c056be23SJianfeng Tan }
451c056be23SJianfeng Tan 
4526c3169a3SBruce Richardson /**
4536c3169a3SBruce Richardson  *  Dump virtqueue internal structures, for debug purpose only.
4546c3169a3SBruce Richardson  */
4556c3169a3SBruce Richardson void virtqueue_dump(struct virtqueue *vq);
4566c3169a3SBruce Richardson /**
4576c3169a3SBruce Richardson  *  Get all mbufs to be freed.
4586c3169a3SBruce Richardson  */
459727411f5SOlivier Matz struct rte_mbuf *virtqueue_detach_unused(struct virtqueue *vq);
4606c3169a3SBruce Richardson 
461d8227497STiwei Bie /* Flush the elements in the used ring. */
462bcf55c93STiwei Bie void virtqueue_rxvq_flush(struct virtqueue *vq);
463d8227497STiwei Bie 
4646ebbf410SXuan Ding int virtqueue_rxvq_reset_packed(struct virtqueue *vq);
4656ebbf410SXuan Ding 
4666ebbf410SXuan Ding int virtqueue_txvq_reset_packed(struct virtqueue *vq);
4676ebbf410SXuan Ding 
4686c3169a3SBruce Richardson static inline int
4696c3169a3SBruce Richardson virtqueue_full(const struct virtqueue *vq)
4706c3169a3SBruce Richardson {
4716c3169a3SBruce Richardson 	return vq->vq_free_cnt == 0;
4726c3169a3SBruce Richardson }
4736c3169a3SBruce Richardson 
474e67ae1e2SOlivier Matz static inline int
475e67ae1e2SOlivier Matz virtio_get_queue_type(struct virtio_hw *hw, uint16_t vtpci_queue_idx)
476e67ae1e2SOlivier Matz {
477e67ae1e2SOlivier Matz 	if (vtpci_queue_idx == hw->max_queue_pairs * 2)
478e67ae1e2SOlivier Matz 		return VTNET_CQ;
479e67ae1e2SOlivier Matz 	else if (vtpci_queue_idx % 2 == 0)
480e67ae1e2SOlivier Matz 		return VTNET_RQ;
481e67ae1e2SOlivier Matz 	else
482e67ae1e2SOlivier Matz 		return VTNET_TQ;
483e67ae1e2SOlivier Matz }
484e67ae1e2SOlivier Matz 
485f0f5d844SPhil Yang /* virtqueue_nused has load-acquire or rte_io_rmb insed */
486ea5207c1SJoyce Kong static inline uint16_t
487ea5207c1SJoyce Kong virtqueue_nused(const struct virtqueue *vq)
488ea5207c1SJoyce Kong {
489ea5207c1SJoyce Kong 	uint16_t idx;
490ea5207c1SJoyce Kong 
491ea5207c1SJoyce Kong 	if (vq->hw->weak_barriers) {
492ea5207c1SJoyce Kong 	/**
493ea5207c1SJoyce Kong 	 * x86 prefers to using rte_smp_rmb over __atomic_load_n as it
494ea5207c1SJoyce Kong 	 * reports a slightly better perf, which comes from the saved
495ea5207c1SJoyce Kong 	 * branch by the compiler.
496f0f5d844SPhil Yang 	 * The if and else branches are identical with the smp and io
497ea5207c1SJoyce Kong 	 * barriers both defined as compiler barriers on x86.
498ea5207c1SJoyce Kong 	 */
499ea5207c1SJoyce Kong #ifdef RTE_ARCH_X86_64
500ea5207c1SJoyce Kong 		idx = vq->vq_split.ring.used->idx;
501ea5207c1SJoyce Kong 		rte_smp_rmb();
502ea5207c1SJoyce Kong #else
503ea5207c1SJoyce Kong 		idx = __atomic_load_n(&(vq)->vq_split.ring.used->idx,
504ea5207c1SJoyce Kong 				__ATOMIC_ACQUIRE);
505ea5207c1SJoyce Kong #endif
506ea5207c1SJoyce Kong 	} else {
507ea5207c1SJoyce Kong 		idx = vq->vq_split.ring.used->idx;
508f0f5d844SPhil Yang 		rte_io_rmb();
509ea5207c1SJoyce Kong 	}
510ea5207c1SJoyce Kong 	return idx - vq->vq_used_cons_idx;
511ea5207c1SJoyce Kong }
5126c3169a3SBruce Richardson 
513d8227497STiwei Bie void vq_ring_free_chain(struct virtqueue *vq, uint16_t desc_idx);
514892dc798SJens Freimann void vq_ring_free_chain_packed(struct virtqueue *vq, uint16_t used_idx);
5157097ca1bSMarvin Liu void vq_ring_free_inorder(struct virtqueue *vq, uint16_t desc_idx,
5167097ca1bSMarvin Liu 			  uint16_t num);
517d8227497STiwei Bie 
5186c3169a3SBruce Richardson static inline void
5196c3169a3SBruce Richardson vq_update_avail_idx(struct virtqueue *vq)
5206c3169a3SBruce Richardson {
5213fc1d87cSJoyce Kong 	if (vq->hw->weak_barriers) {
5223fc1d87cSJoyce Kong 	/* x86 prefers to using rte_smp_wmb over __atomic_store_n as
5233fc1d87cSJoyce Kong 	 * it reports a slightly better perf, which comes from the
5243fc1d87cSJoyce Kong 	 * saved branch by the compiler.
5253fc1d87cSJoyce Kong 	 * The if and else branches are identical with the smp and
526f0f5d844SPhil Yang 	 * io barriers both defined as compiler barriers on x86.
5273fc1d87cSJoyce Kong 	 */
5283fc1d87cSJoyce Kong #ifdef RTE_ARCH_X86_64
5293fc1d87cSJoyce Kong 		rte_smp_wmb();
530dfd33aa4STiwei Bie 		vq->vq_split.ring.avail->idx = vq->vq_avail_idx;
5313fc1d87cSJoyce Kong #else
5323fc1d87cSJoyce Kong 		__atomic_store_n(&vq->vq_split.ring.avail->idx,
5333fc1d87cSJoyce Kong 				 vq->vq_avail_idx, __ATOMIC_RELEASE);
5343fc1d87cSJoyce Kong #endif
5353fc1d87cSJoyce Kong 	} else {
536f0f5d844SPhil Yang 		rte_io_wmb();
5373fc1d87cSJoyce Kong 		vq->vq_split.ring.avail->idx = vq->vq_avail_idx;
5383fc1d87cSJoyce Kong 	}
5396c3169a3SBruce Richardson }
5406c3169a3SBruce Richardson 
5416c3169a3SBruce Richardson static inline void
5426c3169a3SBruce Richardson vq_update_avail_ring(struct virtqueue *vq, uint16_t desc_idx)
5436c3169a3SBruce Richardson {
5446c3169a3SBruce Richardson 	uint16_t avail_idx;
5456c3169a3SBruce Richardson 	/*
5466c3169a3SBruce Richardson 	 * Place the head of the descriptor chain into the next slot and make
5476c3169a3SBruce Richardson 	 * it usable to the host. The chain is made available now rather than
5486c3169a3SBruce Richardson 	 * deferring to virtqueue_notify() in the hopes that if the host is
5496c3169a3SBruce Richardson 	 * currently running on another CPU, we can keep it processing the new
5506c3169a3SBruce Richardson 	 * descriptor.
5516c3169a3SBruce Richardson 	 */
5526c3169a3SBruce Richardson 	avail_idx = (uint16_t)(vq->vq_avail_idx & (vq->vq_nentries - 1));
553dfd33aa4STiwei Bie 	if (unlikely(vq->vq_split.ring.avail->ring[avail_idx] != desc_idx))
554dfd33aa4STiwei Bie 		vq->vq_split.ring.avail->ring[avail_idx] = desc_idx;
5556c3169a3SBruce Richardson 	vq->vq_avail_idx++;
5566c3169a3SBruce Richardson }
5576c3169a3SBruce Richardson 
5586c3169a3SBruce Richardson static inline int
5596c3169a3SBruce Richardson virtqueue_kick_prepare(struct virtqueue *vq)
5606c3169a3SBruce Richardson {
561d21d05c7SIlya Maximets 	/*
562d21d05c7SIlya Maximets 	 * Ensure updated avail->idx is visible to vhost before reading
563d21d05c7SIlya Maximets 	 * the used->flags.
564d21d05c7SIlya Maximets 	 */
5659230ab8dSIlya Maximets 	virtio_mb(vq->hw->weak_barriers);
566dfd33aa4STiwei Bie 	return !(vq->vq_split.ring.used->flags & VRING_USED_F_NO_NOTIFY);
5676c3169a3SBruce Richardson }
5686c3169a3SBruce Richardson 
569892dc798SJens Freimann static inline int
570892dc798SJens Freimann virtqueue_kick_prepare_packed(struct virtqueue *vq)
571892dc798SJens Freimann {
572892dc798SJens Freimann 	uint16_t flags;
573892dc798SJens Freimann 
574d21d05c7SIlya Maximets 	/*
575d21d05c7SIlya Maximets 	 * Ensure updated data is visible to vhost before reading the flags.
576d21d05c7SIlya Maximets 	 */
5779230ab8dSIlya Maximets 	virtio_mb(vq->hw->weak_barriers);
5784cdc4d98STiwei Bie 	flags = vq->vq_packed.ring.device->desc_event_flags;
579892dc798SJens Freimann 
580892dc798SJens Freimann 	return flags != RING_EVENT_FLAGS_DISABLE;
581892dc798SJens Freimann }
582892dc798SJens Freimann 
583cc827f83SIlya Maximets /*
584cc827f83SIlya Maximets  * virtqueue_kick_prepare*() or the virtio_wmb() should be called
585cc827f83SIlya Maximets  * before this function to be sure that all the data is visible to vhost.
586cc827f83SIlya Maximets  */
5876c3169a3SBruce Richardson static inline void
5886c3169a3SBruce Richardson virtqueue_notify(struct virtqueue *vq)
5896c3169a3SBruce Richardson {
590553f4593SYuanhan Liu 	VTPCI_OPS(vq->hw)->notify_queue(vq->hw, vq);
5916c3169a3SBruce Richardson }
5926c3169a3SBruce Richardson 
5936c3169a3SBruce Richardson #ifdef RTE_LIBRTE_VIRTIO_DEBUG_DUMP
5946c3169a3SBruce Richardson #define VIRTQUEUE_DUMP(vq) do { \
5956c3169a3SBruce Richardson 	uint16_t used_idx, nused; \
596ea5207c1SJoyce Kong 	used_idx = __atomic_load_n(&(vq)->vq_split.ring.used->idx, \
597ea5207c1SJoyce Kong 				   __ATOMIC_RELAXED); \
5986c3169a3SBruce Richardson 	nused = (uint16_t)(used_idx - (vq)->vq_used_cons_idx); \
59956785a2dSJens Freimann 	if (vtpci_packed_queue((vq)->hw)) { \
60056785a2dSJens Freimann 		PMD_INIT_LOG(DEBUG, \
60156785a2dSJens Freimann 		"VQ: - size=%d; free=%d; used_cons_idx=%d; avail_idx=%d;" \
6028e148e49STiwei Bie 		" cached_flags=0x%x; used_wrap_counter=%d", \
60356785a2dSJens Freimann 		(vq)->vq_nentries, (vq)->vq_free_cnt, (vq)->vq_used_cons_idx, \
604dfd33aa4STiwei Bie 		(vq)->vq_avail_idx, (vq)->vq_packed.cached_flags, \
605dfd33aa4STiwei Bie 		(vq)->vq_packed.used_wrap_counter); \
60656785a2dSJens Freimann 		break; \
60756785a2dSJens Freimann 	} \
6086c3169a3SBruce Richardson 	PMD_INIT_LOG(DEBUG, \
6096c3169a3SBruce Richardson 	  "VQ: - size=%d; free=%d; used=%d; desc_head_idx=%d;" \
6106c3169a3SBruce Richardson 	  " avail.idx=%d; used_cons_idx=%d; used.idx=%d;" \
6116c3169a3SBruce Richardson 	  " avail.flags=0x%x; used.flags=0x%x", \
612ea5207c1SJoyce Kong 	  (vq)->vq_nentries, (vq)->vq_free_cnt, nused, (vq)->vq_desc_head_idx, \
613ea5207c1SJoyce Kong 	  (vq)->vq_split.ring.avail->idx, (vq)->vq_used_cons_idx, \
614ea5207c1SJoyce Kong 	  __atomic_load_n(&(vq)->vq_split.ring.used->idx, __ATOMIC_RELAXED), \
615dfd33aa4STiwei Bie 	  (vq)->vq_split.ring.avail->flags, (vq)->vq_split.ring.used->flags); \
6166c3169a3SBruce Richardson } while (0)
6176c3169a3SBruce Richardson #else
6186c3169a3SBruce Richardson #define VIRTQUEUE_DUMP(vq) do { } while (0)
6196c3169a3SBruce Richardson #endif
6206c3169a3SBruce Richardson 
62157f90f89SMarvin Liu /* avoid write operation when necessary, to lessen cache issues */
62257f90f89SMarvin Liu #define ASSIGN_UNLESS_EQUAL(var, val) do {	\
623a1412e05SVipul Ashri 	typeof(var) *const var_ = &(var);	\
624a1412e05SVipul Ashri 	typeof(val)  const val_ = (val);	\
625a1412e05SVipul Ashri 	if (*var_ != val_)			\
626a1412e05SVipul Ashri 		*var_ = val_;			\
62757f90f89SMarvin Liu } while (0)
62857f90f89SMarvin Liu 
62957f90f89SMarvin Liu #define virtqueue_clear_net_hdr(hdr) do {		\
63057f90f89SMarvin Liu 	typeof(hdr) hdr_ = (hdr);			\
63157f90f89SMarvin Liu 	ASSIGN_UNLESS_EQUAL((hdr_)->csum_start, 0);	\
63257f90f89SMarvin Liu 	ASSIGN_UNLESS_EQUAL((hdr_)->csum_offset, 0);	\
63357f90f89SMarvin Liu 	ASSIGN_UNLESS_EQUAL((hdr_)->flags, 0);		\
63457f90f89SMarvin Liu 	ASSIGN_UNLESS_EQUAL((hdr_)->gso_type, 0);	\
63557f90f89SMarvin Liu 	ASSIGN_UNLESS_EQUAL((hdr_)->gso_size, 0);	\
63657f90f89SMarvin Liu 	ASSIGN_UNLESS_EQUAL((hdr_)->hdr_len, 0);	\
63757f90f89SMarvin Liu } while (0)
63857f90f89SMarvin Liu 
63957f90f89SMarvin Liu static inline void
64057f90f89SMarvin Liu virtqueue_xmit_offload(struct virtio_net_hdr *hdr,
64157f90f89SMarvin Liu 			struct rte_mbuf *cookie,
64257f90f89SMarvin Liu 			bool offload)
64357f90f89SMarvin Liu {
64457f90f89SMarvin Liu 	if (offload) {
64557f90f89SMarvin Liu 		if (cookie->ol_flags & PKT_TX_TCP_SEG)
64657f90f89SMarvin Liu 			cookie->ol_flags |= PKT_TX_TCP_CKSUM;
64757f90f89SMarvin Liu 
64857f90f89SMarvin Liu 		switch (cookie->ol_flags & PKT_TX_L4_MASK) {
64957f90f89SMarvin Liu 		case PKT_TX_UDP_CKSUM:
65057f90f89SMarvin Liu 			hdr->csum_start = cookie->l2_len + cookie->l3_len;
65157f90f89SMarvin Liu 			hdr->csum_offset = offsetof(struct rte_udp_hdr,
65257f90f89SMarvin Liu 				dgram_cksum);
65357f90f89SMarvin Liu 			hdr->flags = VIRTIO_NET_HDR_F_NEEDS_CSUM;
65457f90f89SMarvin Liu 			break;
65557f90f89SMarvin Liu 
65657f90f89SMarvin Liu 		case PKT_TX_TCP_CKSUM:
65757f90f89SMarvin Liu 			hdr->csum_start = cookie->l2_len + cookie->l3_len;
65857f90f89SMarvin Liu 			hdr->csum_offset = offsetof(struct rte_tcp_hdr, cksum);
65957f90f89SMarvin Liu 			hdr->flags = VIRTIO_NET_HDR_F_NEEDS_CSUM;
66057f90f89SMarvin Liu 			break;
66157f90f89SMarvin Liu 
66257f90f89SMarvin Liu 		default:
66357f90f89SMarvin Liu 			ASSIGN_UNLESS_EQUAL(hdr->csum_start, 0);
66457f90f89SMarvin Liu 			ASSIGN_UNLESS_EQUAL(hdr->csum_offset, 0);
66557f90f89SMarvin Liu 			ASSIGN_UNLESS_EQUAL(hdr->flags, 0);
66657f90f89SMarvin Liu 			break;
66757f90f89SMarvin Liu 		}
66857f90f89SMarvin Liu 
66957f90f89SMarvin Liu 		/* TCP Segmentation Offload */
67057f90f89SMarvin Liu 		if (cookie->ol_flags & PKT_TX_TCP_SEG) {
67157f90f89SMarvin Liu 			hdr->gso_type = (cookie->ol_flags & PKT_TX_IPV6) ?
67257f90f89SMarvin Liu 				VIRTIO_NET_HDR_GSO_TCPV6 :
67357f90f89SMarvin Liu 				VIRTIO_NET_HDR_GSO_TCPV4;
67457f90f89SMarvin Liu 			hdr->gso_size = cookie->tso_segsz;
67557f90f89SMarvin Liu 			hdr->hdr_len =
67657f90f89SMarvin Liu 				cookie->l2_len +
67757f90f89SMarvin Liu 				cookie->l3_len +
67857f90f89SMarvin Liu 				cookie->l4_len;
67957f90f89SMarvin Liu 		} else {
68057f90f89SMarvin Liu 			ASSIGN_UNLESS_EQUAL(hdr->gso_type, 0);
68157f90f89SMarvin Liu 			ASSIGN_UNLESS_EQUAL(hdr->gso_size, 0);
68257f90f89SMarvin Liu 			ASSIGN_UNLESS_EQUAL(hdr->hdr_len, 0);
68357f90f89SMarvin Liu 		}
68457f90f89SMarvin Liu 	}
68557f90f89SMarvin Liu }
68657f90f89SMarvin Liu 
68757f90f89SMarvin Liu static inline void
68857f90f89SMarvin Liu virtqueue_enqueue_xmit_packed(struct virtnet_tx *txvq, struct rte_mbuf *cookie,
689b473061bSMarvin Liu 			      uint16_t needed, int use_indirect, int can_push,
690b473061bSMarvin Liu 			      int in_order)
69157f90f89SMarvin Liu {
69257f90f89SMarvin Liu 	struct virtio_tx_region *txr = txvq->virtio_net_hdr_mz->addr;
69357f90f89SMarvin Liu 	struct vq_desc_extra *dxp;
69457f90f89SMarvin Liu 	struct virtqueue *vq = txvq->vq;
69557f90f89SMarvin Liu 	struct vring_packed_desc *start_dp, *head_dp;
69657f90f89SMarvin Liu 	uint16_t idx, id, head_idx, head_flags;
69757f90f89SMarvin Liu 	int16_t head_size = vq->hw->vtnet_hdr_size;
69857f90f89SMarvin Liu 	struct virtio_net_hdr *hdr;
69957f90f89SMarvin Liu 	uint16_t prev;
70057f90f89SMarvin Liu 	bool prepend_header = false;
701*8410c369SMarvin Liu 	uint16_t seg_num = cookie->nb_segs;
70257f90f89SMarvin Liu 
70357f90f89SMarvin Liu 	id = in_order ? vq->vq_avail_idx : vq->vq_desc_head_idx;
70457f90f89SMarvin Liu 
70557f90f89SMarvin Liu 	dxp = &vq->vq_descx[id];
70657f90f89SMarvin Liu 	dxp->ndescs = needed;
70757f90f89SMarvin Liu 	dxp->cookie = cookie;
70857f90f89SMarvin Liu 
70957f90f89SMarvin Liu 	head_idx = vq->vq_avail_idx;
71057f90f89SMarvin Liu 	idx = head_idx;
71157f90f89SMarvin Liu 	prev = head_idx;
71257f90f89SMarvin Liu 	start_dp = vq->vq_packed.ring.desc;
71357f90f89SMarvin Liu 
71457f90f89SMarvin Liu 	head_dp = &vq->vq_packed.ring.desc[idx];
71557f90f89SMarvin Liu 	head_flags = cookie->next ? VRING_DESC_F_NEXT : 0;
71657f90f89SMarvin Liu 	head_flags |= vq->vq_packed.cached_flags;
71757f90f89SMarvin Liu 
71857f90f89SMarvin Liu 	if (can_push) {
71957f90f89SMarvin Liu 		/* prepend cannot fail, checked by caller */
72057f90f89SMarvin Liu 		hdr = rte_pktmbuf_mtod_offset(cookie, struct virtio_net_hdr *,
72157f90f89SMarvin Liu 					      -head_size);
72257f90f89SMarvin Liu 		prepend_header = true;
72357f90f89SMarvin Liu 
72457f90f89SMarvin Liu 		/* if offload disabled, it is not zeroed below, do it now */
72557f90f89SMarvin Liu 		if (!vq->hw->has_tx_offload)
72657f90f89SMarvin Liu 			virtqueue_clear_net_hdr(hdr);
727b473061bSMarvin Liu 	} else if (use_indirect) {
728b473061bSMarvin Liu 		/* setup tx ring slot to point to indirect
729b473061bSMarvin Liu 		 * descriptor list stored in reserved region.
730b473061bSMarvin Liu 		 *
731b473061bSMarvin Liu 		 * the first slot in indirect ring is already preset
732b473061bSMarvin Liu 		 * to point to the header in reserved region
733b473061bSMarvin Liu 		 */
734b473061bSMarvin Liu 		start_dp[idx].addr  = txvq->virtio_net_hdr_mem +
735b473061bSMarvin Liu 			RTE_PTR_DIFF(&txr[idx].tx_packed_indir, txr);
736*8410c369SMarvin Liu 		start_dp[idx].len   = (seg_num + 1) *
737b473061bSMarvin Liu 			sizeof(struct vring_packed_desc);
738b473061bSMarvin Liu 		/* reset flags for indirect desc */
739b473061bSMarvin Liu 		head_flags = VRING_DESC_F_INDIRECT;
740b473061bSMarvin Liu 		head_flags |= vq->vq_packed.cached_flags;
741b473061bSMarvin Liu 		hdr = (struct virtio_net_hdr *)&txr[idx].tx_hdr;
742b473061bSMarvin Liu 
743b473061bSMarvin Liu 		/* loop below will fill in rest of the indirect elements */
744b473061bSMarvin Liu 		start_dp = txr[idx].tx_packed_indir;
745b473061bSMarvin Liu 		idx = 1;
74657f90f89SMarvin Liu 	} else {
74757f90f89SMarvin Liu 		/* setup first tx ring slot to point to header
74857f90f89SMarvin Liu 		 * stored in reserved region.
74957f90f89SMarvin Liu 		 */
75057f90f89SMarvin Liu 		start_dp[idx].addr  = txvq->virtio_net_hdr_mem +
75157f90f89SMarvin Liu 			RTE_PTR_DIFF(&txr[idx].tx_hdr, txr);
75257f90f89SMarvin Liu 		start_dp[idx].len   = vq->hw->vtnet_hdr_size;
75357f90f89SMarvin Liu 		hdr = (struct virtio_net_hdr *)&txr[idx].tx_hdr;
75457f90f89SMarvin Liu 		idx++;
75557f90f89SMarvin Liu 		if (idx >= vq->vq_nentries) {
75657f90f89SMarvin Liu 			idx -= vq->vq_nentries;
75757f90f89SMarvin Liu 			vq->vq_packed.cached_flags ^=
75857f90f89SMarvin Liu 				VRING_PACKED_DESC_F_AVAIL_USED;
75957f90f89SMarvin Liu 		}
76057f90f89SMarvin Liu 	}
76157f90f89SMarvin Liu 
76257f90f89SMarvin Liu 	virtqueue_xmit_offload(hdr, cookie, vq->hw->has_tx_offload);
76357f90f89SMarvin Liu 
76457f90f89SMarvin Liu 	do {
76557f90f89SMarvin Liu 		uint16_t flags;
76657f90f89SMarvin Liu 
76757f90f89SMarvin Liu 		start_dp[idx].addr = VIRTIO_MBUF_DATA_DMA_ADDR(cookie, vq);
76857f90f89SMarvin Liu 		start_dp[idx].len  = cookie->data_len;
76957f90f89SMarvin Liu 		if (prepend_header) {
77057f90f89SMarvin Liu 			start_dp[idx].addr -= head_size;
77157f90f89SMarvin Liu 			start_dp[idx].len += head_size;
77257f90f89SMarvin Liu 			prepend_header = false;
77357f90f89SMarvin Liu 		}
77457f90f89SMarvin Liu 
77557f90f89SMarvin Liu 		if (likely(idx != head_idx)) {
77657f90f89SMarvin Liu 			flags = cookie->next ? VRING_DESC_F_NEXT : 0;
77757f90f89SMarvin Liu 			flags |= vq->vq_packed.cached_flags;
77857f90f89SMarvin Liu 			start_dp[idx].flags = flags;
77957f90f89SMarvin Liu 		}
78057f90f89SMarvin Liu 		prev = idx;
78157f90f89SMarvin Liu 		idx++;
78257f90f89SMarvin Liu 		if (idx >= vq->vq_nentries) {
78357f90f89SMarvin Liu 			idx -= vq->vq_nentries;
78457f90f89SMarvin Liu 			vq->vq_packed.cached_flags ^=
78557f90f89SMarvin Liu 				VRING_PACKED_DESC_F_AVAIL_USED;
78657f90f89SMarvin Liu 		}
78757f90f89SMarvin Liu 	} while ((cookie = cookie->next) != NULL);
78857f90f89SMarvin Liu 
78957f90f89SMarvin Liu 	start_dp[prev].id = id;
79057f90f89SMarvin Liu 
791b473061bSMarvin Liu 	if (use_indirect) {
792b473061bSMarvin Liu 		idx = head_idx;
793b473061bSMarvin Liu 		if (++idx >= vq->vq_nentries) {
794b473061bSMarvin Liu 			idx -= vq->vq_nentries;
795b473061bSMarvin Liu 			vq->vq_packed.cached_flags ^=
796b473061bSMarvin Liu 				VRING_PACKED_DESC_F_AVAIL_USED;
797b473061bSMarvin Liu 		}
798b473061bSMarvin Liu 	}
799b473061bSMarvin Liu 
80057f90f89SMarvin Liu 	vq->vq_free_cnt = (uint16_t)(vq->vq_free_cnt - needed);
80157f90f89SMarvin Liu 	vq->vq_avail_idx = idx;
80257f90f89SMarvin Liu 
80357f90f89SMarvin Liu 	if (!in_order) {
80457f90f89SMarvin Liu 		vq->vq_desc_head_idx = dxp->next;
80557f90f89SMarvin Liu 		if (vq->vq_desc_head_idx == VQ_RING_DESC_CHAIN_END)
80657f90f89SMarvin Liu 			vq->vq_desc_tail_idx = VQ_RING_DESC_CHAIN_END;
80757f90f89SMarvin Liu 	}
80857f90f89SMarvin Liu 
80957f90f89SMarvin Liu 	virtqueue_store_flags_packed(head_dp, head_flags,
81057f90f89SMarvin Liu 				     vq->hw->weak_barriers);
81157f90f89SMarvin Liu }
81257f90f89SMarvin Liu 
81357f90f89SMarvin Liu static void
81457f90f89SMarvin Liu vq_ring_free_id_packed(struct virtqueue *vq, uint16_t id)
81557f90f89SMarvin Liu {
81657f90f89SMarvin Liu 	struct vq_desc_extra *dxp;
81757f90f89SMarvin Liu 
81857f90f89SMarvin Liu 	dxp = &vq->vq_descx[id];
81957f90f89SMarvin Liu 	vq->vq_free_cnt += dxp->ndescs;
82057f90f89SMarvin Liu 
82157f90f89SMarvin Liu 	if (vq->vq_desc_tail_idx == VQ_RING_DESC_CHAIN_END)
82257f90f89SMarvin Liu 		vq->vq_desc_head_idx = id;
82357f90f89SMarvin Liu 	else
82457f90f89SMarvin Liu 		vq->vq_descx[vq->vq_desc_tail_idx].next = id;
82557f90f89SMarvin Liu 
82657f90f89SMarvin Liu 	vq->vq_desc_tail_idx = id;
82757f90f89SMarvin Liu 	dxp->next = VQ_RING_DESC_CHAIN_END;
82857f90f89SMarvin Liu }
82957f90f89SMarvin Liu 
83057f90f89SMarvin Liu static void
83157f90f89SMarvin Liu virtio_xmit_cleanup_inorder_packed(struct virtqueue *vq, int num)
83257f90f89SMarvin Liu {
83357f90f89SMarvin Liu 	uint16_t used_idx, id, curr_id, free_cnt = 0;
83457f90f89SMarvin Liu 	uint16_t size = vq->vq_nentries;
83557f90f89SMarvin Liu 	struct vring_packed_desc *desc = vq->vq_packed.ring.desc;
83657f90f89SMarvin Liu 	struct vq_desc_extra *dxp;
83757f90f89SMarvin Liu 
83857f90f89SMarvin Liu 	used_idx = vq->vq_used_cons_idx;
839f0f5d844SPhil Yang 	/* desc_is_used has a load-acquire or rte_io_rmb inside
84057f90f89SMarvin Liu 	 * and wait for used desc in virtqueue.
84157f90f89SMarvin Liu 	 */
84257f90f89SMarvin Liu 	while (num > 0 && desc_is_used(&desc[used_idx], vq)) {
84357f90f89SMarvin Liu 		id = desc[used_idx].id;
84457f90f89SMarvin Liu 		do {
84557f90f89SMarvin Liu 			curr_id = used_idx;
84657f90f89SMarvin Liu 			dxp = &vq->vq_descx[used_idx];
84757f90f89SMarvin Liu 			used_idx += dxp->ndescs;
84857f90f89SMarvin Liu 			free_cnt += dxp->ndescs;
84957f90f89SMarvin Liu 			num -= dxp->ndescs;
85057f90f89SMarvin Liu 			if (used_idx >= size) {
85157f90f89SMarvin Liu 				used_idx -= size;
85257f90f89SMarvin Liu 				vq->vq_packed.used_wrap_counter ^= 1;
85357f90f89SMarvin Liu 			}
85457f90f89SMarvin Liu 			if (dxp->cookie != NULL) {
85557f90f89SMarvin Liu 				rte_pktmbuf_free(dxp->cookie);
85657f90f89SMarvin Liu 				dxp->cookie = NULL;
85757f90f89SMarvin Liu 			}
85857f90f89SMarvin Liu 		} while (curr_id != id);
85957f90f89SMarvin Liu 	}
86057f90f89SMarvin Liu 	vq->vq_used_cons_idx = used_idx;
86157f90f89SMarvin Liu 	vq->vq_free_cnt += free_cnt;
86257f90f89SMarvin Liu }
86357f90f89SMarvin Liu 
86457f90f89SMarvin Liu static void
86557f90f89SMarvin Liu virtio_xmit_cleanup_normal_packed(struct virtqueue *vq, int num)
86657f90f89SMarvin Liu {
86757f90f89SMarvin Liu 	uint16_t used_idx, id;
86857f90f89SMarvin Liu 	uint16_t size = vq->vq_nentries;
86957f90f89SMarvin Liu 	struct vring_packed_desc *desc = vq->vq_packed.ring.desc;
87057f90f89SMarvin Liu 	struct vq_desc_extra *dxp;
87157f90f89SMarvin Liu 
87257f90f89SMarvin Liu 	used_idx = vq->vq_used_cons_idx;
873f0f5d844SPhil Yang 	/* desc_is_used has a load-acquire or rte_io_rmb inside
87457f90f89SMarvin Liu 	 * and wait for used desc in virtqueue.
87557f90f89SMarvin Liu 	 */
87657f90f89SMarvin Liu 	while (num-- && desc_is_used(&desc[used_idx], vq)) {
87757f90f89SMarvin Liu 		id = desc[used_idx].id;
87857f90f89SMarvin Liu 		dxp = &vq->vq_descx[id];
87957f90f89SMarvin Liu 		vq->vq_used_cons_idx += dxp->ndescs;
88057f90f89SMarvin Liu 		if (vq->vq_used_cons_idx >= size) {
88157f90f89SMarvin Liu 			vq->vq_used_cons_idx -= size;
88257f90f89SMarvin Liu 			vq->vq_packed.used_wrap_counter ^= 1;
88357f90f89SMarvin Liu 		}
88457f90f89SMarvin Liu 		vq_ring_free_id_packed(vq, id);
88557f90f89SMarvin Liu 		if (dxp->cookie != NULL) {
88657f90f89SMarvin Liu 			rte_pktmbuf_free(dxp->cookie);
88757f90f89SMarvin Liu 			dxp->cookie = NULL;
88857f90f89SMarvin Liu 		}
88957f90f89SMarvin Liu 		used_idx = vq->vq_used_cons_idx;
89057f90f89SMarvin Liu 	}
89157f90f89SMarvin Liu }
89257f90f89SMarvin Liu 
89357f90f89SMarvin Liu /* Cleanup from completed transmits. */
89457f90f89SMarvin Liu static inline void
89557f90f89SMarvin Liu virtio_xmit_cleanup_packed(struct virtqueue *vq, int num, int in_order)
89657f90f89SMarvin Liu {
89757f90f89SMarvin Liu 	if (in_order)
89857f90f89SMarvin Liu 		virtio_xmit_cleanup_inorder_packed(vq, num);
89957f90f89SMarvin Liu 	else
90057f90f89SMarvin Liu 		virtio_xmit_cleanup_normal_packed(vq, num);
90157f90f89SMarvin Liu }
90257f90f89SMarvin Liu 
90357f90f89SMarvin Liu static inline void
90457f90f89SMarvin Liu virtio_xmit_cleanup(struct virtqueue *vq, uint16_t num)
90557f90f89SMarvin Liu {
90657f90f89SMarvin Liu 	uint16_t i, used_idx, desc_idx;
90757f90f89SMarvin Liu 	for (i = 0; i < num; i++) {
90857f90f89SMarvin Liu 		struct vring_used_elem *uep;
90957f90f89SMarvin Liu 		struct vq_desc_extra *dxp;
91057f90f89SMarvin Liu 
91157f90f89SMarvin Liu 		used_idx = (uint16_t)(vq->vq_used_cons_idx &
91257f90f89SMarvin Liu 				(vq->vq_nentries - 1));
91357f90f89SMarvin Liu 		uep = &vq->vq_split.ring.used->ring[used_idx];
91457f90f89SMarvin Liu 
91557f90f89SMarvin Liu 		desc_idx = (uint16_t)uep->id;
91657f90f89SMarvin Liu 		dxp = &vq->vq_descx[desc_idx];
91757f90f89SMarvin Liu 		vq->vq_used_cons_idx++;
91857f90f89SMarvin Liu 		vq_ring_free_chain(vq, desc_idx);
91957f90f89SMarvin Liu 
92057f90f89SMarvin Liu 		if (dxp->cookie != NULL) {
92157f90f89SMarvin Liu 			rte_pktmbuf_free(dxp->cookie);
92257f90f89SMarvin Liu 			dxp->cookie = NULL;
92357f90f89SMarvin Liu 		}
92457f90f89SMarvin Liu 	}
92557f90f89SMarvin Liu }
92657f90f89SMarvin Liu 
92757f90f89SMarvin Liu /* Cleanup from completed inorder transmits. */
92857f90f89SMarvin Liu static __rte_always_inline void
92957f90f89SMarvin Liu virtio_xmit_cleanup_inorder(struct virtqueue *vq, uint16_t num)
93057f90f89SMarvin Liu {
93157f90f89SMarvin Liu 	uint16_t i, idx = vq->vq_used_cons_idx;
93257f90f89SMarvin Liu 	int16_t free_cnt = 0;
93357f90f89SMarvin Liu 	struct vq_desc_extra *dxp = NULL;
93457f90f89SMarvin Liu 
93557f90f89SMarvin Liu 	if (unlikely(num == 0))
93657f90f89SMarvin Liu 		return;
93757f90f89SMarvin Liu 
93857f90f89SMarvin Liu 	for (i = 0; i < num; i++) {
93957f90f89SMarvin Liu 		dxp = &vq->vq_descx[idx++ & (vq->vq_nentries - 1)];
94057f90f89SMarvin Liu 		free_cnt += dxp->ndescs;
94157f90f89SMarvin Liu 		if (dxp->cookie != NULL) {
94257f90f89SMarvin Liu 			rte_pktmbuf_free(dxp->cookie);
94357f90f89SMarvin Liu 			dxp->cookie = NULL;
94457f90f89SMarvin Liu 		}
94557f90f89SMarvin Liu 	}
94657f90f89SMarvin Liu 
94757f90f89SMarvin Liu 	vq->vq_free_cnt += free_cnt;
94857f90f89SMarvin Liu 	vq->vq_used_cons_idx = idx;
94957f90f89SMarvin Liu }
9506c3169a3SBruce Richardson #endif /* _VIRTQUEUE_H_ */
951