blob: 179f319aa4c548de9dfe95722632a81ce311cc07 [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") \
20 _ (UNKNOWN, "unknown")
21
22typedef 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
30static_always_inline void
31virtio_refill_vring_split (vlib_main_t *vm, virtio_if_t *vif,
Mohsin Kazmi0f8912f2022-02-01 18:35:59 +000032 virtio_if_type_t type, vnet_virtio_vring_t *vring,
Mohsin Kazmi6799f9b2021-04-28 18:55:45 +020033 const int hdr_sz, u32 node_index)
34{
35 u16 used, next, avail, n_slots, n_refill;
Mohsin Kazmi0f8912f2022-02-01 18:35:59 +000036 u16 sz = vring->queue_size;
Mohsin Kazmi6799f9b2021-04-28 18:55:45 +020037 u16 mask = sz - 1;
38
39more:
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;
Mohsin Kazmi0f8912f2022-02-01 18:35:59 +000050 n_slots = vlib_buffer_alloc_to_ring_from_pool (vm, vring->buffers, next,
51 vring->queue_size, n_refill,
52 vring->buffer_pool_index);
Mohsin Kazmi6799f9b2021-04-28 18:55:45 +020053
54 if (PREDICT_FALSE (n_slots != n_refill))
55 {
56 vlib_error_count (vm, node_index, VIRTIO_INPUT_ERROR_BUFFER_ALLOC,
57 n_refill - n_slots);
58 if (n_slots == 0)
59 return;
60 }
61
62 while (n_slots)
63 {
Mohsin Kazmi0f8912f2022-02-01 18:35:59 +000064 vnet_virtio_vring_desc_t *d = &vring->desc[next];
Mohsin Kazmi6799f9b2021-04-28 18:55:45 +020065 ;
66 vlib_buffer_t *b = vlib_get_buffer (vm, vring->buffers[next]);
67 /*
68 * current_data may not be initialized with 0 and may contain
69 * previous offset. Here we want to make sure, it should be 0
70 * initialized.
71 */
72 b->current_data = -hdr_sz;
73 clib_memset (vlib_buffer_get_current (b), 0, hdr_sz);
74 d->addr = ((type == VIRTIO_IF_TYPE_PCI) ?
75 vlib_buffer_get_current_pa (vm, b) :
76 pointer_to_uword (vlib_buffer_get_current (b)));
77 d->len = vlib_buffer_get_default_data_size (vm) + hdr_sz;
78 d->flags = VRING_DESC_F_WRITE;
79 vring->avail->ring[avail & mask] = next;
80 avail++;
81 next = (next + 1) & mask;
82 n_slots--;
83 used++;
84 }
85 clib_atomic_store_seq_cst (&vring->avail->idx, avail);
86 vring->desc_next = next;
87 vring->desc_in_use = used;
88 if ((clib_atomic_load_seq_cst (&vring->used->flags) &
89 VRING_USED_F_NO_NOTIFY) == 0)
90 {
91 virtio_kick (vm, vring, vif);
92 }
93 goto more;
94}
95
96static_always_inline void
97virtio_refill_vring_packed (vlib_main_t *vm, virtio_if_t *vif,
Mohsin Kazmi0f8912f2022-02-01 18:35:59 +000098 virtio_if_type_t type, vnet_virtio_vring_t *vring,
Mohsin Kazmi6799f9b2021-04-28 18:55:45 +020099 const int hdr_sz, u32 node_index)
100{
101 u16 used, next, n_slots, n_refill, flags = 0, first_desc_flags;
Mohsin Kazmi0f8912f2022-02-01 18:35:59 +0000102 u16 sz = vring->queue_size;
Mohsin Kazmi6799f9b2021-04-28 18:55:45 +0200103
104more:
105 used = vring->desc_in_use;
106
107 if (sz == used)
108 return;
109
110 /* deliver free buffers in chunks of 64 */
111 n_refill = clib_min (sz - used, 64);
112
113 next = vring->desc_next;
114 first_desc_flags = vring->packed_desc[next].flags;
115 n_slots = vlib_buffer_alloc_to_ring_from_pool (
116 vm, vring->buffers, next, sz, n_refill, vring->buffer_pool_index);
117
118 if (PREDICT_FALSE (n_slots != n_refill))
119 {
120 vlib_error_count (vm, node_index, VIRTIO_INPUT_ERROR_BUFFER_ALLOC,
121 n_refill - n_slots);
122 if (n_slots == 0)
123 return;
124 }
125
126 while (n_slots)
127 {
Mohsin Kazmi0f8912f2022-02-01 18:35:59 +0000128 vnet_virtio_vring_packed_desc_t *d = &vring->packed_desc[next];
Mohsin Kazmi6799f9b2021-04-28 18:55:45 +0200129 vlib_buffer_t *b = vlib_get_buffer (vm, vring->buffers[next]);
130 /*
131 * current_data may not be initialized with 0 and may contain
132 * previous offset. Here we want to make sure, it should be 0
133 * initialized.
134 */
135 b->current_data = -hdr_sz;
136 clib_memset (vlib_buffer_get_current (b), 0, hdr_sz);
137 d->addr = ((type == VIRTIO_IF_TYPE_PCI) ?
138 vlib_buffer_get_current_pa (vm, b) :
139 pointer_to_uword (vlib_buffer_get_current (b)));
140 d->len = vlib_buffer_get_default_data_size (vm) + hdr_sz;
141
142 if (vring->avail_wrap_counter)
143 flags = (VRING_DESC_F_AVAIL | VRING_DESC_F_WRITE);
144 else
145 flags = (VRING_DESC_F_USED | VRING_DESC_F_WRITE);
146
147 d->id = next;
148 if (vring->desc_next == next)
149 first_desc_flags = flags;
150 else
151 d->flags = flags;
152
153 next++;
154 if (next >= sz)
155 {
156 next = 0;
157 vring->avail_wrap_counter ^= 1;
158 }
159 n_slots--;
160 used++;
161 }
162 CLIB_MEMORY_STORE_BARRIER ();
163 vring->packed_desc[vring->desc_next].flags = first_desc_flags;
164 vring->desc_next = next;
165 vring->desc_in_use = used;
166 CLIB_MEMORY_BARRIER ();
167 if (vring->device_event->flags != VRING_EVENT_F_DISABLE)
168 {
169 virtio_kick (vm, vring, vif);
170 }
171
172 goto more;
173}
174
175#endif
176
177/*
178 * fd.io coding-style-patch-verification: ON
179 *
180 * Local Variables:
181 * eval: (c-set-style "gnu")
182 * End:
183 */