X-Git-Url: http://git.droids-corp.org/?a=blobdiff_plain;f=drivers%2Fnet%2Fena%2Fena_ethdev.c;h=c3fd3a4ac0fea617e7aaec8d705df6cf9f21b32f;hb=8430a8b841c8;hp=0d4523c1da5a70ff425cff74158d08aa0eaacdb0;hpb=e1e73e3229355de3c6945b68a94aba63f790a225;p=dpdk.git diff --git a/drivers/net/ena/ena_ethdev.c b/drivers/net/ena/ena_ethdev.c index 0d4523c1da..c3fd3a4ac0 100644 --- a/drivers/net/ena/ena_ethdev.c +++ b/drivers/net/ena/ena_ethdev.c @@ -27,22 +27,14 @@ #include #define DRV_MODULE_VER_MAJOR 2 -#define DRV_MODULE_VER_MINOR 0 -#define DRV_MODULE_VER_SUBMINOR 3 +#define DRV_MODULE_VER_MINOR 1 +#define DRV_MODULE_VER_SUBMINOR 0 #define ENA_IO_TXQ_IDX(q) (2 * (q)) #define ENA_IO_RXQ_IDX(q) (2 * (q) + 1) /*reverse version of ENA_IO_RXQ_IDX*/ #define ENA_IO_RXQ_IDX_REV(q) ((q - 1) / 2) -/* While processing submitted and completed descriptors (rx and tx path - * respectively) in a loop it is desired to: - * - perform batch submissions while populating sumbissmion queue - * - avoid blocking transmission of other packets during cleanup phase - * Hence the utilization ratio of 1/8 of a queue size. - */ -#define ENA_RING_DESCS_RATIO(ring_size) (ring_size / 8) - #define __MERGE_64B_H_L(h, l) (((uint64_t)h << 32) | l) #define TEST_BIT(val, bit_shift) (val & (1UL << bit_shift)) @@ -177,6 +169,13 @@ static int ena_device_init(struct ena_com_dev *ena_dev, struct ena_com_dev_get_features_ctx *get_feat_ctx, bool *wd_state); static int ena_dev_configure(struct rte_eth_dev *dev); +static void ena_tx_map_mbuf(struct ena_ring *tx_ring, + struct ena_tx_buffer *tx_info, + struct rte_mbuf *mbuf, + void **push_header, + uint16_t *header_len); +static int ena_xmit_mbuf(struct ena_ring *tx_ring, struct rte_mbuf *mbuf); +static void ena_tx_cleanup(struct ena_ring *tx_ring); static uint16_t eth_ena_xmit_pkts(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkts); static uint16_t eth_ena_prep_pkts(void *tx_queue, struct rte_mbuf **tx_pkts, @@ -188,10 +187,19 @@ static int ena_rx_queue_setup(struct rte_eth_dev *dev, uint16_t queue_idx, uint16_t nb_desc, unsigned int socket_id, const struct rte_eth_rxconf *rx_conf, struct rte_mempool *mp); +static inline void ena_init_rx_mbuf(struct rte_mbuf *mbuf, uint16_t len); +static struct rte_mbuf *ena_rx_mbuf(struct ena_ring *rx_ring, + struct ena_com_rx_buf_info *ena_bufs, + uint32_t descs, + uint16_t *next_to_clean, + uint8_t offset); static uint16_t eth_ena_recv_pkts(void *rx_queue, struct rte_mbuf **rx_pkts, uint16_t nb_pkts); +static int ena_add_single_rx_desc(struct ena_com_io_sq *io_sq, + struct rte_mbuf *mbuf, uint16_t id); static int ena_populate_rx_queue(struct ena_ring *rxq, unsigned int count); -static void ena_init_rings(struct ena_adapter *adapter); +static void ena_init_rings(struct ena_adapter *adapter, + bool disable_meta_caching); static int ena_mtu_set(struct rte_eth_dev *dev, uint16_t mtu); static int ena_start(struct rte_eth_dev *dev); static void ena_stop(struct rte_eth_dev *dev); @@ -313,7 +321,8 @@ static inline void ena_rx_mbuf_prepare(struct rte_mbuf *mbuf, static inline void ena_tx_mbuf_prepare(struct rte_mbuf *mbuf, struct ena_com_tx_ctx *ena_tx_ctx, - uint64_t queue_offloads) + uint64_t queue_offloads, + bool disable_meta_caching) { struct ena_com_tx_meta *ena_meta = &ena_tx_ctx->ena_meta; @@ -363,6 +372,9 @@ static inline void ena_tx_mbuf_prepare(struct rte_mbuf *mbuf, ena_meta->l3_hdr_len = mbuf->l3_len; ena_meta->l3_hdr_offset = mbuf->l2_len; + ena_tx_ctx->meta_valid = true; + } else if (disable_meta_caching) { + memset(ena_meta, 0, sizeof(*ena_meta)); ena_tx_ctx->meta_valid = true; } else { ena_tx_ctx->meta_valid = false; @@ -744,11 +756,13 @@ static void ena_rx_queue_release_bufs(struct ena_ring *ring) { unsigned int i; - for (i = 0; i < ring->ring_size; ++i) - if (ring->rx_buffer_info[i]) { - rte_mbuf_raw_free(ring->rx_buffer_info[i]); - ring->rx_buffer_info[i] = NULL; + for (i = 0; i < ring->ring_size; ++i) { + struct ena_rx_buffer *rx_info = &ring->rx_buffer_info[i]; + if (rx_info->mbuf) { + rte_mbuf_raw_free(rx_info->mbuf); + rx_info->mbuf = NULL; } + } } static void ena_tx_queue_release_bufs(struct ena_ring *ring) @@ -1261,6 +1275,7 @@ static int ena_tx_queue_setup(struct rte_eth_dev *dev, txq->next_to_clean = 0; txq->next_to_use = 0; txq->ring_size = nb_desc; + txq->size_mask = nb_desc - 1; txq->numa_socket_id = socket_id; txq->tx_buffer_info = rte_zmalloc("txq->tx_buffer_info", @@ -1356,12 +1371,13 @@ static int ena_rx_queue_setup(struct rte_eth_dev *dev, rxq->next_to_clean = 0; rxq->next_to_use = 0; rxq->ring_size = nb_desc; + rxq->size_mask = nb_desc - 1; rxq->numa_socket_id = socket_id; rxq->mb_pool = mp; rxq->rx_buffer_info = rte_zmalloc("rxq->buffer_info", - sizeof(struct rte_mbuf *) * nb_desc, - RTE_CACHE_LINE_SIZE); + sizeof(struct ena_rx_buffer) * nb_desc, + RTE_CACHE_LINE_SIZE); if (!rxq->rx_buffer_info) { PMD_DRV_LOG(ERR, "failed to alloc mem for rx buffer info\n"); return -ENOMEM; @@ -1400,12 +1416,28 @@ static int ena_rx_queue_setup(struct rte_eth_dev *dev, return 0; } +static int ena_add_single_rx_desc(struct ena_com_io_sq *io_sq, + struct rte_mbuf *mbuf, uint16_t id) +{ + struct ena_com_buf ebuf; + int rc; + + /* prepare physical address for DMA transaction */ + ebuf.paddr = mbuf->buf_iova + RTE_PKTMBUF_HEADROOM; + ebuf.len = mbuf->buf_len - RTE_PKTMBUF_HEADROOM; + + /* pass resource to device */ + rc = ena_com_add_single_rx_desc(io_sq, &ebuf, id); + if (unlikely(rc != 0)) + PMD_DRV_LOG(WARNING, "failed adding rx desc\n"); + + return rc; +} + static int ena_populate_rx_queue(struct ena_ring *rxq, unsigned int count) { unsigned int i; int rc; - uint16_t ring_size = rxq->ring_size; - uint16_t ring_mask = ring_size - 1; uint16_t next_to_use = rxq->next_to_use; uint16_t in_use, req_id; struct rte_mbuf **mbufs = rxq->rx_refill_buffer; @@ -1413,8 +1445,10 @@ static int ena_populate_rx_queue(struct ena_ring *rxq, unsigned int count) if (unlikely(!count)) return 0; - in_use = rxq->next_to_use - rxq->next_to_clean; - ena_assert_msg(((in_use + count) < ring_size), "bad ring state\n"); + in_use = rxq->ring_size - 1 - + ena_com_free_q_entries(rxq->ena_com_io_sq); + ena_assert_msg(((in_use + count) < rxq->ring_size), + "bad ring state\n"); /* get resources for incoming packets */ rc = rte_mempool_get_bulk(rxq->mb_pool, (void **)mbufs, count); @@ -1426,31 +1460,25 @@ static int ena_populate_rx_queue(struct ena_ring *rxq, unsigned int count) } for (i = 0; i < count; i++) { - uint16_t next_to_use_masked = next_to_use & ring_mask; struct rte_mbuf *mbuf = mbufs[i]; - struct ena_com_buf ebuf; + struct ena_rx_buffer *rx_info; if (likely((i + 4) < count)) rte_prefetch0(mbufs[i + 4]); - req_id = rxq->empty_rx_reqs[next_to_use_masked]; + req_id = rxq->empty_rx_reqs[next_to_use]; rc = validate_rx_req_id(rxq, req_id); - if (unlikely(rc < 0)) + if (unlikely(rc)) break; - rxq->rx_buffer_info[req_id] = mbuf; - - /* prepare physical address for DMA transaction */ - ebuf.paddr = mbuf->buf_iova + RTE_PKTMBUF_HEADROOM; - ebuf.len = mbuf->buf_len - RTE_PKTMBUF_HEADROOM; - /* pass resource to device */ - rc = ena_com_add_single_rx_desc(rxq->ena_com_io_sq, - &ebuf, req_id); - if (unlikely(rc)) { - PMD_DRV_LOG(WARNING, "failed adding rx desc\n"); - rxq->rx_buffer_info[req_id] = NULL; + + rx_info = &rxq->rx_buffer_info[req_id]; + + rc = ena_add_single_rx_desc(rxq->ena_com_io_sq, mbuf, req_id); + if (unlikely(rc != 0)) break; - } - next_to_use++; + + rx_info->mbuf = mbuf; + next_to_use = ENA_IDX_NEXT_MASKED(next_to_use, rxq->size_mask); } if (unlikely(i < count)) { @@ -1726,8 +1754,8 @@ static int eth_ena_dev_init(struct rte_eth_dev *eth_dev) const char *queue_type_str; uint32_t max_num_io_queues; int rc; - static int adapters_found; + bool disable_meta_caching; bool wd_state; eth_dev->dev_ops = &ena_dev_ops; @@ -1818,8 +1846,16 @@ static int eth_ena_dev_init(struct rte_eth_dev *eth_dev) adapter->max_rx_sgl_size = calc_queue_ctx.max_rx_sgl_size; adapter->max_num_io_queues = max_num_io_queues; + if (ena_dev->tx_mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_DEV) { + disable_meta_caching = + !!(get_feat_ctx.llq.accel_mode.u.get.supported_flags & + BIT(ENA_ADMIN_DISABLE_META_CACHING)); + } else { + disable_meta_caching = false; + } + /* prepare ring structures */ - ena_init_rings(adapter); + ena_init_rings(adapter, disable_meta_caching); ena_config_debug_area(adapter); @@ -1933,7 +1969,8 @@ static int ena_dev_configure(struct rte_eth_dev *dev) return 0; } -static void ena_init_rings(struct ena_adapter *adapter) +static void ena_init_rings(struct ena_adapter *adapter, + bool disable_meta_caching) { size_t i; @@ -1947,6 +1984,7 @@ static void ena_init_rings(struct ena_adapter *adapter) ring->tx_mem_queue_type = adapter->ena_dev.tx_mem_queue_type; ring->tx_max_header_size = adapter->ena_dev.tx_max_header_size; ring->sgl_size = adapter->max_tx_sgl_size; + ring->disable_meta_caching = disable_meta_caching; } for (i = 0; i < adapter->max_num_io_queues; i++) { @@ -2037,24 +2075,126 @@ static int ena_infos_get(struct rte_eth_dev *dev, return 0; } +static inline void ena_init_rx_mbuf(struct rte_mbuf *mbuf, uint16_t len) +{ + mbuf->data_len = len; + mbuf->data_off = RTE_PKTMBUF_HEADROOM; + mbuf->refcnt = 1; + mbuf->next = NULL; +} + +static struct rte_mbuf *ena_rx_mbuf(struct ena_ring *rx_ring, + struct ena_com_rx_buf_info *ena_bufs, + uint32_t descs, + uint16_t *next_to_clean, + uint8_t offset) +{ + struct rte_mbuf *mbuf; + struct rte_mbuf *mbuf_head; + struct ena_rx_buffer *rx_info; + int rc; + uint16_t ntc, len, req_id, buf = 0; + + if (unlikely(descs == 0)) + return NULL; + + ntc = *next_to_clean; + + len = ena_bufs[buf].len; + req_id = ena_bufs[buf].req_id; + if (unlikely(validate_rx_req_id(rx_ring, req_id))) + return NULL; + + rx_info = &rx_ring->rx_buffer_info[req_id]; + + mbuf = rx_info->mbuf; + RTE_ASSERT(mbuf != NULL); + + ena_init_rx_mbuf(mbuf, len); + + /* Fill the mbuf head with the data specific for 1st segment. */ + mbuf_head = mbuf; + mbuf_head->nb_segs = descs; + mbuf_head->port = rx_ring->port_id; + mbuf_head->pkt_len = len; + mbuf_head->data_off += offset; + + rx_info->mbuf = NULL; + rx_ring->empty_rx_reqs[ntc] = req_id; + ntc = ENA_IDX_NEXT_MASKED(ntc, rx_ring->size_mask); + + while (--descs) { + ++buf; + len = ena_bufs[buf].len; + req_id = ena_bufs[buf].req_id; + if (unlikely(validate_rx_req_id(rx_ring, req_id))) { + rte_mbuf_raw_free(mbuf_head); + return NULL; + } + + rx_info = &rx_ring->rx_buffer_info[req_id]; + RTE_ASSERT(rx_info->mbuf != NULL); + + if (unlikely(len == 0)) { + /* + * Some devices can pass descriptor with the length 0. + * To avoid confusion, the PMD is simply putting the + * descriptor back, as it was never used. We'll avoid + * mbuf allocation that way. + */ + rc = ena_add_single_rx_desc(rx_ring->ena_com_io_sq, + rx_info->mbuf, req_id); + if (unlikely(rc != 0)) { + /* Free the mbuf in case of an error. */ + rte_mbuf_raw_free(rx_info->mbuf); + } else { + /* + * If there was no error, just exit the loop as + * 0 length descriptor is always the last one. + */ + break; + } + } else { + /* Create an mbuf chain. */ + mbuf->next = rx_info->mbuf; + mbuf = mbuf->next; + + ena_init_rx_mbuf(mbuf, len); + mbuf_head->pkt_len += len; + } + + /* + * Mark the descriptor as depleted and perform necessary + * cleanup. + * This code will execute in two cases: + * 1. Descriptor len was greater than 0 - normal situation. + * 2. Descriptor len was 0 and we failed to add the descriptor + * to the device. In that situation, we should try to add + * the mbuf again in the populate routine and mark the + * descriptor as used up by the device. + */ + rx_info->mbuf = NULL; + rx_ring->empty_rx_reqs[ntc] = req_id; + ntc = ENA_IDX_NEXT_MASKED(ntc, rx_ring->size_mask); + } + + *next_to_clean = ntc; + + return mbuf_head; +} + static uint16_t eth_ena_recv_pkts(void *rx_queue, struct rte_mbuf **rx_pkts, uint16_t nb_pkts) { struct ena_ring *rx_ring = (struct ena_ring *)(rx_queue); - unsigned int ring_size = rx_ring->ring_size; - unsigned int ring_mask = ring_size - 1; + unsigned int free_queue_entries; + unsigned int refill_threshold; uint16_t next_to_clean = rx_ring->next_to_clean; - uint16_t desc_in_use = 0; - uint16_t req_id; - unsigned int recv_idx = 0; - struct rte_mbuf *mbuf = NULL; - struct rte_mbuf *mbuf_head = NULL; - struct rte_mbuf *mbuf_prev = NULL; - struct rte_mbuf **rx_buff_info = rx_ring->rx_buffer_info; - unsigned int completed; - + uint16_t descs_in_use; + struct rte_mbuf *mbuf; + uint16_t completed; struct ena_com_rx_ctx ena_rx_ctx; - int rc = 0; + int i, rc = 0; /* Check adapter state */ if (unlikely(rx_ring->adapter->state != ENA_ADAPTER_STATE_RUNNING)) { @@ -2063,13 +2203,11 @@ static uint16_t eth_ena_recv_pkts(void *rx_queue, struct rte_mbuf **rx_pkts, return 0; } - desc_in_use = rx_ring->next_to_use - next_to_clean; - if (unlikely(nb_pkts > desc_in_use)) - nb_pkts = desc_in_use; + descs_in_use = rx_ring->ring_size - + ena_com_free_q_entries(rx_ring->ena_com_io_sq) - 1; + nb_pkts = RTE_MIN(descs_in_use, nb_pkts); for (completed = 0; completed < nb_pkts; completed++) { - int segments = 0; - ena_rx_ctx.max_bufs = rx_ring->sgl_size; ena_rx_ctx.ena_bufs = rx_ring->ena_bufs; ena_rx_ctx.descs = 0; @@ -2087,73 +2225,51 @@ static uint16_t eth_ena_recv_pkts(void *rx_queue, struct rte_mbuf **rx_pkts, return 0; } - if (unlikely(ena_rx_ctx.descs == 0)) - break; - - while (segments < ena_rx_ctx.descs) { - req_id = ena_rx_ctx.ena_bufs[segments].req_id; - rc = validate_rx_req_id(rx_ring, req_id); - if (unlikely(rc)) { - if (segments != 0) - rte_mbuf_raw_free(mbuf_head); - break; - } - - mbuf = rx_buff_info[req_id]; - rx_buff_info[req_id] = NULL; - mbuf->data_len = ena_rx_ctx.ena_bufs[segments].len; - mbuf->data_off = RTE_PKTMBUF_HEADROOM; - mbuf->refcnt = 1; - mbuf->next = NULL; - if (unlikely(segments == 0)) { - mbuf->nb_segs = ena_rx_ctx.descs; - mbuf->port = rx_ring->port_id; - mbuf->pkt_len = 0; - mbuf->data_off += ena_rx_ctx.pkt_offset; - mbuf_head = mbuf; - } else { - /* for multi-segment pkts create mbuf chain */ - mbuf_prev->next = mbuf; + mbuf = ena_rx_mbuf(rx_ring, + ena_rx_ctx.ena_bufs, + ena_rx_ctx.descs, + &next_to_clean, + ena_rx_ctx.pkt_offset); + if (unlikely(mbuf == NULL)) { + for (i = 0; i < ena_rx_ctx.descs; ++i) { + rx_ring->empty_rx_reqs[next_to_clean] = + rx_ring->ena_bufs[i].req_id; + next_to_clean = ENA_IDX_NEXT_MASKED( + next_to_clean, rx_ring->size_mask); } - mbuf_head->pkt_len += mbuf->data_len; - - mbuf_prev = mbuf; - rx_ring->empty_rx_reqs[next_to_clean & ring_mask] = - req_id; - segments++; - next_to_clean++; - } - if (unlikely(rc)) break; + } /* fill mbuf attributes if any */ - ena_rx_mbuf_prepare(mbuf_head, &ena_rx_ctx); + ena_rx_mbuf_prepare(mbuf, &ena_rx_ctx); - if (unlikely(mbuf_head->ol_flags & + if (unlikely(mbuf->ol_flags & (PKT_RX_IP_CKSUM_BAD | PKT_RX_L4_CKSUM_BAD))) { rte_atomic64_inc(&rx_ring->adapter->drv_stats->ierrors); ++rx_ring->rx_stats.bad_csum; } - mbuf_head->hash.rss = ena_rx_ctx.hash; + mbuf->hash.rss = ena_rx_ctx.hash; - /* pass to DPDK application head mbuf */ - rx_pkts[recv_idx] = mbuf_head; - recv_idx++; - rx_ring->rx_stats.bytes += mbuf_head->pkt_len; + rx_pkts[completed] = mbuf; + rx_ring->rx_stats.bytes += mbuf->pkt_len; } - rx_ring->rx_stats.cnt += recv_idx; + rx_ring->rx_stats.cnt += completed; rx_ring->next_to_clean = next_to_clean; - desc_in_use = desc_in_use - completed + 1; + free_queue_entries = ena_com_free_q_entries(rx_ring->ena_com_io_sq); + refill_threshold = + RTE_MIN(rx_ring->ring_size / ENA_REFILL_THRESH_DIVIDER, + (unsigned int)ENA_REFILL_THRESH_PACKET); + /* Burst refill to save doorbells, memory barriers, const interval */ - if (ring_size - desc_in_use > ENA_RING_DESCS_RATIO(ring_size)) { + if (free_queue_entries > refill_threshold) { ena_com_update_dev_comp_head(rx_ring->ena_com_io_cq); - ena_populate_rx_queue(rx_ring, ring_size - desc_in_use); + ena_populate_rx_queue(rx_ring, free_queue_entries); } - return recv_idx; + return completed; } static uint16_t @@ -2279,188 +2395,221 @@ static int ena_check_and_linearize_mbuf(struct ena_ring *tx_ring, return rc; } -static uint16_t eth_ena_xmit_pkts(void *tx_queue, struct rte_mbuf **tx_pkts, - uint16_t nb_pkts) +static void ena_tx_map_mbuf(struct ena_ring *tx_ring, + struct ena_tx_buffer *tx_info, + struct rte_mbuf *mbuf, + void **push_header, + uint16_t *header_len) { - struct ena_ring *tx_ring = (struct ena_ring *)(tx_queue); - uint16_t next_to_use = tx_ring->next_to_use; - uint16_t next_to_clean = tx_ring->next_to_clean; - struct rte_mbuf *mbuf; - uint16_t seg_len; - unsigned int ring_size = tx_ring->ring_size; - unsigned int ring_mask = ring_size - 1; - struct ena_com_tx_ctx ena_tx_ctx; - struct ena_tx_buffer *tx_info; - struct ena_com_buf *ebuf; - uint16_t rc, req_id, total_tx_descs = 0; - uint16_t sent_idx = 0, empty_tx_reqs; - uint16_t push_len = 0; - uint16_t delta = 0; - int nb_hw_desc; - uint32_t total_length; + struct ena_com_buf *ena_buf; + uint16_t delta, seg_len, push_len; - /* Check adapter state */ - if (unlikely(tx_ring->adapter->state != ENA_ADAPTER_STATE_RUNNING)) { - PMD_DRV_LOG(ALERT, - "Trying to xmit pkts while device is NOT running\n"); - return 0; - } + delta = 0; + seg_len = mbuf->data_len; - empty_tx_reqs = ring_size - (next_to_use - next_to_clean); - if (nb_pkts > empty_tx_reqs) - nb_pkts = empty_tx_reqs; + tx_info->mbuf = mbuf; + ena_buf = tx_info->bufs; - for (sent_idx = 0; sent_idx < nb_pkts; sent_idx++) { - mbuf = tx_pkts[sent_idx]; - total_length = 0; + if (tx_ring->tx_mem_queue_type == ENA_ADMIN_PLACEMENT_POLICY_DEV) { + /* + * Tx header might be (and will be in most cases) smaller than + * tx_max_header_size. But it's not an issue to send more data + * to the device, than actually needed if the mbuf size is + * greater than tx_max_header_size. + */ + push_len = RTE_MIN(mbuf->pkt_len, tx_ring->tx_max_header_size); + *header_len = push_len; - rc = ena_check_and_linearize_mbuf(tx_ring, mbuf); - if (unlikely(rc)) - break; + if (likely(push_len <= seg_len)) { + /* If the push header is in the single segment, then + * just point it to the 1st mbuf data. + */ + *push_header = rte_pktmbuf_mtod(mbuf, uint8_t *); + } else { + /* If the push header lays in the several segments, copy + * it to the intermediate buffer. + */ + rte_pktmbuf_read(mbuf, 0, push_len, + tx_ring->push_buf_intermediate_buf); + *push_header = tx_ring->push_buf_intermediate_buf; + delta = push_len - seg_len; + } + } else { + *push_header = NULL; + *header_len = 0; + push_len = 0; + } - req_id = tx_ring->empty_tx_reqs[next_to_use & ring_mask]; - tx_info = &tx_ring->tx_buffer_info[req_id]; - tx_info->mbuf = mbuf; - tx_info->num_of_bufs = 0; - ebuf = tx_info->bufs; + /* Process first segment taking into consideration pushed header */ + if (seg_len > push_len) { + ena_buf->paddr = mbuf->buf_iova + + mbuf->data_off + + push_len; + ena_buf->len = seg_len - push_len; + ena_buf++; + tx_info->num_of_bufs++; + } + + while ((mbuf = mbuf->next) != NULL) { + seg_len = mbuf->data_len; - /* Prepare TX context */ - memset(&ena_tx_ctx, 0x0, sizeof(struct ena_com_tx_ctx)); - memset(&ena_tx_ctx.ena_meta, 0x0, - sizeof(struct ena_com_tx_meta)); - ena_tx_ctx.ena_bufs = ebuf; - ena_tx_ctx.req_id = req_id; + /* Skip mbufs if whole data is pushed as a header */ + if (unlikely(delta > seg_len)) { + delta -= seg_len; + continue; + } + + ena_buf->paddr = mbuf->buf_iova + mbuf->data_off + delta; + ena_buf->len = seg_len - delta; + ena_buf++; + tx_info->num_of_bufs++; delta = 0; - seg_len = mbuf->data_len; + } +} - if (tx_ring->tx_mem_queue_type == - ENA_ADMIN_PLACEMENT_POLICY_DEV) { - push_len = RTE_MIN(mbuf->pkt_len, - tx_ring->tx_max_header_size); - ena_tx_ctx.header_len = push_len; +static int ena_xmit_mbuf(struct ena_ring *tx_ring, struct rte_mbuf *mbuf) +{ + struct ena_tx_buffer *tx_info; + struct ena_com_tx_ctx ena_tx_ctx = { { 0 } }; + uint16_t next_to_use; + uint16_t header_len; + uint16_t req_id; + void *push_header; + int nb_hw_desc; + int rc; - if (likely(push_len <= seg_len)) { - /* If the push header is in the single segment, - * then just point it to the 1st mbuf data. - */ - ena_tx_ctx.push_header = - rte_pktmbuf_mtod(mbuf, uint8_t *); - } else { - /* If the push header lays in the several - * segments, copy it to the intermediate buffer. - */ - rte_pktmbuf_read(mbuf, 0, push_len, - tx_ring->push_buf_intermediate_buf); - ena_tx_ctx.push_header = - tx_ring->push_buf_intermediate_buf; - delta = push_len - seg_len; - } - } /* there's no else as we take advantage of memset zeroing */ + rc = ena_check_and_linearize_mbuf(tx_ring, mbuf); + if (unlikely(rc)) + return rc; - /* Set TX offloads flags, if applicable */ - ena_tx_mbuf_prepare(mbuf, &ena_tx_ctx, tx_ring->offloads); + next_to_use = tx_ring->next_to_use; - rte_prefetch0(tx_pkts[(sent_idx + 4) & ring_mask]); + req_id = tx_ring->empty_tx_reqs[next_to_use]; + tx_info = &tx_ring->tx_buffer_info[req_id]; + tx_info->num_of_bufs = 0; - /* Process first segment taking into - * consideration pushed header - */ - if (seg_len > push_len) { - ebuf->paddr = mbuf->buf_iova + - mbuf->data_off + - push_len; - ebuf->len = seg_len - push_len; - ebuf++; - tx_info->num_of_bufs++; - } - total_length += mbuf->data_len; + ena_tx_map_mbuf(tx_ring, tx_info, mbuf, &push_header, &header_len); - while ((mbuf = mbuf->next) != NULL) { - seg_len = mbuf->data_len; + ena_tx_ctx.ena_bufs = tx_info->bufs; + ena_tx_ctx.push_header = push_header; + ena_tx_ctx.num_bufs = tx_info->num_of_bufs; + ena_tx_ctx.req_id = req_id; + ena_tx_ctx.header_len = header_len; - /* Skip mbufs if whole data is pushed as a header */ - if (unlikely(delta > seg_len)) { - delta -= seg_len; - continue; - } + /* Set Tx offloads flags, if applicable */ + ena_tx_mbuf_prepare(mbuf, &ena_tx_ctx, tx_ring->offloads, + tx_ring->disable_meta_caching); - ebuf->paddr = mbuf->buf_iova + mbuf->data_off + delta; - ebuf->len = seg_len - delta; - total_length += ebuf->len; - ebuf++; - tx_info->num_of_bufs++; + if (unlikely(ena_com_is_doorbell_needed(tx_ring->ena_com_io_sq, + &ena_tx_ctx))) { + PMD_DRV_LOG(DEBUG, + "llq tx max burst size of queue %d achieved, writing doorbell to send burst\n", + tx_ring->id); + ena_com_write_sq_doorbell(tx_ring->ena_com_io_sq); + } - delta = 0; - } + /* prepare the packet's descriptors to dma engine */ + rc = ena_com_prepare_tx(tx_ring->ena_com_io_sq, &ena_tx_ctx, + &nb_hw_desc); + if (unlikely(rc)) { + ++tx_ring->tx_stats.prepare_ctx_err; + return rc; + } - ena_tx_ctx.num_bufs = tx_info->num_of_bufs; + tx_info->tx_descs = nb_hw_desc; - if (ena_com_is_doorbell_needed(tx_ring->ena_com_io_sq, - &ena_tx_ctx)) { - PMD_DRV_LOG(DEBUG, "llq tx max burst size of queue %d" - " achieved, writing doorbell to send burst\n", - tx_ring->id); - ena_com_write_sq_doorbell(tx_ring->ena_com_io_sq); - } + tx_ring->tx_stats.cnt++; + tx_ring->tx_stats.bytes += mbuf->pkt_len; - /* prepare the packet's descriptors to dma engine */ - rc = ena_com_prepare_tx(tx_ring->ena_com_io_sq, - &ena_tx_ctx, &nb_hw_desc); - if (unlikely(rc)) { - ++tx_ring->tx_stats.prepare_ctx_err; - break; - } - tx_info->tx_descs = nb_hw_desc; + tx_ring->next_to_use = ENA_IDX_NEXT_MASKED(next_to_use, + tx_ring->size_mask); - next_to_use++; - tx_ring->tx_stats.cnt++; - tx_ring->tx_stats.bytes += total_length; - } - tx_ring->tx_stats.available_desc = - ena_com_free_q_entries(tx_ring->ena_com_io_sq); + return 0; +} - /* If there are ready packets to be xmitted... */ - if (sent_idx > 0) { - /* ...let HW do its best :-) */ - ena_com_write_sq_doorbell(tx_ring->ena_com_io_sq); - tx_ring->tx_stats.doorbells++; - tx_ring->next_to_use = next_to_use; - } +static void ena_tx_cleanup(struct ena_ring *tx_ring) +{ + unsigned int cleanup_budget; + unsigned int total_tx_descs = 0; + uint16_t next_to_clean = tx_ring->next_to_clean; - /* Clear complete packets */ - while (ena_com_tx_comp_req_id_get(tx_ring->ena_com_io_cq, &req_id) >= 0) { - rc = validate_tx_req_id(tx_ring, req_id); - if (rc) + cleanup_budget = RTE_MIN(tx_ring->ring_size / ENA_REFILL_THRESH_DIVIDER, + (unsigned int)ENA_REFILL_THRESH_PACKET); + + while (likely(total_tx_descs < cleanup_budget)) { + struct rte_mbuf *mbuf; + struct ena_tx_buffer *tx_info; + uint16_t req_id; + + if (ena_com_tx_comp_req_id_get(tx_ring->ena_com_io_cq, &req_id) != 0) + break; + + if (unlikely(validate_tx_req_id(tx_ring, req_id) != 0)) break; /* Get Tx info & store how many descs were processed */ tx_info = &tx_ring->tx_buffer_info[req_id]; - total_tx_descs += tx_info->tx_descs; - /* Free whole mbuf chain */ mbuf = tx_info->mbuf; rte_pktmbuf_free(mbuf); + tx_info->mbuf = NULL; + tx_ring->empty_tx_reqs[next_to_clean] = req_id; - /* Put back descriptor to the ring for reuse */ - tx_ring->empty_tx_reqs[next_to_clean & ring_mask] = req_id; - next_to_clean++; + total_tx_descs += tx_info->tx_descs; - /* If too many descs to clean, leave it for another run */ - if (unlikely(total_tx_descs > ENA_RING_DESCS_RATIO(ring_size))) - break; + /* Put back descriptor to the ring for reuse */ + next_to_clean = ENA_IDX_NEXT_MASKED(next_to_clean, + tx_ring->size_mask); } - tx_ring->tx_stats.available_desc = - ena_com_free_q_entries(tx_ring->ena_com_io_sq); - if (total_tx_descs > 0) { + if (likely(total_tx_descs > 0)) { /* acknowledge completion of sent packets */ tx_ring->next_to_clean = next_to_clean; ena_com_comp_ack(tx_ring->ena_com_io_sq, total_tx_descs); ena_com_update_dev_comp_head(tx_ring->ena_com_io_cq); } +} + +static uint16_t eth_ena_xmit_pkts(void *tx_queue, struct rte_mbuf **tx_pkts, + uint16_t nb_pkts) +{ + struct ena_ring *tx_ring = (struct ena_ring *)(tx_queue); + uint16_t sent_idx = 0; + /* Check adapter state */ + if (unlikely(tx_ring->adapter->state != ENA_ADAPTER_STATE_RUNNING)) { + PMD_DRV_LOG(ALERT, + "Trying to xmit pkts while device is NOT running\n"); + return 0; + } + + nb_pkts = RTE_MIN(ena_com_free_q_entries(tx_ring->ena_com_io_sq), + nb_pkts); + + for (sent_idx = 0; sent_idx < nb_pkts; sent_idx++) { + if (ena_xmit_mbuf(tx_ring, tx_pkts[sent_idx])) + break; + + rte_prefetch0(tx_pkts[ENA_IDX_ADD_MASKED(sent_idx, 4, + tx_ring->size_mask)]); + } + + tx_ring->tx_stats.available_desc = + ena_com_free_q_entries(tx_ring->ena_com_io_sq); + + /* If there are ready packets to be xmitted... */ + if (sent_idx > 0) { + /* ...let HW do its best :-) */ + ena_com_write_sq_doorbell(tx_ring->ena_com_io_sq); + tx_ring->tx_stats.doorbells++; + } + + ena_tx_cleanup(tx_ring); + + tx_ring->tx_stats.available_desc = + ena_com_free_q_entries(tx_ring->ena_com_io_sq); tx_ring->tx_stats.tx_poll++; return sent_idx;