vmxnet3: multiple TX queues support 50/17150/6
authorSteven Luong <sluong@cisco.com>
Tue, 29 Jan 2019 23:13:31 +0000 (15:13 -0800)
committerDamjan Marion <dmarion@me.com>
Sat, 2 Feb 2019 15:31:22 +0000 (15:31 +0000)
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>
src/plugins/vmxnet3/README.md
src/plugins/vmxnet3/cli.c
src/plugins/vmxnet3/format.c
src/plugins/vmxnet3/output.c
src/plugins/vmxnet3/vmxnet3.api
src/plugins/vmxnet3/vmxnet3.c
src/plugins/vmxnet3/vmxnet3.h
src/plugins/vmxnet3/vmxnet3_api.c
src/plugins/vmxnet3/vmxnet3_test.c

index ef715a0..65a0bc8 100644 (file)
@@ -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
index 566b0d6..e110a47 100644 (file)
@@ -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);
index 981cda7..8e39b5f 100644 (file)
@@ -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;
 }
 
index 2a6418d..5c48549 100644 (file)
@@ -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);
 
index 68beac0..8666820 100644 (file)
@@ -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
index f7ae58c..a3aae99 100644 (file)
@@ -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));
index 781a951..3333f96 100644 (file)
@@ -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;
index b41866b..635657c 100644 (file)
@@ -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* */
index 53097f0..848b169 100644 (file)
@@ -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