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