tap: add gro support
[vpp.git] / src / vnet / devices / virtio / pci.c
index 65dab0a..d28c746 100644 (file)
@@ -272,7 +272,9 @@ virtio_pci_get_max_virtqueue_pairs (vlib_main_t * vm, virtio_if_t * vif)
 
   virtio_log_debug (vif, "max queue pair is %x", max_queue_pairs);
   if (max_queue_pairs < 1 || max_queue_pairs > 0x8000)
-    return clib_error_return (error, "max queue pair is %x", max_queue_pairs);
+    return clib_error_return (error, "max queue pair is %x,"
+                             " should be in range [1, 0x8000]",
+                             max_queue_pairs);
 
   vif->max_queue_pairs = max_queue_pairs;
   return error;
@@ -312,19 +314,22 @@ virtio_pci_is_link_up (vlib_main_t * vm, virtio_if_t * vif)
 }
 
 static void
-virtio_pci_irq_0_handler (vlib_main_t * vm, vlib_pci_dev_handle_t h, u16 line)
+virtio_pci_irq_queue_handler (vlib_main_t * vm, vlib_pci_dev_handle_t h,
+                             u16 line)
 {
   vnet_main_t *vnm = vnet_get_main ();
   virtio_main_t *vim = &virtio_main;
   uword pd = vlib_pci_get_private_data (vm, h);
   virtio_if_t *vif = pool_elt_at_index (vim->interfaces, pd);
+  line--;
   u16 qid = line;
 
   vnet_device_input_set_interrupt_pending (vnm, vif->hw_if_index, qid);
 }
 
 static void
-virtio_pci_irq_1_handler (vlib_main_t * vm, vlib_pci_dev_handle_t h, u16 line)
+virtio_pci_irq_config_handler (vlib_main_t * vm, vlib_pci_dev_handle_t h,
+                              u16 line)
 {
   vnet_main_t *vnm = vnet_get_main ();
   virtio_main_t *vim = &virtio_main;
@@ -361,10 +366,13 @@ virtio_pci_irq_handler (vlib_main_t * vm, vlib_pci_dev_handle_t h)
    * been made by the device which requires servicing.
    */
   if (isr & VIRTIO_PCI_ISR_INTR)
-    virtio_pci_irq_0_handler (vm, h, line);
+    {
+      for (; line < vif->num_rxqs; line++)
+       virtio_pci_irq_queue_handler (vm, h, (line + 1));
+    }
 
   if (isr & VIRTIO_PCI_ISR_CONFIG)
-    virtio_pci_irq_1_handler (vm, h, line);
+    virtio_pci_irq_config_handler (vm, h, line);
 }
 
 inline void
@@ -816,6 +824,7 @@ virtio_pci_vring_init (vlib_main_t * vm, virtio_if_t * vif, u16 queue_num)
   vring->used = vr.used;
   vring->queue_id = queue_num;
   vring->avail->flags = VIRTIO_RING_FLAG_MASK_INT;
+  vring->flow_table = 0;
 
   ASSERT (vring->buffers == 0);
   vec_validate_aligned (vring->buffers, queue_size, CLIB_CACHE_LINE_BYTES);
@@ -971,11 +980,13 @@ virtio_pci_read_caps (vlib_main_t * vm, virtio_if_t * vif)
            {
              virtio_log_debug (vif, "msix interrupt enabled");
              vif->msix_enabled = VIRTIO_MSIX_ENABLED;
+             vif->msix_table_size = table_size;
            }
          else
            {
              virtio_log_debug (vif, "msix interrupt disabled");
              vif->msix_enabled = VIRTIO_MSIX_DISABLED;
+             vif->msix_table_size = 0;
            }
        }
 
