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> 222235fcdaSSpike Du #include <rte_pmd_mlx5.h> 23a96102c8SMichael Baum 24a96102c8SMichael Baum #include "mlx5_autoconf.h" 25a96102c8SMichael Baum #include "mlx5_defs.h" 26a96102c8SMichael Baum #include "mlx5.h" 27a96102c8SMichael Baum #include "mlx5_utils.h" 28a96102c8SMichael Baum #include "mlx5_rxtx.h" 295c9f3294SSpike Du #include "mlx5_devx.h" 30a96102c8SMichael Baum #include "mlx5_rx.h" 312235fcdaSSpike Du #ifdef HAVE_MLX5_MSTFLINT 322235fcdaSSpike Du #include <mstflint/mtcr.h> 332235fcdaSSpike Du #endif 34a96102c8SMichael Baum 35a96102c8SMichael Baum 36a96102c8SMichael Baum static __rte_always_inline uint32_t 37a96102c8SMichael Baum rxq_cq_to_pkt_type(struct mlx5_rxq_data *rxq, volatile struct mlx5_cqe *cqe, 38a96102c8SMichael Baum volatile struct mlx5_mini_cqe8 *mcqe); 39a96102c8SMichael Baum 40a96102c8SMichael Baum static __rte_always_inline int 41a96102c8SMichael Baum mlx5_rx_poll_len(struct mlx5_rxq_data *rxq, volatile struct mlx5_cqe *cqe, 4202a6195cSAlexander Kozyrev uint16_t cqe_n, uint16_t cqe_mask, 4302a6195cSAlexander Kozyrev volatile struct mlx5_mini_cqe8 **mcqe, 44aa67ed30SAlexander Kozyrev uint16_t *skip_cnt, bool mprq); 45a96102c8SMichael Baum 46a96102c8SMichael Baum static __rte_always_inline uint32_t 47a96102c8SMichael Baum rxq_cq_to_ol_flags(volatile struct mlx5_cqe *cqe); 48a96102c8SMichael Baum 49a96102c8SMichael Baum static __rte_always_inline void 50a96102c8SMichael Baum rxq_cq_to_mbuf(struct mlx5_rxq_data *rxq, struct rte_mbuf *pkt, 51a96102c8SMichael Baum volatile struct mlx5_cqe *cqe, 52a96102c8SMichael Baum volatile struct mlx5_mini_cqe8 *mcqe); 53a96102c8SMichael Baum 54a96102c8SMichael Baum static inline void 55a96102c8SMichael Baum mlx5_lro_update_tcp_hdr(struct rte_tcp_hdr *__rte_restrict tcp, 56a96102c8SMichael Baum volatile struct mlx5_cqe *__rte_restrict cqe, 57a96102c8SMichael Baum uint32_t phcsum, uint8_t l4_type); 58a96102c8SMichael Baum 59a96102c8SMichael Baum static inline void 60a96102c8SMichael Baum mlx5_lro_update_hdr(uint8_t *__rte_restrict padd, 61a96102c8SMichael Baum volatile struct mlx5_cqe *__rte_restrict cqe, 62a96102c8SMichael Baum volatile struct mlx5_mini_cqe8 *mcqe, 63a96102c8SMichael Baum struct mlx5_rxq_data *rxq, uint32_t len); 64a96102c8SMichael Baum 65a96102c8SMichael Baum 66a96102c8SMichael Baum /** 67a96102c8SMichael Baum * Internal function to compute the number of used descriptors in an RX queue. 68a96102c8SMichael Baum * 69a96102c8SMichael Baum * @param rxq 70a96102c8SMichael Baum * The Rx queue. 71a96102c8SMichael Baum * 72a96102c8SMichael Baum * @return 73a96102c8SMichael Baum * The number of used Rx descriptor. 74a96102c8SMichael Baum */ 75a96102c8SMichael Baum static uint32_t 76a96102c8SMichael Baum rx_queue_count(struct mlx5_rxq_data *rxq) 77a96102c8SMichael Baum { 78a96102c8SMichael Baum struct rxq_zip *zip = &rxq->zip; 79a96102c8SMichael Baum volatile struct mlx5_cqe *cqe; 80a96102c8SMichael Baum const unsigned int cqe_n = (1 << rxq->cqe_n); 81a96102c8SMichael Baum const unsigned int sges_n = (1 << rxq->sges_n); 82a96102c8SMichael Baum const unsigned int elts_n = (1 << rxq->elts_n); 830947ed38SMichael Baum const unsigned int strd_n = RTE_BIT32(rxq->log_strd_num); 84a96102c8SMichael Baum const unsigned int cqe_cnt = cqe_n - 1; 85a96102c8SMichael Baum unsigned int cq_ci, used; 86a96102c8SMichael Baum 87a96102c8SMichael Baum /* if we are processing a compressed cqe */ 88a96102c8SMichael Baum if (zip->ai) { 89a96102c8SMichael Baum used = zip->cqe_cnt - zip->ai; 90a96102c8SMichael Baum cq_ci = zip->cq_ci; 91a96102c8SMichael Baum } else { 92a96102c8SMichael Baum used = 0; 93a96102c8SMichael Baum cq_ci = rxq->cq_ci; 94a96102c8SMichael Baum } 95a96102c8SMichael Baum cqe = &(*rxq->cqes)[cq_ci & cqe_cnt]; 96a96102c8SMichael Baum while (check_cqe(cqe, cqe_n, cq_ci) != MLX5_CQE_STATUS_HW_OWN) { 97a96102c8SMichael Baum int8_t op_own; 98a96102c8SMichael Baum unsigned int n; 99a96102c8SMichael Baum 100a96102c8SMichael Baum op_own = cqe->op_own; 101a96102c8SMichael Baum if (MLX5_CQE_FORMAT(op_own) == MLX5_COMPRESSED) 102a96102c8SMichael Baum n = rte_be_to_cpu_32(cqe->byte_cnt); 103a96102c8SMichael Baum else 104a96102c8SMichael Baum n = 1; 105a96102c8SMichael Baum cq_ci += n; 106a96102c8SMichael Baum used += n; 107a96102c8SMichael Baum cqe = &(*rxq->cqes)[cq_ci & cqe_cnt]; 108a96102c8SMichael Baum } 109a96102c8SMichael Baum used = RTE_MIN(used * sges_n, elts_n * strd_n); 110a96102c8SMichael Baum return used; 111a96102c8SMichael Baum } 112a96102c8SMichael Baum 113a96102c8SMichael Baum /** 114a96102c8SMichael Baum * DPDK callback to check the status of a Rx descriptor. 115a96102c8SMichael Baum * 116a96102c8SMichael Baum * @param rx_queue 117a96102c8SMichael Baum * The Rx queue. 118a96102c8SMichael Baum * @param[in] offset 119a96102c8SMichael Baum * The index of the descriptor in the ring. 120a96102c8SMichael Baum * 121a96102c8SMichael Baum * @return 122a96102c8SMichael Baum * The status of the Rx descriptor. 123a96102c8SMichael Baum */ 124a96102c8SMichael Baum int 125a96102c8SMichael Baum mlx5_rx_descriptor_status(void *rx_queue, uint16_t offset) 126a96102c8SMichael Baum { 127a96102c8SMichael Baum struct mlx5_rxq_data *rxq = rx_queue; 128a96102c8SMichael Baum 129a96102c8SMichael Baum if (offset >= (1 << rxq->cqe_n)) { 130a96102c8SMichael Baum rte_errno = EINVAL; 131a96102c8SMichael Baum return -rte_errno; 132a96102c8SMichael Baum } 133a96102c8SMichael Baum if (offset < rx_queue_count(rxq)) 134a96102c8SMichael Baum return RTE_ETH_RX_DESC_DONE; 135a96102c8SMichael Baum return RTE_ETH_RX_DESC_AVAIL; 136a96102c8SMichael Baum } 137a96102c8SMichael Baum 1385c9f3294SSpike Du /* Get rxq lwm percentage according to lwm number. */ 1395c9f3294SSpike Du static uint8_t 1405c9f3294SSpike Du mlx5_rxq_lwm_to_percentage(struct mlx5_rxq_priv *rxq) 1415c9f3294SSpike Du { 1425c9f3294SSpike Du struct mlx5_rxq_data *rxq_data = &rxq->ctrl->rxq; 1435c9f3294SSpike Du uint32_t wqe_cnt = 1 << (rxq_data->elts_n - rxq_data->sges_n); 1445c9f3294SSpike Du 1455c9f3294SSpike Du return rxq->lwm * 100 / wqe_cnt; 1465c9f3294SSpike Du } 1475c9f3294SSpike Du 148a96102c8SMichael Baum /** 149a96102c8SMichael Baum * DPDK callback to get the RX queue information. 150a96102c8SMichael Baum * 151a96102c8SMichael Baum * @param dev 152a96102c8SMichael Baum * Pointer to the device structure. 153a96102c8SMichael Baum * 154a96102c8SMichael Baum * @param rx_queue_id 155a96102c8SMichael Baum * Rx queue identificator. 156a96102c8SMichael Baum * 157a96102c8SMichael Baum * @param qinfo 158a96102c8SMichael Baum * Pointer to the RX queue information structure. 159a96102c8SMichael Baum * 160a96102c8SMichael Baum * @return 161a96102c8SMichael Baum * None. 162a96102c8SMichael Baum */ 163a96102c8SMichael Baum 164a96102c8SMichael Baum void 165a96102c8SMichael Baum mlx5_rxq_info_get(struct rte_eth_dev *dev, uint16_t rx_queue_id, 166a96102c8SMichael Baum struct rte_eth_rxq_info *qinfo) 167a96102c8SMichael Baum { 1685cf0707fSXueming Li struct mlx5_rxq_ctrl *rxq_ctrl = mlx5_rxq_ctrl_get(dev, rx_queue_id); 1695cf0707fSXueming Li struct mlx5_rxq_data *rxq = mlx5_rxq_data_get(dev, rx_queue_id); 1705c9f3294SSpike Du struct mlx5_rxq_priv *rxq_priv = mlx5_rxq_get(dev, rx_queue_id); 171a96102c8SMichael Baum 172a96102c8SMichael Baum if (!rxq) 173a96102c8SMichael Baum return; 174a96102c8SMichael Baum qinfo->mp = mlx5_rxq_mprq_enabled(rxq) ? 175a96102c8SMichael Baum rxq->mprq_mp : rxq->mp; 176a96102c8SMichael Baum qinfo->conf.rx_thresh.pthresh = 0; 177a96102c8SMichael Baum qinfo->conf.rx_thresh.hthresh = 0; 178a96102c8SMichael Baum qinfo->conf.rx_thresh.wthresh = 0; 179a96102c8SMichael Baum qinfo->conf.rx_free_thresh = rxq->rq_repl_thresh; 180a96102c8SMichael Baum qinfo->conf.rx_drop_en = 1; 1815cf0707fSXueming Li if (rxq_ctrl == NULL || rxq_ctrl->obj == NULL) 1825cf0707fSXueming Li qinfo->conf.rx_deferred_start = 0; 1835cf0707fSXueming Li else 1845cf0707fSXueming Li qinfo->conf.rx_deferred_start = 1; 185a96102c8SMichael Baum qinfo->conf.offloads = dev->data->dev_conf.rxmode.offloads; 186a96102c8SMichael Baum qinfo->scattered_rx = dev->data->scattered_rx; 187a96102c8SMichael Baum qinfo->nb_desc = mlx5_rxq_mprq_enabled(rxq) ? 1880947ed38SMichael Baum RTE_BIT32(rxq->elts_n) * RTE_BIT32(rxq->log_strd_num) : 1890947ed38SMichael Baum RTE_BIT32(rxq->elts_n); 1905c9f3294SSpike Du qinfo->avail_thresh = rxq_priv ? 1915c9f3294SSpike Du mlx5_rxq_lwm_to_percentage(rxq_priv) : 0; 192a96102c8SMichael Baum } 193a96102c8SMichael Baum 194a96102c8SMichael Baum /** 195a96102c8SMichael Baum * DPDK callback to get the RX packet burst mode information. 196a96102c8SMichael Baum * 197a96102c8SMichael Baum * @param dev 198a96102c8SMichael Baum * Pointer to the device structure. 199a96102c8SMichael Baum * 200a96102c8SMichael Baum * @param rx_queue_id 2017be78d02SJosh Soref * Rx queue identification. 202a96102c8SMichael Baum * 203a96102c8SMichael Baum * @param mode 204a96102c8SMichael Baum * Pointer to the burts mode information. 205a96102c8SMichael Baum * 206a96102c8SMichael Baum * @return 207a96102c8SMichael Baum * 0 as success, -EINVAL as failure. 208a96102c8SMichael Baum */ 209a96102c8SMichael Baum int 210a96102c8SMichael Baum mlx5_rx_burst_mode_get(struct rte_eth_dev *dev, 211a96102c8SMichael Baum uint16_t rx_queue_id __rte_unused, 212a96102c8SMichael Baum struct rte_eth_burst_mode *mode) 213a96102c8SMichael Baum { 214a96102c8SMichael Baum eth_rx_burst_t pkt_burst = dev->rx_pkt_burst; 2155cf0707fSXueming Li struct mlx5_rxq_priv *rxq = mlx5_rxq_get(dev, rx_queue_id); 216a96102c8SMichael Baum 217a96102c8SMichael Baum if (!rxq) { 218a96102c8SMichael Baum rte_errno = EINVAL; 219a96102c8SMichael Baum return -rte_errno; 220a96102c8SMichael Baum } 221a96102c8SMichael Baum if (pkt_burst == mlx5_rx_burst) { 222a96102c8SMichael Baum snprintf(mode->info, sizeof(mode->info), "%s", "Scalar"); 223a96102c8SMichael Baum } else if (pkt_burst == mlx5_rx_burst_mprq) { 224a96102c8SMichael Baum snprintf(mode->info, sizeof(mode->info), "%s", "Multi-Packet RQ"); 225a96102c8SMichael Baum } else if (pkt_burst == mlx5_rx_burst_vec) { 226a96102c8SMichael Baum #if defined RTE_ARCH_X86_64 227a96102c8SMichael Baum snprintf(mode->info, sizeof(mode->info), "%s", "Vector SSE"); 228a96102c8SMichael Baum #elif defined RTE_ARCH_ARM64 229a96102c8SMichael Baum snprintf(mode->info, sizeof(mode->info), "%s", "Vector Neon"); 230a96102c8SMichael Baum #elif defined RTE_ARCH_PPC_64 231a96102c8SMichael Baum snprintf(mode->info, sizeof(mode->info), "%s", "Vector AltiVec"); 232a96102c8SMichael Baum #else 233a96102c8SMichael Baum return -EINVAL; 234a96102c8SMichael Baum #endif 235a96102c8SMichael Baum } else if (pkt_burst == mlx5_rx_burst_mprq_vec) { 236a96102c8SMichael Baum #if defined RTE_ARCH_X86_64 237a96102c8SMichael Baum snprintf(mode->info, sizeof(mode->info), "%s", "MPRQ Vector SSE"); 238a96102c8SMichael Baum #elif defined RTE_ARCH_ARM64 239a96102c8SMichael Baum snprintf(mode->info, sizeof(mode->info), "%s", "MPRQ Vector Neon"); 240a96102c8SMichael Baum #elif defined RTE_ARCH_PPC_64 241a96102c8SMichael Baum snprintf(mode->info, sizeof(mode->info), "%s", "MPRQ Vector AltiVec"); 242a96102c8SMichael Baum #else 243a96102c8SMichael Baum return -EINVAL; 244a96102c8SMichael Baum #endif 245a96102c8SMichael Baum } else { 246a96102c8SMichael Baum return -EINVAL; 247a96102c8SMichael Baum } 248a96102c8SMichael Baum return 0; 249a96102c8SMichael Baum } 250a96102c8SMichael Baum 251a96102c8SMichael Baum /** 252a96102c8SMichael Baum * DPDK callback to get the number of used descriptors in a RX queue. 253a96102c8SMichael Baum * 2548d7d4fcdSKonstantin Ananyev * @param rx_queue 2558d7d4fcdSKonstantin Ananyev * The Rx queue pointer. 256a96102c8SMichael Baum * 257a96102c8SMichael Baum * @return 258a96102c8SMichael Baum * The number of used rx descriptor. 259a96102c8SMichael Baum * -EINVAL if the queue is invalid 260a96102c8SMichael Baum */ 261a96102c8SMichael Baum uint32_t 2628d7d4fcdSKonstantin Ananyev mlx5_rx_queue_count(void *rx_queue) 263a96102c8SMichael Baum { 2648d7d4fcdSKonstantin Ananyev struct mlx5_rxq_data *rxq = rx_queue; 2658d7d4fcdSKonstantin Ananyev struct rte_eth_dev *dev; 2668d7d4fcdSKonstantin Ananyev 2678d7d4fcdSKonstantin Ananyev if (!rxq) { 2688d7d4fcdSKonstantin Ananyev rte_errno = EINVAL; 2698d7d4fcdSKonstantin Ananyev return -rte_errno; 2708d7d4fcdSKonstantin Ananyev } 2718d7d4fcdSKonstantin Ananyev 2728d7d4fcdSKonstantin Ananyev dev = &rte_eth_devices[rxq->port_id]; 273a96102c8SMichael Baum 274a96102c8SMichael Baum if (dev->rx_pkt_burst == NULL || 275a41f593fSFerruh Yigit dev->rx_pkt_burst == rte_eth_pkt_burst_dummy) { 276a96102c8SMichael Baum rte_errno = ENOTSUP; 277a96102c8SMichael Baum return -rte_errno; 278a96102c8SMichael Baum } 2798d7d4fcdSKonstantin Ananyev 280a96102c8SMichael Baum return rx_queue_count(rxq); 281a96102c8SMichael Baum } 282a96102c8SMichael Baum 2836afc4bafSAnatoly Burakov #define CLB_VAL_IDX 0 2846afc4bafSAnatoly Burakov #define CLB_MSK_IDX 1 2856afc4bafSAnatoly Burakov static int 2866afc4bafSAnatoly Burakov mlx5_monitor_callback(const uint64_t value, 2876afc4bafSAnatoly Burakov const uint64_t opaque[RTE_POWER_MONITOR_OPAQUE_SZ]) 2886afc4bafSAnatoly Burakov { 2896afc4bafSAnatoly Burakov const uint64_t m = opaque[CLB_MSK_IDX]; 2906afc4bafSAnatoly Burakov const uint64_t v = opaque[CLB_VAL_IDX]; 2916afc4bafSAnatoly Burakov 2926afc4bafSAnatoly Burakov return (value & m) == v ? -1 : 0; 2936afc4bafSAnatoly Burakov } 2946afc4bafSAnatoly Burakov 295a8f0df6bSAlexander Kozyrev int mlx5_get_monitor_addr(void *rx_queue, struct rte_power_monitor_cond *pmc) 296a8f0df6bSAlexander Kozyrev { 297a8f0df6bSAlexander Kozyrev struct mlx5_rxq_data *rxq = rx_queue; 298a8f0df6bSAlexander Kozyrev const unsigned int cqe_num = 1 << rxq->cqe_n; 299a8f0df6bSAlexander Kozyrev const unsigned int cqe_mask = cqe_num - 1; 300a8f0df6bSAlexander Kozyrev const uint16_t idx = rxq->cq_ci & cqe_num; 30102a6195cSAlexander Kozyrev const uint8_t vic = rxq->cq_ci >> rxq->cqe_n; 302a8f0df6bSAlexander Kozyrev volatile struct mlx5_cqe *cqe = &(*rxq->cqes)[rxq->cq_ci & cqe_mask]; 303a8f0df6bSAlexander Kozyrev 304a8f0df6bSAlexander Kozyrev if (unlikely(rxq->cqes == NULL)) { 305a8f0df6bSAlexander Kozyrev rte_errno = EINVAL; 306a8f0df6bSAlexander Kozyrev return -rte_errno; 307a8f0df6bSAlexander Kozyrev } 30802a6195cSAlexander Kozyrev if (rxq->cqe_comp_layout) { 30902a6195cSAlexander Kozyrev pmc->addr = &cqe->validity_iteration_count; 31002a6195cSAlexander Kozyrev pmc->opaque[CLB_VAL_IDX] = vic; 31102a6195cSAlexander Kozyrev pmc->opaque[CLB_MSK_IDX] = MLX5_CQE_VIC_INIT; 31202a6195cSAlexander Kozyrev } else { 313a8f0df6bSAlexander Kozyrev pmc->addr = &cqe->op_own; 3146afc4bafSAnatoly Burakov pmc->opaque[CLB_VAL_IDX] = !!idx; 3156afc4bafSAnatoly Burakov pmc->opaque[CLB_MSK_IDX] = MLX5_CQE_OWNER_MASK; 31602a6195cSAlexander Kozyrev } 3176afc4bafSAnatoly Burakov pmc->fn = mlx5_monitor_callback; 318a8f0df6bSAlexander Kozyrev pmc->size = sizeof(uint8_t); 319a8f0df6bSAlexander Kozyrev return 0; 320a8f0df6bSAlexander Kozyrev } 321a8f0df6bSAlexander Kozyrev 322a96102c8SMichael Baum /** 323a96102c8SMichael Baum * Translate RX completion flags to packet type. 324a96102c8SMichael Baum * 325a96102c8SMichael Baum * @param[in] rxq 326a96102c8SMichael Baum * Pointer to RX queue structure. 327a96102c8SMichael Baum * @param[in] cqe 328a96102c8SMichael Baum * Pointer to CQE. 329a96102c8SMichael Baum * 330a96102c8SMichael Baum * @note: fix mlx5_dev_supported_ptypes_get() if any change here. 331a96102c8SMichael Baum * 332a96102c8SMichael Baum * @return 333a96102c8SMichael Baum * Packet type for struct rte_mbuf. 334a96102c8SMichael Baum */ 335a96102c8SMichael Baum static inline uint32_t 336a96102c8SMichael Baum rxq_cq_to_pkt_type(struct mlx5_rxq_data *rxq, volatile struct mlx5_cqe *cqe, 337a96102c8SMichael Baum volatile struct mlx5_mini_cqe8 *mcqe) 338a96102c8SMichael Baum { 339a96102c8SMichael Baum uint8_t idx; 340a96102c8SMichael Baum uint8_t ptype; 341a96102c8SMichael Baum uint8_t pinfo = (cqe->pkt_info & 0x3) << 6; 342a96102c8SMichael Baum 343a96102c8SMichael Baum /* Get l3/l4 header from mini-CQE in case L3/L4 format*/ 344a96102c8SMichael Baum if (mcqe == NULL || 345a96102c8SMichael Baum rxq->mcqe_format != MLX5_CQE_RESP_FORMAT_L34H_STRIDX) 346a96102c8SMichael Baum ptype = (cqe->hdr_type_etc & 0xfc00) >> 10; 347a96102c8SMichael Baum else 348a96102c8SMichael Baum ptype = mcqe->hdr_type >> 2; 349a96102c8SMichael Baum /* 350a96102c8SMichael Baum * The index to the array should have: 351a96102c8SMichael Baum * bit[1:0] = l3_hdr_type 352a96102c8SMichael Baum * bit[4:2] = l4_hdr_type 353a96102c8SMichael Baum * bit[5] = ip_frag 354a96102c8SMichael Baum * bit[6] = tunneled 355a96102c8SMichael Baum * bit[7] = outer_l3_type 356a96102c8SMichael Baum */ 357a96102c8SMichael Baum idx = pinfo | ptype; 358a96102c8SMichael Baum return mlx5_ptype_table[idx] | rxq->tunnel * !!(idx & (1 << 6)); 359a96102c8SMichael Baum } 360a96102c8SMichael Baum 361a96102c8SMichael Baum /** 362a96102c8SMichael Baum * Initialize Rx WQ and indexes. 363a96102c8SMichael Baum * 364a96102c8SMichael Baum * @param[in] rxq 365a96102c8SMichael Baum * Pointer to RX queue structure. 366a96102c8SMichael Baum */ 367a96102c8SMichael Baum void 368a96102c8SMichael Baum mlx5_rxq_initialize(struct mlx5_rxq_data *rxq) 369a96102c8SMichael Baum { 370a96102c8SMichael Baum const unsigned int wqe_n = 1 << rxq->elts_n; 371a96102c8SMichael Baum unsigned int i; 372a96102c8SMichael Baum 373a96102c8SMichael Baum for (i = 0; (i != wqe_n); ++i) { 374a96102c8SMichael Baum volatile struct mlx5_wqe_data_seg *scat; 375a96102c8SMichael Baum uintptr_t addr; 376a96102c8SMichael Baum uint32_t byte_count; 377077be91dSDmitry Kozlyuk uint32_t lkey; 378a96102c8SMichael Baum 379a96102c8SMichael Baum if (mlx5_rxq_mprq_enabled(rxq)) { 380a96102c8SMichael Baum struct mlx5_mprq_buf *buf = (*rxq->mprq_bufs)[i]; 381a96102c8SMichael Baum 382a96102c8SMichael Baum scat = &((volatile struct mlx5_wqe_mprq *) 383a96102c8SMichael Baum rxq->wqes)[i].dseg; 3840947ed38SMichael Baum addr = (uintptr_t)mlx5_mprq_buf_addr 3850947ed38SMichael Baum (buf, RTE_BIT32(rxq->log_strd_num)); 3860947ed38SMichael Baum byte_count = RTE_BIT32(rxq->log_strd_sz) * 3870947ed38SMichael Baum RTE_BIT32(rxq->log_strd_num); 388077be91dSDmitry Kozlyuk lkey = mlx5_rx_addr2mr(rxq, addr); 389a96102c8SMichael Baum } else { 390a96102c8SMichael Baum struct rte_mbuf *buf = (*rxq->elts)[i]; 391a96102c8SMichael Baum 392a96102c8SMichael Baum scat = &((volatile struct mlx5_wqe_data_seg *) 393a96102c8SMichael Baum rxq->wqes)[i]; 394a96102c8SMichael Baum addr = rte_pktmbuf_mtod(buf, uintptr_t); 395a96102c8SMichael Baum byte_count = DATA_LEN(buf); 396077be91dSDmitry Kozlyuk lkey = mlx5_rx_mb2mr(rxq, buf); 397a96102c8SMichael Baum } 398a96102c8SMichael Baum /* scat->addr must be able to store a pointer. */ 399a96102c8SMichael Baum MLX5_ASSERT(sizeof(scat->addr) >= sizeof(uintptr_t)); 400a96102c8SMichael Baum *scat = (struct mlx5_wqe_data_seg){ 401a96102c8SMichael Baum .addr = rte_cpu_to_be_64(addr), 402a96102c8SMichael Baum .byte_count = rte_cpu_to_be_32(byte_count), 403077be91dSDmitry Kozlyuk .lkey = lkey, 404a96102c8SMichael Baum }; 405a96102c8SMichael Baum } 406a96102c8SMichael Baum rxq->consumed_strd = 0; 407a96102c8SMichael Baum rxq->decompressed = 0; 408a96102c8SMichael Baum rxq->rq_pi = 0; 409a96102c8SMichael Baum rxq->zip = (struct rxq_zip){ 410a96102c8SMichael Baum .ai = 0, 411a96102c8SMichael Baum }; 412a96102c8SMichael Baum rxq->elts_ci = mlx5_rxq_mprq_enabled(rxq) ? 4130947ed38SMichael Baum (wqe_n >> rxq->sges_n) * RTE_BIT32(rxq->log_strd_num) : 0; 414a96102c8SMichael Baum /* Update doorbell counter. */ 415a96102c8SMichael Baum rxq->rq_ci = wqe_n >> rxq->sges_n; 416a96102c8SMichael Baum rte_io_wmb(); 417a96102c8SMichael Baum *rxq->rq_db = rte_cpu_to_be_32(rxq->rq_ci); 418a96102c8SMichael Baum } 419a96102c8SMichael Baum 420aa67ed30SAlexander Kozyrev #define MLX5_ERROR_CQE_MASK 0x40000000 42160b254e3SMatan Azrad /* Must be negative. */ 422aa67ed30SAlexander Kozyrev #define MLX5_REGULAR_ERROR_CQE_RET (-5) 423aa67ed30SAlexander Kozyrev #define MLX5_CRITICAL_ERROR_CQE_RET (-4) 42460b254e3SMatan Azrad /* Must not be negative. */ 42560b254e3SMatan Azrad #define MLX5_RECOVERY_ERROR_RET 0 426aa67ed30SAlexander Kozyrev #define MLX5_RECOVERY_IGNORE_RET 1 427aa67ed30SAlexander Kozyrev #define MLX5_RECOVERY_COMPLETED_RET 2 42860b254e3SMatan Azrad 429a96102c8SMichael Baum /** 430a96102c8SMichael Baum * Handle a Rx error. 431a96102c8SMichael Baum * The function inserts the RQ state to reset when the first error CQE is 432a96102c8SMichael Baum * shown, then drains the CQ by the caller function loop. When the CQ is empty, 433a96102c8SMichael Baum * it moves the RQ state to ready and initializes the RQ. 434a96102c8SMichael Baum * Next CQE identification and error counting are in the caller responsibility. 435a96102c8SMichael Baum * 436a96102c8SMichael Baum * @param[in] rxq 437a96102c8SMichael Baum * Pointer to RX queue structure. 438a96102c8SMichael Baum * @param[in] vec 439a96102c8SMichael Baum * 1 when called from vectorized Rx burst, need to prepare mbufs for the RQ. 440a96102c8SMichael Baum * 0 when called from non-vectorized Rx burst. 441633684e0SAlexander Kozyrev * @param[in] err_n 442633684e0SAlexander Kozyrev * Number of CQEs to check for an error. 443a96102c8SMichael Baum * 444a96102c8SMichael Baum * @return 445aa67ed30SAlexander Kozyrev * MLX5_RECOVERY_ERROR_RET in case of recovery error, 446aa67ed30SAlexander Kozyrev * MLX5_RECOVERY_IGNORE_RET in case of non-critical error syndrome, 447aa67ed30SAlexander Kozyrev * MLX5_RECOVERY_COMPLETED_RET in case of recovery is completed, 448aa67ed30SAlexander Kozyrev * otherwise the CQE status after ignored error syndrome or queue reset. 449a96102c8SMichael Baum */ 450a96102c8SMichael Baum int 451aa67ed30SAlexander Kozyrev mlx5_rx_err_handle(struct mlx5_rxq_data *rxq, uint8_t vec, 452aa67ed30SAlexander Kozyrev uint16_t err_n, uint16_t *skip_cnt) 453a96102c8SMichael Baum { 454a96102c8SMichael Baum const uint16_t cqe_n = 1 << rxq->cqe_n; 455a96102c8SMichael Baum const uint16_t cqe_mask = cqe_n - 1; 456a96102c8SMichael Baum const uint16_t wqe_n = 1 << rxq->elts_n; 4570947ed38SMichael Baum const uint16_t strd_n = RTE_BIT32(rxq->log_strd_num); 458a96102c8SMichael Baum struct mlx5_rxq_ctrl *rxq_ctrl = 459a96102c8SMichael Baum container_of(rxq, struct mlx5_rxq_ctrl, rxq); 460a96102c8SMichael Baum union { 461a96102c8SMichael Baum volatile struct mlx5_cqe *cqe; 462*3cddeba0SAlexander Kozyrev volatile struct mlx5_error_cqe *err_cqe; 463a96102c8SMichael Baum } u = { 464633684e0SAlexander Kozyrev .cqe = &(*rxq->cqes)[(rxq->cq_ci - vec) & cqe_mask], 465a96102c8SMichael Baum }; 466a96102c8SMichael Baum struct mlx5_mp_arg_queue_state_modify sm; 467aa67ed30SAlexander Kozyrev bool critical_syndrome = false; 468633684e0SAlexander Kozyrev int ret, i; 469a96102c8SMichael Baum 470a96102c8SMichael Baum switch (rxq->err_state) { 471aa67ed30SAlexander Kozyrev case MLX5_RXQ_ERR_STATE_IGNORE: 472aa67ed30SAlexander Kozyrev ret = check_cqe(u.cqe, cqe_n, rxq->cq_ci - vec); 473aa67ed30SAlexander Kozyrev if (ret != MLX5_CQE_STATUS_ERR) { 474aa67ed30SAlexander Kozyrev rxq->err_state = MLX5_RXQ_ERR_STATE_NO_ERROR; 475aa67ed30SAlexander Kozyrev return ret; 476aa67ed30SAlexander Kozyrev } 477aa67ed30SAlexander Kozyrev /* Fall-through */ 478a96102c8SMichael Baum case MLX5_RXQ_ERR_STATE_NO_ERROR: 479633684e0SAlexander Kozyrev for (i = 0; i < (int)err_n; i++) { 480633684e0SAlexander Kozyrev u.cqe = &(*rxq->cqes)[(rxq->cq_ci - vec - i) & cqe_mask]; 481aa67ed30SAlexander Kozyrev if (MLX5_CQE_OPCODE(u.cqe->op_own) == MLX5_CQE_RESP_ERR) { 482aa67ed30SAlexander Kozyrev if (u.err_cqe->syndrome == MLX5_CQE_SYNDROME_LOCAL_QP_OP_ERR || 483aa67ed30SAlexander Kozyrev u.err_cqe->syndrome == MLX5_CQE_SYNDROME_LOCAL_PROT_ERR || 484aa67ed30SAlexander Kozyrev u.err_cqe->syndrome == MLX5_CQE_SYNDROME_WR_FLUSH_ERR) 485aa67ed30SAlexander Kozyrev critical_syndrome = true; 486633684e0SAlexander Kozyrev break; 487633684e0SAlexander Kozyrev } 488aa67ed30SAlexander Kozyrev } 489aa67ed30SAlexander Kozyrev if (!critical_syndrome) { 490aa67ed30SAlexander Kozyrev if (rxq->err_state == MLX5_RXQ_ERR_STATE_NO_ERROR) { 491aa67ed30SAlexander Kozyrev *skip_cnt = 0; 492aa67ed30SAlexander Kozyrev if (i == err_n) 493aa67ed30SAlexander Kozyrev rxq->err_state = MLX5_RXQ_ERR_STATE_IGNORE; 494aa67ed30SAlexander Kozyrev } 495aa67ed30SAlexander Kozyrev return MLX5_RECOVERY_IGNORE_RET; 496aa67ed30SAlexander Kozyrev } 497a96102c8SMichael Baum rxq->err_state = MLX5_RXQ_ERR_STATE_NEED_RESET; 498a96102c8SMichael Baum /* Fall-through */ 499a96102c8SMichael Baum case MLX5_RXQ_ERR_STATE_NEED_RESET: 500a96102c8SMichael Baum sm.is_wq = 1; 501a96102c8SMichael Baum sm.queue_id = rxq->idx; 502a96102c8SMichael Baum sm.state = IBV_WQS_RESET; 5035db77fefSXueming Li if (mlx5_queue_state_modify(RXQ_DEV(rxq_ctrl), &sm)) 50460b254e3SMatan Azrad return MLX5_RECOVERY_ERROR_RET; 505a96102c8SMichael Baum if (rxq_ctrl->dump_file_n < 5065db77fefSXueming Li RXQ_PORT(rxq_ctrl)->config.max_dump_files_num) { 507a96102c8SMichael Baum MKSTR(err_str, "Unexpected CQE error syndrome " 508a96102c8SMichael Baum "0x%02x CQN = %u RQN = %u wqe_counter = %u" 509a96102c8SMichael Baum " rq_ci = %u cq_ci = %u", u.err_cqe->syndrome, 510a96102c8SMichael Baum rxq->cqn, rxq_ctrl->wqn, 511a96102c8SMichael Baum rte_be_to_cpu_16(u.err_cqe->wqe_counter), 512a96102c8SMichael Baum rxq->rq_ci << rxq->sges_n, rxq->cq_ci); 513a96102c8SMichael Baum MKSTR(name, "dpdk_mlx5_port_%u_rxq_%u_%u", 514a96102c8SMichael Baum rxq->port_id, rxq->idx, (uint32_t)rte_rdtsc()); 515a96102c8SMichael Baum mlx5_dump_debug_information(name, NULL, err_str, 0); 516a96102c8SMichael Baum mlx5_dump_debug_information(name, "MLX5 Error CQ:", 517a96102c8SMichael Baum (const void *)((uintptr_t) 518a96102c8SMichael Baum rxq->cqes), 519a96102c8SMichael Baum sizeof(*u.cqe) * cqe_n); 520a96102c8SMichael Baum mlx5_dump_debug_information(name, "MLX5 Error RQ:", 521a96102c8SMichael Baum (const void *)((uintptr_t) 522a96102c8SMichael Baum rxq->wqes), 523a96102c8SMichael Baum 16 * wqe_n); 524a96102c8SMichael Baum rxq_ctrl->dump_file_n++; 525a96102c8SMichael Baum } 526a96102c8SMichael Baum rxq->err_state = MLX5_RXQ_ERR_STATE_NEED_READY; 527a96102c8SMichael Baum /* Fall-through */ 528a96102c8SMichael Baum case MLX5_RXQ_ERR_STATE_NEED_READY: 529a96102c8SMichael Baum ret = check_cqe(u.cqe, cqe_n, rxq->cq_ci); 530a96102c8SMichael Baum if (ret == MLX5_CQE_STATUS_HW_OWN) { 531a96102c8SMichael Baum rte_io_wmb(); 532a96102c8SMichael Baum *rxq->cq_db = rte_cpu_to_be_32(rxq->cq_ci); 533a96102c8SMichael Baum rte_io_wmb(); 534a96102c8SMichael Baum /* 535a96102c8SMichael Baum * The RQ consumer index must be zeroed while moving 536a96102c8SMichael Baum * from RESET state to RDY state. 537a96102c8SMichael Baum */ 538a96102c8SMichael Baum *rxq->rq_db = rte_cpu_to_be_32(0); 539a96102c8SMichael Baum rte_io_wmb(); 540a96102c8SMichael Baum sm.is_wq = 1; 541a96102c8SMichael Baum sm.queue_id = rxq->idx; 542a96102c8SMichael Baum sm.state = IBV_WQS_RDY; 5435db77fefSXueming Li if (mlx5_queue_state_modify(RXQ_DEV(rxq_ctrl), &sm)) 54460b254e3SMatan Azrad return MLX5_RECOVERY_ERROR_RET; 545a96102c8SMichael Baum if (vec) { 546a96102c8SMichael Baum const uint32_t elts_n = 547a96102c8SMichael Baum mlx5_rxq_mprq_enabled(rxq) ? 548a96102c8SMichael Baum wqe_n * strd_n : wqe_n; 549a96102c8SMichael Baum const uint32_t e_mask = elts_n - 1; 550a96102c8SMichael Baum uint32_t elts_ci = 551a96102c8SMichael Baum mlx5_rxq_mprq_enabled(rxq) ? 552a96102c8SMichael Baum rxq->elts_ci : rxq->rq_ci; 553a96102c8SMichael Baum uint32_t elt_idx; 554a96102c8SMichael Baum struct rte_mbuf **elt; 555a96102c8SMichael Baum unsigned int n = elts_n - (elts_ci - 556a96102c8SMichael Baum rxq->rq_pi); 557a96102c8SMichael Baum 558a96102c8SMichael Baum for (i = 0; i < (int)n; ++i) { 559a96102c8SMichael Baum elt_idx = (elts_ci + i) & e_mask; 560a96102c8SMichael Baum elt = &(*rxq->elts)[elt_idx]; 561a96102c8SMichael Baum *elt = rte_mbuf_raw_alloc(rxq->mp); 562a96102c8SMichael Baum if (!*elt) { 563a96102c8SMichael Baum for (i--; i >= 0; --i) { 564a96102c8SMichael Baum elt_idx = (elts_ci + 565a96102c8SMichael Baum i) & elts_n; 566a96102c8SMichael Baum elt = &(*rxq->elts) 567a96102c8SMichael Baum [elt_idx]; 568a96102c8SMichael Baum rte_pktmbuf_free_seg 569a96102c8SMichael Baum (*elt); 570a96102c8SMichael Baum } 57160b254e3SMatan Azrad return MLX5_RECOVERY_ERROR_RET; 572a96102c8SMichael Baum } 573a96102c8SMichael Baum } 574a96102c8SMichael Baum for (i = 0; i < (int)elts_n; ++i) { 575a96102c8SMichael Baum elt = &(*rxq->elts)[i]; 576a96102c8SMichael Baum DATA_LEN(*elt) = 577a96102c8SMichael Baum (uint16_t)((*elt)->buf_len - 578a96102c8SMichael Baum rte_pktmbuf_headroom(*elt)); 579a96102c8SMichael Baum } 580a96102c8SMichael Baum /* Padding with a fake mbuf for vec Rx. */ 581a96102c8SMichael Baum for (i = 0; i < MLX5_VPMD_DESCS_PER_LOOP; ++i) 582a96102c8SMichael Baum (*rxq->elts)[elts_n + i] = 583a96102c8SMichael Baum &rxq->fake_mbuf; 584a96102c8SMichael Baum } 585a96102c8SMichael Baum mlx5_rxq_initialize(rxq); 586a96102c8SMichael Baum rxq->err_state = MLX5_RXQ_ERR_STATE_NO_ERROR; 587aa67ed30SAlexander Kozyrev return MLX5_RECOVERY_COMPLETED_RET; 588a96102c8SMichael Baum } 589a96102c8SMichael Baum return ret; 590a96102c8SMichael Baum default: 59160b254e3SMatan Azrad return MLX5_RECOVERY_ERROR_RET; 592a96102c8SMichael Baum } 593a96102c8SMichael Baum } 594a96102c8SMichael Baum 595a96102c8SMichael Baum /** 596a96102c8SMichael Baum * Get size of the next packet for a given CQE. For compressed CQEs, the 597a96102c8SMichael Baum * consumer index is updated only once all packets of the current one have 598a96102c8SMichael Baum * been processed. 599a96102c8SMichael Baum * 600a96102c8SMichael Baum * @param rxq 601a96102c8SMichael Baum * Pointer to RX queue. 602a96102c8SMichael Baum * @param cqe 603a96102c8SMichael Baum * CQE to process. 60402a6195cSAlexander Kozyrev * @param cqe_n 60502a6195cSAlexander Kozyrev * Completion queue count. 60602a6195cSAlexander Kozyrev * @param cqe_mask 60702a6195cSAlexander Kozyrev * Completion queue mask. 608a96102c8SMichael Baum * @param[out] mcqe 609a96102c8SMichael Baum * Store pointer to mini-CQE if compressed. Otherwise, the pointer is not 610a96102c8SMichael Baum * written. 611aa67ed30SAlexander Kozyrev * @param[out] skip_cnt 612aa67ed30SAlexander Kozyrev * Number of packets skipped due to recoverable errors. 613aa67ed30SAlexander Kozyrev * @param mprq 614aa67ed30SAlexander Kozyrev * Indication if it is called from MPRQ. 615a96102c8SMichael Baum * @return 616ef296e8fSViacheslav Ovsiienko * 0 in case of empty CQE, 617ef296e8fSViacheslav Ovsiienko * MLX5_REGULAR_ERROR_CQE_RET in case of error CQE, 618aa67ed30SAlexander Kozyrev * MLX5_CRITICAL_ERROR_CQE_RET in case of error CQE lead to Rx queue reset, 619aa67ed30SAlexander Kozyrev * otherwise the packet size in regular RxQ, 620aa67ed30SAlexander Kozyrev * and striding byte count format in mprq case. 621a96102c8SMichael Baum */ 622a96102c8SMichael Baum static inline int 623a96102c8SMichael Baum mlx5_rx_poll_len(struct mlx5_rxq_data *rxq, volatile struct mlx5_cqe *cqe, 62402a6195cSAlexander Kozyrev uint16_t cqe_n, uint16_t cqe_mask, 62502a6195cSAlexander Kozyrev volatile struct mlx5_mini_cqe8 **mcqe, 626aa67ed30SAlexander Kozyrev uint16_t *skip_cnt, bool mprq) 627a96102c8SMichael Baum { 628a96102c8SMichael Baum struct rxq_zip *zip = &rxq->zip; 629aa67ed30SAlexander Kozyrev int len = 0, ret = 0; 63002a6195cSAlexander Kozyrev uint32_t idx, end; 631a96102c8SMichael Baum 632a96102c8SMichael Baum do { 633a96102c8SMichael Baum len = 0; 634a96102c8SMichael Baum /* Process compressed data in the CQE and mini arrays. */ 635a96102c8SMichael Baum if (zip->ai) { 636a96102c8SMichael Baum volatile struct mlx5_mini_cqe8 (*mc)[8] = 637a96102c8SMichael Baum (volatile struct mlx5_mini_cqe8 (*)[8]) 638a96102c8SMichael Baum (uintptr_t)(&(*rxq->cqes)[zip->ca & 63902a6195cSAlexander Kozyrev cqe_mask].pkt_info); 640a96102c8SMichael Baum len = rte_be_to_cpu_32((*mc)[zip->ai & 7].byte_cnt & 641a96102c8SMichael Baum rxq->byte_mask); 642a96102c8SMichael Baum *mcqe = &(*mc)[zip->ai & 7]; 64302a6195cSAlexander Kozyrev if (rxq->cqe_comp_layout) { 64402a6195cSAlexander Kozyrev zip->ai++; 64502a6195cSAlexander Kozyrev if (unlikely(rxq->zip.ai == rxq->zip.cqe_cnt)) { 64602a6195cSAlexander Kozyrev rxq->cq_ci = zip->cq_ci; 64702a6195cSAlexander Kozyrev zip->ai = 0; 64802a6195cSAlexander Kozyrev } 64902a6195cSAlexander Kozyrev } else { 650a96102c8SMichael Baum if ((++zip->ai & 7) == 0) { 651a96102c8SMichael Baum /* Invalidate consumed CQEs */ 652a96102c8SMichael Baum idx = zip->ca; 653a96102c8SMichael Baum end = zip->na; 654a96102c8SMichael Baum while (idx != end) { 65502a6195cSAlexander Kozyrev (*rxq->cqes)[idx & cqe_mask].op_own = 656a96102c8SMichael Baum MLX5_CQE_INVALIDATE; 657a96102c8SMichael Baum ++idx; 658a96102c8SMichael Baum } 659a96102c8SMichael Baum /* 660a96102c8SMichael Baum * Increment consumer index to skip the number 661a96102c8SMichael Baum * of CQEs consumed. Hardware leaves holes in 662a96102c8SMichael Baum * the CQ ring for software use. 663a96102c8SMichael Baum */ 664a96102c8SMichael Baum zip->ca = zip->na; 665a96102c8SMichael Baum zip->na += 8; 666a96102c8SMichael Baum } 667a96102c8SMichael Baum if (unlikely(rxq->zip.ai == rxq->zip.cqe_cnt)) { 668a96102c8SMichael Baum /* Invalidate the rest */ 669a96102c8SMichael Baum idx = zip->ca; 670a96102c8SMichael Baum end = zip->cq_ci; 671a96102c8SMichael Baum 672a96102c8SMichael Baum while (idx != end) { 67302a6195cSAlexander Kozyrev (*rxq->cqes)[idx & cqe_mask].op_own = 674a96102c8SMichael Baum MLX5_CQE_INVALIDATE; 675a96102c8SMichael Baum ++idx; 676a96102c8SMichael Baum } 677a96102c8SMichael Baum rxq->cq_ci = zip->cq_ci; 678a96102c8SMichael Baum zip->ai = 0; 679a96102c8SMichael Baum } 68002a6195cSAlexander Kozyrev } 681a96102c8SMichael Baum /* 682a96102c8SMichael Baum * No compressed data, get next CQE and verify if it is 683a96102c8SMichael Baum * compressed. 684a96102c8SMichael Baum */ 685a96102c8SMichael Baum } else { 686a96102c8SMichael Baum int8_t op_own; 687a96102c8SMichael Baum uint32_t cq_ci; 688a96102c8SMichael Baum 68902a6195cSAlexander Kozyrev ret = (rxq->cqe_comp_layout) ? 69002a6195cSAlexander Kozyrev check_cqe_iteration(cqe, rxq->cqe_n, rxq->cq_ci) : 69102a6195cSAlexander Kozyrev check_cqe(cqe, cqe_n, rxq->cq_ci); 692a96102c8SMichael Baum if (unlikely(ret != MLX5_CQE_STATUS_SW_OWN)) { 693a96102c8SMichael Baum if (unlikely(ret == MLX5_CQE_STATUS_ERR || 694a96102c8SMichael Baum rxq->err_state)) { 695aa67ed30SAlexander Kozyrev ret = mlx5_rx_err_handle(rxq, 0, 1, skip_cnt); 696aa67ed30SAlexander Kozyrev if (ret == MLX5_CQE_STATUS_HW_OWN) 697aa67ed30SAlexander Kozyrev return MLX5_ERROR_CQE_MASK; 698aa67ed30SAlexander Kozyrev if (ret == MLX5_RECOVERY_ERROR_RET || 699aa67ed30SAlexander Kozyrev ret == MLX5_RECOVERY_COMPLETED_RET) 700aa67ed30SAlexander Kozyrev return MLX5_CRITICAL_ERROR_CQE_RET; 701ef296e8fSViacheslav Ovsiienko if (!mprq && ret == MLX5_RECOVERY_IGNORE_RET) { 702ef296e8fSViacheslav Ovsiienko *skip_cnt = 1; 703ef296e8fSViacheslav Ovsiienko ++rxq->cq_ci; 704ef296e8fSViacheslav Ovsiienko return MLX5_ERROR_CQE_MASK; 705ef296e8fSViacheslav Ovsiienko } 706a96102c8SMichael Baum } else { 707a96102c8SMichael Baum return 0; 708a96102c8SMichael Baum } 709a96102c8SMichael Baum } 710a96102c8SMichael Baum /* 711a96102c8SMichael Baum * Introduce the local variable to have queue cq_ci 712a96102c8SMichael Baum * index in queue structure always consistent with 713a96102c8SMichael Baum * actual CQE boundary (not pointing to the middle 714a96102c8SMichael Baum * of compressed CQE session). 715a96102c8SMichael Baum */ 71602a6195cSAlexander Kozyrev cq_ci = rxq->cq_ci + !rxq->cqe_comp_layout; 717a96102c8SMichael Baum op_own = cqe->op_own; 718a96102c8SMichael Baum if (MLX5_CQE_FORMAT(op_own) == MLX5_COMPRESSED) { 719a96102c8SMichael Baum volatile struct mlx5_mini_cqe8 (*mc)[8] = 720a96102c8SMichael Baum (volatile struct mlx5_mini_cqe8 (*)[8]) 721a96102c8SMichael Baum (uintptr_t)(&(*rxq->cqes) 72202a6195cSAlexander Kozyrev [cq_ci & cqe_mask].pkt_info); 723a96102c8SMichael Baum 724a96102c8SMichael Baum /* Fix endianness. */ 72502a6195cSAlexander Kozyrev zip->cqe_cnt = rxq->cqe_comp_layout ? 72602a6195cSAlexander Kozyrev (MLX5_CQE_NUM_MINIS(op_own) + 1U) : 72702a6195cSAlexander Kozyrev rte_be_to_cpu_32(cqe->byte_cnt); 728a96102c8SMichael Baum /* 729a96102c8SMichael Baum * Current mini array position is the one 730a96102c8SMichael Baum * returned by check_cqe64(). 731a96102c8SMichael Baum * 732a96102c8SMichael Baum * If completion comprises several mini arrays, 733a96102c8SMichael Baum * as a special case the second one is located 734a96102c8SMichael Baum * 7 CQEs after the initial CQE instead of 8 735a96102c8SMichael Baum * for subsequent ones. 736a96102c8SMichael Baum */ 737a96102c8SMichael Baum zip->ca = cq_ci; 738a96102c8SMichael Baum zip->na = zip->ca + 7; 739a96102c8SMichael Baum /* Compute the next non compressed CQE. */ 740a96102c8SMichael Baum zip->cq_ci = rxq->cq_ci + zip->cqe_cnt; 741a96102c8SMichael Baum /* Get packet size to return. */ 742a96102c8SMichael Baum len = rte_be_to_cpu_32((*mc)[0].byte_cnt & 743a96102c8SMichael Baum rxq->byte_mask); 744a96102c8SMichael Baum *mcqe = &(*mc)[0]; 74502a6195cSAlexander Kozyrev if (rxq->cqe_comp_layout) { 74602a6195cSAlexander Kozyrev if (MLX5_CQE_NUM_MINIS(op_own)) 74702a6195cSAlexander Kozyrev zip->ai = 1; 74802a6195cSAlexander Kozyrev else 74902a6195cSAlexander Kozyrev rxq->cq_ci = zip->cq_ci; 75002a6195cSAlexander Kozyrev } else { 751a96102c8SMichael Baum zip->ai = 1; 752a96102c8SMichael Baum /* Prefetch all to be invalidated */ 753a96102c8SMichael Baum idx = zip->ca; 754a96102c8SMichael Baum end = zip->cq_ci; 755a96102c8SMichael Baum while (idx != end) { 75602a6195cSAlexander Kozyrev rte_prefetch0(&(*rxq->cqes)[(idx) & cqe_mask]); 757a96102c8SMichael Baum ++idx; 758a96102c8SMichael Baum } 75902a6195cSAlexander Kozyrev } 760a96102c8SMichael Baum } else { 76102a6195cSAlexander Kozyrev ++rxq->cq_ci; 762a96102c8SMichael Baum len = rte_be_to_cpu_32(cqe->byte_cnt); 76302a6195cSAlexander Kozyrev if (rxq->cqe_comp_layout) { 76402a6195cSAlexander Kozyrev volatile struct mlx5_cqe *next; 76502a6195cSAlexander Kozyrev 76602a6195cSAlexander Kozyrev next = &(*rxq->cqes)[rxq->cq_ci & cqe_mask]; 76702a6195cSAlexander Kozyrev ret = check_cqe_iteration(next, rxq->cqe_n, rxq->cq_ci); 76802a6195cSAlexander Kozyrev if (ret != MLX5_CQE_STATUS_SW_OWN || 76902a6195cSAlexander Kozyrev MLX5_CQE_FORMAT(next->op_own) == MLX5_COMPRESSED) 77002a6195cSAlexander Kozyrev rte_memcpy(&rxq->title_cqe, 77102a6195cSAlexander Kozyrev (const void *)(uintptr_t)cqe, 77202a6195cSAlexander Kozyrev sizeof(struct mlx5_cqe)); 77302a6195cSAlexander Kozyrev } 774a96102c8SMichael Baum } 775a96102c8SMichael Baum } 776a96102c8SMichael Baum if (unlikely(rxq->err_state)) { 777aa67ed30SAlexander Kozyrev if (rxq->err_state == MLX5_RXQ_ERR_STATE_IGNORE && 778aa67ed30SAlexander Kozyrev ret == MLX5_CQE_STATUS_SW_OWN) { 779aa67ed30SAlexander Kozyrev rxq->err_state = MLX5_RXQ_ERR_STATE_NO_ERROR; 780aa67ed30SAlexander Kozyrev return len & MLX5_ERROR_CQE_MASK; 781aa67ed30SAlexander Kozyrev } 78202a6195cSAlexander Kozyrev cqe = &(*rxq->cqes)[rxq->cq_ci & cqe_mask]; 783a96102c8SMichael Baum ++rxq->stats.idropped; 784aa67ed30SAlexander Kozyrev (*skip_cnt) += mprq ? (len & MLX5_MPRQ_STRIDE_NUM_MASK) >> 785aa67ed30SAlexander Kozyrev MLX5_MPRQ_STRIDE_NUM_SHIFT : 1; 786a96102c8SMichael Baum } else { 787a96102c8SMichael Baum return len; 788a96102c8SMichael Baum } 789a96102c8SMichael Baum } while (1); 790a96102c8SMichael Baum } 791a96102c8SMichael Baum 792a96102c8SMichael Baum /** 793a96102c8SMichael Baum * Translate RX completion flags to offload flags. 794a96102c8SMichael Baum * 795a96102c8SMichael Baum * @param[in] cqe 796a96102c8SMichael Baum * Pointer to CQE. 797a96102c8SMichael Baum * 798a96102c8SMichael Baum * @return 799a96102c8SMichael Baum * Offload flags (ol_flags) for struct rte_mbuf. 800a96102c8SMichael Baum */ 801a96102c8SMichael Baum static inline uint32_t 802a96102c8SMichael Baum rxq_cq_to_ol_flags(volatile struct mlx5_cqe *cqe) 803a96102c8SMichael Baum { 804a96102c8SMichael Baum uint32_t ol_flags = 0; 805a96102c8SMichael Baum uint16_t flags = rte_be_to_cpu_16(cqe->hdr_type_etc); 806a96102c8SMichael Baum 807a96102c8SMichael Baum ol_flags = 808a96102c8SMichael Baum TRANSPOSE(flags, 809a96102c8SMichael Baum MLX5_CQE_RX_L3_HDR_VALID, 810daa02b5cSOlivier Matz RTE_MBUF_F_RX_IP_CKSUM_GOOD) | 811a96102c8SMichael Baum TRANSPOSE(flags, 812a96102c8SMichael Baum MLX5_CQE_RX_L4_HDR_VALID, 813daa02b5cSOlivier Matz RTE_MBUF_F_RX_L4_CKSUM_GOOD); 814a96102c8SMichael Baum return ol_flags; 815a96102c8SMichael Baum } 816a96102c8SMichael Baum 817a96102c8SMichael Baum /** 818a96102c8SMichael Baum * Fill in mbuf fields from RX completion flags. 819a96102c8SMichael Baum * Note that pkt->ol_flags should be initialized outside of this function. 820a96102c8SMichael Baum * 821a96102c8SMichael Baum * @param rxq 822a96102c8SMichael Baum * Pointer to RX queue. 823a96102c8SMichael Baum * @param pkt 824a96102c8SMichael Baum * mbuf to fill. 825a96102c8SMichael Baum * @param cqe 826a96102c8SMichael Baum * CQE to process. 827a96102c8SMichael Baum * @param rss_hash_res 828a96102c8SMichael Baum * Packet RSS Hash result. 829a96102c8SMichael Baum */ 830a96102c8SMichael Baum static inline void 831a96102c8SMichael Baum rxq_cq_to_mbuf(struct mlx5_rxq_data *rxq, struct rte_mbuf *pkt, 832a96102c8SMichael Baum volatile struct mlx5_cqe *cqe, 833a96102c8SMichael Baum volatile struct mlx5_mini_cqe8 *mcqe) 834a96102c8SMichael Baum { 835a96102c8SMichael Baum /* Update packet information. */ 836a96102c8SMichael Baum pkt->packet_type = rxq_cq_to_pkt_type(rxq, cqe, mcqe); 83725ed2ebfSViacheslav Ovsiienko pkt->port = unlikely(rxq->shared) ? cqe->user_index_low : rxq->port_id; 838a96102c8SMichael Baum 839a96102c8SMichael Baum if (rxq->rss_hash) { 840a96102c8SMichael Baum uint32_t rss_hash_res = 0; 841a96102c8SMichael Baum 842a96102c8SMichael Baum /* If compressed, take hash result from mini-CQE. */ 843a96102c8SMichael Baum if (mcqe == NULL || 844a96102c8SMichael Baum rxq->mcqe_format != MLX5_CQE_RESP_FORMAT_HASH) 845a96102c8SMichael Baum rss_hash_res = rte_be_to_cpu_32(cqe->rx_hash_res); 846a96102c8SMichael Baum else 847a96102c8SMichael Baum rss_hash_res = rte_be_to_cpu_32(mcqe->rx_hash_result); 848a96102c8SMichael Baum if (rss_hash_res) { 849a96102c8SMichael Baum pkt->hash.rss = rss_hash_res; 850daa02b5cSOlivier Matz pkt->ol_flags |= RTE_MBUF_F_RX_RSS_HASH; 851a96102c8SMichael Baum } 852a96102c8SMichael Baum } 853a96102c8SMichael Baum if (rxq->mark) { 854a96102c8SMichael Baum uint32_t mark = 0; 855a96102c8SMichael Baum 856a96102c8SMichael Baum /* If compressed, take flow tag from mini-CQE. */ 857a96102c8SMichael Baum if (mcqe == NULL || 858a96102c8SMichael Baum rxq->mcqe_format != MLX5_CQE_RESP_FORMAT_FTAG_STRIDX) 859a96102c8SMichael Baum mark = cqe->sop_drop_qpn; 860a96102c8SMichael Baum else 861a96102c8SMichael Baum mark = ((mcqe->byte_cnt_flow & 0xff) << 8) | 862a96102c8SMichael Baum (mcqe->flow_tag_high << 16); 863a96102c8SMichael Baum if (MLX5_FLOW_MARK_IS_VALID(mark)) { 864daa02b5cSOlivier Matz pkt->ol_flags |= RTE_MBUF_F_RX_FDIR; 865a96102c8SMichael Baum if (mark != RTE_BE32(MLX5_FLOW_MARK_DEFAULT)) { 866fca8cba4SDavid Marchand pkt->ol_flags |= rxq->mark_flag; 867a96102c8SMichael Baum pkt->hash.fdir.hi = mlx5_flow_mark_get(mark); 868a96102c8SMichael Baum } 869a96102c8SMichael Baum } 870a96102c8SMichael Baum } 871a96102c8SMichael Baum if (rxq->dynf_meta) { 8726d5735c1SAlexander Kozyrev uint32_t meta = rte_be_to_cpu_32(cqe->flow_table_metadata) & 873a96102c8SMichael Baum rxq->flow_meta_port_mask; 874a96102c8SMichael Baum 875a96102c8SMichael Baum if (meta) { 876a96102c8SMichael Baum pkt->ol_flags |= rxq->flow_meta_mask; 877a96102c8SMichael Baum *RTE_MBUF_DYNFIELD(pkt, rxq->flow_meta_offset, 878a96102c8SMichael Baum uint32_t *) = meta; 879a96102c8SMichael Baum } 880a96102c8SMichael Baum } 881a96102c8SMichael Baum if (rxq->csum) 882a96102c8SMichael Baum pkt->ol_flags |= rxq_cq_to_ol_flags(cqe); 883a96102c8SMichael Baum if (rxq->vlan_strip) { 884a96102c8SMichael Baum bool vlan_strip; 885a96102c8SMichael Baum 886a96102c8SMichael Baum if (mcqe == NULL || 887a96102c8SMichael Baum rxq->mcqe_format != MLX5_CQE_RESP_FORMAT_L34H_STRIDX) 888a96102c8SMichael Baum vlan_strip = cqe->hdr_type_etc & 889a96102c8SMichael Baum RTE_BE16(MLX5_CQE_VLAN_STRIPPED); 890a96102c8SMichael Baum else 891a96102c8SMichael Baum vlan_strip = mcqe->hdr_type & 892a96102c8SMichael Baum RTE_BE16(MLX5_CQE_VLAN_STRIPPED); 893a96102c8SMichael Baum if (vlan_strip) { 894daa02b5cSOlivier Matz pkt->ol_flags |= RTE_MBUF_F_RX_VLAN | RTE_MBUF_F_RX_VLAN_STRIPPED; 895a96102c8SMichael Baum pkt->vlan_tci = rte_be_to_cpu_16(cqe->vlan_info); 896a96102c8SMichael Baum } 897a96102c8SMichael Baum } 898a96102c8SMichael Baum if (rxq->hw_timestamp) { 899a96102c8SMichael Baum uint64_t ts = rte_be_to_cpu_64(cqe->timestamp); 900a96102c8SMichael Baum 901a96102c8SMichael Baum if (rxq->rt_timestamp) 902a96102c8SMichael Baum ts = mlx5_txpp_convert_rx_ts(rxq->sh, ts); 903a96102c8SMichael Baum mlx5_timestamp_set(pkt, rxq->timestamp_offset, ts); 904a96102c8SMichael Baum pkt->ol_flags |= rxq->timestamp_rx_flag; 905a96102c8SMichael Baum } 906a96102c8SMichael Baum } 907a96102c8SMichael Baum 908a96102c8SMichael Baum /** 909a96102c8SMichael Baum * DPDK callback for RX. 910a96102c8SMichael Baum * 911a96102c8SMichael Baum * @param dpdk_rxq 912a96102c8SMichael Baum * Generic pointer to RX queue structure. 913a96102c8SMichael Baum * @param[out] pkts 914a96102c8SMichael Baum * Array to store received packets. 915a96102c8SMichael Baum * @param pkts_n 916a96102c8SMichael Baum * Maximum number of packets in array. 917a96102c8SMichael Baum * 918a96102c8SMichael Baum * @return 919a96102c8SMichael Baum * Number of packets successfully received (<= pkts_n). 920a96102c8SMichael Baum */ 921a96102c8SMichael Baum uint16_t 922a96102c8SMichael Baum mlx5_rx_burst(void *dpdk_rxq, struct rte_mbuf **pkts, uint16_t pkts_n) 923a96102c8SMichael Baum { 924a96102c8SMichael Baum struct mlx5_rxq_data *rxq = dpdk_rxq; 92502a6195cSAlexander Kozyrev const uint32_t wqe_n = 1 << rxq->elts_n; 92602a6195cSAlexander Kozyrev const uint32_t wqe_mask = wqe_n - 1; 92702a6195cSAlexander Kozyrev const uint32_t cqe_n = 1 << rxq->cqe_n; 92802a6195cSAlexander Kozyrev const uint32_t cqe_mask = cqe_n - 1; 929a96102c8SMichael Baum const unsigned int sges_n = rxq->sges_n; 930a96102c8SMichael Baum struct rte_mbuf *pkt = NULL; 931a96102c8SMichael Baum struct rte_mbuf *seg = NULL; 932a96102c8SMichael Baum volatile struct mlx5_cqe *cqe = 93302a6195cSAlexander Kozyrev &(*rxq->cqes)[rxq->cq_ci & cqe_mask]; 934a96102c8SMichael Baum unsigned int i = 0; 935a96102c8SMichael Baum unsigned int rq_ci = rxq->rq_ci << sges_n; 936a96102c8SMichael Baum int len = 0; /* keep its value across iterations. */ 937a96102c8SMichael Baum 938a96102c8SMichael Baum while (pkts_n) { 939aa67ed30SAlexander Kozyrev uint16_t skip_cnt; 94002a6195cSAlexander Kozyrev unsigned int idx = rq_ci & wqe_mask; 941a96102c8SMichael Baum volatile struct mlx5_wqe_data_seg *wqe = 942a96102c8SMichael Baum &((volatile struct mlx5_wqe_data_seg *)rxq->wqes)[idx]; 943a96102c8SMichael Baum struct rte_mbuf *rep = (*rxq->elts)[idx]; 944a96102c8SMichael Baum volatile struct mlx5_mini_cqe8 *mcqe = NULL; 945a96102c8SMichael Baum 946a96102c8SMichael Baum if (pkt) 947a96102c8SMichael Baum NEXT(seg) = rep; 948a96102c8SMichael Baum seg = rep; 949a96102c8SMichael Baum rte_prefetch0(seg); 950a96102c8SMichael Baum rte_prefetch0(cqe); 951a96102c8SMichael Baum rte_prefetch0(wqe); 952a96102c8SMichael Baum /* Allocate the buf from the same pool. */ 953a96102c8SMichael Baum rep = rte_mbuf_raw_alloc(seg->pool); 954a96102c8SMichael Baum if (unlikely(rep == NULL)) { 955a96102c8SMichael Baum ++rxq->stats.rx_nombuf; 956a96102c8SMichael Baum if (!pkt) { 957a96102c8SMichael Baum /* 958a96102c8SMichael Baum * no buffers before we even started, 959a96102c8SMichael Baum * bail out silently. 960a96102c8SMichael Baum */ 961a96102c8SMichael Baum break; 962a96102c8SMichael Baum } 963a96102c8SMichael Baum while (pkt != seg) { 964a96102c8SMichael Baum MLX5_ASSERT(pkt != (*rxq->elts)[idx]); 965a96102c8SMichael Baum rep = NEXT(pkt); 966a96102c8SMichael Baum NEXT(pkt) = NULL; 967a96102c8SMichael Baum NB_SEGS(pkt) = 1; 968a96102c8SMichael Baum rte_mbuf_raw_free(pkt); 969a96102c8SMichael Baum pkt = rep; 970a96102c8SMichael Baum } 971a96102c8SMichael Baum rq_ci >>= sges_n; 972a96102c8SMichael Baum ++rq_ci; 973a96102c8SMichael Baum rq_ci <<= sges_n; 974a96102c8SMichael Baum break; 975a96102c8SMichael Baum } 976a96102c8SMichael Baum if (!pkt) { 97702a6195cSAlexander Kozyrev cqe = &(*rxq->cqes)[rxq->cq_ci & cqe_mask]; 97802a6195cSAlexander Kozyrev len = mlx5_rx_poll_len(rxq, cqe, cqe_n, cqe_mask, &mcqe, &skip_cnt, false); 979aa67ed30SAlexander Kozyrev if (unlikely(len & MLX5_ERROR_CQE_MASK)) { 980ef296e8fSViacheslav Ovsiienko /* We drop packets with non-critical errors */ 981a96102c8SMichael Baum rte_mbuf_raw_free(rep); 982ef296e8fSViacheslav Ovsiienko if (len == MLX5_CRITICAL_ERROR_CQE_RET) { 98360b254e3SMatan Azrad rq_ci = rxq->rq_ci << sges_n; 984a96102c8SMichael Baum break; 985a96102c8SMichael Baum } 986ef296e8fSViacheslav Ovsiienko /* Skip specified amount of error CQEs packets */ 987aa67ed30SAlexander Kozyrev rq_ci >>= sges_n; 988aa67ed30SAlexander Kozyrev rq_ci += skip_cnt; 989aa67ed30SAlexander Kozyrev rq_ci <<= sges_n; 990ef296e8fSViacheslav Ovsiienko MLX5_ASSERT(!pkt); 991ef296e8fSViacheslav Ovsiienko continue; 992aa67ed30SAlexander Kozyrev } 993aa67ed30SAlexander Kozyrev if (len == 0) { 994aa67ed30SAlexander Kozyrev rte_mbuf_raw_free(rep); 995aa67ed30SAlexander Kozyrev break; 996aa67ed30SAlexander Kozyrev } 997a96102c8SMichael Baum pkt = seg; 998a96102c8SMichael Baum MLX5_ASSERT(len >= (rxq->crc_present << 2)); 999daa02b5cSOlivier Matz pkt->ol_flags &= RTE_MBUF_F_EXTERNAL; 100002a6195cSAlexander Kozyrev if (rxq->cqe_comp_layout && mcqe) 100102a6195cSAlexander Kozyrev cqe = &rxq->title_cqe; 1002a96102c8SMichael Baum rxq_cq_to_mbuf(rxq, pkt, cqe, mcqe); 1003a96102c8SMichael Baum if (rxq->crc_present) 1004a96102c8SMichael Baum len -= RTE_ETHER_CRC_LEN; 1005a96102c8SMichael Baum PKT_LEN(pkt) = len; 1006a96102c8SMichael Baum if (cqe->lro_num_seg > 1) { 1007a96102c8SMichael Baum mlx5_lro_update_hdr 1008a96102c8SMichael Baum (rte_pktmbuf_mtod(pkt, uint8_t *), cqe, 1009a96102c8SMichael Baum mcqe, rxq, len); 1010daa02b5cSOlivier Matz pkt->ol_flags |= RTE_MBUF_F_RX_LRO; 1011a96102c8SMichael Baum pkt->tso_segsz = len / cqe->lro_num_seg; 1012a96102c8SMichael Baum } 1013a96102c8SMichael Baum } 1014a96102c8SMichael Baum DATA_LEN(rep) = DATA_LEN(seg); 1015a96102c8SMichael Baum PKT_LEN(rep) = PKT_LEN(seg); 1016a96102c8SMichael Baum SET_DATA_OFF(rep, DATA_OFF(seg)); 1017a96102c8SMichael Baum PORT(rep) = PORT(seg); 1018a96102c8SMichael Baum (*rxq->elts)[idx] = rep; 1019a96102c8SMichael Baum /* 1020a96102c8SMichael Baum * Fill NIC descriptor with the new buffer. The lkey and size 1021a96102c8SMichael Baum * of the buffers are already known, only the buffer address 1022a96102c8SMichael Baum * changes. 1023a96102c8SMichael Baum */ 1024a96102c8SMichael Baum wqe->addr = rte_cpu_to_be_64(rte_pktmbuf_mtod(rep, uintptr_t)); 1025a96102c8SMichael Baum /* If there's only one MR, no need to replace LKey in WQE. */ 1026a96102c8SMichael Baum if (unlikely(mlx5_mr_btree_len(&rxq->mr_ctrl.cache_bh) > 1)) 1027a96102c8SMichael Baum wqe->lkey = mlx5_rx_mb2mr(rxq, rep); 1028a96102c8SMichael Baum if (len > DATA_LEN(seg)) { 1029a96102c8SMichael Baum len -= DATA_LEN(seg); 1030a96102c8SMichael Baum ++NB_SEGS(pkt); 1031a96102c8SMichael Baum ++rq_ci; 1032a96102c8SMichael Baum continue; 1033a96102c8SMichael Baum } 1034a96102c8SMichael Baum DATA_LEN(seg) = len; 1035a96102c8SMichael Baum #ifdef MLX5_PMD_SOFT_COUNTERS 1036a96102c8SMichael Baum /* Increment bytes counter. */ 1037a96102c8SMichael Baum rxq->stats.ibytes += PKT_LEN(pkt); 1038a96102c8SMichael Baum #endif 1039a96102c8SMichael Baum /* Return packet. */ 1040a96102c8SMichael Baum *(pkts++) = pkt; 1041a96102c8SMichael Baum pkt = NULL; 1042a96102c8SMichael Baum --pkts_n; 1043a96102c8SMichael Baum ++i; 1044a96102c8SMichael Baum /* Align consumer index to the next stride. */ 1045a96102c8SMichael Baum rq_ci >>= sges_n; 1046a96102c8SMichael Baum ++rq_ci; 1047a96102c8SMichael Baum rq_ci <<= sges_n; 1048a96102c8SMichael Baum } 1049a96102c8SMichael Baum if (unlikely(i == 0 && ((rq_ci >> sges_n) == rxq->rq_ci))) 1050a96102c8SMichael Baum return 0; 1051a96102c8SMichael Baum /* Update the consumer index. */ 1052a96102c8SMichael Baum rxq->rq_ci = rq_ci >> sges_n; 1053a96102c8SMichael Baum rte_io_wmb(); 1054a96102c8SMichael Baum *rxq->cq_db = rte_cpu_to_be_32(rxq->cq_ci); 1055a96102c8SMichael Baum rte_io_wmb(); 1056a96102c8SMichael Baum *rxq->rq_db = rte_cpu_to_be_32(rxq->rq_ci); 1057a96102c8SMichael Baum #ifdef MLX5_PMD_SOFT_COUNTERS 1058a96102c8SMichael Baum /* Increment packets counter. */ 1059a96102c8SMichael Baum rxq->stats.ipackets += i; 1060a96102c8SMichael Baum #endif 1061a96102c8SMichael Baum return i; 1062a96102c8SMichael Baum } 1063a96102c8SMichael Baum 1064a96102c8SMichael Baum /** 1065a96102c8SMichael Baum * Update LRO packet TCP header. 1066a96102c8SMichael Baum * The HW LRO feature doesn't update the TCP header after coalescing the 1067a96102c8SMichael Baum * TCP segments but supplies information in CQE to fill it by SW. 1068a96102c8SMichael Baum * 1069a96102c8SMichael Baum * @param tcp 1070a96102c8SMichael Baum * Pointer to the TCP header. 1071a96102c8SMichael Baum * @param cqe 1072a96102c8SMichael Baum * Pointer to the completion entry. 1073a96102c8SMichael Baum * @param phcsum 1074a96102c8SMichael Baum * The L3 pseudo-header checksum. 1075a96102c8SMichael Baum */ 1076a96102c8SMichael Baum static inline void 1077a96102c8SMichael Baum mlx5_lro_update_tcp_hdr(struct rte_tcp_hdr *__rte_restrict tcp, 1078a96102c8SMichael Baum volatile struct mlx5_cqe *__rte_restrict cqe, 1079a96102c8SMichael Baum uint32_t phcsum, uint8_t l4_type) 1080a96102c8SMichael Baum { 1081a96102c8SMichael Baum /* 1082a96102c8SMichael Baum * The HW calculates only the TCP payload checksum, need to complete 1083a96102c8SMichael Baum * the TCP header checksum and the L3 pseudo-header checksum. 1084a96102c8SMichael Baum */ 1085a96102c8SMichael Baum uint32_t csum = phcsum + cqe->csum; 1086a96102c8SMichael Baum 1087a96102c8SMichael Baum if (l4_type == MLX5_L4_HDR_TYPE_TCP_EMPTY_ACK || 1088a96102c8SMichael Baum l4_type == MLX5_L4_HDR_TYPE_TCP_WITH_ACL) { 1089a96102c8SMichael Baum tcp->tcp_flags |= RTE_TCP_ACK_FLAG; 1090a96102c8SMichael Baum tcp->recv_ack = cqe->lro_ack_seq_num; 1091a96102c8SMichael Baum tcp->rx_win = cqe->lro_tcp_win; 1092a96102c8SMichael Baum } 1093a96102c8SMichael Baum if (cqe->lro_tcppsh_abort_dupack & MLX5_CQE_LRO_PUSH_MASK) 1094a96102c8SMichael Baum tcp->tcp_flags |= RTE_TCP_PSH_FLAG; 1095a96102c8SMichael Baum tcp->cksum = 0; 1096a96102c8SMichael Baum csum += rte_raw_cksum(tcp, (tcp->data_off >> 4) * 4); 1097a96102c8SMichael Baum csum = ((csum & 0xffff0000) >> 16) + (csum & 0xffff); 1098776209c4SHeng Jiang csum = ((csum & 0xffff0000) >> 16) + (csum & 0xffff); 1099a96102c8SMichael Baum csum = (~csum) & 0xffff; 1100a96102c8SMichael Baum if (csum == 0) 1101a96102c8SMichael Baum csum = 0xffff; 1102a96102c8SMichael Baum tcp->cksum = csum; 1103a96102c8SMichael Baum } 1104a96102c8SMichael Baum 1105a96102c8SMichael Baum /** 1106a96102c8SMichael Baum * Update LRO packet headers. 1107a96102c8SMichael Baum * The HW LRO feature doesn't update the L3/TCP headers after coalescing the 1108a96102c8SMichael Baum * TCP segments but supply information in CQE to fill it by SW. 1109a96102c8SMichael Baum * 1110a96102c8SMichael Baum * @param padd 1111a96102c8SMichael Baum * The packet address. 1112a96102c8SMichael Baum * @param cqe 1113a96102c8SMichael Baum * Pointer to the completion entry. 1114a96102c8SMichael Baum * @param len 1115a96102c8SMichael Baum * The packet length. 1116a96102c8SMichael Baum */ 1117a96102c8SMichael Baum static inline void 1118a96102c8SMichael Baum mlx5_lro_update_hdr(uint8_t *__rte_restrict padd, 1119a96102c8SMichael Baum volatile struct mlx5_cqe *__rte_restrict cqe, 1120a96102c8SMichael Baum volatile struct mlx5_mini_cqe8 *mcqe, 1121a96102c8SMichael Baum struct mlx5_rxq_data *rxq, uint32_t len) 1122a96102c8SMichael Baum { 1123a96102c8SMichael Baum union { 1124a96102c8SMichael Baum struct rte_ether_hdr *eth; 1125a96102c8SMichael Baum struct rte_vlan_hdr *vlan; 1126a96102c8SMichael Baum struct rte_ipv4_hdr *ipv4; 1127a96102c8SMichael Baum struct rte_ipv6_hdr *ipv6; 1128a96102c8SMichael Baum struct rte_tcp_hdr *tcp; 1129a96102c8SMichael Baum uint8_t *hdr; 1130a96102c8SMichael Baum } h = { 1131a96102c8SMichael Baum .hdr = padd, 1132a96102c8SMichael Baum }; 1133a96102c8SMichael Baum uint16_t proto = h.eth->ether_type; 1134a96102c8SMichael Baum uint32_t phcsum; 1135a96102c8SMichael Baum uint8_t l4_type; 1136a96102c8SMichael Baum 1137a96102c8SMichael Baum h.eth++; 1138a96102c8SMichael Baum while (proto == RTE_BE16(RTE_ETHER_TYPE_VLAN) || 1139a96102c8SMichael Baum proto == RTE_BE16(RTE_ETHER_TYPE_QINQ)) { 1140a96102c8SMichael Baum proto = h.vlan->eth_proto; 1141a96102c8SMichael Baum h.vlan++; 1142a96102c8SMichael Baum } 1143a96102c8SMichael Baum if (proto == RTE_BE16(RTE_ETHER_TYPE_IPV4)) { 1144a96102c8SMichael Baum h.ipv4->time_to_live = cqe->lro_min_ttl; 1145a96102c8SMichael Baum h.ipv4->total_length = rte_cpu_to_be_16(len - (h.hdr - padd)); 1146a96102c8SMichael Baum h.ipv4->hdr_checksum = 0; 1147a96102c8SMichael Baum h.ipv4->hdr_checksum = rte_ipv4_cksum(h.ipv4); 1148a96102c8SMichael Baum phcsum = rte_ipv4_phdr_cksum(h.ipv4, 0); 1149a96102c8SMichael Baum h.ipv4++; 1150a96102c8SMichael Baum } else { 1151a96102c8SMichael Baum h.ipv6->hop_limits = cqe->lro_min_ttl; 1152a96102c8SMichael Baum h.ipv6->payload_len = rte_cpu_to_be_16(len - (h.hdr - padd) - 1153a96102c8SMichael Baum sizeof(*h.ipv6)); 1154a96102c8SMichael Baum phcsum = rte_ipv6_phdr_cksum(h.ipv6, 0); 1155a96102c8SMichael Baum h.ipv6++; 1156a96102c8SMichael Baum } 1157a96102c8SMichael Baum if (mcqe == NULL || 1158a96102c8SMichael Baum rxq->mcqe_format != MLX5_CQE_RESP_FORMAT_L34H_STRIDX) 1159a96102c8SMichael Baum l4_type = (rte_be_to_cpu_16(cqe->hdr_type_etc) & 1160a96102c8SMichael Baum MLX5_CQE_L4_TYPE_MASK) >> MLX5_CQE_L4_TYPE_SHIFT; 1161a96102c8SMichael Baum else 1162a96102c8SMichael Baum l4_type = (rte_be_to_cpu_16(mcqe->hdr_type) & 1163a96102c8SMichael Baum MLX5_CQE_L4_TYPE_MASK) >> MLX5_CQE_L4_TYPE_SHIFT; 1164a96102c8SMichael Baum mlx5_lro_update_tcp_hdr(h.tcp, cqe, phcsum, l4_type); 1165a96102c8SMichael Baum } 1166a96102c8SMichael Baum 1167a96102c8SMichael Baum void 1168a96102c8SMichael Baum mlx5_mprq_buf_free(struct mlx5_mprq_buf *buf) 1169a96102c8SMichael Baum { 1170a96102c8SMichael Baum mlx5_mprq_buf_free_cb(NULL, buf); 1171a96102c8SMichael Baum } 1172a96102c8SMichael Baum 1173a96102c8SMichael Baum /** 1174a96102c8SMichael Baum * DPDK callback for RX with Multi-Packet RQ support. 1175a96102c8SMichael Baum * 1176a96102c8SMichael Baum * @param dpdk_rxq 1177a96102c8SMichael Baum * Generic pointer to RX queue structure. 1178a96102c8SMichael Baum * @param[out] pkts 1179a96102c8SMichael Baum * Array to store received packets. 1180a96102c8SMichael Baum * @param pkts_n 1181a96102c8SMichael Baum * Maximum number of packets in array. 1182a96102c8SMichael Baum * 1183a96102c8SMichael Baum * @return 1184a96102c8SMichael Baum * Number of packets successfully received (<= pkts_n). 1185a96102c8SMichael Baum */ 1186a96102c8SMichael Baum uint16_t 1187a96102c8SMichael Baum mlx5_rx_burst_mprq(void *dpdk_rxq, struct rte_mbuf **pkts, uint16_t pkts_n) 1188a96102c8SMichael Baum { 1189a96102c8SMichael Baum struct mlx5_rxq_data *rxq = dpdk_rxq; 11900947ed38SMichael Baum const uint32_t strd_n = RTE_BIT32(rxq->log_strd_num); 11910947ed38SMichael Baum const uint32_t strd_sz = RTE_BIT32(rxq->log_strd_sz); 119202a6195cSAlexander Kozyrev const uint32_t cqe_n = 1 << rxq->cqe_n; 119302a6195cSAlexander Kozyrev const uint32_t cq_mask = cqe_n - 1; 119402a6195cSAlexander Kozyrev const uint32_t wqe_n = 1 << rxq->elts_n; 119502a6195cSAlexander Kozyrev const uint32_t wq_mask = wqe_n - 1; 1196a96102c8SMichael Baum volatile struct mlx5_cqe *cqe = &(*rxq->cqes)[rxq->cq_ci & cq_mask]; 1197a96102c8SMichael Baum unsigned int i = 0; 1198a96102c8SMichael Baum uint32_t rq_ci = rxq->rq_ci; 1199a96102c8SMichael Baum uint16_t consumed_strd = rxq->consumed_strd; 1200a96102c8SMichael Baum struct mlx5_mprq_buf *buf = (*rxq->mprq_bufs)[rq_ci & wq_mask]; 1201a96102c8SMichael Baum 1202a96102c8SMichael Baum while (i < pkts_n) { 1203a96102c8SMichael Baum struct rte_mbuf *pkt; 1204a96102c8SMichael Baum int ret; 1205a96102c8SMichael Baum uint32_t len; 1206a96102c8SMichael Baum uint16_t strd_cnt; 1207a96102c8SMichael Baum uint16_t strd_idx; 1208a96102c8SMichael Baum uint32_t byte_cnt; 1209aa67ed30SAlexander Kozyrev uint16_t skip_cnt; 1210a96102c8SMichael Baum volatile struct mlx5_mini_cqe8 *mcqe = NULL; 1211a96102c8SMichael Baum enum mlx5_rqx_code rxq_code; 1212a96102c8SMichael Baum 1213a96102c8SMichael Baum if (consumed_strd == strd_n) { 1214a96102c8SMichael Baum /* Replace WQE if the buffer is still in use. */ 1215a96102c8SMichael Baum mprq_buf_replace(rxq, rq_ci & wq_mask); 1216a96102c8SMichael Baum /* Advance to the next WQE. */ 1217a96102c8SMichael Baum consumed_strd = 0; 1218a96102c8SMichael Baum ++rq_ci; 1219a96102c8SMichael Baum buf = (*rxq->mprq_bufs)[rq_ci & wq_mask]; 1220a96102c8SMichael Baum } 1221a96102c8SMichael Baum cqe = &(*rxq->cqes)[rxq->cq_ci & cq_mask]; 122202a6195cSAlexander Kozyrev ret = mlx5_rx_poll_len(rxq, cqe, cqe_n, cq_mask, &mcqe, &skip_cnt, true); 1223aa67ed30SAlexander Kozyrev if (unlikely(ret & MLX5_ERROR_CQE_MASK)) { 1224aa67ed30SAlexander Kozyrev if (ret == MLX5_CRITICAL_ERROR_CQE_RET) { 122560b254e3SMatan Azrad rq_ci = rxq->rq_ci; 122660b254e3SMatan Azrad consumed_strd = rxq->consumed_strd; 122760b254e3SMatan Azrad break; 122860b254e3SMatan Azrad } 1229aa67ed30SAlexander Kozyrev consumed_strd += skip_cnt; 1230aa67ed30SAlexander Kozyrev while (consumed_strd >= strd_n) { 1231aa67ed30SAlexander Kozyrev /* Replace WQE if the buffer is still in use. */ 1232aa67ed30SAlexander Kozyrev mprq_buf_replace(rxq, rq_ci & wq_mask); 1233aa67ed30SAlexander Kozyrev /* Advance to the next WQE. */ 1234aa67ed30SAlexander Kozyrev consumed_strd -= strd_n; 1235aa67ed30SAlexander Kozyrev ++rq_ci; 1236aa67ed30SAlexander Kozyrev buf = (*rxq->mprq_bufs)[rq_ci & wq_mask]; 1237aa67ed30SAlexander Kozyrev } 1238aa67ed30SAlexander Kozyrev cqe = &(*rxq->cqes)[rxq->cq_ci & cq_mask]; 1239aa67ed30SAlexander Kozyrev } 1240aa67ed30SAlexander Kozyrev if (ret == 0) 1241aa67ed30SAlexander Kozyrev break; 1242a96102c8SMichael Baum byte_cnt = ret; 1243a96102c8SMichael Baum len = (byte_cnt & MLX5_MPRQ_LEN_MASK) >> MLX5_MPRQ_LEN_SHIFT; 1244a96102c8SMichael Baum MLX5_ASSERT((int)len >= (rxq->crc_present << 2)); 1245a96102c8SMichael Baum if (rxq->crc_present) 1246a96102c8SMichael Baum len -= RTE_ETHER_CRC_LEN; 1247a96102c8SMichael Baum if (mcqe && 1248a96102c8SMichael Baum rxq->mcqe_format == MLX5_CQE_RESP_FORMAT_FTAG_STRIDX) 1249a96102c8SMichael Baum strd_cnt = (len / strd_sz) + !!(len % strd_sz); 1250a96102c8SMichael Baum else 1251a96102c8SMichael Baum strd_cnt = (byte_cnt & MLX5_MPRQ_STRIDE_NUM_MASK) >> 1252a96102c8SMichael Baum MLX5_MPRQ_STRIDE_NUM_SHIFT; 1253a96102c8SMichael Baum MLX5_ASSERT(strd_cnt); 1254a96102c8SMichael Baum consumed_strd += strd_cnt; 1255a96102c8SMichael Baum if (byte_cnt & MLX5_MPRQ_FILLER_MASK) 1256a96102c8SMichael Baum continue; 125702a6195cSAlexander Kozyrev if (rxq->cqe_comp_layout && mcqe) 125802a6195cSAlexander Kozyrev cqe = &rxq->title_cqe; 1259a96102c8SMichael Baum strd_idx = rte_be_to_cpu_16(mcqe == NULL ? 1260a96102c8SMichael Baum cqe->wqe_counter : 1261a96102c8SMichael Baum mcqe->stride_idx); 1262a96102c8SMichael Baum MLX5_ASSERT(strd_idx < strd_n); 1263a96102c8SMichael Baum MLX5_ASSERT(!((rte_be_to_cpu_16(cqe->wqe_id) ^ rq_ci) & 1264a96102c8SMichael Baum wq_mask)); 1265a96102c8SMichael Baum pkt = rte_pktmbuf_alloc(rxq->mp); 1266a96102c8SMichael Baum if (unlikely(pkt == NULL)) { 1267a96102c8SMichael Baum ++rxq->stats.rx_nombuf; 1268a96102c8SMichael Baum break; 1269a96102c8SMichael Baum } 1270a96102c8SMichael Baum len = (byte_cnt & MLX5_MPRQ_LEN_MASK) >> MLX5_MPRQ_LEN_SHIFT; 1271a96102c8SMichael Baum MLX5_ASSERT((int)len >= (rxq->crc_present << 2)); 1272a96102c8SMichael Baum if (rxq->crc_present) 1273a96102c8SMichael Baum len -= RTE_ETHER_CRC_LEN; 1274a96102c8SMichael Baum rxq_code = mprq_buf_to_pkt(rxq, pkt, len, buf, 1275a96102c8SMichael Baum strd_idx, strd_cnt); 1276a96102c8SMichael Baum if (unlikely(rxq_code != MLX5_RXQ_CODE_EXIT)) { 1277a96102c8SMichael Baum rte_pktmbuf_free_seg(pkt); 1278a96102c8SMichael Baum if (rxq_code == MLX5_RXQ_CODE_DROPPED) { 1279a96102c8SMichael Baum ++rxq->stats.idropped; 1280a96102c8SMichael Baum continue; 1281a96102c8SMichael Baum } 1282a96102c8SMichael Baum if (rxq_code == MLX5_RXQ_CODE_NOMBUF) { 1283a96102c8SMichael Baum ++rxq->stats.rx_nombuf; 1284a96102c8SMichael Baum break; 1285a96102c8SMichael Baum } 1286a96102c8SMichael Baum } 1287a96102c8SMichael Baum rxq_cq_to_mbuf(rxq, pkt, cqe, mcqe); 1288a96102c8SMichael Baum if (cqe->lro_num_seg > 1) { 1289a96102c8SMichael Baum mlx5_lro_update_hdr(rte_pktmbuf_mtod(pkt, uint8_t *), 1290a96102c8SMichael Baum cqe, mcqe, rxq, len); 1291daa02b5cSOlivier Matz pkt->ol_flags |= RTE_MBUF_F_RX_LRO; 1292a96102c8SMichael Baum pkt->tso_segsz = len / cqe->lro_num_seg; 1293a96102c8SMichael Baum } 1294a96102c8SMichael Baum PKT_LEN(pkt) = len; 1295a96102c8SMichael Baum PORT(pkt) = rxq->port_id; 1296a96102c8SMichael Baum #ifdef MLX5_PMD_SOFT_COUNTERS 1297a96102c8SMichael Baum /* Increment bytes counter. */ 1298a96102c8SMichael Baum rxq->stats.ibytes += PKT_LEN(pkt); 1299a96102c8SMichael Baum #endif 1300a96102c8SMichael Baum /* Return packet. */ 1301a96102c8SMichael Baum *(pkts++) = pkt; 1302a96102c8SMichael Baum ++i; 1303a96102c8SMichael Baum } 1304a96102c8SMichael Baum /* Update the consumer indexes. */ 1305a96102c8SMichael Baum rxq->consumed_strd = consumed_strd; 1306a96102c8SMichael Baum rte_io_wmb(); 1307a96102c8SMichael Baum *rxq->cq_db = rte_cpu_to_be_32(rxq->cq_ci); 1308a96102c8SMichael Baum if (rq_ci != rxq->rq_ci) { 1309a96102c8SMichael Baum rxq->rq_ci = rq_ci; 1310a96102c8SMichael Baum rte_io_wmb(); 1311a96102c8SMichael Baum *rxq->rq_db = rte_cpu_to_be_32(rxq->rq_ci); 1312a96102c8SMichael Baum } 1313a96102c8SMichael Baum #ifdef MLX5_PMD_SOFT_COUNTERS 1314a96102c8SMichael Baum /* Increment packets counter. */ 1315a96102c8SMichael Baum rxq->stats.ipackets += i; 1316a96102c8SMichael Baum #endif 1317a96102c8SMichael Baum return i; 1318a96102c8SMichael Baum } 1319a96102c8SMichael Baum 13205c9f3294SSpike Du int 13215c9f3294SSpike Du mlx5_rx_queue_lwm_query(struct rte_eth_dev *dev, 13225c9f3294SSpike Du uint16_t *queue_id, uint8_t *lwm) 13235c9f3294SSpike Du { 13245c9f3294SSpike Du struct mlx5_priv *priv = dev->data->dev_private; 13255c9f3294SSpike Du unsigned int rxq_id, found = 0, n; 13265c9f3294SSpike Du struct mlx5_rxq_priv *rxq; 13275c9f3294SSpike Du 13285c9f3294SSpike Du if (!queue_id) 13295c9f3294SSpike Du return -EINVAL; 13305c9f3294SSpike Du /* Query all the Rx queues of the port in a circular way. */ 13315c9f3294SSpike Du for (rxq_id = *queue_id, n = 0; n < priv->rxqs_n; n++) { 13325c9f3294SSpike Du rxq = mlx5_rxq_get(dev, rxq_id); 13335c9f3294SSpike Du if (rxq && rxq->lwm_event_pending) { 13345c9f3294SSpike Du pthread_mutex_lock(&priv->sh->lwm_config_lock); 13355c9f3294SSpike Du rxq->lwm_event_pending = 0; 13365c9f3294SSpike Du pthread_mutex_unlock(&priv->sh->lwm_config_lock); 13375c9f3294SSpike Du *queue_id = rxq_id; 13385c9f3294SSpike Du found = 1; 13395c9f3294SSpike Du if (lwm) 13405c9f3294SSpike Du *lwm = mlx5_rxq_lwm_to_percentage(rxq); 13415c9f3294SSpike Du break; 13425c9f3294SSpike Du } 13435c9f3294SSpike Du rxq_id = (rxq_id + 1) % priv->rxqs_n; 13445c9f3294SSpike Du } 13455c9f3294SSpike Du return found; 13465c9f3294SSpike Du } 13475c9f3294SSpike Du 134825025da3SSpike Du /** 134925025da3SSpike Du * Rte interrupt handler for LWM event. 135025025da3SSpike Du * It first checks if the event arrives, if so process the callback for 135125025da3SSpike Du * RTE_ETH_EVENT_RX_LWM. 135225025da3SSpike Du * 135325025da3SSpike Du * @param args 135425025da3SSpike Du * Generic pointer to mlx5_priv. 135525025da3SSpike Du */ 135625025da3SSpike Du void 135725025da3SSpike Du mlx5_dev_interrupt_handler_lwm(void *args) 135825025da3SSpike Du { 135925025da3SSpike Du struct mlx5_priv *priv = args; 136025025da3SSpike Du struct mlx5_rxq_priv *rxq; 136125025da3SSpike Du struct rte_eth_dev *dev; 136225025da3SSpike Du int ret, rxq_idx = 0, port_id = 0; 136325025da3SSpike Du 136425025da3SSpike Du ret = priv->obj_ops.rxq_event_get_lwm(priv, &rxq_idx, &port_id); 136525025da3SSpike Du if (unlikely(ret < 0)) { 136625025da3SSpike Du DRV_LOG(WARNING, "Cannot get LWM event context."); 136725025da3SSpike Du return; 136825025da3SSpike Du } 136925025da3SSpike Du DRV_LOG(INFO, "%s get LWM event, port_id:%d rxq_id:%d.", __func__, 137025025da3SSpike Du port_id, rxq_idx); 137125025da3SSpike Du dev = &rte_eth_devices[port_id]; 137225025da3SSpike Du rxq = mlx5_rxq_get(dev, rxq_idx); 137325025da3SSpike Du if (rxq) { 137425025da3SSpike Du pthread_mutex_lock(&priv->sh->lwm_config_lock); 137525025da3SSpike Du rxq->lwm_event_pending = 1; 137625025da3SSpike Du pthread_mutex_unlock(&priv->sh->lwm_config_lock); 137725025da3SSpike Du } 137825025da3SSpike Du rte_eth_dev_callback_process(dev, RTE_ETH_EVENT_RX_AVAIL_THRESH, NULL); 137925025da3SSpike Du } 13805c9f3294SSpike Du 13815c9f3294SSpike Du /** 13825c9f3294SSpike Du * DPDK callback to arm an Rx queue LWM(limit watermark) event. 13835c9f3294SSpike Du * While the Rx queue fullness reaches the LWM limit, the driver catches 13845c9f3294SSpike Du * an HW event and invokes the user event callback. 13855c9f3294SSpike Du * After the last event handling, the user needs to call this API again 13865c9f3294SSpike Du * to arm an additional event. 13875c9f3294SSpike Du * 13885c9f3294SSpike Du * @param dev 13895c9f3294SSpike Du * Pointer to the device structure. 13905c9f3294SSpike Du * @param[in] rx_queue_id 13915c9f3294SSpike Du * Rx queue identificator. 13925c9f3294SSpike Du * @param[in] lwm 13935c9f3294SSpike Du * The LWM value, is defined by a percentage of the Rx queue size. 13945c9f3294SSpike Du * [1-99] to set a new LWM (update the old value). 13955c9f3294SSpike Du * 0 to unarm the event. 13965c9f3294SSpike Du * 13975c9f3294SSpike Du * @return 13985c9f3294SSpike Du * 0 : operation success. 13995c9f3294SSpike Du * Otherwise: 14005c9f3294SSpike Du * - ENOMEM - not enough memory to create LWM event channel. 14015c9f3294SSpike Du * - EINVAL - the input Rxq is not created by devx. 14025c9f3294SSpike Du * - E2BIG - lwm is bigger than 99. 14035c9f3294SSpike Du */ 14045c9f3294SSpike Du int 14055c9f3294SSpike Du mlx5_rx_queue_lwm_set(struct rte_eth_dev *dev, uint16_t rx_queue_id, 14065c9f3294SSpike Du uint8_t lwm) 14075c9f3294SSpike Du { 14085c9f3294SSpike Du struct mlx5_priv *priv = dev->data->dev_private; 14095c9f3294SSpike Du uint16_t port_id = PORT_ID(priv); 14105c9f3294SSpike Du struct mlx5_rxq_priv *rxq = mlx5_rxq_get(dev, rx_queue_id); 14115c9f3294SSpike Du uint16_t event_nums[1] = {MLX5_EVENT_TYPE_SRQ_LIMIT_REACHED}; 14125c9f3294SSpike Du struct mlx5_rxq_data *rxq_data; 14135c9f3294SSpike Du uint32_t wqe_cnt; 14145c9f3294SSpike Du uint64_t cookie; 14155c9f3294SSpike Du int ret = 0; 14165c9f3294SSpike Du 14175c9f3294SSpike Du if (!rxq) { 14185c9f3294SSpike Du rte_errno = EINVAL; 14195c9f3294SSpike Du return -rte_errno; 14205c9f3294SSpike Du } 14215c9f3294SSpike Du rxq_data = &rxq->ctrl->rxq; 14225c9f3294SSpike Du /* Ensure the Rq is created by devx. */ 14235c9f3294SSpike Du if (priv->obj_ops.rxq_obj_new != devx_obj_ops.rxq_obj_new) { 14245c9f3294SSpike Du rte_errno = EINVAL; 14255c9f3294SSpike Du return -rte_errno; 14265c9f3294SSpike Du } 14275c9f3294SSpike Du if (lwm > 99) { 14285c9f3294SSpike Du DRV_LOG(WARNING, "Too big LWM configuration."); 14295c9f3294SSpike Du rte_errno = E2BIG; 14305c9f3294SSpike Du return -rte_errno; 14315c9f3294SSpike Du } 14325c9f3294SSpike Du /* Start config LWM. */ 14335c9f3294SSpike Du pthread_mutex_lock(&priv->sh->lwm_config_lock); 14345c9f3294SSpike Du if (rxq->lwm == 0 && lwm == 0) { 14355c9f3294SSpike Du /* Both old/new values are 0, do nothing. */ 14365c9f3294SSpike Du ret = 0; 14375c9f3294SSpike Du goto end; 14385c9f3294SSpike Du } 14395c9f3294SSpike Du wqe_cnt = 1 << (rxq_data->elts_n - rxq_data->sges_n); 14405c9f3294SSpike Du if (lwm) { 14415c9f3294SSpike Du if (!priv->sh->devx_channel_lwm) { 14425c9f3294SSpike Du ret = mlx5_lwm_setup(priv); 14435c9f3294SSpike Du if (ret) { 14445c9f3294SSpike Du DRV_LOG(WARNING, 14455c9f3294SSpike Du "Failed to create shared_lwm."); 14465c9f3294SSpike Du rte_errno = ENOMEM; 14475c9f3294SSpike Du ret = -rte_errno; 14485c9f3294SSpike Du goto end; 14495c9f3294SSpike Du } 14505c9f3294SSpike Du } 14515c9f3294SSpike Du if (!rxq->lwm_devx_subscribed) { 14525c9f3294SSpike Du cookie = ((uint32_t) 14535c9f3294SSpike Du (port_id << LWM_COOKIE_PORTID_OFFSET)) | 14545c9f3294SSpike Du (rx_queue_id << LWM_COOKIE_RXQID_OFFSET); 14555c9f3294SSpike Du ret = mlx5_os_devx_subscribe_devx_event 14565c9f3294SSpike Du (priv->sh->devx_channel_lwm, 14575c9f3294SSpike Du rxq->devx_rq.rq->obj, 14585c9f3294SSpike Du sizeof(event_nums), 14595c9f3294SSpike Du event_nums, 14605c9f3294SSpike Du cookie); 14615c9f3294SSpike Du if (ret) { 14625c9f3294SSpike Du rte_errno = rte_errno ? rte_errno : EINVAL; 14635c9f3294SSpike Du ret = -rte_errno; 14645c9f3294SSpike Du goto end; 14655c9f3294SSpike Du } 14665c9f3294SSpike Du rxq->lwm_devx_subscribed = 1; 14675c9f3294SSpike Du } 14685c9f3294SSpike Du } 14695c9f3294SSpike Du /* Save LWM to rxq and send modify_rq devx command. */ 14705c9f3294SSpike Du rxq->lwm = lwm * wqe_cnt / 100; 14715c9f3294SSpike Du /* Prevent integer division loss when switch lwm number to percentage. */ 14725c9f3294SSpike Du if (lwm && (lwm * wqe_cnt % 100)) { 14735c9f3294SSpike Du rxq->lwm = ((uint32_t)(rxq->lwm + 1) >= wqe_cnt) ? 14745c9f3294SSpike Du rxq->lwm : (rxq->lwm + 1); 14755c9f3294SSpike Du } 14765c9f3294SSpike Du if (lwm && !rxq->lwm) { 14775c9f3294SSpike Du /* With mprq, wqe_cnt may be < 100. */ 14785c9f3294SSpike Du DRV_LOG(WARNING, "Too small LWM configuration."); 14795c9f3294SSpike Du rte_errno = EINVAL; 14805c9f3294SSpike Du ret = -rte_errno; 14815c9f3294SSpike Du goto end; 14825c9f3294SSpike Du } 14835c9f3294SSpike Du ret = mlx5_devx_modify_rq(rxq, MLX5_RXQ_MOD_RDY2RDY); 14845c9f3294SSpike Du end: 14855c9f3294SSpike Du pthread_mutex_unlock(&priv->sh->lwm_config_lock); 14865c9f3294SSpike Du return ret; 14875c9f3294SSpike Du } 14885c9f3294SSpike Du 14892235fcdaSSpike Du /** 14902235fcdaSSpike Du * Mlx5 access register function to configure host shaper. 14912235fcdaSSpike Du * It calls API in libmtcr_ul to access QSHR(Qos Shaper Host Register) 14922235fcdaSSpike Du * in firmware. 14932235fcdaSSpike Du * 14942235fcdaSSpike Du * @param dev 14952235fcdaSSpike Du * Pointer to rte_eth_dev. 14962235fcdaSSpike Du * @param lwm_triggered 14972235fcdaSSpike Du * Flag to enable/disable lwm_triggered bit in QSHR. 14982235fcdaSSpike Du * @param rate 14992235fcdaSSpike Du * Host shaper rate, unit is 100Mbps, set to 0 means disable the shaper. 15002235fcdaSSpike Du * @return 15012235fcdaSSpike Du * 0 : operation success. 15022235fcdaSSpike Du * Otherwise: 15032235fcdaSSpike Du * - ENOENT - no ibdev interface. 15042235fcdaSSpike Du * - EBUSY - the register access unit is busy. 15052235fcdaSSpike Du * - EIO - the register access command meets IO error. 15062235fcdaSSpike Du */ 15072235fcdaSSpike Du static int 15082235fcdaSSpike Du mlxreg_host_shaper_config(struct rte_eth_dev *dev, 15092235fcdaSSpike Du bool lwm_triggered, uint8_t rate) 15102235fcdaSSpike Du { 15112235fcdaSSpike Du #ifdef HAVE_MLX5_MSTFLINT 15122235fcdaSSpike Du struct mlx5_priv *priv = dev->data->dev_private; 15132235fcdaSSpike Du uint32_t data[MLX5_ST_SZ_DW(register_qshr)] = {0}; 15142235fcdaSSpike Du int rc, retry_count = 3; 15152235fcdaSSpike Du mfile *mf = NULL; 15162235fcdaSSpike Du int status; 15172235fcdaSSpike Du void *ptr; 15182235fcdaSSpike Du 15192235fcdaSSpike Du mf = mopen(priv->sh->ibdev_name); 15202235fcdaSSpike Du if (!mf) { 15212235fcdaSSpike Du DRV_LOG(WARNING, "mopen failed\n"); 15222235fcdaSSpike Du rte_errno = ENOENT; 15232235fcdaSSpike Du return -rte_errno; 15242235fcdaSSpike Du } 15252235fcdaSSpike Du MLX5_SET(register_qshr, data, connected_host, 1); 15262235fcdaSSpike Du MLX5_SET(register_qshr, data, fast_response, lwm_triggered ? 1 : 0); 15272235fcdaSSpike Du MLX5_SET(register_qshr, data, local_port, 1); 15282235fcdaSSpike Du ptr = MLX5_ADDR_OF(register_qshr, data, global_config); 15292235fcdaSSpike Du MLX5_SET(ets_global_config_register, ptr, rate_limit_update, 1); 15302235fcdaSSpike Du MLX5_SET(ets_global_config_register, ptr, max_bw_units, 15312235fcdaSSpike Du rate ? ETS_GLOBAL_CONFIG_BW_UNIT_HUNDREDS_MBPS : 15322235fcdaSSpike Du ETS_GLOBAL_CONFIG_BW_UNIT_DISABLED); 15332235fcdaSSpike Du MLX5_SET(ets_global_config_register, ptr, max_bw_value, rate); 15342235fcdaSSpike Du do { 15352235fcdaSSpike Du rc = maccess_reg(mf, 15362235fcdaSSpike Du MLX5_QSHR_REGISTER_ID, 15372235fcdaSSpike Du MACCESS_REG_METHOD_SET, 15382235fcdaSSpike Du (u_int32_t *)&data[0], 15392235fcdaSSpike Du sizeof(data), 15402235fcdaSSpike Du sizeof(data), 15412235fcdaSSpike Du sizeof(data), 15422235fcdaSSpike Du &status); 15432235fcdaSSpike Du if ((rc != ME_ICMD_STATUS_IFC_BUSY && 15442235fcdaSSpike Du status != ME_REG_ACCESS_BAD_PARAM) || 15452235fcdaSSpike Du !(mf->flags & MDEVS_REM)) { 15462235fcdaSSpike Du break; 15472235fcdaSSpike Du } 15482235fcdaSSpike Du DRV_LOG(WARNING, "%s retry.", __func__); 15492235fcdaSSpike Du usleep(10000); 15502235fcdaSSpike Du } while (retry_count-- > 0); 15512235fcdaSSpike Du mclose(mf); 15522235fcdaSSpike Du rte_errno = (rc == ME_REG_ACCESS_DEV_BUSY) ? EBUSY : EIO; 15532235fcdaSSpike Du return rc ? -rte_errno : 0; 15542235fcdaSSpike Du #else 15552235fcdaSSpike Du (void)dev; 15562235fcdaSSpike Du (void)lwm_triggered; 15572235fcdaSSpike Du (void)rate; 15582235fcdaSSpike Du return -1; 15592235fcdaSSpike Du #endif 15602235fcdaSSpike Du } 15612235fcdaSSpike Du 15622235fcdaSSpike Du int rte_pmd_mlx5_host_shaper_config(int port_id, uint8_t rate, 15632235fcdaSSpike Du uint32_t flags) 15642235fcdaSSpike Du { 15652235fcdaSSpike Du struct rte_eth_dev *dev = &rte_eth_devices[port_id]; 15662235fcdaSSpike Du struct mlx5_priv *priv = dev->data->dev_private; 15672235fcdaSSpike Du bool lwm_triggered = 156886647d46SThomas Monjalon !!(flags & RTE_BIT32(RTE_PMD_MLX5_HOST_SHAPER_FLAG_AVAIL_THRESH_TRIGGERED)); 15692235fcdaSSpike Du 15702235fcdaSSpike Du if (!lwm_triggered) { 15712235fcdaSSpike Du priv->sh->host_shaper_rate = rate; 15722235fcdaSSpike Du } else { 15732235fcdaSSpike Du switch (rate) { 15742235fcdaSSpike Du case 0: 15752235fcdaSSpike Du /* Rate 0 means disable lwm_triggered. */ 15762235fcdaSSpike Du priv->sh->lwm_triggered = 0; 15772235fcdaSSpike Du break; 15782235fcdaSSpike Du case 1: 15792235fcdaSSpike Du /* Rate 1 means enable lwm_triggered. */ 15802235fcdaSSpike Du priv->sh->lwm_triggered = 1; 15812235fcdaSSpike Du break; 15822235fcdaSSpike Du default: 15832235fcdaSSpike Du return -ENOTSUP; 15842235fcdaSSpike Du } 15852235fcdaSSpike Du } 15862235fcdaSSpike Du return mlxreg_host_shaper_config(dev, priv->sh->lwm_triggered, 15872235fcdaSSpike Du priv->sh->host_shaper_rate); 15882235fcdaSSpike Du } 15893dfa7877SKiran Vedere 15903dfa7877SKiran Vedere /** 15913dfa7877SKiran Vedere * Dump RQ/CQ Context to a file. 15923dfa7877SKiran Vedere * 15933dfa7877SKiran Vedere * @param[in] port_id 15943dfa7877SKiran Vedere * Port ID 15953dfa7877SKiran Vedere * @param[in] queue_id 15963dfa7877SKiran Vedere * Queue ID 15973dfa7877SKiran Vedere * @param[in] filename 15983dfa7877SKiran Vedere * Name of file to dump the Rx Queue Context 15993dfa7877SKiran Vedere * 16003dfa7877SKiran Vedere * @return 16013dfa7877SKiran Vedere * 0 for Success, non-zero value depending on failure type 16023dfa7877SKiran Vedere */ 16033dfa7877SKiran Vedere int rte_pmd_mlx5_rxq_dump_contexts(uint16_t port_id, uint16_t queue_id, const char *filename) 16043dfa7877SKiran Vedere { 16053dfa7877SKiran Vedere struct rte_eth_dev *dev; 16063dfa7877SKiran Vedere struct mlx5_rxq_priv *rxq; 16073dfa7877SKiran Vedere struct mlx5_rxq_ctrl *rxq_ctrl; 16083dfa7877SKiran Vedere struct mlx5_rxq_obj *rxq_obj; 16093dfa7877SKiran Vedere struct mlx5_devx_rq *rq; 16103dfa7877SKiran Vedere struct mlx5_devx_cq *cq; 16113dfa7877SKiran Vedere struct mlx5_devx_obj *rq_devx_obj; 16123dfa7877SKiran Vedere struct mlx5_devx_obj *cq_devx_obj; 16133dfa7877SKiran Vedere 16143dfa7877SKiran Vedere uint32_t rq_out[MLX5_ST_SZ_DW(query_rq_out)] = {0}; 16153dfa7877SKiran Vedere uint32_t cq_out[MLX5_ST_SZ_DW(query_cq_out)] = {0}; 16163dfa7877SKiran Vedere 16173dfa7877SKiran Vedere int ret; 16183dfa7877SKiran Vedere FILE *fd; 16193dfa7877SKiran Vedere MKSTR(path, "./%s", filename); 16203dfa7877SKiran Vedere 16213dfa7877SKiran Vedere if (!rte_eth_dev_is_valid_port(port_id)) 16223dfa7877SKiran Vedere return -ENODEV; 16233dfa7877SKiran Vedere 16243dfa7877SKiran Vedere if (rte_eth_rx_queue_is_valid(port_id, queue_id)) 16253dfa7877SKiran Vedere return -EINVAL; 16263dfa7877SKiran Vedere 16273dfa7877SKiran Vedere fd = fopen(path, "w"); 16283dfa7877SKiran Vedere if (!fd) { 16293dfa7877SKiran Vedere rte_errno = errno; 16303dfa7877SKiran Vedere return -EIO; 16313dfa7877SKiran Vedere } 16323dfa7877SKiran Vedere 16333dfa7877SKiran Vedere dev = &rte_eth_devices[port_id]; 16343dfa7877SKiran Vedere rxq = mlx5_rxq_ref(dev, queue_id); 16353dfa7877SKiran Vedere rxq_ctrl = rxq->ctrl; 16363dfa7877SKiran Vedere rxq_obj = rxq_ctrl->obj; 16373dfa7877SKiran Vedere rq = &rxq->devx_rq; 16383dfa7877SKiran Vedere cq = &rxq_obj->cq_obj; 16393dfa7877SKiran Vedere rq_devx_obj = rq->rq; 16403dfa7877SKiran Vedere cq_devx_obj = cq->cq; 16413dfa7877SKiran Vedere 16423dfa7877SKiran Vedere do { 16433dfa7877SKiran Vedere ret = mlx5_devx_cmd_query_rq(rq_devx_obj, rq_out, sizeof(rq_out)); 16443dfa7877SKiran Vedere if (ret) 16453dfa7877SKiran Vedere break; 16463dfa7877SKiran Vedere 16473dfa7877SKiran Vedere /* Dump rq query output to file */ 16483dfa7877SKiran Vedere MKSTR(rq_headline, "RQ DevX ID = %u Port = %u Queue index = %u ", 16493dfa7877SKiran Vedere rq_devx_obj->id, port_id, queue_id); 16503dfa7877SKiran Vedere mlx5_dump_to_file(fd, NULL, rq_headline, 0); 16513dfa7877SKiran Vedere mlx5_dump_to_file(fd, "Query RQ Dump:", 16523dfa7877SKiran Vedere (const void *)((uintptr_t)rq_out), 16533dfa7877SKiran Vedere sizeof(rq_out)); 16543dfa7877SKiran Vedere 16553dfa7877SKiran Vedere ret = mlx5_devx_cmd_query_cq(cq_devx_obj, cq_out, sizeof(cq_out)); 16563dfa7877SKiran Vedere if (ret) 16573dfa7877SKiran Vedere break; 16583dfa7877SKiran Vedere 16593dfa7877SKiran Vedere /* Dump cq query output to file */ 16603dfa7877SKiran Vedere MKSTR(cq_headline, "CQ DevX ID = %u Port = %u Queue index = %u ", 16613dfa7877SKiran Vedere cq_devx_obj->id, port_id, queue_id); 16623dfa7877SKiran Vedere mlx5_dump_to_file(fd, NULL, cq_headline, 0); 16633dfa7877SKiran Vedere mlx5_dump_to_file(fd, "Query CQ Dump:", 16643dfa7877SKiran Vedere (const void *)((uintptr_t)cq_out), 16653dfa7877SKiran Vedere sizeof(cq_out)); 16663dfa7877SKiran Vedere } while (false); 16673dfa7877SKiran Vedere 16683dfa7877SKiran Vedere fclose(fd); 16693dfa7877SKiran Vedere return ret; 16703dfa7877SKiran Vedere } 1671