vmxnet3: support manual thread assignment to tx queue
[vpp.git] / src / plugins / vmxnet3 / vmxnet3.c
1 /*
2  * Copyright (c) 2018 Cisco and/or its affiliates.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15
16 #include <vppinfra/types.h>
17 #include <vlib/vlib.h>
18 #include <vlib/pci/pci.h>
19 #include <vnet/ethernet/ethernet.h>
20 #include <vnet/plugin/plugin.h>
21 #include <vpp/app/version.h>
22 #include <vnet/interface/rx_queue_funcs.h>
23 #include <vnet/interface/tx_queue_funcs.h>
24 #include <vmxnet3/vmxnet3.h>
25
26 #define PCI_VENDOR_ID_VMWARE                            0x15ad
27 #define PCI_DEVICE_ID_VMWARE_VMXNET3                    0x07b0
28
29 vmxnet3_main_t vmxnet3_main;
30
31 static pci_device_id_t vmxnet3_pci_device_ids[] = {
32   {
33    .vendor_id = PCI_VENDOR_ID_VMWARE,
34    .device_id = PCI_DEVICE_ID_VMWARE_VMXNET3},
35   {0},
36 };
37
38 static clib_error_t *
39 vmxnet3_interface_admin_up_down (vnet_main_t * vnm, u32 hw_if_index,
40                                  u32 flags)
41 {
42   vnet_hw_interface_t *hi = vnet_get_hw_interface (vnm, hw_if_index);
43   vmxnet3_main_t *vmxm = &vmxnet3_main;
44   vmxnet3_device_t *vd = vec_elt_at_index (vmxm->devices, hi->dev_instance);
45   uword is_up = (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) != 0;
46
47   if (vd->flags & VMXNET3_DEVICE_F_ERROR)
48     return clib_error_return (0, "device is in error state");
49
50   if (is_up)
51     {
52       vnet_hw_interface_set_flags (vnm, vd->hw_if_index,
53                                    VNET_HW_INTERFACE_FLAG_LINK_UP);
54       vd->flags |= VMXNET3_DEVICE_F_ADMIN_UP;
55     }
56   else
57     {
58       vnet_hw_interface_set_flags (vnm, vd->hw_if_index, 0);
59       vd->flags &= ~VMXNET3_DEVICE_F_ADMIN_UP;
60     }
61   return 0;
62 }
63
64 static clib_error_t *
65 vmxnet3_interface_rx_mode_change (vnet_main_t * vnm, u32 hw_if_index, u32 qid,
66                                   vnet_hw_if_rx_mode mode)
67 {
68   vmxnet3_main_t *vmxm = &vmxnet3_main;
69   vnet_hw_interface_t *hw = vnet_get_hw_interface (vnm, hw_if_index);
70   vmxnet3_device_t *vd = pool_elt_at_index (vmxm->devices, hw->dev_instance);
71   vmxnet3_rxq_t *rxq = vec_elt_at_index (vd->rxqs, qid);
72
73   if (mode == VNET_HW_IF_RX_MODE_POLLING)
74     rxq->int_mode = 0;
75   else
76     rxq->int_mode = 1;
77
78   return 0;
79 }
80
81 static void
82 vmxnet3_set_interface_next_node (vnet_main_t * vnm, u32 hw_if_index,
83                                  u32 node_index)
84 {
85   vmxnet3_main_t *vmxm = &vmxnet3_main;
86   vnet_hw_interface_t *hw = vnet_get_hw_interface (vnm, hw_if_index);
87   vmxnet3_device_t *vd = pool_elt_at_index (vmxm->devices, hw->dev_instance);
88
89   /* Shut off redirection */
90   if (node_index == ~0)
91     {
92       vd->per_interface_next_index = node_index;
93       return;
94     }
95
96   vd->per_interface_next_index =
97     vlib_node_add_next (vlib_get_main (), vmxnet3_input_node.index,
98                         node_index);
99 }
100
101 static void
102 vmxnet3_clear_hw_interface_counters (u32 instance)
103 {
104   vmxnet3_main_t *vmxm = &vmxnet3_main;
105   vmxnet3_device_t *vd = pool_elt_at_index (vmxm->devices, instance);
106   vmxnet3_tx_queue *tx = VMXNET3_TX_START (vd);
107   vmxnet3_rx_queue *rx = VMXNET3_RX_START (vd);
108   u16 qid;
109
110   /*
111    * Set the "last_cleared_stats" to the current stats, so that
112    * things appear to clear from a display perspective.
113    */
114   vmxnet3_reg_write (vd, 1, VMXNET3_REG_CMD, VMXNET3_CMD_GET_STATS);
115
116   vec_foreach_index (qid, vd->txqs)
117   {
118     vmxnet3_tx_stats *txs = vec_elt_at_index (vd->tx_stats, qid);
119     clib_memcpy (txs, &tx->stats, sizeof (*txs));
120     tx++;
121   }
122   vec_foreach_index (qid, vd->rxqs)
123   {
124     vmxnet3_rx_stats *rxs = vec_elt_at_index (vd->rx_stats, qid);
125     clib_memcpy (rxs, &rx->stats, sizeof (*rxs));
126     rx++;
127   }
128 }
129
130 static char *vmxnet3_tx_func_error_strings[] = {
131 #define _(n,s) s,
132   foreach_vmxnet3_tx_func_error
133 #undef _
134 };
135
136 /* *INDENT-OFF* */
137 VNET_DEVICE_CLASS (vmxnet3_device_class,) =
138 {
139   .name = "VMXNET3 interface",
140   .format_device = format_vmxnet3_device,
141   .format_device_name = format_vmxnet3_device_name,
142   .admin_up_down_function = vmxnet3_interface_admin_up_down,
143   .clear_counters = vmxnet3_clear_hw_interface_counters,
144   .rx_mode_change_function = vmxnet3_interface_rx_mode_change,
145   .rx_redirect_to_node = vmxnet3_set_interface_next_node,
146   .tx_function_n_errors = VMXNET3_TX_N_ERROR,
147   .tx_function_error_strings = vmxnet3_tx_func_error_strings,
148 };
149 /* *INDENT-ON* */
150
151 static u32
152 vmxnet3_flag_change (vnet_main_t * vnm, vnet_hw_interface_t * hw, u32 flags)
153 {
154   return 0;
155 }
156
157 static void
158 vmxnet3_write_mac (vmxnet3_device_t * vd)
159 {
160   u32 val;
161
162   memcpy (&val, vd->mac_addr, 4);
163   vmxnet3_reg_write (vd, 1, VMXNET3_REG_MACL, val);
164
165   val = 0;
166   memcpy (&val, vd->mac_addr + 4, 2);
167   vmxnet3_reg_write (vd, 1, VMXNET3_REG_MACH, val);
168 }
169
170 static clib_error_t *
171 vmxnet3_provision_driver_shared (vlib_main_t * vm, vmxnet3_device_t * vd)
172 {
173   vmxnet3_shared *shared;
174   u64 shared_dma;
175   u16 qid, rid;
176   vmxnet3_tx_queue *tx = VMXNET3_TX_START (vd);
177   vmxnet3_rx_queue *rx = VMXNET3_RX_START (vd);
178
179   vd->driver_shared =
180     vlib_physmem_alloc_aligned_on_numa (vm, sizeof (*vd->driver_shared), 512,
181                                         vd->numa_node);
182   if (vd->driver_shared == 0)
183     return vlib_physmem_last_error (vm);
184
185   clib_memset (vd->driver_shared, 0, sizeof (*vd->driver_shared));
186
187   vec_foreach_index (qid, vd->txqs)
188   {
189     vmxnet3_txq_t *txq = vec_elt_at_index (vd->txqs, qid);
190
191     tx->cfg.desc_address = vmxnet3_dma_addr (vm, vd, txq->tx_desc);
192     tx->cfg.comp_address = vmxnet3_dma_addr (vm, vd, txq->tx_comp);
193     tx->cfg.num_desc = txq->size;
194     tx->cfg.num_comp = txq->size;
195     tx++;
196   }
197
198   vec_foreach_index (qid, vd->rxqs)
199   {
200     vmxnet3_rxq_t *rxq = vec_elt_at_index (vd->rxqs, qid);
201
202     for (rid = 0; rid < VMXNET3_RX_RING_SIZE; rid++)
203       {
204         rx->cfg.desc_address[rid] = vmxnet3_dma_addr (vm, vd,
205                                                       rxq->rx_desc[rid]);
206         rx->cfg.num_desc[rid] = rxq->size;
207       }
208     rx->cfg.comp_address = vmxnet3_dma_addr (vm, vd, rxq->rx_comp);
209     rx->cfg.num_comp = rxq->size;
210     rx->cfg.intr_index = qid;
211     rx++;
212   }
213
214   shared = vd->driver_shared;
215   shared->magic = VMXNET3_SHARED_MAGIC;
216   shared->misc.version = VMXNET3_VERSION_MAGIC;
217   if (sizeof (void *) == 4)
218     shared->misc.guest_info = VMXNET3_GOS_BITS_32;
219   else
220     shared->misc.guest_info = VMXNET3_GOS_BITS_64;
221   shared->misc.guest_info |= VMXNET3_GOS_TYPE_LINUX;
222   shared->misc.version_support = VMXNET3_VERSION_SELECT;
223   shared->misc.upt_features = VMXNET3_F_RXCSUM;
224   if (vd->gso_enable)
225     shared->misc.upt_features |= VMXNET3_F_LRO;
226   if (vd->num_rx_queues > 1)
227     {
228       shared->misc.upt_features |= VMXNET3_F_RSS;
229       shared->rss.version = 1;
230       shared->rss.address = vmxnet3_dma_addr (vm, vd, vd->rss);
231       shared->rss.length = sizeof (*vd->rss);
232     }
233   shared->misc.max_num_rx_sg = 0;
234   shared->misc.upt_version_support = VMXNET3_UPT_VERSION_SELECT;
235   shared->misc.queue_desc_address = vmxnet3_dma_addr (vm, vd, vd->queues);
236   shared->misc.queue_desc_len = sizeof (*tx) * vd->num_tx_queues +
237     sizeof (*rx) * vd->num_rx_queues;
238   shared->misc.mtu = VMXNET3_MTU;
239   shared->misc.num_tx_queues = vd->num_tx_queues;
240   shared->misc.num_rx_queues = vd->num_rx_queues;
241   shared->interrupt.num_intrs = vd->num_intrs;
242   shared->interrupt.event_intr_index = vd->num_rx_queues;
243   shared->interrupt.control = VMXNET3_IC_DISABLE_ALL;
244   shared->rx_filter.mode = VMXNET3_RXMODE_UCAST | VMXNET3_RXMODE_BCAST |
245     VMXNET3_RXMODE_ALL_MULTI | VMXNET3_RXMODE_PROMISC;
246   shared_dma = vmxnet3_dma_addr (vm, vd, shared);
247
248   vmxnet3_reg_write (vd, 1, VMXNET3_REG_DSAL, shared_dma);
249   vmxnet3_reg_write (vd, 1, VMXNET3_REG_DSAH, shared_dma >> 32);
250
251   return 0;
252 }
253
254 static inline void
255 vmxnet3_enable_interrupt (vmxnet3_device_t * vd)
256 {
257   int i;
258   vmxnet3_shared *shared = vd->driver_shared;
259
260   shared->interrupt.control &= ~VMXNET3_IC_DISABLE_ALL;
261   for (i = 0; i < vd->num_intrs; i++)
262     vmxnet3_reg_write (vd, 0, VMXNET3_REG_IMR + i * 8, 0);
263 }
264
265 static inline void
266 vmxnet3_disable_interrupt (vmxnet3_device_t * vd)
267 {
268   int i;
269   vmxnet3_shared *shared = vd->driver_shared;
270
271   shared->interrupt.control |= VMXNET3_IC_DISABLE_ALL;
272   for (i = 0; i < vd->num_intrs; i++)
273     vmxnet3_reg_write (vd, 0, VMXNET3_REG_IMR + i * 8, 1);
274 }
275
276 static clib_error_t *
277 vmxnet3_rxq_init (vlib_main_t * vm, vmxnet3_device_t * vd, u16 qid, u16 qsz)
278 {
279   vmxnet3_rxq_t *rxq;
280   vmxnet3_rx_stats *rxs;
281   u16 rid;
282
283   vec_validate (vd->rx_stats, qid);
284   rxs = vec_elt_at_index (vd->rx_stats, qid);
285   clib_memset (rxs, 0, sizeof (*rxs));
286
287   vec_validate_aligned (vd->rxqs, qid, CLIB_CACHE_LINE_BYTES);
288   rxq = vec_elt_at_index (vd->rxqs, qid);
289   clib_memset (rxq, 0, sizeof (*rxq));
290   rxq->size = qsz;
291   for (rid = 0; rid < VMXNET3_RX_RING_SIZE; rid++)
292     {
293       rxq->rx_desc[rid] = vlib_physmem_alloc_aligned_on_numa
294         (vm, qsz * sizeof (*rxq->rx_desc[rid]), 512, vd->numa_node);
295
296       if (rxq->rx_desc[rid] == 0)
297         return vlib_physmem_last_error (vm);
298
299       clib_memset (rxq->rx_desc[rid], 0, qsz * sizeof (*rxq->rx_desc[rid]));
300     }
301   rxq->rx_comp =
302     vlib_physmem_alloc_aligned_on_numa (vm, qsz * sizeof (*rxq->rx_comp), 512,
303                                         vd->numa_node);
304   if (rxq->rx_comp == 0)
305     return vlib_physmem_last_error (vm);
306
307   clib_memset (rxq->rx_comp, 0, qsz * sizeof (*rxq->rx_comp));
308   for (rid = 0; rid < VMXNET3_RX_RING_SIZE; rid++)
309     {
310       vmxnet3_rx_ring *ring;
311
312       ring = &rxq->rx_ring[rid];
313       ring->gen = VMXNET3_RXF_GEN;
314       ring->rid = rid;
315       vec_validate_aligned (ring->bufs, rxq->size, CLIB_CACHE_LINE_BYTES);
316     }
317   rxq->rx_comp_ring.gen = VMXNET3_RXCF_GEN;
318
319   return 0;
320 }
321
322 static clib_error_t *
323 vmxnet3_txq_init (vlib_main_t * vm, vmxnet3_device_t * vd, u16 qid, u16 qsz)
324 {
325   vmxnet3_txq_t *txq;
326   vmxnet3_tx_stats *txs;
327   u32 size;
328
329   vec_validate_aligned (vd->txqs, qid, CLIB_CACHE_LINE_BYTES);
330   txq = vec_elt_at_index (vd->txqs, qid);
331   clib_memset (txq, 0, sizeof (*txq));
332   clib_spinlock_init (&txq->lock);
333
334   vec_validate (vd->tx_stats, qid);
335   txs = vec_elt_at_index (vd->tx_stats, qid);
336   clib_memset (txs, 0, sizeof (*txs));
337
338   txq->size = qsz;
339   txq->reg_txprod = qid * 8 + VMXNET3_REG_TXPROD;
340
341   size = qsz * sizeof (*txq->tx_desc);
342   txq->tx_desc =
343     vlib_physmem_alloc_aligned_on_numa (vm, size, 512, vd->numa_node);
344   if (txq->tx_desc == 0)
345     return vlib_physmem_last_error (vm);
346
347   clib_memset (txq->tx_desc, 0, size);
348
349   size = qsz * sizeof (*txq->tx_comp);
350   txq->tx_comp =
351     vlib_physmem_alloc_aligned_on_numa (vm, size, 512, vd->numa_node);
352   if (txq->tx_comp == 0)
353     return vlib_physmem_last_error (vm);
354
355   clib_memset (txq->tx_comp, 0, size);
356   vec_validate_aligned (txq->tx_ring.bufs, txq->size, CLIB_CACHE_LINE_BYTES);
357   txq->tx_ring.gen = VMXNET3_TXF_GEN;
358   txq->tx_comp_ring.gen = VMXNET3_TXCF_GEN;
359
360   return 0;
361 }
362
363 static const u8 vmxnet3_rss_key[VMXNET3_RSS_MAX_KEY_SZ] = {
364   0x3b, 0x56, 0xd1, 0x56, 0x13, 0x4a, 0xe7, 0xac,
365   0xe8, 0x79, 0x09, 0x75, 0xe8, 0x65, 0x79, 0x28,
366   0x35, 0x12, 0xb9, 0x56, 0x7c, 0x76, 0x4b, 0x70,
367   0xd8, 0x56, 0xa3, 0x18, 0x9b, 0x0a, 0xee, 0xf3,
368   0x96, 0xa6, 0x9f, 0x8f, 0x9e, 0x8c, 0x90, 0xc9,
369 };
370
371 static clib_error_t *
372 vmxnet3_rss_init (vlib_main_t * vm, vmxnet3_device_t * vd)
373 {
374   vmxnet3_rss_shared *rss;
375   size_t size = sizeof (*rss);
376   u8 i;
377
378   vd->rss = vlib_physmem_alloc_aligned_on_numa (vm, size, 512, vd->numa_node);
379   if (vd->rss == 0)
380     return vlib_physmem_last_error (vm);
381
382   clib_memset (vd->rss, 0, size);
383   rss = vd->rss;
384   rss->hash_type =
385     VMXNET3_RSS_HASH_TYPE_IPV4 | VMXNET3_RSS_HASH_TYPE_TCP_IPV4 |
386     VMXNET3_RSS_HASH_TYPE_IPV6 | VMXNET3_RSS_HASH_TYPE_TCP_IPV6;
387   rss->hash_func = VMXNET3_RSS_HASH_FUNC_TOEPLITZ;
388   rss->hash_key_sz = VMXNET3_RSS_MAX_KEY_SZ;
389   rss->ind_table_sz = VMXNET3_RSS_MAX_IND_TABLE_SZ;
390   clib_memcpy (rss->hash_key, vmxnet3_rss_key, VMXNET3_RSS_MAX_KEY_SZ);
391   for (i = 0; i < rss->ind_table_sz; i++)
392     rss->ind_table[i] = i % vd->num_rx_queues;
393
394   return 0;
395 }
396
397 static clib_error_t *
398 vmxnet3_device_init (vlib_main_t * vm, vmxnet3_device_t * vd,
399                      vmxnet3_create_if_args_t * args)
400 {
401   clib_error_t *error = 0;
402   u32 ret, i, size;
403
404   /* Quiesce the device */
405   vmxnet3_reg_write (vd, 1, VMXNET3_REG_CMD, VMXNET3_CMD_QUIESCE_DEV);
406   ret = vmxnet3_reg_read (vd, 1, VMXNET3_REG_CMD);
407   if (ret != 0)
408     {
409       error = clib_error_return (0, "error on quiescing device rc (%u)", ret);
410       return error;
411     }
412
413   /* Reset the device */
414   vmxnet3_reg_write (vd, 1, VMXNET3_REG_CMD, VMXNET3_CMD_RESET_DEV);
415   ret = vmxnet3_reg_read (vd, 1, VMXNET3_REG_CMD);
416   if (ret != 0)
417     {
418       error = clib_error_return (0, "error on resetting device rc (%u)", ret);
419       return error;
420     }
421
422   ret = vmxnet3_reg_read (vd, 1, VMXNET3_REG_VRRS);
423   vd->version = count_leading_zeros (ret);
424   vd->version = uword_bits - vd->version;
425
426   if (vd->version == 0)
427     {
428       error = clib_error_return (0, "unsupported hardware version %u",
429                                  vd->version);
430       return error;
431     }
432
433   /* cap support version to 3 */
434   vmxnet3_reg_write (vd, 1, VMXNET3_REG_VRRS,
435                      1 << (clib_min (3, vd->version) - 1));
436
437   ret = vmxnet3_reg_read (vd, 1, VMXNET3_REG_UVRS);
438   if (ret & 1)
439     vmxnet3_reg_write (vd, 1, VMXNET3_REG_UVRS, 1);
440   else
441     {
442       error = clib_error_return (0, "unsupported upt version %u", ret);
443       return error;
444     }
445
446   /* GSO is only supported for version >= 3 */
447   if (args->enable_gso)
448     {
449       if (vd->version >= 3)
450         vd->gso_enable = 1;
451       else
452         {
453           error =
454             clib_error_return (0,
455                                "GSO is not supported because hardware version"
456                                " is %u. It must be >= 3", vd->version);
457           return error;
458         }
459     }
460
461   vmxnet3_reg_write (vd, 1, VMXNET3_REG_CMD, VMXNET3_CMD_GET_LINK);
462   ret = vmxnet3_reg_read (vd, 1, VMXNET3_REG_CMD);
463   if (ret & 1)
464     {
465       vd->flags |= VMXNET3_DEVICE_F_LINK_UP;
466       vd->link_speed = ret >> 16;
467     }
468   else
469     vd->flags &= ~VMXNET3_DEVICE_F_LINK_UP;
470
471   /* Get the mac address */
472   ret = vmxnet3_reg_read (vd, 1, VMXNET3_REG_MACL);
473   clib_memcpy (vd->mac_addr, &ret, 4);
474   ret = vmxnet3_reg_read (vd, 1, VMXNET3_REG_MACH);
475   clib_memcpy (vd->mac_addr + 4, &ret, 2);
476
477   size = sizeof (vmxnet3_rx_queue) * vd->num_rx_queues +
478     sizeof (vmxnet3_tx_queue) * vd->num_tx_queues;
479
480   vd->queues =
481     vlib_physmem_alloc_aligned_on_numa (vm, size, 512, vd->numa_node);
482   if (vd->queues == 0)
483     return vlib_physmem_last_error (vm);
484
485   clib_memset (vd->queues, 0, size);
486
487   if (vd->num_rx_queues > 1)
488     {
489       error = vmxnet3_rss_init (vm, vd);
490       if (error)
491         return error;
492     }
493
494   for (i = 0; i < vd->num_rx_queues; i++)
495     {
496       error = vmxnet3_rxq_init (vm, vd, i, args->rxq_size);
497       if (error)
498         return error;
499     }
500
501   for (i = 0; i < vd->num_tx_queues; i++)
502     {
503       error = vmxnet3_txq_init (vm, vd, i, args->txq_size);
504       if (error)
505         return error;
506     }
507
508   error = vmxnet3_provision_driver_shared (vm, vd);
509   if (error)
510     return error;
511
512   vmxnet3_write_mac (vd);
513
514   /* Activate device */
515   vmxnet3_reg_write (vd, 1, VMXNET3_REG_CMD, VMXNET3_CMD_ACTIVATE_DEV);
516   ret = vmxnet3_reg_read (vd, 1, VMXNET3_REG_CMD);
517   if (ret != 0)
518     {
519       error =
520         clib_error_return (0, "error on activating device rc (%u)", ret);
521       return error;
522     }
523
524   return error;
525 }
526
527 static void
528 vmxnet3_rxq_irq_handler (vlib_main_t * vm, vlib_pci_dev_handle_t h, u16 line)
529 {
530   vnet_main_t *vnm = vnet_get_main ();
531   vmxnet3_main_t *vmxm = &vmxnet3_main;
532   uword pd = vlib_pci_get_private_data (vm, h);
533   vmxnet3_device_t *vd = pool_elt_at_index (vmxm->devices, pd);
534   u16 qid = line;
535   vmxnet3_rxq_t *rxq = vec_elt_at_index (vd->rxqs, qid);
536
537   if (vec_len (vd->rxqs) > qid && vd->rxqs[qid].int_mode != 0)
538     vnet_hw_if_rx_queue_set_int_pending (vnm, rxq->queue_index);
539 }
540
541 static void
542 vmxnet3_event_irq_handler (vlib_main_t * vm, vlib_pci_dev_handle_t h,
543                            u16 line)
544 {
545   vnet_main_t *vnm = vnet_get_main ();
546   vmxnet3_main_t *vmxm = &vmxnet3_main;
547   uword pd = vlib_pci_get_private_data (vm, h);
548   vmxnet3_device_t *vd = pool_elt_at_index (vmxm->devices, pd);
549   u32 ret;
550
551   vmxnet3_reg_write (vd, 1, VMXNET3_REG_CMD, VMXNET3_CMD_GET_LINK);
552   ret = vmxnet3_reg_read (vd, 1, VMXNET3_REG_CMD);
553   if (ret & 1)
554     {
555       vd->flags |= VMXNET3_DEVICE_F_LINK_UP;
556       vd->link_speed = ret >> 16;
557       vnet_hw_interface_set_link_speed (vnm, vd->hw_if_index,
558                                         vd->link_speed * 1000);
559       vnet_hw_interface_set_flags (vnm, vd->hw_if_index,
560                                    VNET_HW_INTERFACE_FLAG_LINK_UP);
561     }
562   else
563     {
564       vd->flags &= ~VMXNET3_DEVICE_F_LINK_UP;
565       vnet_hw_interface_set_flags (vnm, vd->hw_if_index, 0);
566     }
567 }
568
569 static u8
570 vmxnet3_queue_size_valid (u16 qsz)
571 {
572   if (qsz < 64 || qsz > 4096)
573     return 0;
574   if ((qsz % 64) != 0)
575     return 0;
576   return 1;
577 }
578
579 static u8
580 vmxnet3_tx_queue_num_valid (u16 num)
581 {
582   vlib_thread_main_t *tm = vlib_get_thread_main ();
583
584   if ((num > VMXNET3_TXQ_MAX) || (num > tm->n_vlib_mains))
585     return 0;
586   return 1;
587 }
588
589 static u8
590 vmxnet3_rx_queue_num_valid (u16 num)
591 {
592   if (num > VMXNET3_RXQ_MAX)
593     return 0;
594   return 1;
595 }
596
597 void
598 vmxnet3_create_if (vlib_main_t * vm, vmxnet3_create_if_args_t * args)
599 {
600   vnet_main_t *vnm = vnet_get_main ();
601   vmxnet3_main_t *vmxm = &vmxnet3_main;
602   vmxnet3_device_t *vd;
603   vlib_pci_dev_handle_t h;
604   clib_error_t *error = 0;
605   u16 qid;
606   u32 num_intr;
607
608   if (args->txq_num == 0)
609     args->txq_num = 1;
610   if (args->rxq_num == 0)
611     args->rxq_num = 1;
612   if (!vmxnet3_rx_queue_num_valid (args->rxq_num))
613     {
614       args->rv = VNET_API_ERROR_INVALID_VALUE;
615       args->error =
616         clib_error_return (error, "number of rx queues must be <= %u",
617                            VMXNET3_RXQ_MAX);
618       vlib_log (VLIB_LOG_LEVEL_ERR, vmxm->log_default, "%U: %s",
619                 format_vlib_pci_addr, &args->addr,
620                 "number of rx queues must be <= %u", VMXNET3_RXQ_MAX);
621       return;
622     }
623
624   if (!vmxnet3_tx_queue_num_valid (args->txq_num))
625     {
626       args->rv = VNET_API_ERROR_INVALID_VALUE;
627       args->error =
628         clib_error_return (error,
629                            "number of tx queues must be <= %u and <= number of "
630                            "CPU's assigned to VPP", VMXNET3_TXQ_MAX);
631       vlib_log (VLIB_LOG_LEVEL_ERR, vmxm->log_default, "%U: %s",
632                 format_vlib_pci_addr, &args->addr,
633                 "number of tx queues must be <= %u and <= number of "
634                 "CPU's assigned to VPP", VMXNET3_TXQ_MAX);
635       return;
636     }
637   if (args->rxq_size == 0)
638     args->rxq_size = VMXNET3_NUM_RX_DESC;
639   if (args->txq_size == 0)
640     args->txq_size = VMXNET3_NUM_TX_DESC;
641
642   if (!vmxnet3_queue_size_valid (args->rxq_size) ||
643       !vmxnet3_queue_size_valid (args->txq_size))
644     {
645       args->rv = VNET_API_ERROR_INVALID_VALUE;
646       args->error =
647         clib_error_return (error,
648                            "queue size must be <= 4096, >= 64, "
649                            "and multiples of 64");
650       vlib_log (VLIB_LOG_LEVEL_ERR, vmxm->log_default, "%U: %s",
651                 format_vlib_pci_addr, &args->addr,
652                 "queue size must be <= 4096, >= 64, and multiples of 64");
653       return;
654     }
655
656   /* *INDENT-OFF* */
657   pool_foreach (vd, vmxm->devices)  {
658     if (vd->pci_addr.as_u32 == args->addr.as_u32)
659       {
660         args->rv = VNET_API_ERROR_ADDRESS_IN_USE;
661         args->error =
662           clib_error_return (error, "%U: %s", format_vlib_pci_addr,
663                              &args->addr, "pci address in use");
664         vlib_log (VLIB_LOG_LEVEL_ERR, vmxm->log_default, "%U: %s",
665                   format_vlib_pci_addr, &args->addr, "pci address in use");
666         return;
667       }
668   }
669   /* *INDENT-ON* */
670
671   if (args->bind)
672     {
673       error = vlib_pci_bind_to_uio (vm, &args->addr, (char *) "auto");
674       if (error)
675         {
676           args->rv = VNET_API_ERROR_INVALID_INTERFACE;
677           args->error =
678             clib_error_return (error, "%U: %s", format_vlib_pci_addr,
679                                &args->addr,
680                                "error encountered on binding pci device");
681           vlib_log (VLIB_LOG_LEVEL_ERR, vmxm->log_default, "%U: %s",
682                     format_vlib_pci_addr, &args->addr,
683                     "error encountered on binding pci devicee");
684           return;
685         }
686     }
687
688   if ((error =
689        vlib_pci_device_open (vm, &args->addr, vmxnet3_pci_device_ids, &h)))
690     {
691       args->rv = VNET_API_ERROR_INVALID_INTERFACE;
692       args->error =
693         clib_error_return (error, "%U: %s", format_vlib_pci_addr,
694                            &args->addr,
695                            "error encountered on pci device open");
696       vlib_log (VLIB_LOG_LEVEL_ERR, vmxm->log_default, "%U: %s",
697                 format_vlib_pci_addr, &args->addr,
698                 "error encountered on pci device open");
699       return;
700     }
701
702   /*
703    * Do not use vmxnet3_log_error prior to this line since the macro
704    * references vd->pci_dev_handle
705    */
706   pool_get (vmxm->devices, vd);
707   vd->num_tx_queues = args->txq_num;
708   vd->num_rx_queues = args->rxq_num;
709   vd->dev_instance = vd - vmxm->devices;
710   vd->per_interface_next_index = ~0;
711   vd->pci_addr = args->addr;
712
713   if (args->enable_elog)
714     vd->flags |= VMXNET3_DEVICE_F_ELOG;
715
716   vd->pci_dev_handle = h;
717   vd->numa_node = vlib_pci_get_numa_node (vm, h);
718   vd->num_intrs = vd->num_rx_queues + 1;        // +1 for the event interrupt
719
720   vlib_pci_set_private_data (vm, h, vd->dev_instance);
721
722   if ((error = vlib_pci_bus_master_enable (vm, h)))
723     {
724       vmxnet3_log_error (vd, "error encountered on pci bus master enable");
725       goto error;
726     }
727
728   if ((error = vlib_pci_map_region (vm, h, 0, (void **) &vd->bar[0])))
729     {
730       vmxnet3_log_error (vd, "error encountered on pci map region for bar 0");
731       goto error;
732     }
733
734   if ((error = vlib_pci_map_region (vm, h, 1, (void **) &vd->bar[1])))
735     {
736       vmxnet3_log_error (vd, "error encountered on pci map region for bar 1");
737       goto error;
738     }
739
740   num_intr = vlib_pci_get_num_msix_interrupts (vm, h);
741   if (num_intr < vd->num_rx_queues + 1)
742     {
743       vmxnet3_log_error (vd,
744                          "No sufficient interrupt lines (%u) for rx queues",
745                          num_intr);
746       error =
747         clib_error_return (0,
748                            "No sufficient interrupt lines (%u) for rx queues",
749                            num_intr);
750       goto error;
751     }
752   if ((error = vlib_pci_register_msix_handler (vm, h, 0, vd->num_rx_queues,
753                                                &vmxnet3_rxq_irq_handler)))
754     {
755       vmxnet3_log_error (vd,
756                          "error encountered on pci register msix handler 0");
757       goto error;
758     }
759
760   if ((error = vlib_pci_register_msix_handler (vm, h, vd->num_rx_queues, 1,
761                                                &vmxnet3_event_irq_handler)))
762     {
763       vmxnet3_log_error (vd,
764                          "error encountered on pci register msix handler 1");
765       goto error;
766     }
767
768   if ((error = vlib_pci_enable_msix_irq (vm, h, 0, vd->num_rx_queues + 1)))
769     {
770       vmxnet3_log_error (vd, "error encountered on pci enable msix irq");
771       goto error;
772     }
773
774   if ((error = vlib_pci_intr_enable (vm, h)))
775     {
776       vmxnet3_log_error (vd, "error encountered on pci interrupt enable");
777       goto error;
778     }
779
780   if ((error = vmxnet3_device_init (vm, vd, args)))
781     {
782       vmxnet3_log_error (vd, "error encountered on device init");
783       goto error;
784     }
785
786   /* create interface */
787   error = ethernet_register_interface (vnm, vmxnet3_device_class.index,
788                                        vd->dev_instance, vd->mac_addr,
789                                        &vd->hw_if_index, vmxnet3_flag_change);
790
791   if (error)
792     {
793       vmxnet3_log_error (vd,
794                          "error encountered on ethernet register interface");
795       goto error;
796     }
797
798   vnet_sw_interface_t *sw = vnet_get_hw_sw_interface (vnm, vd->hw_if_index);
799   vd->sw_if_index = sw->sw_if_index;
800   args->sw_if_index = sw->sw_if_index;
801
802   vnet_hw_interface_t *hw = vnet_get_hw_interface (vnm, vd->hw_if_index);
803   hw->caps |= VNET_HW_INTERFACE_CAP_SUPPORTS_INT_MODE;
804   if (vd->gso_enable)
805     {
806       hw->caps |= (VNET_HW_INTERFACE_CAP_SUPPORTS_TCP_GSO |
807                    VNET_HW_INTERFACE_CAP_SUPPORTS_TX_TCP_CKSUM |
808                    VNET_HW_INTERFACE_CAP_SUPPORTS_TX_UDP_CKSUM);
809     }
810
811   vnet_hw_if_set_input_node (vnm, vd->hw_if_index, vmxnet3_input_node.index);
812   /* Disable interrupts */
813   vmxnet3_disable_interrupt (vd);
814   vec_foreach_index (qid, vd->rxqs)
815   {
816     vmxnet3_rxq_t *rxq = vec_elt_at_index (vd->rxqs, qid);
817     u32 qi, fi;
818
819     qi = vnet_hw_if_register_rx_queue (vnm, vd->hw_if_index, qid,
820                                        VNET_HW_IF_RXQ_THREAD_ANY);
821     fi = vlib_pci_get_msix_file_index (vm, vd->pci_dev_handle, qid);
822     vnet_hw_if_set_rx_queue_file_index (vnm, qi, fi);
823     rxq->queue_index = qi;
824     rxq->buffer_pool_index =
825       vnet_hw_if_get_rx_queue_numa_node (vnm, rxq->queue_index);
826     vmxnet3_rxq_refill_ring0 (vm, vd, rxq);
827     vmxnet3_rxq_refill_ring1 (vm, vd, rxq);
828   }
829
830   vec_foreach_index (qid, vd->txqs)
831     {
832       vmxnet3_txq_t *txq = vec_elt_at_index (vd->txqs, qid);
833       txq->queue_index =
834         vnet_hw_if_register_tx_queue (vnm, vd->hw_if_index, qid);
835     }
836   for (u32 i = 0; i < vlib_get_n_threads (); i++)
837     {
838       u32 qi = vd->txqs[i % vd->num_tx_queues].queue_index;
839       vnet_hw_if_tx_queue_assign_thread (vnm, qi, i);
840     }
841   vnet_hw_if_update_runtime_data (vnm, vd->hw_if_index);
842
843   vd->flags |= VMXNET3_DEVICE_F_INITIALIZED;
844   vmxnet3_enable_interrupt (vd);
845
846   vnet_hw_interface_set_link_speed (vnm, vd->hw_if_index,
847                                     vd->link_speed * 1000);
848   if (vd->flags & VMXNET3_DEVICE_F_LINK_UP)
849     vnet_hw_interface_set_flags (vnm, vd->hw_if_index,
850                                  VNET_HW_INTERFACE_FLAG_LINK_UP);
851   else
852     vnet_hw_interface_set_flags (vnm, vd->hw_if_index, 0);
853   return;
854
855 error:
856   vmxnet3_delete_if (vm, vd);
857   args->rv = VNET_API_ERROR_INVALID_INTERFACE;
858   args->error = error;
859 }
860
861 void
862 vmxnet3_delete_if (vlib_main_t * vm, vmxnet3_device_t * vd)
863 {
864   vnet_main_t *vnm = vnet_get_main ();
865   vmxnet3_main_t *vmxm = &vmxnet3_main;
866   u32 i, bi;
867   u16 desc_idx;
868
869   /* Quiesce the device */
870   vmxnet3_reg_write (vd, 1, VMXNET3_REG_CMD, VMXNET3_CMD_QUIESCE_DEV);
871
872   /* Reset the device */
873   vmxnet3_reg_write (vd, 1, VMXNET3_REG_CMD, VMXNET3_CMD_RESET_DEV);
874
875   if (vd->hw_if_index)
876     {
877       vnet_hw_interface_set_flags (vnm, vd->hw_if_index, 0);
878       ethernet_delete_interface (vnm, vd->hw_if_index);
879     }
880
881   vlib_pci_device_close (vm, vd->pci_dev_handle);
882
883   /* *INDENT-OFF* */
884   vec_foreach_index (i, vd->rxqs)
885     {
886       vmxnet3_rxq_t *rxq = vec_elt_at_index (vd->rxqs, i);
887       u16 mask = rxq->size - 1;
888       u16 rid;
889
890       for (rid = 0; rid < VMXNET3_RX_RING_SIZE; rid++)
891         {
892           vmxnet3_rx_ring *ring;
893
894           ring = &rxq->rx_ring[rid];
895           desc_idx = (ring->consume + 1) & mask;
896           vlib_buffer_free_from_ring (vm, ring->bufs, desc_idx, rxq->size,
897                                       ring->fill);
898           vec_free (ring->bufs);
899           vlib_physmem_free (vm, rxq->rx_desc[rid]);
900         }
901       vlib_physmem_free (vm, rxq->rx_comp);
902     }
903   /* *INDENT-ON* */
904   vec_free (vd->rxqs);
905   vec_free (vd->rx_stats);
906
907   /* *INDENT-OFF* */
908   vec_foreach_index (i, vd->txqs)
909     {
910       vmxnet3_txq_t *txq = vec_elt_at_index (vd->txqs, i);
911       u16 mask = txq->size - 1;
912       u16 end_idx;
913
914       desc_idx = txq->tx_ring.consume;
915       end_idx = txq->tx_ring.produce;
916       while (desc_idx != end_idx)
917         {
918           bi = txq->tx_ring.bufs[desc_idx];
919           vlib_buffer_free_no_next (vm, &bi, 1);
920           desc_idx++;
921           desc_idx &= mask;
922         }
923       clib_spinlock_free (&txq->lock);
924       vec_free (txq->tx_ring.bufs);
925       vlib_physmem_free (vm, txq->tx_desc);
926       vlib_physmem_free (vm, txq->tx_comp);
927     }
928   /* *INDENT-ON* */
929   vec_free (vd->txqs);
930   vec_free (vd->tx_stats);
931
932   vlib_physmem_free (vm, vd->driver_shared);
933   vlib_physmem_free (vm, vd->queues);
934   vlib_physmem_free (vm, vd->rss);
935
936   clib_error_free (vd->error);
937   clib_memset (vd, 0, sizeof (*vd));
938   pool_put (vmxm->devices, vd);
939
940 }
941
942 /*
943  * fd.io coding-style-patch-verification: ON
944  *
945  * Local Variables:
946  * eval: (c-set-style "gnu")
947  * End:
948  */