vmxnet3: multiple TX queues support
[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
23 #include <vmxnet3/vmxnet3.h>
24
25 #define PCI_VENDOR_ID_VMWARE                            0x15ad
26 #define PCI_DEVICE_ID_VMWARE_VMXNET3                    0x07b0
27
28 vmxnet3_main_t vmxnet3_main;
29
30 static pci_device_id_t vmxnet3_pci_device_ids[] = {
31   {
32    .vendor_id = PCI_VENDOR_ID_VMWARE,
33    .device_id = PCI_DEVICE_ID_VMWARE_VMXNET3},
34   {0},
35 };
36
37 static clib_error_t *
38 vmxnet3_interface_admin_up_down (vnet_main_t * vnm, u32 hw_if_index,
39                                  u32 flags)
40 {
41   vnet_hw_interface_t *hi = vnet_get_hw_interface (vnm, hw_if_index);
42   vmxnet3_main_t *vmxm = &vmxnet3_main;
43   vmxnet3_device_t *vd = vec_elt_at_index (vmxm->devices, hi->dev_instance);
44   uword is_up = (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) != 0;
45
46   if (vd->flags & VMXNET3_DEVICE_F_ERROR)
47     return clib_error_return (0, "device is in error state");
48
49   if (is_up)
50     {
51       vnet_hw_interface_set_flags (vnm, vd->hw_if_index,
52                                    VNET_HW_INTERFACE_FLAG_LINK_UP);
53       vd->flags |= VMXNET3_DEVICE_F_ADMIN_UP;
54     }
55   else
56     {
57       vnet_hw_interface_set_flags (vnm, vd->hw_if_index, 0);
58       vd->flags &= ~VMXNET3_DEVICE_F_ADMIN_UP;
59     }
60   return 0;
61 }
62
63 static clib_error_t *
64 vmxnet3_interface_rx_mode_change (vnet_main_t * vnm, u32 hw_if_index, u32 qid,
65                                   vnet_hw_interface_rx_mode mode)
66 {
67   vmxnet3_main_t *vmxm = &vmxnet3_main;
68   vnet_hw_interface_t *hw = vnet_get_hw_interface (vnm, hw_if_index);
69   vmxnet3_device_t *vd = pool_elt_at_index (vmxm->devices, hw->dev_instance);
70   vmxnet3_rxq_t *rxq = vec_elt_at_index (vd->rxqs, qid);
71
72   if (mode == VNET_HW_INTERFACE_RX_MODE_POLLING)
73     rxq->int_mode = 0;
74   else
75     rxq->int_mode = 1;
76
77   return 0;
78 }
79
80 static void
81 vmxnet3_set_interface_next_node (vnet_main_t * vnm, u32 hw_if_index,
82                                  u32 node_index)
83 {
84   vmxnet3_main_t *vmxm = &vmxnet3_main;
85   vnet_hw_interface_t *hw = vnet_get_hw_interface (vnm, hw_if_index);
86   vmxnet3_device_t *vd = pool_elt_at_index (vmxm->devices, hw->dev_instance);
87
88   /* Shut off redirection */
89   if (node_index == ~0)
90     {
91       vd->per_interface_next_index = node_index;
92       return;
93     }
94
95   vd->per_interface_next_index =
96     vlib_node_add_next (vlib_get_main (), vmxnet3_input_node.index,
97                         node_index);
98 }
99
100 static void
101 vmxnet3_clear_hw_interface_counters (u32 instance)
102 {
103   vmxnet3_main_t *vmxm = &vmxnet3_main;
104   vmxnet3_device_t *vd = pool_elt_at_index (vmxm->devices, instance);
105   vmxnet3_tx_queue *tx = VMXNET3_TX_START (vd);
106   vmxnet3_rx_queue *rx = VMXNET3_RX_START (vd);
107   u16 qid;
108
109   /*
110    * Set the "last_cleared_stats" to the current stats, so that
111    * things appear to clear from a display perspective.
112    */
113   vmxnet3_reg_write (vd, 1, VMXNET3_REG_CMD, VMXNET3_CMD_GET_STATS);
114
115   vec_foreach_index (qid, vd->txqs)
116   {
117     vmxnet3_tx_stats *txs = vec_elt_at_index (vd->tx_stats, qid);
118     clib_memcpy (txs, &tx->stats, sizeof (*txs));
119     tx++;
120   }
121   vec_foreach_index (qid, vd->rxqs)
122   {
123     vmxnet3_rx_stats *rxs = vec_elt_at_index (vd->rx_stats, qid);
124     clib_memcpy (rxs, &rx->stats, sizeof (*rxs));
125     rx++;
126   }
127 }
128
129 static char *vmxnet3_tx_func_error_strings[] = {
130 #define _(n,s) s,
131   foreach_vmxnet3_tx_func_error
132 #undef _
133 };
134
135 /* *INDENT-OFF* */
136 VNET_DEVICE_CLASS (vmxnet3_device_class,) =
137 {
138   .name = "VMXNET3 interface",
139   .format_device = format_vmxnet3_device,
140   .format_device_name = format_vmxnet3_device_name,
141   .admin_up_down_function = vmxnet3_interface_admin_up_down,
142   .clear_counters = vmxnet3_clear_hw_interface_counters,
143   .rx_mode_change_function = vmxnet3_interface_rx_mode_change,
144   .rx_redirect_to_node = vmxnet3_set_interface_next_node,
145   .tx_function_n_errors = VMXNET3_TX_N_ERROR,
146   .tx_function_error_strings = vmxnet3_tx_func_error_strings,
147 };
148 /* *INDENT-ON* */
149
150 static u32
151 vmxnet3_flag_change (vnet_main_t * vnm, vnet_hw_interface_t * hw, u32 flags)
152 {
153   return 0;
154 }
155
156 static void
157 vmxnet3_write_mac (vmxnet3_device_t * vd)
158 {
159   u32 val;
160
161   memcpy (&val, vd->mac_addr, 4);
162   vmxnet3_reg_write (vd, 1, VMXNET3_REG_MACL, val);
163
164   val = 0;
165   memcpy (&val, vd->mac_addr + 4, 2);
166   vmxnet3_reg_write (vd, 1, VMXNET3_REG_MACH, val);
167 }
168
169 static clib_error_t *
170 vmxnet3_provision_driver_shared (vlib_main_t * vm, vmxnet3_device_t * vd)
171 {
172   vmxnet3_shared *shared;
173   u64 shared_dma;
174   u16 qid, rid;
175   vmxnet3_tx_queue *tx = VMXNET3_TX_START (vd);
176   vmxnet3_rx_queue *rx = VMXNET3_RX_START (vd);
177
178   vd->driver_shared =
179     vlib_physmem_alloc_aligned_on_numa (vm, sizeof (*vd->driver_shared), 512,
180                                         vd->numa_node);
181   if (vd->driver_shared == 0)
182     return vlib_physmem_last_error (vm);
183
184   clib_memset (vd->driver_shared, 0, sizeof (*vd->driver_shared));
185
186   vec_foreach_index (qid, vd->txqs)
187   {
188     vmxnet3_txq_t *txq = vec_elt_at_index (vd->txqs, qid);
189
190     tx->cfg.desc_address = vmxnet3_dma_addr (vm, vd, txq->tx_desc);
191     tx->cfg.comp_address = vmxnet3_dma_addr (vm, vd, txq->tx_comp);
192     tx->cfg.num_desc = txq->size;
193     tx->cfg.num_comp = txq->size;
194     tx++;
195   }
196
197   vec_foreach_index (qid, vd->rxqs)
198   {
199     vmxnet3_rxq_t *rxq = vec_elt_at_index (vd->rxqs, qid);
200
201     for (rid = 0; rid < VMXNET3_RX_RING_SIZE; rid++)
202       {
203         rx->cfg.desc_address[rid] = vmxnet3_dma_addr (vm, vd,
204                                                       rxq->rx_desc[rid]);
205         rx->cfg.num_desc[rid] = rxq->size;
206       }
207     rx->cfg.comp_address = vmxnet3_dma_addr (vm, vd, rxq->rx_comp);
208     rx->cfg.num_comp = rxq->size;
209     rx++;
210   }
211
212   shared = vd->driver_shared;
213   shared->magic = VMXNET3_SHARED_MAGIC;
214   shared->misc.version = VMXNET3_VERSION_MAGIC;
215   if (sizeof (void *) == 4)
216     shared->misc.guest_info = VMXNET3_GOS_BITS_32;
217   else
218     shared->misc.guest_info = VMXNET3_GOS_BITS_64;
219   shared->misc.guest_info |= VMXNET3_GOS_TYPE_LINUX;
220   shared->misc.version_support = VMXNET3_VERSION_SELECT;
221   shared->misc.upt_version_support = VMXNET3_UPT_VERSION_SELECT;
222   shared->misc.queue_desc_address = vmxnet3_dma_addr (vm, vd, vd->queues);
223   shared->misc.queue_desc_len = sizeof (*tx) * vd->num_tx_queues +
224     sizeof (*rx) * vd->num_rx_queues;
225   shared->misc.mtu = VMXNET3_MTU;
226   shared->misc.num_tx_queues = vd->num_tx_queues;
227   shared->misc.num_rx_queues = vd->num_rx_queues;
228   shared->interrupt.num_intrs = vd->num_intrs;
229   shared->interrupt.event_intr_index = 1;
230   shared->interrupt.control = VMXNET3_IC_DISABLE_ALL;
231   shared->rx_filter.mode = VMXNET3_RXMODE_UCAST | VMXNET3_RXMODE_BCAST |
232     VMXNET3_RXMODE_ALL_MULTI | VMXNET3_RXMODE_PROMISC;
233   shared_dma = vmxnet3_dma_addr (vm, vd, shared);
234
235   vmxnet3_reg_write (vd, 1, VMXNET3_REG_DSAL, shared_dma);
236   vmxnet3_reg_write (vd, 1, VMXNET3_REG_DSAH, shared_dma >> 32);
237
238   return 0;
239 }
240
241 static inline void
242 vmxnet3_enable_interrupt (vmxnet3_device_t * vd)
243 {
244   int i;
245   vmxnet3_shared *shared = vd->driver_shared;
246
247   shared->interrupt.control &= ~VMXNET3_IC_DISABLE_ALL;
248   for (i = 0; i < vd->num_intrs; i++)
249     vmxnet3_reg_write (vd, 0, VMXNET3_REG_IMR + i * 8, 0);
250 }
251
252 static inline void
253 vmxnet3_disable_interrupt (vmxnet3_device_t * vd)
254 {
255   int i;
256   vmxnet3_shared *shared = vd->driver_shared;
257
258   shared->interrupt.control |= VMXNET3_IC_DISABLE_ALL;
259   for (i = 0; i < vd->num_intrs; i++)
260     vmxnet3_reg_write (vd, 0, VMXNET3_REG_IMR + i * 8, 1);
261 }
262
263 static clib_error_t *
264 vmxnet3_rxq_init (vlib_main_t * vm, vmxnet3_device_t * vd, u16 qid, u16 qsz)
265 {
266   vmxnet3_rxq_t *rxq;
267   vmxnet3_rx_stats *rxs;
268   u16 rid;
269
270   vec_validate (vd->rx_stats, qid);
271   rxs = vec_elt_at_index (vd->rx_stats, qid);
272   clib_memset (rxs, 0, sizeof (*rxs));
273
274   vec_validate_aligned (vd->rxqs, qid, CLIB_CACHE_LINE_BYTES);
275   rxq = vec_elt_at_index (vd->rxqs, qid);
276   clib_memset (rxq, 0, sizeof (*rxq));
277   rxq->size = qsz;
278   for (rid = 0; rid < VMXNET3_RX_RING_SIZE; rid++)
279     {
280       rxq->rx_desc[rid] = vlib_physmem_alloc_aligned_on_numa
281         (vm, qsz * sizeof (*rxq->rx_desc[rid]), 512, vd->numa_node);
282
283       if (rxq->rx_desc[rid] == 0)
284         return vlib_physmem_last_error (vm);
285
286       clib_memset (rxq->rx_desc[rid], 0, qsz * sizeof (*rxq->rx_desc[rid]));
287     }
288   rxq->rx_comp =
289     vlib_physmem_alloc_aligned_on_numa (vm, qsz * sizeof (*rxq->rx_comp), 512,
290                                         vd->numa_node);
291   if (rxq->rx_comp == 0)
292     return vlib_physmem_last_error (vm);
293
294   clib_memset (rxq->rx_comp, 0, qsz * sizeof (*rxq->rx_comp));
295   for (rid = 0; rid < VMXNET3_RX_RING_SIZE; rid++)
296     {
297       vmxnet3_rx_ring *ring;
298
299       ring = &rxq->rx_ring[rid];
300       ring->gen = VMXNET3_RXF_GEN;
301       ring->rid = rid;
302       vec_validate_aligned (ring->bufs, rxq->size, CLIB_CACHE_LINE_BYTES);
303     }
304   rxq->rx_comp_ring.gen = VMXNET3_RXCF_GEN;
305
306   return 0;
307 }
308
309 static clib_error_t *
310 vmxnet3_txq_init (vlib_main_t * vm, vmxnet3_device_t * vd, u16 qid, u16 qsz)
311 {
312   vmxnet3_txq_t *txq;
313   vmxnet3_tx_stats *txs;
314   u32 size;
315
316   if (qid >= vd->num_tx_queues)
317     {
318       qid = qid % vd->num_tx_queues;
319       txq = vec_elt_at_index (vd->txqs, qid);
320       if (txq->lock == 0)
321         clib_spinlock_init (&txq->lock);
322       vd->flags |= VMXNET3_DEVICE_F_SHARED_TXQ_LOCK;
323       return 0;
324     }
325
326   vec_validate (vd->tx_stats, qid);
327   txs = vec_elt_at_index (vd->tx_stats, qid);
328   clib_memset (txs, 0, sizeof (*txs));
329
330   vec_validate_aligned (vd->txqs, qid, CLIB_CACHE_LINE_BYTES);
331   txq = vec_elt_at_index (vd->txqs, qid);
332   clib_memset (txq, 0, sizeof (*txq));
333   txq->size = qsz;
334   txq->reg_txprod = qid * 8 + VMXNET3_REG_TXPROD;
335
336   size = qsz * sizeof (*txq->tx_desc);
337   txq->tx_desc =
338     vlib_physmem_alloc_aligned_on_numa (vm, size, 512, vd->numa_node);
339   if (txq->tx_desc == 0)
340     return vlib_physmem_last_error (vm);
341
342   memset (txq->tx_desc, 0, size);
343
344   size = qsz * sizeof (*txq->tx_comp);
345   txq->tx_comp =
346     vlib_physmem_alloc_aligned_on_numa (vm, size, 512, vd->numa_node);
347   if (txq->tx_comp == 0)
348     return vlib_physmem_last_error (vm);
349
350   clib_memset (txq->tx_comp, 0, size);
351   vec_validate_aligned (txq->tx_ring.bufs, txq->size, CLIB_CACHE_LINE_BYTES);
352   txq->tx_ring.gen = VMXNET3_TXF_GEN;
353   txq->tx_comp_ring.gen = VMXNET3_TXCF_GEN;
354
355   return 0;
356 }
357
358 static clib_error_t *
359 vmxnet3_device_init (vlib_main_t * vm, vmxnet3_device_t * vd,
360                      vmxnet3_create_if_args_t * args)
361 {
362   clib_error_t *error = 0;
363   u32 ret, i, size;
364   vlib_thread_main_t *tm = vlib_get_thread_main ();
365
366   /* Quiesce the device */
367   vmxnet3_reg_write (vd, 1, VMXNET3_REG_CMD, VMXNET3_CMD_QUIESCE_DEV);
368   ret = vmxnet3_reg_read (vd, 1, VMXNET3_REG_CMD);
369   if (ret != 0)
370     {
371       error = clib_error_return (0, "error on quiescing device rc (%u)", ret);
372       return error;
373     }
374
375   /* Reset the device */
376   vmxnet3_reg_write (vd, 1, VMXNET3_REG_CMD, VMXNET3_CMD_RESET_DEV);
377   ret = vmxnet3_reg_read (vd, 1, VMXNET3_REG_CMD);
378   if (ret != 0)
379     {
380       error = clib_error_return (0, "error on resetting device rc (%u)", ret);
381       return error;
382     }
383
384   ret = vmxnet3_reg_read (vd, 1, VMXNET3_REG_VRRS);
385   vd->version = count_leading_zeros (ret);
386   vd->version = uword_bits - vd->version;
387
388   if (vd->version == 0)
389     {
390       error = clib_error_return (0, "unsupported hardware version %u",
391                                  vd->version);
392       return error;
393     }
394
395   /* cap support version to 3 */
396   vmxnet3_reg_write (vd, 1, VMXNET3_REG_VRRS,
397                      1 << (clib_min (3, vd->version) - 1));
398
399   ret = vmxnet3_reg_read (vd, 1, VMXNET3_REG_UVRS);
400   if (ret & 1)
401     vmxnet3_reg_write (vd, 1, VMXNET3_REG_UVRS, 1);
402   else
403     {
404       error = clib_error_return (0, "unsupported upt version %u", ret);
405       return error;
406     }
407
408   vmxnet3_reg_write (vd, 1, VMXNET3_REG_CMD, VMXNET3_CMD_GET_LINK);
409   ret = vmxnet3_reg_read (vd, 1, VMXNET3_REG_CMD);
410   if (ret & 1)
411     {
412       vd->flags |= VMXNET3_DEVICE_F_LINK_UP;
413       vd->link_speed = ret >> 16;
414     }
415   else
416     {
417       vd->flags &= ~VMXNET3_DEVICE_F_LINK_UP;
418     }
419
420   /* Get the mac address */
421   ret = vmxnet3_reg_read (vd, 1, VMXNET3_REG_MACL);
422   clib_memcpy (vd->mac_addr, &ret, 4);
423   ret = vmxnet3_reg_read (vd, 1, VMXNET3_REG_MACH);
424   clib_memcpy (vd->mac_addr + 4, &ret, 2);
425
426   size = sizeof (vmxnet3_rx_queue) * vd->num_rx_queues +
427     sizeof (vmxnet3_tx_queue) * vd->num_tx_queues;
428
429   vd->queues =
430     vlib_physmem_alloc_aligned_on_numa (vm, size, 512, vd->numa_node);
431   if (vd->queues == 0)
432     return vlib_physmem_last_error (vm);
433
434   clib_memset (vd->queues, 0, size);
435
436   error = vmxnet3_rxq_init (vm, vd, 0, args->rxq_size);
437   if (error)
438     return error;
439
440   for (i = 0; i < tm->n_vlib_mains; i++)
441     {
442       error = vmxnet3_txq_init (vm, vd, i, args->txq_size);
443       if (error)
444         return error;
445     }
446
447   error = vmxnet3_provision_driver_shared (vm, vd);
448   if (error)
449     return error;
450
451   vmxnet3_write_mac (vd);
452
453   /* Activate device */
454   vmxnet3_reg_write (vd, 1, VMXNET3_REG_CMD, VMXNET3_CMD_ACTIVATE_DEV);
455   ret = vmxnet3_reg_read (vd, 1, VMXNET3_REG_CMD);
456   if (ret != 0)
457     {
458       error =
459         clib_error_return (0, "error on activating device rc (%u)", ret);
460       return error;
461     }
462
463   /* Disable interrupts */
464   vmxnet3_disable_interrupt (vd);
465
466   vec_foreach_index (i, vd->rxqs)
467   {
468     vmxnet3_rxq_t *rxq = vec_elt_at_index (vd->rxqs, i);
469
470     vmxnet3_rxq_refill_ring0 (vm, vd, rxq);
471     vmxnet3_rxq_refill_ring1 (vm, vd, rxq);
472   }
473   vd->flags |= VMXNET3_DEVICE_F_INITIALIZED;
474
475   vmxnet3_enable_interrupt (vd);
476
477   return error;
478 }
479
480 static void
481 vmxnet3_irq_0_handler (vlib_main_t * vm, vlib_pci_dev_handle_t h, u16 line)
482 {
483   vnet_main_t *vnm = vnet_get_main ();
484   vmxnet3_main_t *vmxm = &vmxnet3_main;
485   uword pd = vlib_pci_get_private_data (vm, h);
486   vmxnet3_device_t *vd = pool_elt_at_index (vmxm->devices, pd);
487   u16 qid = line;
488
489   if (vec_len (vd->rxqs) > qid && vd->rxqs[qid].int_mode != 0)
490     vnet_device_input_set_interrupt_pending (vnm, vd->hw_if_index, qid);
491 }
492
493 static void
494 vmxnet3_irq_1_handler (vlib_main_t * vm, vlib_pci_dev_handle_t h, u16 line)
495 {
496   vnet_main_t *vnm = vnet_get_main ();
497   vmxnet3_main_t *vmxm = &vmxnet3_main;
498   uword pd = vlib_pci_get_private_data (vm, h);
499   vmxnet3_device_t *vd = pool_elt_at_index (vmxm->devices, pd);
500   u32 ret;
501
502   vmxnet3_reg_write (vd, 1, VMXNET3_REG_CMD, VMXNET3_CMD_GET_LINK);
503   ret = vmxnet3_reg_read (vd, 1, VMXNET3_REG_CMD);
504   if (ret & 1)
505     {
506       vd->flags |= VMXNET3_DEVICE_F_LINK_UP;
507       vd->link_speed = ret >> 16;
508       vnet_hw_interface_set_link_speed (vnm, vd->hw_if_index,
509                                         vd->link_speed * 1000);
510       vnet_hw_interface_set_flags (vnm, vd->hw_if_index,
511                                    VNET_HW_INTERFACE_FLAG_LINK_UP);
512     }
513   else
514     {
515       vd->flags &= ~VMXNET3_DEVICE_F_LINK_UP;
516       vnet_hw_interface_set_flags (vnm, vd->hw_if_index, 0);
517     }
518 }
519
520 static u8
521 vmxnet3_queue_size_valid (u16 qsz)
522 {
523   if (qsz < 64 || qsz > 4096)
524     return 0;
525   if ((qsz % 64) != 0)
526     return 0;
527   return 1;
528 }
529
530 static u8
531 vmxnet3_queue_num_valid (u16 num)
532 {
533   vlib_thread_main_t *tm = vlib_get_thread_main ();
534
535   if ((num > VMXNET3_TXQ_MAX) || (num > tm->n_vlib_mains))
536     return 0;
537   return 1;
538 }
539
540 void
541 vmxnet3_create_if (vlib_main_t * vm, vmxnet3_create_if_args_t * args)
542 {
543   vnet_main_t *vnm = vnet_get_main ();
544   vmxnet3_main_t *vmxm = &vmxnet3_main;
545   vmxnet3_device_t *vd;
546   vlib_pci_dev_handle_t h;
547   clib_error_t *error = 0;
548
549   if (args->txq_num == 0)
550     args->txq_num = 1;
551   if (!vmxnet3_queue_num_valid (args->txq_num))
552     {
553       args->rv = VNET_API_ERROR_INVALID_VALUE;
554       args->error =
555         clib_error_return (error,
556                            "number of queues must be <= %u and <= number of "
557                            "CPU's assigned to VPP", VMXNET3_TXQ_MAX);
558       vlib_log (VLIB_LOG_LEVEL_ERR, vmxm->log_default, "%U: %s",
559                 format_vlib_pci_addr, &args->addr,
560                 "number of queues must be <= %u and <= number of "
561                 "CPU's assigned to VPP", VMXNET3_TXQ_MAX);
562       return;
563     }
564   if (args->rxq_size == 0)
565     args->rxq_size = VMXNET3_NUM_RX_DESC;
566   if (args->txq_size == 0)
567     args->txq_size = VMXNET3_NUM_TX_DESC;
568
569   if (!vmxnet3_queue_size_valid (args->rxq_size) ||
570       !vmxnet3_queue_size_valid (args->txq_size))
571     {
572       args->rv = VNET_API_ERROR_INVALID_VALUE;
573       args->error =
574         clib_error_return (error,
575                            "queue size must be <= 4096, >= 64, "
576                            "and multiples of 64");
577       vlib_log (VLIB_LOG_LEVEL_ERR, vmxm->log_default, "%U: %s",
578                 format_vlib_pci_addr, &args->addr,
579                 "queue size must be <= 4096, >= 64, and multiples of 64");
580       return;
581     }
582
583   /* *INDENT-OFF* */
584   pool_foreach (vd, vmxm->devices, ({
585     if (vd->pci_addr.as_u32 == args->addr.as_u32)
586       {
587         args->rv = VNET_API_ERROR_INVALID_VALUE;
588         args->error =
589           clib_error_return (error, "PCI address in use");
590         vlib_log (VLIB_LOG_LEVEL_ERR, vmxm->log_default, "%U: %s",
591                   format_vlib_pci_addr, &args->addr, "pci address in use");
592         return;
593       }
594   }));
595   /* *INDENT-ON* */
596
597   pool_get (vmxm->devices, vd);
598   vd->num_tx_queues = args->txq_num;
599   vd->dev_instance = vd - vmxm->devices;
600   vd->per_interface_next_index = ~0;
601   vd->pci_addr = args->addr;
602
603   if (args->enable_elog)
604     vd->flags |= VMXNET3_DEVICE_F_ELOG;
605
606   if ((error =
607        vlib_pci_device_open (vm, &args->addr, vmxnet3_pci_device_ids, &h)))
608     {
609       pool_put (vmxm->devices, vd);
610       args->rv = VNET_API_ERROR_INVALID_INTERFACE;
611       args->error =
612         clib_error_return (error, "pci-addr %U", format_vlib_pci_addr,
613                            &args->addr);
614       vlib_log (VLIB_LOG_LEVEL_ERR, vmxm->log_default, "%U: %s",
615                 format_vlib_pci_addr, &args->addr,
616                 "error encountered on pci device open");
617       return;
618     }
619
620   /*
621    * Do not use vmxnet3_log_error prior to this line since the macro
622    * references vd->pci_dev_handle
623    */
624   vd->pci_dev_handle = h;
625   vd->numa_node = vlib_pci_get_numa_node (vm, h);
626   vd->num_rx_queues = 1;
627   vd->num_intrs = 2;
628
629   vlib_pci_set_private_data (vm, h, vd->dev_instance);
630
631   if ((error = vlib_pci_bus_master_enable (vm, h)))
632     {
633       vmxnet3_log_error (vd, "error encountered on pci bus master enable");
634       goto error;
635     }
636
637   if ((error = vlib_pci_map_region (vm, h, 0, (void **) &vd->bar[0])))
638     {
639       vmxnet3_log_error (vd, "error encountered on pci map region for bar 0");
640       goto error;
641     }
642
643   if ((error = vlib_pci_map_region (vm, h, 1, (void **) &vd->bar[1])))
644     {
645       vmxnet3_log_error (vd, "error encountered on pci map region for bar 1");
646       goto error;
647     }
648
649   if ((error = vlib_pci_register_msix_handler (vm, h, 0, 1,
650                                                &vmxnet3_irq_0_handler)))
651     {
652       vmxnet3_log_error (vd,
653                          "error encountered on pci register msix handler 0");
654       goto error;
655     }
656
657   if ((error = vlib_pci_register_msix_handler (vm, h, 1, 1,
658                                                &vmxnet3_irq_1_handler)))
659     {
660       vmxnet3_log_error (vd,
661                          "error encountered on pci register msix handler 1");
662       goto error;
663     }
664
665   if ((error = vlib_pci_enable_msix_irq (vm, h, 0, 2)))
666     {
667       vmxnet3_log_error (vd, "error encountered on pci enable msix irq");
668       goto error;
669     }
670
671   if ((error = vlib_pci_intr_enable (vm, h)))
672     {
673       vmxnet3_log_error (vd, "error encountered on pci interrupt enable");
674       goto error;
675     }
676
677   if ((error = vmxnet3_device_init (vm, vd, args)))
678     {
679       vmxnet3_log_error (vd, "error encountered on device init");
680       goto error;
681     }
682
683   /* create interface */
684   error = ethernet_register_interface (vnm, vmxnet3_device_class.index,
685                                        vd->dev_instance, vd->mac_addr,
686                                        &vd->hw_if_index, vmxnet3_flag_change);
687
688   if (error)
689     {
690       vmxnet3_log_error (vd,
691                          "error encountered on ethernet register interface");
692       goto error;
693     }
694
695   vnet_sw_interface_t *sw = vnet_get_hw_sw_interface (vnm, vd->hw_if_index);
696   vd->sw_if_index = sw->sw_if_index;
697   args->sw_if_index = sw->sw_if_index;
698
699   vnet_hw_interface_t *hw = vnet_get_hw_interface (vnm, vd->hw_if_index);
700   hw->flags |= VNET_HW_INTERFACE_FLAG_SUPPORTS_INT_MODE;
701   vnet_hw_interface_set_input_node (vnm, vd->hw_if_index,
702                                     vmxnet3_input_node.index);
703   vnet_hw_interface_assign_rx_thread (vnm, vd->hw_if_index, 0, ~0);
704   vnet_hw_interface_set_link_speed (vnm, vd->hw_if_index,
705                                     vd->link_speed * 1000);
706   if (vd->flags & VMXNET3_DEVICE_F_LINK_UP)
707     vnet_hw_interface_set_flags (vnm, vd->hw_if_index,
708                                  VNET_HW_INTERFACE_FLAG_LINK_UP);
709   else
710     vnet_hw_interface_set_flags (vnm, vd->hw_if_index, 0);
711   return;
712
713 error:
714   vmxnet3_delete_if (vm, vd);
715   args->rv = VNET_API_ERROR_INVALID_INTERFACE;
716   args->error = error;
717 }
718
719 void
720 vmxnet3_delete_if (vlib_main_t * vm, vmxnet3_device_t * vd)
721 {
722   vnet_main_t *vnm = vnet_get_main ();
723   vmxnet3_main_t *vmxm = &vmxnet3_main;
724   u32 i, bi;
725   u16 desc_idx;
726
727   /* Quiesce the device */
728   vmxnet3_reg_write (vd, 1, VMXNET3_REG_CMD, VMXNET3_CMD_QUIESCE_DEV);
729
730   /* Reset the device */
731   vmxnet3_reg_write (vd, 1, VMXNET3_REG_CMD, VMXNET3_CMD_RESET_DEV);
732
733   if (vd->hw_if_index)
734     {
735       vnet_hw_interface_set_flags (vnm, vd->hw_if_index, 0);
736       vnet_hw_interface_unassign_rx_thread (vnm, vd->hw_if_index, 0);
737       ethernet_delete_interface (vnm, vd->hw_if_index);
738     }
739
740   vlib_pci_device_close (vm, vd->pci_dev_handle);
741
742   /* *INDENT-OFF* */
743   vec_foreach_index (i, vd->rxqs)
744     {
745       vmxnet3_rxq_t *rxq = vec_elt_at_index (vd->rxqs, i);
746       u16 mask = rxq->size - 1;
747       u16 rid;
748
749       for (rid = 0; rid < VMXNET3_RX_RING_SIZE; rid++)
750         {
751           vmxnet3_rx_ring *ring;
752
753           ring = &rxq->rx_ring[rid];
754           desc_idx = (ring->consume + 1) & mask;
755           vlib_buffer_free_from_ring (vm, ring->bufs, desc_idx, rxq->size,
756                                       ring->fill);
757           vec_free (ring->bufs);
758           vlib_physmem_free (vm, rxq->rx_desc[rid]);
759         }
760       vlib_physmem_free (vm, rxq->rx_comp);
761     }
762   /* *INDENT-ON* */
763   vec_free (vd->rxqs);
764   vec_free (vd->rx_stats);
765
766   /* *INDENT-OFF* */
767   vec_foreach_index (i, vd->txqs)
768     {
769       vmxnet3_txq_t *txq = vec_elt_at_index (vd->txqs, i);
770       u16 mask = txq->size - 1;
771       u16 end_idx;
772
773       desc_idx = txq->tx_ring.consume;
774       end_idx = txq->tx_ring.produce;
775       while (desc_idx != end_idx)
776         {
777           bi = txq->tx_ring.bufs[desc_idx];
778           vlib_buffer_free_no_next (vm, &bi, 1);
779           desc_idx++;
780           desc_idx &= mask;
781         }
782       clib_spinlock_free (&txq->lock);
783       vec_free (txq->tx_ring.bufs);
784       vlib_physmem_free (vm, txq->tx_desc);
785       vlib_physmem_free (vm, txq->tx_comp);
786     }
787   /* *INDENT-ON* */
788   vec_free (vd->txqs);
789   vec_free (vd->tx_stats);
790
791   vlib_physmem_free (vm, vd->driver_shared);
792   vlib_physmem_free (vm, vd->queues);
793
794   clib_error_free (vd->error);
795   clib_memset (vd, 0, sizeof (*vd));
796   pool_put (vmxm->devices, vd);
797 }
798
799 /*
800  * fd.io coding-style-patch-verification: ON
801  *
802  * Local Variables:
803  * eval: (c-set-style "gnu")
804  * End:
805  */