1410333daSLong Li /* SPDX-License-Identifier: BSD-3-Clause 2410333daSLong Li * Copyright 2022 Microsoft Corporation 3410333daSLong Li */ 4410333daSLong Li 5410333daSLong Li #include <ethdev_driver.h> 6410333daSLong Li 7410333daSLong Li #include <infiniband/verbs.h> 8410333daSLong Li #include <infiniband/manadv.h> 9410333daSLong Li 10410333daSLong Li #include "mana.h" 11410333daSLong Li 12410333daSLong Li int 13410333daSLong Li mana_stop_tx_queues(struct rte_eth_dev *dev) 14410333daSLong Li { 15410333daSLong Li struct mana_priv *priv = dev->data->dev_private; 16410333daSLong Li int i, ret; 17410333daSLong Li 18319855c9SLong Li for (i = 0; i < priv->num_queues; i++) 19319855c9SLong Li if (dev->data->tx_queue_state[i] == RTE_ETH_QUEUE_STATE_STOPPED) 20319855c9SLong Li return -EINVAL; 21319855c9SLong Li 22410333daSLong Li for (i = 0; i < priv->num_queues; i++) { 23410333daSLong Li struct mana_txq *txq = dev->data->tx_queues[i]; 24410333daSLong Li 25410333daSLong Li if (txq->qp) { 26410333daSLong Li ret = ibv_destroy_qp(txq->qp); 27410333daSLong Li if (ret) 28410333daSLong Li DRV_LOG(ERR, "tx_queue destroy_qp failed %d", 29410333daSLong Li ret); 30410333daSLong Li txq->qp = NULL; 31410333daSLong Li } 32410333daSLong Li 33410333daSLong Li if (txq->cq) { 34410333daSLong Li ret = ibv_destroy_cq(txq->cq); 35410333daSLong Li if (ret) 36410333daSLong Li DRV_LOG(ERR, "tx_queue destroy_cp failed %d", 37410333daSLong Li ret); 38410333daSLong Li txq->cq = NULL; 39410333daSLong Li } 40410333daSLong Li 41410333daSLong Li /* Drain and free posted WQEs */ 42410333daSLong Li while (txq->desc_ring_tail != txq->desc_ring_head) { 43410333daSLong Li struct mana_txq_desc *desc = 44410333daSLong Li &txq->desc_ring[txq->desc_ring_tail]; 45410333daSLong Li 46410333daSLong Li rte_pktmbuf_free(desc->pkt); 47410333daSLong Li 48410333daSLong Li txq->desc_ring_tail = 49410333daSLong Li (txq->desc_ring_tail + 1) % txq->num_desc; 50cce2c9dfSLong Li txq->desc_ring_len--; 51410333daSLong Li } 52410333daSLong Li txq->desc_ring_head = 0; 53410333daSLong Li txq->desc_ring_tail = 0; 54cce2c9dfSLong Li txq->desc_ring_len = 0; 55410333daSLong Li 56410333daSLong Li memset(&txq->gdma_sq, 0, sizeof(txq->gdma_sq)); 57410333daSLong Li memset(&txq->gdma_cq, 0, sizeof(txq->gdma_cq)); 58319855c9SLong Li 59319855c9SLong Li dev->data->tx_queue_state[i] = RTE_ETH_QUEUE_STATE_STOPPED; 60410333daSLong Li } 61410333daSLong Li 62410333daSLong Li return 0; 63410333daSLong Li } 64410333daSLong Li 65410333daSLong Li int 66410333daSLong Li mana_start_tx_queues(struct rte_eth_dev *dev) 67410333daSLong Li { 68410333daSLong Li struct mana_priv *priv = dev->data->dev_private; 69410333daSLong Li int ret, i; 70410333daSLong Li 71410333daSLong Li /* start TX queues */ 72319855c9SLong Li 73319855c9SLong Li for (i = 0; i < priv->num_queues; i++) 74319855c9SLong Li if (dev->data->tx_queue_state[i] == RTE_ETH_QUEUE_STATE_STARTED) 75319855c9SLong Li return -EINVAL; 76319855c9SLong Li 77410333daSLong Li for (i = 0; i < priv->num_queues; i++) { 78410333daSLong Li struct mana_txq *txq; 79410333daSLong Li struct ibv_qp_init_attr qp_attr = { 0 }; 80410333daSLong Li struct manadv_obj obj = {}; 81410333daSLong Li struct manadv_qp dv_qp; 82410333daSLong Li struct manadv_cq dv_cq; 83410333daSLong Li 84410333daSLong Li txq = dev->data->tx_queues[i]; 85410333daSLong Li 86410333daSLong Li manadv_set_context_attr(priv->ib_ctx, 87410333daSLong Li MANADV_CTX_ATTR_BUF_ALLOCATORS, 88410333daSLong Li (void *)((uintptr_t)&(struct manadv_ctx_allocators){ 89410333daSLong Li .alloc = &mana_alloc_verbs_buf, 90410333daSLong Li .free = &mana_free_verbs_buf, 91410333daSLong Li .data = (void *)(uintptr_t)txq->socket, 92410333daSLong Li })); 93410333daSLong Li 94410333daSLong Li txq->cq = ibv_create_cq(priv->ib_ctx, txq->num_desc, 95410333daSLong Li NULL, NULL, 0); 96410333daSLong Li if (!txq->cq) { 97410333daSLong Li DRV_LOG(ERR, "failed to create cq queue index %d", i); 98410333daSLong Li ret = -errno; 99410333daSLong Li goto fail; 100410333daSLong Li } 101410333daSLong Li 102410333daSLong Li qp_attr.send_cq = txq->cq; 103410333daSLong Li qp_attr.recv_cq = txq->cq; 104410333daSLong Li qp_attr.cap.max_send_wr = txq->num_desc; 105410333daSLong Li qp_attr.cap.max_send_sge = priv->max_send_sge; 106410333daSLong Li 107410333daSLong Li /* Skip setting qp_attr.cap.max_inline_data */ 108410333daSLong Li 109410333daSLong Li qp_attr.qp_type = IBV_QPT_RAW_PACKET; 110410333daSLong Li qp_attr.sq_sig_all = 0; 111410333daSLong Li 112410333daSLong Li txq->qp = ibv_create_qp(priv->ib_parent_pd, &qp_attr); 113410333daSLong Li if (!txq->qp) { 114410333daSLong Li DRV_LOG(ERR, "Failed to create qp queue index %d", i); 115410333daSLong Li ret = -errno; 116410333daSLong Li goto fail; 117410333daSLong Li } 118410333daSLong Li 119410333daSLong Li /* Get the addresses of CQ, QP and DB */ 120410333daSLong Li obj.qp.in = txq->qp; 121410333daSLong Li obj.qp.out = &dv_qp; 122410333daSLong Li obj.cq.in = txq->cq; 123410333daSLong Li obj.cq.out = &dv_cq; 124410333daSLong Li ret = manadv_init_obj(&obj, MANADV_OBJ_QP | MANADV_OBJ_CQ); 125410333daSLong Li if (ret) { 126410333daSLong Li DRV_LOG(ERR, "Failed to get manadv objects"); 127410333daSLong Li goto fail; 128410333daSLong Li } 129410333daSLong Li 130410333daSLong Li txq->gdma_sq.buffer = obj.qp.out->sq_buf; 131410333daSLong Li txq->gdma_sq.count = obj.qp.out->sq_count; 132410333daSLong Li txq->gdma_sq.size = obj.qp.out->sq_size; 133410333daSLong Li txq->gdma_sq.id = obj.qp.out->sq_id; 134410333daSLong Li 135410333daSLong Li txq->tx_vp_offset = obj.qp.out->tx_vp_offset; 136410333daSLong Li priv->db_page = obj.qp.out->db_page; 137410333daSLong Li DRV_LOG(INFO, "txq sq id %u vp_offset %u db_page %p " 138410333daSLong Li " buf %p count %u size %u", 139410333daSLong Li txq->gdma_sq.id, txq->tx_vp_offset, 140410333daSLong Li priv->db_page, 141410333daSLong Li txq->gdma_sq.buffer, txq->gdma_sq.count, 142410333daSLong Li txq->gdma_sq.size); 143410333daSLong Li 144410333daSLong Li txq->gdma_cq.buffer = obj.cq.out->buf; 145410333daSLong Li txq->gdma_cq.count = obj.cq.out->count; 146410333daSLong Li txq->gdma_cq.size = txq->gdma_cq.count * COMP_ENTRY_SIZE; 147410333daSLong Li txq->gdma_cq.id = obj.cq.out->cq_id; 148410333daSLong Li 149410333daSLong Li /* CQ head starts with count (not 0) */ 150410333daSLong Li txq->gdma_cq.head = txq->gdma_cq.count; 151410333daSLong Li 152410333daSLong Li DRV_LOG(INFO, "txq cq id %u buf %p count %u size %u head %u", 153410333daSLong Li txq->gdma_cq.id, txq->gdma_cq.buffer, 154410333daSLong Li txq->gdma_cq.count, txq->gdma_cq.size, 155410333daSLong Li txq->gdma_cq.head); 156319855c9SLong Li 157*084d0cdbSMorten Brørup __rte_assume(i < RTE_MAX_QUEUES_PER_PORT); 158319855c9SLong Li dev->data->tx_queue_state[i] = RTE_ETH_QUEUE_STATE_STARTED; 159410333daSLong Li } 160410333daSLong Li 161410333daSLong Li return 0; 162410333daSLong Li 163410333daSLong Li fail: 164410333daSLong Li mana_stop_tx_queues(dev); 165410333daSLong Li return ret; 166410333daSLong Li } 167410333daSLong Li 168410333daSLong Li static inline uint16_t 169410333daSLong Li get_vsq_frame_num(uint32_t vsq) 170410333daSLong Li { 171410333daSLong Li union { 172410333daSLong Li uint32_t gdma_txq_id; 173410333daSLong Li struct { 174410333daSLong Li uint32_t reserved1 : 10; 175410333daSLong Li uint32_t vsq_frame : 14; 176410333daSLong Li uint32_t reserved2 : 8; 177410333daSLong Li }; 178410333daSLong Li } v; 179410333daSLong Li 180410333daSLong Li v.gdma_txq_id = vsq; 181410333daSLong Li return v.vsq_frame; 182410333daSLong Li } 1837f322844SLong Li 1847f322844SLong Li uint16_t 1857f322844SLong Li mana_tx_burst(void *dpdk_txq, struct rte_mbuf **tx_pkts, uint16_t nb_pkts) 1867f322844SLong Li { 1877f322844SLong Li struct mana_txq *txq = dpdk_txq; 1887f322844SLong Li struct mana_priv *priv = txq->priv; 1897f322844SLong Li int ret; 1907f322844SLong Li void *db_page; 1917f322844SLong Li uint16_t pkt_sent = 0; 192cce2c9dfSLong Li uint32_t num_comp, i; 19326c6bdf3SWei Hu #ifdef RTE_ARCH_32 19426c6bdf3SWei Hu uint32_t wqe_count = 0; 19526c6bdf3SWei Hu #endif 1967f322844SLong Li 1977f322844SLong Li /* Process send completions from GDMA */ 19831124619SLong Li num_comp = gdma_poll_completion_queue(&txq->gdma_cq, 19931124619SLong Li txq->gdma_comp_buf, txq->num_desc); 20031124619SLong Li 201cce2c9dfSLong Li i = 0; 202cce2c9dfSLong Li while (i < num_comp) { 2037f322844SLong Li struct mana_txq_desc *desc = 2047f322844SLong Li &txq->desc_ring[txq->desc_ring_tail]; 20531124619SLong Li struct mana_tx_comp_oob *oob = (struct mana_tx_comp_oob *) 20631124619SLong Li txq->gdma_comp_buf[i].cqe_data; 2077f322844SLong Li 2087f322844SLong Li if (oob->cqe_hdr.cqe_type != CQE_TX_OKAY) { 209e2d3a3c0SLong Li DP_LOG(ERR, 2107f322844SLong Li "mana_tx_comp_oob cqe_type %u vendor_err %u", 2117f322844SLong Li oob->cqe_hdr.cqe_type, oob->cqe_hdr.vendor_err); 2127f322844SLong Li txq->stats.errors++; 2137f322844SLong Li } else { 214e2d3a3c0SLong Li DP_LOG(DEBUG, "mana_tx_comp_oob CQE_TX_OKAY"); 2157f322844SLong Li txq->stats.packets++; 2167f322844SLong Li } 2177f322844SLong Li 2187f322844SLong Li if (!desc->pkt) { 219e2d3a3c0SLong Li DP_LOG(ERR, "mana_txq_desc has a NULL pkt"); 2207f322844SLong Li } else { 221e1582eaaSLong Li txq->stats.bytes += desc->pkt->pkt_len; 2227f322844SLong Li rte_pktmbuf_free(desc->pkt); 2237f322844SLong Li } 2247f322844SLong Li 2257f322844SLong Li desc->pkt = NULL; 2267f322844SLong Li txq->desc_ring_tail = (txq->desc_ring_tail + 1) % txq->num_desc; 227cce2c9dfSLong Li txq->desc_ring_len--; 2287f322844SLong Li txq->gdma_sq.tail += desc->wqe_size_in_bu; 229cce2c9dfSLong Li 230cce2c9dfSLong Li /* If TX CQE suppression is used, don't read more CQE but move 231cce2c9dfSLong Li * on to the next packet 232cce2c9dfSLong Li */ 233cce2c9dfSLong Li if (desc->suppress_tx_cqe) 234cce2c9dfSLong Li continue; 235cce2c9dfSLong Li 236cce2c9dfSLong Li i++; 2377f322844SLong Li } 2387f322844SLong Li 2397f322844SLong Li /* Post send requests to GDMA */ 2407f322844SLong Li for (uint16_t pkt_idx = 0; pkt_idx < nb_pkts; pkt_idx++) { 2417f322844SLong Li struct rte_mbuf *m_pkt = tx_pkts[pkt_idx]; 2427f322844SLong Li struct rte_mbuf *m_seg = m_pkt; 243b5dfcaecSLong Li struct transmit_oob_v2 tx_oob; 244b5dfcaecSLong Li struct one_sgl sgl; 2457f322844SLong Li uint16_t seg_idx; 2467f322844SLong Li 247cce2c9dfSLong Li if (txq->desc_ring_len >= txq->num_desc) 248cce2c9dfSLong Li break; 249cce2c9dfSLong Li 2507f322844SLong Li /* Drop the packet if it exceeds max segments */ 2517f322844SLong Li if (m_pkt->nb_segs > priv->max_send_sge) { 252e2d3a3c0SLong Li DP_LOG(ERR, "send packet segments %d exceeding max", 2537f322844SLong Li m_pkt->nb_segs); 2547f322844SLong Li continue; 2557f322844SLong Li } 2567f322844SLong Li 2577f322844SLong Li /* Fill in the oob */ 258f8a4217dSWei Hu if (m_pkt->ol_flags & RTE_MBUF_F_TX_VLAN) { 259f8a4217dSWei Hu tx_oob.short_oob.packet_format = LONG_PACKET_FORMAT; 260f8a4217dSWei Hu tx_oob.long_oob.inject_vlan_prior_tag = 1; 261f8a4217dSWei Hu tx_oob.long_oob.priority_code_point = 262f8a4217dSWei Hu RTE_VLAN_TCI_PRI(m_pkt->vlan_tci); 263f8a4217dSWei Hu tx_oob.long_oob.drop_eligible_indicator = 264f8a4217dSWei Hu RTE_VLAN_TCI_DEI(m_pkt->vlan_tci); 265f8a4217dSWei Hu tx_oob.long_oob.vlan_identifier = 266f8a4217dSWei Hu RTE_VLAN_TCI_ID(m_pkt->vlan_tci); 267f8a4217dSWei Hu } else { 2687f322844SLong Li tx_oob.short_oob.packet_format = SHORT_PACKET_FORMAT; 269f8a4217dSWei Hu } 2707f322844SLong Li tx_oob.short_oob.tx_is_outer_ipv4 = 2717f322844SLong Li m_pkt->ol_flags & RTE_MBUF_F_TX_IPV4 ? 1 : 0; 2727f322844SLong Li tx_oob.short_oob.tx_is_outer_ipv6 = 2737f322844SLong Li m_pkt->ol_flags & RTE_MBUF_F_TX_IPV6 ? 1 : 0; 2747f322844SLong Li 2757f322844SLong Li tx_oob.short_oob.tx_compute_IP_header_checksum = 2767f322844SLong Li m_pkt->ol_flags & RTE_MBUF_F_TX_IP_CKSUM ? 1 : 0; 2777f322844SLong Li 2787f322844SLong Li if ((m_pkt->ol_flags & RTE_MBUF_F_TX_L4_MASK) == 2797f322844SLong Li RTE_MBUF_F_TX_TCP_CKSUM) { 2807f322844SLong Li struct rte_tcp_hdr *tcp_hdr; 2817f322844SLong Li 2827f322844SLong Li /* HW needs partial TCP checksum */ 2837f322844SLong Li 2847f322844SLong Li tcp_hdr = rte_pktmbuf_mtod_offset(m_pkt, 2857f322844SLong Li struct rte_tcp_hdr *, 2867f322844SLong Li m_pkt->l2_len + m_pkt->l3_len); 2877f322844SLong Li 2887f322844SLong Li if (m_pkt->ol_flags & RTE_MBUF_F_TX_IPV4) { 2897f322844SLong Li struct rte_ipv4_hdr *ip_hdr; 2907f322844SLong Li 2917f322844SLong Li ip_hdr = rte_pktmbuf_mtod_offset(m_pkt, 2927f322844SLong Li struct rte_ipv4_hdr *, 2937f322844SLong Li m_pkt->l2_len); 2947f322844SLong Li tcp_hdr->cksum = rte_ipv4_phdr_cksum(ip_hdr, 2957f322844SLong Li m_pkt->ol_flags); 2967f322844SLong Li 2977f322844SLong Li } else if (m_pkt->ol_flags & RTE_MBUF_F_TX_IPV6) { 2987f322844SLong Li struct rte_ipv6_hdr *ip_hdr; 2997f322844SLong Li 3007f322844SLong Li ip_hdr = rte_pktmbuf_mtod_offset(m_pkt, 3017f322844SLong Li struct rte_ipv6_hdr *, 3027f322844SLong Li m_pkt->l2_len); 3037f322844SLong Li tcp_hdr->cksum = rte_ipv6_phdr_cksum(ip_hdr, 3047f322844SLong Li m_pkt->ol_flags); 3057f322844SLong Li } else { 306e2d3a3c0SLong Li DP_LOG(ERR, "Invalid input for TCP CKSUM"); 3077f322844SLong Li } 3087f322844SLong Li 3097f322844SLong Li tx_oob.short_oob.tx_compute_TCP_checksum = 1; 3107f322844SLong Li tx_oob.short_oob.tx_transport_header_offset = 3117f322844SLong Li m_pkt->l2_len + m_pkt->l3_len; 312b5dfcaecSLong Li } else { 313b5dfcaecSLong Li tx_oob.short_oob.tx_compute_TCP_checksum = 0; 3147f322844SLong Li } 3157f322844SLong Li 3167f322844SLong Li if ((m_pkt->ol_flags & RTE_MBUF_F_TX_L4_MASK) == 3177f322844SLong Li RTE_MBUF_F_TX_UDP_CKSUM) { 3187f322844SLong Li struct rte_udp_hdr *udp_hdr; 3197f322844SLong Li 3207f322844SLong Li /* HW needs partial UDP checksum */ 3217f322844SLong Li udp_hdr = rte_pktmbuf_mtod_offset(m_pkt, 3227f322844SLong Li struct rte_udp_hdr *, 3237f322844SLong Li m_pkt->l2_len + m_pkt->l3_len); 3247f322844SLong Li 3257f322844SLong Li if (m_pkt->ol_flags & RTE_MBUF_F_TX_IPV4) { 3267f322844SLong Li struct rte_ipv4_hdr *ip_hdr; 3277f322844SLong Li 3287f322844SLong Li ip_hdr = rte_pktmbuf_mtod_offset(m_pkt, 3297f322844SLong Li struct rte_ipv4_hdr *, 3307f322844SLong Li m_pkt->l2_len); 3317f322844SLong Li 3327f322844SLong Li udp_hdr->dgram_cksum = 3337f322844SLong Li rte_ipv4_phdr_cksum(ip_hdr, 3347f322844SLong Li m_pkt->ol_flags); 3357f322844SLong Li 3367f322844SLong Li } else if (m_pkt->ol_flags & RTE_MBUF_F_TX_IPV6) { 3377f322844SLong Li struct rte_ipv6_hdr *ip_hdr; 3387f322844SLong Li 3397f322844SLong Li ip_hdr = rte_pktmbuf_mtod_offset(m_pkt, 3407f322844SLong Li struct rte_ipv6_hdr *, 3417f322844SLong Li m_pkt->l2_len); 3427f322844SLong Li 3437f322844SLong Li udp_hdr->dgram_cksum = 3447f322844SLong Li rte_ipv6_phdr_cksum(ip_hdr, 3457f322844SLong Li m_pkt->ol_flags); 3467f322844SLong Li 3477f322844SLong Li } else { 348e2d3a3c0SLong Li DP_LOG(ERR, "Invalid input for UDP CKSUM"); 3497f322844SLong Li } 3507f322844SLong Li 3517f322844SLong Li tx_oob.short_oob.tx_compute_UDP_checksum = 1; 352b5dfcaecSLong Li } else { 353b5dfcaecSLong Li tx_oob.short_oob.tx_compute_UDP_checksum = 0; 3547f322844SLong Li } 3557f322844SLong Li 3567f322844SLong Li tx_oob.short_oob.VCQ_number = txq->gdma_cq.id; 3577f322844SLong Li 3587f322844SLong Li tx_oob.short_oob.VSQ_frame_num = 3597f322844SLong Li get_vsq_frame_num(txq->gdma_sq.id); 3607f322844SLong Li tx_oob.short_oob.short_vport_offset = txq->tx_vp_offset; 3617f322844SLong Li 362e2d3a3c0SLong Li DP_LOG(DEBUG, "tx_oob packet_format %u ipv4 %u ipv6 %u", 3637f322844SLong Li tx_oob.short_oob.packet_format, 3647f322844SLong Li tx_oob.short_oob.tx_is_outer_ipv4, 3657f322844SLong Li tx_oob.short_oob.tx_is_outer_ipv6); 3667f322844SLong Li 367e2d3a3c0SLong Li DP_LOG(DEBUG, "tx_oob checksum ip %u tcp %u udp %u offset %u", 3687f322844SLong Li tx_oob.short_oob.tx_compute_IP_header_checksum, 3697f322844SLong Li tx_oob.short_oob.tx_compute_TCP_checksum, 3707f322844SLong Li tx_oob.short_oob.tx_compute_UDP_checksum, 3717f322844SLong Li tx_oob.short_oob.tx_transport_header_offset); 3727f322844SLong Li 373e2d3a3c0SLong Li DP_LOG(DEBUG, "pkt[%d]: buf_addr 0x%p, nb_segs %d, pkt_len %d", 3747f322844SLong Li pkt_idx, m_pkt->buf_addr, m_pkt->nb_segs, 3757f322844SLong Li m_pkt->pkt_len); 3767f322844SLong Li 3777f322844SLong Li /* Create SGL for packet data buffers */ 3787f322844SLong Li for (seg_idx = 0; seg_idx < m_pkt->nb_segs; seg_idx++) { 3797f322844SLong Li struct mana_mr_cache *mr = 3807d79530eSLong Li mana_alloc_pmd_mr(&txq->mr_btree, priv, m_seg); 3817f322844SLong Li 3827f322844SLong Li if (!mr) { 383e2d3a3c0SLong Li DP_LOG(ERR, "failed to get MR, pkt_idx %u", 3847f322844SLong Li pkt_idx); 3857f322844SLong Li break; 3867f322844SLong Li } 3877f322844SLong Li 3887f322844SLong Li sgl.gdma_sgl[seg_idx].address = 3897f322844SLong Li rte_cpu_to_le_64(rte_pktmbuf_mtod(m_seg, 3907f322844SLong Li uint64_t)); 3917f322844SLong Li sgl.gdma_sgl[seg_idx].size = m_seg->data_len; 3927f322844SLong Li sgl.gdma_sgl[seg_idx].memory_key = mr->lkey; 3937f322844SLong Li 394e2d3a3c0SLong Li DP_LOG(DEBUG, 3957f322844SLong Li "seg idx %u addr 0x%" PRIx64 " size %x key %x", 3967f322844SLong Li seg_idx, sgl.gdma_sgl[seg_idx].address, 3977f322844SLong Li sgl.gdma_sgl[seg_idx].size, 3987f322844SLong Li sgl.gdma_sgl[seg_idx].memory_key); 3997f322844SLong Li 4007f322844SLong Li m_seg = m_seg->next; 4017f322844SLong Li } 4027f322844SLong Li 4037f322844SLong Li /* Skip this packet if we can't populate all segments */ 4047f322844SLong Li if (seg_idx != m_pkt->nb_segs) 4057f322844SLong Li continue; 4067f322844SLong Li 407cce2c9dfSLong Li /* If we can at least queue post two WQEs and there are at 408cce2c9dfSLong Li * least two packets to send, use TX CQE suppression for the 409cce2c9dfSLong Li * current WQE 410cce2c9dfSLong Li */ 411cce2c9dfSLong Li if (txq->desc_ring_len + 1 < txq->num_desc && 412cce2c9dfSLong Li pkt_idx + 1 < nb_pkts) 413cce2c9dfSLong Li tx_oob.short_oob.suppress_tx_CQE_generation = 1; 414cce2c9dfSLong Li else 415cce2c9dfSLong Li tx_oob.short_oob.suppress_tx_CQE_generation = 0; 416cce2c9dfSLong Li 417b5dfcaecSLong Li struct gdma_work_request work_req; 418b5dfcaecSLong Li uint32_t wqe_size_in_bu; 4197f322844SLong Li 4207f322844SLong Li work_req.gdma_header.struct_size = sizeof(work_req); 4217f322844SLong Li 4227f322844SLong Li work_req.sgl = sgl.gdma_sgl; 4237f322844SLong Li work_req.num_sgl_elements = m_pkt->nb_segs; 424f8a4217dSWei Hu if (tx_oob.short_oob.packet_format == SHORT_PACKET_FORMAT) 4257f322844SLong Li work_req.inline_oob_size_in_bytes = 4267f322844SLong Li sizeof(struct transmit_short_oob_v2); 427f8a4217dSWei Hu else 428f8a4217dSWei Hu work_req.inline_oob_size_in_bytes = 429f8a4217dSWei Hu sizeof(struct transmit_oob_v2); 4307f322844SLong Li work_req.inline_oob_data = &tx_oob; 4317f322844SLong Li work_req.flags = 0; 4327f322844SLong Li work_req.client_data_unit = NOT_USING_CLIENT_DATA_UNIT; 4337f322844SLong Li 4347f322844SLong Li ret = gdma_post_work_request(&txq->gdma_sq, &work_req, 435b5dfcaecSLong Li &wqe_size_in_bu); 4367f322844SLong Li if (!ret) { 4377f322844SLong Li struct mana_txq_desc *desc = 4387f322844SLong Li &txq->desc_ring[txq->desc_ring_head]; 4397f322844SLong Li 4407f322844SLong Li /* Update queue for tracking pending requests */ 4417f322844SLong Li desc->pkt = m_pkt; 442b5dfcaecSLong Li desc->wqe_size_in_bu = wqe_size_in_bu; 443cce2c9dfSLong Li desc->suppress_tx_cqe = 444cce2c9dfSLong Li tx_oob.short_oob.suppress_tx_CQE_generation; 4457f322844SLong Li txq->desc_ring_head = 4467f322844SLong Li (txq->desc_ring_head + 1) % txq->num_desc; 447cce2c9dfSLong Li txq->desc_ring_len++; 4487f322844SLong Li 4497f322844SLong Li pkt_sent++; 4507f322844SLong Li 451e2d3a3c0SLong Li DP_LOG(DEBUG, "nb_pkts %u pkt[%d] sent", 4527f322844SLong Li nb_pkts, pkt_idx); 45326c6bdf3SWei Hu #ifdef RTE_ARCH_32 45426c6bdf3SWei Hu wqe_count += wqe_size_in_bu; 45526c6bdf3SWei Hu if (wqe_count > TX_WQE_SHORT_DB_THRESHOLD) { 45626c6bdf3SWei Hu /* wqe_count approaching to short doorbell 45726c6bdf3SWei Hu * increment limit. Stop processing further 45826c6bdf3SWei Hu * more packets and just ring short 45926c6bdf3SWei Hu * doorbell. 46026c6bdf3SWei Hu */ 46126c6bdf3SWei Hu DP_LOG(DEBUG, "wqe_count %u reaching limit, " 46226c6bdf3SWei Hu "pkt_sent %d", 46326c6bdf3SWei Hu wqe_count, pkt_sent); 46426c6bdf3SWei Hu break; 46526c6bdf3SWei Hu } 46626c6bdf3SWei Hu #endif 4677f322844SLong Li } else { 468e2d3a3c0SLong Li DP_LOG(DEBUG, "pkt[%d] failed to post send ret %d", 4697f322844SLong Li pkt_idx, ret); 4707f322844SLong Li break; 4717f322844SLong Li } 4727f322844SLong Li } 4737f322844SLong Li 4747f322844SLong Li /* Ring hardware door bell */ 4757f322844SLong Li db_page = priv->db_page; 4767f322844SLong Li if (rte_eal_process_type() == RTE_PROC_SECONDARY) { 4777f322844SLong Li struct rte_eth_dev *dev = 4787f322844SLong Li &rte_eth_devices[priv->dev_data->port_id]; 4797f322844SLong Li struct mana_process_priv *process_priv = dev->process_private; 4807f322844SLong Li 4817f322844SLong Li db_page = process_priv->db_page; 4827f322844SLong Li } 4837f322844SLong Li 4847f322844SLong Li if (pkt_sent) { 48526c6bdf3SWei Hu #ifdef RTE_ARCH_32 48626c6bdf3SWei Hu ret = mana_ring_short_doorbell(db_page, GDMA_QUEUE_SEND, 48726c6bdf3SWei Hu txq->gdma_sq.id, 48826c6bdf3SWei Hu wqe_count * 48926c6bdf3SWei Hu GDMA_WQE_ALIGNMENT_UNIT_SIZE, 49026c6bdf3SWei Hu 0); 49126c6bdf3SWei Hu #else 4927f322844SLong Li ret = mana_ring_doorbell(db_page, GDMA_QUEUE_SEND, 4937f322844SLong Li txq->gdma_sq.id, 4947f322844SLong Li txq->gdma_sq.head * 495afd5d170SLong Li GDMA_WQE_ALIGNMENT_UNIT_SIZE, 496afd5d170SLong Li 0); 49726c6bdf3SWei Hu #endif 4987f322844SLong Li if (ret) 499e2d3a3c0SLong Li DP_LOG(ERR, "mana_ring_doorbell failed ret %d", ret); 5007f322844SLong Li } 5017f322844SLong Li 5027f322844SLong Li return pkt_sent; 5037f322844SLong Li } 504