@@ -1034,10 +1045,15 @@ virtio_pci_device_init (vlib_main_t * vm, virtio_if_t * vif,
   u8 status = 0;
 
   if ((error = virtio_pci_read_caps (vm, vif)))
-    clib_error_return (error, "Device is not supported");
+    {
+      args->rv = VNET_API_ERROR_UNSUPPORTED;
+      virtio_log_error (vif, "Device is not supported");
+      clib_error_return (error, "Device is not supported");
+    }
 
   if (virtio_pci_reset_device (vm, vif) < 0)
     {
+      args->rv = VNET_API_ERROR_INIT_FAILED;
       virtio_log_error (vif, "Failed to reset the device");
       clib_error_return (error, "Failed to reset the device");
     }
@@ -1045,6 +1061,17 @@ virtio_pci_device_init (vlib_main_t * vm, virtio_if_t * vif,
    * read device features and negotiate (user) requested features
    */
   virtio_pci_read_device_feature (vm, vif);
+  if ((vif->remote_features & VIRTIO_FEATURE (VIRTIO_RING_F_INDIRECT_DESC)) ==
+      0)
+    {
+      virtio_log_warning (vif, "error encountered: vhost-net backend doesn't "
+                         "support VIRTIO_RING_F_INDIRECT_DESC features");
+    }
+  if ((vif->remote_features & VIRTIO_FEATURE (VIRTIO_NET_F_MRG_RXBUF)) == 0)
+    {
+      virtio_log_warning (vif, "error encountered: vhost-net backend doesn't "
+                         "support VIRTIO_NET_F_MRG_RXBUF features");
+    }
   virtio_negotiate_features (vm, vif, args->features);
 
   /*
@@ -1054,6 +1081,7 @@ virtio_pci_device_init (vlib_main_t * vm, virtio_if_t * vif,
   status = virtio_pci_legacy_get_status (vm, vif);
   if (!(status & VIRTIO_CONFIG_STATUS_FEATURES_OK))
     {
+      args->rv = VNET_API_ERROR_UNSUPPORTED;
       virtio_log_error (vif,
                        "error encountered: Device doesn't support requested features");
       clib_error_return (error, "Device doesn't support requested features");
@@ -1082,14 +1110,34 @@ virtio_pci_device_init (vlib_main_t * vm, virtio_if_t * vif,
    * Initialize the virtqueues
    */
   if ((error = virtio_pci_get_max_virtqueue_pairs (vm, vif)))
-    goto err;
+    {
+      args->rv = VNET_API_ERROR_EXCEEDED_NUMBER_OF_RANGES_CAPACITY;
+      goto err;
+    }
+
+  if (vif->msix_enabled == VIRTIO_MSIX_ENABLED)
+    {
+      if (vif->msix_table_size <= vif->max_queue_pairs)
+       {
+         virtio_log_error (vif,
+                           "error MSIX lines (%u) <= Number of RXQs (%u)",
+                           vif->msix_table_size, vif->max_queue_pairs);
+         return clib_error_return (error,
+                                   "error MSIX lines (%u) <= Number of RXQs (%u)",
+                                   vif->msix_table_size,
+                                   vif->max_queue_pairs);
+       }
+    }
 
   for (int i = 0; i < vif->max_queue_pairs; i++)
     {
       if ((error = virtio_pci_vring_init (vm, vif, RX_QUEUE (i))))
        {
-         virtio_log_warning (vif, "%s (%u) %s", "error in rxq-queue",
-                             RX_QUEUE (i), "initialization");
+         args->rv = VNET_API_ERROR_INIT_FAILED;
+         virtio_log_error (vif, "%s (%u) %s", "error in rxq-queue",
+                           RX_QUEUE (i), "initialization");
+         clib_error_return (error, "%s (%u) %s", "error in rxq-queue",
+                            RX_QUEUE (i), "initialization");
        }
       else
        {
@@ -1114,8 +1162,11 @@ virtio_pci_device_init (vlib_main_t * vm, virtio_if_t * vif,
 
       if ((error = virtio_pci_vring_init (vm, vif, TX_QUEUE (i))))
        {
-         virtio_log_warning (vif, "%s (%u) %s", "error in txq-queue",
-                             TX_QUEUE (i), "initialization");
+         args->rv = VNET_API_ERROR_INIT_FAILED;
+         virtio_log_error (vif, "%s (%u) %s", "error in txq-queue",
+                           TX_QUEUE (i), "initialization");
+         clib_error_return (error, "%s (%u) %s", "error in txq-queue",
+                            TX_QUEUE (i), "initialization");
        }
       else
        {
@@ -1145,12 +1196,30 @@ virtio_pci_device_init (vlib_main_t * vm, virtio_if_t * vif,
    */
   if (vif->msix_enabled == VIRTIO_MSIX_ENABLED)
     {
-      if (virtio_pci_legacy_set_config_irq (vm, vif, 1) ==
-         VIRTIO_MSI_NO_VECTOR)
-       virtio_log_warning (vif, "config vector 1 is not set");
-      if (virtio_pci_legacy_set_queue_irq (vm, vif, 0, 0) ==
+      int i, j;
+      if (virtio_pci_legacy_set_config_irq (vm, vif, 0) ==
          VIRTIO_MSI_NO_VECTOR)
-       virtio_log_warning (vif, "queue vector 0 is not set");
+       {
+         virtio_log_warning (vif, "config vector 0 is not set");
+       }
+      else
+       {
+         virtio_log_debug (vif, "config msix vector is set at 0");
+       }
+      for (i = 0, j = 1; i < vif->max_queue_pairs; i++, j++)
+       {
+         if (virtio_pci_legacy_set_queue_irq (vm, vif, j, RX_QUEUE (i)) ==
+             VIRTIO_MSI_NO_VECTOR)
+           {
+             virtio_log_warning (vif, "queue (%u) vector is not set at %u",
+                                 RX_QUEUE (i), j);
+           }
+         else
+           {
+             virtio_log_debug (vif, "%s (%u) %s %u", "queue",
+                               RX_QUEUE (i), "msix vector is set at", j);
+           }
+       }
     }
 
   /*
@@ -1170,12 +1239,13 @@ virtio_pci_create_if (vlib_main_t * vm, virtio_pci_create_if_args_t * args)
   virtio_if_t *vif;
   vlib_pci_dev_handle_t h;
   clib_error_t *error = 0;
+  u32 interrupt_count = 0;
 
   /* *INDENT-OFF* */
   pool_foreach (vif, vim->interfaces, ({
     if (vif->pci_addr.as_u32 == args->addr)
       {
-       args->rv = VNET_API_ERROR_INVALID_VALUE;
+       args->rv = VNET_API_ERROR_ADDRESS_IN_USE;
        args->error =
          clib_error_return (error, "PCI address in use");
          vlib_log (VLIB_LOG_LEVEL_ERR, vim->log_default, "%U: %s",
@@ -1222,24 +1292,29 @@ virtio_pci_create_if (vlib_main_t * vm, virtio_pci_create_if_args_t * args)
       goto error;
     }
 
-  if (vlib_pci_get_num_msix_interrupts (vm, h) > 1)
+  interrupt_count = vlib_pci_get_num_msix_interrupts (vm, h);
+  if (interrupt_count > 1)
     {
       if ((error = vlib_pci_register_msix_handler (vm, h, 0, 1,
-                                                  &virtio_pci_irq_0_handler)))
+                                                  &virtio_pci_irq_config_handler)))
        {
+         args->rv = VNET_API_ERROR_INVALID_REGISTRATION;
          virtio_log_error (vif,
                            "error encountered on pci register msix handler 0");
          goto error;
        }
-      if ((error = vlib_pci_register_msix_handler (vm, h, 1, 1,
-                                                  &virtio_pci_irq_1_handler)))
+
+      if ((error =
+          vlib_pci_register_msix_handler (vm, h, 1, (interrupt_count - 1),
+                                          &virtio_pci_irq_queue_handler)))
        {
+         args->rv = VNET_API_ERROR_INVALID_REGISTRATION;
          virtio_log_error (vif,
                            "error encountered on pci register msix handler 1");
          goto error;
        }
 
-      if ((error = vlib_pci_enable_msix_irq (vm, h, 0, 2)))
+      if ((error = vlib_pci_enable_msix_irq (vm, h, 0, interrupt_count)))
        {
          virtio_log_error (vif, "error encountered on pci enable msix irq");
          goto error;
@@ -1247,7 +1322,7 @@ virtio_pci_create_if (vlib_main_t * vm, virtio_pci_create_if_args_t * args)
       vif->support_int_mode = 1;
       virtio_log_debug (vif, "device supports msix interrupts");
     }
-  else if (vlib_pci_get_num_msix_interrupts (vm, h) == 1)
+  else if (interrupt_count == 1)
     {
       /*
        * if msix table-size is 1, fall back to intX.
@@ -1292,6 +1367,7 @@ virtio_pci_create_if (vlib_main_t * vm, virtio_pci_create_if_args_t * args)
 
   if (error)
     {
+      args->rv = VNET_API_ERROR_INVALID_REGISTRATION;
       virtio_log_error (vif,
                        "error encountered on ethernet register interface");
       goto error;
@@ -1336,7 +1412,8 @@ virtio_pci_create_if (vlib_main_t * vm, virtio_pci_create_if_args_t * args)
 
 error:
   virtio_pci_delete_if (vm, vif);
-  args->rv = VNET_API_ERROR_INVALID_INTERFACE;
+  if (args->rv == 0)
+    args->rv = VNET_API_ERROR_INVALID_INTERFACE;
   args->error = error;
 }