LCOV - code coverage report
Current view: top level - vnet/devices/virtio - pci.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 0 831 0.0 %
Date: 2023-07-05 22:20:52 Functions: 0 32 0.0 %

          Line data    Source code
       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 <fcntl.h>
      17             : #include <sys/ioctl.h>
      18             : 
      19             : #include <vppinfra/types.h>
      20             : #include <vlib/vlib.h>
      21             : #include <vlib/pci/pci.h>
      22             : #include <vnet/ethernet/ethernet.h>
      23             : #include <vnet/ip/ip4_packet.h>
      24             : #include <vnet/ip/ip6_packet.h>
      25             : #include <vnet/devices/virtio/virtio.h>
      26             : #include <vnet/devices/virtio/pci.h>
      27             : #include <vnet/interface/rx_queue_funcs.h>
      28             : 
      29             : #define PCI_VENDOR_ID_VIRTIO                            0x1af4
      30             : #define PCI_DEVICE_ID_VIRTIO_NIC                        0x1000
      31             : /* Doesn't support modern device */
      32             : #define PCI_DEVICE_ID_VIRTIO_NIC_MODERN                 0x1041
      33             : 
      34             : #define PCI_CAPABILITY_LIST     0x34
      35             : #define PCI_CAP_ID_VNDR         0x09
      36             : #define PCI_CAP_ID_MSIX         0x11
      37             : 
      38             : #define PCI_MSIX_ENABLE 0x8000
      39             : 
      40             : static pci_device_id_t virtio_pci_device_ids[] = {
      41             :   {
      42             :    .vendor_id = PCI_VENDOR_ID_VIRTIO,
      43             :    .device_id = PCI_DEVICE_ID_VIRTIO_NIC},
      44             :   {
      45             :    .vendor_id = PCI_VENDOR_ID_VIRTIO,
      46             :    .device_id = PCI_DEVICE_ID_VIRTIO_NIC_MODERN},
      47             :   {0},
      48             : };
      49             : 
      50             : static u32
      51           0 : virtio_pci_flag_change (vnet_main_t * vnm, vnet_hw_interface_t * hw,
      52             :                         u32 flags)
      53             : {
      54           0 :   return 0;
      55             : }
      56             : 
      57             : static clib_error_t *
      58           0 : virtio_pci_get_max_virtqueue_pairs (vlib_main_t * vm, virtio_if_t * vif)
      59             : {
      60           0 :   clib_error_t *error = 0;
      61           0 :   u16 max_queue_pairs = 1;
      62             : 
      63           0 :   if (vif->features & VIRTIO_FEATURE (VIRTIO_NET_F_MQ))
      64             :     {
      65           0 :       max_queue_pairs = vif->virtio_pci_func->get_max_queue_pairs (vm, vif);
      66             :     }
      67             : 
      68           0 :   virtio_log_debug (vif, "max queue pair is %x", max_queue_pairs);
      69           0 :   if (max_queue_pairs < 1 || max_queue_pairs > 0x8000)
      70           0 :     return clib_error_return (error, "max queue pair is %x,"
      71             :                               " should be in range [1, 0x8000]",
      72             :                               max_queue_pairs);
      73             : 
      74           0 :   vif->max_queue_pairs = max_queue_pairs;
      75           0 :   return error;
      76             : }
      77             : 
      78             : static void
      79           0 : virtio_pci_set_mac (vlib_main_t * vm, virtio_if_t * vif)
      80             : {
      81           0 :   if (vif->features & VIRTIO_FEATURE (VIRTIO_NET_F_MAC))
      82           0 :     vif->virtio_pci_func->set_mac (vm, vif);
      83           0 : }
      84             : 
      85             : static u32
      86           0 : virtio_pci_get_mac (vlib_main_t * vm, virtio_if_t * vif)
      87             : {
      88           0 :   if (vif->features & VIRTIO_FEATURE (VIRTIO_NET_F_MAC))
      89             :     {
      90           0 :       vif->virtio_pci_func->get_mac (vm, vif);
      91           0 :       return 0;
      92             :     }
      93           0 :   return 1;
      94             : }
      95             : 
      96             : static u16
      97           0 : virtio_pci_is_link_up (vlib_main_t * vm, virtio_if_t * vif)
      98             : {
      99             :   /*
     100             :    * Minimal driver: assumes link is up
     101             :    */
     102           0 :   u16 status = 1;
     103           0 :   if (vif->features & VIRTIO_FEATURE (VIRTIO_NET_F_STATUS))
     104           0 :     status = vif->virtio_pci_func->get_device_status (vm, vif);
     105           0 :   return status;
     106             : }
     107             : 
     108             : static void
     109           0 : virtio_pci_irq_queue_handler (vlib_main_t * vm, vlib_pci_dev_handle_t h,
     110             :                               u16 line)
     111             : {
     112           0 :   vnet_main_t *vnm = vnet_get_main ();
     113           0 :   virtio_main_t *vim = &virtio_main;
     114           0 :   uword pd = vlib_pci_get_private_data (vm, h);
     115           0 :   virtio_if_t *vif = pool_elt_at_index (vim->interfaces, pd);
     116           0 :   line--;
     117           0 :   u16 qid = line;
     118             : 
     119           0 :   vnet_virtio_vring_t *vring = vec_elt_at_index (vif->rxq_vrings, qid);
     120           0 :   vnet_hw_if_rx_queue_set_int_pending (vnm, vring->queue_index);
     121           0 : }
     122             : 
     123             : static void
     124           0 : virtio_pci_irq_config_handler (vlib_main_t * vm, vlib_pci_dev_handle_t h,
     125             :                                u16 line)
     126             : {
     127           0 :   vnet_main_t *vnm = vnet_get_main ();
     128           0 :   virtio_main_t *vim = &virtio_main;
     129           0 :   uword pd = vlib_pci_get_private_data (vm, h);
     130           0 :   virtio_if_t *vif = pool_elt_at_index (vim->interfaces, pd);
     131             : 
     132           0 :   if (virtio_pci_is_link_up (vm, vif) & VIRTIO_NET_S_LINK_UP)
     133             :     {
     134           0 :       vnet_hw_interface_set_flags (vnm, vif->hw_if_index,
     135             :                                    VNET_HW_INTERFACE_FLAG_LINK_UP);
     136             :     }
     137             :   else
     138             :     {
     139           0 :       vnet_hw_interface_set_flags (vnm, vif->hw_if_index, 0);
     140             :     }
     141           0 : }
     142             : 
     143             : static void
     144           0 : virtio_pci_irq_handler (vlib_main_t * vm, vlib_pci_dev_handle_t h)
     145             : {
     146           0 :   virtio_main_t *vim = &virtio_main;
     147           0 :   uword pd = vlib_pci_get_private_data (vm, h);
     148           0 :   virtio_if_t *vif = pool_elt_at_index (vim->interfaces, pd);
     149           0 :   u8 isr = 0;
     150           0 :   u16 line = 0;
     151             : 
     152           0 :   isr = vif->virtio_pci_func->get_isr (vm, vif);
     153             : 
     154             :   /*
     155             :    * If the lower bit is set: look through the used rings of
     156             :    * all virtqueues for the device, to see if any progress has
     157             :    * been made by the device which requires servicing.
     158             :    */
     159           0 :   if (isr & VIRTIO_PCI_ISR_INTR)
     160             :     {
     161           0 :       for (; line < vif->num_rxqs; line++)
     162           0 :         virtio_pci_irq_queue_handler (vm, h, (line + 1));
     163             :     }
     164             : 
     165           0 :   if (isr & VIRTIO_PCI_ISR_CONFIG)
     166           0 :     virtio_pci_irq_config_handler (vm, h, line);
     167           0 : }
     168             : 
     169             : inline void
     170           0 : device_status (vlib_main_t * vm, virtio_if_t * vif)
     171             : {
     172             :   struct status_struct
     173             :   {
     174             :     u8 bit;
     175             :     char *str;
     176             :   };
     177             :   struct status_struct *status_entry;
     178             :   static struct status_struct status_array[] = {
     179             : #define _(s,b) { .str = #s, .bit = b, },
     180             :     foreach_virtio_config_status_flags
     181             : #undef _
     182             :     {.str = NULL}
     183             :   };
     184             : 
     185           0 :   vlib_cli_output (vm, "  status 0x%x", vif->status);
     186             : 
     187           0 :   status_entry = (struct status_struct *) &status_array;
     188           0 :   while (status_entry->str)
     189             :     {
     190           0 :       if (vif->status & status_entry->bit)
     191           0 :         vlib_cli_output (vm, "    %s (%x)", status_entry->str,
     192           0 :                          status_entry->bit);
     193           0 :       status_entry++;
     194             :     }
     195           0 : }
     196             : 
     197             : static int
     198           0 : virtio_pci_send_ctrl_msg_packed (vlib_main_t * vm, virtio_if_t * vif,
     199             :                                  virtio_ctrl_msg_t * data, u32 len)
     200             : {
     201           0 :   vnet_virtio_vring_t *vring = vif->cxq_vring;
     202           0 :   virtio_net_ctrl_ack_t status = VIRTIO_NET_ERR;
     203             :   virtio_ctrl_msg_t result;
     204             :   u32 buffer_index;
     205             :   vlib_buffer_t *b;
     206             :   u16 used, next;
     207           0 :   u16 sz = vring->queue_size;
     208           0 :   u16 flags = 0, first_desc_flags = 0;
     209             : 
     210           0 :   used = vring->desc_in_use;
     211           0 :   next = vring->desc_next;
     212           0 :   vnet_virtio_vring_packed_desc_t *d = &vring->packed_desc[next];
     213             : 
     214           0 :   if (vlib_buffer_alloc (vm, &buffer_index, 1))
     215           0 :     b = vlib_get_buffer (vm, buffer_index);
     216             :   else
     217           0 :     return VIRTIO_NET_ERR;
     218             :   /*
     219             :    * current_data may not be initialized with 0 and may contain
     220             :    * previous offset.
     221             :    */
     222           0 :   b->current_data = 0;
     223           0 :   clib_memcpy (vlib_buffer_get_current (b), data, sizeof (virtio_ctrl_msg_t));
     224             : 
     225           0 :   first_desc_flags = VRING_DESC_F_NEXT;
     226           0 :   if (vring->avail_wrap_counter)
     227             :     {
     228           0 :       first_desc_flags |= VRING_DESC_F_AVAIL;
     229           0 :       first_desc_flags &= ~VRING_DESC_F_USED;
     230             :     }
     231             :   else
     232             :     {
     233           0 :       first_desc_flags &= ~VRING_DESC_F_AVAIL;
     234           0 :       first_desc_flags |= VRING_DESC_F_USED;
     235             :     }
     236           0 :   d->addr = vlib_buffer_get_current_pa (vm, b);
     237           0 :   d->len = sizeof (virtio_net_ctrl_hdr_t);
     238           0 :   d->id = next;
     239             : 
     240           0 :   next++;
     241           0 :   if (next >= sz)
     242             :     {
     243           0 :       next = 0;
     244           0 :       vring->avail_wrap_counter ^= 1;
     245             :     }
     246           0 :   used++;
     247             : 
     248           0 :   d = &vring->packed_desc[next];
     249           0 :   flags = VRING_DESC_F_NEXT;
     250           0 :   if (vring->avail_wrap_counter)
     251             :     {
     252           0 :       flags |= VRING_DESC_F_AVAIL;
     253           0 :       flags &= ~VRING_DESC_F_USED;
     254             :     }
     255             :   else
     256             :     {
     257           0 :       flags &= ~VRING_DESC_F_AVAIL;
     258           0 :       flags |= VRING_DESC_F_USED;
     259             :     }
     260           0 :   d->addr = vlib_buffer_get_current_pa (vm, b) +
     261             :     STRUCT_OFFSET_OF (virtio_ctrl_msg_t, data);
     262           0 :   d->len = len;
     263           0 :   d->id = next;
     264           0 :   d->flags = flags;
     265             : 
     266           0 :   next++;
     267           0 :   if (next >= sz)
     268             :     {
     269           0 :       next = 0;
     270           0 :       vring->avail_wrap_counter ^= 1;
     271             :     }
     272           0 :   used++;
     273             : 
     274           0 :   d = &vring->packed_desc[next];
     275           0 :   flags = VRING_DESC_F_WRITE;
     276           0 :   if (vring->avail_wrap_counter)
     277             :     {
     278           0 :       flags |= VRING_DESC_F_AVAIL;
     279           0 :       flags &= ~VRING_DESC_F_USED;
     280             :     }
     281             :   else
     282             :     {
     283           0 :       flags &= ~VRING_DESC_F_AVAIL;
     284           0 :       flags |= VRING_DESC_F_USED;
     285             :     }
     286           0 :   d->addr = vlib_buffer_get_current_pa (vm, b) +
     287             :     STRUCT_OFFSET_OF (virtio_ctrl_msg_t, status);
     288           0 :   d->len = sizeof (data->status);
     289           0 :   d->id = next;
     290           0 :   d->flags = flags;
     291             : 
     292           0 :   next++;
     293           0 :   if (next >= sz)
     294             :     {
     295           0 :       next = 0;
     296           0 :       vring->avail_wrap_counter ^= 1;
     297             :     }
     298           0 :   used++;
     299             : 
     300           0 :   CLIB_MEMORY_STORE_BARRIER ();
     301           0 :   vring->packed_desc[vring->desc_next].flags = first_desc_flags;
     302           0 :   vring->desc_next = next;
     303           0 :   vring->desc_in_use = used;
     304           0 :   CLIB_MEMORY_BARRIER ();
     305           0 :   if (vring->device_event->flags != VRING_EVENT_F_DISABLE)
     306             :     {
     307           0 :       virtio_kick (vm, vring, vif);
     308             :     }
     309             : 
     310           0 :   u16 last = vring->last_used_idx;
     311           0 :   d = &vring->packed_desc[last];
     312             :   do
     313             :     {
     314           0 :       flags = d->flags;
     315             :     }
     316           0 :   while ((flags & VRING_DESC_F_AVAIL) != (vring->used_wrap_counter << 7)
     317           0 :          || (flags & VRING_DESC_F_USED) != (vring->used_wrap_counter << 15));
     318             : 
     319           0 :   last += 3;
     320           0 :   if (last >= vring->queue_size)
     321             :     {
     322           0 :       last = last - vring->queue_size;
     323           0 :       vring->used_wrap_counter ^= 1;
     324             :     }
     325           0 :   vring->desc_in_use -= 3;
     326           0 :   vring->last_used_idx = last;
     327             : 
     328           0 :   CLIB_MEMORY_BARRIER ();
     329           0 :   clib_memcpy (&result, vlib_buffer_get_current (b),
     330             :                sizeof (virtio_ctrl_msg_t));
     331           0 :   virtio_log_debug (vif, "ctrl-queue: status %u", result.status);
     332           0 :   status = result.status;
     333           0 :   vlib_buffer_free (vm, &buffer_index, 1);
     334           0 :   return status;
     335             : }
     336             : 
     337             : static int
     338           0 : virtio_pci_send_ctrl_msg_split (vlib_main_t * vm, virtio_if_t * vif,
     339             :                                 virtio_ctrl_msg_t * data, u32 len)
     340             : {
     341           0 :   vnet_virtio_vring_t *vring = vif->cxq_vring;
     342           0 :   virtio_net_ctrl_ack_t status = VIRTIO_NET_ERR;
     343             :   virtio_ctrl_msg_t result;
     344             :   u32 buffer_index;
     345             :   vlib_buffer_t *b;
     346             :   u16 used, next, avail;
     347           0 :   u16 sz = vring->queue_size;
     348           0 :   u16 mask = sz - 1;
     349             : 
     350           0 :   used = vring->desc_in_use;
     351           0 :   next = vring->desc_next;
     352           0 :   avail = vring->avail->idx;
     353           0 :   vnet_virtio_vring_desc_t *d = &vring->desc[next];
     354             : 
     355           0 :   if (vlib_buffer_alloc (vm, &buffer_index, 1))
     356           0 :     b = vlib_get_buffer (vm, buffer_index);
     357             :   else
     358           0 :     return VIRTIO_NET_ERR;
     359             :   /*
     360             :    * current_data may not be initialized with 0 and may contain
     361             :    * previous offset.
     362             :    */
     363           0 :   b->current_data = 0;
     364           0 :   clib_memcpy (vlib_buffer_get_current (b), data, sizeof (virtio_ctrl_msg_t));
     365           0 :   d->flags = VRING_DESC_F_NEXT;
     366           0 :   d->addr = vlib_buffer_get_current_pa (vm, b);
     367           0 :   d->len = sizeof (virtio_net_ctrl_hdr_t);
     368           0 :   vring->avail->ring[avail & mask] = next;
     369           0 :   avail++;
     370           0 :   next = (next + 1) & mask;
     371           0 :   d->next = next;
     372           0 :   used++;
     373             : 
     374           0 :   d = &vring->desc[next];
     375           0 :   d->flags = VRING_DESC_F_NEXT;
     376           0 :   d->addr = vlib_buffer_get_current_pa (vm, b) +
     377             :     STRUCT_OFFSET_OF (virtio_ctrl_msg_t, data);
     378           0 :   d->len = len;
     379           0 :   next = (next + 1) & mask;
     380           0 :   d->next = next;
     381           0 :   used++;
     382             : 
     383           0 :   d = &vring->desc[next];
     384           0 :   d->flags = VRING_DESC_F_WRITE;
     385           0 :   d->addr = vlib_buffer_get_current_pa (vm, b) +
     386             :     STRUCT_OFFSET_OF (virtio_ctrl_msg_t, status);
     387           0 :   d->len = sizeof (data->status);
     388           0 :   next = (next + 1) & mask;
     389           0 :   used++;
     390             : 
     391           0 :   CLIB_MEMORY_STORE_BARRIER ();
     392           0 :   vring->avail->idx = avail;
     393           0 :   vring->desc_next = next;
     394           0 :   vring->desc_in_use = used;
     395             : 
     396           0 :   if ((vring->used->flags & VIRTIO_RING_FLAG_MASK_INT) == 0)
     397             :     {
     398           0 :       virtio_kick (vm, vring, vif);
     399             :     }
     400             : 
     401           0 :   u16 last = vring->last_used_idx, n_left = 0;
     402           0 :   n_left = vring->used->idx - last;
     403             : 
     404           0 :   while (n_left)
     405             :     {
     406           0 :       vnet_virtio_vring_used_elem_t *e = &vring->used->ring[last & mask];
     407           0 :       u16 slot = e->id;
     408             : 
     409           0 :       d = &vring->desc[slot];
     410           0 :       while (d->flags & VRING_DESC_F_NEXT)
     411             :         {
     412           0 :           used--;
     413           0 :           slot = d->next;
     414           0 :           d = &vring->desc[slot];
     415             :         }
     416           0 :       used--;
     417           0 :       last++;
     418           0 :       n_left--;
     419             :     }
     420           0 :   vring->desc_in_use = used;
     421           0 :   vring->last_used_idx = last;
     422             : 
     423           0 :   CLIB_MEMORY_BARRIER ();
     424           0 :   clib_memcpy (&result, vlib_buffer_get_current (b),
     425             :                sizeof (virtio_ctrl_msg_t));
     426           0 :   virtio_log_debug (vif, "ctrl-queue: status %u", result.status);
     427           0 :   status = result.status;
     428           0 :   vlib_buffer_free (vm, &buffer_index, 1);
     429           0 :   return status;
     430             : }
     431             : 
     432             : static int
     433           0 : virtio_pci_send_ctrl_msg (vlib_main_t * vm, virtio_if_t * vif,
     434             :                           virtio_ctrl_msg_t * data, u32 len)
     435             : {
     436           0 :   if (vif->is_packed)
     437           0 :     return virtio_pci_send_ctrl_msg_packed (vm, vif, data, len);
     438             :   else
     439           0 :     return virtio_pci_send_ctrl_msg_split (vm, vif, data, len);
     440             : }
     441             : 
     442             : static int
     443           0 : virtio_pci_disable_offload (vlib_main_t * vm, virtio_if_t * vif)
     444             : {
     445             :   virtio_ctrl_msg_t offload_hdr;
     446           0 :   virtio_net_ctrl_ack_t status = VIRTIO_NET_ERR;
     447             : 
     448           0 :   offload_hdr.ctrl.class = VIRTIO_NET_CTRL_GUEST_OFFLOADS;
     449           0 :   offload_hdr.ctrl.cmd = VIRTIO_NET_CTRL_GUEST_OFFLOADS_SET;
     450           0 :   offload_hdr.status = VIRTIO_NET_ERR;
     451           0 :   u64 offloads = 0ULL;
     452           0 :   clib_memcpy (offload_hdr.data, &offloads, sizeof (offloads));
     453             : 
     454           0 :   status =
     455           0 :     virtio_pci_send_ctrl_msg (vm, vif, &offload_hdr, sizeof (offloads));
     456           0 :   virtio_log_debug (vif, "disable offloads");
     457           0 :   vif->remote_features = vif->virtio_pci_func->get_device_features (vm, vif);
     458           0 :   vif->virtio_pci_func->get_driver_features (vm, vif);
     459           0 :   return status;
     460             : }
     461             : 
     462             : static int
     463           0 : virtio_pci_enable_checksum_offload (vlib_main_t * vm, virtio_if_t * vif)
     464             : {
     465             :   virtio_ctrl_msg_t csum_offload_hdr;
     466           0 :   virtio_net_ctrl_ack_t status = VIRTIO_NET_ERR;
     467             : 
     468           0 :   csum_offload_hdr.ctrl.class = VIRTIO_NET_CTRL_GUEST_OFFLOADS;
     469           0 :   csum_offload_hdr.ctrl.cmd = VIRTIO_NET_CTRL_GUEST_OFFLOADS_SET;
     470           0 :   csum_offload_hdr.status = VIRTIO_NET_ERR;
     471           0 :   u64 offloads = 0ULL;
     472           0 :   offloads |= VIRTIO_FEATURE (VIRTIO_NET_F_GUEST_CSUM);
     473           0 :   clib_memcpy (csum_offload_hdr.data, &offloads, sizeof (offloads));
     474             : 
     475           0 :   status =
     476           0 :     virtio_pci_send_ctrl_msg (vm, vif, &csum_offload_hdr, sizeof (offloads));
     477           0 :   virtio_log_debug (vif, "enable checksum offload");
     478           0 :   vif->remote_features = vif->virtio_pci_func->get_device_features (vm, vif);
     479           0 :   vif->features = vif->virtio_pci_func->get_driver_features (vm, vif);
     480           0 :   return status;
     481             : }
     482             : 
     483             : static int
     484           0 : virtio_pci_enable_gso (vlib_main_t * vm, virtio_if_t * vif)
     485             : {
     486             :   virtio_ctrl_msg_t gso_hdr;
     487           0 :   virtio_net_ctrl_ack_t status = VIRTIO_NET_ERR;
     488             : 
     489           0 :   gso_hdr.ctrl.class = VIRTIO_NET_CTRL_GUEST_OFFLOADS;
     490           0 :   gso_hdr.ctrl.cmd = VIRTIO_NET_CTRL_GUEST_OFFLOADS_SET;
     491           0 :   gso_hdr.status = VIRTIO_NET_ERR;
     492           0 :   u64 offloads = VIRTIO_FEATURE (VIRTIO_NET_F_GUEST_CSUM)
     493             :     | VIRTIO_FEATURE (VIRTIO_NET_F_GUEST_TSO4)
     494             :     | VIRTIO_FEATURE (VIRTIO_NET_F_GUEST_TSO6);
     495           0 :   clib_memcpy (gso_hdr.data, &offloads, sizeof (offloads));
     496             : 
     497           0 :   status = virtio_pci_send_ctrl_msg (vm, vif, &gso_hdr, sizeof (offloads));
     498           0 :   virtio_log_debug (vif, "enable gso");
     499           0 :   vif->remote_features = vif->virtio_pci_func->get_device_features (vm, vif);
     500           0 :   vif->virtio_pci_func->get_driver_features (vm, vif);
     501           0 :   return status;
     502             : }
     503             : 
     504             : static int
     505           0 : virtio_pci_offloads (vlib_main_t * vm, virtio_if_t * vif, int gso_enabled,
     506             :                      int csum_offload_enabled)
     507             : {
     508           0 :   vnet_main_t *vnm = vnet_get_main ();
     509           0 :   vnet_hw_if_caps_change_t cc = {};
     510             : 
     511           0 :   if ((vif->features & VIRTIO_FEATURE (VIRTIO_NET_F_CTRL_VQ)) &&
     512           0 :       (vif->features & VIRTIO_FEATURE (VIRTIO_NET_F_CTRL_GUEST_OFFLOADS)))
     513             :     {
     514           0 :       if (gso_enabled
     515           0 :           && (vif->features & (VIRTIO_FEATURE (VIRTIO_NET_F_HOST_TSO4) |
     516             :                                VIRTIO_FEATURE (VIRTIO_NET_F_HOST_TSO6))))
     517             :         {
     518           0 :           if (virtio_pci_enable_gso (vm, vif))
     519             :             {
     520           0 :               virtio_log_warning (vif, "gso is not enabled");
     521             :             }
     522             :           else
     523             :             {
     524           0 :               vif->gso_enabled = 1;
     525           0 :               vif->csum_offload_enabled = 1;
     526           0 :               cc.val = cc.mask = VNET_HW_IF_CAP_TCP_GSO |
     527             :                                  VNET_HW_IF_CAP_TX_TCP_CKSUM |
     528             :                                  VNET_HW_IF_CAP_TX_UDP_CKSUM;
     529             :             }
     530             :         }
     531           0 :       else if (csum_offload_enabled
     532           0 :                && (vif->features & VIRTIO_FEATURE (VIRTIO_NET_F_CSUM)))
     533             :         {
     534           0 :           if (virtio_pci_enable_checksum_offload (vm, vif))
     535             :             {
     536           0 :               virtio_log_warning (vif, "checksum offload is not enabled");
     537             :             }
     538             :           else
     539             :             {
     540           0 :               vif->csum_offload_enabled = 1;
     541           0 :               vif->gso_enabled = 0;
     542           0 :               cc.val =
     543             :                 VNET_HW_IF_CAP_TX_TCP_CKSUM | VNET_HW_IF_CAP_TX_UDP_CKSUM;
     544           0 :               cc.mask = VNET_HW_IF_CAP_TCP_GSO | VNET_HW_IF_CAP_TX_TCP_CKSUM |
     545             :                         VNET_HW_IF_CAP_TX_UDP_CKSUM;
     546             :             }
     547             :         }
     548             :       else
     549             :         {
     550           0 :           if (virtio_pci_disable_offload (vm, vif))
     551             :             {
     552           0 :               virtio_log_warning (vif, "offloads are not disabled");
     553             :             }
     554             :           else
     555             :             {
     556           0 :               vif->csum_offload_enabled = 0;
     557           0 :               vif->gso_enabled = 0;
     558           0 :               cc.val = 0;
     559           0 :               cc.mask = VNET_HW_IF_CAP_L4_TX_CKSUM | VNET_HW_IF_CAP_TCP_GSO;
     560             :             }
     561             :         }
     562             :     }
     563             : 
     564           0 :   if (cc.mask)
     565           0 :     vnet_hw_if_change_caps (vnm, vif->hw_if_index, &cc);
     566             : 
     567           0 :   return 0;
     568             : }
     569             : 
     570             : static int
     571           0 : virtio_pci_enable_multiqueue (vlib_main_t * vm, virtio_if_t * vif,
     572             :                               u16 num_queues)
     573             : {
     574             :   virtio_ctrl_msg_t mq_hdr;
     575           0 :   virtio_net_ctrl_ack_t status = VIRTIO_NET_ERR;
     576             : 
     577           0 :   mq_hdr.ctrl.class = VIRTIO_NET_CTRL_MQ;
     578           0 :   mq_hdr.ctrl.cmd = VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET;
     579           0 :   mq_hdr.status = VIRTIO_NET_ERR;
     580           0 :   clib_memcpy (mq_hdr.data, &num_queues, sizeof (num_queues));
     581             : 
     582           0 :   status = virtio_pci_send_ctrl_msg (vm, vif, &mq_hdr, sizeof (num_queues));
     583           0 :   virtio_log_debug (vif, "multi-queue enable %u queues", num_queues);
     584           0 :   return status;
     585             : }
     586             : 
     587             : static u8
     588           0 : virtio_pci_queue_size_valid (u16 qsz)
     589             : {
     590           0 :   if (qsz < 64 || qsz > 4096)
     591           0 :     return 0;
     592           0 :   if ((qsz % 64) != 0)
     593           0 :     return 0;
     594           0 :   return 1;
     595             : }
     596             : 
     597             : clib_error_t *
     598           0 : virtio_pci_control_vring_packed_init (vlib_main_t * vm, virtio_if_t * vif,
     599             :                                       u16 queue_num)
     600             : {
     601           0 :   clib_error_t *error = 0;
     602           0 :   u16 queue_size = 0;
     603             :   vnet_virtio_vring_t *vring;
     604           0 :   u32 i = 0;
     605           0 :   void *ptr = NULL;
     606             : 
     607           0 :   queue_size = vif->virtio_pci_func->get_queue_size (vm, vif, queue_num);
     608             : 
     609           0 :   if (queue_size > 32768)
     610           0 :     return clib_error_return (0, "ring size must be 32768 or lower");
     611             : 
     612           0 :   if (queue_size == 0)
     613           0 :     queue_size = 256;
     614             : 
     615           0 :   vec_validate_aligned (vif->cxq_vring, 0, CLIB_CACHE_LINE_BYTES);
     616           0 :   vring = vec_elt_at_index (vif->cxq_vring, 0);
     617             : 
     618           0 :   i = (((queue_size * sizeof (vnet_virtio_vring_packed_desc_t)) +
     619           0 :         sizeof (vnet_virtio_vring_desc_event_t) + VNET_VIRTIO_PCI_VRING_ALIGN -
     620           0 :         1) &
     621             :        ~(VNET_VIRTIO_PCI_VRING_ALIGN - 1)) +
     622             :       sizeof (vnet_virtio_vring_desc_event_t);
     623             : 
     624           0 :   ptr = vlib_physmem_alloc_aligned_on_numa (vm, i, VNET_VIRTIO_PCI_VRING_ALIGN,
     625             :                                             vif->numa_node);
     626           0 :   if (!ptr)
     627           0 :     return vlib_physmem_last_error (vm);
     628           0 :   clib_memset (ptr, 0, i);
     629             : 
     630           0 :   vring->packed_desc = ptr;
     631             : 
     632           0 :   vring->driver_event =
     633           0 :     ptr + (queue_size * sizeof (vnet_virtio_vring_packed_desc_t));
     634           0 :   vring->driver_event->off_wrap = 0;
     635           0 :   vring->driver_event->flags = VRING_EVENT_F_DISABLE;
     636             : 
     637           0 :   vring->device_event =
     638           0 :     ptr + (((queue_size * sizeof (vnet_virtio_vring_packed_desc_t)) +
     639             :             sizeof (vnet_virtio_vring_desc_event_t) +
     640           0 :             VNET_VIRTIO_PCI_VRING_ALIGN - 1) &
     641             :            ~(VNET_VIRTIO_PCI_VRING_ALIGN - 1));
     642           0 :   vring->device_event->off_wrap = 0;
     643           0 :   vring->device_event->flags = 0;
     644             : 
     645           0 :   vring->total_packets = 0;
     646           0 :   vring->queue_id = queue_num;
     647           0 :   vring->queue_size = queue_size;
     648           0 :   vring->avail_wrap_counter = 1;
     649           0 :   vring->used_wrap_counter = 1;
     650             : 
     651           0 :   ASSERT (vring->buffers == 0);
     652             : 
     653           0 :   virtio_log_debug (vif, "control-queue: number %u, size %u", queue_num,
     654             :                     queue_size);
     655           0 :   vif->virtio_pci_func->setup_queue (vm, vif, queue_num, vring);
     656           0 :   vring->queue_notify_offset =
     657           0 :     vif->notify_off_multiplier *
     658           0 :     vif->virtio_pci_func->get_queue_notify_off (vm, vif, queue_num);
     659           0 :   virtio_log_debug (vif, "queue-notify-offset: number %u, offset %u",
     660             :                     queue_num, vring->queue_notify_offset);
     661           0 :   return error;
     662             : }
     663             : 
     664             : clib_error_t *
     665           0 : virtio_pci_control_vring_split_init (vlib_main_t * vm, virtio_if_t * vif,
     666             :                                      u16 queue_num)
     667             : {
     668           0 :   clib_error_t *error = 0;
     669           0 :   u16 queue_size = 0;
     670             :   vnet_virtio_vring_t *vring;
     671           0 :   u32 i = 0;
     672           0 :   void *ptr = NULL;
     673             : 
     674           0 :   queue_size = vif->virtio_pci_func->get_queue_size (vm, vif, queue_num);
     675           0 :   if (!virtio_pci_queue_size_valid (queue_size))
     676           0 :     clib_warning ("queue size is not valid");
     677             : 
     678           0 :   if (!is_pow2 (queue_size))
     679           0 :     return clib_error_return (0, "ring size must be power of 2");
     680             : 
     681           0 :   if (queue_size > 32768)
     682           0 :     return clib_error_return (0, "ring size must be 32768 or lower");
     683             : 
     684           0 :   if (queue_size == 0)
     685           0 :     queue_size = 256;
     686             : 
     687           0 :   vec_validate_aligned (vif->cxq_vring, 0, CLIB_CACHE_LINE_BYTES);
     688           0 :   vring = vec_elt_at_index (vif->cxq_vring, 0);
     689           0 :   i = vnet_virtio_vring_size (queue_size, VNET_VIRTIO_PCI_VRING_ALIGN);
     690           0 :   i = round_pow2 (i, VNET_VIRTIO_PCI_VRING_ALIGN);
     691           0 :   ptr = vlib_physmem_alloc_aligned_on_numa (vm, i, VNET_VIRTIO_PCI_VRING_ALIGN,
     692             :                                             vif->numa_node);
     693           0 :   if (!ptr)
     694           0 :     return vlib_physmem_last_error (vm);
     695           0 :   clib_memset (ptr, 0, i);
     696           0 :   vnet_virtio_vring_init (vring, queue_size, ptr, VNET_VIRTIO_PCI_VRING_ALIGN);
     697           0 :   vring->queue_id = queue_num;
     698           0 :   vring->total_packets = 0;
     699             : 
     700           0 :   ASSERT (vring->buffers == 0);
     701           0 :   virtio_log_debug (vif, "control-queue: number %u, size %u", queue_num,
     702             :                     queue_size);
     703           0 :   vif->virtio_pci_func->setup_queue (vm, vif, queue_num, vring);
     704           0 :   vring->queue_notify_offset =
     705           0 :     vif->notify_off_multiplier *
     706           0 :     vif->virtio_pci_func->get_queue_notify_off (vm, vif, queue_num);
     707           0 :   virtio_log_debug (vif, "queue-notify-offset: number %u, offset %u",
     708             :                     queue_num, vring->queue_notify_offset);
     709             : 
     710           0 :   return error;
     711             : }
     712             : 
     713             : clib_error_t *
     714           0 : virtio_pci_control_vring_init (vlib_main_t * vm, virtio_if_t * vif,
     715             :                                u16 queue_num)
     716             : {
     717           0 :   if (vif->is_packed)
     718           0 :     return virtio_pci_control_vring_packed_init (vm, vif, queue_num);
     719             :   else
     720           0 :     return virtio_pci_control_vring_split_init (vm, vif, queue_num);
     721             : }
     722             : 
     723             : clib_error_t *
     724           0 : virtio_pci_vring_split_init (vlib_main_t * vm, virtio_if_t * vif,
     725             :                              u16 queue_num)
     726             : {
     727           0 :   clib_error_t *error = 0;
     728           0 :   u16 queue_size = 0;
     729             :   vnet_virtio_vring_t *vring;
     730           0 :   u32 i = 0;
     731           0 :   void *ptr = NULL;
     732             : 
     733           0 :   queue_size = vif->virtio_pci_func->get_queue_size (vm, vif, queue_num);
     734           0 :   if (!virtio_pci_queue_size_valid (queue_size))
     735           0 :     clib_warning ("queue size is not valid");
     736             : 
     737           0 :   if (!is_pow2 (queue_size))
     738           0 :     return clib_error_return (0, "ring size must be power of 2");
     739             : 
     740           0 :   if (queue_size > 32768)
     741           0 :     return clib_error_return (0, "ring size must be 32768 or lower");
     742             : 
     743           0 :   if (queue_size == 0)
     744           0 :     queue_size = 256;
     745             : 
     746           0 :   if (queue_num % 2)
     747             :     {
     748           0 :       vec_validate_aligned (vif->txq_vrings, TX_QUEUE_ACCESS (queue_num),
     749             :                             CLIB_CACHE_LINE_BYTES);
     750           0 :       vring = vec_elt_at_index (vif->txq_vrings, TX_QUEUE_ACCESS (queue_num));
     751           0 :       clib_spinlock_init (&vring->lockp);
     752             :     }
     753             :   else
     754             :     {
     755           0 :       vec_validate_aligned (vif->rxq_vrings, RX_QUEUE_ACCESS (queue_num),
     756             :                             CLIB_CACHE_LINE_BYTES);
     757           0 :       vring = vec_elt_at_index (vif->rxq_vrings, RX_QUEUE_ACCESS (queue_num));
     758             :     }
     759           0 :   i = vnet_virtio_vring_size (queue_size, VNET_VIRTIO_PCI_VRING_ALIGN);
     760           0 :   i = round_pow2 (i, VNET_VIRTIO_PCI_VRING_ALIGN);
     761           0 :   ptr = vlib_physmem_alloc_aligned_on_numa (vm, i, VNET_VIRTIO_PCI_VRING_ALIGN,
     762             :                                             vif->numa_node);
     763           0 :   if (!ptr)
     764           0 :     return vlib_physmem_last_error (vm);
     765           0 :   clib_memset (ptr, 0, i);
     766           0 :   vnet_virtio_vring_init (vring, queue_size, ptr, VNET_VIRTIO_PCI_VRING_ALIGN);
     767           0 :   vring->queue_id = queue_num;
     768           0 :   vring->avail->flags = VIRTIO_RING_FLAG_MASK_INT;
     769           0 :   vring->flow_table = 0;
     770           0 :   vring->total_packets = 0;
     771             : 
     772           0 :   ASSERT (vring->buffers == 0);
     773           0 :   vec_validate_aligned (vring->buffers, queue_size, CLIB_CACHE_LINE_BYTES);
     774           0 :   if (queue_num % 2)
     775             :     {
     776           0 :       virtio_log_debug (vif, "tx-queue: number %u, size %u", queue_num,
     777             :                         queue_size);
     778           0 :       clib_memset_u32 (vring->buffers, ~0, queue_size);
     779             :     }
     780             :   else
     781             :     {
     782           0 :       virtio_log_debug (vif, "rx-queue: number %u, size %u", queue_num,
     783             :                         queue_size);
     784             :     }
     785           0 :   vring->queue_size = queue_size;
     786           0 :   if (vif->virtio_pci_func->setup_queue (vm, vif, queue_num, vring))
     787           0 :     return clib_error_return (0, "error in queue address setup");
     788             : 
     789           0 :   vring->queue_notify_offset =
     790           0 :     vif->notify_off_multiplier *
     791           0 :     vif->virtio_pci_func->get_queue_notify_off (vm, vif, queue_num);
     792           0 :   virtio_log_debug (vif, "queue-notify-offset: number %u, offset %u",
     793             :                     queue_num, vring->queue_notify_offset);
     794           0 :   return error;
     795             : }
     796             : 
     797             : clib_error_t *
     798           0 : virtio_pci_vring_packed_init (vlib_main_t * vm, virtio_if_t * vif,
     799             :                               u16 queue_num)
     800             : {
     801           0 :   clib_error_t *error = 0;
     802           0 :   u16 queue_size = 0;
     803             :   vnet_virtio_vring_t *vring;
     804           0 :   u32 i = 0;
     805           0 :   void *ptr = NULL;
     806             : 
     807           0 :   queue_size = vif->virtio_pci_func->get_queue_size (vm, vif, queue_num);
     808             : 
     809           0 :   if (queue_size > 32768)
     810           0 :     return clib_error_return (0, "ring size must be 32768 or lower");
     811             : 
     812           0 :   if (queue_size == 0)
     813           0 :     queue_size = 256;
     814             : 
     815           0 :   if (queue_num % 2)
     816             :     {
     817           0 :       vec_validate_aligned (vif->txq_vrings, TX_QUEUE_ACCESS (queue_num),
     818             :                             CLIB_CACHE_LINE_BYTES);
     819           0 :       vring = vec_elt_at_index (vif->txq_vrings, TX_QUEUE_ACCESS (queue_num));
     820           0 :       clib_spinlock_init (&vring->lockp);
     821             :     }
     822             :   else
     823             :     {
     824           0 :       vec_validate_aligned (vif->rxq_vrings, RX_QUEUE_ACCESS (queue_num),
     825             :                             CLIB_CACHE_LINE_BYTES);
     826           0 :       vring = vec_elt_at_index (vif->rxq_vrings, RX_QUEUE_ACCESS (queue_num));
     827             :     }
     828             : 
     829           0 :   i = (((queue_size * sizeof (vnet_virtio_vring_packed_desc_t)) +
     830           0 :         sizeof (vnet_virtio_vring_desc_event_t) + VNET_VIRTIO_PCI_VRING_ALIGN -
     831           0 :         1) &
     832             :        ~(VNET_VIRTIO_PCI_VRING_ALIGN - 1)) +
     833             :       sizeof (vnet_virtio_vring_desc_event_t);
     834             : 
     835           0 :   ptr = vlib_physmem_alloc_aligned_on_numa (vm, i, VNET_VIRTIO_PCI_VRING_ALIGN,
     836             :                                             vif->numa_node);
     837           0 :   if (!ptr)
     838           0 :     return vlib_physmem_last_error (vm);
     839             : 
     840           0 :   clib_memset (ptr, 0, i);
     841           0 :   vring->packed_desc = ptr;
     842             : 
     843           0 :   vring->driver_event =
     844           0 :     ptr + (queue_size * sizeof (vnet_virtio_vring_packed_desc_t));
     845           0 :   vring->driver_event->off_wrap = 0;
     846           0 :   vring->driver_event->flags = VRING_EVENT_F_DISABLE;
     847             : 
     848           0 :   vring->device_event =
     849           0 :     ptr + (((queue_size * sizeof (vnet_virtio_vring_packed_desc_t)) +
     850             :             sizeof (vnet_virtio_vring_desc_event_t) +
     851           0 :             VNET_VIRTIO_PCI_VRING_ALIGN - 1) &
     852             :            ~(VNET_VIRTIO_PCI_VRING_ALIGN - 1));
     853           0 :   vring->device_event->off_wrap = 0;
     854           0 :   vring->device_event->flags = 0;
     855             : 
     856           0 :   vring->queue_id = queue_num;
     857             : 
     858           0 :   vring->avail_wrap_counter = 1;
     859           0 :   vring->used_wrap_counter = 1;
     860           0 :   vring->total_packets = 0;
     861             : 
     862           0 :   ASSERT (vring->buffers == 0);
     863           0 :   vec_validate_aligned (vring->buffers, queue_size, CLIB_CACHE_LINE_BYTES);
     864           0 :   if (queue_num % 2)
     865             :     {
     866           0 :       virtio_log_debug (vif, "tx-queue: number %u, size %u", queue_num,
     867             :                         queue_size);
     868           0 :       clib_memset_u32 (vring->buffers, ~0, queue_size);
     869             :     }
     870             :   else
     871             :     {
     872           0 :       virtio_log_debug (vif, "rx-queue: number %u, size %u", queue_num,
     873             :                         queue_size);
     874             :     }
     875           0 :   vring->queue_size = queue_size;
     876           0 :   if (vif->virtio_pci_func->setup_queue (vm, vif, queue_num, vring))
     877           0 :     return clib_error_return (0, "error in queue address setup");
     878             : 
     879           0 :   vring->queue_notify_offset =
     880           0 :     vif->notify_off_multiplier *
     881           0 :     vif->virtio_pci_func->get_queue_notify_off (vm, vif, queue_num);
     882           0 :   virtio_log_debug (vif, "queue-notify-offset: number %u, offset %u",
     883             :                     queue_num, vring->queue_notify_offset);
     884             : 
     885           0 :   return error;
     886             : }
     887             : 
     888             : clib_error_t *
     889           0 : virtio_pci_vring_init (vlib_main_t * vm, virtio_if_t * vif, u16 queue_num)
     890             : {
     891           0 :   if (vif->is_packed)
     892           0 :     return virtio_pci_vring_packed_init (vm, vif, queue_num);
     893             :   else
     894           0 :     return virtio_pci_vring_split_init (vm, vif, queue_num);
     895             : }
     896             : 
     897             : static void
     898           0 : virtio_negotiate_features (vlib_main_t * vm, virtio_if_t * vif,
     899             :                            u64 req_features)
     900             : {
     901             :   /*
     902             :    * if features are not requested
     903             :    * default: all supported features
     904             :    */
     905           0 :   u64 supported_features = VIRTIO_FEATURE (VIRTIO_NET_F_CSUM)
     906             :     | VIRTIO_FEATURE (VIRTIO_NET_F_GUEST_CSUM)
     907             :     | VIRTIO_FEATURE (VIRTIO_NET_F_CTRL_GUEST_OFFLOADS)
     908             :     | VIRTIO_FEATURE (VIRTIO_NET_F_MTU)
     909             :     | VIRTIO_FEATURE (VIRTIO_NET_F_MAC)
     910             :     | VIRTIO_FEATURE (VIRTIO_NET_F_GSO)
     911             :     | VIRTIO_FEATURE (VIRTIO_NET_F_GUEST_TSO4)
     912             :     | VIRTIO_FEATURE (VIRTIO_NET_F_GUEST_TSO6)
     913             :     | VIRTIO_FEATURE (VIRTIO_NET_F_GUEST_UFO)
     914             :     | VIRTIO_FEATURE (VIRTIO_NET_F_HOST_TSO4)
     915             :     | VIRTIO_FEATURE (VIRTIO_NET_F_HOST_TSO6)
     916             :     | VIRTIO_FEATURE (VIRTIO_NET_F_HOST_UFO)
     917             :     | VIRTIO_FEATURE (VIRTIO_NET_F_MRG_RXBUF)
     918             :     | VIRTIO_FEATURE (VIRTIO_NET_F_STATUS)
     919             :     | VIRTIO_FEATURE (VIRTIO_NET_F_CTRL_VQ)
     920             :     | VIRTIO_FEATURE (VIRTIO_NET_F_MQ)
     921             :     | VIRTIO_FEATURE (VIRTIO_F_NOTIFY_ON_EMPTY)
     922             :     | VIRTIO_FEATURE (VIRTIO_F_ANY_LAYOUT)
     923             :     | VIRTIO_FEATURE (VIRTIO_RING_F_INDIRECT_DESC);
     924             : 
     925           0 :   if (vif->is_modern)
     926           0 :     supported_features |= VIRTIO_FEATURE (VIRTIO_F_VERSION_1);
     927             : 
     928           0 :   if (vif->is_packed)
     929             :     {
     930           0 :       supported_features |=
     931             :         (VIRTIO_FEATURE (VIRTIO_F_RING_PACKED) |
     932             :          VIRTIO_FEATURE (VIRTIO_F_IN_ORDER));
     933             :     }
     934             : 
     935           0 :   if (req_features == 0)
     936             :     {
     937           0 :       req_features = supported_features;
     938             :     }
     939             : 
     940           0 :   vif->features = req_features & vif->remote_features & supported_features;
     941             : 
     942           0 :   if (vif->features & VIRTIO_FEATURE (VIRTIO_NET_F_MTU))
     943             :     {
     944           0 :       u16 mtu = 0;
     945           0 :       mtu = vif->virtio_pci_func->get_mtu (vm, vif);
     946             : 
     947           0 :       if (mtu < 64)
     948           0 :         vif->features &= ~VIRTIO_FEATURE (VIRTIO_NET_F_MTU);
     949             :     }
     950             : 
     951           0 :   if ((vif->features & (VIRTIO_FEATURE (VIRTIO_F_RING_PACKED))) == 0)
     952           0 :     vif->is_packed = 0;
     953             : 
     954           0 :   vif->virtio_pci_func->set_driver_features (vm, vif, vif->features);
     955           0 :   vif->features = vif->virtio_pci_func->get_driver_features (vm, vif);
     956           0 : }
     957             : 
     958             : void
     959           0 : virtio_pci_read_device_feature (vlib_main_t * vm, virtio_if_t * vif)
     960             : {
     961           0 :   vif->remote_features = vif->virtio_pci_func->get_device_features (vm, vif);
     962           0 : }
     963             : 
     964             : int
     965           0 : virtio_pci_reset_device (vlib_main_t * vm, virtio_if_t * vif)
     966             : {
     967           0 :   u8 status = 0;
     968             : 
     969             :   /*
     970             :    * Reset the device
     971             :    */
     972           0 :   status = vif->virtio_pci_func->device_reset (vm, vif);
     973             : 
     974             :   /*
     975             :    * Set the Acknowledge status bit
     976             :    */
     977           0 :   vif->virtio_pci_func->set_status (vm, vif, VIRTIO_CONFIG_STATUS_ACK);
     978             : 
     979             :   /*
     980             :    * Set the Driver status bit
     981             :    */
     982           0 :   vif->virtio_pci_func->set_status (vm, vif, VIRTIO_CONFIG_STATUS_DRIVER);
     983             : 
     984             :   /*
     985             :    * Read the status and verify it
     986             :    */
     987           0 :   status = vif->virtio_pci_func->get_status (vm, vif);
     988           0 :   if ((status & VIRTIO_CONFIG_STATUS_ACK)
     989           0 :       && (status & VIRTIO_CONFIG_STATUS_DRIVER))
     990           0 :     vif->status = status;
     991             :   else
     992           0 :     return -1;
     993             : 
     994           0 :   return 0;
     995             : }
     996             : 
     997             : clib_error_t *
     998           0 : virtio_pci_read_caps (vlib_main_t * vm, virtio_if_t * vif, void **bar)
     999             : {
    1000           0 :   clib_error_t *error = 0;
    1001             :   virtio_pci_cap_t cap;
    1002           0 :   u8 pos, common_cfg = 0, notify = 0, dev_cfg = 0, isr = 0, pci_cfg = 0;
    1003           0 :   vlib_pci_dev_handle_t h = vif->pci_dev_handle;
    1004             : 
    1005           0 :   if ((error = vlib_pci_read_config_u8 (vm, h, PCI_CAPABILITY_LIST, &pos)))
    1006             :     {
    1007           0 :       virtio_log_error (vif, "error in reading capabilty list position");
    1008           0 :       return clib_error_return (error,
    1009             :                                 "error in reading capabilty list position");
    1010             :     }
    1011           0 :   while (pos)
    1012             :     {
    1013           0 :       if ((error =
    1014           0 :            vlib_pci_read_write_config (vm, h, VLIB_READ, pos, &cap,
    1015             :                                        sizeof (cap))))
    1016             :         {
    1017           0 :           virtio_log_error (vif, "%s [%2x]",
    1018             :                             "error in reading the capability at", pos);
    1019           0 :           return clib_error_return (error,
    1020             :                                     "error in reading the capability at [%2x]",
    1021             :                                     pos);
    1022             :         }
    1023             : 
    1024           0 :       if (cap.cap_vndr == PCI_CAP_ID_MSIX)
    1025             :         {
    1026           0 :           u16 flags, table_size, table_size_mask = 0x07FF;
    1027             : 
    1028           0 :           if ((error =
    1029           0 :                vlib_pci_read_write_config (vm, h, VLIB_READ, pos + 2, &flags,
    1030             :                                            sizeof (flags))))
    1031           0 :             return clib_error_return (error,
    1032             :                                       "error in reading the capability at [%2x]",
    1033             :                                       pos + 2);
    1034             : 
    1035           0 :           table_size = flags & table_size_mask;
    1036           0 :           virtio_log_debug (vif, "flags:0x%x %s 0x%x", flags,
    1037             :                             "msix interrupt vector table-size", table_size);
    1038             : 
    1039           0 :           if (flags & PCI_MSIX_ENABLE)
    1040             :             {
    1041           0 :               virtio_log_debug (vif, "msix interrupt enabled");
    1042           0 :               vif->msix_enabled = VIRTIO_MSIX_ENABLED;
    1043           0 :               vif->msix_table_size = table_size;
    1044             :             }
    1045             :           else
    1046             :             {
    1047           0 :               virtio_log_debug (vif, "msix interrupt disabled");
    1048           0 :               vif->msix_enabled = VIRTIO_MSIX_DISABLED;
    1049           0 :               vif->msix_table_size = 0;
    1050             :             }
    1051             :         }
    1052             : 
    1053           0 :       if (cap.cap_vndr != PCI_CAP_ID_VNDR)
    1054             :         {
    1055           0 :           virtio_log_debug (vif, "[%2x] %s %2x ", pos,
    1056             :                             "skipping non VNDR cap id:", cap.cap_vndr);
    1057           0 :           goto next;
    1058             :         }
    1059             : 
    1060           0 :       virtio_log_debug (vif,
    1061             :                         "[%4x] cfg type: %u, bar: %u, offset: %04x, len: %u",
    1062             :                         pos, cap.cfg_type, cap.bar, cap.offset, cap.length);
    1063             : 
    1064           0 :       if (cap.bar >= 0 && cap.bar <= 5)
    1065             :         {
    1066           0 :           vif->bar = bar[cap.bar];
    1067           0 :           vif->bar_id = cap.bar;
    1068             :         }
    1069             :       else
    1070           0 :         return clib_error_return (error, "invalid bar %u", cap.bar);
    1071             : 
    1072           0 :       switch (cap.cfg_type)
    1073             :         {
    1074           0 :         case VIRTIO_PCI_CAP_COMMON_CFG:
    1075           0 :           vif->common_offset = cap.offset;
    1076           0 :           common_cfg = 1;
    1077           0 :           break;
    1078           0 :         case VIRTIO_PCI_CAP_NOTIFY_CFG:
    1079           0 :           if ((error =
    1080           0 :                vlib_pci_read_write_config (vm, h, VLIB_READ,
    1081             :                                            pos + sizeof (cap),
    1082           0 :                                            &vif->notify_off_multiplier,
    1083             :                                            sizeof
    1084             :                                            (vif->notify_off_multiplier))))
    1085             :             {
    1086           0 :               virtio_log_error (vif, "notify off multiplier is not given");
    1087             :             }
    1088             :           else
    1089             :             {
    1090           0 :               virtio_log_debug (vif, "notify off multiplier is %u",
    1091             :                                 vif->notify_off_multiplier);
    1092           0 :               vif->notify_offset = cap.offset;
    1093           0 :               notify = 1;
    1094             :             }
    1095           0 :           break;
    1096           0 :         case VIRTIO_PCI_CAP_DEVICE_CFG:
    1097           0 :           vif->device_offset = cap.offset;
    1098           0 :           dev_cfg = 1;
    1099           0 :           break;
    1100           0 :         case VIRTIO_PCI_CAP_ISR_CFG:
    1101           0 :           vif->isr_offset = cap.offset;
    1102           0 :           isr = 1;
    1103           0 :           break;
    1104           0 :         case VIRTIO_PCI_CAP_PCI_CFG:
    1105           0 :           if (cap.bar == 0)
    1106           0 :             pci_cfg = 1;
    1107           0 :           break;
    1108             :         }
    1109           0 :     next:
    1110           0 :       pos = cap.cap_next;
    1111             :     }
    1112             : 
    1113           0 :   if (common_cfg == 0 || notify == 0 || dev_cfg == 0 || isr == 0)
    1114             :     {
    1115           0 :       vif->virtio_pci_func = &virtio_pci_legacy_func;
    1116           0 :       vif->notify_off_multiplier = 0;
    1117           0 :       virtio_log_debug (vif, "legacy virtio pci device found");
    1118           0 :       return error;
    1119             :     }
    1120             : 
    1121           0 :   vif->is_modern = 1;
    1122           0 :   vif->virtio_pci_func = &virtio_pci_modern_func;
    1123             : 
    1124           0 :   if (!pci_cfg)
    1125             :     {
    1126           0 :       virtio_log_debug (vif, "modern virtio pci device found");
    1127             :     }
    1128             :   else
    1129             :     {
    1130           0 :       virtio_log_debug (vif, "transitional virtio pci device found");
    1131             :     }
    1132             : 
    1133           0 :   return error;
    1134             : }
    1135             : 
    1136             : static clib_error_t *
    1137           0 : virtio_pci_device_init (vlib_main_t * vm, virtio_if_t * vif,
    1138             :                         virtio_pci_create_if_args_t * args, void **bar)
    1139             : {
    1140           0 :   clib_error_t *error = 0;
    1141           0 :   u8 status = 0;
    1142             : 
    1143           0 :   if ((error = virtio_pci_read_caps (vm, vif, bar)))
    1144             :     {
    1145           0 :       args->rv = VNET_API_ERROR_UNSUPPORTED;
    1146           0 :       virtio_log_error (vif, "Device is not supported");
    1147           0 :       return clib_error_return (error, "Device is not supported");
    1148             :     }
    1149             : 
    1150           0 :   if (virtio_pci_reset_device (vm, vif) < 0)
    1151             :     {
    1152           0 :       args->rv = VNET_API_ERROR_INIT_FAILED;
    1153           0 :       virtio_log_error (vif, "Failed to reset the device");
    1154           0 :       return clib_error_return (error, "Failed to reset the device");
    1155             :     }
    1156             :   /*
    1157             :    * read device features and negotiate (user) requested features
    1158             :    */
    1159           0 :   virtio_pci_read_device_feature (vm, vif);
    1160           0 :   if ((vif->remote_features & VIRTIO_FEATURE (VIRTIO_RING_F_INDIRECT_DESC)) ==
    1161             :       0)
    1162             :     {
    1163           0 :       virtio_log_warning (vif, "error encountered: vhost-net backend doesn't "
    1164             :                           "support VIRTIO_RING_F_INDIRECT_DESC features");
    1165             :     }
    1166           0 :   if ((vif->remote_features & VIRTIO_FEATURE (VIRTIO_NET_F_MRG_RXBUF)) == 0)
    1167             :     {
    1168           0 :       virtio_log_warning (vif, "error encountered: vhost-net backend doesn't "
    1169             :                           "support VIRTIO_NET_F_MRG_RXBUF features");
    1170             :     }
    1171           0 :   virtio_negotiate_features (vm, vif, args->features);
    1172             : 
    1173             :   /*
    1174             :    * After FEATURE_OK, driver should not accept new feature bits
    1175             :    */
    1176           0 :   vif->virtio_pci_func->set_status (vm, vif,
    1177             :                                     VIRTIO_CONFIG_STATUS_FEATURES_OK);
    1178           0 :   status = vif->virtio_pci_func->get_status (vm, vif);
    1179           0 :   if (!(status & VIRTIO_CONFIG_STATUS_FEATURES_OK))
    1180             :     {
    1181           0 :       args->rv = VNET_API_ERROR_UNSUPPORTED;
    1182           0 :       virtio_log_error (vif,
    1183             :                         "error encountered: Device doesn't support requested features");
    1184           0 :       return clib_error_return (error,
    1185             :                                 "Device doesn't support requested features");
    1186             :     }
    1187           0 :   vif->status = status;
    1188             : 
    1189             :   /*
    1190             :    * get or set the mac address
    1191             :    */
    1192           0 :   if (virtio_pci_get_mac (vm, vif))
    1193             :     {
    1194           0 :       f64 now = vlib_time_now (vm);
    1195             :       u32 rnd;
    1196           0 :       rnd = (u32) (now * 1e6);
    1197           0 :       rnd = random_u32 (&rnd);
    1198             : 
    1199           0 :       memcpy (vif->mac_addr + 2, &rnd, sizeof (rnd));
    1200           0 :       vif->mac_addr[0] = 2;
    1201           0 :       vif->mac_addr[1] = 0xfe;
    1202           0 :       virtio_pci_set_mac (vm, vif);
    1203             :     }
    1204             : 
    1205           0 :   virtio_set_net_hdr_size (vif);
    1206             : 
    1207             :   /*
    1208             :    * Initialize the virtqueues
    1209             :    */
    1210           0 :   if ((error = virtio_pci_get_max_virtqueue_pairs (vm, vif)))
    1211             :     {
    1212           0 :       args->rv = VNET_API_ERROR_EXCEEDED_NUMBER_OF_RANGES_CAPACITY;
    1213           0 :       goto err;
    1214             :     }
    1215             : 
    1216           0 :   if (vif->msix_enabled == VIRTIO_MSIX_ENABLED)
    1217             :     {
    1218           0 :       if (vif->msix_table_size <= vif->max_queue_pairs)
    1219             :         {
    1220           0 :           virtio_log_error (vif,
    1221             :                             "error MSIX lines (%u) <= Number of RXQs (%u)",
    1222             :                             vif->msix_table_size, vif->max_queue_pairs);
    1223           0 :           return clib_error_return (error,
    1224             :                                     "error MSIX lines (%u) <= Number of RXQs (%u)",
    1225             :                                     vif->msix_table_size,
    1226             :                                     vif->max_queue_pairs);
    1227             :         }
    1228             :     }
    1229             : 
    1230           0 :   for (int i = 0; i < vif->max_queue_pairs; i++)
    1231             :     {
    1232           0 :       if ((error = virtio_pci_vring_init (vm, vif, RX_QUEUE (i))))
    1233             :         {
    1234           0 :           args->rv = VNET_API_ERROR_INIT_FAILED;
    1235           0 :           virtio_log_error (vif, "%s (%u) %s", "error in rxq-queue",
    1236             :                             RX_QUEUE (i), "initialization");
    1237             :           error =
    1238           0 :             clib_error_return (error, "%s (%u) %s", "error in rxq-queue",
    1239             :                                RX_QUEUE (i), "initialization");
    1240           0 :           goto err;
    1241             :         }
    1242             :       else
    1243             :         {
    1244           0 :           vif->num_rxqs++;
    1245             :         }
    1246             : 
    1247           0 :       if ((error = virtio_pci_vring_init (vm, vif, TX_QUEUE (i))))
    1248             :         {
    1249           0 :           args->rv = VNET_API_ERROR_INIT_FAILED;
    1250           0 :           virtio_log_error (vif, "%s (%u) %s", "error in txq-queue",
    1251             :                             TX_QUEUE (i), "initialization");
    1252             :           error =
    1253           0 :             clib_error_return (error, "%s (%u) %s", "error in txq-queue",
    1254             :                                TX_QUEUE (i), "initialization");
    1255           0 :           goto err;
    1256             :         }
    1257             :       else
    1258             :         {
    1259           0 :           vif->num_txqs++;
    1260             :         }
    1261             :     }
    1262             : 
    1263           0 :   if (vif->features & VIRTIO_FEATURE (VIRTIO_NET_F_CTRL_VQ))
    1264             :     {
    1265           0 :       if ((error =
    1266           0 :            virtio_pci_control_vring_init (vm, vif, vif->max_queue_pairs * 2)))
    1267             :         {
    1268           0 :           virtio_log_warning (vif, "%s (%u) %s", "error in control-queue",
    1269             :                               vif->max_queue_pairs * 2, "initialization");
    1270           0 :           if (vif->features & VIRTIO_FEATURE (VIRTIO_NET_F_MQ))
    1271           0 :             vif->features &= ~VIRTIO_FEATURE (VIRTIO_NET_F_MQ);
    1272             :         }
    1273             :     }
    1274             :   else
    1275             :     {
    1276           0 :       virtio_log_debug (vif, "control queue is not available");
    1277           0 :       vif->cxq_vring = NULL;
    1278             :     }
    1279             : 
    1280             :   /*
    1281             :    * set the msix interrupts
    1282             :    */
    1283           0 :   if (vif->msix_enabled == VIRTIO_MSIX_ENABLED)
    1284             :     {
    1285             :       int i, j;
    1286           0 :       if (vif->virtio_pci_func->set_config_irq (vm, vif, 0) ==
    1287             :           VIRTIO_MSI_NO_VECTOR)
    1288             :         {
    1289           0 :           virtio_log_warning (vif, "config vector 0 is not set");
    1290             :         }
    1291             :       else
    1292             :         {
    1293           0 :           virtio_log_debug (vif, "config msix vector is set at 0");
    1294             :         }
    1295           0 :       for (i = 0, j = 1; i < vif->max_queue_pairs; i++, j++)
    1296             :         {
    1297           0 :           if (vif->virtio_pci_func->set_queue_irq (vm, vif, j,
    1298             :                                                    RX_QUEUE (i)) ==
    1299             :               VIRTIO_MSI_NO_VECTOR)
    1300             :             {
    1301           0 :               virtio_log_warning (vif, "queue (%u) vector is not set at %u",
    1302             :                                   RX_QUEUE (i), j);
    1303             :             }
    1304             :           else
    1305             :             {
    1306           0 :               virtio_log_debug (vif, "%s (%u) %s %u", "queue",
    1307             :                                 RX_QUEUE (i), "msix vector is set at", j);
    1308             :             }
    1309             :         }
    1310             :     }
    1311             : 
    1312             :   /*
    1313             :    * set the driver status OK
    1314             :    */
    1315           0 :   vif->virtio_pci_func->set_status (vm, vif, VIRTIO_CONFIG_STATUS_DRIVER_OK);
    1316           0 :   vif->status = vif->virtio_pci_func->get_status (vm, vif);
    1317           0 : err:
    1318           0 :   return error;
    1319             : }
    1320             : 
    1321             : void
    1322           0 : virtio_pci_create_if (vlib_main_t * vm, virtio_pci_create_if_args_t * args)
    1323             : {
    1324           0 :   vnet_main_t *vnm = vnet_get_main ();
    1325           0 :   virtio_main_t *vim = &virtio_main;
    1326             :   virtio_if_t *vif;
    1327             :   vlib_pci_dev_handle_t h;
    1328           0 :   clib_error_t *error = 0;
    1329           0 :   u32 interrupt_count = 0;
    1330             : 
    1331             :   /* *INDENT-OFF* */
    1332           0 :   pool_foreach (vif, vim->interfaces)  {
    1333           0 :     if (vif->pci_addr.as_u32 == args->addr)
    1334             :       {
    1335           0 :         args->rv = VNET_API_ERROR_ADDRESS_IN_USE;
    1336           0 :         args->error =
    1337           0 :           clib_error_return (error, "PCI address in use");
    1338           0 :           vlib_log (VLIB_LOG_LEVEL_ERR, vim->log_default, "%U: %s",
    1339             :                 format_vlib_pci_addr, &args->addr,
    1340             :                 " PCI address in use");
    1341           0 :         return;
    1342             :       }
    1343             :   }
    1344             :   /* *INDENT-ON* */
    1345             : 
    1346           0 :   if (args->bind)
    1347             :     {
    1348           0 :       vlib_pci_addr_t pci = { .as_u32 = args->addr };
    1349           0 :       error = vlib_pci_bind_to_uio (vm, &pci, (char *) "auto",
    1350           0 :                                     VIRTIO_BIND_FORCE == args->bind);
    1351           0 :       if (error)
    1352             :         {
    1353           0 :           args->rv = VNET_API_ERROR_INVALID_INTERFACE;
    1354           0 :           args->error =
    1355           0 :             clib_error_return (error, "%U: %s", format_vlib_pci_addr, &pci,
    1356             :                                "error encountered on binding pci device");
    1357           0 :           vlib_log (VLIB_LOG_LEVEL_ERR, vim->log_default, "%U: %s",
    1358             :                     format_vlib_pci_addr, &pci,
    1359             :                     "error encountered on binding pci devicee");
    1360           0 :           return;
    1361             :         }
    1362             :     }
    1363             : 
    1364           0 :   pool_get (vim->interfaces, vif);
    1365           0 :   vif->dev_instance = vif - vim->interfaces;
    1366           0 :   vif->per_interface_next_index = ~0;
    1367           0 :   vif->pci_addr.as_u32 = args->addr;
    1368           0 :   if (args->virtio_flags & VIRTIO_FLAG_PACKED)
    1369           0 :     vif->is_packed = 1;
    1370             : 
    1371           0 :   if ((error =
    1372           0 :        vlib_pci_device_open (vm, (vlib_pci_addr_t *) & vif->pci_addr,
    1373             :                              virtio_pci_device_ids, &h)))
    1374             :     {
    1375           0 :       args->rv = VNET_API_ERROR_INVALID_INTERFACE;
    1376           0 :       args->error =
    1377           0 :         clib_error_return (error, "pci-addr %U", format_vlib_pci_addr,
    1378             :                            &vif->pci_addr);
    1379           0 :       vlib_log (VLIB_LOG_LEVEL_ERR, vim->log_default, "%U: %s",
    1380           0 :                 format_vlib_pci_addr, &vif->pci_addr,
    1381             :                 "error encountered on pci device open");
    1382           0 :       pool_put (vim->interfaces, vif);
    1383           0 :       return;
    1384             :     }
    1385           0 :   vif->pci_dev_handle = h;
    1386           0 :   vlib_pci_set_private_data (vm, h, vif->dev_instance);
    1387           0 :   vif->numa_node = vlib_pci_get_numa_node (vm, h);
    1388           0 :   vif->type = VIRTIO_IF_TYPE_PCI;
    1389             : 
    1390           0 :   if ((error = vlib_pci_bus_master_enable (vm, h)))
    1391             :     {
    1392           0 :       virtio_log_error (vif, "error encountered on pci bus master enable");
    1393           0 :       goto error;
    1394             :     }
    1395             : 
    1396             :   void *bar[6];
    1397           0 :   for (u32 i = 0; i <= 5; i++)
    1398             :     {
    1399             : 
    1400           0 :       if ((error = vlib_pci_map_region (vm, h, i, &bar[i])))
    1401             :         {
    1402           0 :           virtio_log_debug (vif, "no pci map region for bar %u", i);
    1403             :         }
    1404             :       else
    1405             :         {
    1406           0 :           virtio_log_debug (vif, "pci map region for bar %u at %p", i,
    1407             :                             bar[i]);
    1408             :         }
    1409             :     }
    1410             : 
    1411           0 :   if ((error = vlib_pci_io_region (vm, h, 0)))
    1412             :     {
    1413           0 :       virtio_log_error (vif, "error encountered on pci io region");
    1414           0 :       goto error;
    1415             :     }
    1416             : 
    1417           0 :   interrupt_count = vlib_pci_get_num_msix_interrupts (vm, h);
    1418           0 :   if (interrupt_count > 1)
    1419             :     {
    1420           0 :       if ((error = vlib_pci_register_msix_handler (vm, h, 0, 1,
    1421             :                                                    &virtio_pci_irq_config_handler)))
    1422             :         {
    1423           0 :           args->rv = VNET_API_ERROR_INVALID_REGISTRATION;
    1424           0 :           virtio_log_error (vif,
    1425             :                             "error encountered on pci register msix handler 0");
    1426           0 :           goto error;
    1427             :         }
    1428             : 
    1429           0 :       if ((error =
    1430           0 :            vlib_pci_register_msix_handler (vm, h, 1, (interrupt_count - 1),
    1431             :                                            &virtio_pci_irq_queue_handler)))
    1432             :         {
    1433           0 :           args->rv = VNET_API_ERROR_INVALID_REGISTRATION;
    1434           0 :           virtio_log_error (vif,
    1435             :                             "error encountered on pci register msix handler 1");
    1436           0 :           goto error;
    1437             :         }
    1438             : 
    1439           0 :       if ((error = vlib_pci_enable_msix_irq (vm, h, 0, interrupt_count)))
    1440             :         {
    1441           0 :           virtio_log_error (vif, "error encountered on pci enable msix irq");
    1442           0 :           goto error;
    1443             :         }
    1444           0 :       vif->support_int_mode = 1;
    1445           0 :       virtio_log_debug (vif, "device supports msix interrupts");
    1446             :     }
    1447             :   else
    1448             :     {
    1449             :       /*
    1450             :        * WARN: performance will be sub-optimal.
    1451             :        * Fall back to intX, if msix table-size is 1 or
    1452             :        * if UIO driver is being used.
    1453             :        */
    1454           0 :       if ((error =
    1455           0 :            vlib_pci_register_intx_handler (vm, h, &virtio_pci_irq_handler)))
    1456             :         {
    1457           0 :           virtio_log_error (vif,
    1458             :                             "error encountered on pci register interrupt handler");
    1459           0 :           goto error;
    1460             :         }
    1461           0 :       vif->support_int_mode = 1;
    1462           0 :       virtio_log_debug (vif, "pci register interrupt handler");
    1463             :     }
    1464             : 
    1465           0 :   if ((error = vlib_pci_intr_enable (vm, h)))
    1466             :     {
    1467           0 :       virtio_log_error (vif, "error encountered on pci interrupt enable");
    1468           0 :       goto error;
    1469             :     }
    1470             : 
    1471           0 :   if ((error = virtio_pci_device_init (vm, vif, args, bar)))
    1472             :     {
    1473           0 :       virtio_log_error (vif, "error encountered on device init");
    1474           0 :       goto error;
    1475             :     }
    1476             : 
    1477             :   /* create interface */
    1478           0 :   vnet_eth_interface_registration_t eir = {};
    1479           0 :   eir.dev_class_index = virtio_device_class.index;
    1480           0 :   eir.dev_instance = vif->dev_instance;
    1481           0 :   eir.address = vif->mac_addr;
    1482           0 :   eir.cb.flag_change = virtio_pci_flag_change;
    1483           0 :   vif->hw_if_index = vnet_eth_register_interface (vnm, &eir);
    1484             : 
    1485           0 :   vnet_sw_interface_t *sw = vnet_get_hw_sw_interface (vnm, vif->hw_if_index);
    1486           0 :   vif->sw_if_index = sw->sw_if_index;
    1487           0 :   args->sw_if_index = sw->sw_if_index;
    1488             : 
    1489           0 :   vnet_hw_if_set_caps (vnm, vif->hw_if_index, VNET_HW_IF_CAP_INT_MODE);
    1490             : 
    1491           0 :   if (args->virtio_flags & VIRTIO_FLAG_BUFFERING)
    1492             :     {
    1493           0 :       error = virtio_set_packet_buffering (vif, args->buffering_size);
    1494           0 :       if (error)
    1495             :         {
    1496           0 :           args->rv = VNET_API_ERROR_INIT_FAILED;
    1497           0 :           virtio_log_error (vif,
    1498             :                             "error encountered during packet buffering init");
    1499           0 :           goto error;
    1500             :         }
    1501             :       /*
    1502             :        * packet buffering flag needs to be set 1 before calling the
    1503             :        * virtio_pre_input_node_enable but after the successful initialization
    1504             :        * of buffering queues above.
    1505             :        * Packet buffering flag set to 0 if there will be any error during
    1506             :        * buffering initialization.
    1507             :        */
    1508           0 :       vif->packet_buffering = 1;
    1509           0 :       virtio_pre_input_node_enable (vm, vif);
    1510             :     }
    1511             : 
    1512           0 :   virtio_vring_set_rx_queues (vm, vif);
    1513           0 :   virtio_vring_set_tx_queues (vm, vif);
    1514             : 
    1515           0 :   if (virtio_pci_is_link_up (vm, vif) & VIRTIO_NET_S_LINK_UP)
    1516             :     {
    1517           0 :       vnet_hw_interface_set_flags (vnm, vif->hw_if_index,
    1518             :                                    VNET_HW_INTERFACE_FLAG_LINK_UP);
    1519             :     }
    1520             :   else
    1521           0 :     vnet_hw_interface_set_flags (vnm, vif->hw_if_index, 0);
    1522             : 
    1523           0 :   virtio_pci_offloads (vm, vif, args->gso_enabled,
    1524           0 :                        args->checksum_offload_enabled);
    1525             : 
    1526           0 :   if ((vif->features & VIRTIO_FEATURE (VIRTIO_NET_F_CTRL_VQ)) &&
    1527           0 :       (vif->features & VIRTIO_FEATURE (VIRTIO_NET_F_MQ)))
    1528             :     {
    1529           0 :       if (virtio_pci_enable_multiqueue (vm, vif, vif->max_queue_pairs))
    1530           0 :         virtio_log_warning (vif, "multiqueue is not set");
    1531             :     }
    1532           0 :   return;
    1533             : 
    1534           0 : error:
    1535           0 :   virtio_pci_delete_if (vm, vif);
    1536           0 :   if (args->rv == 0)
    1537           0 :     args->rv = VNET_API_ERROR_INVALID_INTERFACE;
    1538           0 :   args->error = error;
    1539             : }
    1540             : 
    1541             : int
    1542           0 : virtio_pci_delete_if (vlib_main_t * vm, virtio_if_t * vif)
    1543             : {
    1544           0 :   vnet_main_t *vnm = vnet_get_main ();
    1545           0 :   virtio_main_t *vim = &virtio_main;
    1546           0 :   u32 i = 0;
    1547             : 
    1548           0 :   if (vif->type != VIRTIO_IF_TYPE_PCI)
    1549           0 :     return VNET_API_ERROR_INVALID_INTERFACE;
    1550             : 
    1551           0 :   vlib_pci_intr_disable (vm, vif->pci_dev_handle);
    1552             : 
    1553           0 :   if (vif->virtio_pci_func)
    1554             :     {
    1555           0 :       for (i = 0; i < vif->max_queue_pairs; i++)
    1556             :         {
    1557           0 :           vif->virtio_pci_func->del_queue (vm, vif, RX_QUEUE (i));
    1558           0 :           vif->virtio_pci_func->del_queue (vm, vif, TX_QUEUE (i));
    1559             :         }
    1560             : 
    1561           0 :       if (vif->features & VIRTIO_FEATURE (VIRTIO_NET_F_CTRL_VQ))
    1562           0 :         vif->virtio_pci_func->del_queue (vm, vif, vif->max_queue_pairs * 2);
    1563             : 
    1564           0 :       vif->virtio_pci_func->device_reset (vm, vif);
    1565             :     }
    1566             : 
    1567           0 :   if (vif->hw_if_index)
    1568             :     {
    1569           0 :       vnet_hw_interface_set_flags (vnm, vif->hw_if_index, 0);
    1570           0 :       ethernet_delete_interface (vnm, vif->hw_if_index);
    1571             :     }
    1572             : 
    1573           0 :   vlib_pci_device_close (vm, vif->pci_dev_handle);
    1574             : 
    1575           0 :   vec_foreach_index (i, vif->rxq_vrings)
    1576             :   {
    1577           0 :     vnet_virtio_vring_t *vring = vec_elt_at_index (vif->rxq_vrings, i);
    1578           0 :     if (vring->used)
    1579             :       {
    1580           0 :         virtio_free_buffers (vm, vring);
    1581             :       }
    1582           0 :     vec_free (vring->buffers);
    1583           0 :     vlib_physmem_free (vm, vring->desc);
    1584             :   }
    1585             : 
    1586           0 :   if (vif->packet_buffering)
    1587           0 :     virtio_pre_input_node_disable (vm, vif);
    1588             : 
    1589           0 :   vec_foreach_index (i, vif->txq_vrings)
    1590             :   {
    1591           0 :     vnet_virtio_vring_t *vring = vec_elt_at_index (vif->txq_vrings, i);
    1592           0 :     if (vring->used)
    1593             :       {
    1594           0 :         virtio_free_buffers (vm, vring);
    1595             :       }
    1596           0 :     vec_free (vring->buffers);
    1597           0 :     gro_flow_table_free (vring->flow_table);
    1598           0 :     virtio_vring_buffering_free (vm, vring->buffering);
    1599           0 :     clib_spinlock_free (&vring->lockp);
    1600           0 :     vlib_physmem_free (vm, vring->desc);
    1601             :   }
    1602             : 
    1603           0 :   if (vif->cxq_vring != NULL)
    1604             :     {
    1605           0 :       u16 last = vif->cxq_vring->last_used_idx;
    1606           0 :       u16 n_left = vif->cxq_vring->used->idx - last;
    1607           0 :       while (n_left)
    1608             :         {
    1609           0 :           last++;
    1610           0 :           n_left--;
    1611             :         }
    1612             : 
    1613           0 :       vif->cxq_vring->last_used_idx = last;
    1614           0 :       vlib_physmem_free (vm, vif->cxq_vring->desc);
    1615             :     }
    1616             : 
    1617           0 :   vec_free (vif->rxq_vrings);
    1618           0 :   vec_free (vif->txq_vrings);
    1619           0 :   vec_free (vif->cxq_vring);
    1620             : 
    1621           0 :   clib_error_free (vif->error);
    1622           0 :   memset (vif, 0, sizeof (*vif));
    1623           0 :   pool_put (vim->interfaces, vif);
    1624             : 
    1625           0 :   return 0;
    1626             : }
    1627             : 
    1628             : int
    1629           0 : virtio_pci_enable_disable_offloads (vlib_main_t * vm, virtio_if_t * vif,
    1630             :                                     int gso_enabled,
    1631             :                                     int checksum_offload_enabled,
    1632             :                                     int offloads_disabled)
    1633             : {
    1634           0 :   if (vif->type != VIRTIO_IF_TYPE_PCI)
    1635           0 :     return VNET_API_ERROR_INVALID_INTERFACE;
    1636             : 
    1637           0 :   if (gso_enabled)
    1638           0 :     virtio_pci_offloads (vm, vif, 1, 0);
    1639           0 :   else if (checksum_offload_enabled)
    1640           0 :     virtio_pci_offloads (vm, vif, 0, 1);
    1641           0 :   else if (offloads_disabled)
    1642           0 :     virtio_pci_offloads (vm, vif, 0, 0);
    1643             : 
    1644           0 :   return 0;
    1645             : }
    1646             : 
    1647             : /*
    1648             :  * fd.io coding-style-patch-verification: ON
    1649             :  *
    1650             :  * Local Variables:
    1651             :  * eval: (c-set-style "gnu")
    1652             :  * End:
    1653             :  */

Generated by: LCOV version 1.14