1a96102c8SMichael Baum /* SPDX-License-Identifier: BSD-3-Clause 2a96102c8SMichael Baum * Copyright 2021 6WIND S.A. 3a96102c8SMichael Baum * Copyright 2021 Mellanox Technologies, Ltd 4a96102c8SMichael Baum */ 5a96102c8SMichael Baum 6a96102c8SMichael Baum #include <stdint.h> 7a96102c8SMichael Baum #include <string.h> 8a96102c8SMichael Baum #include <stdlib.h> 9a96102c8SMichael Baum 10a96102c8SMichael Baum #include <rte_mbuf.h> 11a96102c8SMichael Baum #include <rte_mempool.h> 12a96102c8SMichael Baum #include <rte_prefetch.h> 13a96102c8SMichael Baum #include <rte_common.h> 14a96102c8SMichael Baum #include <rte_branch_prediction.h> 15a96102c8SMichael Baum #include <rte_ether.h> 16a96102c8SMichael Baum #include <rte_cycles.h> 17a96102c8SMichael Baum #include <rte_flow.h> 18a96102c8SMichael Baum 19a96102c8SMichael Baum #include <mlx5_prm.h> 20a96102c8SMichael Baum #include <mlx5_common.h> 21fc59a1ecSMichael Baum #include <mlx5_common_mr.h> 22a96102c8SMichael Baum 23a96102c8SMichael Baum #include "mlx5_autoconf.h" 24a96102c8SMichael Baum #include "mlx5_defs.h" 25a96102c8SMichael Baum #include "mlx5.h" 26a96102c8SMichael Baum #include "mlx5_utils.h" 27a96102c8SMichael Baum #include "mlx5_rxtx.h" 28a96102c8SMichael Baum #include "mlx5_rx.h" 29a96102c8SMichael Baum 30a96102c8SMichael Baum 31a96102c8SMichael Baum static __rte_always_inline uint32_t 32a96102c8SMichael Baum rxq_cq_to_pkt_type(struct mlx5_rxq_data *rxq, volatile struct mlx5_cqe *cqe, 33a96102c8SMichael Baum volatile struct mlx5_mini_cqe8 *mcqe); 34a96102c8SMichael Baum 35a96102c8SMichael Baum static __rte_always_inline int 36a96102c8SMichael Baum mlx5_rx_poll_len(struct mlx5_rxq_data *rxq, volatile struct mlx5_cqe *cqe, 37a96102c8SMichael Baum uint16_t cqe_cnt, volatile struct mlx5_mini_cqe8 **mcqe); 38a96102c8SMichael Baum 39a96102c8SMichael Baum static __rte_always_inline uint32_t 40a96102c8SMichael Baum rxq_cq_to_ol_flags(volatile struct mlx5_cqe *cqe); 41a96102c8SMichael Baum 42a96102c8SMichael Baum static __rte_always_inline void 43a96102c8SMichael Baum rxq_cq_to_mbuf(struct mlx5_rxq_data *rxq, struct rte_mbuf *pkt, 44a96102c8SMichael Baum volatile struct mlx5_cqe *cqe, 45a96102c8SMichael Baum volatile struct mlx5_mini_cqe8 *mcqe); 46a96102c8SMichael Baum 47a96102c8SMichael Baum static inline void 48a96102c8SMichael Baum mlx5_lro_update_tcp_hdr(struct rte_tcp_hdr *__rte_restrict tcp, 49a96102c8SMichael Baum volatile struct mlx5_cqe *__rte_restrict cqe, 50a96102c8SMichael Baum uint32_t phcsum, uint8_t l4_type); 51a96102c8SMichael Baum 52a96102c8SMichael Baum static inline void 53a96102c8SMichael Baum mlx5_lro_update_hdr(uint8_t *__rte_restrict padd, 54a96102c8SMichael Baum volatile struct mlx5_cqe *__rte_restrict cqe, 55a96102c8SMichael Baum volatile struct mlx5_mini_cqe8 *mcqe, 56a96102c8SMichael Baum struct mlx5_rxq_data *rxq, uint32_t len); 57a96102c8SMichael Baum 58a96102c8SMichael Baum 59a96102c8SMichael Baum /** 60a96102c8SMichael Baum * Internal function to compute the number of used descriptors in an RX queue. 61a96102c8SMichael Baum * 62a96102c8SMichael Baum * @param rxq 63a96102c8SMichael Baum * The Rx queue. 64a96102c8SMichael Baum * 65a96102c8SMichael Baum * @return 66a96102c8SMichael Baum * The number of used Rx descriptor. 67a96102c8SMichael Baum */ 68a96102c8SMichael Baum static uint32_t 69a96102c8SMichael Baum rx_queue_count(struct mlx5_rxq_data *rxq) 70a96102c8SMichael Baum { 71a96102c8SMichael Baum struct rxq_zip *zip = &rxq->zip; 72a96102c8SMichael Baum volatile struct mlx5_cqe *cqe; 73a96102c8SMichael Baum const unsigned int cqe_n = (1 << rxq->cqe_n); 74a96102c8SMichael Baum const unsigned int sges_n = (1 << rxq->sges_n); 75a96102c8SMichael Baum const unsigned int elts_n = (1 << rxq->elts_n); 76a96102c8SMichael Baum const unsigned int strd_n = (1 << rxq->strd_num_n); 77a96102c8SMichael Baum const unsigned int cqe_cnt = cqe_n - 1; 78a96102c8SMichael Baum unsigned int cq_ci, used; 79a96102c8SMichael Baum 80a96102c8SMichael Baum /* if we are processing a compressed cqe */ 81a96102c8SMichael Baum if (zip->ai) { 82a96102c8SMichael Baum used = zip->cqe_cnt - zip->ai; 83a96102c8SMichael Baum cq_ci = zip->cq_ci; 84a96102c8SMichael Baum } else { 85a96102c8SMichael Baum used = 0; 86a96102c8SMichael Baum cq_ci = rxq->cq_ci; 87a96102c8SMichael Baum } 88a96102c8SMichael Baum cqe = &(*rxq->cqes)[cq_ci & cqe_cnt]; 89a96102c8SMichael Baum while (check_cqe(cqe, cqe_n, cq_ci) != MLX5_CQE_STATUS_HW_OWN) { 90a96102c8SMichael Baum int8_t op_own; 91a96102c8SMichael Baum unsigned int n; 92a96102c8SMichael Baum 93a96102c8SMichael Baum op_own = cqe->op_own; 94a96102c8SMichael Baum if (MLX5_CQE_FORMAT(op_own) == MLX5_COMPRESSED) 95a96102c8SMichael Baum n = rte_be_to_cpu_32(cqe->byte_cnt); 96a96102c8SMichael Baum else 97a96102c8SMichael Baum n = 1; 98a96102c8SMichael Baum cq_ci += n; 99a96102c8SMichael Baum used += n; 100a96102c8SMichael Baum cqe = &(*rxq->cqes)[cq_ci & cqe_cnt]; 101a96102c8SMichael Baum } 102a96102c8SMichael Baum used = RTE_MIN(used * sges_n, elts_n * strd_n); 103a96102c8SMichael Baum return used; 104a96102c8SMichael Baum } 105a96102c8SMichael Baum 106a96102c8SMichael Baum /** 107a96102c8SMichael Baum * DPDK callback to check the status of a Rx descriptor. 108a96102c8SMichael Baum * 109a96102c8SMichael Baum * @param rx_queue 110a96102c8SMichael Baum * The Rx queue. 111a96102c8SMichael Baum * @param[in] offset 112a96102c8SMichael Baum * The index of the descriptor in the ring. 113a96102c8SMichael Baum * 114a96102c8SMichael Baum * @return 115a96102c8SMichael Baum * The status of the Rx descriptor. 116a96102c8SMichael Baum */ 117a96102c8SMichael Baum int 118a96102c8SMichael Baum mlx5_rx_descriptor_status(void *rx_queue, uint16_t offset) 119a96102c8SMichael Baum { 120a96102c8SMichael Baum struct mlx5_rxq_data *rxq = rx_queue; 121a96102c8SMichael Baum struct mlx5_rxq_ctrl *rxq_ctrl = 122a96102c8SMichael Baum container_of(rxq, struct mlx5_rxq_ctrl, rxq); 123a96102c8SMichael Baum struct rte_eth_dev *dev = ETH_DEV(rxq_ctrl->priv); 124a96102c8SMichael Baum 125a96102c8SMichael Baum if (dev->rx_pkt_burst == NULL || 126a96102c8SMichael Baum dev->rx_pkt_burst == removed_rx_burst) { 127a96102c8SMichael Baum rte_errno = ENOTSUP; 128a96102c8SMichael Baum return -rte_errno; 129a96102c8SMichael Baum } 130a96102c8SMichael Baum if (offset >= (1 << rxq->cqe_n)) { 131a96102c8SMichael Baum rte_errno = EINVAL; 132a96102c8SMichael Baum return -rte_errno; 133a96102c8SMichael Baum } 134a96102c8SMichael Baum if (offset < rx_queue_count(rxq)) 135a96102c8SMichael Baum return RTE_ETH_RX_DESC_DONE; 136a96102c8SMichael Baum return RTE_ETH_RX_DESC_AVAIL; 137a96102c8SMichael Baum } 138a96102c8SMichael Baum 139a96102c8SMichael Baum /** 140a96102c8SMichael Baum * DPDK callback to get the RX queue information. 141a96102c8SMichael Baum * 142a96102c8SMichael Baum * @param dev 143a96102c8SMichael Baum * Pointer to the device structure. 144a96102c8SMichael Baum * 145a96102c8SMichael Baum * @param rx_queue_id 146a96102c8SMichael Baum * Rx queue identificator. 147a96102c8SMichael Baum * 148a96102c8SMichael Baum * @param qinfo 149a96102c8SMichael Baum * Pointer to the RX queue information structure. 150a96102c8SMichael Baum * 151a96102c8SMichael Baum * @return 152a96102c8SMichael Baum * None. 153a96102c8SMichael Baum */ 154a96102c8SMichael Baum 155a96102c8SMichael Baum void 156a96102c8SMichael Baum mlx5_rxq_info_get(struct rte_eth_dev *dev, uint16_t rx_queue_id, 157a96102c8SMichael Baum struct rte_eth_rxq_info *qinfo) 158a96102c8SMichael Baum { 159a96102c8SMichael Baum struct mlx5_priv *priv = dev->data->dev_private; 160a96102c8SMichael Baum struct mlx5_rxq_data *rxq = (*priv->rxqs)[rx_queue_id]; 161a96102c8SMichael Baum struct mlx5_rxq_ctrl *rxq_ctrl = 162a96102c8SMichael Baum container_of(rxq, struct mlx5_rxq_ctrl, rxq); 163a96102c8SMichael Baum 164a96102c8SMichael Baum if (!rxq) 165a96102c8SMichael Baum return; 166a96102c8SMichael Baum qinfo->mp = mlx5_rxq_mprq_enabled(rxq) ? 167a96102c8SMichael Baum rxq->mprq_mp : rxq->mp; 168a96102c8SMichael Baum qinfo->conf.rx_thresh.pthresh = 0; 169a96102c8SMichael Baum qinfo->conf.rx_thresh.hthresh = 0; 170a96102c8SMichael Baum qinfo->conf.rx_thresh.wthresh = 0; 171a96102c8SMichael Baum qinfo->conf.rx_free_thresh = rxq->rq_repl_thresh; 172a96102c8SMichael Baum qinfo->conf.rx_drop_en = 1; 173a96102c8SMichael Baum qinfo->conf.rx_deferred_start = rxq_ctrl ? 0 : 1; 174a96102c8SMichael Baum qinfo->conf.offloads = dev->data->dev_conf.rxmode.offloads; 175a96102c8SMichael Baum qinfo->scattered_rx = dev->data->scattered_rx; 176a96102c8SMichael Baum qinfo->nb_desc = mlx5_rxq_mprq_enabled(rxq) ? 177a96102c8SMichael Baum (1 << rxq->elts_n) * (1 << rxq->strd_num_n) : 178a96102c8SMichael Baum (1 << rxq->elts_n); 179a96102c8SMichael Baum } 180a96102c8SMichael Baum 181a96102c8SMichael Baum /** 182a96102c8SMichael Baum * DPDK callback to get the RX packet burst mode information. 183a96102c8SMichael Baum * 184a96102c8SMichael Baum * @param dev 185a96102c8SMichael Baum * Pointer to the device structure. 186a96102c8SMichael Baum * 187a96102c8SMichael Baum * @param rx_queue_id 188a96102c8SMichael Baum * Rx queue identificatior. 189a96102c8SMichael Baum * 190a96102c8SMichael Baum * @param mode 191a96102c8SMichael Baum * Pointer to the burts mode information. 192a96102c8SMichael Baum * 193a96102c8SMichael Baum * @return 194a96102c8SMichael Baum * 0 as success, -EINVAL as failure. 195a96102c8SMichael Baum */ 196a96102c8SMichael Baum int 197a96102c8SMichael Baum mlx5_rx_burst_mode_get(struct rte_eth_dev *dev, 198a96102c8SMichael Baum uint16_t rx_queue_id __rte_unused, 199a96102c8SMichael Baum struct rte_eth_burst_mode *mode) 200a96102c8SMichael Baum { 201a96102c8SMichael Baum eth_rx_burst_t pkt_burst = dev->rx_pkt_burst; 202a96102c8SMichael Baum struct mlx5_priv *priv = dev->data->dev_private; 203a96102c8SMichael Baum struct mlx5_rxq_data *rxq; 204a96102c8SMichael Baum 205a96102c8SMichael Baum rxq = (*priv->rxqs)[rx_queue_id]; 206a96102c8SMichael Baum if (!rxq) { 207a96102c8SMichael Baum rte_errno = EINVAL; 208a96102c8SMichael Baum return -rte_errno; 209a96102c8SMichael Baum } 210a96102c8SMichael Baum if (pkt_burst == mlx5_rx_burst) { 211a96102c8SMichael Baum snprintf(mode->info, sizeof(mode->info), "%s", "Scalar"); 212a96102c8SMichael Baum } else if (pkt_burst == mlx5_rx_burst_mprq) { 213a96102c8SMichael Baum snprintf(mode->info, sizeof(mode->info), "%s", "Multi-Packet RQ"); 214a96102c8SMichael Baum } else if (pkt_burst == mlx5_rx_burst_vec) { 215a96102c8SMichael Baum #if defined RTE_ARCH_X86_64 216a96102c8SMichael Baum snprintf(mode->info, sizeof(mode->info), "%s", "Vector SSE"); 217a96102c8SMichael Baum #elif defined RTE_ARCH_ARM64 218a96102c8SMichael Baum snprintf(mode->info, sizeof(mode->info), "%s", "Vector Neon"); 219a96102c8SMichael Baum #elif defined RTE_ARCH_PPC_64 220a96102c8SMichael Baum snprintf(mode->info, sizeof(mode->info), "%s", "Vector AltiVec"); 221a96102c8SMichael Baum #else 222a96102c8SMichael Baum return -EINVAL; 223a96102c8SMichael Baum #endif 224a96102c8SMichael Baum } else if (pkt_burst == mlx5_rx_burst_mprq_vec) { 225a96102c8SMichael Baum #if defined RTE_ARCH_X86_64 226a96102c8SMichael Baum snprintf(mode->info, sizeof(mode->info), "%s", "MPRQ Vector SSE"); 227a96102c8SMichael Baum #elif defined RTE_ARCH_ARM64 228a96102c8SMichael Baum snprintf(mode->info, sizeof(mode->info), "%s", "MPRQ Vector Neon"); 229a96102c8SMichael Baum #elif defined RTE_ARCH_PPC_64 230a96102c8SMichael Baum snprintf(mode->info, sizeof(mode->info), "%s", "MPRQ Vector AltiVec"); 231a96102c8SMichael Baum #else 232a96102c8SMichael Baum return -EINVAL; 233a96102c8SMichael Baum #endif 234a96102c8SMichael Baum } else { 235a96102c8SMichael Baum return -EINVAL; 236a96102c8SMichael Baum } 237a96102c8SMichael Baum return 0; 238a96102c8SMichael Baum } 239a96102c8SMichael Baum 240a96102c8SMichael Baum /** 241a96102c8SMichael Baum * DPDK callback to get the number of used descriptors in a RX queue. 242a96102c8SMichael Baum * 2438d7d4fcdSKonstantin Ananyev * @param rx_queue 2448d7d4fcdSKonstantin Ananyev * The Rx queue pointer. 245a96102c8SMichael Baum * 246a96102c8SMichael Baum * @return 247a96102c8SMichael Baum * The number of used rx descriptor. 248a96102c8SMichael Baum * -EINVAL if the queue is invalid 249a96102c8SMichael Baum */ 250a96102c8SMichael Baum uint32_t 2518d7d4fcdSKonstantin Ananyev mlx5_rx_queue_count(void *rx_queue) 252a96102c8SMichael Baum { 2538d7d4fcdSKonstantin Ananyev struct mlx5_rxq_data *rxq = rx_queue; 2548d7d4fcdSKonstantin Ananyev struct rte_eth_dev *dev; 2558d7d4fcdSKonstantin Ananyev 2568d7d4fcdSKonstantin Ananyev if (!rxq) { 2578d7d4fcdSKonstantin Ananyev rte_errno = EINVAL; 2588d7d4fcdSKonstantin Ananyev return -rte_errno; 2598d7d4fcdSKonstantin Ananyev } 2608d7d4fcdSKonstantin Ananyev 2618d7d4fcdSKonstantin Ananyev dev = &rte_eth_devices[rxq->port_id]; 262a96102c8SMichael Baum 263a96102c8SMichael Baum if (dev->rx_pkt_burst == NULL || 264a96102c8SMichael Baum dev->rx_pkt_burst == removed_rx_burst) { 265a96102c8SMichael Baum rte_errno = ENOTSUP; 266a96102c8SMichael Baum return -rte_errno; 267a96102c8SMichael Baum } 2688d7d4fcdSKonstantin Ananyev 269a96102c8SMichael Baum return rx_queue_count(rxq); 270a96102c8SMichael Baum } 271a96102c8SMichael Baum 2726afc4bafSAnatoly Burakov #define CLB_VAL_IDX 0 2736afc4bafSAnatoly Burakov #define CLB_MSK_IDX 1 2746afc4bafSAnatoly Burakov static int 2756afc4bafSAnatoly Burakov mlx5_monitor_callback(const uint64_t value, 2766afc4bafSAnatoly Burakov const uint64_t opaque[RTE_POWER_MONITOR_OPAQUE_SZ]) 2776afc4bafSAnatoly Burakov { 2786afc4bafSAnatoly Burakov const uint64_t m = opaque[CLB_MSK_IDX]; 2796afc4bafSAnatoly Burakov const uint64_t v = opaque[CLB_VAL_IDX]; 2806afc4bafSAnatoly Burakov 2816afc4bafSAnatoly Burakov return (value & m) == v ? -1 : 0; 2826afc4bafSAnatoly Burakov } 2836afc4bafSAnatoly Burakov 284a8f0df6bSAlexander Kozyrev int mlx5_get_monitor_addr(void *rx_queue, struct rte_power_monitor_cond *pmc) 285a8f0df6bSAlexander Kozyrev { 286a8f0df6bSAlexander Kozyrev struct mlx5_rxq_data *rxq = rx_queue; 287a8f0df6bSAlexander Kozyrev const unsigned int cqe_num = 1 << rxq->cqe_n; 288a8f0df6bSAlexander Kozyrev const unsigned int cqe_mask = cqe_num - 1; 289a8f0df6bSAlexander Kozyrev const uint16_t idx = rxq->cq_ci & cqe_num; 290a8f0df6bSAlexander Kozyrev volatile struct mlx5_cqe *cqe = &(*rxq->cqes)[rxq->cq_ci & cqe_mask]; 291a8f0df6bSAlexander Kozyrev 292a8f0df6bSAlexander Kozyrev if (unlikely(rxq->cqes == NULL)) { 293a8f0df6bSAlexander Kozyrev rte_errno = EINVAL; 294a8f0df6bSAlexander Kozyrev return -rte_errno; 295a8f0df6bSAlexander Kozyrev } 296a8f0df6bSAlexander Kozyrev pmc->addr = &cqe->op_own; 2976afc4bafSAnatoly Burakov pmc->opaque[CLB_VAL_IDX] = !!idx; 2986afc4bafSAnatoly Burakov pmc->opaque[CLB_MSK_IDX] = MLX5_CQE_OWNER_MASK; 2996afc4bafSAnatoly Burakov pmc->fn = mlx5_monitor_callback; 300a8f0df6bSAlexander Kozyrev pmc->size = sizeof(uint8_t); 301a8f0df6bSAlexander Kozyrev return 0; 302a8f0df6bSAlexander Kozyrev } 303a8f0df6bSAlexander Kozyrev 304a96102c8SMichael Baum /** 305a96102c8SMichael Baum * Translate RX completion flags to packet type. 306a96102c8SMichael Baum * 307a96102c8SMichael Baum * @param[in] rxq 308a96102c8SMichael Baum * Pointer to RX queue structure. 309a96102c8SMichael Baum * @param[in] cqe 310a96102c8SMichael Baum * Pointer to CQE. 311a96102c8SMichael Baum * 312a96102c8SMichael Baum * @note: fix mlx5_dev_supported_ptypes_get() if any change here. 313a96102c8SMichael Baum * 314a96102c8SMichael Baum * @return 315a96102c8SMichael Baum * Packet type for struct rte_mbuf. 316a96102c8SMichael Baum */ 317a96102c8SMichael Baum static inline uint32_t 318a96102c8SMichael Baum rxq_cq_to_pkt_type(struct mlx5_rxq_data *rxq, volatile struct mlx5_cqe *cqe, 319a96102c8SMichael Baum volatile struct mlx5_mini_cqe8 *mcqe) 320a96102c8SMichael Baum { 321a96102c8SMichael Baum uint8_t idx; 322a96102c8SMichael Baum uint8_t ptype; 323a96102c8SMichael Baum uint8_t pinfo = (cqe->pkt_info & 0x3) << 6; 324a96102c8SMichael Baum 325a96102c8SMichael Baum /* Get l3/l4 header from mini-CQE in case L3/L4 format*/ 326a96102c8SMichael Baum if (mcqe == NULL || 327a96102c8SMichael Baum rxq->mcqe_format != MLX5_CQE_RESP_FORMAT_L34H_STRIDX) 328a96102c8SMichael Baum ptype = (cqe->hdr_type_etc & 0xfc00) >> 10; 329a96102c8SMichael Baum else 330a96102c8SMichael Baum ptype = mcqe->hdr_type >> 2; 331a96102c8SMichael Baum /* 332a96102c8SMichael Baum * The index to the array should have: 333a96102c8SMichael Baum * bit[1:0] = l3_hdr_type 334a96102c8SMichael Baum * bit[4:2] = l4_hdr_type 335a96102c8SMichael Baum * bit[5] = ip_frag 336a96102c8SMichael Baum * bit[6] = tunneled 337a96102c8SMichael Baum * bit[7] = outer_l3_type 338a96102c8SMichael Baum */ 339a96102c8SMichael Baum idx = pinfo | ptype; 340a96102c8SMichael Baum return mlx5_ptype_table[idx] | rxq->tunnel * !!(idx & (1 << 6)); 341a96102c8SMichael Baum } 342a96102c8SMichael Baum 343a96102c8SMichael Baum /** 344a96102c8SMichael Baum * Initialize Rx WQ and indexes. 345a96102c8SMichael Baum * 346a96102c8SMichael Baum * @param[in] rxq 347a96102c8SMichael Baum * Pointer to RX queue structure. 348a96102c8SMichael Baum */ 349a96102c8SMichael Baum void 350a96102c8SMichael Baum mlx5_rxq_initialize(struct mlx5_rxq_data *rxq) 351a96102c8SMichael Baum { 352a96102c8SMichael Baum const unsigned int wqe_n = 1 << rxq->elts_n; 353a96102c8SMichael Baum unsigned int i; 354a96102c8SMichael Baum 355a96102c8SMichael Baum for (i = 0; (i != wqe_n); ++i) { 356a96102c8SMichael Baum volatile struct mlx5_wqe_data_seg *scat; 357a96102c8SMichael Baum uintptr_t addr; 358a96102c8SMichael Baum uint32_t byte_count; 359a96102c8SMichael Baum 360a96102c8SMichael Baum if (mlx5_rxq_mprq_enabled(rxq)) { 361a96102c8SMichael Baum struct mlx5_mprq_buf *buf = (*rxq->mprq_bufs)[i]; 362a96102c8SMichael Baum 363a96102c8SMichael Baum scat = &((volatile struct mlx5_wqe_mprq *) 364a96102c8SMichael Baum rxq->wqes)[i].dseg; 365a96102c8SMichael Baum addr = (uintptr_t)mlx5_mprq_buf_addr(buf, 366a96102c8SMichael Baum 1 << rxq->strd_num_n); 367a96102c8SMichael Baum byte_count = (1 << rxq->strd_sz_n) * 368a96102c8SMichael Baum (1 << rxq->strd_num_n); 369a96102c8SMichael Baum } else { 370a96102c8SMichael Baum struct rte_mbuf *buf = (*rxq->elts)[i]; 371a96102c8SMichael Baum 372a96102c8SMichael Baum scat = &((volatile struct mlx5_wqe_data_seg *) 373a96102c8SMichael Baum rxq->wqes)[i]; 374a96102c8SMichael Baum addr = rte_pktmbuf_mtod(buf, uintptr_t); 375a96102c8SMichael Baum byte_count = DATA_LEN(buf); 376a96102c8SMichael Baum } 377a96102c8SMichael Baum /* scat->addr must be able to store a pointer. */ 378a96102c8SMichael Baum MLX5_ASSERT(sizeof(scat->addr) >= sizeof(uintptr_t)); 379a96102c8SMichael Baum *scat = (struct mlx5_wqe_data_seg){ 380a96102c8SMichael Baum .addr = rte_cpu_to_be_64(addr), 381a96102c8SMichael Baum .byte_count = rte_cpu_to_be_32(byte_count), 382a96102c8SMichael Baum .lkey = mlx5_rx_addr2mr(rxq, addr), 383a96102c8SMichael Baum }; 384a96102c8SMichael Baum } 385a96102c8SMichael Baum rxq->consumed_strd = 0; 386a96102c8SMichael Baum rxq->decompressed = 0; 387a96102c8SMichael Baum rxq->rq_pi = 0; 388a96102c8SMichael Baum rxq->zip = (struct rxq_zip){ 389a96102c8SMichael Baum .ai = 0, 390a96102c8SMichael Baum }; 391a96102c8SMichael Baum rxq->elts_ci = mlx5_rxq_mprq_enabled(rxq) ? 392a96102c8SMichael Baum (wqe_n >> rxq->sges_n) * (1 << rxq->strd_num_n) : 0; 393a96102c8SMichael Baum /* Update doorbell counter. */ 394a96102c8SMichael Baum rxq->rq_ci = wqe_n >> rxq->sges_n; 395a96102c8SMichael Baum rte_io_wmb(); 396a96102c8SMichael Baum *rxq->rq_db = rte_cpu_to_be_32(rxq->rq_ci); 397a96102c8SMichael Baum } 398a96102c8SMichael Baum 399a96102c8SMichael Baum /** 400a96102c8SMichael Baum * Handle a Rx error. 401a96102c8SMichael Baum * The function inserts the RQ state to reset when the first error CQE is 402a96102c8SMichael Baum * shown, then drains the CQ by the caller function loop. When the CQ is empty, 403a96102c8SMichael Baum * it moves the RQ state to ready and initializes the RQ. 404a96102c8SMichael Baum * Next CQE identification and error counting are in the caller responsibility. 405a96102c8SMichael Baum * 406a96102c8SMichael Baum * @param[in] rxq 407a96102c8SMichael Baum * Pointer to RX queue structure. 408a96102c8SMichael Baum * @param[in] vec 409a96102c8SMichael Baum * 1 when called from vectorized Rx burst, need to prepare mbufs for the RQ. 410a96102c8SMichael Baum * 0 when called from non-vectorized Rx burst. 411a96102c8SMichael Baum * 412a96102c8SMichael Baum * @return 413a96102c8SMichael Baum * -1 in case of recovery error, otherwise the CQE status. 414a96102c8SMichael Baum */ 415a96102c8SMichael Baum int 416a96102c8SMichael Baum mlx5_rx_err_handle(struct mlx5_rxq_data *rxq, uint8_t vec) 417a96102c8SMichael Baum { 418a96102c8SMichael Baum const uint16_t cqe_n = 1 << rxq->cqe_n; 419a96102c8SMichael Baum const uint16_t cqe_mask = cqe_n - 1; 420a96102c8SMichael Baum const uint16_t wqe_n = 1 << rxq->elts_n; 421a96102c8SMichael Baum const uint16_t strd_n = 1 << rxq->strd_num_n; 422a96102c8SMichael Baum struct mlx5_rxq_ctrl *rxq_ctrl = 423a96102c8SMichael Baum container_of(rxq, struct mlx5_rxq_ctrl, rxq); 424a96102c8SMichael Baum union { 425a96102c8SMichael Baum volatile struct mlx5_cqe *cqe; 426a96102c8SMichael Baum volatile struct mlx5_err_cqe *err_cqe; 427a96102c8SMichael Baum } u = { 428a96102c8SMichael Baum .cqe = &(*rxq->cqes)[rxq->cq_ci & cqe_mask], 429a96102c8SMichael Baum }; 430a96102c8SMichael Baum struct mlx5_mp_arg_queue_state_modify sm; 431a96102c8SMichael Baum int ret; 432a96102c8SMichael Baum 433a96102c8SMichael Baum switch (rxq->err_state) { 434a96102c8SMichael Baum case MLX5_RXQ_ERR_STATE_NO_ERROR: 435a96102c8SMichael Baum rxq->err_state = MLX5_RXQ_ERR_STATE_NEED_RESET; 436a96102c8SMichael Baum /* Fall-through */ 437a96102c8SMichael Baum case MLX5_RXQ_ERR_STATE_NEED_RESET: 438a96102c8SMichael Baum sm.is_wq = 1; 439a96102c8SMichael Baum sm.queue_id = rxq->idx; 440a96102c8SMichael Baum sm.state = IBV_WQS_RESET; 441a96102c8SMichael Baum if (mlx5_queue_state_modify(ETH_DEV(rxq_ctrl->priv), &sm)) 442a96102c8SMichael Baum return -1; 443a96102c8SMichael Baum if (rxq_ctrl->dump_file_n < 444a96102c8SMichael Baum rxq_ctrl->priv->config.max_dump_files_num) { 445a96102c8SMichael Baum MKSTR(err_str, "Unexpected CQE error syndrome " 446a96102c8SMichael Baum "0x%02x CQN = %u RQN = %u wqe_counter = %u" 447a96102c8SMichael Baum " rq_ci = %u cq_ci = %u", u.err_cqe->syndrome, 448a96102c8SMichael Baum rxq->cqn, rxq_ctrl->wqn, 449a96102c8SMichael Baum rte_be_to_cpu_16(u.err_cqe->wqe_counter), 450a96102c8SMichael Baum rxq->rq_ci << rxq->sges_n, rxq->cq_ci); 451a96102c8SMichael Baum MKSTR(name, "dpdk_mlx5_port_%u_rxq_%u_%u", 452a96102c8SMichael Baum rxq->port_id, rxq->idx, (uint32_t)rte_rdtsc()); 453a96102c8SMichael Baum mlx5_dump_debug_information(name, NULL, err_str, 0); 454a96102c8SMichael Baum mlx5_dump_debug_information(name, "MLX5 Error CQ:", 455a96102c8SMichael Baum (const void *)((uintptr_t) 456a96102c8SMichael Baum rxq->cqes), 457a96102c8SMichael Baum sizeof(*u.cqe) * cqe_n); 458a96102c8SMichael Baum mlx5_dump_debug_information(name, "MLX5 Error RQ:", 459a96102c8SMichael Baum (const void *)((uintptr_t) 460a96102c8SMichael Baum rxq->wqes), 461a96102c8SMichael Baum 16 * wqe_n); 462a96102c8SMichael Baum rxq_ctrl->dump_file_n++; 463a96102c8SMichael Baum } 464a96102c8SMichael Baum rxq->err_state = MLX5_RXQ_ERR_STATE_NEED_READY; 465a96102c8SMichael Baum /* Fall-through */ 466a96102c8SMichael Baum case MLX5_RXQ_ERR_STATE_NEED_READY: 467a96102c8SMichael Baum ret = check_cqe(u.cqe, cqe_n, rxq->cq_ci); 468a96102c8SMichael Baum if (ret == MLX5_CQE_STATUS_HW_OWN) { 469a96102c8SMichael Baum rte_io_wmb(); 470a96102c8SMichael Baum *rxq->cq_db = rte_cpu_to_be_32(rxq->cq_ci); 471a96102c8SMichael Baum rte_io_wmb(); 472a96102c8SMichael Baum /* 473a96102c8SMichael Baum * The RQ consumer index must be zeroed while moving 474a96102c8SMichael Baum * from RESET state to RDY state. 475a96102c8SMichael Baum */ 476a96102c8SMichael Baum *rxq->rq_db = rte_cpu_to_be_32(0); 477a96102c8SMichael Baum rte_io_wmb(); 478a96102c8SMichael Baum sm.is_wq = 1; 479a96102c8SMichael Baum sm.queue_id = rxq->idx; 480a96102c8SMichael Baum sm.state = IBV_WQS_RDY; 481a96102c8SMichael Baum if (mlx5_queue_state_modify(ETH_DEV(rxq_ctrl->priv), 482a96102c8SMichael Baum &sm)) 483a96102c8SMichael Baum return -1; 484a96102c8SMichael Baum if (vec) { 485a96102c8SMichael Baum const uint32_t elts_n = 486a96102c8SMichael Baum mlx5_rxq_mprq_enabled(rxq) ? 487a96102c8SMichael Baum wqe_n * strd_n : wqe_n; 488a96102c8SMichael Baum const uint32_t e_mask = elts_n - 1; 489a96102c8SMichael Baum uint32_t elts_ci = 490a96102c8SMichael Baum mlx5_rxq_mprq_enabled(rxq) ? 491a96102c8SMichael Baum rxq->elts_ci : rxq->rq_ci; 492a96102c8SMichael Baum uint32_t elt_idx; 493a96102c8SMichael Baum struct rte_mbuf **elt; 494a96102c8SMichael Baum int i; 495a96102c8SMichael Baum unsigned int n = elts_n - (elts_ci - 496a96102c8SMichael Baum rxq->rq_pi); 497a96102c8SMichael Baum 498a96102c8SMichael Baum for (i = 0; i < (int)n; ++i) { 499a96102c8SMichael Baum elt_idx = (elts_ci + i) & e_mask; 500a96102c8SMichael Baum elt = &(*rxq->elts)[elt_idx]; 501a96102c8SMichael Baum *elt = rte_mbuf_raw_alloc(rxq->mp); 502a96102c8SMichael Baum if (!*elt) { 503a96102c8SMichael Baum for (i--; i >= 0; --i) { 504a96102c8SMichael Baum elt_idx = (elts_ci + 505a96102c8SMichael Baum i) & elts_n; 506a96102c8SMichael Baum elt = &(*rxq->elts) 507a96102c8SMichael Baum [elt_idx]; 508a96102c8SMichael Baum rte_pktmbuf_free_seg 509a96102c8SMichael Baum (*elt); 510a96102c8SMichael Baum } 511a96102c8SMichael Baum return -1; 512a96102c8SMichael Baum } 513a96102c8SMichael Baum } 514a96102c8SMichael Baum for (i = 0; i < (int)elts_n; ++i) { 515a96102c8SMichael Baum elt = &(*rxq->elts)[i]; 516a96102c8SMichael Baum DATA_LEN(*elt) = 517a96102c8SMichael Baum (uint16_t)((*elt)->buf_len - 518a96102c8SMichael Baum rte_pktmbuf_headroom(*elt)); 519a96102c8SMichael Baum } 520a96102c8SMichael Baum /* Padding with a fake mbuf for vec Rx. */ 521a96102c8SMichael Baum for (i = 0; i < MLX5_VPMD_DESCS_PER_LOOP; ++i) 522a96102c8SMichael Baum (*rxq->elts)[elts_n + i] = 523a96102c8SMichael Baum &rxq->fake_mbuf; 524a96102c8SMichael Baum } 525a96102c8SMichael Baum mlx5_rxq_initialize(rxq); 526a96102c8SMichael Baum rxq->err_state = MLX5_RXQ_ERR_STATE_NO_ERROR; 527a96102c8SMichael Baum } 528a96102c8SMichael Baum return ret; 529a96102c8SMichael Baum default: 530a96102c8SMichael Baum return -1; 531a96102c8SMichael Baum } 532a96102c8SMichael Baum } 533a96102c8SMichael Baum 534a96102c8SMichael Baum /** 535a96102c8SMichael Baum * Get size of the next packet for a given CQE. For compressed CQEs, the 536a96102c8SMichael Baum * consumer index is updated only once all packets of the current one have 537a96102c8SMichael Baum * been processed. 538a96102c8SMichael Baum * 539a96102c8SMichael Baum * @param rxq 540a96102c8SMichael Baum * Pointer to RX queue. 541a96102c8SMichael Baum * @param cqe 542a96102c8SMichael Baum * CQE to process. 543a96102c8SMichael Baum * @param[out] mcqe 544a96102c8SMichael Baum * Store pointer to mini-CQE if compressed. Otherwise, the pointer is not 545a96102c8SMichael Baum * written. 546a96102c8SMichael Baum * 547a96102c8SMichael Baum * @return 548a96102c8SMichael Baum * 0 in case of empty CQE, otherwise the packet size in bytes. 549a96102c8SMichael Baum */ 550a96102c8SMichael Baum static inline int 551a96102c8SMichael Baum mlx5_rx_poll_len(struct mlx5_rxq_data *rxq, volatile struct mlx5_cqe *cqe, 552a96102c8SMichael Baum uint16_t cqe_cnt, volatile struct mlx5_mini_cqe8 **mcqe) 553a96102c8SMichael Baum { 554a96102c8SMichael Baum struct rxq_zip *zip = &rxq->zip; 555a96102c8SMichael Baum uint16_t cqe_n = cqe_cnt + 1; 556a96102c8SMichael Baum int len; 557a96102c8SMichael Baum uint16_t idx, end; 558a96102c8SMichael Baum 559a96102c8SMichael Baum do { 560a96102c8SMichael Baum len = 0; 561a96102c8SMichael Baum /* Process compressed data in the CQE and mini arrays. */ 562a96102c8SMichael Baum if (zip->ai) { 563a96102c8SMichael Baum volatile struct mlx5_mini_cqe8 (*mc)[8] = 564a96102c8SMichael Baum (volatile struct mlx5_mini_cqe8 (*)[8]) 565a96102c8SMichael Baum (uintptr_t)(&(*rxq->cqes)[zip->ca & 566a96102c8SMichael Baum cqe_cnt].pkt_info); 567a96102c8SMichael Baum len = rte_be_to_cpu_32((*mc)[zip->ai & 7].byte_cnt & 568a96102c8SMichael Baum rxq->byte_mask); 569a96102c8SMichael Baum *mcqe = &(*mc)[zip->ai & 7]; 570a96102c8SMichael Baum if ((++zip->ai & 7) == 0) { 571a96102c8SMichael Baum /* Invalidate consumed CQEs */ 572a96102c8SMichael Baum idx = zip->ca; 573a96102c8SMichael Baum end = zip->na; 574a96102c8SMichael Baum while (idx != end) { 575a96102c8SMichael Baum (*rxq->cqes)[idx & cqe_cnt].op_own = 576a96102c8SMichael Baum MLX5_CQE_INVALIDATE; 577a96102c8SMichael Baum ++idx; 578a96102c8SMichael Baum } 579a96102c8SMichael Baum /* 580a96102c8SMichael Baum * Increment consumer index to skip the number 581a96102c8SMichael Baum * of CQEs consumed. Hardware leaves holes in 582a96102c8SMichael Baum * the CQ ring for software use. 583a96102c8SMichael Baum */ 584a96102c8SMichael Baum zip->ca = zip->na; 585a96102c8SMichael Baum zip->na += 8; 586a96102c8SMichael Baum } 587a96102c8SMichael Baum if (unlikely(rxq->zip.ai == rxq->zip.cqe_cnt)) { 588a96102c8SMichael Baum /* Invalidate the rest */ 589a96102c8SMichael Baum idx = zip->ca; 590a96102c8SMichael Baum end = zip->cq_ci; 591a96102c8SMichael Baum 592a96102c8SMichael Baum while (idx != end) { 593a96102c8SMichael Baum (*rxq->cqes)[idx & cqe_cnt].op_own = 594a96102c8SMichael Baum MLX5_CQE_INVALIDATE; 595a96102c8SMichael Baum ++idx; 596a96102c8SMichael Baum } 597a96102c8SMichael Baum rxq->cq_ci = zip->cq_ci; 598a96102c8SMichael Baum zip->ai = 0; 599a96102c8SMichael Baum } 600a96102c8SMichael Baum /* 601a96102c8SMichael Baum * No compressed data, get next CQE and verify if it is 602a96102c8SMichael Baum * compressed. 603a96102c8SMichael Baum */ 604a96102c8SMichael Baum } else { 605a96102c8SMichael Baum int ret; 606a96102c8SMichael Baum int8_t op_own; 607a96102c8SMichael Baum uint32_t cq_ci; 608a96102c8SMichael Baum 609a96102c8SMichael Baum ret = check_cqe(cqe, cqe_n, rxq->cq_ci); 610a96102c8SMichael Baum if (unlikely(ret != MLX5_CQE_STATUS_SW_OWN)) { 611a96102c8SMichael Baum if (unlikely(ret == MLX5_CQE_STATUS_ERR || 612a96102c8SMichael Baum rxq->err_state)) { 613a96102c8SMichael Baum ret = mlx5_rx_err_handle(rxq, 0); 614a96102c8SMichael Baum if (ret == MLX5_CQE_STATUS_HW_OWN || 615a96102c8SMichael Baum ret == -1) 616a96102c8SMichael Baum return 0; 617a96102c8SMichael Baum } else { 618a96102c8SMichael Baum return 0; 619a96102c8SMichael Baum } 620a96102c8SMichael Baum } 621a96102c8SMichael Baum /* 622a96102c8SMichael Baum * Introduce the local variable to have queue cq_ci 623a96102c8SMichael Baum * index in queue structure always consistent with 624a96102c8SMichael Baum * actual CQE boundary (not pointing to the middle 625a96102c8SMichael Baum * of compressed CQE session). 626a96102c8SMichael Baum */ 627a96102c8SMichael Baum cq_ci = rxq->cq_ci + 1; 628a96102c8SMichael Baum op_own = cqe->op_own; 629a96102c8SMichael Baum if (MLX5_CQE_FORMAT(op_own) == MLX5_COMPRESSED) { 630a96102c8SMichael Baum volatile struct mlx5_mini_cqe8 (*mc)[8] = 631a96102c8SMichael Baum (volatile struct mlx5_mini_cqe8 (*)[8]) 632a96102c8SMichael Baum (uintptr_t)(&(*rxq->cqes) 633a96102c8SMichael Baum [cq_ci & cqe_cnt].pkt_info); 634a96102c8SMichael Baum 635a96102c8SMichael Baum /* Fix endianness. */ 636a96102c8SMichael Baum zip->cqe_cnt = rte_be_to_cpu_32(cqe->byte_cnt); 637a96102c8SMichael Baum /* 638a96102c8SMichael Baum * Current mini array position is the one 639a96102c8SMichael Baum * returned by check_cqe64(). 640a96102c8SMichael Baum * 641a96102c8SMichael Baum * If completion comprises several mini arrays, 642a96102c8SMichael Baum * as a special case the second one is located 643a96102c8SMichael Baum * 7 CQEs after the initial CQE instead of 8 644a96102c8SMichael Baum * for subsequent ones. 645a96102c8SMichael Baum */ 646a96102c8SMichael Baum zip->ca = cq_ci; 647a96102c8SMichael Baum zip->na = zip->ca + 7; 648a96102c8SMichael Baum /* Compute the next non compressed CQE. */ 649a96102c8SMichael Baum zip->cq_ci = rxq->cq_ci + zip->cqe_cnt; 650a96102c8SMichael Baum /* Get packet size to return. */ 651a96102c8SMichael Baum len = rte_be_to_cpu_32((*mc)[0].byte_cnt & 652a96102c8SMichael Baum rxq->byte_mask); 653a96102c8SMichael Baum *mcqe = &(*mc)[0]; 654a96102c8SMichael Baum zip->ai = 1; 655a96102c8SMichael Baum /* Prefetch all to be invalidated */ 656a96102c8SMichael Baum idx = zip->ca; 657a96102c8SMichael Baum end = zip->cq_ci; 658a96102c8SMichael Baum while (idx != end) { 659a96102c8SMichael Baum rte_prefetch0(&(*rxq->cqes)[(idx) & 660a96102c8SMichael Baum cqe_cnt]); 661a96102c8SMichael Baum ++idx; 662a96102c8SMichael Baum } 663a96102c8SMichael Baum } else { 664a96102c8SMichael Baum rxq->cq_ci = cq_ci; 665a96102c8SMichael Baum len = rte_be_to_cpu_32(cqe->byte_cnt); 666a96102c8SMichael Baum } 667a96102c8SMichael Baum } 668a96102c8SMichael Baum if (unlikely(rxq->err_state)) { 669a96102c8SMichael Baum cqe = &(*rxq->cqes)[rxq->cq_ci & cqe_cnt]; 670a96102c8SMichael Baum ++rxq->stats.idropped; 671a96102c8SMichael Baum } else { 672a96102c8SMichael Baum return len; 673a96102c8SMichael Baum } 674a96102c8SMichael Baum } while (1); 675a96102c8SMichael Baum } 676a96102c8SMichael Baum 677a96102c8SMichael Baum /** 678a96102c8SMichael Baum * Translate RX completion flags to offload flags. 679a96102c8SMichael Baum * 680a96102c8SMichael Baum * @param[in] cqe 681a96102c8SMichael Baum * Pointer to CQE. 682a96102c8SMichael Baum * 683a96102c8SMichael Baum * @return 684a96102c8SMichael Baum * Offload flags (ol_flags) for struct rte_mbuf. 685a96102c8SMichael Baum */ 686a96102c8SMichael Baum static inline uint32_t 687a96102c8SMichael Baum rxq_cq_to_ol_flags(volatile struct mlx5_cqe *cqe) 688a96102c8SMichael Baum { 689a96102c8SMichael Baum uint32_t ol_flags = 0; 690a96102c8SMichael Baum uint16_t flags = rte_be_to_cpu_16(cqe->hdr_type_etc); 691a96102c8SMichael Baum 692a96102c8SMichael Baum ol_flags = 693a96102c8SMichael Baum TRANSPOSE(flags, 694a96102c8SMichael Baum MLX5_CQE_RX_L3_HDR_VALID, 695*daa02b5cSOlivier Matz RTE_MBUF_F_RX_IP_CKSUM_GOOD) | 696a96102c8SMichael Baum TRANSPOSE(flags, 697a96102c8SMichael Baum MLX5_CQE_RX_L4_HDR_VALID, 698*daa02b5cSOlivier Matz RTE_MBUF_F_RX_L4_CKSUM_GOOD); 699a96102c8SMichael Baum return ol_flags; 700a96102c8SMichael Baum } 701a96102c8SMichael Baum 702a96102c8SMichael Baum /** 703a96102c8SMichael Baum * Fill in mbuf fields from RX completion flags. 704a96102c8SMichael Baum * Note that pkt->ol_flags should be initialized outside of this function. 705a96102c8SMichael Baum * 706a96102c8SMichael Baum * @param rxq 707a96102c8SMichael Baum * Pointer to RX queue. 708a96102c8SMichael Baum * @param pkt 709a96102c8SMichael Baum * mbuf to fill. 710a96102c8SMichael Baum * @param cqe 711a96102c8SMichael Baum * CQE to process. 712a96102c8SMichael Baum * @param rss_hash_res 713a96102c8SMichael Baum * Packet RSS Hash result. 714a96102c8SMichael Baum */ 715a96102c8SMichael Baum static inline void 716a96102c8SMichael Baum rxq_cq_to_mbuf(struct mlx5_rxq_data *rxq, struct rte_mbuf *pkt, 717a96102c8SMichael Baum volatile struct mlx5_cqe *cqe, 718a96102c8SMichael Baum volatile struct mlx5_mini_cqe8 *mcqe) 719a96102c8SMichael Baum { 720a96102c8SMichael Baum /* Update packet information. */ 721a96102c8SMichael Baum pkt->packet_type = rxq_cq_to_pkt_type(rxq, cqe, mcqe); 722a96102c8SMichael Baum 723a96102c8SMichael Baum if (rxq->rss_hash) { 724a96102c8SMichael Baum uint32_t rss_hash_res = 0; 725a96102c8SMichael Baum 726a96102c8SMichael Baum /* If compressed, take hash result from mini-CQE. */ 727a96102c8SMichael Baum if (mcqe == NULL || 728a96102c8SMichael Baum rxq->mcqe_format != MLX5_CQE_RESP_FORMAT_HASH) 729a96102c8SMichael Baum rss_hash_res = rte_be_to_cpu_32(cqe->rx_hash_res); 730a96102c8SMichael Baum else 731a96102c8SMichael Baum rss_hash_res = rte_be_to_cpu_32(mcqe->rx_hash_result); 732a96102c8SMichael Baum if (rss_hash_res) { 733a96102c8SMichael Baum pkt->hash.rss = rss_hash_res; 734*daa02b5cSOlivier Matz pkt->ol_flags |= RTE_MBUF_F_RX_RSS_HASH; 735a96102c8SMichael Baum } 736a96102c8SMichael Baum } 737a96102c8SMichael Baum if (rxq->mark) { 738a96102c8SMichael Baum uint32_t mark = 0; 739a96102c8SMichael Baum 740a96102c8SMichael Baum /* If compressed, take flow tag from mini-CQE. */ 741a96102c8SMichael Baum if (mcqe == NULL || 742a96102c8SMichael Baum rxq->mcqe_format != MLX5_CQE_RESP_FORMAT_FTAG_STRIDX) 743a96102c8SMichael Baum mark = cqe->sop_drop_qpn; 744a96102c8SMichael Baum else 745a96102c8SMichael Baum mark = ((mcqe->byte_cnt_flow & 0xff) << 8) | 746a96102c8SMichael Baum (mcqe->flow_tag_high << 16); 747a96102c8SMichael Baum if (MLX5_FLOW_MARK_IS_VALID(mark)) { 748*daa02b5cSOlivier Matz pkt->ol_flags |= RTE_MBUF_F_RX_FDIR; 749a96102c8SMichael Baum if (mark != RTE_BE32(MLX5_FLOW_MARK_DEFAULT)) { 750*daa02b5cSOlivier Matz pkt->ol_flags |= RTE_MBUF_F_RX_FDIR_ID; 751a96102c8SMichael Baum pkt->hash.fdir.hi = mlx5_flow_mark_get(mark); 752a96102c8SMichael Baum } 753a96102c8SMichael Baum } 754a96102c8SMichael Baum } 755a96102c8SMichael Baum if (rxq->dynf_meta) { 7566d5735c1SAlexander Kozyrev uint32_t meta = rte_be_to_cpu_32(cqe->flow_table_metadata) & 757a96102c8SMichael Baum rxq->flow_meta_port_mask; 758a96102c8SMichael Baum 759a96102c8SMichael Baum if (meta) { 760a96102c8SMichael Baum pkt->ol_flags |= rxq->flow_meta_mask; 761a96102c8SMichael Baum *RTE_MBUF_DYNFIELD(pkt, rxq->flow_meta_offset, 762a96102c8SMichael Baum uint32_t *) = meta; 763a96102c8SMichael Baum } 764a96102c8SMichael Baum } 765a96102c8SMichael Baum if (rxq->csum) 766a96102c8SMichael Baum pkt->ol_flags |= rxq_cq_to_ol_flags(cqe); 767a96102c8SMichael Baum if (rxq->vlan_strip) { 768a96102c8SMichael Baum bool vlan_strip; 769a96102c8SMichael Baum 770a96102c8SMichael Baum if (mcqe == NULL || 771a96102c8SMichael Baum rxq->mcqe_format != MLX5_CQE_RESP_FORMAT_L34H_STRIDX) 772a96102c8SMichael Baum vlan_strip = cqe->hdr_type_etc & 773a96102c8SMichael Baum RTE_BE16(MLX5_CQE_VLAN_STRIPPED); 774a96102c8SMichael Baum else 775a96102c8SMichael Baum vlan_strip = mcqe->hdr_type & 776a96102c8SMichael Baum RTE_BE16(MLX5_CQE_VLAN_STRIPPED); 777a96102c8SMichael Baum if (vlan_strip) { 778*daa02b5cSOlivier Matz pkt->ol_flags |= RTE_MBUF_F_RX_VLAN | RTE_MBUF_F_RX_VLAN_STRIPPED; 779a96102c8SMichael Baum pkt->vlan_tci = rte_be_to_cpu_16(cqe->vlan_info); 780a96102c8SMichael Baum } 781a96102c8SMichael Baum } 782a96102c8SMichael Baum if (rxq->hw_timestamp) { 783a96102c8SMichael Baum uint64_t ts = rte_be_to_cpu_64(cqe->timestamp); 784a96102c8SMichael Baum 785a96102c8SMichael Baum if (rxq->rt_timestamp) 786a96102c8SMichael Baum ts = mlx5_txpp_convert_rx_ts(rxq->sh, ts); 787a96102c8SMichael Baum mlx5_timestamp_set(pkt, rxq->timestamp_offset, ts); 788a96102c8SMichael Baum pkt->ol_flags |= rxq->timestamp_rx_flag; 789a96102c8SMichael Baum } 790a96102c8SMichael Baum } 791a96102c8SMichael Baum 792a96102c8SMichael Baum /** 793a96102c8SMichael Baum * DPDK callback for RX. 794a96102c8SMichael Baum * 795a96102c8SMichael Baum * @param dpdk_rxq 796a96102c8SMichael Baum * Generic pointer to RX queue structure. 797a96102c8SMichael Baum * @param[out] pkts 798a96102c8SMichael Baum * Array to store received packets. 799a96102c8SMichael Baum * @param pkts_n 800a96102c8SMichael Baum * Maximum number of packets in array. 801a96102c8SMichael Baum * 802a96102c8SMichael Baum * @return 803a96102c8SMichael Baum * Number of packets successfully received (<= pkts_n). 804a96102c8SMichael Baum */ 805a96102c8SMichael Baum uint16_t 806a96102c8SMichael Baum mlx5_rx_burst(void *dpdk_rxq, struct rte_mbuf **pkts, uint16_t pkts_n) 807a96102c8SMichael Baum { 808a96102c8SMichael Baum struct mlx5_rxq_data *rxq = dpdk_rxq; 809a96102c8SMichael Baum const unsigned int wqe_cnt = (1 << rxq->elts_n) - 1; 810a96102c8SMichael Baum const unsigned int cqe_cnt = (1 << rxq->cqe_n) - 1; 811a96102c8SMichael Baum const unsigned int sges_n = rxq->sges_n; 812a96102c8SMichael Baum struct rte_mbuf *pkt = NULL; 813a96102c8SMichael Baum struct rte_mbuf *seg = NULL; 814a96102c8SMichael Baum volatile struct mlx5_cqe *cqe = 815a96102c8SMichael Baum &(*rxq->cqes)[rxq->cq_ci & cqe_cnt]; 816a96102c8SMichael Baum unsigned int i = 0; 817a96102c8SMichael Baum unsigned int rq_ci = rxq->rq_ci << sges_n; 818a96102c8SMichael Baum int len = 0; /* keep its value across iterations. */ 819a96102c8SMichael Baum 820a96102c8SMichael Baum while (pkts_n) { 821a96102c8SMichael Baum unsigned int idx = rq_ci & wqe_cnt; 822a96102c8SMichael Baum volatile struct mlx5_wqe_data_seg *wqe = 823a96102c8SMichael Baum &((volatile struct mlx5_wqe_data_seg *)rxq->wqes)[idx]; 824a96102c8SMichael Baum struct rte_mbuf *rep = (*rxq->elts)[idx]; 825a96102c8SMichael Baum volatile struct mlx5_mini_cqe8 *mcqe = NULL; 826a96102c8SMichael Baum 827a96102c8SMichael Baum if (pkt) 828a96102c8SMichael Baum NEXT(seg) = rep; 829a96102c8SMichael Baum seg = rep; 830a96102c8SMichael Baum rte_prefetch0(seg); 831a96102c8SMichael Baum rte_prefetch0(cqe); 832a96102c8SMichael Baum rte_prefetch0(wqe); 833a96102c8SMichael Baum /* Allocate the buf from the same pool. */ 834a96102c8SMichael Baum rep = rte_mbuf_raw_alloc(seg->pool); 835a96102c8SMichael Baum if (unlikely(rep == NULL)) { 836a96102c8SMichael Baum ++rxq->stats.rx_nombuf; 837a96102c8SMichael Baum if (!pkt) { 838a96102c8SMichael Baum /* 839a96102c8SMichael Baum * no buffers before we even started, 840a96102c8SMichael Baum * bail out silently. 841a96102c8SMichael Baum */ 842a96102c8SMichael Baum break; 843a96102c8SMichael Baum } 844a96102c8SMichael Baum while (pkt != seg) { 845a96102c8SMichael Baum MLX5_ASSERT(pkt != (*rxq->elts)[idx]); 846a96102c8SMichael Baum rep = NEXT(pkt); 847a96102c8SMichael Baum NEXT(pkt) = NULL; 848a96102c8SMichael Baum NB_SEGS(pkt) = 1; 849a96102c8SMichael Baum rte_mbuf_raw_free(pkt); 850a96102c8SMichael Baum pkt = rep; 851a96102c8SMichael Baum } 852a96102c8SMichael Baum rq_ci >>= sges_n; 853a96102c8SMichael Baum ++rq_ci; 854a96102c8SMichael Baum rq_ci <<= sges_n; 855a96102c8SMichael Baum break; 856a96102c8SMichael Baum } 857a96102c8SMichael Baum if (!pkt) { 858a96102c8SMichael Baum cqe = &(*rxq->cqes)[rxq->cq_ci & cqe_cnt]; 859a96102c8SMichael Baum len = mlx5_rx_poll_len(rxq, cqe, cqe_cnt, &mcqe); 860a96102c8SMichael Baum if (!len) { 861a96102c8SMichael Baum rte_mbuf_raw_free(rep); 862a96102c8SMichael Baum break; 863a96102c8SMichael Baum } 864a96102c8SMichael Baum pkt = seg; 865a96102c8SMichael Baum MLX5_ASSERT(len >= (rxq->crc_present << 2)); 866*daa02b5cSOlivier Matz pkt->ol_flags &= RTE_MBUF_F_EXTERNAL; 867a96102c8SMichael Baum rxq_cq_to_mbuf(rxq, pkt, cqe, mcqe); 868a96102c8SMichael Baum if (rxq->crc_present) 869a96102c8SMichael Baum len -= RTE_ETHER_CRC_LEN; 870a96102c8SMichael Baum PKT_LEN(pkt) = len; 871a96102c8SMichael Baum if (cqe->lro_num_seg > 1) { 872a96102c8SMichael Baum mlx5_lro_update_hdr 873a96102c8SMichael Baum (rte_pktmbuf_mtod(pkt, uint8_t *), cqe, 874a96102c8SMichael Baum mcqe, rxq, len); 875*daa02b5cSOlivier Matz pkt->ol_flags |= RTE_MBUF_F_RX_LRO; 876a96102c8SMichael Baum pkt->tso_segsz = len / cqe->lro_num_seg; 877a96102c8SMichael Baum } 878a96102c8SMichael Baum } 879a96102c8SMichael Baum DATA_LEN(rep) = DATA_LEN(seg); 880a96102c8SMichael Baum PKT_LEN(rep) = PKT_LEN(seg); 881a96102c8SMichael Baum SET_DATA_OFF(rep, DATA_OFF(seg)); 882a96102c8SMichael Baum PORT(rep) = PORT(seg); 883a96102c8SMichael Baum (*rxq->elts)[idx] = rep; 884a96102c8SMichael Baum /* 885a96102c8SMichael Baum * Fill NIC descriptor with the new buffer. The lkey and size 886a96102c8SMichael Baum * of the buffers are already known, only the buffer address 887a96102c8SMichael Baum * changes. 888a96102c8SMichael Baum */ 889a96102c8SMichael Baum wqe->addr = rte_cpu_to_be_64(rte_pktmbuf_mtod(rep, uintptr_t)); 890a96102c8SMichael Baum /* If there's only one MR, no need to replace LKey in WQE. */ 891a96102c8SMichael Baum if (unlikely(mlx5_mr_btree_len(&rxq->mr_ctrl.cache_bh) > 1)) 892a96102c8SMichael Baum wqe->lkey = mlx5_rx_mb2mr(rxq, rep); 893a96102c8SMichael Baum if (len > DATA_LEN(seg)) { 894a96102c8SMichael Baum len -= DATA_LEN(seg); 895a96102c8SMichael Baum ++NB_SEGS(pkt); 896a96102c8SMichael Baum ++rq_ci; 897a96102c8SMichael Baum continue; 898a96102c8SMichael Baum } 899a96102c8SMichael Baum DATA_LEN(seg) = len; 900a96102c8SMichael Baum #ifdef MLX5_PMD_SOFT_COUNTERS 901a96102c8SMichael Baum /* Increment bytes counter. */ 902a96102c8SMichael Baum rxq->stats.ibytes += PKT_LEN(pkt); 903a96102c8SMichael Baum #endif 904a96102c8SMichael Baum /* Return packet. */ 905a96102c8SMichael Baum *(pkts++) = pkt; 906a96102c8SMichael Baum pkt = NULL; 907a96102c8SMichael Baum --pkts_n; 908a96102c8SMichael Baum ++i; 909a96102c8SMichael Baum /* Align consumer index to the next stride. */ 910a96102c8SMichael Baum rq_ci >>= sges_n; 911a96102c8SMichael Baum ++rq_ci; 912a96102c8SMichael Baum rq_ci <<= sges_n; 913a96102c8SMichael Baum } 914a96102c8SMichael Baum if (unlikely(i == 0 && ((rq_ci >> sges_n) == rxq->rq_ci))) 915a96102c8SMichael Baum return 0; 916a96102c8SMichael Baum /* Update the consumer index. */ 917a96102c8SMichael Baum rxq->rq_ci = rq_ci >> sges_n; 918a96102c8SMichael Baum rte_io_wmb(); 919a96102c8SMichael Baum *rxq->cq_db = rte_cpu_to_be_32(rxq->cq_ci); 920a96102c8SMichael Baum rte_io_wmb(); 921a96102c8SMichael Baum *rxq->rq_db = rte_cpu_to_be_32(rxq->rq_ci); 922a96102c8SMichael Baum #ifdef MLX5_PMD_SOFT_COUNTERS 923a96102c8SMichael Baum /* Increment packets counter. */ 924a96102c8SMichael Baum rxq->stats.ipackets += i; 925a96102c8SMichael Baum #endif 926a96102c8SMichael Baum return i; 927a96102c8SMichael Baum } 928a96102c8SMichael Baum 929a96102c8SMichael Baum /** 930a96102c8SMichael Baum * Update LRO packet TCP header. 931a96102c8SMichael Baum * The HW LRO feature doesn't update the TCP header after coalescing the 932a96102c8SMichael Baum * TCP segments but supplies information in CQE to fill it by SW. 933a96102c8SMichael Baum * 934a96102c8SMichael Baum * @param tcp 935a96102c8SMichael Baum * Pointer to the TCP header. 936a96102c8SMichael Baum * @param cqe 937a96102c8SMichael Baum * Pointer to the completion entry. 938a96102c8SMichael Baum * @param phcsum 939a96102c8SMichael Baum * The L3 pseudo-header checksum. 940a96102c8SMichael Baum */ 941a96102c8SMichael Baum static inline void 942a96102c8SMichael Baum mlx5_lro_update_tcp_hdr(struct rte_tcp_hdr *__rte_restrict tcp, 943a96102c8SMichael Baum volatile struct mlx5_cqe *__rte_restrict cqe, 944a96102c8SMichael Baum uint32_t phcsum, uint8_t l4_type) 945a96102c8SMichael Baum { 946a96102c8SMichael Baum /* 947a96102c8SMichael Baum * The HW calculates only the TCP payload checksum, need to complete 948a96102c8SMichael Baum * the TCP header checksum and the L3 pseudo-header checksum. 949a96102c8SMichael Baum */ 950a96102c8SMichael Baum uint32_t csum = phcsum + cqe->csum; 951a96102c8SMichael Baum 952a96102c8SMichael Baum if (l4_type == MLX5_L4_HDR_TYPE_TCP_EMPTY_ACK || 953a96102c8SMichael Baum l4_type == MLX5_L4_HDR_TYPE_TCP_WITH_ACL) { 954a96102c8SMichael Baum tcp->tcp_flags |= RTE_TCP_ACK_FLAG; 955a96102c8SMichael Baum tcp->recv_ack = cqe->lro_ack_seq_num; 956a96102c8SMichael Baum tcp->rx_win = cqe->lro_tcp_win; 957a96102c8SMichael Baum } 958a96102c8SMichael Baum if (cqe->lro_tcppsh_abort_dupack & MLX5_CQE_LRO_PUSH_MASK) 959a96102c8SMichael Baum tcp->tcp_flags |= RTE_TCP_PSH_FLAG; 960a96102c8SMichael Baum tcp->cksum = 0; 961a96102c8SMichael Baum csum += rte_raw_cksum(tcp, (tcp->data_off >> 4) * 4); 962a96102c8SMichael Baum csum = ((csum & 0xffff0000) >> 16) + (csum & 0xffff); 963a96102c8SMichael Baum csum = (~csum) & 0xffff; 964a96102c8SMichael Baum if (csum == 0) 965a96102c8SMichael Baum csum = 0xffff; 966a96102c8SMichael Baum tcp->cksum = csum; 967a96102c8SMichael Baum } 968a96102c8SMichael Baum 969a96102c8SMichael Baum /** 970a96102c8SMichael Baum * Update LRO packet headers. 971a96102c8SMichael Baum * The HW LRO feature doesn't update the L3/TCP headers after coalescing the 972a96102c8SMichael Baum * TCP segments but supply information in CQE to fill it by SW. 973a96102c8SMichael Baum * 974a96102c8SMichael Baum * @param padd 975a96102c8SMichael Baum * The packet address. 976a96102c8SMichael Baum * @param cqe 977a96102c8SMichael Baum * Pointer to the completion entry. 978a96102c8SMichael Baum * @param len 979a96102c8SMichael Baum * The packet length. 980a96102c8SMichael Baum */ 981a96102c8SMichael Baum static inline void 982a96102c8SMichael Baum mlx5_lro_update_hdr(uint8_t *__rte_restrict padd, 983a96102c8SMichael Baum volatile struct mlx5_cqe *__rte_restrict cqe, 984a96102c8SMichael Baum volatile struct mlx5_mini_cqe8 *mcqe, 985a96102c8SMichael Baum struct mlx5_rxq_data *rxq, uint32_t len) 986a96102c8SMichael Baum { 987a96102c8SMichael Baum union { 988a96102c8SMichael Baum struct rte_ether_hdr *eth; 989a96102c8SMichael Baum struct rte_vlan_hdr *vlan; 990a96102c8SMichael Baum struct rte_ipv4_hdr *ipv4; 991a96102c8SMichael Baum struct rte_ipv6_hdr *ipv6; 992a96102c8SMichael Baum struct rte_tcp_hdr *tcp; 993a96102c8SMichael Baum uint8_t *hdr; 994a96102c8SMichael Baum } h = { 995a96102c8SMichael Baum .hdr = padd, 996a96102c8SMichael Baum }; 997a96102c8SMichael Baum uint16_t proto = h.eth->ether_type; 998a96102c8SMichael Baum uint32_t phcsum; 999a96102c8SMichael Baum uint8_t l4_type; 1000a96102c8SMichael Baum 1001a96102c8SMichael Baum h.eth++; 1002a96102c8SMichael Baum while (proto == RTE_BE16(RTE_ETHER_TYPE_VLAN) || 1003a96102c8SMichael Baum proto == RTE_BE16(RTE_ETHER_TYPE_QINQ)) { 1004a96102c8SMichael Baum proto = h.vlan->eth_proto; 1005a96102c8SMichael Baum h.vlan++; 1006a96102c8SMichael Baum } 1007a96102c8SMichael Baum if (proto == RTE_BE16(RTE_ETHER_TYPE_IPV4)) { 1008a96102c8SMichael Baum h.ipv4->time_to_live = cqe->lro_min_ttl; 1009a96102c8SMichael Baum h.ipv4->total_length = rte_cpu_to_be_16(len - (h.hdr - padd)); 1010a96102c8SMichael Baum h.ipv4->hdr_checksum = 0; 1011a96102c8SMichael Baum h.ipv4->hdr_checksum = rte_ipv4_cksum(h.ipv4); 1012a96102c8SMichael Baum phcsum = rte_ipv4_phdr_cksum(h.ipv4, 0); 1013a96102c8SMichael Baum h.ipv4++; 1014a96102c8SMichael Baum } else { 1015a96102c8SMichael Baum h.ipv6->hop_limits = cqe->lro_min_ttl; 1016a96102c8SMichael Baum h.ipv6->payload_len = rte_cpu_to_be_16(len - (h.hdr - padd) - 1017a96102c8SMichael Baum sizeof(*h.ipv6)); 1018a96102c8SMichael Baum phcsum = rte_ipv6_phdr_cksum(h.ipv6, 0); 1019a96102c8SMichael Baum h.ipv6++; 1020a96102c8SMichael Baum } 1021a96102c8SMichael Baum if (mcqe == NULL || 1022a96102c8SMichael Baum rxq->mcqe_format != MLX5_CQE_RESP_FORMAT_L34H_STRIDX) 1023a96102c8SMichael Baum l4_type = (rte_be_to_cpu_16(cqe->hdr_type_etc) & 1024a96102c8SMichael Baum MLX5_CQE_L4_TYPE_MASK) >> MLX5_CQE_L4_TYPE_SHIFT; 1025a96102c8SMichael Baum else 1026a96102c8SMichael Baum l4_type = (rte_be_to_cpu_16(mcqe->hdr_type) & 1027a96102c8SMichael Baum MLX5_CQE_L4_TYPE_MASK) >> MLX5_CQE_L4_TYPE_SHIFT; 1028a96102c8SMichael Baum mlx5_lro_update_tcp_hdr(h.tcp, cqe, phcsum, l4_type); 1029a96102c8SMichael Baum } 1030a96102c8SMichael Baum 1031a96102c8SMichael Baum void 1032a96102c8SMichael Baum mlx5_mprq_buf_free(struct mlx5_mprq_buf *buf) 1033a96102c8SMichael Baum { 1034a96102c8SMichael Baum mlx5_mprq_buf_free_cb(NULL, buf); 1035a96102c8SMichael Baum } 1036a96102c8SMichael Baum 1037a96102c8SMichael Baum /** 1038a96102c8SMichael Baum * DPDK callback for RX with Multi-Packet RQ support. 1039a96102c8SMichael Baum * 1040a96102c8SMichael Baum * @param dpdk_rxq 1041a96102c8SMichael Baum * Generic pointer to RX queue structure. 1042a96102c8SMichael Baum * @param[out] pkts 1043a96102c8SMichael Baum * Array to store received packets. 1044a96102c8SMichael Baum * @param pkts_n 1045a96102c8SMichael Baum * Maximum number of packets in array. 1046a96102c8SMichael Baum * 1047a96102c8SMichael Baum * @return 1048a96102c8SMichael Baum * Number of packets successfully received (<= pkts_n). 1049a96102c8SMichael Baum */ 1050a96102c8SMichael Baum uint16_t 1051a96102c8SMichael Baum mlx5_rx_burst_mprq(void *dpdk_rxq, struct rte_mbuf **pkts, uint16_t pkts_n) 1052a96102c8SMichael Baum { 1053a96102c8SMichael Baum struct mlx5_rxq_data *rxq = dpdk_rxq; 1054a96102c8SMichael Baum const uint32_t strd_n = 1 << rxq->strd_num_n; 1055a96102c8SMichael Baum const uint32_t strd_sz = 1 << rxq->strd_sz_n; 1056a96102c8SMichael Baum const uint32_t cq_mask = (1 << rxq->cqe_n) - 1; 1057a96102c8SMichael Baum const uint32_t wq_mask = (1 << rxq->elts_n) - 1; 1058a96102c8SMichael Baum volatile struct mlx5_cqe *cqe = &(*rxq->cqes)[rxq->cq_ci & cq_mask]; 1059a96102c8SMichael Baum unsigned int i = 0; 1060a96102c8SMichael Baum uint32_t rq_ci = rxq->rq_ci; 1061a96102c8SMichael Baum uint16_t consumed_strd = rxq->consumed_strd; 1062a96102c8SMichael Baum struct mlx5_mprq_buf *buf = (*rxq->mprq_bufs)[rq_ci & wq_mask]; 1063a96102c8SMichael Baum 1064a96102c8SMichael Baum while (i < pkts_n) { 1065a96102c8SMichael Baum struct rte_mbuf *pkt; 1066a96102c8SMichael Baum int ret; 1067a96102c8SMichael Baum uint32_t len; 1068a96102c8SMichael Baum uint16_t strd_cnt; 1069a96102c8SMichael Baum uint16_t strd_idx; 1070a96102c8SMichael Baum uint32_t byte_cnt; 1071a96102c8SMichael Baum volatile struct mlx5_mini_cqe8 *mcqe = NULL; 1072a96102c8SMichael Baum enum mlx5_rqx_code rxq_code; 1073a96102c8SMichael Baum 1074a96102c8SMichael Baum if (consumed_strd == strd_n) { 1075a96102c8SMichael Baum /* Replace WQE if the buffer is still in use. */ 1076a96102c8SMichael Baum mprq_buf_replace(rxq, rq_ci & wq_mask); 1077a96102c8SMichael Baum /* Advance to the next WQE. */ 1078a96102c8SMichael Baum consumed_strd = 0; 1079a96102c8SMichael Baum ++rq_ci; 1080a96102c8SMichael Baum buf = (*rxq->mprq_bufs)[rq_ci & wq_mask]; 1081a96102c8SMichael Baum } 1082a96102c8SMichael Baum cqe = &(*rxq->cqes)[rxq->cq_ci & cq_mask]; 1083a96102c8SMichael Baum ret = mlx5_rx_poll_len(rxq, cqe, cq_mask, &mcqe); 1084a96102c8SMichael Baum if (!ret) 1085a96102c8SMichael Baum break; 1086a96102c8SMichael Baum byte_cnt = ret; 1087a96102c8SMichael Baum len = (byte_cnt & MLX5_MPRQ_LEN_MASK) >> MLX5_MPRQ_LEN_SHIFT; 1088a96102c8SMichael Baum MLX5_ASSERT((int)len >= (rxq->crc_present << 2)); 1089a96102c8SMichael Baum if (rxq->crc_present) 1090a96102c8SMichael Baum len -= RTE_ETHER_CRC_LEN; 1091a96102c8SMichael Baum if (mcqe && 1092a96102c8SMichael Baum rxq->mcqe_format == MLX5_CQE_RESP_FORMAT_FTAG_STRIDX) 1093a96102c8SMichael Baum strd_cnt = (len / strd_sz) + !!(len % strd_sz); 1094a96102c8SMichael Baum else 1095a96102c8SMichael Baum strd_cnt = (byte_cnt & MLX5_MPRQ_STRIDE_NUM_MASK) >> 1096a96102c8SMichael Baum MLX5_MPRQ_STRIDE_NUM_SHIFT; 1097a96102c8SMichael Baum MLX5_ASSERT(strd_cnt); 1098a96102c8SMichael Baum consumed_strd += strd_cnt; 1099a96102c8SMichael Baum if (byte_cnt & MLX5_MPRQ_FILLER_MASK) 1100a96102c8SMichael Baum continue; 1101a96102c8SMichael Baum strd_idx = rte_be_to_cpu_16(mcqe == NULL ? 1102a96102c8SMichael Baum cqe->wqe_counter : 1103a96102c8SMichael Baum mcqe->stride_idx); 1104a96102c8SMichael Baum MLX5_ASSERT(strd_idx < strd_n); 1105a96102c8SMichael Baum MLX5_ASSERT(!((rte_be_to_cpu_16(cqe->wqe_id) ^ rq_ci) & 1106a96102c8SMichael Baum wq_mask)); 1107a96102c8SMichael Baum pkt = rte_pktmbuf_alloc(rxq->mp); 1108a96102c8SMichael Baum if (unlikely(pkt == NULL)) { 1109a96102c8SMichael Baum ++rxq->stats.rx_nombuf; 1110a96102c8SMichael Baum break; 1111a96102c8SMichael Baum } 1112a96102c8SMichael Baum len = (byte_cnt & MLX5_MPRQ_LEN_MASK) >> MLX5_MPRQ_LEN_SHIFT; 1113a96102c8SMichael Baum MLX5_ASSERT((int)len >= (rxq->crc_present << 2)); 1114a96102c8SMichael Baum if (rxq->crc_present) 1115a96102c8SMichael Baum len -= RTE_ETHER_CRC_LEN; 1116a96102c8SMichael Baum rxq_code = mprq_buf_to_pkt(rxq, pkt, len, buf, 1117a96102c8SMichael Baum strd_idx, strd_cnt); 1118a96102c8SMichael Baum if (unlikely(rxq_code != MLX5_RXQ_CODE_EXIT)) { 1119a96102c8SMichael Baum rte_pktmbuf_free_seg(pkt); 1120a96102c8SMichael Baum if (rxq_code == MLX5_RXQ_CODE_DROPPED) { 1121a96102c8SMichael Baum ++rxq->stats.idropped; 1122a96102c8SMichael Baum continue; 1123a96102c8SMichael Baum } 1124a96102c8SMichael Baum if (rxq_code == MLX5_RXQ_CODE_NOMBUF) { 1125a96102c8SMichael Baum ++rxq->stats.rx_nombuf; 1126a96102c8SMichael Baum break; 1127a96102c8SMichael Baum } 1128a96102c8SMichael Baum } 1129a96102c8SMichael Baum rxq_cq_to_mbuf(rxq, pkt, cqe, mcqe); 1130a96102c8SMichael Baum if (cqe->lro_num_seg > 1) { 1131a96102c8SMichael Baum mlx5_lro_update_hdr(rte_pktmbuf_mtod(pkt, uint8_t *), 1132a96102c8SMichael Baum cqe, mcqe, rxq, len); 1133*daa02b5cSOlivier Matz pkt->ol_flags |= RTE_MBUF_F_RX_LRO; 1134a96102c8SMichael Baum pkt->tso_segsz = len / cqe->lro_num_seg; 1135a96102c8SMichael Baum } 1136a96102c8SMichael Baum PKT_LEN(pkt) = len; 1137a96102c8SMichael Baum PORT(pkt) = rxq->port_id; 1138a96102c8SMichael Baum #ifdef MLX5_PMD_SOFT_COUNTERS 1139a96102c8SMichael Baum /* Increment bytes counter. */ 1140a96102c8SMichael Baum rxq->stats.ibytes += PKT_LEN(pkt); 1141a96102c8SMichael Baum #endif 1142a96102c8SMichael Baum /* Return packet. */ 1143a96102c8SMichael Baum *(pkts++) = pkt; 1144a96102c8SMichael Baum ++i; 1145a96102c8SMichael Baum } 1146a96102c8SMichael Baum /* Update the consumer indexes. */ 1147a96102c8SMichael Baum rxq->consumed_strd = consumed_strd; 1148a96102c8SMichael Baum rte_io_wmb(); 1149a96102c8SMichael Baum *rxq->cq_db = rte_cpu_to_be_32(rxq->cq_ci); 1150a96102c8SMichael Baum if (rq_ci != rxq->rq_ci) { 1151a96102c8SMichael Baum rxq->rq_ci = rq_ci; 1152a96102c8SMichael Baum rte_io_wmb(); 1153a96102c8SMichael Baum *rxq->rq_db = rte_cpu_to_be_32(rxq->rq_ci); 1154a96102c8SMichael Baum } 1155a96102c8SMichael Baum #ifdef MLX5_PMD_SOFT_COUNTERS 1156a96102c8SMichael Baum /* Increment packets counter. */ 1157a96102c8SMichael Baum rxq->stats.ipackets += i; 1158a96102c8SMichael Baum #endif 1159a96102c8SMichael Baum return i; 1160a96102c8SMichael Baum } 1161a96102c8SMichael Baum 1162a96102c8SMichael Baum /** 1163a96102c8SMichael Baum * Dummy DPDK callback for RX. 1164a96102c8SMichael Baum * 1165a96102c8SMichael Baum * This function is used to temporarily replace the real callback during 1166a96102c8SMichael Baum * unsafe control operations on the queue, or in case of error. 1167a96102c8SMichael Baum * 1168a96102c8SMichael Baum * @param dpdk_rxq 1169a96102c8SMichael Baum * Generic pointer to RX queue structure. 1170a96102c8SMichael Baum * @param[out] pkts 1171a96102c8SMichael Baum * Array to store received packets. 1172a96102c8SMichael Baum * @param pkts_n 1173a96102c8SMichael Baum * Maximum number of packets in array. 1174a96102c8SMichael Baum * 1175a96102c8SMichael Baum * @return 1176a96102c8SMichael Baum * Number of packets successfully received (<= pkts_n). 1177a96102c8SMichael Baum */ 1178a96102c8SMichael Baum uint16_t 1179a96102c8SMichael Baum removed_rx_burst(void *dpdk_rxq __rte_unused, 1180a96102c8SMichael Baum struct rte_mbuf **pkts __rte_unused, 1181a96102c8SMichael Baum uint16_t pkts_n __rte_unused) 1182a96102c8SMichael Baum { 1183a96102c8SMichael Baum rte_mb(); 1184a96102c8SMichael Baum return 0; 1185a96102c8SMichael Baum } 1186a96102c8SMichael Baum 1187a96102c8SMichael Baum /* 1188a96102c8SMichael Baum * Vectorized Rx routines are not compiled in when required vector instructions 1189a96102c8SMichael Baum * are not supported on a target architecture. 1190a96102c8SMichael Baum * The following null stubs are needed for linkage when those are not included 1191a96102c8SMichael Baum * outside of this file (e.g. mlx5_rxtx_vec_sse.c for x86). 1192a96102c8SMichael Baum */ 1193a96102c8SMichael Baum 1194a96102c8SMichael Baum __rte_weak uint16_t 1195a96102c8SMichael Baum mlx5_rx_burst_vec(void *dpdk_rxq __rte_unused, 1196a96102c8SMichael Baum struct rte_mbuf **pkts __rte_unused, 1197a96102c8SMichael Baum uint16_t pkts_n __rte_unused) 1198a96102c8SMichael Baum { 1199a96102c8SMichael Baum return 0; 1200a96102c8SMichael Baum } 1201a96102c8SMichael Baum 1202a96102c8SMichael Baum __rte_weak uint16_t 1203a96102c8SMichael Baum mlx5_rx_burst_mprq_vec(void *dpdk_rxq __rte_unused, 1204a96102c8SMichael Baum struct rte_mbuf **pkts __rte_unused, 1205a96102c8SMichael Baum uint16_t pkts_n __rte_unused) 1206a96102c8SMichael Baum { 1207a96102c8SMichael Baum return 0; 1208a96102c8SMichael Baum } 1209a96102c8SMichael Baum 1210a96102c8SMichael Baum __rte_weak int 1211a96102c8SMichael Baum mlx5_rxq_check_vec_support(struct mlx5_rxq_data *rxq __rte_unused) 1212a96102c8SMichael Baum { 1213a96102c8SMichael Baum return -ENOTSUP; 1214a96102c8SMichael Baum } 1215a96102c8SMichael Baum 1216a96102c8SMichael Baum __rte_weak int 1217a96102c8SMichael Baum mlx5_check_vec_rx_support(struct rte_eth_dev *dev __rte_unused) 1218a96102c8SMichael Baum { 1219a96102c8SMichael Baum return -ENOTSUP; 1220a96102c8SMichael Baum } 1221a96102c8SMichael Baum 1222