1a8ad8cf8SIvan Malov /*- 2a8ad8cf8SIvan Malov * Copyright (c) 2016 Solarflare Communications Inc. 3a8ad8cf8SIvan Malov * All rights reserved. 4a8ad8cf8SIvan Malov * 5a8ad8cf8SIvan Malov * This software was jointly developed between OKTET Labs (under contract 6a8ad8cf8SIvan Malov * for Solarflare) and Solarflare Communications, Inc. 7a8ad8cf8SIvan Malov * 8a8ad8cf8SIvan Malov * Redistribution and use in source and binary forms, with or without 9a8ad8cf8SIvan Malov * modification, are permitted provided that the following conditions are met: 10a8ad8cf8SIvan Malov * 11a8ad8cf8SIvan Malov * 1. Redistributions of source code must retain the above copyright notice, 12a8ad8cf8SIvan Malov * this list of conditions and the following disclaimer. 13a8ad8cf8SIvan Malov * 2. Redistributions in binary form must reproduce the above copyright notice, 14a8ad8cf8SIvan Malov * this list of conditions and the following disclaimer in the documentation 15a8ad8cf8SIvan Malov * and/or other materials provided with the distribution. 16a8ad8cf8SIvan Malov * 17a8ad8cf8SIvan Malov * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18a8ad8cf8SIvan Malov * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 19a8ad8cf8SIvan Malov * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 20a8ad8cf8SIvan Malov * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 21a8ad8cf8SIvan Malov * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 22a8ad8cf8SIvan Malov * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 23a8ad8cf8SIvan Malov * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 24a8ad8cf8SIvan Malov * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 25a8ad8cf8SIvan Malov * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 26a8ad8cf8SIvan Malov * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 27a8ad8cf8SIvan Malov * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28a8ad8cf8SIvan Malov */ 29a8ad8cf8SIvan Malov 30a8ad8cf8SIvan Malov #include "sfc.h" 31fed9aeb4SIvan Malov #include "sfc_debug.h" 32a8ad8cf8SIvan Malov #include "sfc_log.h" 33a8ad8cf8SIvan Malov #include "sfc_ev.h" 34a8ad8cf8SIvan Malov #include "sfc_tx.h" 35428c7dddSIvan Malov #include "sfc_tweak.h" 36a8ad8cf8SIvan Malov 37fed9aeb4SIvan Malov /* 38fed9aeb4SIvan Malov * Maximum number of TX queue flush attempts in case of 39fed9aeb4SIvan Malov * failure or flush timeout 40fed9aeb4SIvan Malov */ 41fed9aeb4SIvan Malov #define SFC_TX_QFLUSH_ATTEMPTS (3) 42fed9aeb4SIvan Malov 43fed9aeb4SIvan Malov /* 44fed9aeb4SIvan Malov * Time to wait between event queue polling attempts when waiting for TX 45fed9aeb4SIvan Malov * queue flush done or flush failed events 46fed9aeb4SIvan Malov */ 47fed9aeb4SIvan Malov #define SFC_TX_QFLUSH_POLL_WAIT_MS (1) 48fed9aeb4SIvan Malov 49fed9aeb4SIvan Malov /* 50fed9aeb4SIvan Malov * Maximum number of event queue polling attempts when waiting for TX queue 51fed9aeb4SIvan Malov * flush done or flush failed events; it defines TX queue flush attempt timeout 52fed9aeb4SIvan Malov * together with SFC_TX_QFLUSH_POLL_WAIT_MS 53fed9aeb4SIvan Malov */ 54fed9aeb4SIvan Malov #define SFC_TX_QFLUSH_POLL_ATTEMPTS (2000) 55fed9aeb4SIvan Malov 56a8ad8cf8SIvan Malov static int 5721f6411cSIvan Malov sfc_tx_qcheck_conf(struct sfc_adapter *sa, uint16_t nb_tx_desc, 58b1b7ad93SIvan Malov const struct rte_eth_txconf *tx_conf) 59b1b7ad93SIvan Malov { 60b1b7ad93SIvan Malov unsigned int flags = tx_conf->txq_flags; 61b1b7ad93SIvan Malov int rc = 0; 62b1b7ad93SIvan Malov 63b1b7ad93SIvan Malov if (tx_conf->tx_rs_thresh != 0) { 64b1b7ad93SIvan Malov sfc_err(sa, "RS bit in transmit descriptor is not supported"); 65b1b7ad93SIvan Malov rc = EINVAL; 66b1b7ad93SIvan Malov } 67b1b7ad93SIvan Malov 6821f6411cSIvan Malov if (tx_conf->tx_free_thresh > EFX_TXQ_LIMIT(nb_tx_desc)) { 69b1b7ad93SIvan Malov sfc_err(sa, 7021f6411cSIvan Malov "TxQ free threshold too large: %u vs maximum %u", 7121f6411cSIvan Malov tx_conf->tx_free_thresh, EFX_TXQ_LIMIT(nb_tx_desc)); 72b1b7ad93SIvan Malov rc = EINVAL; 73b1b7ad93SIvan Malov } 74b1b7ad93SIvan Malov 75b1b7ad93SIvan Malov if (tx_conf->tx_thresh.pthresh != 0 || 76b1b7ad93SIvan Malov tx_conf->tx_thresh.hthresh != 0 || 77b1b7ad93SIvan Malov tx_conf->tx_thresh.wthresh != 0) { 78b1b7ad93SIvan Malov sfc_err(sa, 79b1b7ad93SIvan Malov "prefetch/host/writeback thresholds are not supported"); 80b1b7ad93SIvan Malov rc = EINVAL; 81b1b7ad93SIvan Malov } 82b1b7ad93SIvan Malov 83b1b7ad93SIvan Malov if ((flags & ETH_TXQ_FLAGS_NOVLANOFFL) == 0) { 84b1b7ad93SIvan Malov sfc_err(sa, "VLAN offload is not supported"); 85b1b7ad93SIvan Malov rc = EINVAL; 86b1b7ad93SIvan Malov } 87b1b7ad93SIvan Malov 88b1b7ad93SIvan Malov if ((flags & ETH_TXQ_FLAGS_NOXSUMSCTP) == 0) { 89b1b7ad93SIvan Malov sfc_err(sa, "SCTP offload is not supported"); 90b1b7ad93SIvan Malov rc = EINVAL; 91b1b7ad93SIvan Malov } 92b1b7ad93SIvan Malov 93b1b7ad93SIvan Malov /* We either perform both TCP and UDP offload, or no offload at all */ 94b1b7ad93SIvan Malov if (((flags & ETH_TXQ_FLAGS_NOXSUMTCP) == 0) != 95b1b7ad93SIvan Malov ((flags & ETH_TXQ_FLAGS_NOXSUMUDP) == 0)) { 96b1b7ad93SIvan Malov sfc_err(sa, "TCP and UDP offloads can't be set independently"); 97b1b7ad93SIvan Malov rc = EINVAL; 98b1b7ad93SIvan Malov } 99b1b7ad93SIvan Malov 100b1b7ad93SIvan Malov return rc; 101b1b7ad93SIvan Malov } 102b1b7ad93SIvan Malov 103fed9aeb4SIvan Malov void 104fed9aeb4SIvan Malov sfc_tx_qflush_done(struct sfc_txq *txq) 105fed9aeb4SIvan Malov { 106fed9aeb4SIvan Malov txq->state |= SFC_TXQ_FLUSHED; 107fed9aeb4SIvan Malov txq->state &= ~SFC_TXQ_FLUSHING; 108fed9aeb4SIvan Malov } 109fed9aeb4SIvan Malov 110fed9aeb4SIvan Malov static void 111fed9aeb4SIvan Malov sfc_tx_reap(struct sfc_txq *txq) 112fed9aeb4SIvan Malov { 113fed9aeb4SIvan Malov unsigned int completed; 114fed9aeb4SIvan Malov 115fed9aeb4SIvan Malov 116fed9aeb4SIvan Malov sfc_ev_qpoll(txq->evq); 117fed9aeb4SIvan Malov 118fed9aeb4SIvan Malov for (completed = txq->completed; 119fed9aeb4SIvan Malov completed != txq->pending; completed++) { 120fed9aeb4SIvan Malov struct sfc_tx_sw_desc *txd; 121fed9aeb4SIvan Malov 122fed9aeb4SIvan Malov txd = &txq->sw_ring[completed & txq->ptr_mask]; 123fed9aeb4SIvan Malov 124fed9aeb4SIvan Malov if (txd->mbuf != NULL) { 125fed9aeb4SIvan Malov rte_pktmbuf_free(txd->mbuf); 126fed9aeb4SIvan Malov txd->mbuf = NULL; 127fed9aeb4SIvan Malov } 128fed9aeb4SIvan Malov } 129fed9aeb4SIvan Malov 130fed9aeb4SIvan Malov txq->completed = completed; 131fed9aeb4SIvan Malov } 132fed9aeb4SIvan Malov 133b1b7ad93SIvan Malov int 134b1b7ad93SIvan Malov sfc_tx_qinit(struct sfc_adapter *sa, unsigned int sw_index, 135b1b7ad93SIvan Malov uint16_t nb_tx_desc, unsigned int socket_id, 136b1b7ad93SIvan Malov const struct rte_eth_txconf *tx_conf) 137b1b7ad93SIvan Malov { 138b1b7ad93SIvan Malov struct sfc_txq_info *txq_info; 139b1b7ad93SIvan Malov struct sfc_evq *evq; 140b1b7ad93SIvan Malov struct sfc_txq *txq; 141b1b7ad93SIvan Malov unsigned int evq_index = sfc_evq_index_by_txq_sw_index(sa, sw_index); 142b1b7ad93SIvan Malov int rc = 0; 143b1b7ad93SIvan Malov 144b1b7ad93SIvan Malov sfc_log_init(sa, "TxQ = %u", sw_index); 145b1b7ad93SIvan Malov 14621f6411cSIvan Malov rc = sfc_tx_qcheck_conf(sa, nb_tx_desc, tx_conf); 147b1b7ad93SIvan Malov if (rc != 0) 148b1b7ad93SIvan Malov goto fail_bad_conf; 149b1b7ad93SIvan Malov 150b1b7ad93SIvan Malov SFC_ASSERT(sw_index < sa->txq_count); 151b1b7ad93SIvan Malov txq_info = &sa->txq_info[sw_index]; 152b1b7ad93SIvan Malov 153b1b7ad93SIvan Malov SFC_ASSERT(nb_tx_desc <= sa->txq_max_entries); 154b1b7ad93SIvan Malov txq_info->entries = nb_tx_desc; 155b1b7ad93SIvan Malov 156b1b7ad93SIvan Malov rc = sfc_ev_qinit(sa, evq_index, txq_info->entries, socket_id); 157b1b7ad93SIvan Malov if (rc != 0) 158b1b7ad93SIvan Malov goto fail_ev_qinit; 159b1b7ad93SIvan Malov 160b1b7ad93SIvan Malov evq = sa->evq_info[evq_index].evq; 161b1b7ad93SIvan Malov 162b1b7ad93SIvan Malov rc = ENOMEM; 163b1b7ad93SIvan Malov txq = rte_zmalloc_socket("sfc-txq", sizeof(*txq), 0, socket_id); 164b1b7ad93SIvan Malov if (txq == NULL) 165b1b7ad93SIvan Malov goto fail_txq_alloc; 166b1b7ad93SIvan Malov 167b1b7ad93SIvan Malov rc = sfc_dma_alloc(sa, "txq", sw_index, EFX_TXQ_SIZE(txq_info->entries), 168b1b7ad93SIvan Malov socket_id, &txq->mem); 169b1b7ad93SIvan Malov if (rc != 0) 170b1b7ad93SIvan Malov goto fail_dma_alloc; 171b1b7ad93SIvan Malov 172b1b7ad93SIvan Malov rc = ENOMEM; 173b1b7ad93SIvan Malov txq->pend_desc = rte_calloc_socket("sfc-txq-pend-desc", 174b1b7ad93SIvan Malov EFX_TXQ_LIMIT(txq_info->entries), 175b1b7ad93SIvan Malov sizeof(efx_desc_t), 0, socket_id); 176b1b7ad93SIvan Malov if (txq->pend_desc == NULL) 177b1b7ad93SIvan Malov goto fail_pend_desc_alloc; 178b1b7ad93SIvan Malov 179b1b7ad93SIvan Malov rc = ENOMEM; 180b1b7ad93SIvan Malov txq->sw_ring = rte_calloc_socket("sfc-txq-desc", txq_info->entries, 181b1b7ad93SIvan Malov sizeof(*txq->sw_ring), 0, socket_id); 182b1b7ad93SIvan Malov if (txq->sw_ring == NULL) 183b1b7ad93SIvan Malov goto fail_desc_alloc; 184b1b7ad93SIvan Malov 185b1b7ad93SIvan Malov txq->state = SFC_TXQ_INITIALIZED; 186b1b7ad93SIvan Malov txq->ptr_mask = txq_info->entries - 1; 18721f6411cSIvan Malov txq->free_thresh = (tx_conf->tx_free_thresh) ? tx_conf->tx_free_thresh : 18821f6411cSIvan Malov SFC_TX_DEFAULT_FREE_THRESH; 189b1b7ad93SIvan Malov txq->hw_index = sw_index; 190b1b7ad93SIvan Malov txq->flags = tx_conf->txq_flags; 191b1b7ad93SIvan Malov txq->evq = evq; 192b1b7ad93SIvan Malov 193b1b7ad93SIvan Malov evq->txq = txq; 194b1b7ad93SIvan Malov 195b1b7ad93SIvan Malov txq_info->txq = txq; 196*c6a1d9b5SIvan Malov txq_info->deferred_start = (tx_conf->tx_deferred_start != 0); 197b1b7ad93SIvan Malov 198b1b7ad93SIvan Malov return 0; 199b1b7ad93SIvan Malov 200b1b7ad93SIvan Malov fail_desc_alloc: 201b1b7ad93SIvan Malov rte_free(txq->pend_desc); 202b1b7ad93SIvan Malov 203b1b7ad93SIvan Malov fail_pend_desc_alloc: 204b1b7ad93SIvan Malov sfc_dma_free(sa, &txq->mem); 205b1b7ad93SIvan Malov 206b1b7ad93SIvan Malov fail_dma_alloc: 207b1b7ad93SIvan Malov rte_free(txq); 208b1b7ad93SIvan Malov 209b1b7ad93SIvan Malov fail_txq_alloc: 210b1b7ad93SIvan Malov sfc_ev_qfini(sa, evq_index); 211b1b7ad93SIvan Malov 212b1b7ad93SIvan Malov fail_ev_qinit: 213b1b7ad93SIvan Malov txq_info->entries = 0; 214b1b7ad93SIvan Malov 215b1b7ad93SIvan Malov fail_bad_conf: 216b1b7ad93SIvan Malov sfc_log_init(sa, "failed (TxQ = %u, rc = %d)", sw_index, rc); 217b1b7ad93SIvan Malov return rc; 218b1b7ad93SIvan Malov } 219b1b7ad93SIvan Malov 220b1b7ad93SIvan Malov void 221b1b7ad93SIvan Malov sfc_tx_qfini(struct sfc_adapter *sa, unsigned int sw_index) 222b1b7ad93SIvan Malov { 223b1b7ad93SIvan Malov struct sfc_txq_info *txq_info; 224b1b7ad93SIvan Malov struct sfc_txq *txq; 225b1b7ad93SIvan Malov 226b1b7ad93SIvan Malov sfc_log_init(sa, "TxQ = %u", sw_index); 227b1b7ad93SIvan Malov 228b1b7ad93SIvan Malov SFC_ASSERT(sw_index < sa->txq_count); 229b1b7ad93SIvan Malov txq_info = &sa->txq_info[sw_index]; 230b1b7ad93SIvan Malov 231b1b7ad93SIvan Malov txq = txq_info->txq; 232b1b7ad93SIvan Malov SFC_ASSERT(txq != NULL); 233b1b7ad93SIvan Malov SFC_ASSERT(txq->state == SFC_TXQ_INITIALIZED); 234b1b7ad93SIvan Malov 235b1b7ad93SIvan Malov txq_info->txq = NULL; 236b1b7ad93SIvan Malov txq_info->entries = 0; 237b1b7ad93SIvan Malov 238b1b7ad93SIvan Malov rte_free(txq->sw_ring); 239b1b7ad93SIvan Malov rte_free(txq->pend_desc); 240b1b7ad93SIvan Malov sfc_dma_free(sa, &txq->mem); 241b1b7ad93SIvan Malov rte_free(txq); 242b1b7ad93SIvan Malov } 243b1b7ad93SIvan Malov 244b1b7ad93SIvan Malov static int 245a8ad8cf8SIvan Malov sfc_tx_qinit_info(struct sfc_adapter *sa, unsigned int sw_index) 246a8ad8cf8SIvan Malov { 247a8ad8cf8SIvan Malov sfc_log_init(sa, "TxQ = %u", sw_index); 248a8ad8cf8SIvan Malov 249a8ad8cf8SIvan Malov return 0; 250a8ad8cf8SIvan Malov } 251a8ad8cf8SIvan Malov 252dbf0f627SIvan Malov static int 253dbf0f627SIvan Malov sfc_tx_check_mode(struct sfc_adapter *sa, const struct rte_eth_txmode *txmode) 254dbf0f627SIvan Malov { 255dbf0f627SIvan Malov int rc = 0; 256dbf0f627SIvan Malov 257dbf0f627SIvan Malov switch (txmode->mq_mode) { 258dbf0f627SIvan Malov case ETH_MQ_TX_NONE: 259dbf0f627SIvan Malov break; 260dbf0f627SIvan Malov default: 261dbf0f627SIvan Malov sfc_err(sa, "Tx multi-queue mode %u not supported", 262dbf0f627SIvan Malov txmode->mq_mode); 263dbf0f627SIvan Malov rc = EINVAL; 264dbf0f627SIvan Malov } 265dbf0f627SIvan Malov 266dbf0f627SIvan Malov /* 267dbf0f627SIvan Malov * These features are claimed to be i40e-specific, 268dbf0f627SIvan Malov * but it does make sense to double-check their absence 269dbf0f627SIvan Malov */ 270dbf0f627SIvan Malov if (txmode->hw_vlan_reject_tagged) { 271dbf0f627SIvan Malov sfc_err(sa, "Rejecting tagged packets not supported"); 272dbf0f627SIvan Malov rc = EINVAL; 273dbf0f627SIvan Malov } 274dbf0f627SIvan Malov 275dbf0f627SIvan Malov if (txmode->hw_vlan_reject_untagged) { 276dbf0f627SIvan Malov sfc_err(sa, "Rejecting untagged packets not supported"); 277dbf0f627SIvan Malov rc = EINVAL; 278dbf0f627SIvan Malov } 279dbf0f627SIvan Malov 280dbf0f627SIvan Malov if (txmode->hw_vlan_insert_pvid) { 281dbf0f627SIvan Malov sfc_err(sa, "Port-based VLAN insertion not supported"); 282dbf0f627SIvan Malov rc = EINVAL; 283dbf0f627SIvan Malov } 284dbf0f627SIvan Malov 285dbf0f627SIvan Malov return rc; 286dbf0f627SIvan Malov } 287dbf0f627SIvan Malov 288a8ad8cf8SIvan Malov int 289a8ad8cf8SIvan Malov sfc_tx_init(struct sfc_adapter *sa) 290a8ad8cf8SIvan Malov { 291dbf0f627SIvan Malov const struct rte_eth_conf *dev_conf = &sa->eth_dev->data->dev_conf; 292a8ad8cf8SIvan Malov unsigned int sw_index; 293a8ad8cf8SIvan Malov int rc = 0; 294a8ad8cf8SIvan Malov 295dbf0f627SIvan Malov rc = sfc_tx_check_mode(sa, &dev_conf->txmode); 296dbf0f627SIvan Malov if (rc != 0) 297dbf0f627SIvan Malov goto fail_check_mode; 298dbf0f627SIvan Malov 299a8ad8cf8SIvan Malov sa->txq_count = sa->eth_dev->data->nb_tx_queues; 300a8ad8cf8SIvan Malov 301a8ad8cf8SIvan Malov sa->txq_info = rte_calloc_socket("sfc-txqs", sa->txq_count, 302a8ad8cf8SIvan Malov sizeof(sa->txq_info[0]), 0, 303a8ad8cf8SIvan Malov sa->socket_id); 304a8ad8cf8SIvan Malov if (sa->txq_info == NULL) 305a8ad8cf8SIvan Malov goto fail_txqs_alloc; 306a8ad8cf8SIvan Malov 307a8ad8cf8SIvan Malov for (sw_index = 0; sw_index < sa->txq_count; ++sw_index) { 308a8ad8cf8SIvan Malov rc = sfc_tx_qinit_info(sa, sw_index); 309a8ad8cf8SIvan Malov if (rc != 0) 310a8ad8cf8SIvan Malov goto fail_tx_qinit_info; 311a8ad8cf8SIvan Malov } 312a8ad8cf8SIvan Malov 313a8ad8cf8SIvan Malov return 0; 314a8ad8cf8SIvan Malov 315a8ad8cf8SIvan Malov fail_tx_qinit_info: 316a8ad8cf8SIvan Malov rte_free(sa->txq_info); 317a8ad8cf8SIvan Malov sa->txq_info = NULL; 318a8ad8cf8SIvan Malov 319a8ad8cf8SIvan Malov fail_txqs_alloc: 320a8ad8cf8SIvan Malov sa->txq_count = 0; 321a8ad8cf8SIvan Malov 322dbf0f627SIvan Malov fail_check_mode: 323a8ad8cf8SIvan Malov sfc_log_init(sa, "failed (rc = %d)", rc); 324a8ad8cf8SIvan Malov return rc; 325a8ad8cf8SIvan Malov } 326a8ad8cf8SIvan Malov 327a8ad8cf8SIvan Malov void 328a8ad8cf8SIvan Malov sfc_tx_fini(struct sfc_adapter *sa) 329a8ad8cf8SIvan Malov { 330b1b7ad93SIvan Malov int sw_index; 331b1b7ad93SIvan Malov 332b1b7ad93SIvan Malov sw_index = sa->txq_count; 333b1b7ad93SIvan Malov while (--sw_index >= 0) { 334b1b7ad93SIvan Malov if (sa->txq_info[sw_index].txq != NULL) 335b1b7ad93SIvan Malov sfc_tx_qfini(sa, sw_index); 336b1b7ad93SIvan Malov } 337b1b7ad93SIvan Malov 338a8ad8cf8SIvan Malov rte_free(sa->txq_info); 339a8ad8cf8SIvan Malov sa->txq_info = NULL; 340a8ad8cf8SIvan Malov sa->txq_count = 0; 341a8ad8cf8SIvan Malov } 342fed9aeb4SIvan Malov 343fed9aeb4SIvan Malov int 344fed9aeb4SIvan Malov sfc_tx_qstart(struct sfc_adapter *sa, unsigned int sw_index) 345fed9aeb4SIvan Malov { 346fed9aeb4SIvan Malov struct rte_eth_dev_data *dev_data; 347fed9aeb4SIvan Malov struct sfc_txq_info *txq_info; 348fed9aeb4SIvan Malov struct sfc_txq *txq; 349fed9aeb4SIvan Malov struct sfc_evq *evq; 350fed9aeb4SIvan Malov uint16_t flags; 351fed9aeb4SIvan Malov unsigned int desc_index; 352fed9aeb4SIvan Malov int rc = 0; 353fed9aeb4SIvan Malov 354fed9aeb4SIvan Malov sfc_log_init(sa, "TxQ = %u", sw_index); 355fed9aeb4SIvan Malov 356fed9aeb4SIvan Malov SFC_ASSERT(sw_index < sa->txq_count); 357fed9aeb4SIvan Malov txq_info = &sa->txq_info[sw_index]; 358fed9aeb4SIvan Malov 359fed9aeb4SIvan Malov txq = txq_info->txq; 360fed9aeb4SIvan Malov 361fed9aeb4SIvan Malov SFC_ASSERT(txq->state == SFC_TXQ_INITIALIZED); 362fed9aeb4SIvan Malov 363fed9aeb4SIvan Malov evq = txq->evq; 364fed9aeb4SIvan Malov 365fed9aeb4SIvan Malov rc = sfc_ev_qstart(sa, evq->evq_index); 366fed9aeb4SIvan Malov if (rc != 0) 367fed9aeb4SIvan Malov goto fail_ev_qstart; 368fed9aeb4SIvan Malov 369fed9aeb4SIvan Malov /* 370fed9aeb4SIvan Malov * It seems that DPDK has no controls regarding IPv4 offloads, 371fed9aeb4SIvan Malov * hence, we always enable it here 372fed9aeb4SIvan Malov */ 373fed9aeb4SIvan Malov if ((txq->flags & ETH_TXQ_FLAGS_NOXSUMTCP) || 374fed9aeb4SIvan Malov (txq->flags & ETH_TXQ_FLAGS_NOXSUMUDP)) 375fed9aeb4SIvan Malov flags = EFX_TXQ_CKSUM_IPV4; 376fed9aeb4SIvan Malov else 377fed9aeb4SIvan Malov flags = EFX_TXQ_CKSUM_IPV4 | EFX_TXQ_CKSUM_TCPUDP; 378fed9aeb4SIvan Malov 379fed9aeb4SIvan Malov rc = efx_tx_qcreate(sa->nic, sw_index, 0, &txq->mem, 380fed9aeb4SIvan Malov txq_info->entries, 0 /* not used on EF10 */, 381fed9aeb4SIvan Malov flags, evq->common, 382fed9aeb4SIvan Malov &txq->common, &desc_index); 383fed9aeb4SIvan Malov if (rc != 0) 384fed9aeb4SIvan Malov goto fail_tx_qcreate; 385fed9aeb4SIvan Malov 386fed9aeb4SIvan Malov txq->added = txq->pending = txq->completed = desc_index; 387fed9aeb4SIvan Malov 388fed9aeb4SIvan Malov efx_tx_qenable(txq->common); 389fed9aeb4SIvan Malov 390fed9aeb4SIvan Malov txq->state |= (SFC_TXQ_STARTED | SFC_TXQ_RUNNING); 391fed9aeb4SIvan Malov 392fed9aeb4SIvan Malov /* 393fed9aeb4SIvan Malov * It seems to be used by DPDK for debug purposes only ('rte_ether') 394fed9aeb4SIvan Malov */ 395fed9aeb4SIvan Malov dev_data = sa->eth_dev->data; 396fed9aeb4SIvan Malov dev_data->tx_queue_state[sw_index] = RTE_ETH_QUEUE_STATE_STARTED; 397fed9aeb4SIvan Malov 398fed9aeb4SIvan Malov return 0; 399fed9aeb4SIvan Malov 400fed9aeb4SIvan Malov fail_tx_qcreate: 401fed9aeb4SIvan Malov sfc_ev_qstop(sa, evq->evq_index); 402fed9aeb4SIvan Malov 403fed9aeb4SIvan Malov fail_ev_qstart: 404fed9aeb4SIvan Malov return rc; 405fed9aeb4SIvan Malov } 406fed9aeb4SIvan Malov 407fed9aeb4SIvan Malov void 408fed9aeb4SIvan Malov sfc_tx_qstop(struct sfc_adapter *sa, unsigned int sw_index) 409fed9aeb4SIvan Malov { 410fed9aeb4SIvan Malov struct rte_eth_dev_data *dev_data; 411fed9aeb4SIvan Malov struct sfc_txq_info *txq_info; 412fed9aeb4SIvan Malov struct sfc_txq *txq; 413fed9aeb4SIvan Malov unsigned int retry_count; 414fed9aeb4SIvan Malov unsigned int wait_count; 415fed9aeb4SIvan Malov unsigned int txds; 416fed9aeb4SIvan Malov 417fed9aeb4SIvan Malov sfc_log_init(sa, "TxQ = %u", sw_index); 418fed9aeb4SIvan Malov 419fed9aeb4SIvan Malov SFC_ASSERT(sw_index < sa->txq_count); 420fed9aeb4SIvan Malov txq_info = &sa->txq_info[sw_index]; 421fed9aeb4SIvan Malov 422fed9aeb4SIvan Malov txq = txq_info->txq; 423fed9aeb4SIvan Malov 424*c6a1d9b5SIvan Malov if (txq->state == SFC_TXQ_INITIALIZED) 425*c6a1d9b5SIvan Malov return; 426*c6a1d9b5SIvan Malov 427fed9aeb4SIvan Malov SFC_ASSERT(txq->state & SFC_TXQ_STARTED); 428fed9aeb4SIvan Malov 429fed9aeb4SIvan Malov txq->state &= ~SFC_TXQ_RUNNING; 430fed9aeb4SIvan Malov 431fed9aeb4SIvan Malov /* 432fed9aeb4SIvan Malov * Retry TX queue flushing in case of flush failed or 433fed9aeb4SIvan Malov * timeout; in the worst case it can delay for 6 seconds 434fed9aeb4SIvan Malov */ 435fed9aeb4SIvan Malov for (retry_count = 0; 436fed9aeb4SIvan Malov ((txq->state & SFC_TXQ_FLUSHED) == 0) && 437fed9aeb4SIvan Malov (retry_count < SFC_TX_QFLUSH_ATTEMPTS); 438fed9aeb4SIvan Malov ++retry_count) { 439fed9aeb4SIvan Malov if (efx_tx_qflush(txq->common) != 0) { 440fed9aeb4SIvan Malov txq->state |= SFC_TXQ_FLUSHING; 441fed9aeb4SIvan Malov break; 442fed9aeb4SIvan Malov } 443fed9aeb4SIvan Malov 444fed9aeb4SIvan Malov /* 445fed9aeb4SIvan Malov * Wait for TX queue flush done or flush failed event at least 446fed9aeb4SIvan Malov * SFC_TX_QFLUSH_POLL_WAIT_MS milliseconds and not more 447fed9aeb4SIvan Malov * than 2 seconds (SFC_TX_QFLUSH_POLL_WAIT_MS multiplied 448fed9aeb4SIvan Malov * by SFC_TX_QFLUSH_POLL_ATTEMPTS) 449fed9aeb4SIvan Malov */ 450fed9aeb4SIvan Malov wait_count = 0; 451fed9aeb4SIvan Malov do { 452fed9aeb4SIvan Malov rte_delay_ms(SFC_TX_QFLUSH_POLL_WAIT_MS); 453fed9aeb4SIvan Malov sfc_ev_qpoll(txq->evq); 454fed9aeb4SIvan Malov } while ((txq->state & SFC_TXQ_FLUSHING) && 455fed9aeb4SIvan Malov wait_count++ < SFC_TX_QFLUSH_POLL_ATTEMPTS); 456fed9aeb4SIvan Malov 457fed9aeb4SIvan Malov if (txq->state & SFC_TXQ_FLUSHING) 458fed9aeb4SIvan Malov sfc_err(sa, "TxQ %u flush timed out", sw_index); 459fed9aeb4SIvan Malov 460fed9aeb4SIvan Malov if (txq->state & SFC_TXQ_FLUSHED) 461fed9aeb4SIvan Malov sfc_info(sa, "TxQ %u flushed", sw_index); 462fed9aeb4SIvan Malov } 463fed9aeb4SIvan Malov 464fed9aeb4SIvan Malov sfc_tx_reap(txq); 465fed9aeb4SIvan Malov 466fed9aeb4SIvan Malov for (txds = 0; txds < txq_info->entries; txds++) { 467fed9aeb4SIvan Malov if (txq->sw_ring[txds].mbuf != NULL) { 468fed9aeb4SIvan Malov rte_pktmbuf_free(txq->sw_ring[txds].mbuf); 469fed9aeb4SIvan Malov txq->sw_ring[txds].mbuf = NULL; 470fed9aeb4SIvan Malov } 471fed9aeb4SIvan Malov } 472fed9aeb4SIvan Malov 473fed9aeb4SIvan Malov txq->state = SFC_TXQ_INITIALIZED; 474fed9aeb4SIvan Malov 475fed9aeb4SIvan Malov efx_tx_qdestroy(txq->common); 476fed9aeb4SIvan Malov 477fed9aeb4SIvan Malov sfc_ev_qstop(sa, txq->evq->evq_index); 478fed9aeb4SIvan Malov 479fed9aeb4SIvan Malov /* 480fed9aeb4SIvan Malov * It seems to be used by DPDK for debug purposes only ('rte_ether') 481fed9aeb4SIvan Malov */ 482fed9aeb4SIvan Malov dev_data = sa->eth_dev->data; 483fed9aeb4SIvan Malov dev_data->tx_queue_state[sw_index] = RTE_ETH_QUEUE_STATE_STOPPED; 484fed9aeb4SIvan Malov } 485fed9aeb4SIvan Malov 486fed9aeb4SIvan Malov int 487fed9aeb4SIvan Malov sfc_tx_start(struct sfc_adapter *sa) 488fed9aeb4SIvan Malov { 489fed9aeb4SIvan Malov unsigned int sw_index; 490fed9aeb4SIvan Malov int rc = 0; 491fed9aeb4SIvan Malov 492fed9aeb4SIvan Malov sfc_log_init(sa, "txq_count = %u", sa->txq_count); 493fed9aeb4SIvan Malov 494fed9aeb4SIvan Malov rc = efx_tx_init(sa->nic); 495fed9aeb4SIvan Malov if (rc != 0) 496fed9aeb4SIvan Malov goto fail_efx_tx_init; 497fed9aeb4SIvan Malov 498fed9aeb4SIvan Malov for (sw_index = 0; sw_index < sa->txq_count; ++sw_index) { 499*c6a1d9b5SIvan Malov if (!(sa->txq_info[sw_index].deferred_start) || 500*c6a1d9b5SIvan Malov sa->txq_info[sw_index].deferred_started) { 501fed9aeb4SIvan Malov rc = sfc_tx_qstart(sa, sw_index); 502fed9aeb4SIvan Malov if (rc != 0) 503fed9aeb4SIvan Malov goto fail_tx_qstart; 504fed9aeb4SIvan Malov } 505*c6a1d9b5SIvan Malov } 506fed9aeb4SIvan Malov 507fed9aeb4SIvan Malov return 0; 508fed9aeb4SIvan Malov 509fed9aeb4SIvan Malov fail_tx_qstart: 510fed9aeb4SIvan Malov while (sw_index-- > 0) 511fed9aeb4SIvan Malov sfc_tx_qstop(sa, sw_index); 512fed9aeb4SIvan Malov 513fed9aeb4SIvan Malov efx_tx_fini(sa->nic); 514fed9aeb4SIvan Malov 515fed9aeb4SIvan Malov fail_efx_tx_init: 516fed9aeb4SIvan Malov sfc_log_init(sa, "failed (rc = %d)", rc); 517fed9aeb4SIvan Malov return rc; 518fed9aeb4SIvan Malov } 519fed9aeb4SIvan Malov 520fed9aeb4SIvan Malov void 521fed9aeb4SIvan Malov sfc_tx_stop(struct sfc_adapter *sa) 522fed9aeb4SIvan Malov { 523fed9aeb4SIvan Malov unsigned int sw_index; 524fed9aeb4SIvan Malov 525fed9aeb4SIvan Malov sfc_log_init(sa, "txq_count = %u", sa->txq_count); 526fed9aeb4SIvan Malov 527fed9aeb4SIvan Malov sw_index = sa->txq_count; 528fed9aeb4SIvan Malov while (sw_index-- > 0) { 529fed9aeb4SIvan Malov if (sa->txq_info[sw_index].txq != NULL) 530fed9aeb4SIvan Malov sfc_tx_qstop(sa, sw_index); 531fed9aeb4SIvan Malov } 532fed9aeb4SIvan Malov 533fed9aeb4SIvan Malov efx_tx_fini(sa->nic); 534fed9aeb4SIvan Malov } 535428c7dddSIvan Malov 536428c7dddSIvan Malov uint16_t 537428c7dddSIvan Malov sfc_xmit_pkts(void *tx_queue, struct rte_mbuf **tx_pkts, uint16_t nb_pkts) 538428c7dddSIvan Malov { 539428c7dddSIvan Malov struct sfc_txq *txq = (struct sfc_txq *)tx_queue; 540428c7dddSIvan Malov unsigned int added = txq->added; 541428c7dddSIvan Malov unsigned int pushed = added; 542428c7dddSIvan Malov unsigned int pkts_sent = 0; 543428c7dddSIvan Malov efx_desc_t *pend = &txq->pend_desc[0]; 544428c7dddSIvan Malov const unsigned int hard_max_fill = EFX_TXQ_LIMIT(txq->ptr_mask + 1); 54521f6411cSIvan Malov const unsigned int soft_max_fill = hard_max_fill - txq->free_thresh; 546428c7dddSIvan Malov unsigned int fill_level = added - txq->completed; 547428c7dddSIvan Malov boolean_t reap_done; 548428c7dddSIvan Malov int rc __rte_unused; 549428c7dddSIvan Malov struct rte_mbuf **pktp; 550428c7dddSIvan Malov 551428c7dddSIvan Malov if (unlikely((txq->state & SFC_TXQ_RUNNING) == 0)) 552428c7dddSIvan Malov goto done; 553428c7dddSIvan Malov 554428c7dddSIvan Malov /* 555428c7dddSIvan Malov * If insufficient space for a single packet is present, 556428c7dddSIvan Malov * we should reap; otherwise, we shouldn't do that all the time 557428c7dddSIvan Malov * to avoid latency increase 558428c7dddSIvan Malov */ 559428c7dddSIvan Malov reap_done = (fill_level > soft_max_fill); 560428c7dddSIvan Malov 561428c7dddSIvan Malov if (reap_done) { 562428c7dddSIvan Malov sfc_tx_reap(txq); 563428c7dddSIvan Malov /* 564428c7dddSIvan Malov * Recalculate fill level since 'txq->completed' 565428c7dddSIvan Malov * might have changed on reap 566428c7dddSIvan Malov */ 567428c7dddSIvan Malov fill_level = added - txq->completed; 568428c7dddSIvan Malov } 569428c7dddSIvan Malov 570428c7dddSIvan Malov for (pkts_sent = 0, pktp = &tx_pkts[0]; 571428c7dddSIvan Malov (pkts_sent < nb_pkts) && (fill_level <= soft_max_fill); 572428c7dddSIvan Malov pkts_sent++, pktp++) { 573428c7dddSIvan Malov struct rte_mbuf *m_seg = *pktp; 574428c7dddSIvan Malov size_t pkt_len = m_seg->pkt_len; 575428c7dddSIvan Malov unsigned int pkt_descs = 0; 576428c7dddSIvan Malov 577428c7dddSIvan Malov for (; m_seg != NULL; m_seg = m_seg->next) { 578428c7dddSIvan Malov efsys_dma_addr_t next_frag; 579428c7dddSIvan Malov size_t seg_len; 580428c7dddSIvan Malov 581428c7dddSIvan Malov seg_len = m_seg->data_len; 582428c7dddSIvan Malov next_frag = rte_mbuf_data_dma_addr(m_seg); 583428c7dddSIvan Malov 584428c7dddSIvan Malov do { 585428c7dddSIvan Malov efsys_dma_addr_t frag_addr = next_frag; 586428c7dddSIvan Malov size_t frag_len; 587428c7dddSIvan Malov 588428c7dddSIvan Malov next_frag = RTE_ALIGN(frag_addr + 1, 589428c7dddSIvan Malov SFC_TX_SEG_BOUNDARY); 590428c7dddSIvan Malov frag_len = MIN(next_frag - frag_addr, seg_len); 591428c7dddSIvan Malov seg_len -= frag_len; 592428c7dddSIvan Malov pkt_len -= frag_len; 593428c7dddSIvan Malov 594428c7dddSIvan Malov efx_tx_qdesc_dma_create(txq->common, 595428c7dddSIvan Malov frag_addr, frag_len, 596428c7dddSIvan Malov (pkt_len == 0), 597428c7dddSIvan Malov pend++); 598428c7dddSIvan Malov 599428c7dddSIvan Malov pkt_descs++; 600428c7dddSIvan Malov } while (seg_len != 0); 601428c7dddSIvan Malov } 602428c7dddSIvan Malov 603428c7dddSIvan Malov added += pkt_descs; 604428c7dddSIvan Malov 605428c7dddSIvan Malov fill_level += pkt_descs; 606428c7dddSIvan Malov if (unlikely(fill_level > hard_max_fill)) { 607428c7dddSIvan Malov /* 608428c7dddSIvan Malov * Our estimation for maximum number of descriptors 609428c7dddSIvan Malov * required to send a packet seems to be wrong. 610428c7dddSIvan Malov * Try to reap (if we haven't yet). 611428c7dddSIvan Malov */ 612428c7dddSIvan Malov if (!reap_done) { 613428c7dddSIvan Malov sfc_tx_reap(txq); 614428c7dddSIvan Malov reap_done = B_TRUE; 615428c7dddSIvan Malov fill_level = added - txq->completed; 616428c7dddSIvan Malov if (fill_level > hard_max_fill) { 617428c7dddSIvan Malov pend -= pkt_descs; 618428c7dddSIvan Malov break; 619428c7dddSIvan Malov } 620428c7dddSIvan Malov } else { 621428c7dddSIvan Malov pend -= pkt_descs; 622428c7dddSIvan Malov break; 623428c7dddSIvan Malov } 624428c7dddSIvan Malov } 625428c7dddSIvan Malov 626428c7dddSIvan Malov /* Assign mbuf to the last used desc */ 627428c7dddSIvan Malov txq->sw_ring[(added - 1) & txq->ptr_mask].mbuf = *pktp; 628428c7dddSIvan Malov } 629428c7dddSIvan Malov 630428c7dddSIvan Malov if (likely(pkts_sent > 0)) { 631428c7dddSIvan Malov rc = efx_tx_qdesc_post(txq->common, txq->pend_desc, 632428c7dddSIvan Malov pend - &txq->pend_desc[0], 633428c7dddSIvan Malov txq->completed, &txq->added); 634428c7dddSIvan Malov SFC_ASSERT(rc == 0); 635428c7dddSIvan Malov 636428c7dddSIvan Malov if (likely(pushed != txq->added)) 637428c7dddSIvan Malov efx_tx_qpush(txq->common, txq->added, pushed); 638428c7dddSIvan Malov } 639428c7dddSIvan Malov 640428c7dddSIvan Malov #if SFC_TX_XMIT_PKTS_REAP_AT_LEAST_ONCE 641428c7dddSIvan Malov if (!reap_done) 642428c7dddSIvan Malov sfc_tx_reap(txq); 643428c7dddSIvan Malov #endif 644428c7dddSIvan Malov 645428c7dddSIvan Malov done: 646428c7dddSIvan Malov return pkts_sent; 647428c7dddSIvan Malov } 648