/* * Copyright (c) 2015 Cisco and/or its affiliates. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef __VIRTIO_INLINE_H__ #define __VIRTIO_INLINE_H__ #define foreach_virtio_input_error \ _ (BUFFER_ALLOC, "buffer alloc error") \ _ (UNKNOWN, "unknown") typedef enum { #define _(f, s) VIRTIO_INPUT_ERROR_##f, foreach_virtio_input_error #undef _ VIRTIO_INPUT_N_ERROR, } virtio_input_error_t; static_always_inline void virtio_refill_vring_split (vlib_main_t *vm, virtio_if_t *vif, virtio_if_type_t type, vnet_virtio_vring_t *vring, const int hdr_sz, u32 node_index) { u16 used, next, avail, n_slots, n_refill; u16 sz = vring->queue_size; u16 mask = sz - 1; more: used = vring->desc_in_use; if (sz - used < sz / 8) return; /* deliver free buffers in chunks of 64 */ n_refill = clib_min (sz - used, 64); next = vring->desc_next; avail = vring->avail->idx; n_slots = vlib_buffer_alloc_to_ring_from_pool (vm, vring->buffers, next, vring->queue_size, n_refill, vring->buffer_pool_index); if (PREDICT_FALSE (n_slots != n_refill)) { vlib_error_count (vm, node_index, VIRTIO_INPUT_ERROR_BUFFER_ALLOC, n_refill - n_slots); if (n_slots == 0) return; } while (n_slots) { vnet_virtio_vring_desc_t *d = &vring->desc[next]; ; vlib_buffer_t *b = vlib_get_buffer (vm, vring->buffers[next]); /* * current_data may not be initialized with 0 and may contain * previous offset. Here we want to make sure, it should be 0 * initialized. */ b->current_data = -hdr_sz; clib_memset (vlib_buffer_get_current (b), 0, hdr_sz); d->addr = ((type == VIRTIO_IF_TYPE_PCI) ? vlib_buffer_get_current_pa (vm, b) : pointer_to_uword (vlib_buffer_get_current (b))); d->len = vlib_buffer_get_default_data_size (vm) + hdr_sz; d->flags = VRING_DESC_F_WRITE; vring->avail->ring[avail & mask] = next; avail++; next = (next + 1) & mask; n_slots--; used++; } clib_atomic_store_seq_cst (&vring->avail->idx, avail); vring->desc_next = next; vring->desc_in_use = used; if ((clib_atomic_load_seq_cst (&vring->used->flags) & VRING_USED_F_NO_NOTIFY) == 0) { virtio_kick (vm, vring, vif); } goto more; } static_always_inline void virtio_refill_vring_packed (vlib_main_t *vm, virtio_if_t *vif, virtio_if_type_t type, vnet_virtio_vring_t *vring, const int hdr_sz, u32 node_index) { u16 used, next, n_slots, n_refill, flags = 0, first_desc_flags; u16 sz = vring->queue_size; more: used = vring->desc_in_use; if (sz == used) return; /* deliver free buffers in chunks of 64 */ n_refill = clib_min (sz - used, 64); next = vring->desc_next; first_desc_flags = vring->packed_desc[next].flags; n_slots = vlib_buffer_alloc_to_ring_from_pool ( vm, vring->buffers, next, sz, n_refill, vring->buffer_pool_index); if (PREDICT_FALSE (n_slots != n_refill)) { vlib_error_count (vm, node_index, VIRTIO_INPUT_ERROR_BUFFER_ALLOC, n_refill - n_slots); if (n_slots == 0) return; } while (n_slots) { vnet_virtio_vring_packed_desc_t *d = &vring->packed_desc[next]; vlib_buffer_t *b = vlib_get_buffer (vm, vring->buffers[next]); /* * current_data may not be initialized with 0 and may contain * previous offset. Here we want to make sure, it should be 0 * initialized. */ b->current_data = -hdr_sz; clib_memset (vlib_buffer_get_current (b), 0, hdr_sz); d->addr = ((type == VIRTIO_IF_TYPE_PCI) ? vlib_buffer_get_current_pa (vm, b) : pointer_to_uword (vlib_buffer_get_current (b))); d->len = vlib_buffer_get_default_data_size (vm) + hdr_sz; if (vring->avail_wrap_counter) flags = (VRING_DESC_F_AVAIL | VRING_DESC_F_WRITE); else flags = (VRING_DESC_F_USED | VRING_DESC_F_WRITE); d->id = next; if (vring->desc_next == next) first_desc_flags = flags; else d->flags = flags; next++; if (next >= sz) { next = 0; vring->avail_wrap_counter ^= 1; } n_slots--; used++; } CLIB_MEMORY_STORE_BARRIER (); vring->packed_desc[vring->desc_next].flags = first_desc_flags; vring->desc_next = next; vring->desc_in_use = used; CLIB_MEMORY_BARRIER (); if (vring->device_event->flags != VRING_EVENT_F_DISABLE) { virtio_kick (vm, vring, vif); } goto more; } #endif /* * fd.io coding-style-patch-verification: ON * * Local Variables: * eval: (c-set-style "gnu") * End: */