xref: /f-stack/dpdk/drivers/net/virtio/virtqueue.h (revision 2d9fd380)
1d30ea906Sjfb8856606 /* SPDX-License-Identifier: BSD-3-Clause
2d30ea906Sjfb8856606  * Copyright(c) 2010-2014 Intel Corporation
3a9643ea8Slogwang  */
4a9643ea8Slogwang 
5a9643ea8Slogwang #ifndef _VIRTQUEUE_H_
6a9643ea8Slogwang #define _VIRTQUEUE_H_
7a9643ea8Slogwang 
8a9643ea8Slogwang #include <stdint.h>
9a9643ea8Slogwang 
10a9643ea8Slogwang #include <rte_atomic.h>
11a9643ea8Slogwang #include <rte_memory.h>
12a9643ea8Slogwang #include <rte_mempool.h>
13*2d9fd380Sjfb8856606 #include <rte_net.h>
14a9643ea8Slogwang 
15a9643ea8Slogwang #include "virtio_pci.h"
16a9643ea8Slogwang #include "virtio_ring.h"
17a9643ea8Slogwang #include "virtio_logs.h"
182bfe3f2eSlogwang #include "virtio_rxtx.h"
19a9643ea8Slogwang 
20a9643ea8Slogwang struct rte_mbuf;
21a9643ea8Slogwang 
22*2d9fd380Sjfb8856606 #define DEFAULT_TX_FREE_THRESH 32
23*2d9fd380Sjfb8856606 #define DEFAULT_RX_FREE_THRESH 32
24*2d9fd380Sjfb8856606 
25*2d9fd380Sjfb8856606 #define VIRTIO_MBUF_BURST_SZ 64
26a9643ea8Slogwang /*
274418919fSjohnjiang  * Per virtio_ring.h in Linux.
28a9643ea8Slogwang  *     For virtio_pci on SMP, we don't need to order with respect to MMIO
29a9643ea8Slogwang  *     accesses through relaxed memory I/O windows, so smp_mb() et al are
30a9643ea8Slogwang  *     sufficient.
31a9643ea8Slogwang  *
324418919fSjohnjiang  *     For using virtio to talk to real devices (eg. vDPA) we do need real
334418919fSjohnjiang  *     barriers.
34a9643ea8Slogwang  */
354418919fSjohnjiang static inline void
virtio_mb(uint8_t weak_barriers)364418919fSjohnjiang virtio_mb(uint8_t weak_barriers)
374418919fSjohnjiang {
384418919fSjohnjiang 	if (weak_barriers)
394418919fSjohnjiang 		rte_smp_mb();
404418919fSjohnjiang 	else
414418919fSjohnjiang 		rte_mb();
424418919fSjohnjiang }
43a9643ea8Slogwang 
444418919fSjohnjiang static inline void
virtio_rmb(uint8_t weak_barriers)454418919fSjohnjiang virtio_rmb(uint8_t weak_barriers)
464418919fSjohnjiang {
474418919fSjohnjiang 	if (weak_barriers)
484418919fSjohnjiang 		rte_smp_rmb();
494418919fSjohnjiang 	else
50*2d9fd380Sjfb8856606 		rte_io_rmb();
514418919fSjohnjiang }
524418919fSjohnjiang 
534418919fSjohnjiang static inline void
virtio_wmb(uint8_t weak_barriers)544418919fSjohnjiang virtio_wmb(uint8_t weak_barriers)
554418919fSjohnjiang {
564418919fSjohnjiang 	if (weak_barriers)
574418919fSjohnjiang 		rte_smp_wmb();
584418919fSjohnjiang 	else
59*2d9fd380Sjfb8856606 		rte_io_wmb();
604418919fSjohnjiang }
614418919fSjohnjiang 
624418919fSjohnjiang static inline uint16_t
virtqueue_fetch_flags_packed(struct vring_packed_desc * dp,uint8_t weak_barriers)634418919fSjohnjiang virtqueue_fetch_flags_packed(struct vring_packed_desc *dp,
644418919fSjohnjiang 			      uint8_t weak_barriers)
654418919fSjohnjiang {
664418919fSjohnjiang 	uint16_t flags;
674418919fSjohnjiang 
684418919fSjohnjiang 	if (weak_barriers) {
694418919fSjohnjiang /* x86 prefers to using rte_smp_rmb over __atomic_load_n as it reports
704418919fSjohnjiang  * a better perf(~1.5%), which comes from the saved branch by the compiler.
71*2d9fd380Sjfb8856606  * The if and else branch are identical with the smp and io barriers both
724418919fSjohnjiang  * defined as compiler barriers on x86.
734418919fSjohnjiang  */
744418919fSjohnjiang #ifdef RTE_ARCH_X86_64
754418919fSjohnjiang 		flags = dp->flags;
764418919fSjohnjiang 		rte_smp_rmb();
774418919fSjohnjiang #else
784418919fSjohnjiang 		flags = __atomic_load_n(&dp->flags, __ATOMIC_ACQUIRE);
794418919fSjohnjiang #endif
804418919fSjohnjiang 	} else {
814418919fSjohnjiang 		flags = dp->flags;
82*2d9fd380Sjfb8856606 		rte_io_rmb();
834418919fSjohnjiang 	}
844418919fSjohnjiang 
854418919fSjohnjiang 	return flags;
864418919fSjohnjiang }
874418919fSjohnjiang 
884418919fSjohnjiang static inline void
virtqueue_store_flags_packed(struct vring_packed_desc * dp,uint16_t flags,uint8_t weak_barriers)894418919fSjohnjiang virtqueue_store_flags_packed(struct vring_packed_desc *dp,
904418919fSjohnjiang 			      uint16_t flags, uint8_t weak_barriers)
914418919fSjohnjiang {
924418919fSjohnjiang 	if (weak_barriers) {
934418919fSjohnjiang /* x86 prefers to using rte_smp_wmb over __atomic_store_n as it reports
944418919fSjohnjiang  * a better perf(~1.5%), which comes from the saved branch by the compiler.
95*2d9fd380Sjfb8856606  * The if and else branch are identical with the smp and io barriers both
964418919fSjohnjiang  * defined as compiler barriers on x86.
974418919fSjohnjiang  */
984418919fSjohnjiang #ifdef RTE_ARCH_X86_64
994418919fSjohnjiang 		rte_smp_wmb();
1004418919fSjohnjiang 		dp->flags = flags;
1014418919fSjohnjiang #else
1024418919fSjohnjiang 		__atomic_store_n(&dp->flags, flags, __ATOMIC_RELEASE);
1034418919fSjohnjiang #endif
1044418919fSjohnjiang 	} else {
105*2d9fd380Sjfb8856606 		rte_io_wmb();
1064418919fSjohnjiang 		dp->flags = flags;
1074418919fSjohnjiang 	}
1084418919fSjohnjiang }
109a9643ea8Slogwang #ifdef RTE_PMD_PACKET_PREFETCH
110a9643ea8Slogwang #define rte_packet_prefetch(p)  rte_prefetch1(p)
111a9643ea8Slogwang #else
112a9643ea8Slogwang #define rte_packet_prefetch(p)  do {} while(0)
113a9643ea8Slogwang #endif
114a9643ea8Slogwang 
115a9643ea8Slogwang #define VIRTQUEUE_MAX_NAME_SZ 32
116a9643ea8Slogwang 
117a9643ea8Slogwang #ifdef RTE_VIRTIO_USER
118a9643ea8Slogwang /**
119a9643ea8Slogwang  * Return the physical address (or virtual address in case of
120a9643ea8Slogwang  * virtio-user) of mbuf data buffer.
1212bfe3f2eSlogwang  *
1222bfe3f2eSlogwang  * The address is firstly casted to the word size (sizeof(uintptr_t))
1232bfe3f2eSlogwang  * before casting it to uint64_t. This is to make it work with different
1242bfe3f2eSlogwang  * combination of word size (64 bit and 32 bit) and virtio device
1252bfe3f2eSlogwang  * (virtio-pci and virtio-user).
126a9643ea8Slogwang  */
1272bfe3f2eSlogwang #define VIRTIO_MBUF_ADDR(mb, vq) \
1282bfe3f2eSlogwang 	((uint64_t)(*(uintptr_t *)((uintptr_t)(mb) + (vq)->offset)))
129a9643ea8Slogwang #else
1302bfe3f2eSlogwang #define VIRTIO_MBUF_ADDR(mb, vq) ((mb)->buf_iova)
131a9643ea8Slogwang #endif
132a9643ea8Slogwang 
133a9643ea8Slogwang /**
134a9643ea8Slogwang  * Return the physical address (or virtual address in case of
135a9643ea8Slogwang  * virtio-user) of mbuf data buffer, taking care of mbuf data offset
136a9643ea8Slogwang  */
137a9643ea8Slogwang #define VIRTIO_MBUF_DATA_DMA_ADDR(mb, vq) \
138a9643ea8Slogwang 	(VIRTIO_MBUF_ADDR(mb, vq) + (mb)->data_off)
139a9643ea8Slogwang 
140a9643ea8Slogwang #define VTNET_SQ_RQ_QUEUE_IDX 0
141a9643ea8Slogwang #define VTNET_SQ_TQ_QUEUE_IDX 1
142a9643ea8Slogwang #define VTNET_SQ_CQ_QUEUE_IDX 2
143a9643ea8Slogwang 
144a9643ea8Slogwang enum { VTNET_RQ = 0, VTNET_TQ = 1, VTNET_CQ = 2 };
145a9643ea8Slogwang /**
146a9643ea8Slogwang  * The maximum virtqueue size is 2^15. Use that value as the end of
147a9643ea8Slogwang  * descriptor chain terminator since it will never be a valid index
148a9643ea8Slogwang  * in the descriptor table. This is used to verify we are correctly
149a9643ea8Slogwang  * handling vq_free_cnt.
150a9643ea8Slogwang  */
151a9643ea8Slogwang #define VQ_RING_DESC_CHAIN_END 32768
152a9643ea8Slogwang 
153a9643ea8Slogwang /**
154a9643ea8Slogwang  * Control the RX mode, ie. promiscuous, allmulti, etc...
155a9643ea8Slogwang  * All commands require an "out" sg entry containing a 1 byte
156a9643ea8Slogwang  * state value, zero = disable, non-zero = enable.  Commands
157a9643ea8Slogwang  * 0 and 1 are supported with the VIRTIO_NET_F_CTRL_RX feature.
158a9643ea8Slogwang  * Commands 2-5 are added with VIRTIO_NET_F_CTRL_RX_EXTRA.
159a9643ea8Slogwang  */
160a9643ea8Slogwang #define VIRTIO_NET_CTRL_RX              0
161a9643ea8Slogwang #define VIRTIO_NET_CTRL_RX_PROMISC      0
162a9643ea8Slogwang #define VIRTIO_NET_CTRL_RX_ALLMULTI     1
163a9643ea8Slogwang #define VIRTIO_NET_CTRL_RX_ALLUNI       2
164a9643ea8Slogwang #define VIRTIO_NET_CTRL_RX_NOMULTI      3
165a9643ea8Slogwang #define VIRTIO_NET_CTRL_RX_NOUNI        4
166a9643ea8Slogwang #define VIRTIO_NET_CTRL_RX_NOBCAST      5
167a9643ea8Slogwang 
168a9643ea8Slogwang /**
169a9643ea8Slogwang  * Control the MAC
170a9643ea8Slogwang  *
171a9643ea8Slogwang  * The MAC filter table is managed by the hypervisor, the guest should
172a9643ea8Slogwang  * assume the size is infinite.  Filtering should be considered
173a9643ea8Slogwang  * non-perfect, ie. based on hypervisor resources, the guest may
174a9643ea8Slogwang  * received packets from sources not specified in the filter list.
175a9643ea8Slogwang  *
176a9643ea8Slogwang  * In addition to the class/cmd header, the TABLE_SET command requires
177a9643ea8Slogwang  * two out scatterlists.  Each contains a 4 byte count of entries followed
178a9643ea8Slogwang  * by a concatenated byte stream of the ETH_ALEN MAC addresses.  The
179a9643ea8Slogwang  * first sg list contains unicast addresses, the second is for multicast.
180a9643ea8Slogwang  * This functionality is present if the VIRTIO_NET_F_CTRL_RX feature
181a9643ea8Slogwang  * is available.
182a9643ea8Slogwang  *
183a9643ea8Slogwang  * The ADDR_SET command requests one out scatterlist, it contains a
184a9643ea8Slogwang  * 6 bytes MAC address. This functionality is present if the
185a9643ea8Slogwang  * VIRTIO_NET_F_CTRL_MAC_ADDR feature is available.
186a9643ea8Slogwang  */
187a9643ea8Slogwang struct virtio_net_ctrl_mac {
188a9643ea8Slogwang 	uint32_t entries;
1894418919fSjohnjiang 	uint8_t macs[][RTE_ETHER_ADDR_LEN];
190*2d9fd380Sjfb8856606 } __rte_packed;
191a9643ea8Slogwang 
192a9643ea8Slogwang #define VIRTIO_NET_CTRL_MAC    1
193a9643ea8Slogwang #define VIRTIO_NET_CTRL_MAC_TABLE_SET        0
194a9643ea8Slogwang #define VIRTIO_NET_CTRL_MAC_ADDR_SET         1
195a9643ea8Slogwang 
196a9643ea8Slogwang /**
197a9643ea8Slogwang  * Control VLAN filtering
198a9643ea8Slogwang  *
199a9643ea8Slogwang  * The VLAN filter table is controlled via a simple ADD/DEL interface.
200a9643ea8Slogwang  * VLAN IDs not added may be filtered by the hypervisor.  Del is the
201a9643ea8Slogwang  * opposite of add.  Both commands expect an out entry containing a 2
202a9643ea8Slogwang  * byte VLAN ID.  VLAN filtering is available with the
203a9643ea8Slogwang  * VIRTIO_NET_F_CTRL_VLAN feature bit.
204a9643ea8Slogwang  */
205a9643ea8Slogwang #define VIRTIO_NET_CTRL_VLAN     2
206a9643ea8Slogwang #define VIRTIO_NET_CTRL_VLAN_ADD 0
207a9643ea8Slogwang #define VIRTIO_NET_CTRL_VLAN_DEL 1
208a9643ea8Slogwang 
209d30ea906Sjfb8856606 /*
210d30ea906Sjfb8856606  * Control link announce acknowledgement
211d30ea906Sjfb8856606  *
212d30ea906Sjfb8856606  * The command VIRTIO_NET_CTRL_ANNOUNCE_ACK is used to indicate that
213d30ea906Sjfb8856606  * driver has recevied the notification; device would clear the
214d30ea906Sjfb8856606  * VIRTIO_NET_S_ANNOUNCE bit in the status field after it receives
215d30ea906Sjfb8856606  * this command.
216d30ea906Sjfb8856606  */
217d30ea906Sjfb8856606 #define VIRTIO_NET_CTRL_ANNOUNCE     3
218d30ea906Sjfb8856606 #define VIRTIO_NET_CTRL_ANNOUNCE_ACK 0
219d30ea906Sjfb8856606 
220a9643ea8Slogwang struct virtio_net_ctrl_hdr {
221a9643ea8Slogwang 	uint8_t class;
222a9643ea8Slogwang 	uint8_t cmd;
223*2d9fd380Sjfb8856606 } __rte_packed;
224a9643ea8Slogwang 
225a9643ea8Slogwang typedef uint8_t virtio_net_ctrl_ack;
226a9643ea8Slogwang 
227a9643ea8Slogwang #define VIRTIO_NET_OK     0
228a9643ea8Slogwang #define VIRTIO_NET_ERR    1
229a9643ea8Slogwang 
230a9643ea8Slogwang #define VIRTIO_MAX_CTRL_DATA 2048
231a9643ea8Slogwang 
232a9643ea8Slogwang struct virtio_pmd_ctrl {
233a9643ea8Slogwang 	struct virtio_net_ctrl_hdr hdr;
234a9643ea8Slogwang 	virtio_net_ctrl_ack status;
235a9643ea8Slogwang 	uint8_t data[VIRTIO_MAX_CTRL_DATA];
236a9643ea8Slogwang };
237a9643ea8Slogwang 
238a9643ea8Slogwang struct vq_desc_extra {
239a9643ea8Slogwang 	void *cookie;
240a9643ea8Slogwang 	uint16_t ndescs;
2414418919fSjohnjiang 	uint16_t next;
242a9643ea8Slogwang };
243a9643ea8Slogwang 
244a9643ea8Slogwang struct virtqueue {
245a9643ea8Slogwang 	struct virtio_hw  *hw; /**< virtio_hw structure pointer. */
2464418919fSjohnjiang 	union {
2474418919fSjohnjiang 		struct {
2484418919fSjohnjiang 			/**< vring keeping desc, used and avail */
2494418919fSjohnjiang 			struct vring ring;
2504418919fSjohnjiang 		} vq_split;
2514418919fSjohnjiang 
2524418919fSjohnjiang 		struct {
2534418919fSjohnjiang 			/**< vring keeping descs and events */
2544418919fSjohnjiang 			struct vring_packed ring;
2554418919fSjohnjiang 			bool used_wrap_counter;
2564418919fSjohnjiang 			uint16_t cached_flags; /**< cached flags for descs */
2574418919fSjohnjiang 			uint16_t event_flags_shadow;
2584418919fSjohnjiang 		} vq_packed;
2594418919fSjohnjiang 	};
2604418919fSjohnjiang 
2614418919fSjohnjiang 	uint16_t vq_used_cons_idx; /**< last consumed descriptor */
262a9643ea8Slogwang 	uint16_t vq_nentries;  /**< vring desc numbers */
263a9643ea8Slogwang 	uint16_t vq_free_cnt;  /**< num of desc available */
264a9643ea8Slogwang 	uint16_t vq_avail_idx; /**< sync until needed */
265a9643ea8Slogwang 	uint16_t vq_free_thresh; /**< free threshold */
266a9643ea8Slogwang 
267a9643ea8Slogwang 	void *vq_ring_virt_mem;  /**< linear address of vring*/
268a9643ea8Slogwang 	unsigned int vq_ring_size;
269a9643ea8Slogwang 
2702bfe3f2eSlogwang 	union {
2712bfe3f2eSlogwang 		struct virtnet_rx rxq;
2722bfe3f2eSlogwang 		struct virtnet_tx txq;
2732bfe3f2eSlogwang 		struct virtnet_ctl cq;
2742bfe3f2eSlogwang 	};
2752bfe3f2eSlogwang 
2762bfe3f2eSlogwang 	rte_iova_t vq_ring_mem; /**< physical address of vring,
277a9643ea8Slogwang 	                         * or virtual address for virtio_user. */
278a9643ea8Slogwang 
279a9643ea8Slogwang 	/**
280a9643ea8Slogwang 	 * Head of the free chain in the descriptor table. If
281a9643ea8Slogwang 	 * there are no free descriptors, this will be set to
282a9643ea8Slogwang 	 * VQ_RING_DESC_CHAIN_END.
283a9643ea8Slogwang 	 */
284a9643ea8Slogwang 	uint16_t  vq_desc_head_idx;
285a9643ea8Slogwang 	uint16_t  vq_desc_tail_idx;
286a9643ea8Slogwang 	uint16_t  vq_queue_index;   /**< PCI queue index */
287a9643ea8Slogwang 	uint16_t offset; /**< relative offset to obtain addr in mbuf */
288a9643ea8Slogwang 	uint16_t  *notify_addr;
289a9643ea8Slogwang 	struct rte_mbuf **sw_ring;  /**< RX software ring. */
290a9643ea8Slogwang 	struct vq_desc_extra vq_descx[0];
291a9643ea8Slogwang };
292a9643ea8Slogwang 
293a9643ea8Slogwang /* If multiqueue is provided by host, then we suppport it. */
294a9643ea8Slogwang #define VIRTIO_NET_CTRL_MQ   4
295a9643ea8Slogwang #define VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET        0
296a9643ea8Slogwang #define VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MIN        1
297a9643ea8Slogwang #define VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MAX        0x8000
298a9643ea8Slogwang 
299a9643ea8Slogwang /**
300a9643ea8Slogwang  * This is the first element of the scatter-gather list.  If you don't
301a9643ea8Slogwang  * specify GSO or CSUM features, you can simply ignore the header.
302a9643ea8Slogwang  */
303a9643ea8Slogwang struct virtio_net_hdr {
304a9643ea8Slogwang #define VIRTIO_NET_HDR_F_NEEDS_CSUM 1    /**< Use csum_start,csum_offset*/
3052bfe3f2eSlogwang #define VIRTIO_NET_HDR_F_DATA_VALID 2    /**< Checksum is valid */
306a9643ea8Slogwang 	uint8_t flags;
307a9643ea8Slogwang #define VIRTIO_NET_HDR_GSO_NONE     0    /**< Not a GSO frame */
308a9643ea8Slogwang #define VIRTIO_NET_HDR_GSO_TCPV4    1    /**< GSO frame, IPv4 TCP (TSO) */
309a9643ea8Slogwang #define VIRTIO_NET_HDR_GSO_UDP      3    /**< GSO frame, IPv4 UDP (UFO) */
310a9643ea8Slogwang #define VIRTIO_NET_HDR_GSO_TCPV6    4    /**< GSO frame, IPv6 TCP */
311a9643ea8Slogwang #define VIRTIO_NET_HDR_GSO_ECN      0x80 /**< TCP has ECN set */
312a9643ea8Slogwang 	uint8_t gso_type;
313a9643ea8Slogwang 	uint16_t hdr_len;     /**< Ethernet + IP + tcp/udp hdrs */
314a9643ea8Slogwang 	uint16_t gso_size;    /**< Bytes to append to hdr_len per frame */
315a9643ea8Slogwang 	uint16_t csum_start;  /**< Position to start checksumming from */
316a9643ea8Slogwang 	uint16_t csum_offset; /**< Offset after that to place checksum */
317a9643ea8Slogwang };
318a9643ea8Slogwang 
319a9643ea8Slogwang /**
320a9643ea8Slogwang  * This is the version of the header to use when the MRG_RXBUF
321a9643ea8Slogwang  * feature has been negotiated.
322a9643ea8Slogwang  */
323a9643ea8Slogwang struct virtio_net_hdr_mrg_rxbuf {
324a9643ea8Slogwang 	struct   virtio_net_hdr hdr;
325a9643ea8Slogwang 	uint16_t num_buffers; /**< Number of merged rx buffers */
326a9643ea8Slogwang };
327a9643ea8Slogwang 
328a9643ea8Slogwang /* Region reserved to allow for transmit header and indirect ring */
329a9643ea8Slogwang #define VIRTIO_MAX_TX_INDIRECT 8
330a9643ea8Slogwang struct virtio_tx_region {
331a9643ea8Slogwang 	struct virtio_net_hdr_mrg_rxbuf tx_hdr;
3320c6bd470Sfengbojiang 	union {
3330c6bd470Sfengbojiang 		struct vring_desc tx_indir[VIRTIO_MAX_TX_INDIRECT];
3340c6bd470Sfengbojiang 		struct vring_packed_desc
3350c6bd470Sfengbojiang 			tx_packed_indir[VIRTIO_MAX_TX_INDIRECT];
336*2d9fd380Sjfb8856606 	} __rte_aligned(16);
337a9643ea8Slogwang };
338a9643ea8Slogwang 
3394418919fSjohnjiang static inline int
desc_is_used(struct vring_packed_desc * desc,struct virtqueue * vq)3404418919fSjohnjiang desc_is_used(struct vring_packed_desc *desc, struct virtqueue *vq)
3414418919fSjohnjiang {
3424418919fSjohnjiang 	uint16_t used, avail, flags;
3434418919fSjohnjiang 
3444418919fSjohnjiang 	flags = virtqueue_fetch_flags_packed(desc, vq->hw->weak_barriers);
3454418919fSjohnjiang 	used = !!(flags & VRING_PACKED_DESC_F_USED);
3464418919fSjohnjiang 	avail = !!(flags & VRING_PACKED_DESC_F_AVAIL);
3474418919fSjohnjiang 
3484418919fSjohnjiang 	return avail == used && used == vq->vq_packed.used_wrap_counter;
3494418919fSjohnjiang }
3504418919fSjohnjiang 
3514418919fSjohnjiang static inline void
vring_desc_init_packed(struct virtqueue * vq,int n)3524418919fSjohnjiang vring_desc_init_packed(struct virtqueue *vq, int n)
3534418919fSjohnjiang {
3544418919fSjohnjiang 	int i;
3554418919fSjohnjiang 	for (i = 0; i < n - 1; i++) {
3564418919fSjohnjiang 		vq->vq_packed.ring.desc[i].id = i;
3574418919fSjohnjiang 		vq->vq_descx[i].next = i + 1;
3584418919fSjohnjiang 	}
3594418919fSjohnjiang 	vq->vq_packed.ring.desc[i].id = i;
3604418919fSjohnjiang 	vq->vq_descx[i].next = VQ_RING_DESC_CHAIN_END;
3614418919fSjohnjiang }
3624418919fSjohnjiang 
363a9643ea8Slogwang /* Chain all the descriptors in the ring with an END */
364a9643ea8Slogwang static inline void
vring_desc_init_split(struct vring_desc * dp,uint16_t n)3654418919fSjohnjiang vring_desc_init_split(struct vring_desc *dp, uint16_t n)
366a9643ea8Slogwang {
367a9643ea8Slogwang 	uint16_t i;
368a9643ea8Slogwang 
369a9643ea8Slogwang 	for (i = 0; i < n - 1; i++)
370a9643ea8Slogwang 		dp[i].next = (uint16_t)(i + 1);
371a9643ea8Slogwang 	dp[i].next = VQ_RING_DESC_CHAIN_END;
372a9643ea8Slogwang }
373a9643ea8Slogwang 
3740c6bd470Sfengbojiang static inline void
vring_desc_init_indirect_packed(struct vring_packed_desc * dp,int n)3750c6bd470Sfengbojiang vring_desc_init_indirect_packed(struct vring_packed_desc *dp, int n)
3760c6bd470Sfengbojiang {
3770c6bd470Sfengbojiang 	int i;
3780c6bd470Sfengbojiang 	for (i = 0; i < n; i++) {
3790c6bd470Sfengbojiang 		dp[i].id = (uint16_t)i;
3800c6bd470Sfengbojiang 		dp[i].flags = VRING_DESC_F_WRITE;
3810c6bd470Sfengbojiang 	}
3820c6bd470Sfengbojiang }
3830c6bd470Sfengbojiang 
384a9643ea8Slogwang /**
3854418919fSjohnjiang  * Tell the backend not to interrupt us. Implementation for packed virtqueues.
3864418919fSjohnjiang  */
3874418919fSjohnjiang static inline void
virtqueue_disable_intr_packed(struct virtqueue * vq)3884418919fSjohnjiang virtqueue_disable_intr_packed(struct virtqueue *vq)
3894418919fSjohnjiang {
3904418919fSjohnjiang 	if (vq->vq_packed.event_flags_shadow != RING_EVENT_FLAGS_DISABLE) {
3914418919fSjohnjiang 		vq->vq_packed.event_flags_shadow = RING_EVENT_FLAGS_DISABLE;
3924418919fSjohnjiang 		vq->vq_packed.ring.driver->desc_event_flags =
3934418919fSjohnjiang 			vq->vq_packed.event_flags_shadow;
3944418919fSjohnjiang 	}
3954418919fSjohnjiang }
3964418919fSjohnjiang 
3974418919fSjohnjiang /**
3984418919fSjohnjiang  * Tell the backend not to interrupt us. Implementation for split virtqueues.
3994418919fSjohnjiang  */
4004418919fSjohnjiang static inline void
virtqueue_disable_intr_split(struct virtqueue * vq)4014418919fSjohnjiang virtqueue_disable_intr_split(struct virtqueue *vq)
4024418919fSjohnjiang {
4034418919fSjohnjiang 	vq->vq_split.ring.avail->flags |= VRING_AVAIL_F_NO_INTERRUPT;
4044418919fSjohnjiang }
4054418919fSjohnjiang 
4064418919fSjohnjiang /**
407a9643ea8Slogwang  * Tell the backend not to interrupt us.
408a9643ea8Slogwang  */
4092bfe3f2eSlogwang static inline void
virtqueue_disable_intr(struct virtqueue * vq)4102bfe3f2eSlogwang virtqueue_disable_intr(struct virtqueue *vq)
4112bfe3f2eSlogwang {
4124418919fSjohnjiang 	if (vtpci_packed_queue(vq->hw))
4134418919fSjohnjiang 		virtqueue_disable_intr_packed(vq);
4144418919fSjohnjiang 	else
4154418919fSjohnjiang 		virtqueue_disable_intr_split(vq);
4164418919fSjohnjiang }
4174418919fSjohnjiang 
4184418919fSjohnjiang /**
4194418919fSjohnjiang  * Tell the backend to interrupt. Implementation for packed virtqueues.
4204418919fSjohnjiang  */
4214418919fSjohnjiang static inline void
virtqueue_enable_intr_packed(struct virtqueue * vq)4224418919fSjohnjiang virtqueue_enable_intr_packed(struct virtqueue *vq)
4234418919fSjohnjiang {
4244418919fSjohnjiang 	if (vq->vq_packed.event_flags_shadow == RING_EVENT_FLAGS_DISABLE) {
4254418919fSjohnjiang 		vq->vq_packed.event_flags_shadow = RING_EVENT_FLAGS_ENABLE;
4264418919fSjohnjiang 		vq->vq_packed.ring.driver->desc_event_flags =
4274418919fSjohnjiang 			vq->vq_packed.event_flags_shadow;
4284418919fSjohnjiang 	}
4294418919fSjohnjiang }
4304418919fSjohnjiang 
4314418919fSjohnjiang /**
4324418919fSjohnjiang  * Tell the backend to interrupt. Implementation for split virtqueues.
4334418919fSjohnjiang  */
4344418919fSjohnjiang static inline void
virtqueue_enable_intr_split(struct virtqueue * vq)4354418919fSjohnjiang virtqueue_enable_intr_split(struct virtqueue *vq)
4364418919fSjohnjiang {
4374418919fSjohnjiang 	vq->vq_split.ring.avail->flags &= (~VRING_AVAIL_F_NO_INTERRUPT);
4382bfe3f2eSlogwang }
4392bfe3f2eSlogwang 
4402bfe3f2eSlogwang /**
4412bfe3f2eSlogwang  * Tell the backend to interrupt us.
4422bfe3f2eSlogwang  */
4432bfe3f2eSlogwang static inline void
virtqueue_enable_intr(struct virtqueue * vq)4442bfe3f2eSlogwang virtqueue_enable_intr(struct virtqueue *vq)
4452bfe3f2eSlogwang {
4464418919fSjohnjiang 	if (vtpci_packed_queue(vq->hw))
4474418919fSjohnjiang 		virtqueue_enable_intr_packed(vq);
4484418919fSjohnjiang 	else
4494418919fSjohnjiang 		virtqueue_enable_intr_split(vq);
4502bfe3f2eSlogwang }
4512bfe3f2eSlogwang 
452a9643ea8Slogwang /**
453a9643ea8Slogwang  *  Dump virtqueue internal structures, for debug purpose only.
454a9643ea8Slogwang  */
455a9643ea8Slogwang void virtqueue_dump(struct virtqueue *vq);
456a9643ea8Slogwang /**
457a9643ea8Slogwang  *  Get all mbufs to be freed.
458a9643ea8Slogwang  */
459d30ea906Sjfb8856606 struct rte_mbuf *virtqueue_detach_unused(struct virtqueue *vq);
460a9643ea8Slogwang 
4612bfe3f2eSlogwang /* Flush the elements in the used ring. */
4622bfe3f2eSlogwang void virtqueue_rxvq_flush(struct virtqueue *vq);
4632bfe3f2eSlogwang 
4644418919fSjohnjiang int virtqueue_rxvq_reset_packed(struct virtqueue *vq);
4654418919fSjohnjiang 
4664418919fSjohnjiang int virtqueue_txvq_reset_packed(struct virtqueue *vq);
4674418919fSjohnjiang 
468a9643ea8Slogwang static inline int
virtqueue_full(const struct virtqueue * vq)469a9643ea8Slogwang virtqueue_full(const struct virtqueue *vq)
470a9643ea8Slogwang {
471a9643ea8Slogwang 	return vq->vq_free_cnt == 0;
472a9643ea8Slogwang }
473a9643ea8Slogwang 
4742bfe3f2eSlogwang static inline int
virtio_get_queue_type(struct virtio_hw * hw,uint16_t vtpci_queue_idx)4752bfe3f2eSlogwang virtio_get_queue_type(struct virtio_hw *hw, uint16_t vtpci_queue_idx)
4762bfe3f2eSlogwang {
4772bfe3f2eSlogwang 	if (vtpci_queue_idx == hw->max_queue_pairs * 2)
4782bfe3f2eSlogwang 		return VTNET_CQ;
4792bfe3f2eSlogwang 	else if (vtpci_queue_idx % 2 == 0)
4802bfe3f2eSlogwang 		return VTNET_RQ;
4812bfe3f2eSlogwang 	else
4822bfe3f2eSlogwang 		return VTNET_TQ;
4832bfe3f2eSlogwang }
4842bfe3f2eSlogwang 
485*2d9fd380Sjfb8856606 /* virtqueue_nused has load-acquire or rte_io_rmb insed */
486*2d9fd380Sjfb8856606 static inline uint16_t
virtqueue_nused(const struct virtqueue * vq)487*2d9fd380Sjfb8856606 virtqueue_nused(const struct virtqueue *vq)
488*2d9fd380Sjfb8856606 {
489*2d9fd380Sjfb8856606 	uint16_t idx;
490*2d9fd380Sjfb8856606 
491*2d9fd380Sjfb8856606 	if (vq->hw->weak_barriers) {
492*2d9fd380Sjfb8856606 	/**
493*2d9fd380Sjfb8856606 	 * x86 prefers to using rte_smp_rmb over __atomic_load_n as it
494*2d9fd380Sjfb8856606 	 * reports a slightly better perf, which comes from the saved
495*2d9fd380Sjfb8856606 	 * branch by the compiler.
496*2d9fd380Sjfb8856606 	 * The if and else branches are identical with the smp and io
497*2d9fd380Sjfb8856606 	 * barriers both defined as compiler barriers on x86.
498*2d9fd380Sjfb8856606 	 */
499*2d9fd380Sjfb8856606 #ifdef RTE_ARCH_X86_64
500*2d9fd380Sjfb8856606 		idx = vq->vq_split.ring.used->idx;
501*2d9fd380Sjfb8856606 		rte_smp_rmb();
502*2d9fd380Sjfb8856606 #else
503*2d9fd380Sjfb8856606 		idx = __atomic_load_n(&(vq)->vq_split.ring.used->idx,
504*2d9fd380Sjfb8856606 				__ATOMIC_ACQUIRE);
505*2d9fd380Sjfb8856606 #endif
506*2d9fd380Sjfb8856606 	} else {
507*2d9fd380Sjfb8856606 		idx = vq->vq_split.ring.used->idx;
508*2d9fd380Sjfb8856606 		rte_io_rmb();
509*2d9fd380Sjfb8856606 	}
510*2d9fd380Sjfb8856606 	return idx - vq->vq_used_cons_idx;
511*2d9fd380Sjfb8856606 }
512a9643ea8Slogwang 
5132bfe3f2eSlogwang void vq_ring_free_chain(struct virtqueue *vq, uint16_t desc_idx);
5144418919fSjohnjiang void vq_ring_free_chain_packed(struct virtqueue *vq, uint16_t used_idx);
515d30ea906Sjfb8856606 void vq_ring_free_inorder(struct virtqueue *vq, uint16_t desc_idx,
516d30ea906Sjfb8856606 			  uint16_t num);
5172bfe3f2eSlogwang 
518a9643ea8Slogwang static inline void
vq_update_avail_idx(struct virtqueue * vq)519a9643ea8Slogwang vq_update_avail_idx(struct virtqueue *vq)
520a9643ea8Slogwang {
521*2d9fd380Sjfb8856606 	if (vq->hw->weak_barriers) {
522*2d9fd380Sjfb8856606 	/* x86 prefers to using rte_smp_wmb over __atomic_store_n as
523*2d9fd380Sjfb8856606 	 * it reports a slightly better perf, which comes from the
524*2d9fd380Sjfb8856606 	 * saved branch by the compiler.
525*2d9fd380Sjfb8856606 	 * The if and else branches are identical with the smp and
526*2d9fd380Sjfb8856606 	 * io barriers both defined as compiler barriers on x86.
527*2d9fd380Sjfb8856606 	 */
528*2d9fd380Sjfb8856606 #ifdef RTE_ARCH_X86_64
529*2d9fd380Sjfb8856606 		rte_smp_wmb();
5304418919fSjohnjiang 		vq->vq_split.ring.avail->idx = vq->vq_avail_idx;
531*2d9fd380Sjfb8856606 #else
532*2d9fd380Sjfb8856606 		__atomic_store_n(&vq->vq_split.ring.avail->idx,
533*2d9fd380Sjfb8856606 				 vq->vq_avail_idx, __ATOMIC_RELEASE);
534*2d9fd380Sjfb8856606 #endif
535*2d9fd380Sjfb8856606 	} else {
536*2d9fd380Sjfb8856606 		rte_io_wmb();
537*2d9fd380Sjfb8856606 		vq->vq_split.ring.avail->idx = vq->vq_avail_idx;
538*2d9fd380Sjfb8856606 	}
539a9643ea8Slogwang }
540a9643ea8Slogwang 
541a9643ea8Slogwang static inline void
vq_update_avail_ring(struct virtqueue * vq,uint16_t desc_idx)542a9643ea8Slogwang vq_update_avail_ring(struct virtqueue *vq, uint16_t desc_idx)
543a9643ea8Slogwang {
544a9643ea8Slogwang 	uint16_t avail_idx;
545a9643ea8Slogwang 	/*
546a9643ea8Slogwang 	 * Place the head of the descriptor chain into the next slot and make
547a9643ea8Slogwang 	 * it usable to the host. The chain is made available now rather than
548a9643ea8Slogwang 	 * deferring to virtqueue_notify() in the hopes that if the host is
549a9643ea8Slogwang 	 * currently running on another CPU, we can keep it processing the new
550a9643ea8Slogwang 	 * descriptor.
551a9643ea8Slogwang 	 */
552a9643ea8Slogwang 	avail_idx = (uint16_t)(vq->vq_avail_idx & (vq->vq_nentries - 1));
5534418919fSjohnjiang 	if (unlikely(vq->vq_split.ring.avail->ring[avail_idx] != desc_idx))
5544418919fSjohnjiang 		vq->vq_split.ring.avail->ring[avail_idx] = desc_idx;
555a9643ea8Slogwang 	vq->vq_avail_idx++;
556a9643ea8Slogwang }
557a9643ea8Slogwang 
558a9643ea8Slogwang static inline int
virtqueue_kick_prepare(struct virtqueue * vq)559a9643ea8Slogwang virtqueue_kick_prepare(struct virtqueue *vq)
560a9643ea8Slogwang {
5611646932aSjfb8856606 	/*
5621646932aSjfb8856606 	 * Ensure updated avail->idx is visible to vhost before reading
5631646932aSjfb8856606 	 * the used->flags.
5641646932aSjfb8856606 	 */
5654418919fSjohnjiang 	virtio_mb(vq->hw->weak_barriers);
5664418919fSjohnjiang 	return !(vq->vq_split.ring.used->flags & VRING_USED_F_NO_NOTIFY);
567a9643ea8Slogwang }
568a9643ea8Slogwang 
5694418919fSjohnjiang static inline int
virtqueue_kick_prepare_packed(struct virtqueue * vq)5704418919fSjohnjiang virtqueue_kick_prepare_packed(struct virtqueue *vq)
5714418919fSjohnjiang {
5724418919fSjohnjiang 	uint16_t flags;
5734418919fSjohnjiang 
5744418919fSjohnjiang 	/*
5754418919fSjohnjiang 	 * Ensure updated data is visible to vhost before reading the flags.
5764418919fSjohnjiang 	 */
5774418919fSjohnjiang 	virtio_mb(vq->hw->weak_barriers);
5784418919fSjohnjiang 	flags = vq->vq_packed.ring.device->desc_event_flags;
5794418919fSjohnjiang 
5804418919fSjohnjiang 	return flags != RING_EVENT_FLAGS_DISABLE;
5814418919fSjohnjiang }
5824418919fSjohnjiang 
5834418919fSjohnjiang /*
5844418919fSjohnjiang  * virtqueue_kick_prepare*() or the virtio_wmb() should be called
5854418919fSjohnjiang  * before this function to be sure that all the data is visible to vhost.
5864418919fSjohnjiang  */
587a9643ea8Slogwang static inline void
virtqueue_notify(struct virtqueue * vq)588a9643ea8Slogwang virtqueue_notify(struct virtqueue *vq)
589a9643ea8Slogwang {
5902bfe3f2eSlogwang 	VTPCI_OPS(vq->hw)->notify_queue(vq->hw, vq);
591a9643ea8Slogwang }
592a9643ea8Slogwang 
593a9643ea8Slogwang #ifdef RTE_LIBRTE_VIRTIO_DEBUG_DUMP
594a9643ea8Slogwang #define VIRTQUEUE_DUMP(vq) do { \
595a9643ea8Slogwang 	uint16_t used_idx, nused; \
596*2d9fd380Sjfb8856606 	used_idx = __atomic_load_n(&(vq)->vq_split.ring.used->idx, \
597*2d9fd380Sjfb8856606 				   __ATOMIC_RELAXED); \
598a9643ea8Slogwang 	nused = (uint16_t)(used_idx - (vq)->vq_used_cons_idx); \
5994418919fSjohnjiang 	if (vtpci_packed_queue((vq)->hw)) { \
6004418919fSjohnjiang 		PMD_INIT_LOG(DEBUG, \
6014418919fSjohnjiang 		"VQ: - size=%d; free=%d; used_cons_idx=%d; avail_idx=%d;" \
6024418919fSjohnjiang 		" cached_flags=0x%x; used_wrap_counter=%d", \
6034418919fSjohnjiang 		(vq)->vq_nentries, (vq)->vq_free_cnt, (vq)->vq_used_cons_idx, \
6044418919fSjohnjiang 		(vq)->vq_avail_idx, (vq)->vq_packed.cached_flags, \
6054418919fSjohnjiang 		(vq)->vq_packed.used_wrap_counter); \
6064418919fSjohnjiang 		break; \
6074418919fSjohnjiang 	} \
608a9643ea8Slogwang 	PMD_INIT_LOG(DEBUG, \
609a9643ea8Slogwang 	  "VQ: - size=%d; free=%d; used=%d; desc_head_idx=%d;" \
610a9643ea8Slogwang 	  " avail.idx=%d; used_cons_idx=%d; used.idx=%d;" \
611a9643ea8Slogwang 	  " avail.flags=0x%x; used.flags=0x%x", \
612*2d9fd380Sjfb8856606 	  (vq)->vq_nentries, (vq)->vq_free_cnt, nused, (vq)->vq_desc_head_idx, \
613*2d9fd380Sjfb8856606 	  (vq)->vq_split.ring.avail->idx, (vq)->vq_used_cons_idx, \
614*2d9fd380Sjfb8856606 	  __atomic_load_n(&(vq)->vq_split.ring.used->idx, __ATOMIC_RELAXED), \
6154418919fSjohnjiang 	  (vq)->vq_split.ring.avail->flags, (vq)->vq_split.ring.used->flags); \
616a9643ea8Slogwang } while (0)
617a9643ea8Slogwang #else
618a9643ea8Slogwang #define VIRTQUEUE_DUMP(vq) do { } while (0)
619a9643ea8Slogwang #endif
620a9643ea8Slogwang 
621*2d9fd380Sjfb8856606 /* avoid write operation when necessary, to lessen cache issues */
622*2d9fd380Sjfb8856606 #define ASSIGN_UNLESS_EQUAL(var, val) do {	\
623*2d9fd380Sjfb8856606 	typeof(var) *const var_ = &(var);	\
624*2d9fd380Sjfb8856606 	typeof(val)  const val_ = (val);	\
625*2d9fd380Sjfb8856606 	if (*var_ != val_)			\
626*2d9fd380Sjfb8856606 		*var_ = val_;			\
627*2d9fd380Sjfb8856606 } while (0)
628*2d9fd380Sjfb8856606 
629*2d9fd380Sjfb8856606 #define virtqueue_clear_net_hdr(hdr) do {		\
630*2d9fd380Sjfb8856606 	typeof(hdr) hdr_ = (hdr);			\
631*2d9fd380Sjfb8856606 	ASSIGN_UNLESS_EQUAL((hdr_)->csum_start, 0);	\
632*2d9fd380Sjfb8856606 	ASSIGN_UNLESS_EQUAL((hdr_)->csum_offset, 0);	\
633*2d9fd380Sjfb8856606 	ASSIGN_UNLESS_EQUAL((hdr_)->flags, 0);		\
634*2d9fd380Sjfb8856606 	ASSIGN_UNLESS_EQUAL((hdr_)->gso_type, 0);	\
635*2d9fd380Sjfb8856606 	ASSIGN_UNLESS_EQUAL((hdr_)->gso_size, 0);	\
636*2d9fd380Sjfb8856606 	ASSIGN_UNLESS_EQUAL((hdr_)->hdr_len, 0);	\
637*2d9fd380Sjfb8856606 } while (0)
638*2d9fd380Sjfb8856606 
639*2d9fd380Sjfb8856606 static inline void
virtqueue_xmit_offload(struct virtio_net_hdr * hdr,struct rte_mbuf * cookie,bool offload)640*2d9fd380Sjfb8856606 virtqueue_xmit_offload(struct virtio_net_hdr *hdr,
641*2d9fd380Sjfb8856606 			struct rte_mbuf *cookie,
642*2d9fd380Sjfb8856606 			bool offload)
643*2d9fd380Sjfb8856606 {
644*2d9fd380Sjfb8856606 	if (offload) {
645*2d9fd380Sjfb8856606 		if (cookie->ol_flags & PKT_TX_TCP_SEG)
646*2d9fd380Sjfb8856606 			cookie->ol_flags |= PKT_TX_TCP_CKSUM;
647*2d9fd380Sjfb8856606 
648*2d9fd380Sjfb8856606 		switch (cookie->ol_flags & PKT_TX_L4_MASK) {
649*2d9fd380Sjfb8856606 		case PKT_TX_UDP_CKSUM:
650*2d9fd380Sjfb8856606 			hdr->csum_start = cookie->l2_len + cookie->l3_len;
651*2d9fd380Sjfb8856606 			hdr->csum_offset = offsetof(struct rte_udp_hdr,
652*2d9fd380Sjfb8856606 				dgram_cksum);
653*2d9fd380Sjfb8856606 			hdr->flags = VIRTIO_NET_HDR_F_NEEDS_CSUM;
654*2d9fd380Sjfb8856606 			break;
655*2d9fd380Sjfb8856606 
656*2d9fd380Sjfb8856606 		case PKT_TX_TCP_CKSUM:
657*2d9fd380Sjfb8856606 			hdr->csum_start = cookie->l2_len + cookie->l3_len;
658*2d9fd380Sjfb8856606 			hdr->csum_offset = offsetof(struct rte_tcp_hdr, cksum);
659*2d9fd380Sjfb8856606 			hdr->flags = VIRTIO_NET_HDR_F_NEEDS_CSUM;
660*2d9fd380Sjfb8856606 			break;
661*2d9fd380Sjfb8856606 
662*2d9fd380Sjfb8856606 		default:
663*2d9fd380Sjfb8856606 			ASSIGN_UNLESS_EQUAL(hdr->csum_start, 0);
664*2d9fd380Sjfb8856606 			ASSIGN_UNLESS_EQUAL(hdr->csum_offset, 0);
665*2d9fd380Sjfb8856606 			ASSIGN_UNLESS_EQUAL(hdr->flags, 0);
666*2d9fd380Sjfb8856606 			break;
667*2d9fd380Sjfb8856606 		}
668*2d9fd380Sjfb8856606 
669*2d9fd380Sjfb8856606 		/* TCP Segmentation Offload */
670*2d9fd380Sjfb8856606 		if (cookie->ol_flags & PKT_TX_TCP_SEG) {
671*2d9fd380Sjfb8856606 			hdr->gso_type = (cookie->ol_flags & PKT_TX_IPV6) ?
672*2d9fd380Sjfb8856606 				VIRTIO_NET_HDR_GSO_TCPV6 :
673*2d9fd380Sjfb8856606 				VIRTIO_NET_HDR_GSO_TCPV4;
674*2d9fd380Sjfb8856606 			hdr->gso_size = cookie->tso_segsz;
675*2d9fd380Sjfb8856606 			hdr->hdr_len =
676*2d9fd380Sjfb8856606 				cookie->l2_len +
677*2d9fd380Sjfb8856606 				cookie->l3_len +
678*2d9fd380Sjfb8856606 				cookie->l4_len;
679*2d9fd380Sjfb8856606 		} else {
680*2d9fd380Sjfb8856606 			ASSIGN_UNLESS_EQUAL(hdr->gso_type, 0);
681*2d9fd380Sjfb8856606 			ASSIGN_UNLESS_EQUAL(hdr->gso_size, 0);
682*2d9fd380Sjfb8856606 			ASSIGN_UNLESS_EQUAL(hdr->hdr_len, 0);
683*2d9fd380Sjfb8856606 		}
684*2d9fd380Sjfb8856606 	}
685*2d9fd380Sjfb8856606 }
686*2d9fd380Sjfb8856606 
687*2d9fd380Sjfb8856606 static inline void
virtqueue_enqueue_xmit_packed(struct virtnet_tx * txvq,struct rte_mbuf * cookie,uint16_t needed,int use_indirect,int can_push,int in_order)688*2d9fd380Sjfb8856606 virtqueue_enqueue_xmit_packed(struct virtnet_tx *txvq, struct rte_mbuf *cookie,
689*2d9fd380Sjfb8856606 			      uint16_t needed, int use_indirect, int can_push,
690*2d9fd380Sjfb8856606 			      int in_order)
691*2d9fd380Sjfb8856606 {
692*2d9fd380Sjfb8856606 	struct virtio_tx_region *txr = txvq->virtio_net_hdr_mz->addr;
693*2d9fd380Sjfb8856606 	struct vq_desc_extra *dxp;
694*2d9fd380Sjfb8856606 	struct virtqueue *vq = txvq->vq;
695*2d9fd380Sjfb8856606 	struct vring_packed_desc *start_dp, *head_dp;
696*2d9fd380Sjfb8856606 	uint16_t idx, id, head_idx, head_flags;
697*2d9fd380Sjfb8856606 	int16_t head_size = vq->hw->vtnet_hdr_size;
698*2d9fd380Sjfb8856606 	struct virtio_net_hdr *hdr;
699*2d9fd380Sjfb8856606 	uint16_t prev;
700*2d9fd380Sjfb8856606 	bool prepend_header = false;
701*2d9fd380Sjfb8856606 	uint16_t seg_num = cookie->nb_segs;
702*2d9fd380Sjfb8856606 
703*2d9fd380Sjfb8856606 	id = in_order ? vq->vq_avail_idx : vq->vq_desc_head_idx;
704*2d9fd380Sjfb8856606 
705*2d9fd380Sjfb8856606 	dxp = &vq->vq_descx[id];
706*2d9fd380Sjfb8856606 	dxp->ndescs = needed;
707*2d9fd380Sjfb8856606 	dxp->cookie = cookie;
708*2d9fd380Sjfb8856606 
709*2d9fd380Sjfb8856606 	head_idx = vq->vq_avail_idx;
710*2d9fd380Sjfb8856606 	idx = head_idx;
711*2d9fd380Sjfb8856606 	prev = head_idx;
712*2d9fd380Sjfb8856606 	start_dp = vq->vq_packed.ring.desc;
713*2d9fd380Sjfb8856606 
714*2d9fd380Sjfb8856606 	head_dp = &vq->vq_packed.ring.desc[idx];
715*2d9fd380Sjfb8856606 	head_flags = cookie->next ? VRING_DESC_F_NEXT : 0;
716*2d9fd380Sjfb8856606 	head_flags |= vq->vq_packed.cached_flags;
717*2d9fd380Sjfb8856606 
718*2d9fd380Sjfb8856606 	if (can_push) {
719*2d9fd380Sjfb8856606 		/* prepend cannot fail, checked by caller */
720*2d9fd380Sjfb8856606 		hdr = rte_pktmbuf_mtod_offset(cookie, struct virtio_net_hdr *,
721*2d9fd380Sjfb8856606 					      -head_size);
722*2d9fd380Sjfb8856606 		prepend_header = true;
723*2d9fd380Sjfb8856606 
724*2d9fd380Sjfb8856606 		/* if offload disabled, it is not zeroed below, do it now */
725*2d9fd380Sjfb8856606 		if (!vq->hw->has_tx_offload)
726*2d9fd380Sjfb8856606 			virtqueue_clear_net_hdr(hdr);
727*2d9fd380Sjfb8856606 	} else if (use_indirect) {
728*2d9fd380Sjfb8856606 		/* setup tx ring slot to point to indirect
729*2d9fd380Sjfb8856606 		 * descriptor list stored in reserved region.
730*2d9fd380Sjfb8856606 		 *
731*2d9fd380Sjfb8856606 		 * the first slot in indirect ring is already preset
732*2d9fd380Sjfb8856606 		 * to point to the header in reserved region
733*2d9fd380Sjfb8856606 		 */
734*2d9fd380Sjfb8856606 		start_dp[idx].addr  = txvq->virtio_net_hdr_mem +
735*2d9fd380Sjfb8856606 			RTE_PTR_DIFF(&txr[idx].tx_packed_indir, txr);
736*2d9fd380Sjfb8856606 		start_dp[idx].len   = (seg_num + 1) *
737*2d9fd380Sjfb8856606 			sizeof(struct vring_packed_desc);
738*2d9fd380Sjfb8856606 		/* reset flags for indirect desc */
739*2d9fd380Sjfb8856606 		head_flags = VRING_DESC_F_INDIRECT;
740*2d9fd380Sjfb8856606 		head_flags |= vq->vq_packed.cached_flags;
741*2d9fd380Sjfb8856606 		hdr = (struct virtio_net_hdr *)&txr[idx].tx_hdr;
742*2d9fd380Sjfb8856606 
743*2d9fd380Sjfb8856606 		/* loop below will fill in rest of the indirect elements */
744*2d9fd380Sjfb8856606 		start_dp = txr[idx].tx_packed_indir;
745*2d9fd380Sjfb8856606 		idx = 1;
746*2d9fd380Sjfb8856606 	} else {
747*2d9fd380Sjfb8856606 		/* setup first tx ring slot to point to header
748*2d9fd380Sjfb8856606 		 * stored in reserved region.
749*2d9fd380Sjfb8856606 		 */
750*2d9fd380Sjfb8856606 		start_dp[idx].addr  = txvq->virtio_net_hdr_mem +
751*2d9fd380Sjfb8856606 			RTE_PTR_DIFF(&txr[idx].tx_hdr, txr);
752*2d9fd380Sjfb8856606 		start_dp[idx].len   = vq->hw->vtnet_hdr_size;
753*2d9fd380Sjfb8856606 		hdr = (struct virtio_net_hdr *)&txr[idx].tx_hdr;
754*2d9fd380Sjfb8856606 		idx++;
755*2d9fd380Sjfb8856606 		if (idx >= vq->vq_nentries) {
756*2d9fd380Sjfb8856606 			idx -= vq->vq_nentries;
757*2d9fd380Sjfb8856606 			vq->vq_packed.cached_flags ^=
758*2d9fd380Sjfb8856606 				VRING_PACKED_DESC_F_AVAIL_USED;
759*2d9fd380Sjfb8856606 		}
760*2d9fd380Sjfb8856606 	}
761*2d9fd380Sjfb8856606 
762*2d9fd380Sjfb8856606 	virtqueue_xmit_offload(hdr, cookie, vq->hw->has_tx_offload);
763*2d9fd380Sjfb8856606 
764*2d9fd380Sjfb8856606 	do {
765*2d9fd380Sjfb8856606 		uint16_t flags;
766*2d9fd380Sjfb8856606 
767*2d9fd380Sjfb8856606 		start_dp[idx].addr = VIRTIO_MBUF_DATA_DMA_ADDR(cookie, vq);
768*2d9fd380Sjfb8856606 		start_dp[idx].len  = cookie->data_len;
769*2d9fd380Sjfb8856606 		if (prepend_header) {
770*2d9fd380Sjfb8856606 			start_dp[idx].addr -= head_size;
771*2d9fd380Sjfb8856606 			start_dp[idx].len += head_size;
772*2d9fd380Sjfb8856606 			prepend_header = false;
773*2d9fd380Sjfb8856606 		}
774*2d9fd380Sjfb8856606 
775*2d9fd380Sjfb8856606 		if (likely(idx != head_idx)) {
776*2d9fd380Sjfb8856606 			flags = cookie->next ? VRING_DESC_F_NEXT : 0;
777*2d9fd380Sjfb8856606 			flags |= vq->vq_packed.cached_flags;
778*2d9fd380Sjfb8856606 			start_dp[idx].flags = flags;
779*2d9fd380Sjfb8856606 		}
780*2d9fd380Sjfb8856606 		prev = idx;
781*2d9fd380Sjfb8856606 		idx++;
782*2d9fd380Sjfb8856606 		if (idx >= vq->vq_nentries) {
783*2d9fd380Sjfb8856606 			idx -= vq->vq_nentries;
784*2d9fd380Sjfb8856606 			vq->vq_packed.cached_flags ^=
785*2d9fd380Sjfb8856606 				VRING_PACKED_DESC_F_AVAIL_USED;
786*2d9fd380Sjfb8856606 		}
787*2d9fd380Sjfb8856606 	} while ((cookie = cookie->next) != NULL);
788*2d9fd380Sjfb8856606 
789*2d9fd380Sjfb8856606 	start_dp[prev].id = id;
790*2d9fd380Sjfb8856606 
791*2d9fd380Sjfb8856606 	if (use_indirect) {
792*2d9fd380Sjfb8856606 		idx = head_idx;
793*2d9fd380Sjfb8856606 		if (++idx >= vq->vq_nentries) {
794*2d9fd380Sjfb8856606 			idx -= vq->vq_nentries;
795*2d9fd380Sjfb8856606 			vq->vq_packed.cached_flags ^=
796*2d9fd380Sjfb8856606 				VRING_PACKED_DESC_F_AVAIL_USED;
797*2d9fd380Sjfb8856606 		}
798*2d9fd380Sjfb8856606 	}
799*2d9fd380Sjfb8856606 
800*2d9fd380Sjfb8856606 	vq->vq_free_cnt = (uint16_t)(vq->vq_free_cnt - needed);
801*2d9fd380Sjfb8856606 	vq->vq_avail_idx = idx;
802*2d9fd380Sjfb8856606 
803*2d9fd380Sjfb8856606 	if (!in_order) {
804*2d9fd380Sjfb8856606 		vq->vq_desc_head_idx = dxp->next;
805*2d9fd380Sjfb8856606 		if (vq->vq_desc_head_idx == VQ_RING_DESC_CHAIN_END)
806*2d9fd380Sjfb8856606 			vq->vq_desc_tail_idx = VQ_RING_DESC_CHAIN_END;
807*2d9fd380Sjfb8856606 	}
808*2d9fd380Sjfb8856606 
809*2d9fd380Sjfb8856606 	virtqueue_store_flags_packed(head_dp, head_flags,
810*2d9fd380Sjfb8856606 				     vq->hw->weak_barriers);
811*2d9fd380Sjfb8856606 }
812*2d9fd380Sjfb8856606 
813*2d9fd380Sjfb8856606 static void
vq_ring_free_id_packed(struct virtqueue * vq,uint16_t id)814*2d9fd380Sjfb8856606 vq_ring_free_id_packed(struct virtqueue *vq, uint16_t id)
815*2d9fd380Sjfb8856606 {
816*2d9fd380Sjfb8856606 	struct vq_desc_extra *dxp;
817*2d9fd380Sjfb8856606 
818*2d9fd380Sjfb8856606 	dxp = &vq->vq_descx[id];
819*2d9fd380Sjfb8856606 	vq->vq_free_cnt += dxp->ndescs;
820*2d9fd380Sjfb8856606 
821*2d9fd380Sjfb8856606 	if (vq->vq_desc_tail_idx == VQ_RING_DESC_CHAIN_END)
822*2d9fd380Sjfb8856606 		vq->vq_desc_head_idx = id;
823*2d9fd380Sjfb8856606 	else
824*2d9fd380Sjfb8856606 		vq->vq_descx[vq->vq_desc_tail_idx].next = id;
825*2d9fd380Sjfb8856606 
826*2d9fd380Sjfb8856606 	vq->vq_desc_tail_idx = id;
827*2d9fd380Sjfb8856606 	dxp->next = VQ_RING_DESC_CHAIN_END;
828*2d9fd380Sjfb8856606 }
829*2d9fd380Sjfb8856606 
830*2d9fd380Sjfb8856606 static void
virtio_xmit_cleanup_inorder_packed(struct virtqueue * vq,int num)831*2d9fd380Sjfb8856606 virtio_xmit_cleanup_inorder_packed(struct virtqueue *vq, int num)
832*2d9fd380Sjfb8856606 {
833*2d9fd380Sjfb8856606 	uint16_t used_idx, id, curr_id, free_cnt = 0;
834*2d9fd380Sjfb8856606 	uint16_t size = vq->vq_nentries;
835*2d9fd380Sjfb8856606 	struct vring_packed_desc *desc = vq->vq_packed.ring.desc;
836*2d9fd380Sjfb8856606 	struct vq_desc_extra *dxp;
837*2d9fd380Sjfb8856606 
838*2d9fd380Sjfb8856606 	used_idx = vq->vq_used_cons_idx;
839*2d9fd380Sjfb8856606 	/* desc_is_used has a load-acquire or rte_io_rmb inside
840*2d9fd380Sjfb8856606 	 * and wait for used desc in virtqueue.
841*2d9fd380Sjfb8856606 	 */
842*2d9fd380Sjfb8856606 	while (num > 0 && desc_is_used(&desc[used_idx], vq)) {
843*2d9fd380Sjfb8856606 		id = desc[used_idx].id;
844*2d9fd380Sjfb8856606 		do {
845*2d9fd380Sjfb8856606 			curr_id = used_idx;
846*2d9fd380Sjfb8856606 			dxp = &vq->vq_descx[used_idx];
847*2d9fd380Sjfb8856606 			used_idx += dxp->ndescs;
848*2d9fd380Sjfb8856606 			free_cnt += dxp->ndescs;
849*2d9fd380Sjfb8856606 			num -= dxp->ndescs;
850*2d9fd380Sjfb8856606 			if (used_idx >= size) {
851*2d9fd380Sjfb8856606 				used_idx -= size;
852*2d9fd380Sjfb8856606 				vq->vq_packed.used_wrap_counter ^= 1;
853*2d9fd380Sjfb8856606 			}
854*2d9fd380Sjfb8856606 			if (dxp->cookie != NULL) {
855*2d9fd380Sjfb8856606 				rte_pktmbuf_free(dxp->cookie);
856*2d9fd380Sjfb8856606 				dxp->cookie = NULL;
857*2d9fd380Sjfb8856606 			}
858*2d9fd380Sjfb8856606 		} while (curr_id != id);
859*2d9fd380Sjfb8856606 	}
860*2d9fd380Sjfb8856606 	vq->vq_used_cons_idx = used_idx;
861*2d9fd380Sjfb8856606 	vq->vq_free_cnt += free_cnt;
862*2d9fd380Sjfb8856606 }
863*2d9fd380Sjfb8856606 
864*2d9fd380Sjfb8856606 static void
virtio_xmit_cleanup_normal_packed(struct virtqueue * vq,int num)865*2d9fd380Sjfb8856606 virtio_xmit_cleanup_normal_packed(struct virtqueue *vq, int num)
866*2d9fd380Sjfb8856606 {
867*2d9fd380Sjfb8856606 	uint16_t used_idx, id;
868*2d9fd380Sjfb8856606 	uint16_t size = vq->vq_nentries;
869*2d9fd380Sjfb8856606 	struct vring_packed_desc *desc = vq->vq_packed.ring.desc;
870*2d9fd380Sjfb8856606 	struct vq_desc_extra *dxp;
871*2d9fd380Sjfb8856606 
872*2d9fd380Sjfb8856606 	used_idx = vq->vq_used_cons_idx;
873*2d9fd380Sjfb8856606 	/* desc_is_used has a load-acquire or rte_io_rmb inside
874*2d9fd380Sjfb8856606 	 * and wait for used desc in virtqueue.
875*2d9fd380Sjfb8856606 	 */
876*2d9fd380Sjfb8856606 	while (num-- && desc_is_used(&desc[used_idx], vq)) {
877*2d9fd380Sjfb8856606 		id = desc[used_idx].id;
878*2d9fd380Sjfb8856606 		dxp = &vq->vq_descx[id];
879*2d9fd380Sjfb8856606 		vq->vq_used_cons_idx += dxp->ndescs;
880*2d9fd380Sjfb8856606 		if (vq->vq_used_cons_idx >= size) {
881*2d9fd380Sjfb8856606 			vq->vq_used_cons_idx -= size;
882*2d9fd380Sjfb8856606 			vq->vq_packed.used_wrap_counter ^= 1;
883*2d9fd380Sjfb8856606 		}
884*2d9fd380Sjfb8856606 		vq_ring_free_id_packed(vq, id);
885*2d9fd380Sjfb8856606 		if (dxp->cookie != NULL) {
886*2d9fd380Sjfb8856606 			rte_pktmbuf_free(dxp->cookie);
887*2d9fd380Sjfb8856606 			dxp->cookie = NULL;
888*2d9fd380Sjfb8856606 		}
889*2d9fd380Sjfb8856606 		used_idx = vq->vq_used_cons_idx;
890*2d9fd380Sjfb8856606 	}
891*2d9fd380Sjfb8856606 }
892*2d9fd380Sjfb8856606 
893*2d9fd380Sjfb8856606 /* Cleanup from completed transmits. */
894*2d9fd380Sjfb8856606 static inline void
virtio_xmit_cleanup_packed(struct virtqueue * vq,int num,int in_order)895*2d9fd380Sjfb8856606 virtio_xmit_cleanup_packed(struct virtqueue *vq, int num, int in_order)
896*2d9fd380Sjfb8856606 {
897*2d9fd380Sjfb8856606 	if (in_order)
898*2d9fd380Sjfb8856606 		virtio_xmit_cleanup_inorder_packed(vq, num);
899*2d9fd380Sjfb8856606 	else
900*2d9fd380Sjfb8856606 		virtio_xmit_cleanup_normal_packed(vq, num);
901*2d9fd380Sjfb8856606 }
902*2d9fd380Sjfb8856606 
903*2d9fd380Sjfb8856606 static inline void
virtio_xmit_cleanup(struct virtqueue * vq,uint16_t num)904*2d9fd380Sjfb8856606 virtio_xmit_cleanup(struct virtqueue *vq, uint16_t num)
905*2d9fd380Sjfb8856606 {
906*2d9fd380Sjfb8856606 	uint16_t i, used_idx, desc_idx;
907*2d9fd380Sjfb8856606 	for (i = 0; i < num; i++) {
908*2d9fd380Sjfb8856606 		struct vring_used_elem *uep;
909*2d9fd380Sjfb8856606 		struct vq_desc_extra *dxp;
910*2d9fd380Sjfb8856606 
911*2d9fd380Sjfb8856606 		used_idx = (uint16_t)(vq->vq_used_cons_idx &
912*2d9fd380Sjfb8856606 				(vq->vq_nentries - 1));
913*2d9fd380Sjfb8856606 		uep = &vq->vq_split.ring.used->ring[used_idx];
914*2d9fd380Sjfb8856606 
915*2d9fd380Sjfb8856606 		desc_idx = (uint16_t)uep->id;
916*2d9fd380Sjfb8856606 		dxp = &vq->vq_descx[desc_idx];
917*2d9fd380Sjfb8856606 		vq->vq_used_cons_idx++;
918*2d9fd380Sjfb8856606 		vq_ring_free_chain(vq, desc_idx);
919*2d9fd380Sjfb8856606 
920*2d9fd380Sjfb8856606 		if (dxp->cookie != NULL) {
921*2d9fd380Sjfb8856606 			rte_pktmbuf_free(dxp->cookie);
922*2d9fd380Sjfb8856606 			dxp->cookie = NULL;
923*2d9fd380Sjfb8856606 		}
924*2d9fd380Sjfb8856606 	}
925*2d9fd380Sjfb8856606 }
926*2d9fd380Sjfb8856606 
927*2d9fd380Sjfb8856606 /* Cleanup from completed inorder transmits. */
928*2d9fd380Sjfb8856606 static __rte_always_inline void
virtio_xmit_cleanup_inorder(struct virtqueue * vq,uint16_t num)929*2d9fd380Sjfb8856606 virtio_xmit_cleanup_inorder(struct virtqueue *vq, uint16_t num)
930*2d9fd380Sjfb8856606 {
931*2d9fd380Sjfb8856606 	uint16_t i, idx = vq->vq_used_cons_idx;
932*2d9fd380Sjfb8856606 	int16_t free_cnt = 0;
933*2d9fd380Sjfb8856606 	struct vq_desc_extra *dxp = NULL;
934*2d9fd380Sjfb8856606 
935*2d9fd380Sjfb8856606 	if (unlikely(num == 0))
936*2d9fd380Sjfb8856606 		return;
937*2d9fd380Sjfb8856606 
938*2d9fd380Sjfb8856606 	for (i = 0; i < num; i++) {
939*2d9fd380Sjfb8856606 		dxp = &vq->vq_descx[idx++ & (vq->vq_nentries - 1)];
940*2d9fd380Sjfb8856606 		free_cnt += dxp->ndescs;
941*2d9fd380Sjfb8856606 		if (dxp->cookie != NULL) {
942*2d9fd380Sjfb8856606 			rte_pktmbuf_free(dxp->cookie);
943*2d9fd380Sjfb8856606 			dxp->cookie = NULL;
944*2d9fd380Sjfb8856606 		}
945*2d9fd380Sjfb8856606 	}
946*2d9fd380Sjfb8856606 
947*2d9fd380Sjfb8856606 	vq->vq_free_cnt += free_cnt;
948*2d9fd380Sjfb8856606 	vq->vq_used_cons_idx = idx;
949*2d9fd380Sjfb8856606 }
950a9643ea8Slogwang #endif /* _VIRTQUEUE_H_ */
951