aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteven Luong <sluong@cisco.com>2019-01-29 15:13:31 -0800
committerDamjan Marion <dmarion@me.com>2019-02-02 15:31:22 +0000
commit773291163a4f72f131afc6a84b065bcfed13aeb7 (patch)
tree55a50c027d91bef911d84e6c437b7aa57bbc9dad
parent900cbadde906a000ce1b431fc637a9c0f7089339 (diff)
vmxnet3: multiple TX queues support
Add num-tx-queues to the vmxnet3 create CLI/API. Default is 1. Max is min (8, the number of cores assigned to VPP). Change-Id: I7e0a659a82d01c719665c228dd8a71e3288a2895 Signed-off-by: Steven Luong <sluong@cisco.com>
-rw-r--r--src/plugins/vmxnet3/README.md2
-rw-r--r--src/plugins/vmxnet3/cli.c18
-rw-r--r--src/plugins/vmxnet3/format.c140
-rw-r--r--src/plugins/vmxnet3/output.c8
-rw-r--r--src/plugins/vmxnet3/vmxnet3.api46
-rw-r--r--src/plugins/vmxnet3/vmxnet3.c157
-rw-r--r--src/plugins/vmxnet3/vmxnet3.h36
-rw-r--r--src/plugins/vmxnet3/vmxnet3_api.c29
-rw-r--r--src/plugins/vmxnet3/vmxnet3_test.c42
9 files changed, 296 insertions, 182 deletions
diff --git a/src/plugins/vmxnet3/README.md b/src/plugins/vmxnet3/README.md
index ef715a09696..65a0bc89f4a 100644
--- a/src/plugins/vmxnet3/README.md
+++ b/src/plugins/vmxnet3/README.md
@@ -16,7 +16,7 @@ vfio driver can still be used with recent kernels which support no-iommu mode.
##Known issues
* TSO/LRO
-* RSS/multiple queues
+* RSS
* VLAN filter
## Usage
diff --git a/src/plugins/vmxnet3/cli.c b/src/plugins/vmxnet3/cli.c
index 566b0d68079..e110a479988 100644
--- a/src/plugins/vmxnet3/cli.c
+++ b/src/plugins/vmxnet3/cli.c
@@ -32,7 +32,6 @@ vmxnet3_create_command_fn (vlib_main_t * vm, unformat_input_t * input,
{
unformat_input_t _line_input, *line_input = &_line_input;
vmxnet3_create_if_args_t args;
- u32 tmp;
/* Get a line of input. */
if (!unformat_user (input, unformat_line_input, line_input))
@@ -45,10 +44,12 @@ vmxnet3_create_command_fn (vlib_main_t * vm, unformat_input_t * input,
;
else if (unformat (line_input, "elog"))
args.enable_elog = 1;
- else if (unformat (line_input, "rx-queue-size %u", &tmp))
- args.rxq_size = tmp;
- else if (unformat (line_input, "tx-queue-size %u", &tmp))
- args.txq_size = tmp;
+ else if (unformat (line_input, "rx-queue-size %u", &args.rxq_size))
+ ;
+ else if (unformat (line_input, "tx-queue-size %u", &args.txq_size))
+ ;
+ else if (unformat (line_input, "num-tx-queues %u", &args.txq_num))
+ ;
else
return clib_error_return (0, "unknown input `%U'",
format_unformat_error, input);
@@ -65,7 +66,8 @@ vmxnet3_create_command_fn (vlib_main_t * vm, unformat_input_t * input,
VLIB_CLI_COMMAND (vmxnet3_create_command, static) = {
.path = "create interface vmxnet3",
.short_help = "create interface vmxnet3 <pci-address>"
- "[rx-queue-size <size>] [tx-queue-size <size>]",
+ "[rx-queue-size <size>] [tx-queue-size <size>]"
+ "[num-tx-queues <number>]",
.function = vmxnet3_create_command_fn,
};
/* *INDENT-ON* */
@@ -319,9 +321,9 @@ show_vmxnet3 (vlib_main_t * vm, u32 * hw_if_indices, u8 show_descr,
}
}
- vec_foreach_index (qid, vd->rxqs)
+ vec_foreach_index (qid, vd->txqs)
{
- txq = vec_elt_at_index (vd->txqs, 0);
+ txq = vec_elt_at_index (vd->txqs, qid);
vlib_cli_output (vm, " Queue %u (TX)", qid);
vlib_cli_output (vm, " TX completion next index %u",
txq->tx_comp_ring.next);
diff --git a/src/plugins/vmxnet3/format.c b/src/plugins/vmxnet3/format.c
index 981cda73ff6..8e39b5faf36 100644
--- a/src/plugins/vmxnet3/format.c
+++ b/src/plugins/vmxnet3/format.c
@@ -58,9 +58,11 @@ format_vmxnet3_device (u8 * s, va_list * args)
vmxnet3_main_t *vmxm = &vmxnet3_main;
vmxnet3_device_t *vd = vec_elt_at_index (vmxm->devices, i);
u32 indent = format_get_indent (s);
- vmxnet3_queues *q = &vd->dma->queues;
vmxnet3_rxq_t *rxq = vec_elt_at_index (vd->rxqs, 0);
vmxnet3_txq_t *txq = vec_elt_at_index (vd->txqs, 0);
+ vmxnet3_tx_queue *tx = VMXNET3_TX_START (vd);
+ vmxnet3_rx_queue *rx = VMXNET3_RX_START (vd);
+ u16 qid;
s = format (s, "flags: %U", format_vmxnet3_device_flags, vd);
s = format (s, "\n%Urx queues %u, rx desc %u, tx queues %u, tx desc %u",
@@ -72,69 +74,81 @@ format_vmxnet3_device (u8 * s, va_list * args)
vmxnet3_reg_write (vd, 1, VMXNET3_REG_CMD, VMXNET3_CMD_GET_STATS);
- s = format (s, "\n%UTX:", format_white_space, indent);
- s = format (s, "\n%U TSO packets %llu",
- format_white_space, indent,
- q->tx.stats.tso_pkts - vd->tx_stats.tso_pkts);
- s = format (s, "\n%U TSO bytes %llu",
- format_white_space, indent,
- q->tx.stats.tso_bytes - vd->tx_stats.tso_bytes);
- s = format (s, "\n%U ucast packets %llu",
- format_white_space, indent,
- q->tx.stats.ucast_pkts - vd->tx_stats.ucast_pkts);
- s = format (s, "\n%U ucast bytes %llu",
- format_white_space, indent,
- q->tx.stats.ucast_bytes - vd->tx_stats.ucast_bytes);
- s = format (s, "\n%U mcast packets %llu",
- format_white_space, indent,
- q->tx.stats.mcast_pkts - vd->tx_stats.mcast_pkts);
- s = format (s, "\n%U mcast bytes %llu",
- format_white_space, indent,
- q->tx.stats.mcast_bytes - vd->tx_stats.mcast_bytes);
- s = format (s, "\n%U bcast packets %llu",
- format_white_space, indent,
- q->tx.stats.bcast_pkts - vd->tx_stats.bcast_pkts);
- s = format (s, "\n%U bcast bytes %llu",
- format_white_space, indent,
- q->tx.stats.bcast_bytes - vd->tx_stats.bcast_bytes);
- s = format (s, "\n%U Errors packets %llu",
- format_white_space, indent,
- q->tx.stats.error_pkts - vd->tx_stats.error_pkts);
- s = format (s, "\n%U Discard packets %llu",
- format_white_space, indent,
- q->tx.stats.discard_pkts - vd->tx_stats.discard_pkts);
+ vec_foreach_index (qid, vd->txqs)
+ {
+ vmxnet3_tx_stats *txs = vec_elt_at_index (vd->tx_stats, qid);
- s = format (s, "\n%URX:", format_white_space, indent);
- s = format (s, "\n%U LRO packets %llu",
- format_white_space, indent,
- q->rx.stats.lro_pkts - vd->rx_stats.lro_pkts);
- s = format (s, "\n%U LRO bytes %llu",
- format_white_space, indent,
- q->rx.stats.lro_bytes - vd->rx_stats.lro_bytes);
- s = format (s, "\n%U ucast packets %llu",
- format_white_space, indent,
- q->rx.stats.ucast_pkts - vd->rx_stats.ucast_pkts);
- s = format (s, "\n%U ucast bytes %llu",
- format_white_space, indent,
- q->rx.stats.ucast_bytes - vd->rx_stats.ucast_bytes);
- s = format (s, "\n%U mcast packets %llu",
- format_white_space, indent,
- q->rx.stats.mcast_pkts - vd->rx_stats.mcast_pkts);
- s = format (s, "\n%U mcast bytes %llu",
- format_white_space, indent,
- q->rx.stats.mcast_bytes - vd->rx_stats.mcast_bytes);
- s = format (s, "\n%U bcast packets %llu",
- format_white_space, indent,
- q->rx.stats.bcast_pkts - vd->rx_stats.bcast_pkts);
- s = format (s, "\n%U bcast bytes %llu",
- format_white_space, indent,
- q->rx.stats.bcast_bytes - vd->rx_stats.bcast_bytes);
- s = format (s, "\n%U No Bufs %llu",
- format_white_space, indent,
- q->rx.stats.nobuf_pkts - vd->rx_stats.nobuf_pkts);
- s = format (s, "\n%U Error packets %llu",
- format_white_space, indent,
- q->rx.stats.error_pkts - vd->rx_stats.error_pkts);
+ s = format (s, "\n%UTX Queue %u:", format_white_space, indent, qid);
+ s = format (s, "\n%U TSO packets %llu",
+ format_white_space, indent,
+ tx->stats.tso_pkts - txs->tso_pkts);
+ s = format (s, "\n%U TSO bytes %llu",
+ format_white_space, indent,
+ tx->stats.tso_bytes - txs->tso_bytes);
+ s = format (s, "\n%U ucast packets %llu",
+ format_white_space, indent,
+ tx->stats.ucast_pkts - txs->ucast_pkts);
+ s = format (s, "\n%U ucast bytes %llu",
+ format_white_space, indent,
+ tx->stats.ucast_bytes - txs->ucast_bytes);
+ s = format (s, "\n%U mcast packets %llu",
+ format_white_space, indent,
+ tx->stats.mcast_pkts - txs->mcast_pkts);
+ s = format (s, "\n%U mcast bytes %llu",
+ format_white_space, indent,
+ tx->stats.mcast_bytes - txs->mcast_bytes);
+ s = format (s, "\n%U bcast packets %llu",
+ format_white_space, indent,
+ tx->stats.bcast_pkts - txs->bcast_pkts);
+ s = format (s, "\n%U bcast bytes %llu",
+ format_white_space, indent,
+ tx->stats.bcast_bytes - txs->bcast_bytes);
+ s = format (s, "\n%U Errors packets %llu",
+ format_white_space, indent,
+ tx->stats.error_pkts - txs->error_pkts);
+ s = format (s, "\n%U Discard packets %llu",
+ format_white_space, indent,
+ tx->stats.discard_pkts - txs->discard_pkts);
+ tx++;
+ }
+
+ vec_foreach_index (qid, vd->rxqs)
+ {
+ vmxnet3_rx_stats *rxs = vec_elt_at_index (vd->rx_stats, qid);
+
+ s = format (s, "\n%URX Queue %u:", format_white_space, indent, qid);
+ s = format (s, "\n%U LRO packets %llu",
+ format_white_space, indent,
+ rx->stats.lro_pkts - rxs->lro_pkts);
+ s = format (s, "\n%U LRO bytes %llu",
+ format_white_space, indent,
+ rx->stats.lro_bytes - rxs->lro_bytes);
+ s = format (s, "\n%U ucast packets %llu",
+ format_white_space, indent,
+ rx->stats.ucast_pkts - rxs->ucast_pkts);
+ s = format (s, "\n%U ucast bytes %llu",
+ format_white_space, indent,
+ rx->stats.ucast_bytes - rxs->ucast_bytes);
+ s = format (s, "\n%U mcast packets %llu",
+ format_white_space, indent,
+ rx->stats.mcast_pkts - rxs->mcast_pkts);
+ s = format (s, "\n%U mcast bytes %llu",
+ format_white_space, indent,
+ rx->stats.mcast_bytes - rxs->mcast_bytes);
+ s = format (s, "\n%U bcast packets %llu",
+ format_white_space, indent,
+ rx->stats.bcast_pkts - rxs->bcast_pkts);
+ s = format (s, "\n%U bcast bytes %llu",
+ format_white_space, indent,
+ rx->stats.bcast_bytes - rxs->bcast_bytes);
+ s = format (s, "\n%U No Bufs %llu",
+ format_white_space, indent,
+ rx->stats.nobuf_pkts - rxs->nobuf_pkts);
+ s = format (s, "\n%U Error packets %llu",
+ format_white_space, indent,
+ rx->stats.error_pkts - rxs->error_pkts);
+ rx++;
+ }
return s;
}
diff --git a/src/plugins/vmxnet3/output.c b/src/plugins/vmxnet3/output.c
index 2a6418dfa44..5c48549e60d 100644
--- a/src/plugins/vmxnet3/output.c
+++ b/src/plugins/vmxnet3/output.c
@@ -108,8 +108,7 @@ VNET_DEVICE_CLASS_TX_FN (vmxnet3_device_class) (vlib_main_t * vm,
u16 space_left;
u16 n_left = frame->n_vectors;
vmxnet3_txq_t *txq;
- u32 thread_index = vm->thread_index;
- u16 qid = thread_index, produce;
+ u16 qid = vm->thread_index % vd->num_tx_queues, produce;
if (PREDICT_FALSE (!(vd->flags & VMXNET3_DEVICE_F_LINK_UP)))
{
@@ -119,7 +118,7 @@ VNET_DEVICE_CLASS_TX_FN (vmxnet3_device_class) (vlib_main_t * vm,
return (0);
}
- txq = vec_elt_at_index (vd->txqs, qid % vd->num_tx_queues);
+ txq = vec_elt_at_index (vd->txqs, qid);
clib_spinlock_lock_if_init (&txq->lock);
vmxnet3_txq_release (vm, vd, txq);
@@ -202,8 +201,7 @@ VNET_DEVICE_CLASS_TX_FN (vmxnet3_device_class) (vlib_main_t * vm,
}
if (PREDICT_TRUE (produce != txq->tx_ring.produce))
- vmxnet3_reg_write_inline (vd, 0, VMXNET3_REG_TXPROD,
- txq->tx_ring.produce);
+ vmxnet3_reg_write_inline (vd, 0, txq->reg_txprod, txq->tx_ring.produce);
clib_spinlock_unlock_if_init (&txq->lock);
diff --git a/src/plugins/vmxnet3/vmxnet3.api b/src/plugins/vmxnet3/vmxnet3.api
index 68beac030c1..8666820db69 100644
--- a/src/plugins/vmxnet3/vmxnet3.api
+++ b/src/plugins/vmxnet3/vmxnet3.api
@@ -26,6 +26,7 @@ option version = "1.0.0";
@param enable_elog - turn on elog (optional - default is off)
@param rxq_size - receive queue size (optional - default is 1024)
@param txq_size - transmit queue size (optional - default is 1024)
+ @param txq_num - number of transmit queues (optional - default is 1)
*/
define vmxnet3_create
@@ -37,6 +38,7 @@ define vmxnet3_create
i32 enable_elog;
u16 rxq_size;
u16 txq_size;
+ u16 txq_num;
};
/** \brief
@@ -66,21 +68,36 @@ autoreply define vmxnet3_delete
u32 sw_if_index;
};
+/** \brief vmxnet3_tx_list structure
+ @param tx_qsize - tx queue size
+ @param tx_next - tx next index
+ @param tx_produce - tx produce index
+ @param tx_consume - tx consume index
+*/
+
+typeonly define vmxnet3_tx_list
+{
+ u16 tx_qsize;
+ u16 tx_next;
+ u16 tx_produce;
+ u16 tx_consume;
+};
+
/** \brief Memory interface details structure
@param context - sender context, to match reply w/ request (memif_dump)
@param sw_if_index - index of the interface
@param if_name - name of the interface
@param hw_addr - interface MAC address
- @param id - id associated with the interface
- @param role - role of the interface in the connection (master/slave)
- @param mode - interface mode
- @param socket_id - id of the socket filename used by this interface
- to establish new connections
- @param ring_size - the number of entries of RX/TX rings
- @param buffer_size - size of the buffer allocated for each ring entry
+ @param pci_addr - pci address of the interface
+ @param version - vmxnet3 hardware version
@param admin_up_down - interface administrative status
- @param link_up_down - interface link status
-
+ @param rx_qsize - rx queue size
+ @param rx_fill - rx fill count
+ @param rx_next - rx next index
+ @param rx_produce - rx produce index
+ @param rx_consume - rx consume index
+ @param tx_count - number of of elements in tx_list
+ @param tx_list - list of vmnxnet3_tx_list
*/
define vmxnet3_details
{
@@ -91,21 +108,16 @@ define vmxnet3_details
u8 hw_addr[6];
u32 pci_addr;
u8 version;
+ u8 admin_up_down;
- u16 rx_qid;
u16 rx_qsize;
u16 rx_fill[2];
u16 rx_next;
u16 rx_produce[2];
u16 rx_consume[2];
- u16 tx_qid;
- u16 tx_qsize;
- u16 tx_next;
- u16 tx_produce;
- u16 tx_consume;
-
- u8 admin_up_down;
+ u8 tx_count;
+ vl_api_vmxnet3_tx_list_t tx_list[8];
};
/** \brief Dump all vmxnet3 interfaces
diff --git a/src/plugins/vmxnet3/vmxnet3.c b/src/plugins/vmxnet3/vmxnet3.c
index f7ae58c0fe4..a3aae99f211 100644
--- a/src/plugins/vmxnet3/vmxnet3.c
+++ b/src/plugins/vmxnet3/vmxnet3.c
@@ -102,7 +102,9 @@ vmxnet3_clear_hw_interface_counters (u32 instance)
{
vmxnet3_main_t *vmxm = &vmxnet3_main;
vmxnet3_device_t *vd = pool_elt_at_index (vmxm->devices, instance);
- vmxnet3_queues *q = &vd->dma->queues;
+ vmxnet3_tx_queue *tx = VMXNET3_TX_START (vd);
+ vmxnet3_rx_queue *rx = VMXNET3_RX_START (vd);
+ u16 qid;
/*
* Set the "last_cleared_stats" to the current stats, so that
@@ -110,8 +112,18 @@ vmxnet3_clear_hw_interface_counters (u32 instance)
*/
vmxnet3_reg_write (vd, 1, VMXNET3_REG_CMD, VMXNET3_CMD_GET_STATS);
- clib_memcpy (&vd->tx_stats, &q->tx.stats, sizeof (vd->tx_stats));
- clib_memcpy (&vd->rx_stats, &q->rx.stats, sizeof (vd->rx_stats));
+ vec_foreach_index (qid, vd->txqs)
+ {
+ vmxnet3_tx_stats *txs = vec_elt_at_index (vd->tx_stats, qid);
+ clib_memcpy (txs, &tx->stats, sizeof (*txs));
+ tx++;
+ }
+ vec_foreach_index (qid, vd->rxqs)
+ {
+ vmxnet3_rx_stats *rxs = vec_elt_at_index (vd->rx_stats, qid);
+ clib_memcpy (rxs, &rx->stats, sizeof (*rxs));
+ rx++;
+ }
}
static char *vmxnet3_tx_func_error_strings[] = {
@@ -158,34 +170,46 @@ static clib_error_t *
vmxnet3_provision_driver_shared (vlib_main_t * vm, vmxnet3_device_t * vd)
{
vmxnet3_shared *shared;
- vmxnet3_queues *q;
u64 shared_dma;
- u16 qid = 0, rid;
- vmxnet3_rxq_t *rxq = vec_elt_at_index (vd->rxqs, qid);
- vmxnet3_txq_t *txq = vec_elt_at_index (vd->txqs, qid);
+ u16 qid, rid;
+ vmxnet3_tx_queue *tx = VMXNET3_TX_START (vd);
+ vmxnet3_rx_queue *rx = VMXNET3_RX_START (vd);
- vd->dma = vlib_physmem_alloc_aligned_on_numa (vm, sizeof (*vd->dma), 512,
- vd->numa_node);
- if (vd->dma == 0)
+ vd->driver_shared =
+ vlib_physmem_alloc_aligned_on_numa (vm, sizeof (*vd->driver_shared), 512,
+ vd->numa_node);
+ if (vd->driver_shared == 0)
return vlib_physmem_last_error (vm);
- clib_memset (vd->dma, 0, sizeof (*vd->dma));
+ clib_memset (vd->driver_shared, 0, sizeof (*vd->driver_shared));
- q = &vd->dma->queues;
- q->tx.cfg.desc_address = vmxnet3_dma_addr (vm, vd, txq->tx_desc);
- q->tx.cfg.comp_address = vmxnet3_dma_addr (vm, vd, txq->tx_comp);
- q->tx.cfg.num_desc = txq->size;
- q->tx.cfg.num_comp = txq->size;
- for (rid = 0; rid < VMXNET3_RX_RING_SIZE; rid++)
- {
- q->rx.cfg.desc_address[rid] = vmxnet3_dma_addr (vm, vd,
+ vec_foreach_index (qid, vd->txqs)
+ {
+ vmxnet3_txq_t *txq = vec_elt_at_index (vd->txqs, qid);
+
+ tx->cfg.desc_address = vmxnet3_dma_addr (vm, vd, txq->tx_desc);
+ tx->cfg.comp_address = vmxnet3_dma_addr (vm, vd, txq->tx_comp);
+ tx->cfg.num_desc = txq->size;
+ tx->cfg.num_comp = txq->size;
+ tx++;
+ }
+
+ vec_foreach_index (qid, vd->rxqs)
+ {
+ vmxnet3_rxq_t *rxq = vec_elt_at_index (vd->rxqs, qid);
+
+ for (rid = 0; rid < VMXNET3_RX_RING_SIZE; rid++)
+ {
+ rx->cfg.desc_address[rid] = vmxnet3_dma_addr (vm, vd,
rxq->rx_desc[rid]);
- q->rx.cfg.num_desc[rid] = rxq->size;
- }
- q->rx.cfg.comp_address = vmxnet3_dma_addr (vm, vd, rxq->rx_comp);
- q->rx.cfg.num_comp = rxq->size;
+ rx->cfg.num_desc[rid] = rxq->size;
+ }
+ rx->cfg.comp_address = vmxnet3_dma_addr (vm, vd, rxq->rx_comp);
+ rx->cfg.num_comp = rxq->size;
+ rx++;
+ }
- shared = &vd->dma->shared;
+ shared = vd->driver_shared;
shared->magic = VMXNET3_SHARED_MAGIC;
shared->misc.version = VMXNET3_VERSION_MAGIC;
if (sizeof (void *) == 4)
@@ -195,8 +219,9 @@ vmxnet3_provision_driver_shared (vlib_main_t * vm, vmxnet3_device_t * vd)
shared->misc.guest_info |= VMXNET3_GOS_TYPE_LINUX;
shared->misc.version_support = VMXNET3_VERSION_SELECT;
shared->misc.upt_version_support = VMXNET3_UPT_VERSION_SELECT;
- shared->misc.queue_desc_address = vmxnet3_dma_addr (vm, vd, q);
- shared->misc.queue_desc_len = sizeof (*q);
+ shared->misc.queue_desc_address = vmxnet3_dma_addr (vm, vd, vd->queues);
+ shared->misc.queue_desc_len = sizeof (*tx) * vd->num_tx_queues +
+ sizeof (*rx) * vd->num_rx_queues;
shared->misc.mtu = VMXNET3_MTU;
shared->misc.num_tx_queues = vd->num_tx_queues;
shared->misc.num_rx_queues = vd->num_rx_queues;
@@ -217,7 +242,7 @@ static inline void
vmxnet3_enable_interrupt (vmxnet3_device_t * vd)
{
int i;
- vmxnet3_shared *shared = &vd->dma->shared;
+ vmxnet3_shared *shared = vd->driver_shared;
shared->interrupt.control &= ~VMXNET3_IC_DISABLE_ALL;
for (i = 0; i < vd->num_intrs; i++)
@@ -228,7 +253,7 @@ static inline void
vmxnet3_disable_interrupt (vmxnet3_device_t * vd)
{
int i;
- vmxnet3_shared *shared = &vd->dma->shared;
+ vmxnet3_shared *shared = vd->driver_shared;
shared->interrupt.control |= VMXNET3_IC_DISABLE_ALL;
for (i = 0; i < vd->num_intrs; i++)
@@ -239,8 +264,13 @@ static clib_error_t *
vmxnet3_rxq_init (vlib_main_t * vm, vmxnet3_device_t * vd, u16 qid, u16 qsz)
{
vmxnet3_rxq_t *rxq;
+ vmxnet3_rx_stats *rxs;
u16 rid;
+ vec_validate (vd->rx_stats, qid);
+ rxs = vec_elt_at_index (vd->rx_stats, qid);
+ clib_memset (rxs, 0, sizeof (*rxs));
+
vec_validate_aligned (vd->rxqs, qid, CLIB_CACHE_LINE_BYTES);
rxq = vec_elt_at_index (vd->rxqs, qid);
clib_memset (rxq, 0, sizeof (*rxq));
@@ -280,6 +310,8 @@ static clib_error_t *
vmxnet3_txq_init (vlib_main_t * vm, vmxnet3_device_t * vd, u16 qid, u16 qsz)
{
vmxnet3_txq_t *txq;
+ vmxnet3_tx_stats *txs;
+ u32 size;
if (qid >= vd->num_tx_queues)
{
@@ -291,24 +323,31 @@ vmxnet3_txq_init (vlib_main_t * vm, vmxnet3_device_t * vd, u16 qid, u16 qsz)
return 0;
}
+ vec_validate (vd->tx_stats, qid);
+ txs = vec_elt_at_index (vd->tx_stats, qid);
+ clib_memset (txs, 0, sizeof (*txs));
+
vec_validate_aligned (vd->txqs, qid, CLIB_CACHE_LINE_BYTES);
txq = vec_elt_at_index (vd->txqs, qid);
clib_memset (txq, 0, sizeof (*txq));
txq->size = qsz;
+ txq->reg_txprod = qid * 8 + VMXNET3_REG_TXPROD;
+
+ size = qsz * sizeof (*txq->tx_desc);
txq->tx_desc =
- vlib_physmem_alloc_aligned_on_numa (vm, qsz * sizeof (*txq->tx_desc), 512,
- vd->numa_node);
+ vlib_physmem_alloc_aligned_on_numa (vm, size, 512, vd->numa_node);
if (txq->tx_desc == 0)
return vlib_physmem_last_error (vm);
- memset (txq->tx_desc, 0, qsz * sizeof (*txq->tx_desc));
+ memset (txq->tx_desc, 0, size);
+
+ size = qsz * sizeof (*txq->tx_comp);
txq->tx_comp =
- vlib_physmem_alloc_aligned_on_numa (vm, qsz * sizeof (*txq->tx_comp), 512,
- vd->numa_node);
+ vlib_physmem_alloc_aligned_on_numa (vm, size, 512, vd->numa_node);
if (txq->tx_comp == 0)
return vlib_physmem_last_error (vm);
- clib_memset (txq->tx_comp, 0, qsz * sizeof (*txq->tx_comp));
+ clib_memset (txq->tx_comp, 0, size);
vec_validate_aligned (txq->tx_ring.bufs, txq->size, CLIB_CACHE_LINE_BYTES);
txq->tx_ring.gen = VMXNET3_TXF_GEN;
txq->tx_comp_ring.gen = VMXNET3_TXCF_GEN;
@@ -321,13 +360,9 @@ vmxnet3_device_init (vlib_main_t * vm, vmxnet3_device_t * vd,
vmxnet3_create_if_args_t * args)
{
clib_error_t *error = 0;
- u32 ret, i;
+ u32 ret, i, size;
vlib_thread_main_t *tm = vlib_get_thread_main ();
- vd->num_tx_queues = 1;
- vd->num_rx_queues = 1;
- vd->num_intrs = 2;
-
/* Quiesce the device */
vmxnet3_reg_write (vd, 1, VMXNET3_REG_CMD, VMXNET3_CMD_QUIESCE_DEV);
ret = vmxnet3_reg_read (vd, 1, VMXNET3_REG_CMD);
@@ -388,6 +423,16 @@ vmxnet3_device_init (vlib_main_t * vm, vmxnet3_device_t * vd,
ret = vmxnet3_reg_read (vd, 1, VMXNET3_REG_MACH);
clib_memcpy (vd->mac_addr + 4, &ret, 2);
+ size = sizeof (vmxnet3_rx_queue) * vd->num_rx_queues +
+ sizeof (vmxnet3_tx_queue) * vd->num_tx_queues;
+
+ vd->queues =
+ vlib_physmem_alloc_aligned_on_numa (vm, size, 512, vd->numa_node);
+ if (vd->queues == 0)
+ return vlib_physmem_last_error (vm);
+
+ clib_memset (vd->queues, 0, size);
+
error = vmxnet3_rxq_init (vm, vd, 0, args->rxq_size);
if (error)
return error;
@@ -482,6 +527,16 @@ vmxnet3_queue_size_valid (u16 qsz)
return 1;
}
+static u8
+vmxnet3_queue_num_valid (u16 num)
+{
+ vlib_thread_main_t *tm = vlib_get_thread_main ();
+
+ if ((num > VMXNET3_TXQ_MAX) || (num > tm->n_vlib_mains))
+ return 0;
+ return 1;
+}
+
void
vmxnet3_create_if (vlib_main_t * vm, vmxnet3_create_if_args_t * args)
{
@@ -491,6 +546,21 @@ vmxnet3_create_if (vlib_main_t * vm, vmxnet3_create_if_args_t * args)
vlib_pci_dev_handle_t h;
clib_error_t *error = 0;
+ if (args->txq_num == 0)
+ args->txq_num = 1;
+ if (!vmxnet3_queue_num_valid (args->txq_num))
+ {
+ args->rv = VNET_API_ERROR_INVALID_VALUE;
+ args->error =
+ clib_error_return (error,
+ "number of queues must be <= %u and <= number of "
+ "CPU's assigned to VPP", VMXNET3_TXQ_MAX);
+ vlib_log (VLIB_LOG_LEVEL_ERR, vmxm->log_default, "%U: %s",
+ format_vlib_pci_addr, &args->addr,
+ "number of queues must be <= %u and <= number of "
+ "CPU's assigned to VPP", VMXNET3_TXQ_MAX);
+ return;
+ }
if (args->rxq_size == 0)
args->rxq_size = VMXNET3_NUM_RX_DESC;
if (args->txq_size == 0)
@@ -525,6 +595,7 @@ vmxnet3_create_if (vlib_main_t * vm, vmxnet3_create_if_args_t * args)
/* *INDENT-ON* */
pool_get (vmxm->devices, vd);
+ vd->num_tx_queues = args->txq_num;
vd->dev_instance = vd - vmxm->devices;
vd->per_interface_next_index = ~0;
vd->pci_addr = args->addr;
@@ -552,6 +623,9 @@ vmxnet3_create_if (vlib_main_t * vm, vmxnet3_create_if_args_t * args)
*/
vd->pci_dev_handle = h;
vd->numa_node = vlib_pci_get_numa_node (vm, h);
+ vd->num_rx_queues = 1;
+ vd->num_intrs = 2;
+
vlib_pci_set_private_data (vm, h, vd->dev_instance);
if ((error = vlib_pci_bus_master_enable (vm, h)))
@@ -687,6 +761,7 @@ vmxnet3_delete_if (vlib_main_t * vm, vmxnet3_device_t * vd)
}
/* *INDENT-ON* */
vec_free (vd->rxqs);
+ vec_free (vd->rx_stats);
/* *INDENT-OFF* */
vec_foreach_index (i, vd->txqs)
@@ -711,8 +786,10 @@ vmxnet3_delete_if (vlib_main_t * vm, vmxnet3_device_t * vd)
}
/* *INDENT-ON* */
vec_free (vd->txqs);
+ vec_free (vd->tx_stats);
- vlib_physmem_free (vm, vd->dma);
+ vlib_physmem_free (vm, vd->driver_shared);
+ vlib_physmem_free (vm, vd->queues);
clib_error_free (vd->error);
clib_memset (vd, 0, sizeof (*vd));
diff --git a/src/plugins/vmxnet3/vmxnet3.h b/src/plugins/vmxnet3/vmxnet3.h
index 781a9519a0f..3333f96b85b 100644
--- a/src/plugins/vmxnet3/vmxnet3.h
+++ b/src/plugins/vmxnet3/vmxnet3.h
@@ -57,6 +57,11 @@ enum
#undef _
};
+#define VMXNET3_TXQ_MAX 8
+#define VMXNET3_TX_START(vd) ((vd)->queues)
+#define VMXNET3_RX_START(vd) \
+ ((vd)->queues + (vd)->num_tx_queues * sizeof (vmxnet3_tx_queue))
+
/* BAR 0 */
#define VMXNET3_REG_IMR 0x0000 /* Interrupt Mask Register */
#define VMXNET3_REG_TXPROD 0x0600 /* Tx Producer Index */
@@ -297,11 +302,6 @@ typedef CLIB_PACKED (struct
u8 pad[88];
}) vmxnet3_rx_queue;
-typedef CLIB_PACKED (struct
- {
- vmxnet3_tx_queue tx; vmxnet3_rx_queue rx;
- }) vmxnet3_queues;
-
/*
* flags:
* buffer length -- bits 0-13
@@ -445,6 +445,7 @@ typedef struct
{
CLIB_CACHE_LINE_ALIGN_MARK (cacheline0);
u16 size;
+ u32 reg_txprod;
clib_spinlock_t lock;
vmxnet3_tx_desc *tx_desc;
@@ -453,11 +454,6 @@ typedef struct
vmxnet3_tx_comp_ring tx_comp_ring;
} vmxnet3_txq_t;
-typedef CLIB_PACKED (struct
- {
- vmxnet3_queues queues; vmxnet3_shared shared;
- }) vmxnet3_dma;
-
typedef struct
{
CLIB_CACHE_LINE_ALIGN_MARK (cacheline0);
@@ -486,11 +482,12 @@ typedef struct
/* error */
clib_error_t *error;
- vmxnet3_dma *dma;
+ vmxnet3_shared *driver_shared;
+ void *queues;
u32 link_speed;
- vmxnet3_tx_stats tx_stats;
- vmxnet3_rx_stats rx_stats;
+ vmxnet3_tx_stats *tx_stats;
+ vmxnet3_rx_stats *rx_stats;
} vmxnet3_device_t;
typedef struct
@@ -508,6 +505,7 @@ typedef struct
u32 enable_elog;
u16 rxq_size;
u16 txq_size;
+ u16 txq_num;
/* return */
i32 rv;
u32 sw_if_index;
@@ -593,7 +591,7 @@ vmxnet3_rxq_refill_ring0 (vlib_main_t * vm, vmxnet3_device_t * vd,
vmxnet3_rx_desc *rxd;
u16 n_refill, n_alloc;
vmxnet3_rx_ring *ring;
- vmxnet3_queues *q;
+ vmxnet3_rx_queue *rx;
ring = &rxq->rx_ring[0];
n_refill = rxq->size - ring->fill;
@@ -624,8 +622,8 @@ vmxnet3_rxq_refill_ring0 (vlib_main_t * vm, vmxnet3_device_t * vd,
n_alloc--;
}
- q = &vd->dma->queues;
- if (PREDICT_FALSE (q->rx.ctrl.update_prod))
+ rx = VMXNET3_RX_START (vd);
+ if (PREDICT_FALSE (rx->ctrl.update_prod))
vmxnet3_reg_write_inline (vd, 0, VMXNET3_REG_RXPROD, ring->produce);
return 0;
@@ -638,7 +636,7 @@ vmxnet3_rxq_refill_ring1 (vlib_main_t * vm, vmxnet3_device_t * vd,
vmxnet3_rx_desc *rxd;
u16 n_refill, n_alloc;
vmxnet3_rx_ring *ring;
- vmxnet3_queues *q;
+ vmxnet3_rx_queue *rx;
ring = &rxq->rx_ring[1];
n_refill = rxq->size - ring->fill;
@@ -669,8 +667,8 @@ vmxnet3_rxq_refill_ring1 (vlib_main_t * vm, vmxnet3_device_t * vd,
n_alloc--;
}
- q = &vd->dma->queues;
- if (PREDICT_FALSE (q->rx.ctrl.update_prod))
+ rx = VMXNET3_RX_START (vd);
+ if (PREDICT_FALSE (rx->ctrl.update_prod))
vmxnet3_reg_write_inline (vd, 0, VMXNET3_REG_RXPROD2, ring->produce);
return 0;
diff --git a/src/plugins/vmxnet3/vmxnet3_api.c b/src/plugins/vmxnet3/vmxnet3_api.c
index b41866be117..635657c2bb6 100644
--- a/src/plugins/vmxnet3/vmxnet3_api.c
+++ b/src/plugins/vmxnet3/vmxnet3_api.c
@@ -71,6 +71,7 @@ vl_api_vmxnet3_create_t_handler (vl_api_vmxnet3_create_t * mp)
args.addr.as_u32 = ntohl (mp->pci_addr);
args.rxq_size = ntohs (mp->rxq_size);
args.txq_size = ntohs (mp->txq_size);
+ args.txq_num = ntohs (mp->txq_num);
vmxnet3_create_if (vm, &args);
rv = args.rv;
@@ -111,8 +112,7 @@ reply:
static void
send_vmxnet3_details (vl_api_registration_t * reg, vmxnet3_device_t * vd,
- u16 rx_qid, vmxnet3_rxq_t * rxq, u16 tx_qid,
- vmxnet3_txq_t * txq, vnet_sw_interface_t * swif,
+ vmxnet3_rxq_t * rxq, vnet_sw_interface_t * swif,
u8 * interface_name, u32 context)
{
vl_api_vmxnet3_details_t *mp;
@@ -120,7 +120,7 @@ send_vmxnet3_details (vl_api_registration_t * reg, vmxnet3_device_t * vd,
vmxnet3_main_t *vmxm = &vmxnet3_main;
vnet_hw_interface_t *hwif;
vmxnet3_rx_ring *ring;
- u16 rid;
+ u16 rid, qid;
hwif = vnet_get_sup_hw_interface (vnm, swif->sw_if_index);
@@ -139,6 +139,7 @@ send_vmxnet3_details (vl_api_registration_t * reg, vmxnet3_device_t * vd,
mp->version = vd->version;
mp->pci_addr = ntohl (vd->pci_addr.as_u32);
+ mp->admin_up_down = (swif->flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) ? 1 : 0;
mp->rx_qsize = htons (rxq->size);
mp->rx_next = htons (rxq->rx_comp_ring.next);
@@ -149,12 +150,19 @@ send_vmxnet3_details (vl_api_registration_t * reg, vmxnet3_device_t * vd,
mp->rx_produce[rid] = htons (ring->produce);
mp->rx_consume[rid] = htons (ring->consume);
}
- mp->tx_qsize = htons (txq->size);
- mp->tx_next = htons (txq->tx_comp_ring.next);
- mp->tx_produce = htons (txq->tx_ring.produce);
- mp->tx_consume = htons (txq->tx_ring.consume);
- mp->admin_up_down = (swif->flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) ? 1 : 0;
+ mp->tx_count = clib_min (vec_len (vd->txqs), VMXNET3_TXQ_MAX);
+ vec_foreach_index (qid, vd->txqs)
+ {
+ vmxnet3_txq_t *txq = vec_elt_at_index (vd->txqs, qid);
+ vl_api_vmxnet3_tx_list_t *tx_list = &mp->tx_list[qid];
+
+ ASSERT (qid < VMXNET3_TXQ_MAX);
+ tx_list->tx_qsize = htons (txq->size);
+ tx_list->tx_next = htons (txq->tx_comp_ring.next);
+ tx_list->tx_produce = htons (txq->tx_ring.produce);
+ tx_list->tx_consume = htons (txq->tx_ring.consume);
+ }
vl_api_send_msg (reg, (u8 *) mp);
}
@@ -173,7 +181,6 @@ vl_api_vmxnet3_dump_t_handler (vl_api_vmxnet3_dump_t * mp)
u8 *if_name = 0;
vl_api_registration_t *reg;
vmxnet3_rxq_t *rxq;
- vmxnet3_txq_t *txq;
u16 qid = 0;
reg = vl_api_client_index_to_registration (mp->client_index);
@@ -187,9 +194,7 @@ vl_api_vmxnet3_dump_t_handler (vl_api_vmxnet3_dump_t * mp)
if_name = format (if_name, "%U%c", format_vnet_sw_interface_name, vnm,
swif, 0);
rxq = vec_elt_at_index (vd->rxqs, qid);
- txq = vec_elt_at_index (vd->txqs, qid);
- send_vmxnet3_details (reg, vd, qid, rxq, qid, txq, swif, if_name,
- mp->context);
+ send_vmxnet3_details (reg, vd, rxq, swif, if_name, mp->context);
_vec_len (if_name) = 0;
}));
/* *INDENT-ON* */
diff --git a/src/plugins/vmxnet3/vmxnet3_test.c b/src/plugins/vmxnet3/vmxnet3_test.c
index 53097f02d63..848b1698797 100644
--- a/src/plugins/vmxnet3/vmxnet3_test.c
+++ b/src/plugins/vmxnet3/vmxnet3_test.c
@@ -121,6 +121,8 @@ api_vmxnet3_create (vat_main_t * vam)
;
else if (unformat (i, "tx-queue-size %u", &args.txq_size))
;
+ else if (unformat (i, "num-tx-queues %u", &args.txq_num))
+ ;
else
{
clib_warning ("unknown input '%U'", format_unformat_error, i);
@@ -134,6 +136,7 @@ api_vmxnet3_create (vat_main_t * vam)
mp->enable_elog = clib_host_to_net_u16 (args.enable_elog);
mp->rxq_size = clib_host_to_net_u16 (args.rxq_size);
mp->txq_size = clib_host_to_net_u16 (args.txq_size);
+ mp->txq_num = clib_host_to_net_u16 (args.txq_num);
S (mp);
W (ret);
@@ -240,33 +243,38 @@ vl_api_vmxnet3_details_t_handler (vl_api_vmxnet3_details_t * mp)
{
vat_main_t *vam = vmxnet3_test_main.vat_main;
u32 pci_addr = ntohl (mp->pci_addr);
+ u16 qid;
fformat (vam->ofp, "%s: sw_if_index %u mac %U\n"
" version: %u\n"
" PCI Address: %U\n"
- " RX completion next index %u"
- " RX Queue %u\n"
- " ring 0 size %u fill %u consume %u produce %u\n"
- " ring 1 size %u fill %u consume %u produce %u\n"
- " TX completion next index %u"
- " TX Queue %u\n"
- " size %u consume %u produce %u\n"
- " state %s\n",
+ " state %s\n"
+ " RX Queue 0\n"
+ " RX completion next index %u\n"
+ " ring 0 size %u fill %u consume %u produce %u\n"
+ " ring 1 size %u fill %u consume %u produce %u\n",
mp->if_name, ntohl (mp->sw_if_index), format_ethernet_address,
mp->hw_addr, mp->version,
format_pci_addr, &pci_addr,
+ mp->admin_up_down ? "up" : "down",
ntohs (mp->rx_next),
- ntohs (mp->rx_qid),
ntohs (mp->rx_qsize), ntohs (mp->rx_fill[0]),
ntohs (mp->rx_consume[0]),
ntohs (mp->rx_produce[0]),
ntohs (mp->rx_qsize), ntohs (mp->rx_fill[1]),
- ntohs (mp->rx_consume[1]),
- ntohs (mp->rx_produce[1]),
- ntohs (mp->tx_next),
- ntohs (mp->tx_qid),
- ntohs (mp->tx_qsize), ntohs (mp->tx_consume),
- ntohs (mp->tx_produce), mp->admin_up_down ? "up" : "down");
+ ntohs (mp->rx_consume[1]), ntohs (mp->rx_produce[1]));
+ for (qid = 0; qid < mp->tx_count; qid++)
+ {
+ vl_api_vmxnet3_tx_list_t *tx_list = &mp->tx_list[qid];
+ fformat (vam->ofp,
+ " TX Queue %u\n"
+ " TX completion next index %u\n"
+ " size %u consume %u produce %u\n",
+ qid,
+ ntohs (tx_list->tx_next),
+ ntohs (tx_list->tx_qsize), ntohs (tx_list->tx_consume),
+ ntohs (tx_list->tx_produce));
+ }
}
/*
@@ -275,8 +283,8 @@ vl_api_vmxnet3_details_t_handler (vl_api_vmxnet3_details_t * mp)
*/
#define foreach_vpe_api_msg \
_(vmxnet3_create, "<pci-address> [rx-queue-size <size>] " \
- "[tx-queue-size <size>]") \
-_(vmxnet3_delete, "<sw_if_index>") \
+ "[tx-queue-size <size>] [num-tx-queues <num>]") \
+_(vmxnet3_delete, "sw_if_index <sw_if_index>") \
_(vmxnet3_dump, "")
static void