virtio: integrate with new tx infra
[vpp.git] / src / vnet / devices / virtio / virtio_buffering.h
1 /*
2  *------------------------------------------------------------------
3  * Copyright (c) 2020 Cisco and/or its affiliates.
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at:
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *------------------------------------------------------------------
16  */
17
18 #ifndef _VNET_DEVICES_VIRTIO_VIRTIO_BUFFERING_H_
19 #define _VNET_DEVICES_VIRTIO_VIRTIO_BUFFERING_H_
20
21 #include <vnet/interface.h>
22
23 #define VIRTIO_BUFFERING_DEFAULT_SIZE 1024
24 #define VIRTIO_BUFFERING_TIMEOUT 1e-5
25
26 typedef struct
27 {
28   f64 timeout_ts;
29   u32 *buffers;
30   u32 node_index;
31   u16 size;
32   u16 free_size;
33   u16 front;
34   u16 back;
35   u8 is_enable;
36 } virtio_vring_buffering_t;
37
38 static_always_inline clib_error_t *
39 virtio_vring_buffering_init (virtio_vring_buffering_t ** buffering,
40                              u32 node_index, u16 size)
41 {
42   if (*buffering)
43     return clib_error_return (0, "buffering: already initialized");
44
45   if (!is_pow2 (size))
46     return clib_error_return (0, "buffering: size must be power of 2");
47
48   if (size > 32768)
49     return clib_error_return (0, "buffering: size must be 32768 or lower");
50
51   if (size == 0)
52     size = VIRTIO_BUFFERING_DEFAULT_SIZE;
53
54   virtio_vring_buffering_t *b_temp = 0;
55   b_temp =
56     (virtio_vring_buffering_t *)
57     clib_mem_alloc (sizeof (virtio_vring_buffering_t));
58   if (!b_temp)
59     return clib_error_return (0, "buffering: memory allocation failed");
60
61   clib_memset (b_temp, 0, sizeof (virtio_vring_buffering_t));
62
63   b_temp->node_index = node_index;
64   b_temp->free_size = size;
65   b_temp->size = size;
66
67   vec_validate_aligned (b_temp->buffers, size, CLIB_CACHE_LINE_BYTES);
68   b_temp->is_enable = 1;
69
70   *buffering = b_temp;
71   return 0;
72 }
73
74 static_always_inline void
75 virtio_vring_buffering_buffers_free (vlib_main_t * vm,
76                                      virtio_vring_buffering_t * buffering)
77 {
78   u16 n_buffers = buffering->size - buffering->free_size;
79   if (n_buffers)
80     {
81       vlib_buffer_free_from_ring (vm, buffering->buffers, buffering->front,
82                                   buffering->size, n_buffers);
83       buffering->free_size += n_buffers;
84     }
85 }
86
87 static_always_inline void
88 virtio_vring_buffering_free (vlib_main_t * vm,
89                              virtio_vring_buffering_t * buffering)
90 {
91   if (buffering)
92     {
93       virtio_vring_buffering_buffers_free (vm, buffering);
94       vec_free (buffering->buffers);
95       clib_mem_free (buffering);
96     }
97 }
98
99 static_always_inline u8
100 virtio_vring_buffering_is_enable (virtio_vring_buffering_t * buffering)
101 {
102   if (buffering)
103     return buffering->is_enable;
104
105   return 0;
106 }
107
108 static_always_inline void
109 virtio_vring_buffering_set_is_enable (virtio_vring_buffering_t * buffering,
110                                       u8 is_enable)
111 {
112   if (buffering)
113     buffering->is_enable = is_enable;
114 }
115
116 static_always_inline void
117 virtio_vring_buffering_set_timeout (vlib_main_t * vm,
118                                     virtio_vring_buffering_t * buffering,
119                                     f64 timeout_expire)
120 {
121   if (buffering)
122     buffering->timeout_ts = vlib_time_now (vm) + timeout_expire;
123 }
124
125 static_always_inline u8
126 virtio_vring_buffering_is_timeout (vlib_main_t * vm,
127                                    virtio_vring_buffering_t * buffering)
128 {
129   if (buffering && (buffering->timeout_ts < vlib_time_now (vm)))
130     return 1;
131   return 0;
132 }
133
134 static_always_inline u8
135 virtio_vring_buffering_is_empty (virtio_vring_buffering_t * buffering)
136 {
137   if (buffering->size == buffering->free_size)
138     return 1;
139   return 0;
140 }
141
142 static_always_inline u8
143 virtio_vring_buffering_is_full (virtio_vring_buffering_t * buffering)
144 {
145   if (buffering->free_size == 0)
146     return 1;
147   return 0;
148 }
149
150 static_always_inline u16
151 virtio_vring_n_buffers (virtio_vring_buffering_t * buffering)
152 {
153   return (buffering->size - buffering->free_size);
154 }
155
156 static_always_inline u16
157 virtio_vring_buffering_store_packets (virtio_vring_buffering_t * buffering,
158                                       u32 * bi, u16 n_store)
159 {
160   u16 mask, n_s = 0, i = 0;
161
162   if (!virtio_vring_buffering_is_enable (buffering)
163       || virtio_vring_buffering_is_full (buffering))
164     return 0;
165
166   mask = buffering->size - 1;
167   n_s = clib_min (n_store, buffering->free_size);
168
169   while (i < n_s)
170     {
171       buffering->buffers[buffering->back] = bi[i];
172       buffering->back = (buffering->back + 1) & mask;
173       buffering->free_size--;
174       i++;
175     }
176   return n_s;
177 }
178
179 static_always_inline u32
180 virtio_vring_buffering_read_from_front (virtio_vring_buffering_t * buffering)
181 {
182   u32 bi = ~0;
183   u16 mask = buffering->size - 1;
184   if (virtio_vring_buffering_is_empty (buffering))
185     return bi;
186
187   bi = buffering->buffers[buffering->front];
188   buffering->buffers[buffering->front] = ~0;
189   buffering->front = (buffering->front + 1) & mask;
190   buffering->free_size++;
191   return bi;
192 }
193
194 static_always_inline u32
195 virtio_vring_buffering_read_from_back (virtio_vring_buffering_t * buffering)
196 {
197   u32 bi = ~0;
198   u16 mask = buffering->size - 1;
199   if (virtio_vring_buffering_is_empty (buffering))
200     return bi;
201
202   buffering->back = (buffering->back - 1) & mask;
203   bi = buffering->buffers[buffering->back];
204   buffering->buffers[buffering->back] = ~0;
205   buffering->free_size++;
206   return bi;
207 }
208
209 static_always_inline void
210 virtio_vring_buffering_schedule_node_on_dispatcher (
211   vlib_main_t *vm, vnet_hw_if_tx_queue_t *txq,
212   virtio_vring_buffering_t *buffering)
213 {
214   if (buffering && virtio_vring_buffering_is_timeout (vm, buffering)
215       && virtio_vring_n_buffers (buffering))
216     {
217       vlib_frame_t *f = vlib_get_frame_to_node (vm, buffering->node_index);
218       vnet_hw_if_tx_frame_t *ft = vlib_frame_scalar_args (f);
219       u32 *f_to = vlib_frame_vector_args (f);
220       ft->shared_queue = txq->shared_queue;
221       ft->queue_id = txq->queue_id;
222       f_to[f->n_vectors] = virtio_vring_buffering_read_from_back (buffering);
223       f->n_vectors++;
224       vlib_put_frame_to_node (vm, buffering->node_index, f);
225       virtio_vring_buffering_set_timeout (vm, buffering,
226                                           VIRTIO_BUFFERING_TIMEOUT);
227     }
228 }
229
230 static_always_inline u8 *
231 virtio_vring_buffering_format (u8 * s, va_list * args)
232 {
233   virtio_vring_buffering_t *buffering =
234     va_arg (*args, virtio_vring_buffering_t *);
235   u32 indent = format_get_indent (s);
236
237   if (!buffering)
238     return s;
239
240   indent += 2;
241
242   if (buffering->is_enable)
243     s = format (s, "packet-buffering: enable\n");
244   else
245     s = format (s, "packet-buffering: disable\n");
246   s =
247     format (s,
248             "%Usize %u n_buffers %u front %u back %u",
249             format_white_space, indent, buffering->size,
250             virtio_vring_n_buffers (buffering), buffering->front,
251             buffering->back);
252
253   return s;
254 }
255
256 #endif /* _VNET_DEVICES_VIRTIO_VIRTIO_BUFFERING_H_ */
257
258 /*
259  * fd.io coding-style-patch-verification: ON
260  *
261  * Local Variables:
262  * eval: (c-set-style "gnu")
263  * End:
264  */