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