LCOV - code coverage report
Current view: top level - plugins/vhost - vhost_user_inline.h (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 8 193 4.1 %
Date: 2023-07-05 22:20:52 Functions: 3 22 13.6 %

          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             : #ifndef __VIRTIO_VHOST_USER_INLINE_H__
      16             : #define __VIRTIO_VHOST_USER_INLINE_H__
      17             : /* vhost-user inline functions */
      18             : #include <vppinfra/elog.h>
      19             : 
      20             : static_always_inline void *
      21           0 : map_guest_mem (vhost_user_intf_t * vui, uword addr, u32 * hint)
      22             : {
      23           0 :   int i = *hint;
      24           0 :   if (PREDICT_TRUE ((vui->regions[i].guest_phys_addr <= addr) &&
      25             :                     ((vui->regions[i].guest_phys_addr +
      26             :                       vui->regions[i].memory_size) > addr)))
      27             :     {
      28           0 :       return (void *) (vui->region_mmap_addr[i] + addr -
      29           0 :                        vui->regions[i].guest_phys_addr);
      30             :     }
      31             : #if __SSE4_2__
      32             :   __m128i rl, rh, al, ah, r;
      33           0 :   al = _mm_set1_epi64x (addr + 1);
      34           0 :   ah = _mm_set1_epi64x (addr);
      35             : 
      36           0 :   rl = _mm_loadu_si128 ((__m128i *) & vui->region_guest_addr_lo[0]);
      37           0 :   rl = _mm_cmpgt_epi64 (al, rl);
      38           0 :   rh = _mm_loadu_si128 ((__m128i *) & vui->region_guest_addr_hi[0]);
      39           0 :   rh = _mm_cmpgt_epi64 (rh, ah);
      40           0 :   r = _mm_and_si128 (rl, rh);
      41             : 
      42           0 :   rl = _mm_loadu_si128 ((__m128i *) & vui->region_guest_addr_lo[2]);
      43           0 :   rl = _mm_cmpgt_epi64 (al, rl);
      44           0 :   rh = _mm_loadu_si128 ((__m128i *) & vui->region_guest_addr_hi[2]);
      45           0 :   rh = _mm_cmpgt_epi64 (rh, ah);
      46           0 :   r = _mm_blend_epi16 (r, _mm_and_si128 (rl, rh), 0x22);
      47             : 
      48           0 :   rl = _mm_loadu_si128 ((__m128i *) & vui->region_guest_addr_lo[4]);
      49           0 :   rl = _mm_cmpgt_epi64 (al, rl);
      50           0 :   rh = _mm_loadu_si128 ((__m128i *) & vui->region_guest_addr_hi[4]);
      51           0 :   rh = _mm_cmpgt_epi64 (rh, ah);
      52           0 :   r = _mm_blend_epi16 (r, _mm_and_si128 (rl, rh), 0x44);
      53             : 
      54           0 :   rl = _mm_loadu_si128 ((__m128i *) & vui->region_guest_addr_lo[6]);
      55           0 :   rl = _mm_cmpgt_epi64 (al, rl);
      56           0 :   rh = _mm_loadu_si128 ((__m128i *) & vui->region_guest_addr_hi[6]);
      57           0 :   rh = _mm_cmpgt_epi64 (rh, ah);
      58           0 :   r = _mm_blend_epi16 (r, _mm_and_si128 (rl, rh), 0x88);
      59             : 
      60           0 :   r = _mm_shuffle_epi8 (r, _mm_set_epi64x (0, 0x0e060c040a020800));
      61           0 :   i = count_trailing_zeros (_mm_movemask_epi8 (r) |
      62             :                             (1 << VHOST_MEMORY_MAX_NREGIONS));
      63             : 
      64           0 :   if (i < vui->nregions)
      65             :     {
      66           0 :       *hint = i;
      67           0 :       return (void *) (vui->region_mmap_addr[i] + addr -
      68           0 :                        vui->regions[i].guest_phys_addr);
      69             :     }
      70             : #elif __aarch64__ && __ARM_NEON
      71             :   uint64x2_t al, ah, rl, rh, r;
      72             :   uint32_t u32 = 0;
      73             : 
      74             :   al = vdupq_n_u64 (addr + 1);
      75             :   ah = vdupq_n_u64 (addr);
      76             : 
      77             :   /*First Iteration */
      78             :   rl = vld1q_u64 (&vui->region_guest_addr_lo[0]);
      79             :   rl = vcgtq_u64 (al, rl);
      80             :   rh = vld1q_u64 (&vui->region_guest_addr_hi[0]);
      81             :   rh = vcgtq_u64 (rh, ah);
      82             :   r = vandq_u64 (rl, rh);
      83             :   u32 |= (vgetq_lane_u8 (vreinterpretq_u8_u64 (r), 0) & 0x1);
      84             :   u32 |= ((vgetq_lane_u8 (vreinterpretq_u8_u64 (r), 8) & 0x1) << 1);
      85             : 
      86             :   if (u32)
      87             :     {
      88             :       i = count_trailing_zeros (u32);
      89             :       goto vhost_map_guest_mem_done;
      90             :     }
      91             : 
      92             :   /*Second Iteration */
      93             :   rl = vld1q_u64 (&vui->region_guest_addr_lo[2]);
      94             :   rl = vcgtq_u64 (al, rl);
      95             :   rh = vld1q_u64 (&vui->region_guest_addr_hi[2]);
      96             :   rh = vcgtq_u64 (rh, ah);
      97             :   r = vandq_u64 (rl, rh);
      98             :   u32 |= ((vgetq_lane_u8 (vreinterpretq_u8_u64 (r), 0) & 0x1) << 2);
      99             :   u32 |= ((vgetq_lane_u8 (vreinterpretq_u8_u64 (r), 8) & 0x1) << 3);
     100             : 
     101             :   if (u32)
     102             :     {
     103             :       i = count_trailing_zeros (u32);
     104             :       goto vhost_map_guest_mem_done;
     105             :     }
     106             : 
     107             :   /*Third Iteration */
     108             :   rl = vld1q_u64 (&vui->region_guest_addr_lo[4]);
     109             :   rl = vcgtq_u64 (al, rl);
     110             :   rh = vld1q_u64 (&vui->region_guest_addr_hi[4]);
     111             :   rh = vcgtq_u64 (rh, ah);
     112             :   r = vandq_u64 (rl, rh);
     113             :   u32 |= ((vgetq_lane_u8 (vreinterpretq_u8_u64 (r), 0) & 0x1) << 6);
     114             :   u32 |= ((vgetq_lane_u8 (vreinterpretq_u8_u64 (r), 8) & 0x1) << 7);
     115             : 
     116             :   i = count_trailing_zeros (u32 | (1 << VHOST_MEMORY_MAX_NREGIONS));
     117             : 
     118             : vhost_map_guest_mem_done:
     119             :   if (i < vui->nregions)
     120             :     {
     121             :       *hint = i;
     122             :       return (void *) (vui->region_mmap_addr[i] + addr -
     123             :                        vui->regions[i].guest_phys_addr);
     124             :     }
     125             : #else
     126             :   for (i = 0; i < vui->nregions; i++)
     127             :     {
     128             :       if ((vui->regions[i].guest_phys_addr <= addr) &&
     129             :           ((vui->regions[i].guest_phys_addr + vui->regions[i].memory_size) >
     130             :            addr))
     131             :         {
     132             :           *hint = i;
     133             :           return (void *) (vui->region_mmap_addr[i] + addr -
     134             :                            vui->regions[i].guest_phys_addr);
     135             :         }
     136             :     }
     137             : #endif
     138             :   /* *INDENT-OFF* */
     139             :   ELOG_TYPE_DECLARE (el) =
     140             :   {
     141             :     .format = "failed to map guest mem addr %lx",
     142             :     .format_args = "i8",
     143             :   };
     144             :   /* *INDENT-ON* */
     145             :   struct
     146             :   {
     147             :     uword addr;
     148             :   } *ed;
     149           0 :   ed = ELOG_DATA (&vlib_global_main.elog_main, el);
     150           0 :   ed->addr = addr;
     151           0 :   *hint = 0;
     152           0 :   return 0;
     153             : }
     154             : 
     155             : static_always_inline void *
     156           0 : map_user_mem (vhost_user_intf_t * vui, uword addr)
     157             : {
     158             :   int i;
     159           0 :   for (i = 0; i < vui->nregions; i++)
     160             :     {
     161           0 :       if ((vui->regions[i].userspace_addr <= addr) &&
     162           0 :           ((vui->regions[i].userspace_addr + vui->regions[i].memory_size) >
     163             :            addr))
     164             :         {
     165           0 :           return (void *) (vui->region_mmap_addr[i] + addr -
     166           0 :                            vui->regions[i].userspace_addr);
     167             :         }
     168             :     }
     169           0 :   return 0;
     170             : }
     171             : 
     172             : #define VHOST_LOG_PAGE 0x1000
     173             : 
     174             : static_always_inline void
     175           0 : vhost_user_log_dirty_pages_2 (vhost_user_intf_t * vui,
     176             :                               u64 addr, u64 len, u8 is_host_address)
     177             : {
     178           0 :   if (PREDICT_TRUE (vui->log_base_addr == 0
     179             :                     || !(vui->features & VIRTIO_FEATURE (VHOST_F_LOG_ALL))))
     180             :     {
     181           0 :       return;
     182             :     }
     183           0 :   if (is_host_address)
     184             :     {
     185           0 :       addr = pointer_to_uword (map_user_mem (vui, (uword) addr));
     186             :     }
     187           0 :   if (PREDICT_FALSE ((addr + len - 1) / VHOST_LOG_PAGE / 8 >= vui->log_size))
     188             :     {
     189           0 :       vu_log_debug (vui, "vhost_user_log_dirty_pages(): out of range\n");
     190           0 :       return;
     191             :     }
     192             : 
     193           0 :   CLIB_MEMORY_BARRIER ();
     194           0 :   u64 page = addr / VHOST_LOG_PAGE;
     195           0 :   while (page * VHOST_LOG_PAGE < addr + len)
     196             :     {
     197           0 :       ((u8 *) vui->log_base_addr)[page / 8] |= 1 << page % 8;
     198           0 :       page++;
     199             :     }
     200             : }
     201             : 
     202             : #define vhost_user_log_dirty_ring(vui, vq, member)                            \
     203             :   if (PREDICT_FALSE (vq->log_used))                                           \
     204             :     {                                                                         \
     205             :       vhost_user_log_dirty_pages_2 (                                          \
     206             :         vui,                                                                  \
     207             :         vq->log_guest_addr +                                                  \
     208             :           STRUCT_OFFSET_OF (vnet_virtio_vring_used_t, member),                \
     209             :         sizeof (vq->used->member), 0);                                        \
     210             :     }
     211             : 
     212             : static_always_inline u8 *
     213           0 : format_vhost_trace (u8 * s, va_list * va)
     214             : {
     215           0 :   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*va, vlib_main_t *);
     216           0 :   CLIB_UNUSED (vlib_node_t * node) = va_arg (*va, vlib_node_t *);
     217           0 :   CLIB_UNUSED (vnet_main_t * vnm) = vnet_get_main ();
     218           0 :   vhost_user_main_t *vum = &vhost_user_main;
     219           0 :   vhost_trace_t *t = va_arg (*va, vhost_trace_t *);
     220           0 :   vhost_user_intf_t *vui = vum->vhost_user_interfaces + t->device_index;
     221             :   vnet_sw_interface_t *sw;
     222             :   u32 indent;
     223             : 
     224           0 :   if (pool_is_free (vum->vhost_user_interfaces, vui))
     225             :     {
     226           0 :       s = format (s, "vhost-user interface is deleted");
     227           0 :       return s;
     228             :     }
     229           0 :   sw = vnet_get_sw_interface (vnm, vui->sw_if_index);
     230           0 :   indent = format_get_indent (s);
     231           0 :   s = format (s, "%U %U queue %d\n", format_white_space, indent,
     232           0 :               format_vnet_sw_interface_name, vnm, sw, t->qid);
     233             : 
     234           0 :   s = format (s, "%U virtio flags:\n", format_white_space, indent);
     235             : #define _(n,i,st) \
     236             :           if (t->virtio_ring_flags & (1 << VIRTIO_TRACE_F_##n)) \
     237             :             s = format (s, "%U  %s %s\n", format_white_space, indent, #n, st);
     238           0 :   foreach_virtio_trace_flags
     239             : #undef _
     240           0 :     s = format (s, "%U virtio_net_hdr first_desc_len %u\n",
     241           0 :                 format_white_space, indent, t->first_desc_len);
     242             : 
     243           0 :   s = format (s, "%U   flags 0x%02x gso_type %u\n",
     244             :               format_white_space, indent,
     245           0 :               t->hdr.hdr.flags, t->hdr.hdr.gso_type);
     246             : 
     247           0 :   if (vui->virtio_net_hdr_sz == 12)
     248           0 :     s = format (s, "%U   num_buff %u",
     249           0 :                 format_white_space, indent, t->hdr.num_buffers);
     250             : 
     251           0 :   return s;
     252             : }
     253             : 
     254             : static_always_inline u64
     255      165028 : vhost_user_is_packed_ring_supported (vhost_user_intf_t * vui)
     256             : {
     257      165028 :   return (vui->features & VIRTIO_FEATURE (VIRTIO_F_RING_PACKED));
     258             : }
     259             : 
     260             : static_always_inline u64
     261           0 : vhost_user_is_event_idx_supported (vhost_user_intf_t * vui)
     262             : {
     263           0 :   return (vui->features & VIRTIO_FEATURE (VIRTIO_RING_F_EVENT_IDX));
     264             : }
     265             : 
     266             : static_always_inline void
     267           0 : vhost_user_kick (vlib_main_t * vm, vhost_user_vring_t * vq)
     268             : {
     269           0 :   vhost_user_main_t *vum = &vhost_user_main;
     270           0 :   u64 x = 1;
     271           0 :   int fd = UNIX_GET_FD (vq->callfd_idx);
     272             :   int rv;
     273             : 
     274           0 :   rv = write (fd, &x, sizeof (x));
     275           0 :   if (PREDICT_FALSE (rv <= 0))
     276             :     {
     277           0 :       clib_unix_warning
     278             :         ("Error: Could not write to unix socket for callfd %d", fd);
     279           0 :       return;
     280             :     }
     281             : 
     282           0 :   vq->n_since_last_int = 0;
     283           0 :   vq->int_deadline = vlib_time_now (vm) + vum->coalesce_time;
     284             : }
     285             : 
     286             : static_always_inline u16
     287           0 : vhost_user_avail_event_idx (vhost_user_vring_t * vq)
     288             : {
     289           0 :   volatile u16 *event_idx = (u16 *) & (vq->used->ring[vq->qsz_mask + 1]);
     290             : 
     291           0 :   return *event_idx;
     292             : }
     293             : 
     294             : static_always_inline u16
     295           0 : vhost_user_used_event_idx (vhost_user_vring_t * vq)
     296             : {
     297           0 :   volatile u16 *event_idx = (u16 *) & (vq->avail->ring[vq->qsz_mask + 1]);
     298             : 
     299           0 :   return *event_idx;
     300             : }
     301             : 
     302             : static_always_inline u16
     303           0 : vhost_user_need_event (u16 event_idx, u16 new_idx, u16 old_idx)
     304             : {
     305           0 :   return ((u16) (new_idx - event_idx - 1) < (u16) (new_idx - old_idx));
     306             : }
     307             : 
     308             : static_always_inline void
     309           0 : vhost_user_send_call_event_idx (vlib_main_t * vm, vhost_user_vring_t * vq)
     310             : {
     311           0 :   vhost_user_main_t *vum = &vhost_user_main;
     312           0 :   u8 first_kick = vq->first_kick;
     313           0 :   u16 event_idx = vhost_user_used_event_idx (vq);
     314             : 
     315           0 :   vq->first_kick = 1;
     316           0 :   if (vhost_user_need_event (event_idx, vq->last_used_idx, vq->last_kick) ||
     317           0 :       PREDICT_FALSE (!first_kick))
     318             :     {
     319           0 :       vhost_user_kick (vm, vq);
     320           0 :       vq->last_kick = event_idx;
     321             :     }
     322             :   else
     323             :     {
     324           0 :       vq->n_since_last_int = 0;
     325           0 :       vq->int_deadline = vlib_time_now (vm) + vum->coalesce_time;
     326             :     }
     327           0 : }
     328             : 
     329             : static_always_inline void
     330           0 : vhost_user_send_call_event_idx_packed (vlib_main_t * vm,
     331             :                                        vhost_user_vring_t * vq)
     332             : {
     333           0 :   vhost_user_main_t *vum = &vhost_user_main;
     334           0 :   u8 first_kick = vq->first_kick;
     335             :   u16 off_wrap;
     336             :   u16 event_idx;
     337           0 :   u16 new_idx = vq->last_used_idx;
     338           0 :   u16 old_idx = vq->last_kick;
     339             : 
     340           0 :   if (PREDICT_TRUE (vq->avail_event->flags == VRING_EVENT_F_DESC))
     341             :     {
     342           0 :       CLIB_COMPILER_BARRIER ();
     343           0 :       off_wrap = vq->avail_event->off_wrap;
     344           0 :       event_idx = off_wrap & 0x7fff;
     345           0 :       if (vq->used_wrap_counter != (off_wrap >> 15))
     346           0 :         event_idx -= (vq->qsz_mask + 1);
     347             : 
     348           0 :       if (new_idx <= old_idx)
     349           0 :         old_idx -= (vq->qsz_mask + 1);
     350             : 
     351           0 :       vq->first_kick = 1;
     352           0 :       vq->last_kick = event_idx;
     353           0 :       if (vhost_user_need_event (event_idx, new_idx, old_idx) ||
     354           0 :           PREDICT_FALSE (!first_kick))
     355           0 :         vhost_user_kick (vm, vq);
     356             :       else
     357             :         {
     358           0 :           vq->n_since_last_int = 0;
     359           0 :           vq->int_deadline = vlib_time_now (vm) + vum->coalesce_time;
     360             :         }
     361             :     }
     362             :   else
     363           0 :     vhost_user_kick (vm, vq);
     364           0 : }
     365             : 
     366             : static_always_inline void
     367           0 : vhost_user_send_call (vlib_main_t * vm, vhost_user_intf_t * vui,
     368             :                       vhost_user_vring_t * vq)
     369             : {
     370           0 :   if (vhost_user_is_event_idx_supported (vui))
     371             :     {
     372           0 :       if (vhost_user_is_packed_ring_supported (vui))
     373           0 :         vhost_user_send_call_event_idx_packed (vm, vq);
     374             :       else
     375           0 :         vhost_user_send_call_event_idx (vm, vq);
     376             :     }
     377             :   else
     378           0 :     vhost_user_kick (vm, vq);
     379           0 : }
     380             : 
     381             : static_always_inline u8
     382          12 : vui_is_link_up (vhost_user_intf_t * vui)
     383             : {
     384          12 :   return vui->admin_up && vui->is_ready;
     385             : }
     386             : 
     387             : static_always_inline void
     388           8 : vhost_user_update_gso_interface_count (vhost_user_intf_t * vui, u8 add)
     389             : {
     390           8 :   vhost_user_main_t *vum = &vhost_user_main;
     391             : 
     392           8 :   if (vui->enable_gso)
     393             :     {
     394           0 :       if (add)
     395             :         {
     396           0 :           vum->gso_count++;
     397             :         }
     398             :       else
     399             :         {
     400           0 :           ASSERT (vum->gso_count > 0);
     401           0 :           vum->gso_count--;
     402             :         }
     403             :     }
     404           8 : }
     405             : 
     406             : static_always_inline u8
     407           0 : vhost_user_packed_desc_available (vhost_user_vring_t * vring, u16 idx)
     408             : {
     409           0 :   return (((vring->packed_desc[idx].flags & VRING_DESC_F_AVAIL) ==
     410           0 :            vring->avail_wrap_counter));
     411             : }
     412             : 
     413             : static_always_inline void
     414           0 : vhost_user_advance_last_avail_idx (vhost_user_vring_t * vring)
     415             : {
     416           0 :   vring->last_avail_idx++;
     417           0 :   if (PREDICT_FALSE ((vring->last_avail_idx & vring->qsz_mask) == 0))
     418             :     {
     419           0 :       vring->avail_wrap_counter ^= VRING_DESC_F_AVAIL;
     420           0 :       vring->last_avail_idx = 0;
     421             :     }
     422           0 : }
     423             : 
     424             : static_always_inline void
     425           0 : vhost_user_advance_last_avail_table_idx (vhost_user_intf_t * vui,
     426             :                                          vhost_user_vring_t * vring,
     427             :                                          u8 chained)
     428             : {
     429           0 :   if (chained)
     430             :     {
     431           0 :       vnet_virtio_vring_packed_desc_t *desc_table = vring->packed_desc;
     432             : 
     433             :       /* pick up the slot of the next avail idx */
     434           0 :       while (desc_table[vring->last_avail_idx & vring->qsz_mask].flags &
     435             :              VRING_DESC_F_NEXT)
     436           0 :         vhost_user_advance_last_avail_idx (vring);
     437             :     }
     438             : 
     439           0 :   vhost_user_advance_last_avail_idx (vring);
     440           0 : }
     441             : 
     442             : static_always_inline void
     443           0 : vhost_user_undo_advanced_last_avail_idx (vhost_user_vring_t * vring)
     444             : {
     445           0 :   if (PREDICT_FALSE ((vring->last_avail_idx & vring->qsz_mask) == 0))
     446           0 :     vring->avail_wrap_counter ^= VRING_DESC_F_AVAIL;
     447             : 
     448           0 :   if (PREDICT_FALSE (vring->last_avail_idx == 0))
     449           0 :     vring->last_avail_idx = vring->qsz_mask;
     450             :   else
     451           0 :     vring->last_avail_idx--;
     452           0 : }
     453             : 
     454             : static_always_inline void
     455           0 : vhost_user_dequeue_descs (vhost_user_vring_t *rxvq,
     456             :                           vnet_virtio_net_hdr_mrg_rxbuf_t *hdr,
     457             :                           u16 *n_descs_processed)
     458             : {
     459             :   u16 i;
     460             : 
     461           0 :   *n_descs_processed -= (hdr->num_buffers - 1);
     462           0 :   for (i = 0; i < hdr->num_buffers - 1; i++)
     463           0 :     vhost_user_undo_advanced_last_avail_idx (rxvq);
     464           0 : }
     465             : 
     466             : static_always_inline void
     467           0 : vhost_user_dequeue_chained_descs (vhost_user_vring_t * rxvq,
     468             :                                   u16 * n_descs_processed)
     469             : {
     470           0 :   while (*n_descs_processed)
     471             :     {
     472           0 :       vhost_user_undo_advanced_last_avail_idx (rxvq);
     473           0 :       (*n_descs_processed)--;
     474             :     }
     475           0 : }
     476             : 
     477             : static_always_inline void
     478           0 : vhost_user_advance_last_used_idx (vhost_user_vring_t * vring)
     479             : {
     480           0 :   vring->last_used_idx++;
     481           0 :   if (PREDICT_FALSE ((vring->last_used_idx & vring->qsz_mask) == 0))
     482             :     {
     483           0 :       vring->used_wrap_counter ^= 1;
     484           0 :       vring->last_used_idx = 0;
     485             :     }
     486           0 : }
     487             : 
     488             : #endif
     489             : 
     490             : /*
     491             :  * fd.io coding-style-patch-verification: ON
     492             :  *
     493             :  * Local Variables:
     494             :  * eval: (c-set-style "gnu")
     495             :  * End:
     496             :  */

Generated by: LCOV version 1.14