net/mrvl: add Rx/Tx support
Add rx/tx support. Signed-off-by: Jacek Siuda <jck@semihalf.com> Signed-off-by: Tomasz Duszynski <tdu@semihalf.com>
This commit is contained in:
parent
0ddc9b815b
commit
afb4d0d0bf
@ -70,6 +70,9 @@
|
||||
#define MRVL_MUSDK_HIFS_MAX 9
|
||||
|
||||
#define MRVL_MAC_ADDRS_MAX 1
|
||||
/* prefetch shift */
|
||||
#define MRVL_MUSDK_PREFETCH_SHIFT 2
|
||||
|
||||
#define MRVL_MATCH_LEN 16
|
||||
#define MRVL_PKT_EFFEC_OFFS (MRVL_PKT_OFFS + MV_MH_SIZE)
|
||||
/* Maximum allowable packet size */
|
||||
@ -100,8 +103,29 @@ static int used_bpools[PP2_NUM_PKT_PROC] = {
|
||||
MRVL_MUSDK_BPOOLS_RESERVED
|
||||
};
|
||||
|
||||
struct pp2_bpool *mrvl_port_to_bpool_lookup[RTE_MAX_ETHPORTS];
|
||||
int mrvl_port_bpool_size[PP2_NUM_PKT_PROC][PP2_BPOOL_NUM_POOLS][RTE_MAX_LCORE];
|
||||
uint64_t cookie_addr_high = MRVL_COOKIE_ADDR_INVALID;
|
||||
|
||||
/*
|
||||
* To use buffer harvesting based on loopback port shadow queue structure
|
||||
* was introduced for buffers information bookkeeping.
|
||||
*
|
||||
* Before sending the packet, related buffer information (pp2_buff_inf) is
|
||||
* stored in shadow queue. After packet is transmitted no longer used
|
||||
* packet buffer is released back to it's original hardware pool,
|
||||
* on condition it originated from interface.
|
||||
* In case it was generated by application itself i.e: mbuf->port field is
|
||||
* 0xff then its released to software mempool.
|
||||
*/
|
||||
struct mrvl_shadow_txq {
|
||||
int head; /* write index - used when sending buffers */
|
||||
int tail; /* read index - used when releasing buffers */
|
||||
u16 size; /* queue occupied size */
|
||||
u16 num_to_release; /* number of buffers sent, that can be released */
|
||||
struct buff_release_entry ent[MRVL_PP2_TX_SHADOWQ_SIZE]; /* q entries */
|
||||
};
|
||||
|
||||
struct mrvl_rxq {
|
||||
struct mrvl_priv *priv;
|
||||
struct rte_mempool *mp;
|
||||
@ -115,8 +139,31 @@ struct mrvl_txq {
|
||||
int port_id;
|
||||
};
|
||||
|
||||
/*
|
||||
* Every tx queue should have dedicated shadow tx queue.
|
||||
*
|
||||
* Ports assigned by DPDK might not start at zero or be continuous so
|
||||
* as a workaround define shadow queues for each possible port so that
|
||||
* we eventually fit somewhere.
|
||||
*/
|
||||
struct mrvl_shadow_txq shadow_txqs[RTE_MAX_ETHPORTS][RTE_MAX_LCORE];
|
||||
|
||||
/** Number of ports configured. */
|
||||
int mrvl_ports_nb;
|
||||
static int mrvl_lcore_first;
|
||||
static int mrvl_lcore_last;
|
||||
|
||||
static inline int
|
||||
mrvl_get_bpool_size(int pp2_id, int pool_id)
|
||||
{
|
||||
int i;
|
||||
int size = 0;
|
||||
|
||||
for (i = mrvl_lcore_first; i <= mrvl_lcore_last; i++)
|
||||
size += mrvl_port_bpool_size[pp2_id][pool_id][i];
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static inline int
|
||||
mrvl_reserve_bit(int *bitmap, int max)
|
||||
@ -325,6 +372,33 @@ mrvl_flush_rx_queues(struct rte_eth_dev *dev)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Flush transmit shadow queues.
|
||||
*
|
||||
* @param dev
|
||||
* Pointer to Ethernet device structure.
|
||||
*/
|
||||
static void
|
||||
mrvl_flush_tx_shadow_queues(struct rte_eth_dev *dev)
|
||||
{
|
||||
int i;
|
||||
|
||||
RTE_LOG(INFO, PMD, "Flushing tx shadow queues\n");
|
||||
for (i = 0; i < RTE_MAX_LCORE; i++) {
|
||||
struct mrvl_shadow_txq *sq =
|
||||
&shadow_txqs[dev->data->port_id][i];
|
||||
|
||||
while (sq->tail != sq->head) {
|
||||
uint64_t addr = cookie_addr_high |
|
||||
sq->ent[sq->tail].buff.cookie;
|
||||
rte_pktmbuf_free((struct rte_mbuf *)addr);
|
||||
sq->tail = (sq->tail + 1) & MRVL_PP2_TX_SHADOWQ_MASK;
|
||||
}
|
||||
|
||||
memset(sq, 0, sizeof(*sq));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Flush hardware bpool (buffer-pool).
|
||||
*
|
||||
@ -371,6 +445,7 @@ mrvl_dev_stop(struct rte_eth_dev *dev)
|
||||
|
||||
mrvl_dev_set_link_down(dev);
|
||||
mrvl_flush_rx_queues(dev);
|
||||
mrvl_flush_tx_shadow_queues(dev);
|
||||
if (priv->qos_tbl)
|
||||
pp2_cls_qos_tbl_deinit(priv->qos_tbl);
|
||||
pp2_ppio_deinit(priv->ppio);
|
||||
@ -543,6 +618,7 @@ mrvl_fill_bpool(struct mrvl_rxq *rxq, int num)
|
||||
}
|
||||
|
||||
pp2_bpool_put_buffs(hif, entries, (uint16_t *)&i);
|
||||
mrvl_port_bpool_size[bpool->pp2_id][bpool->id][core_id] += i;
|
||||
|
||||
if (i != num)
|
||||
goto out;
|
||||
@ -619,6 +695,7 @@ mrvl_rx_queue_setup(struct rte_eth_dev *dev, uint16_t idx, uint16_t desc,
|
||||
rxq->mp = mp;
|
||||
rxq->queue_id = idx;
|
||||
rxq->port_id = dev->data->port_id;
|
||||
mrvl_port_to_bpool_lookup[rxq->port_id] = priv->bpool;
|
||||
|
||||
tc = priv->rxq_map[rxq->queue_id].tc,
|
||||
inq = priv->rxq_map[rxq->queue_id].inq;
|
||||
@ -749,6 +826,276 @@ static const struct eth_dev_ops mrvl_ops = {
|
||||
.tx_queue_release = mrvl_tx_queue_release,
|
||||
};
|
||||
|
||||
/**
|
||||
* DPDK callback for receive.
|
||||
*
|
||||
* @param rxq
|
||||
* Generic pointer to the receive queue.
|
||||
* @param rx_pkts
|
||||
* Array to store received packets.
|
||||
* @param nb_pkts
|
||||
* Maximum number of packets in array.
|
||||
*
|
||||
* @return
|
||||
* Number of packets successfully received.
|
||||
*/
|
||||
static uint16_t
|
||||
mrvl_rx_pkt_burst(void *rxq, struct rte_mbuf **rx_pkts, uint16_t nb_pkts)
|
||||
{
|
||||
struct mrvl_rxq *q = rxq;
|
||||
struct pp2_ppio_desc descs[nb_pkts];
|
||||
struct pp2_bpool *bpool;
|
||||
int i, ret, rx_done = 0;
|
||||
int num;
|
||||
unsigned int core_id = rte_lcore_id();
|
||||
|
||||
if (unlikely(!q->priv->ppio))
|
||||
return 0;
|
||||
|
||||
bpool = q->priv->bpool;
|
||||
|
||||
ret = pp2_ppio_recv(q->priv->ppio, q->priv->rxq_map[q->queue_id].tc,
|
||||
q->priv->rxq_map[q->queue_id].inq, descs, &nb_pkts);
|
||||
if (unlikely(ret < 0)) {
|
||||
RTE_LOG(ERR, PMD, "Failed to receive packets\n");
|
||||
return 0;
|
||||
}
|
||||
mrvl_port_bpool_size[bpool->pp2_id][bpool->id][core_id] -= nb_pkts;
|
||||
|
||||
for (i = 0; i < nb_pkts; i++) {
|
||||
struct rte_mbuf *mbuf;
|
||||
enum pp2_inq_desc_status status;
|
||||
uint64_t addr;
|
||||
|
||||
if (likely(nb_pkts - i > MRVL_MUSDK_PREFETCH_SHIFT)) {
|
||||
struct pp2_ppio_desc *pref_desc;
|
||||
u64 pref_addr;
|
||||
|
||||
pref_desc = &descs[i + MRVL_MUSDK_PREFETCH_SHIFT];
|
||||
pref_addr = cookie_addr_high |
|
||||
pp2_ppio_inq_desc_get_cookie(pref_desc);
|
||||
rte_mbuf_prefetch_part1((struct rte_mbuf *)(pref_addr));
|
||||
rte_mbuf_prefetch_part2((struct rte_mbuf *)(pref_addr));
|
||||
}
|
||||
|
||||
addr = cookie_addr_high |
|
||||
pp2_ppio_inq_desc_get_cookie(&descs[i]);
|
||||
mbuf = (struct rte_mbuf *)addr;
|
||||
rte_pktmbuf_reset(mbuf);
|
||||
|
||||
/* drop packet in case of mac, overrun or resource error */
|
||||
status = pp2_ppio_inq_desc_get_l2_pkt_error(&descs[i]);
|
||||
if (unlikely(status != PP2_DESC_ERR_OK)) {
|
||||
struct pp2_buff_inf binf = {
|
||||
.addr = rte_mbuf_data_dma_addr_default(mbuf),
|
||||
.cookie = (pp2_cookie_t)(uint64_t)mbuf,
|
||||
};
|
||||
|
||||
pp2_bpool_put_buff(hifs[core_id], bpool, &binf);
|
||||
mrvl_port_bpool_size
|
||||
[bpool->pp2_id][bpool->id][core_id]++;
|
||||
continue;
|
||||
}
|
||||
|
||||
mbuf->data_off += MRVL_PKT_EFFEC_OFFS;
|
||||
mbuf->pkt_len = pp2_ppio_inq_desc_get_pkt_len(&descs[i]);
|
||||
mbuf->data_len = mbuf->pkt_len;
|
||||
mbuf->port = q->port_id;
|
||||
|
||||
rx_pkts[rx_done++] = mbuf;
|
||||
}
|
||||
|
||||
if (rte_spinlock_trylock(&q->priv->lock) == 1) {
|
||||
num = mrvl_get_bpool_size(bpool->pp2_id, bpool->id);
|
||||
|
||||
if (unlikely(num <= q->priv->bpool_min_size ||
|
||||
(!rx_done && num < q->priv->bpool_init_size))) {
|
||||
ret = mrvl_fill_bpool(q, MRVL_BURST_SIZE);
|
||||
if (ret)
|
||||
RTE_LOG(ERR, PMD, "Failed to fill bpool\n");
|
||||
} else if (unlikely(num > q->priv->bpool_max_size)) {
|
||||
int i;
|
||||
int pkt_to_remove = num - q->priv->bpool_init_size;
|
||||
struct rte_mbuf *mbuf;
|
||||
struct pp2_buff_inf buff;
|
||||
|
||||
RTE_LOG(DEBUG, PMD,
|
||||
"\nport-%d:%d: bpool %d oversize - remove %d buffers (pool size: %d -> %d)\n",
|
||||
bpool->pp2_id, q->priv->ppio->port_id,
|
||||
bpool->id, pkt_to_remove, num,
|
||||
q->priv->bpool_init_size);
|
||||
|
||||
for (i = 0; i < pkt_to_remove; i++) {
|
||||
pp2_bpool_get_buff(hifs[core_id], bpool, &buff);
|
||||
mbuf = (struct rte_mbuf *)
|
||||
(cookie_addr_high | buff.cookie);
|
||||
rte_pktmbuf_free(mbuf);
|
||||
}
|
||||
mrvl_port_bpool_size
|
||||
[bpool->pp2_id][bpool->id][core_id] -=
|
||||
pkt_to_remove;
|
||||
}
|
||||
rte_spinlock_unlock(&q->priv->lock);
|
||||
}
|
||||
|
||||
return rx_done;
|
||||
}
|
||||
|
||||
/**
|
||||
* Release already sent buffers to bpool (buffer-pool).
|
||||
*
|
||||
* @param ppio
|
||||
* Pointer to the port structure.
|
||||
* @param hif
|
||||
* Pointer to the MUSDK hardware interface.
|
||||
* @param sq
|
||||
* Pointer to the shadow queue.
|
||||
* @param qid
|
||||
* Queue id number.
|
||||
* @param force
|
||||
* Force releasing packets.
|
||||
*/
|
||||
static inline void
|
||||
mrvl_free_sent_buffers(struct pp2_ppio *ppio, struct pp2_hif *hif,
|
||||
struct mrvl_shadow_txq *sq, int qid, int force)
|
||||
{
|
||||
struct buff_release_entry *entry;
|
||||
uint16_t nb_done = 0, num = 0, skip_bufs = 0;
|
||||
int i, core_id = rte_lcore_id();
|
||||
|
||||
pp2_ppio_get_num_outq_done(ppio, hif, qid, &nb_done);
|
||||
|
||||
sq->num_to_release += nb_done;
|
||||
|
||||
if (likely(!force &&
|
||||
sq->num_to_release < MRVL_PP2_BUF_RELEASE_BURST_SIZE))
|
||||
return;
|
||||
|
||||
nb_done = sq->num_to_release;
|
||||
sq->num_to_release = 0;
|
||||
|
||||
for (i = 0; i < nb_done; i++) {
|
||||
entry = &sq->ent[sq->tail + num];
|
||||
if (unlikely(!entry->buff.addr)) {
|
||||
RTE_LOG(ERR, PMD,
|
||||
"Shadow memory @%d: cookie(%lx), pa(%lx)!\n",
|
||||
sq->tail, (u64)entry->buff.cookie,
|
||||
(u64)entry->buff.addr);
|
||||
skip_bufs = 1;
|
||||
goto skip;
|
||||
}
|
||||
|
||||
if (unlikely(!entry->bpool)) {
|
||||
struct rte_mbuf *mbuf;
|
||||
|
||||
mbuf = (struct rte_mbuf *)
|
||||
(cookie_addr_high | entry->buff.cookie);
|
||||
rte_pktmbuf_free(mbuf);
|
||||
skip_bufs = 1;
|
||||
goto skip;
|
||||
}
|
||||
|
||||
mrvl_port_bpool_size
|
||||
[entry->bpool->pp2_id][entry->bpool->id][core_id]++;
|
||||
num++;
|
||||
if (unlikely(sq->tail + num == MRVL_PP2_TX_SHADOWQ_SIZE))
|
||||
goto skip;
|
||||
continue;
|
||||
skip:
|
||||
if (likely(num))
|
||||
pp2_bpool_put_buffs(hif, &sq->ent[sq->tail], &num);
|
||||
num += skip_bufs;
|
||||
sq->tail = (sq->tail + num) & MRVL_PP2_TX_SHADOWQ_MASK;
|
||||
sq->size -= num;
|
||||
num = 0;
|
||||
}
|
||||
|
||||
if (likely(num)) {
|
||||
pp2_bpool_put_buffs(hif, &sq->ent[sq->tail], &num);
|
||||
sq->tail = (sq->tail + num) & MRVL_PP2_TX_SHADOWQ_MASK;
|
||||
sq->size -= num;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* DPDK callback for transmit.
|
||||
*
|
||||
* @param txq
|
||||
* Generic pointer transmit queue.
|
||||
* @param tx_pkts
|
||||
* Packets to transmit.
|
||||
* @param nb_pkts
|
||||
* Number of packets in array.
|
||||
*
|
||||
* @return
|
||||
* Number of packets successfully transmitted.
|
||||
*/
|
||||
static uint16_t
|
||||
mrvl_tx_pkt_burst(void *txq, struct rte_mbuf **tx_pkts, uint16_t nb_pkts)
|
||||
{
|
||||
struct mrvl_txq *q = txq;
|
||||
struct mrvl_shadow_txq *sq = &shadow_txqs[q->port_id][rte_lcore_id()];
|
||||
struct pp2_hif *hif = hifs[rte_lcore_id()];
|
||||
struct pp2_ppio_desc descs[nb_pkts];
|
||||
int i;
|
||||
uint16_t num, sq_free_size;
|
||||
|
||||
if (unlikely(!q->priv->ppio))
|
||||
return 0;
|
||||
|
||||
if (sq->size)
|
||||
mrvl_free_sent_buffers(q->priv->ppio, hif, sq, q->queue_id, 0);
|
||||
|
||||
sq_free_size = MRVL_PP2_TX_SHADOWQ_SIZE - sq->size - 1;
|
||||
if (unlikely(nb_pkts > sq_free_size)) {
|
||||
RTE_LOG(DEBUG, PMD,
|
||||
"No room in shadow queue for %d packets! %d packets will be sent.\n",
|
||||
nb_pkts, sq_free_size);
|
||||
nb_pkts = sq_free_size;
|
||||
}
|
||||
|
||||
for (i = 0; i < nb_pkts; i++) {
|
||||
struct rte_mbuf *mbuf = tx_pkts[i];
|
||||
|
||||
if (likely(nb_pkts - i > MRVL_MUSDK_PREFETCH_SHIFT)) {
|
||||
struct rte_mbuf *pref_pkt_hdr;
|
||||
|
||||
pref_pkt_hdr = tx_pkts[i + MRVL_MUSDK_PREFETCH_SHIFT];
|
||||
rte_mbuf_prefetch_part1(pref_pkt_hdr);
|
||||
rte_mbuf_prefetch_part2(pref_pkt_hdr);
|
||||
}
|
||||
|
||||
sq->ent[sq->head].buff.cookie = (pp2_cookie_t)(uint64_t)mbuf;
|
||||
sq->ent[sq->head].buff.addr =
|
||||
rte_mbuf_data_dma_addr_default(mbuf);
|
||||
sq->ent[sq->head].bpool =
|
||||
(unlikely(mbuf->port == 0xff || mbuf->refcnt > 1)) ?
|
||||
NULL : mrvl_port_to_bpool_lookup[mbuf->port];
|
||||
sq->head = (sq->head + 1) & MRVL_PP2_TX_SHADOWQ_MASK;
|
||||
sq->size++;
|
||||
|
||||
pp2_ppio_outq_desc_reset(&descs[i]);
|
||||
pp2_ppio_outq_desc_set_phys_addr(&descs[i],
|
||||
rte_pktmbuf_mtophys(mbuf));
|
||||
pp2_ppio_outq_desc_set_pkt_offset(&descs[i], 0);
|
||||
pp2_ppio_outq_desc_set_pkt_len(&descs[i],
|
||||
rte_pktmbuf_pkt_len(mbuf));
|
||||
}
|
||||
|
||||
num = nb_pkts;
|
||||
pp2_ppio_send(q->priv->ppio, hif, q->queue_id, descs, &nb_pkts);
|
||||
/* number of packets that were not sent */
|
||||
if (unlikely(num > nb_pkts)) {
|
||||
for (i = nb_pkts; i < num; i++) {
|
||||
sq->head = (MRVL_PP2_TX_SHADOWQ_SIZE + sq->head - 1) &
|
||||
MRVL_PP2_TX_SHADOWQ_MASK;
|
||||
}
|
||||
sq->size -= num - nb_pkts;
|
||||
}
|
||||
|
||||
return nb_pkts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize packet processor.
|
||||
*
|
||||
@ -821,6 +1168,7 @@ mrvl_priv_create(const char *dev_name)
|
||||
goto out_clear_bpool_bit;
|
||||
|
||||
priv->ppio_params.type = PP2_PPIO_T_NIC;
|
||||
rte_spinlock_init(&priv->lock);
|
||||
|
||||
return priv;
|
||||
out_clear_bpool_bit:
|
||||
@ -875,6 +1223,8 @@ mrvl_eth_dev_create(struct rte_vdev_device *vdev, const char *name)
|
||||
memcpy(eth_dev->data->mac_addrs[0].addr_bytes,
|
||||
req.ifr_addr.sa_data, ETHER_ADDR_LEN);
|
||||
|
||||
eth_dev->rx_pkt_burst = mrvl_rx_pkt_burst;
|
||||
eth_dev->tx_pkt_burst = mrvl_tx_pkt_burst;
|
||||
eth_dev->data->dev_private = priv;
|
||||
eth_dev->device = &vdev->device;
|
||||
eth_dev->dev_ops = &mrvl_ops;
|
||||
@ -984,6 +1334,15 @@ mrvl_deinit_hifs(void)
|
||||
}
|
||||
}
|
||||
|
||||
static void mrvl_set_first_last_cores(int core_id)
|
||||
{
|
||||
if (core_id < mrvl_lcore_first)
|
||||
mrvl_lcore_first = core_id;
|
||||
|
||||
if (core_id > mrvl_lcore_last)
|
||||
mrvl_lcore_last = core_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* DPDK callback to register the virtual device.
|
||||
*
|
||||
@ -999,7 +1358,7 @@ rte_pmd_mrvl_probe(struct rte_vdev_device *vdev)
|
||||
struct rte_kvargs *kvlist;
|
||||
const char *ifnames[PP2_NUM_ETH_PPIO * PP2_NUM_PKT_PROC];
|
||||
int ret = -EINVAL;
|
||||
uint32_t i, ifnum, cfgnum;
|
||||
uint32_t i, ifnum, cfgnum, core_id;
|
||||
const char *params;
|
||||
|
||||
params = rte_vdev_device_args(vdev);
|
||||
@ -1053,6 +1412,15 @@ rte_pmd_mrvl_probe(struct rte_vdev_device *vdev)
|
||||
|
||||
rte_kvargs_free(kvlist);
|
||||
|
||||
memset(mrvl_port_bpool_size, 0, sizeof(mrvl_port_bpool_size));
|
||||
|
||||
mrvl_lcore_first = RTE_MAX_LCORE;
|
||||
mrvl_lcore_last = 0;
|
||||
|
||||
RTE_LCORE_FOREACH(core_id) {
|
||||
mrvl_set_first_last_cores(core_id);
|
||||
}
|
||||
|
||||
return 0;
|
||||
out_cleanup:
|
||||
for (; i > 0; i--)
|
||||
|
@ -33,6 +33,7 @@
|
||||
#ifndef _MRVL_ETHDEV_H_
|
||||
#define _MRVL_ETHDEV_H_
|
||||
|
||||
#include <rte_spinlock.h>
|
||||
#include <drivers/mv_pp2_cls.h>
|
||||
#include <drivers/mv_pp2_ppio.h>
|
||||
|
||||
@ -69,10 +70,20 @@
|
||||
/** Packet offset inside RX buffer. */
|
||||
#define MRVL_PKT_OFFS 64
|
||||
|
||||
/** Maximum number of descriptors in shadow queue. Must be power of 2 */
|
||||
#define MRVL_PP2_TX_SHADOWQ_SIZE MRVL_PP2_TXD_MAX
|
||||
|
||||
/** Shadow queue size mask (since shadow queue size is power of 2) */
|
||||
#define MRVL_PP2_TX_SHADOWQ_MASK (MRVL_PP2_TX_SHADOWQ_SIZE - 1)
|
||||
|
||||
/** Minimum number of sent buffers to release from shadow queue to BM */
|
||||
#define MRVL_PP2_BUF_RELEASE_BURST_SIZE 64
|
||||
|
||||
struct mrvl_priv {
|
||||
/* Hot fields, used in fast path. */
|
||||
struct pp2_bpool *bpool; /**< BPool pointer */
|
||||
struct pp2_ppio *ppio; /**< Port handler pointer */
|
||||
rte_spinlock_t lock; /**< Spinlock for checking bpool status */
|
||||
uint16_t bpool_max_size; /**< BPool maximum size */
|
||||
uint16_t bpool_min_size; /**< BPool minimum size */
|
||||
uint16_t bpool_init_size; /**< Configured BPool size */
|
||||
|
Loading…
Reference in New Issue
Block a user