5e046832f1
The helper rte_eth_dma_zone_reserve() is called by PMDs when probing a new port. It creates a new memzone with an unique name. The name of this memzone was using the name of the driver doing the probe. In order to avoid assigning the driver before the end of the probing, the driver name is removed from these memzone names. The ethdev name (data->name) is not used because it may be too long and may be not set at this stage of probing. Syntax of old name: <driver>_<ring>_<port>_<queue> Syntax of new name: eth_p<port>_q<queue>_<ring> Signed-off-by: Thomas Monjalon <thomas@monjalon.net> Tested-by: Andrew Rybchenko <arybchenko@solarflare.com>
476 lines
12 KiB
C
476 lines
12 KiB
C
/* SPDX-License-Identifier: BSD-3-Clause
|
|
* Copyright (c) 2013-2015 Brocade Communications Systems, Inc.
|
|
* Copyright (c) 2015-2018 Cavium Inc.
|
|
* All rights reserved.
|
|
* www.cavium.com
|
|
*/
|
|
|
|
#include "bnx2x.h"
|
|
#include "bnx2x_rxtx.h"
|
|
|
|
static const struct rte_memzone *
|
|
ring_dma_zone_reserve(struct rte_eth_dev *dev, const char *ring_name,
|
|
uint16_t queue_id, uint32_t ring_size, int socket_id)
|
|
{
|
|
return rte_eth_dma_zone_reserve(dev, ring_name, queue_id,
|
|
ring_size, BNX2X_PAGE_SIZE, socket_id);
|
|
}
|
|
|
|
static void
|
|
bnx2x_rx_queue_release(struct bnx2x_rx_queue *rx_queue)
|
|
{
|
|
uint16_t i;
|
|
struct rte_mbuf **sw_ring;
|
|
|
|
if (NULL != rx_queue) {
|
|
|
|
sw_ring = rx_queue->sw_ring;
|
|
if (NULL != sw_ring) {
|
|
for (i = 0; i < rx_queue->nb_rx_desc; i++) {
|
|
if (NULL != sw_ring[i])
|
|
rte_pktmbuf_free(sw_ring[i]);
|
|
}
|
|
rte_free(sw_ring);
|
|
}
|
|
rte_free(rx_queue);
|
|
}
|
|
}
|
|
|
|
void
|
|
bnx2x_dev_rx_queue_release(void *rxq)
|
|
{
|
|
bnx2x_rx_queue_release(rxq);
|
|
}
|
|
|
|
int
|
|
bnx2x_dev_rx_queue_setup(struct rte_eth_dev *dev,
|
|
uint16_t queue_idx,
|
|
uint16_t nb_desc,
|
|
unsigned int socket_id,
|
|
__rte_unused const struct rte_eth_rxconf *rx_conf,
|
|
struct rte_mempool *mp)
|
|
{
|
|
uint16_t j, idx;
|
|
const struct rte_memzone *dma;
|
|
struct bnx2x_rx_queue *rxq;
|
|
uint32_t dma_size;
|
|
struct rte_mbuf *mbuf;
|
|
struct bnx2x_softc *sc = dev->data->dev_private;
|
|
struct bnx2x_fastpath *fp = &sc->fp[queue_idx];
|
|
struct eth_rx_cqe_next_page *nextpg;
|
|
rte_iova_t *rx_bd;
|
|
rte_iova_t busaddr;
|
|
|
|
/* First allocate the rx queue data structure */
|
|
rxq = rte_zmalloc_socket("ethdev RX queue", sizeof(struct bnx2x_rx_queue),
|
|
RTE_CACHE_LINE_SIZE, socket_id);
|
|
if (NULL == rxq) {
|
|
PMD_DRV_LOG(ERR, sc, "rte_zmalloc for rxq failed!");
|
|
return -ENOMEM;
|
|
}
|
|
rxq->sc = sc;
|
|
rxq->mb_pool = mp;
|
|
rxq->queue_id = queue_idx;
|
|
rxq->port_id = dev->data->port_id;
|
|
|
|
rxq->nb_rx_pages = 1;
|
|
while (USABLE_RX_BD(rxq) < nb_desc)
|
|
rxq->nb_rx_pages <<= 1;
|
|
|
|
rxq->nb_rx_desc = TOTAL_RX_BD(rxq);
|
|
sc->rx_ring_size = USABLE_RX_BD(rxq);
|
|
rxq->nb_cq_pages = RCQ_BD_PAGES(rxq);
|
|
|
|
PMD_DRV_LOG(DEBUG, sc, "fp[%02d] req_bd=%u, usable_bd=%lu, "
|
|
"total_bd=%lu, rx_pages=%u, cq_pages=%u",
|
|
queue_idx, nb_desc, (unsigned long)USABLE_RX_BD(rxq),
|
|
(unsigned long)TOTAL_RX_BD(rxq), rxq->nb_rx_pages,
|
|
rxq->nb_cq_pages);
|
|
|
|
/* Allocate RX ring hardware descriptors */
|
|
dma_size = rxq->nb_rx_desc * sizeof(struct eth_rx_bd);
|
|
dma = ring_dma_zone_reserve(dev, "hw_ring", queue_idx, dma_size, socket_id);
|
|
if (NULL == dma) {
|
|
PMD_RX_LOG(ERR, "ring_dma_zone_reserve for rx_ring failed!");
|
|
bnx2x_rx_queue_release(rxq);
|
|
return -ENOMEM;
|
|
}
|
|
fp->rx_desc_mapping = rxq->rx_ring_phys_addr = (uint64_t)dma->iova;
|
|
rxq->rx_ring = (uint64_t*)dma->addr;
|
|
memset((void *)rxq->rx_ring, 0, dma_size);
|
|
|
|
/* Link the RX chain pages. */
|
|
for (j = 1; j <= rxq->nb_rx_pages; j++) {
|
|
rx_bd = &rxq->rx_ring[TOTAL_RX_BD_PER_PAGE * j - 2];
|
|
busaddr = rxq->rx_ring_phys_addr + BNX2X_PAGE_SIZE * (j % rxq->nb_rx_pages);
|
|
*rx_bd = busaddr;
|
|
}
|
|
|
|
/* Allocate software ring */
|
|
dma_size = rxq->nb_rx_desc * sizeof(struct bnx2x_rx_entry);
|
|
rxq->sw_ring = rte_zmalloc_socket("sw_ring", dma_size,
|
|
RTE_CACHE_LINE_SIZE,
|
|
socket_id);
|
|
if (NULL == rxq->sw_ring) {
|
|
PMD_RX_LOG(ERR, "rte_zmalloc for sw_ring failed!");
|
|
bnx2x_rx_queue_release(rxq);
|
|
return -ENOMEM;
|
|
}
|
|
|
|
/* Initialize software ring entries */
|
|
for (idx = 0; idx < rxq->nb_rx_desc; idx = NEXT_RX_BD(idx)) {
|
|
mbuf = rte_mbuf_raw_alloc(mp);
|
|
if (NULL == mbuf) {
|
|
PMD_RX_LOG(ERR, "RX mbuf alloc failed queue_id=%u, idx=%d",
|
|
(unsigned)rxq->queue_id, idx);
|
|
bnx2x_rx_queue_release(rxq);
|
|
return -ENOMEM;
|
|
}
|
|
rxq->sw_ring[idx] = mbuf;
|
|
rxq->rx_ring[idx] =
|
|
rte_cpu_to_le_64(rte_mbuf_data_iova_default(mbuf));
|
|
}
|
|
rxq->pkt_first_seg = NULL;
|
|
rxq->pkt_last_seg = NULL;
|
|
rxq->rx_bd_head = 0;
|
|
rxq->rx_bd_tail = rxq->nb_rx_desc;
|
|
|
|
/* Allocate CQ chain. */
|
|
dma_size = BNX2X_RX_CHAIN_PAGE_SZ * rxq->nb_cq_pages;
|
|
dma = ring_dma_zone_reserve(dev, "bnx2x_rcq", queue_idx, dma_size, socket_id);
|
|
if (NULL == dma) {
|
|
PMD_RX_LOG(ERR, "RCQ alloc failed");
|
|
return -ENOMEM;
|
|
}
|
|
fp->rx_comp_mapping = rxq->cq_ring_phys_addr = (uint64_t)dma->iova;
|
|
rxq->cq_ring = (union eth_rx_cqe*)dma->addr;
|
|
|
|
/* Link the CQ chain pages. */
|
|
for (j = 1; j <= rxq->nb_cq_pages; j++) {
|
|
nextpg = &rxq->cq_ring[TOTAL_RCQ_ENTRIES_PER_PAGE * j - 1].next_page_cqe;
|
|
busaddr = rxq->cq_ring_phys_addr + BNX2X_PAGE_SIZE * (j % rxq->nb_cq_pages);
|
|
nextpg->addr_hi = rte_cpu_to_le_32(U64_HI(busaddr));
|
|
nextpg->addr_lo = rte_cpu_to_le_32(U64_LO(busaddr));
|
|
}
|
|
rxq->rx_cq_head = 0;
|
|
rxq->rx_cq_tail = TOTAL_RCQ_ENTRIES(rxq);
|
|
|
|
dev->data->rx_queues[queue_idx] = rxq;
|
|
if (!sc->rx_queues) sc->rx_queues = dev->data->rx_queues;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void
|
|
bnx2x_tx_queue_release(struct bnx2x_tx_queue *tx_queue)
|
|
{
|
|
uint16_t i;
|
|
struct rte_mbuf **sw_ring;
|
|
|
|
if (NULL != tx_queue) {
|
|
|
|
sw_ring = tx_queue->sw_ring;
|
|
if (NULL != sw_ring) {
|
|
for (i = 0; i < tx_queue->nb_tx_desc; i++) {
|
|
if (NULL != sw_ring[i])
|
|
rte_pktmbuf_free(sw_ring[i]);
|
|
}
|
|
rte_free(sw_ring);
|
|
}
|
|
rte_free(tx_queue);
|
|
}
|
|
}
|
|
|
|
void
|
|
bnx2x_dev_tx_queue_release(void *txq)
|
|
{
|
|
bnx2x_tx_queue_release(txq);
|
|
}
|
|
|
|
static uint16_t
|
|
bnx2x_xmit_pkts(void *p_txq, struct rte_mbuf **tx_pkts, uint16_t nb_pkts)
|
|
{
|
|
struct bnx2x_tx_queue *txq;
|
|
struct bnx2x_softc *sc;
|
|
struct bnx2x_fastpath *fp;
|
|
uint16_t nb_tx_pkts;
|
|
uint16_t nb_pkt_sent = 0;
|
|
uint32_t ret;
|
|
|
|
txq = p_txq;
|
|
sc = txq->sc;
|
|
fp = &sc->fp[txq->queue_id];
|
|
|
|
if ((unlikely((txq->nb_tx_desc - txq->nb_tx_avail) >
|
|
txq->tx_free_thresh)))
|
|
bnx2x_txeof(sc, fp);
|
|
|
|
nb_tx_pkts = RTE_MIN(nb_pkts, txq->nb_tx_avail / BDS_PER_TX_PKT);
|
|
if (unlikely(nb_tx_pkts == 0))
|
|
return 0;
|
|
|
|
while (nb_tx_pkts--) {
|
|
struct rte_mbuf *m = *tx_pkts++;
|
|
assert(m != NULL);
|
|
ret = bnx2x_tx_encap(txq, m);
|
|
fp->tx_db.data.prod += ret;
|
|
nb_pkt_sent++;
|
|
}
|
|
|
|
bnx2x_update_fp_sb_idx(fp);
|
|
mb();
|
|
DOORBELL(sc, txq->queue_id, fp->tx_db.raw);
|
|
mb();
|
|
|
|
if ((txq->nb_tx_desc - txq->nb_tx_avail) >
|
|
txq->tx_free_thresh)
|
|
bnx2x_txeof(sc, fp);
|
|
|
|
return nb_pkt_sent;
|
|
}
|
|
|
|
int
|
|
bnx2x_dev_tx_queue_setup(struct rte_eth_dev *dev,
|
|
uint16_t queue_idx,
|
|
uint16_t nb_desc,
|
|
unsigned int socket_id,
|
|
const struct rte_eth_txconf *tx_conf)
|
|
{
|
|
uint16_t i;
|
|
unsigned int tsize;
|
|
const struct rte_memzone *tz;
|
|
struct bnx2x_tx_queue *txq;
|
|
struct eth_tx_next_bd *tx_n_bd;
|
|
uint64_t busaddr;
|
|
struct bnx2x_softc *sc = dev->data->dev_private;
|
|
struct bnx2x_fastpath *fp = &sc->fp[queue_idx];
|
|
|
|
/* First allocate the tx queue data structure */
|
|
txq = rte_zmalloc("ethdev TX queue", sizeof(struct bnx2x_tx_queue),
|
|
RTE_CACHE_LINE_SIZE);
|
|
if (txq == NULL)
|
|
return -ENOMEM;
|
|
txq->sc = sc;
|
|
|
|
txq->nb_tx_pages = 1;
|
|
while (USABLE_TX_BD(txq) < nb_desc)
|
|
txq->nb_tx_pages <<= 1;
|
|
|
|
txq->nb_tx_desc = TOTAL_TX_BD(txq);
|
|
sc->tx_ring_size = TOTAL_TX_BD(txq);
|
|
|
|
txq->tx_free_thresh = tx_conf->tx_free_thresh ?
|
|
tx_conf->tx_free_thresh : DEFAULT_TX_FREE_THRESH;
|
|
txq->tx_free_thresh = min(txq->tx_free_thresh,
|
|
txq->nb_tx_desc - BDS_PER_TX_PKT);
|
|
|
|
PMD_DRV_LOG(DEBUG, sc, "fp[%02d] req_bd=%u, thresh=%u, usable_bd=%lu, "
|
|
"total_bd=%lu, tx_pages=%u",
|
|
queue_idx, nb_desc, txq->tx_free_thresh,
|
|
(unsigned long)USABLE_TX_BD(txq),
|
|
(unsigned long)TOTAL_TX_BD(txq), txq->nb_tx_pages);
|
|
|
|
/* Allocate TX ring hardware descriptors */
|
|
tsize = txq->nb_tx_desc * sizeof(union eth_tx_bd_types);
|
|
tz = ring_dma_zone_reserve(dev, "tx_hw_ring", queue_idx, tsize, socket_id);
|
|
if (tz == NULL) {
|
|
bnx2x_tx_queue_release(txq);
|
|
return -ENOMEM;
|
|
}
|
|
fp->tx_desc_mapping = txq->tx_ring_phys_addr = (uint64_t)tz->iova;
|
|
txq->tx_ring = (union eth_tx_bd_types *) tz->addr;
|
|
memset(txq->tx_ring, 0, tsize);
|
|
|
|
/* Allocate software ring */
|
|
tsize = txq->nb_tx_desc * sizeof(struct rte_mbuf *);
|
|
txq->sw_ring = rte_zmalloc("tx_sw_ring", tsize,
|
|
RTE_CACHE_LINE_SIZE);
|
|
if (txq->sw_ring == NULL) {
|
|
bnx2x_tx_queue_release(txq);
|
|
return -ENOMEM;
|
|
}
|
|
|
|
/* PMD_DRV_LOG(DEBUG, sc, "sw_ring=%p hw_ring=%p dma_addr=0x%"PRIx64,
|
|
txq->sw_ring, txq->tx_ring, txq->tx_ring_phys_addr); */
|
|
|
|
/* Link TX pages */
|
|
for (i = 1; i <= txq->nb_tx_pages; i++) {
|
|
tx_n_bd = &txq->tx_ring[TOTAL_TX_BD_PER_PAGE * i - 1].next_bd;
|
|
busaddr = txq->tx_ring_phys_addr + BNX2X_PAGE_SIZE * (i % txq->nb_tx_pages);
|
|
tx_n_bd->addr_hi = rte_cpu_to_le_32(U64_HI(busaddr));
|
|
tx_n_bd->addr_lo = rte_cpu_to_le_32(U64_LO(busaddr));
|
|
/* PMD_DRV_LOG(DEBUG, sc, "link tx page %lu",
|
|
* (TOTAL_TX_BD_PER_PAGE * i - 1));
|
|
*/
|
|
}
|
|
|
|
txq->queue_id = queue_idx;
|
|
txq->port_id = dev->data->port_id;
|
|
txq->tx_pkt_tail = 0;
|
|
txq->tx_pkt_head = 0;
|
|
txq->tx_bd_tail = 0;
|
|
txq->tx_bd_head = 0;
|
|
txq->nb_tx_avail = txq->nb_tx_desc;
|
|
dev->tx_pkt_burst = bnx2x_xmit_pkts;
|
|
dev->data->tx_queues[queue_idx] = txq;
|
|
if (!sc->tx_queues) sc->tx_queues = dev->data->tx_queues;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static inline void
|
|
bnx2x_upd_rx_prod_fast(struct bnx2x_softc *sc, struct bnx2x_fastpath *fp,
|
|
uint16_t rx_bd_prod, uint16_t rx_cq_prod)
|
|
{
|
|
union ustorm_eth_rx_producers rx_prods;
|
|
|
|
rx_prods.prod.bd_prod = rx_bd_prod;
|
|
rx_prods.prod.cqe_prod = rx_cq_prod;
|
|
|
|
REG_WR(sc, fp->ustorm_rx_prods_offset, rx_prods.raw_data[0]);
|
|
}
|
|
|
|
static uint16_t
|
|
bnx2x_recv_pkts(void *p_rxq, struct rte_mbuf **rx_pkts, uint16_t nb_pkts)
|
|
{
|
|
struct bnx2x_rx_queue *rxq = p_rxq;
|
|
struct bnx2x_softc *sc = rxq->sc;
|
|
struct bnx2x_fastpath *fp = &sc->fp[rxq->queue_id];
|
|
uint32_t nb_rx = 0;
|
|
uint16_t hw_cq_cons, sw_cq_cons, sw_cq_prod;
|
|
uint16_t bd_cons, bd_prod;
|
|
struct rte_mbuf *new_mb;
|
|
uint16_t rx_pref;
|
|
struct eth_fast_path_rx_cqe *cqe_fp;
|
|
uint16_t len, pad;
|
|
struct rte_mbuf *rx_mb = NULL;
|
|
|
|
hw_cq_cons = le16toh(*fp->rx_cq_cons_sb);
|
|
if ((hw_cq_cons & USABLE_RCQ_ENTRIES_PER_PAGE) ==
|
|
USABLE_RCQ_ENTRIES_PER_PAGE) {
|
|
++hw_cq_cons;
|
|
}
|
|
|
|
bd_cons = rxq->rx_bd_head;
|
|
bd_prod = rxq->rx_bd_tail;
|
|
sw_cq_cons = rxq->rx_cq_head;
|
|
sw_cq_prod = rxq->rx_cq_tail;
|
|
|
|
if (sw_cq_cons == hw_cq_cons)
|
|
return 0;
|
|
|
|
while (nb_rx < nb_pkts && sw_cq_cons != hw_cq_cons) {
|
|
|
|
bd_prod &= MAX_RX_BD(rxq);
|
|
bd_cons &= MAX_RX_BD(rxq);
|
|
|
|
cqe_fp = &rxq->cq_ring[sw_cq_cons & MAX_RX_BD(rxq)].fast_path_cqe;
|
|
|
|
if (unlikely(CQE_TYPE_SLOW(cqe_fp->type_error_flags & ETH_FAST_PATH_RX_CQE_TYPE))) {
|
|
PMD_RX_LOG(ERR, "slowpath event during traffic processing");
|
|
break;
|
|
}
|
|
|
|
if (unlikely(cqe_fp->type_error_flags & ETH_FAST_PATH_RX_CQE_PHY_DECODE_ERR_FLG)) {
|
|
PMD_RX_LOG(ERR, "flags 0x%x rx packet %u",
|
|
cqe_fp->type_error_flags, sw_cq_cons);
|
|
goto next_rx;
|
|
}
|
|
|
|
len = cqe_fp->pkt_len_or_gro_seg_len;
|
|
pad = cqe_fp->placement_offset;
|
|
|
|
new_mb = rte_mbuf_raw_alloc(rxq->mb_pool);
|
|
if (unlikely(!new_mb)) {
|
|
PMD_RX_LOG(ERR, "mbuf alloc fail fp[%02d]", fp->index);
|
|
rte_eth_devices[rxq->port_id].data->
|
|
rx_mbuf_alloc_failed++;
|
|
goto next_rx;
|
|
}
|
|
|
|
rx_mb = rxq->sw_ring[bd_cons];
|
|
rxq->sw_ring[bd_cons] = new_mb;
|
|
rxq->rx_ring[bd_prod] =
|
|
rte_cpu_to_le_64(rte_mbuf_data_iova_default(new_mb));
|
|
|
|
rx_pref = NEXT_RX_BD(bd_cons) & MAX_RX_BD(rxq);
|
|
rte_prefetch0(rxq->sw_ring[rx_pref]);
|
|
if ((rx_pref & 0x3) == 0) {
|
|
rte_prefetch0(&rxq->rx_ring[rx_pref]);
|
|
rte_prefetch0(&rxq->sw_ring[rx_pref]);
|
|
}
|
|
|
|
rx_mb->data_off = pad + RTE_PKTMBUF_HEADROOM;
|
|
rx_mb->nb_segs = 1;
|
|
rx_mb->next = NULL;
|
|
rx_mb->pkt_len = rx_mb->data_len = len;
|
|
rx_mb->port = rxq->port_id;
|
|
rte_prefetch1(rte_pktmbuf_mtod(rx_mb, void *));
|
|
|
|
/*
|
|
* If we received a packet with a vlan tag,
|
|
* attach that information to the packet.
|
|
*/
|
|
if (cqe_fp->pars_flags.flags & PARSING_FLAGS_VLAN) {
|
|
rx_mb->vlan_tci = cqe_fp->vlan_tag;
|
|
rx_mb->ol_flags |= PKT_RX_VLAN;
|
|
}
|
|
|
|
rx_pkts[nb_rx] = rx_mb;
|
|
nb_rx++;
|
|
|
|
/* limit spinning on the queue */
|
|
if (unlikely(nb_rx == sc->rx_budget)) {
|
|
PMD_RX_LOG(ERR, "Limit spinning on the queue");
|
|
break;
|
|
}
|
|
|
|
next_rx:
|
|
bd_cons = NEXT_RX_BD(bd_cons);
|
|
bd_prod = NEXT_RX_BD(bd_prod);
|
|
sw_cq_prod = NEXT_RCQ_IDX(sw_cq_prod);
|
|
sw_cq_cons = NEXT_RCQ_IDX(sw_cq_cons);
|
|
}
|
|
rxq->rx_bd_head = bd_cons;
|
|
rxq->rx_bd_tail = bd_prod;
|
|
rxq->rx_cq_head = sw_cq_cons;
|
|
rxq->rx_cq_tail = sw_cq_prod;
|
|
|
|
bnx2x_upd_rx_prod_fast(sc, fp, bd_prod, sw_cq_prod);
|
|
|
|
return nb_rx;
|
|
}
|
|
|
|
int
|
|
bnx2x_dev_rx_init(struct rte_eth_dev *dev)
|
|
{
|
|
dev->rx_pkt_burst = bnx2x_recv_pkts;
|
|
|
|
return 0;
|
|
}
|
|
|
|
void
|
|
bnx2x_dev_clear_queues(struct rte_eth_dev *dev)
|
|
{
|
|
struct bnx2x_softc *sc = dev->data->dev_private;
|
|
uint8_t i;
|
|
|
|
PMD_INIT_FUNC_TRACE(sc);
|
|
|
|
for (i = 0; i < dev->data->nb_tx_queues; i++) {
|
|
struct bnx2x_tx_queue *txq = dev->data->tx_queues[i];
|
|
if (txq != NULL) {
|
|
bnx2x_tx_queue_release(txq);
|
|
dev->data->tx_queues[i] = NULL;
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < dev->data->nb_rx_queues; i++) {
|
|
struct bnx2x_rx_queue *rxq = dev->data->rx_queues[i];
|
|
if (rxq != NULL) {
|
|
bnx2x_rx_queue_release(rxq);
|
|
dev->data->rx_queues[i] = NULL;
|
|
}
|
|
}
|
|
}
|