blob: 41bba755934ad83ff70001eb2ff329d87777ca44 [file] [log] [blame]
Mohsin Kazmi6799f9b2021-04-28 18:55:45 +02001/*
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 Luong1b053782024-03-20 12:28:49 -070020 _ (FULL_RX_QUEUE, "full rx queue (driver tx drop)") \
Mohsin Kazmi6799f9b2021-04-28 18:55:45 +020021 _ (UNKNOWN, "unknown")
22
23typedef 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
31static_always_inline void
32virtio_refill_vring_split (vlib_main_t *vm, virtio_if_t *vif,
Mohsin Kazmi0f8912f2022-02-01 18:35:59 +000033 virtio_if_type_t type, vnet_virtio_vring_t *vring,
Mohsin Kazmi6799f9b2021-04-28 18:55:45 +020034 const int hdr_sz, u32 node_index)
35{
36 u16 used, next, avail, n_slots, n_refill;
Mohsin Kazmi0f8912f2022-02-01 18:35:59 +000037 u16 sz = vring->queue_size;
Mohsin Kazmi6799f9b2021-04-28 18:55:45 +020038 u16 mask = sz - 1;
39
40more:
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 Kazmi0f8912f2022-02-01 18:35:59 +000051 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 Kazmi6799f9b2021-04-28 18:55:45 +020054
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 Kazmi0f8912f2022-02-01 18:35:59 +000065 vnet_virtio_vring_desc_t *d = &vring->desc[next];
Mohsin Kazmi6799f9b2021-04-28 18:55:45 +020066 ;
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
97static_always_inline void
98virtio_refill_vring_packed (vlib_main_t *vm, virtio_if_t *vif,
Mohsin Kazmi0f8912f2022-02-01 18:35:59 +000099 virtio_if_type_t type, vnet_virtio_vring_t *vring,
Mohsin Kazmi6799f9b2021-04-28 18:55:45 +0200100 const int hdr_sz, u32 node_index)
101{
102 u16 used, next, n_slots, n_refill, flags = 0, first_desc_flags;
Mohsin Kazmi0f8912f2022-02-01 18:35:59 +0000103 u16 sz = vring->queue_size;
Mohsin Kazmi6799f9b2021-04-28 18:55:45 +0200104
105more:
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 Kazmi0f8912f2022-02-01 18:35:59 +0000129 vnet_virtio_vring_packed_desc_t *d = &vring->packed_desc[next];
Mohsin Kazmi6799f9b2021-04-28 18:55:45 +0200130 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 */