Mohsin Kazmi | 6799f9b | 2021-04-28 18:55:45 +0200 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (c) 2015 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_INLINE_H__ |
| 16 | #define __VIRTIO_INLINE_H__ |
| 17 | |
| 18 | #define foreach_virtio_input_error \ |
| 19 | _ (BUFFER_ALLOC, "buffer alloc error") \ |
| 20 | _ (UNKNOWN, "unknown") |
| 21 | |
| 22 | typedef enum |
| 23 | { |
| 24 | #define _(f, s) VIRTIO_INPUT_ERROR_##f, |
| 25 | foreach_virtio_input_error |
| 26 | #undef _ |
| 27 | VIRTIO_INPUT_N_ERROR, |
| 28 | } virtio_input_error_t; |
| 29 | |
| 30 | static_always_inline void |
| 31 | virtio_refill_vring_split (vlib_main_t *vm, virtio_if_t *vif, |
| 32 | virtio_if_type_t type, virtio_vring_t *vring, |
| 33 | const int hdr_sz, u32 node_index) |
| 34 | { |
| 35 | u16 used, next, avail, n_slots, n_refill; |
| 36 | u16 sz = vring->size; |
| 37 | u16 mask = sz - 1; |
| 38 | |
| 39 | more: |
| 40 | used = vring->desc_in_use; |
| 41 | |
| 42 | if (sz - used < sz / 8) |
| 43 | return; |
| 44 | |
| 45 | /* deliver free buffers in chunks of 64 */ |
| 46 | n_refill = clib_min (sz - used, 64); |
| 47 | |
| 48 | next = vring->desc_next; |
| 49 | avail = vring->avail->idx; |
| 50 | n_slots = vlib_buffer_alloc_to_ring_from_pool ( |
| 51 | vm, vring->buffers, next, vring->size, n_refill, vring->buffer_pool_index); |
| 52 | |
| 53 | if (PREDICT_FALSE (n_slots != n_refill)) |
| 54 | { |
| 55 | vlib_error_count (vm, node_index, VIRTIO_INPUT_ERROR_BUFFER_ALLOC, |
| 56 | n_refill - n_slots); |
| 57 | if (n_slots == 0) |
| 58 | return; |
| 59 | } |
| 60 | |
| 61 | while (n_slots) |
| 62 | { |
| 63 | vring_desc_t *d = &vring->desc[next]; |
| 64 | ; |
| 65 | vlib_buffer_t *b = vlib_get_buffer (vm, vring->buffers[next]); |
| 66 | /* |
| 67 | * current_data may not be initialized with 0 and may contain |
| 68 | * previous offset. Here we want to make sure, it should be 0 |
| 69 | * initialized. |
| 70 | */ |
| 71 | b->current_data = -hdr_sz; |
| 72 | clib_memset (vlib_buffer_get_current (b), 0, hdr_sz); |
| 73 | d->addr = ((type == VIRTIO_IF_TYPE_PCI) ? |
| 74 | vlib_buffer_get_current_pa (vm, b) : |
| 75 | pointer_to_uword (vlib_buffer_get_current (b))); |
| 76 | d->len = vlib_buffer_get_default_data_size (vm) + hdr_sz; |
| 77 | d->flags = VRING_DESC_F_WRITE; |
| 78 | vring->avail->ring[avail & mask] = next; |
| 79 | avail++; |
| 80 | next = (next + 1) & mask; |
| 81 | n_slots--; |
| 82 | used++; |
| 83 | } |
| 84 | clib_atomic_store_seq_cst (&vring->avail->idx, avail); |
| 85 | vring->desc_next = next; |
| 86 | vring->desc_in_use = used; |
| 87 | if ((clib_atomic_load_seq_cst (&vring->used->flags) & |
| 88 | VRING_USED_F_NO_NOTIFY) == 0) |
| 89 | { |
| 90 | virtio_kick (vm, vring, vif); |
| 91 | } |
| 92 | goto more; |
| 93 | } |
| 94 | |
| 95 | static_always_inline void |
| 96 | virtio_refill_vring_packed (vlib_main_t *vm, virtio_if_t *vif, |
| 97 | virtio_if_type_t type, virtio_vring_t *vring, |
| 98 | const int hdr_sz, u32 node_index) |
| 99 | { |
| 100 | u16 used, next, n_slots, n_refill, flags = 0, first_desc_flags; |
| 101 | u16 sz = vring->size; |
| 102 | |
| 103 | more: |
| 104 | used = vring->desc_in_use; |
| 105 | |
| 106 | if (sz == used) |
| 107 | return; |
| 108 | |
| 109 | /* deliver free buffers in chunks of 64 */ |
| 110 | n_refill = clib_min (sz - used, 64); |
| 111 | |
| 112 | next = vring->desc_next; |
| 113 | first_desc_flags = vring->packed_desc[next].flags; |
| 114 | n_slots = vlib_buffer_alloc_to_ring_from_pool ( |
| 115 | vm, vring->buffers, next, sz, n_refill, vring->buffer_pool_index); |
| 116 | |
| 117 | if (PREDICT_FALSE (n_slots != n_refill)) |
| 118 | { |
| 119 | vlib_error_count (vm, node_index, VIRTIO_INPUT_ERROR_BUFFER_ALLOC, |
| 120 | n_refill - n_slots); |
| 121 | if (n_slots == 0) |
| 122 | return; |
| 123 | } |
| 124 | |
| 125 | while (n_slots) |
| 126 | { |
| 127 | vring_packed_desc_t *d = &vring->packed_desc[next]; |
| 128 | vlib_buffer_t *b = vlib_get_buffer (vm, vring->buffers[next]); |
| 129 | /* |
| 130 | * current_data may not be initialized with 0 and may contain |
| 131 | * previous offset. Here we want to make sure, it should be 0 |
| 132 | * initialized. |
| 133 | */ |
| 134 | b->current_data = -hdr_sz; |
| 135 | clib_memset (vlib_buffer_get_current (b), 0, hdr_sz); |
| 136 | d->addr = ((type == VIRTIO_IF_TYPE_PCI) ? |
| 137 | vlib_buffer_get_current_pa (vm, b) : |
| 138 | pointer_to_uword (vlib_buffer_get_current (b))); |
| 139 | d->len = vlib_buffer_get_default_data_size (vm) + hdr_sz; |
| 140 | |
| 141 | if (vring->avail_wrap_counter) |
| 142 | flags = (VRING_DESC_F_AVAIL | VRING_DESC_F_WRITE); |
| 143 | else |
| 144 | flags = (VRING_DESC_F_USED | VRING_DESC_F_WRITE); |
| 145 | |
| 146 | d->id = next; |
| 147 | if (vring->desc_next == next) |
| 148 | first_desc_flags = flags; |
| 149 | else |
| 150 | d->flags = flags; |
| 151 | |
| 152 | next++; |
| 153 | if (next >= sz) |
| 154 | { |
| 155 | next = 0; |
| 156 | vring->avail_wrap_counter ^= 1; |
| 157 | } |
| 158 | n_slots--; |
| 159 | used++; |
| 160 | } |
| 161 | CLIB_MEMORY_STORE_BARRIER (); |
| 162 | vring->packed_desc[vring->desc_next].flags = first_desc_flags; |
| 163 | vring->desc_next = next; |
| 164 | vring->desc_in_use = used; |
| 165 | CLIB_MEMORY_BARRIER (); |
| 166 | if (vring->device_event->flags != VRING_EVENT_F_DISABLE) |
| 167 | { |
| 168 | virtio_kick (vm, vring, vif); |
| 169 | } |
| 170 | |
| 171 | goto more; |
| 172 | } |
| 173 | |
| 174 | #endif |
| 175 | |
| 176 | /* |
| 177 | * fd.io coding-style-patch-verification: ON |
| 178 | * |
| 179 | * Local Variables: |
| 180 | * eval: (c-set-style "gnu") |
| 181 | * End: |
| 182 | */ |