The combined Tx burst path suffers from severe cache misses because the compact CQE and normal paths are interleaved. Split out a dedicated compact CQE entry point and select it directly from the runtime flag instead of the dynamic tx_ops indirection.
Signed-off-by: Jiacheng Ye <[email protected]> --- doc/guides/rel_notes/release_26_11.rst | 1 + drivers/net/hinic3/hinic3_ethdev.c | 31 +- drivers/net/hinic3/hinic3_ethdev.h | 1 - drivers/net/hinic3/hinic3_tx.c | 519 +++++++++++++++++++++---- drivers/net/hinic3/hinic3_tx.h | 35 +- 5 files changed, 455 insertions(+), 132 deletions(-) diff --git a/doc/guides/rel_notes/release_26_11.rst b/doc/guides/rel_notes/release_26_11.rst index 53d0f76a32..8556fc5272 100644 --- a/doc/guides/rel_notes/release_26_11.rst +++ b/doc/guides/rel_notes/release_26_11.rst @@ -125,6 +125,7 @@ New Features * Added device parameters for runtime configuration. * Added a compact CQE receive data path. * Extended TCP segmentation offload (TSO) to 255 segments. + * Added a compact CQE transmit data path. * **Updated Intel iavf driver.** diff --git a/drivers/net/hinic3/hinic3_ethdev.c b/drivers/net/hinic3/hinic3_ethdev.c index d3e95a361a..b64746664d 100644 --- a/drivers/net/hinic3/hinic3_ethdev.c +++ b/drivers/net/hinic3/hinic3_ethdev.c @@ -1392,6 +1392,7 @@ hinic3_tx_queue_setup(struct rte_eth_dev *dev, uint16_t qid, uint16_t nb_desc, (HINIC3_COS_NUM_MAX - 1) & nic_dev->cos_mask]; txq->tx_deferred_start = tx_conf->tx_deferred_start; + txq->tx_wqe_compact_task = HINIC3_SUPPORT_TX_WQE_COMPACT_TASK(nic_dev); ci_mz = hinic3_dma_zone_reserve(dev, "hinic3_sq_ci", qid, @@ -3715,14 +3716,6 @@ static const struct eth_dev_ops hinic3_pmd_vf_ops = { .eth_dev_priv_dump = hinic3_eth_dev_priv_dump, }; -static void hinic3_nic_tx_rx_ops_init(struct hinic3_nic_dev *nic_dev) -{ - if (HINIC3_SUPPORT_TX_WQE_COMPACT_TASK(nic_dev)) - nic_dev->tx_ops->nic_tx_set_wqe_offload = hinic3_tx_set_compact_task_offload; - else - nic_dev->tx_ops->nic_tx_set_wqe_offload = hinic3_tx_set_normal_task_offload; -} - /** * Initialize the network function, including hardware configuration, memory * allocation for data structures, MAC address setup, and interrupt enabling. @@ -3783,13 +3776,6 @@ hinic3_func_init(struct rte_eth_dev *eth_dev) goto alloc_eth_addr_fail; } - nic_dev->tx_ops = rte_zmalloc("tx_ops", sizeof(struct hinic3_nic_tx_ops), 0); - if (!nic_dev->tx_ops) { - PMD_DRV_LOG(ERR, "Allocate tx_ops memory failed"); - err = -ENOMEM; - goto alloc_tx_ops_fail; - } - nic_dev->mc_list = rte_zmalloc("hinic3_mc", HINIC3_MAX_MC_MAC_ADDRS * sizeof(struct rte_ether_addr), 0); if (!nic_dev->mc_list) { @@ -3843,8 +3829,6 @@ hinic3_func_init(struct rte_eth_dev *eth_dev) goto get_cap_fail; } - hinic3_nic_tx_rx_ops_init(nic_dev); - err = hinic3_init_sw_rxtxqs(nic_dev); if (err) { PMD_DRV_LOG(ERR, "Init sw rxqs or txqs failed, dev_name: %s", @@ -3934,10 +3918,6 @@ hinic3_func_init(struct rte_eth_dev *eth_dev) nic_dev->mc_list = NULL; alloc_mc_list_fail: - rte_free(nic_dev->tx_ops); - nic_dev->tx_ops = NULL; - -alloc_tx_ops_fail: rte_free(eth_dev->data->mac_addrs); eth_dev->data->mac_addrs = NULL; @@ -4087,14 +4067,15 @@ hinic3_dev_init(struct rte_eth_dev *eth_dev) return err; } - if (nic_dev->config.rx_cqe_compact_en != HINIC3_RX_CQE_COMPACT_EN) + if (nic_dev->config.rx_cqe_compact_en != HINIC3_RX_CQE_COMPACT_EN) { eth_dev->rx_pkt_burst = hinic3_recv_pkts; - else + eth_dev->tx_pkt_burst = hinic3_xmit_pkts; + } else { eth_dev->rx_pkt_burst = hinic3_recv_pkts_compact_cqe; + eth_dev->tx_pkt_burst = hinic3_xmit_pkts_compact_cqe; + } } - eth_dev->tx_pkt_burst = hinic3_xmit_pkts; - return 0; } diff --git a/drivers/net/hinic3/hinic3_ethdev.h b/drivers/net/hinic3/hinic3_ethdev.h index 281953a8eb..92c7d44741 100644 --- a/drivers/net/hinic3/hinic3_ethdev.h +++ b/drivers/net/hinic3/hinic3_ethdev.h @@ -186,7 +186,6 @@ struct hinic3_nic_dev { struct hinic3_fdir_rule_filter_list filter_fdir_rule_list; uint8_t cos_map[HINIC3_COS_NUM_MAX]; struct hinic3_ptype_table *ptype_tbl; - struct hinic3_nic_tx_ops *tx_ops; enum nic_type nic_type; /**< NIC type. */ }; diff --git a/drivers/net/hinic3/hinic3_tx.c b/drivers/net/hinic3/hinic3_tx.c index c8a4170b87..b52be4c180 100644 --- a/drivers/net/hinic3/hinic3_tx.c +++ b/drivers/net/hinic3/hinic3_tx.c @@ -77,6 +77,30 @@ hinic3_get_and_update_sq_owner(struct hinic3_txq *sq, uint16_t curr_pi, uint16_t return owner; } +static void * +hinic3_get_sq_wqe(struct hinic3_txq *sq, + struct hinic3_wqe_info *wqe_info) +{ + uint16_t cur_pi = MASKED_QUEUE_IDX(sq, sq->prod_idx); + uint32_t end_pi; + + end_pi = cur_pi + wqe_info->wqebb_cnt; + sq->prod_idx += wqe_info->wqebb_cnt; + + wqe_info->owner = (uint8_t)(sq->owner); + wqe_info->pi = cur_pi; + wqe_info->wrapped = 0; + + if (unlikely(end_pi >= sq->q_depth)) { + sq->owner = !sq->owner; + + if (likely(end_pi > sq->q_depth)) + wqe_info->wrapped = (uint8_t)(sq->q_depth - cur_pi); + } + + return NIC_WQE_ADDR(sq, cur_pi); +} + static inline void hinic3_put_sq_wqe(struct hinic3_txq *sq, struct hinic3_wqe_info *wqe_info) { @@ -97,9 +121,9 @@ hinic3_put_sq_wqe(struct hinic3_txq *sq, struct hinic3_wqe_info *wqe_info) * Point to wqe_info of send queue(SQ). */ static void -hinic3_set_wqe_combo(struct hinic3_txq *sq, - struct hinic3_sq_wqe_combo *wqe_combo, - struct hinic3_wqe_info *wqe_info) +hinic3_set_wqe_combo_compact_cqe(struct hinic3_txq *sq, + struct hinic3_sq_wqe_combo *wqe_combo, + struct hinic3_wqe_info *wqe_info) { uint16_t tmp_pi; @@ -124,6 +148,62 @@ hinic3_set_wqe_combo(struct hinic3_txq *sq, wqe_info->owner = hinic3_get_and_update_sq_owner(sq, wqe_info->pi, wqe_info->wqebb_cnt); } +/** + * Sets the WQE combination information in the transmit queue (SQ). + * + * @param[in] sq + * Point to send queue. + * @param[out] wqe_combo + * Point to wqe_combo of send queue(SQ). + * @param[in] wqe_info + * Point to wqe_info of send queue(SQ). + */ +static void +hinic3_set_wqe_combo(struct hinic3_txq *sq, + struct hinic3_sq_wqe_combo *wqe_combo, + struct hinic3_sq_wqe *wqe, + struct hinic3_wqe_info *wqe_info) +{ + wqe_combo->hdr = &wqe->compact_wqe.wqe_desc; + + if (wqe_info->offload) { + if (wqe_info->wrapped == HINIC3_TX_TASK_WRAPPED) { + wqe_combo->task = (struct hinic3_sq_task *) + (void *)sq->sq_head_addr; + wqe_combo->bds_head = (struct hinic3_sq_bufdesc *) + (void *)(sq->sq_head_addr + sq->wqebb_size); + } else if (wqe_info->wrapped == HINIC3_TX_BD_DESC_WRAPPED) { + wqe_combo->task = &wqe->extend_wqe.task; + wqe_combo->bds_head = (struct hinic3_sq_bufdesc *) + (void *)(sq->sq_head_addr); + } else { + wqe_combo->task = &wqe->extend_wqe.task; + wqe_combo->bds_head = wqe->extend_wqe.buf_desc; + } + + wqe_combo->wqe_type = SQ_WQE_EXTENDED_TYPE; + wqe_combo->task_type = SQ_WQE_TASKSECT_16BYTES; + return; + } + + if (wqe_info->wrapped == HINIC3_TX_TASK_WRAPPED) { + wqe_combo->bds_head = (struct hinic3_sq_bufdesc *) + (void *)(sq->sq_head_addr); + } else { + wqe_combo->bds_head = + (struct hinic3_sq_bufdesc *)(&wqe->extend_wqe.task); + } + + if (wqe_info->wqebb_cnt > 1) { + wqe_combo->wqe_type = SQ_WQE_EXTENDED_TYPE; + wqe_combo->task_type = SQ_WQE_TASKSECT_4BYTES; + /* This section used as vlan insert, needs to clear */ + wqe_combo->bds_head->rsvd = 0; + } else { + wqe_combo->wqe_type = SQ_WQE_COMPACT_TYPE; + } +} + int hinic3_start_all_sqs(struct rte_eth_dev *eth_dev) { @@ -343,33 +423,15 @@ hinic3_tx_offload_pkt_prepare(struct hinic3_nic_dev *nic_dev, struct rte_mbuf *m return 0; } -void -hinic3_tx_set_normal_task_offload(struct hinic3_wqe_info *wqe_info, - struct hinic3_sq_wqe_combo *wqe_combo) +static inline void hinic3_set_vlan_tx_offload(struct hinic3_sq_task *task, + uint16_t vlan_tag, uint8_t vlan_type) { - struct hinic3_sq_task *task = wqe_combo->task; - struct hinic3_offload_info *offload_info = &wqe_info->offload_info; - - task->pkt_info0 = 0; - task->pkt_info0 |= SQ_TASK_INFO0_SET(offload_info->inner_l4_en, INNER_L4_EN); - task->pkt_info0 |= SQ_TASK_INFO0_SET(offload_info->inner_l3_en, INNER_L3_EN); - task->pkt_info0 |= SQ_TASK_INFO0_SET(offload_info->encapsulation, TUNNEL_FLAG); - task->pkt_info0 |= SQ_TASK_INFO0_SET(offload_info->out_l3_en, OUT_L3_EN); - task->pkt_info0 |= SQ_TASK_INFO0_SET(offload_info->out_l4_en, OUT_L4_EN); - task->pkt_info0 = hinic3_hw_be32(task->pkt_info0); - - if (wqe_combo->task_type == SQ_WQE_TASKSECT_16BYTES) { - task->ip_identify = 0; - task->pkt_info2 = 0; - task->vlan_offload = 0; - task->vlan_offload = SQ_TASK_INFO3_SET(offload_info->vlan_tag, VLAN_TAG) | - SQ_TASK_INFO3_SET(offload_info->vlan_sel, VLAN_TYPE) | - SQ_TASK_INFO3_SET(offload_info->vlan_valid, VLAN_TAG_VALID); - task->vlan_offload = hinic3_hw_be32(task->vlan_offload); - } + task->vlan_offload = SQ_TASK_INFO3_SET(vlan_tag, VLAN_TAG) | + SQ_TASK_INFO3_SET(vlan_type, VLAN_TYPE) | + SQ_TASK_INFO3_SET(1U, VLAN_TAG_VALID); } -void +static void hinic3_tx_set_compact_task_offload(struct hinic3_wqe_info *wqe_info, struct hinic3_sq_wqe_combo *wqe_combo) { @@ -390,10 +452,9 @@ hinic3_tx_set_compact_task_offload(struct hinic3_wqe_info *wqe_info, } static int -hinic3_set_tx_offload(struct hinic3_nic_dev *nic_dev, - struct rte_mbuf *mbuf, - struct hinic3_sq_wqe_combo *wqe_combo, - struct hinic3_wqe_info *wqe_info) +hinic3_set_tx_offload_compact_cqe(struct rte_mbuf *mbuf, + struct hinic3_sq_wqe_combo *wqe_combo, + struct hinic3_wqe_info *wqe_info) { uint64_t ol_flags = mbuf->ol_flags; struct hinic3_offload_info *offload_info = &wqe_info->offload_info; @@ -442,6 +503,9 @@ hinic3_set_tx_offload(struct hinic3_nic_dev *nic_dev, offload_info->encapsulation = 1; wqe_info->queue_info.udp_dp_en = 1; break; + case HINIC3_PKT_TX_TUNNEL_IPIP: + offload_info->encapsulation = 1; + break; case 0: break; @@ -457,11 +521,113 @@ hinic3_set_tx_offload(struct hinic3_nic_dev *nic_dev, offload_info->out_l4_en = 1; set_tx_wqe_offload: - nic_dev->tx_ops->nic_tx_set_wqe_offload(wqe_info, wqe_combo); + hinic3_tx_set_compact_task_offload(wqe_info, wqe_combo); return 0; } +static int +hinic3_set_tx_offload(struct rte_mbuf *mbuf, + struct hinic3_sq_task *task, + struct hinic3_wqe_info *wqe_info, + enum nic_type nic_type) +{ + uint64_t ol_flags = mbuf->ol_flags; + uint16_t pld_offset = 0; + uint32_t queue_info = 0; + uint16_t vlan_tag; + + task->pkt_info0 = 0; + task->ip_identify = 0; + task->pkt_info2 = 0; + task->vlan_offload = 0; + + /* Vlan offload */ + if (unlikely(ol_flags & HINIC3_PKT_TX_VLAN_PKT)) { + vlan_tag = mbuf->vlan_tci; + hinic3_set_vlan_tx_offload(task, vlan_tag, HINIC3_TX_TPID0); + task->vlan_offload = hinic3_hw_be32(task->vlan_offload); + } + + if (!(ol_flags & HINIC3_TX_CKSUM_OFFLOAD_MASK)) + return 0; + + /* Tso offload */ + if (ol_flags & HINIC3_PKT_TX_TCP_SEG) { + if (((ol_flags & HINIC3_PKT_TX_TUNNEL_IPIP) == HINIC3_PKT_TX_TUNNEL_IPIP) && + nic_type == NIC_SP620) { + PMD_DRV_LOG(ERR, "IPinIP not support TSO"); + return -EINVAL; + } + if ((ol_flags & HINIC3_PKT_TX_TUNNEL_MASK) == HINIC3_PKT_TX_TUNNEL_VXLAN_GPE) { + PMD_DRV_LOG(ERR, "VXLAN_GPE not support TSO"); + return -EINVAL; + } + pld_offset = wqe_info->payload_offset; + if ((pld_offset >> 1) > MAX_PAYLOAD_OFFSET) + return -EINVAL; + + task->pkt_info0 |= SQ_TASK_INFO0_SET(1U, INNER_L4_EN); + task->pkt_info0 |= SQ_TASK_INFO0_SET(1U, INNER_L3_EN); + + queue_info |= SQ_CTRL_QUEUE_INFO_SET(1U, TSO); + queue_info |= SQ_CTRL_QUEUE_INFO_SET(pld_offset >> 1, PLDOFF); + + /* Set MSS value */ + queue_info = SQ_CTRL_QUEUE_INFO_CLEAR(queue_info, MSS); + queue_info |= SQ_CTRL_QUEUE_INFO_SET(mbuf->tso_segsz, MSS); + } else { + if (ol_flags & HINIC3_PKT_TX_IP_CKSUM) + task->pkt_info0 |= SQ_TASK_INFO0_SET(1U, INNER_L3_EN); + + switch (ol_flags & HINIC3_PKT_TX_L4_MASK) { + case HINIC3_PKT_TX_TCP_CKSUM: + case HINIC3_PKT_TX_UDP_CKSUM: + case HINIC3_PKT_TX_SCTP_CKSUM: + task->pkt_info0 |= SQ_TASK_INFO0_SET(1U, INNER_L4_EN); + break; + case HINIC3_PKT_TX_L4_NO_CKSUM: + break; + default: + PMD_DRV_LOG(INFO, "not support pkt type"); + return -EINVAL; + } + } + + /* For vxlan, also can support PKT_TX_TUNNEL_GENEVE/GRE, etc */ + switch (ol_flags & HINIC3_PKT_TX_TUNNEL_MASK) { + case HINIC3_PKT_TX_TUNNEL_VXLAN: + task->pkt_info0 |= SQ_TASK_INFO0_SET(1U, TUNNEL_FLAG); + break; + case HINIC3_PKT_TX_TUNNEL_VXLAN_GPE: + task->pkt_info0 |= SQ_TASK_INFO0_SET(1U, TUNNEL_FLAG); + break; + case HINIC3_PKT_TX_TUNNEL_GENEVE: + task->pkt_info0 |= SQ_TASK_INFO0_SET(1U, TUNNEL_FLAG); + break; + case HINIC3_PKT_TX_TUNNEL_IPIP: + task->pkt_info0 |= SQ_TASK_INFO0_SET(1U, TUNNEL_FLAG); + break; + case 0: + break; + default: + /* For non UDP/GRE tunneling, drop the tunnel packet */ + PMD_DRV_LOG(INFO, "not support tunnel pkt type"); + return -EINVAL; + } + + if (ol_flags & HINIC3_PKT_TX_OUTER_IP_CKSUM) + task->pkt_info0 |= SQ_TASK_INFO0_SET(1U, OUT_L3_EN); + + if (ol_flags & HINIC3_PKT_TX_OUTER_UDP_CKSUM) + task->pkt_info0 |= SQ_TASK_INFO0_SET(1U, OUT_L4_EN); + + task->pkt_info0 = hinic3_hw_be32(task->pkt_info0); + task->pkt_info2 = hinic3_hw_be32(task->pkt_info2); + wqe_info->queue_info_sp600 = queue_info; + return 0; +} + /** * Check whether the number of segments in the mbuf is valid. * @@ -597,6 +763,8 @@ hinic3_non_tso_pkt_pre_process(struct rte_mbuf *mbuf, struct hinic3_wqe_info *wq * Point to the mbuf to send. * @param[in] wqe_info * Point to wqe_info of send queue(SQ). + * @param[in] non_tso_max_pkt_len + * Number of non_tso_max_pkt_len(SP230 is 9600, SP620/SP560 is 64K) * @return * 0 as success, -EINVAL as failure. */ @@ -802,6 +970,14 @@ hinic3_mbuf_dma_map_sge(struct hinic3_txq *txq, struct rte_mbuf *mbuf, hinic3_set_buf_desc(buf_desc, dma_addr, mbuf->data_len); buf_desc++; } + + /* + * SP620: For wqe compact type, no need to prepare + * sq ctrl info. Need set queue_info = 0. + */ + if (txq->nic_dev->nic_type == NIC_SP620) + wqe_desc->queue_info = 0; + mbuf = mbuf->next; } @@ -849,8 +1025,8 @@ hinic3_mbuf_dma_map_sge(struct hinic3_txq *txq, struct rte_mbuf *mbuf, * Point to wqe_info of send queue. */ static void -hinic3_prepare_sq_ctrl(struct hinic3_sq_wqe_combo *wqe_combo, - struct hinic3_wqe_info *wqe_info) +hinic3_prepare_sq_ctrl_compact_cqe(struct hinic3_sq_wqe_combo *wqe_combo, + struct hinic3_wqe_info *wqe_info) { struct hinic3_queue_info *queue_info = &wqe_info->queue_info; struct hinic3_sq_wqe_desc *wqe_desc = wqe_combo->hdr; @@ -863,7 +1039,7 @@ hinic3_prepare_sq_ctrl(struct hinic3_sq_wqe_combo *wqe_combo, if (wqe_combo->wqe_type == SQ_WQE_EXTENDED_TYPE) { wqe_desc->ctrl_len |= SQ_CTRL_SET(wqe_info->sge_cnt, BUFDESC_NUM) | SQ_CTRL_SET(wqe_combo->task_type, TASKSECT_LEN) | - SQ_CTRL_SET(SQ_NORMAL_WQE, DATA_FORMAT); + SQ_CTRL_SET(SQ_WQE_SGL, DATA_FORMAT); *qsf = SQ_CTRL_QUEUE_INFO_SET(1, UC) | SQ_CTRL_QUEUE_INFO_SET(queue_info->sctp, SCTP) | @@ -884,14 +1060,56 @@ hinic3_prepare_sq_ctrl(struct hinic3_sq_wqe_combo *wqe_combo, *qsf = hinic3_hw_be32(*qsf); } else { wqe_desc->ctrl_len |= SQ_CTRL_COMPACT_QUEUE_INFO_SET(queue_info->sctp, SCTP) | - SQ_CTRL_COMPACT_QUEUE_INFO_SET(queue_info->udp_dp_en, UDP_DP_EN) | - SQ_CTRL_COMPACT_QUEUE_INFO_SET(queue_info->ufo, UFO) | - SQ_CTRL_COMPACT_QUEUE_INFO_SET(queue_info->pkt_type, PKT_TYPE); + SQ_CTRL_COMPACT_QUEUE_INFO_SET(queue_info->udp_dp_en, + UDP_DP_EN) | + SQ_CTRL_COMPACT_QUEUE_INFO_SET(queue_info->ufo, UFO) | + SQ_CTRL_COMPACT_QUEUE_INFO_SET(queue_info->pkt_type, + PKT_TYPE); } wqe_desc->ctrl_len = hinic3_hw_be32(wqe_desc->ctrl_len); } +/** + * Sets and configures fields in the transmit queue control descriptor based on + * the WQE type. + * + * @param[out] wqe_combo + * Point to wqe_combo of send queue. + * @param[in] wqe_info + * Point to wqe_info of send queue. + */ +static void +hinic3_prepare_sq_ctrl(struct hinic3_sq_wqe_combo *wqe_combo, + struct hinic3_wqe_info *wqe_info) +{ + struct hinic3_sq_wqe_desc *wqe_desc = wqe_combo->hdr; + + wqe_desc->ctrl_len |= SQ_CTRL_SET(wqe_info->sge_cnt, BUFDESC_NUM) | + SQ_CTRL_SET(wqe_combo->task_type, TASKSECT_LEN) | + SQ_CTRL_SET(SQ_NORMAL_WQE, DATA_FORMAT) | + SQ_CTRL_SET(wqe_combo->wqe_type, EXTENDED) | + SQ_CTRL_SET(wqe_info->owner, OWNER); + + wqe_desc->ctrl_len = hinic3_hw_be32(wqe_desc->ctrl_len); + + wqe_desc->queue_info = wqe_info->queue_info_sp600; + wqe_desc->queue_info |= SQ_CTRL_QUEUE_INFO_SET(1U, UC); + + if (!SQ_CTRL_QUEUE_INFO_GET(wqe_desc->queue_info, MSS)) { + wqe_desc->queue_info |= + SQ_CTRL_QUEUE_INFO_SET(TX_MSS_DEFAULT, MSS); + } else if (SQ_CTRL_QUEUE_INFO_GET(wqe_desc->queue_info, MSS) < + TX_MSS_MIN) { + /* Mss should not less than 80 */ + wqe_desc->queue_info = + SQ_CTRL_QUEUE_INFO_CLEAR(wqe_desc->queue_info, MSS); + wqe_desc->queue_info |= SQ_CTRL_QUEUE_INFO_SET(TX_MSS_MIN, MSS); + } + + wqe_desc->queue_info = hinic3_hw_be32(wqe_desc->queue_info); +} + /** * It is responsible for sending data packets. * @@ -911,10 +1129,11 @@ hinic3_xmit_pkts(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkts) struct hinic3_tx_info *tx_info = NULL; struct rte_mbuf *mbuf_pkt = NULL; struct hinic3_sq_wqe_combo wqe_combo = {0}; + struct hinic3_sq_wqe *sq_wqe = NULL; struct hinic3_wqe_info wqe_info = {0}; uint32_t offload_err, free_cnt; uint64_t tx_bytes = 0; - uint16_t free_wqebb_cnt, nb_tx; + uint16_t free_wqebb_cnt, nb_tx, nb_pkt = 0; int err; #ifdef HINIC3_XSTAT_PROF_TX @@ -925,6 +1144,7 @@ hinic3_xmit_pkts(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkts) if (unlikely(!HINIC3_TXQ_IS_STARTED(txq))) return 0; + rte_prefetch0(tx_pkts[0]); free_cnt = txq->tx_free_thresh; /* Reclaim tx mbuf before xmit new packets. */ if (hinic3_get_sq_free_wqebbs(txq) < txq->tx_free_thresh) @@ -933,59 +1153,73 @@ hinic3_xmit_pkts(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkts) /* Tx loop routine. */ for (nb_tx = 0; nb_tx < nb_pkts; nb_tx++) { mbuf_pkt = *tx_pkts++; + rte_prefetch0(*tx_pkts); if (unlikely(hinic3_get_tx_offload(txq->nic_dev, mbuf_pkt, &wqe_info, txq->non_tso_max_pkt_len))) { + rte_pktmbuf_free(mbuf_pkt); txq->txq_stats.offload_errors++; - break; + continue; } - wqe_info.wqebb_cnt = wqe_info.sge_cnt; - if (likely(wqe_info.offload || wqe_info.wqebb_cnt > 1)) { - if (txq->tx_wqe_compact_task) { - /** - * One more wqebb is needed for compact task under two situations: - * 1. TSO: MSS field is needed, no available space for - * compact task in compact wqe. - * 2. SGE number > 1: wqe is handlerd as extended wqe by nic. - */ - if (mbuf_pkt->ol_flags & HINIC3_PKT_TX_TCP_SEG || - wqe_info.wqebb_cnt > 1) - wqe_info.wqebb_cnt++; - } else { - /* Use extended sq wqe with normal TS */ - wqe_info.wqebb_cnt++; - } - } + if (!wqe_info.offload) + /* + * Use extended sq wqe with small TS, which can include + * multi sges, or compact sq normal wqe, which just + * supports one sge + */ + wqe_info.wqebb_cnt = wqe_info.sge_cnt; + else + /* Use extended sq wqe with normal TS */ + wqe_info.wqebb_cnt = wqe_info.sge_cnt + 1; free_wqebb_cnt = hinic3_get_sq_free_wqebbs(txq); - if (unlikely(wqe_info.wqebb_cnt > free_wqebb_cnt)) { - /* Reclaim again. */ + if (wqe_info.wqebb_cnt > free_wqebb_cnt) { + /* + * Try to reclaim completed Tx WQEs when SQ space is + * insufficient. This gives hardware a chance to free + * descriptors and helps prevent packet drops caused + * by transient SQ congestion. + */ hinic3_xmit_mbuf_cleanup(txq, free_cnt); free_wqebb_cnt = hinic3_get_sq_free_wqebbs(txq); - if (unlikely(wqe_info.wqebb_cnt > free_wqebb_cnt)) { + if (wqe_info.wqebb_cnt > free_wqebb_cnt) { txq->txq_stats.tx_busy += (nb_pkts - nb_tx); - break; + goto end; } } - /* Task or bd section maybe wrapped for one wqe. */ - hinic3_set_wqe_combo(txq, &wqe_combo, &wqe_info); + /* Get sq wqe address from wqe_page */ + sq_wqe = hinic3_get_sq_wqe(txq, &wqe_info); + if (unlikely(!sq_wqe)) { + txq->txq_stats.tx_busy++; + break; + } - /* Fill tx packet offload into qsf and task field. */ - offload_err = hinic3_set_tx_offload(txq->nic_dev, mbuf_pkt, &wqe_combo, &wqe_info); + /* Task or bd section maybe wrapped for one wqe */ + hinic3_set_wqe_combo(txq, &wqe_combo, sq_wqe, &wqe_info); + + wqe_info.queue_info_sp600 = 0; + /* Fill tx packet offload into qsf and task field */ + if (wqe_info.offload) { + offload_err = hinic3_set_tx_offload(mbuf_pkt, + wqe_combo.task, + &wqe_info, + txq->nic_dev->nic_type); if (unlikely(offload_err)) { hinic3_put_sq_wqe(txq, &wqe_info); + rte_pktmbuf_free(mbuf_pkt); txq->txq_stats.offload_errors++; - break; + continue; } - + } /* Fill sq_wqe buf_desc and bd_desc. */ err = hinic3_mbuf_dma_map_sge(txq, mbuf_pkt, &wqe_combo, &wqe_info); if (err) { hinic3_put_sq_wqe(txq, &wqe_info); + rte_pktmbuf_free(mbuf_pkt); txq->txq_stats.offload_errors++; - break; + continue; } /* Record tx info. */ @@ -1001,27 +1235,28 @@ hinic3_xmit_pkts(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkts) hinic3_prepare_sq_ctrl(&wqe_combo, &wqe_info); tx_bytes += mbuf_pkt->pkt_len; + nb_pkt++; } - +end: /* Update txq stats. */ - if (nb_tx) { + if (nb_pkt) { hinic3_write_db(txq->db_addr, txq->q_id, (int)(txq->cos), SQ_CFLAG_DP, MASKED_QUEUE_IDX(txq, txq->prod_idx)); - txq->txq_stats.packets += nb_tx; + txq->txq_stats.packets += nb_pkt; txq->txq_stats.bytes += tx_bytes; } - txq->txq_stats.burst_pkts = nb_tx; + txq->txq_stats.burst_pkts = nb_pkt; #ifdef HINIC3_XSTAT_PROF_TX t2 = rte_get_tsc_cycles(); txq->txq_stats.app_tsc = t1 - txq->prof_tx_end_tsc; txq->prof_tx_end_tsc = t2; txq->txq_stats.pmd_tsc = t2 - t1; - txq->txq_stats.burst_pkts = nb_tx; + txq->txq_stats.burst_pkts = nb_pkt; #endif - return nb_tx; + return nb_pkt; } int @@ -1077,3 +1312,139 @@ hinic3_flush_txqs(struct hinic3_nic_dev *nic_dev) PMD_DRV_LOG(ERR, "Stop sq%d failed", qid); } } + +/** + * It is responsible for sending data packets. + * + * @param[in] tx_queue + * Point to send queue. + * @param[in] tx_pkts + * Pointer to the array of data packets to be sent. + * @param[in] nb_pkts + * Number of sent packets. + * @return + * Number of actually sent packets. + */ +uint16_t +hinic3_xmit_pkts_compact_cqe(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkts) +{ + struct hinic3_txq *txq = tx_queue; + struct hinic3_nic_dev *nic_dev = txq->nic_dev; + struct hinic3_tx_info *tx_info = NULL; + struct rte_mbuf *mbuf_pkt = NULL; + struct hinic3_sq_wqe_combo wqe_combo = {0}; + struct hinic3_wqe_info wqe_info = {0}; + uint32_t offload_err, free_cnt; + uint64_t tx_bytes = 0; + uint16_t free_wqebb_cnt, nb_tx, nb_pkt = 0; + int err; + +#ifdef HINIC3_XSTAT_PROF_TX + uint64_t t1, t2; + t1 = rte_get_tsc_cycles(); +#endif + + if (unlikely(!HINIC3_TXQ_IS_STARTED(txq))) + return 0; + + free_cnt = txq->tx_free_thresh; + /* Reclaim tx mbuf before xmit new packets. */ + if (hinic3_get_sq_free_wqebbs(txq) < txq->tx_free_thresh) + hinic3_xmit_mbuf_cleanup(txq, free_cnt); + + /* Tx loop routine. */ + for (nb_tx = 0; nb_tx < nb_pkts; nb_tx++) { + mbuf_pkt = *tx_pkts++; + if (unlikely(hinic3_get_tx_offload(nic_dev, mbuf_pkt, &wqe_info, + txq->non_tso_max_pkt_len))) { + rte_pktmbuf_free(mbuf_pkt); + txq->txq_stats.offload_errors++; + continue; + } + + wqe_info.wqebb_cnt = wqe_info.sge_cnt; + if (likely(wqe_info.offload || wqe_info.wqebb_cnt > 1)) { + if (txq->tx_wqe_compact_task) { + /** + * One more wqebb is needed for compact task under two situations: + * 1. TSO: MSS field is needed, no available space for + * compact task in compact wqe. + * 2. SGE number > 1: wqe is handlerd as extended wqe by nic. + */ + if (mbuf_pkt->ol_flags & HINIC3_PKT_TX_TCP_SEG || + wqe_info.wqebb_cnt > 1) + wqe_info.wqebb_cnt++; + } else { + /* Use extended sq wqe with normal TS */ + wqe_info.wqebb_cnt++; + } + } + + free_wqebb_cnt = hinic3_get_sq_free_wqebbs(txq); + if (wqe_info.wqebb_cnt > free_wqebb_cnt) { + /* Reclaim again */ + hinic3_xmit_mbuf_cleanup(txq, free_cnt); + free_wqebb_cnt = hinic3_get_sq_free_wqebbs(txq); + if (wqe_info.wqebb_cnt > free_wqebb_cnt) { + txq->txq_stats.tx_busy += (nb_pkts - nb_tx); + goto end; + } + } + + /* Task or bd section maybe wrapped for one wqe. */ + hinic3_set_wqe_combo_compact_cqe(txq, &wqe_combo, &wqe_info); + + /* Fill tx packet offload into qsf and task field. */ + offload_err = hinic3_set_tx_offload_compact_cqe(mbuf_pkt, &wqe_combo, &wqe_info); + if (unlikely(offload_err)) { + hinic3_put_sq_wqe(txq, &wqe_info); + rte_pktmbuf_free(mbuf_pkt); + txq->txq_stats.offload_errors++; + continue; + } + + /* Fill sq_wqe buf_desc and bd_desc. */ + err = hinic3_mbuf_dma_map_sge(txq, mbuf_pkt, &wqe_combo, &wqe_info); + + if (err) { + hinic3_put_sq_wqe(txq, &wqe_info); + rte_pktmbuf_free(mbuf_pkt); + txq->txq_stats.offload_errors++; + continue; + } + + /* Record tx info. */ + tx_info = &txq->tx_info[wqe_info.pi]; + tx_info->mbuf = mbuf_pkt; + tx_info->wqebb_cnt = wqe_info.wqebb_cnt; + + /* + * For wqe compact type, no need to prepare + * sq ctrl info. + */ + hinic3_prepare_sq_ctrl_compact_cqe(&wqe_combo, &wqe_info); + + tx_bytes += mbuf_pkt->pkt_len; + nb_pkt++; + } +end: + /* Update txq stats. */ + if (nb_pkt) { + hinic3_write_db(txq->db_addr, txq->q_id, (int)(txq->cos), + SQ_CFLAG_DP, + MASKED_QUEUE_IDX(txq, txq->prod_idx)); + txq->txq_stats.packets += nb_pkt; + txq->txq_stats.bytes += tx_bytes; + } + txq->txq_stats.burst_pkts = nb_pkt; + +#ifdef HINIC3_XSTAT_PROF_TX + t2 = rte_get_tsc_cycles(); + txq->txq_stats.app_tsc = t1 - txq->prof_tx_end_tsc; + txq->prof_tx_end_tsc = t2; + txq->txq_stats.pmd_tsc = t2 - t1; + txq->txq_stats.burst_pkts = nb_pkt; +#endif + + return nb_pkt; +} diff --git a/drivers/net/hinic3/hinic3_tx.h b/drivers/net/hinic3/hinic3_tx.h index 5d4101630e..b216a39ecd 100644 --- a/drivers/net/hinic3/hinic3_tx.h +++ b/drivers/net/hinic3/hinic3_tx.h @@ -55,10 +55,10 @@ struct hinic3_wqe_info { uint16_t sge_cnt; uint8_t offload; - uint8_t rsvd0; /**< Reserved field 0. */ + uint8_t wrapped; uint16_t payload_offset; - uint8_t rsvd1; /**< Reserved field 1. */ + uint32_t queue_info_sp600; uint8_t owner; uint16_t pi; @@ -388,41 +388,12 @@ struct __rte_cache_aligned hinic3_txq { #endif }; -/* Tx WQE offload set callback function */ -typedef void (*nic_tx_set_wqe_offload_t)(struct hinic3_wqe_info *wqe_info, - struct hinic3_sq_wqe_combo *wqe_combo); - -struct hinic3_nic_tx_ops { - nic_tx_set_wqe_offload_t nic_tx_set_wqe_offload; -}; - void hinic3_flush_txqs(struct hinic3_nic_dev *nic_dev); void hinic3_free_txq_mbufs(struct hinic3_txq *txq); void hinic3_free_all_txq_mbufs(struct hinic3_nic_dev *nic_dev); +uint16_t hinic3_xmit_pkts_compact_cqe(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkts); uint16_t hinic3_xmit_pkts(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkts); int hinic3_stop_sq(struct hinic3_txq *txq); int hinic3_start_all_sqs(struct rte_eth_dev *eth_dev); int hinic3_tx_done_cleanup(void *txq, uint32_t free_cnt); - -/** - * Set wqe task section - * - * @param[in] wqe_info - * Packet info parsed according to mbuf - * @param[in] wqe_combo - * Wqe need to format - */ -void hinic3_tx_set_normal_task_offload(struct hinic3_wqe_info *wqe_info, - struct hinic3_sq_wqe_combo *wqe_combo); - -/** - * Set compact wqe task section - * - * @param[in] wqe_info - * Packet info parsed according to mbuf - * @param[in] wqe_combo - * Wqe need to format - */ -void hinic3_tx_set_compact_task_offload(struct hinic3_wqe_info *wqe_info, - struct hinic3_sq_wqe_combo *wqe_combo); #endif /**< _HINIC3_TX_H_ */ -- 2.33.0

