blob: 140cdb94153a5f76c138c22744015404dcb06330 [file] [log] [blame]
Mohsin Kazmid6c15af2018-10-23 18:00:47 +02001/*
2 * Copyright (c) 2018 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
16#include <fcntl.h>
17#include <sys/ioctl.h>
Mohsin Kazmid6c15af2018-10-23 18:00:47 +020018
19#include <vppinfra/types.h>
20#include <vlib/vlib.h>
21#include <vlib/pci/pci.h>
22#include <vnet/ethernet/ethernet.h>
Mohsin Kazmid6c15af2018-10-23 18:00:47 +020023#include <vnet/ip/ip4_packet.h>
24#include <vnet/ip/ip6_packet.h>
25#include <vnet/devices/virtio/virtio.h>
26#include <vnet/devices/virtio/pci.h>
Damjan Marion94100532020-11-06 23:25:57 +010027#include <vnet/interface/rx_queue_funcs.h>
Mohsin Kazmid6c15af2018-10-23 18:00:47 +020028
29#define PCI_VENDOR_ID_VIRTIO 0x1af4
30#define PCI_DEVICE_ID_VIRTIO_NIC 0x1000
31/* Doesn't support modern device */
32#define PCI_DEVICE_ID_VIRTIO_NIC_MODERN 0x1041
33
34#define PCI_CAPABILITY_LIST 0x34
35#define PCI_CAP_ID_VNDR 0x09
36#define PCI_CAP_ID_MSIX 0x11
37
38#define PCI_MSIX_ENABLE 0x8000
39
Steven Luonge9bc3322023-12-14 08:54:55 -080040static const u8 virtio_rss_key[VIRTIO_NET_RSS_MAX_KEY_SIZE] = {
41 0x6d, 0x5a, 0x56, 0xda, 0x25, 0x5b, 0x0e, 0xc2, 0x41, 0x67,
42 0x25, 0x3d, 0x43, 0xa3, 0x8f, 0xb0, 0xd0, 0xca, 0x2b, 0xcb,
43 0xae, 0x7b, 0x30, 0xb4, 0x77, 0xcb, 0x2d, 0xa3, 0x80, 0x30,
44 0xf2, 0x0c, 0x6a, 0x42, 0xb7, 0x3b, 0xbe, 0xac, 0x01, 0xfa,
45};
46
Mohsin Kazmid6c15af2018-10-23 18:00:47 +020047static pci_device_id_t virtio_pci_device_ids[] = {
48 {
49 .vendor_id = PCI_VENDOR_ID_VIRTIO,
50 .device_id = PCI_DEVICE_ID_VIRTIO_NIC},
51 {
52 .vendor_id = PCI_VENDOR_ID_VIRTIO,
53 .device_id = PCI_DEVICE_ID_VIRTIO_NIC_MODERN},
54 {0},
55};
56
Mohsin Kazmid6c15af2018-10-23 18:00:47 +020057static u32
58virtio_pci_flag_change (vnet_main_t * vnm, vnet_hw_interface_t * hw,
59 u32 flags)
60{
61 return 0;
62}
63
64static clib_error_t *
65virtio_pci_get_max_virtqueue_pairs (vlib_main_t * vm, virtio_if_t * vif)
66{
Mohsin Kazmid6c15af2018-10-23 18:00:47 +020067 clib_error_t *error = 0;
68 u16 max_queue_pairs = 1;
69
70 if (vif->features & VIRTIO_FEATURE (VIRTIO_NET_F_MQ))
71 {
Mohsin Kazmia0a68332020-07-16 12:55:42 +000072 max_queue_pairs = vif->virtio_pci_func->get_max_queue_pairs (vm, vif);
Mohsin Kazmid6c15af2018-10-23 18:00:47 +020073 }
74
Damjan Marionf41244f2019-11-08 17:41:06 +010075 virtio_log_debug (vif, "max queue pair is %x", max_queue_pairs);
Mohsin Kazmid6c15af2018-10-23 18:00:47 +020076 if (max_queue_pairs < 1 || max_queue_pairs > 0x8000)
Mohsin Kazmi57d73212020-03-05 12:22:41 +000077 return clib_error_return (error, "max queue pair is %x,"
78 " should be in range [1, 0x8000]",
79 max_queue_pairs);
Mohsin Kazmid6c15af2018-10-23 18:00:47 +020080
81 vif->max_queue_pairs = max_queue_pairs;
82 return error;
83}
84
85static void
86virtio_pci_set_mac (vlib_main_t * vm, virtio_if_t * vif)
87{
Mohsin Kazmia0a68332020-07-16 12:55:42 +000088 if (vif->features & VIRTIO_FEATURE (VIRTIO_NET_F_MAC))
89 vif->virtio_pci_func->set_mac (vm, vif);
Mohsin Kazmid6c15af2018-10-23 18:00:47 +020090}
91
92static u32
93virtio_pci_get_mac (vlib_main_t * vm, virtio_if_t * vif)
94{
Mohsin Kazmi09a3bc52019-04-02 11:45:08 +000095 if (vif->features & VIRTIO_FEATURE (VIRTIO_NET_F_MAC))
Mohsin Kazmid6c15af2018-10-23 18:00:47 +020096 {
Mohsin Kazmia0a68332020-07-16 12:55:42 +000097 vif->virtio_pci_func->get_mac (vm, vif);
Mohsin Kazmid6c15af2018-10-23 18:00:47 +020098 return 0;
99 }
100 return 1;
101}
102
103static u16
104virtio_pci_is_link_up (vlib_main_t * vm, virtio_if_t * vif)
105{
106 /*
107 * Minimal driver: assumes link is up
108 */
109 u16 status = 1;
Mohsin Kazmi09a3bc52019-04-02 11:45:08 +0000110 if (vif->features & VIRTIO_FEATURE (VIRTIO_NET_F_STATUS))
Mohsin Kazmia0a68332020-07-16 12:55:42 +0000111 status = vif->virtio_pci_func->get_device_status (vm, vif);
Mohsin Kazmid6c15af2018-10-23 18:00:47 +0200112 return status;
113}
114
115static void
Mohsin Kazmi8046fdc2020-07-15 11:54:10 +0000116virtio_pci_irq_queue_handler (vlib_main_t * vm, vlib_pci_dev_handle_t h,
117 u16 line)
Mohsin Kazmid6c15af2018-10-23 18:00:47 +0200118{
119 vnet_main_t *vnm = vnet_get_main ();
Mohsin Kazmi33cc5cf2019-01-21 15:19:39 +0000120 virtio_main_t *vim = &virtio_main;
Mohsin Kazmid6c15af2018-10-23 18:00:47 +0200121 uword pd = vlib_pci_get_private_data (vm, h);
Mohsin Kazmi33cc5cf2019-01-21 15:19:39 +0000122 virtio_if_t *vif = pool_elt_at_index (vim->interfaces, pd);
Mohsin Kazmi8046fdc2020-07-15 11:54:10 +0000123 line--;
Mohsin Kazmid6c15af2018-10-23 18:00:47 +0200124 u16 qid = line;
125
Mohsin Kazmi0f8912f2022-02-01 18:35:59 +0000126 vnet_virtio_vring_t *vring = vec_elt_at_index (vif->rxq_vrings, qid);
Damjan Marion94100532020-11-06 23:25:57 +0100127 vnet_hw_if_rx_queue_set_int_pending (vnm, vring->queue_index);
Mohsin Kazmid6c15af2018-10-23 18:00:47 +0200128}
129
130static void
Mohsin Kazmi8046fdc2020-07-15 11:54:10 +0000131virtio_pci_irq_config_handler (vlib_main_t * vm, vlib_pci_dev_handle_t h,
132 u16 line)
Mohsin Kazmid6c15af2018-10-23 18:00:47 +0200133{
134 vnet_main_t *vnm = vnet_get_main ();
Mohsin Kazmi33cc5cf2019-01-21 15:19:39 +0000135 virtio_main_t *vim = &virtio_main;
Mohsin Kazmid6c15af2018-10-23 18:00:47 +0200136 uword pd = vlib_pci_get_private_data (vm, h);
Mohsin Kazmi33cc5cf2019-01-21 15:19:39 +0000137 virtio_if_t *vif = pool_elt_at_index (vim->interfaces, pd);
Mohsin Kazmid6c15af2018-10-23 18:00:47 +0200138
139 if (virtio_pci_is_link_up (vm, vif) & VIRTIO_NET_S_LINK_UP)
140 {
Mohsin Kazmid6c15af2018-10-23 18:00:47 +0200141 vnet_hw_interface_set_flags (vnm, vif->hw_if_index,
142 VNET_HW_INTERFACE_FLAG_LINK_UP);
143 }
144 else
145 {
Mohsin Kazmid6c15af2018-10-23 18:00:47 +0200146 vnet_hw_interface_set_flags (vnm, vif->hw_if_index, 0);
147 }
148}
149
150static void
151virtio_pci_irq_handler (vlib_main_t * vm, vlib_pci_dev_handle_t h)
152{
Mohsin Kazmi33cc5cf2019-01-21 15:19:39 +0000153 virtio_main_t *vim = &virtio_main;
Mohsin Kazmid6c15af2018-10-23 18:00:47 +0200154 uword pd = vlib_pci_get_private_data (vm, h);
Mohsin Kazmi33cc5cf2019-01-21 15:19:39 +0000155 virtio_if_t *vif = pool_elt_at_index (vim->interfaces, pd);
Mohsin Kazmid6c15af2018-10-23 18:00:47 +0200156 u8 isr = 0;
157 u16 line = 0;
158
Mohsin Kazmia0a68332020-07-16 12:55:42 +0000159 isr = vif->virtio_pci_func->get_isr (vm, vif);
Mohsin Kazmid6c15af2018-10-23 18:00:47 +0200160
161 /*
162 * If the lower bit is set: look through the used rings of
163 * all virtqueues for the device, to see if any progress has
164 * been made by the device which requires servicing.
165 */
166 if (isr & VIRTIO_PCI_ISR_INTR)
Mohsin Kazmi8046fdc2020-07-15 11:54:10 +0000167 {
168 for (; line < vif->num_rxqs; line++)
169 virtio_pci_irq_queue_handler (vm, h, (line + 1));
170 }
Mohsin Kazmid6c15af2018-10-23 18:00:47 +0200171
172 if (isr & VIRTIO_PCI_ISR_CONFIG)
Mohsin Kazmi8046fdc2020-07-15 11:54:10 +0000173 virtio_pci_irq_config_handler (vm, h, line);
Mohsin Kazmid6c15af2018-10-23 18:00:47 +0200174}
175
176inline void
177device_status (vlib_main_t * vm, virtio_if_t * vif)
178{
179 struct status_struct
180 {
181 u8 bit;
182 char *str;
183 };
184 struct status_struct *status_entry;
185 static struct status_struct status_array[] = {
186#define _(s,b) { .str = #s, .bit = b, },
187 foreach_virtio_config_status_flags
188#undef _
189 {.str = NULL}
190 };
191
192 vlib_cli_output (vm, " status 0x%x", vif->status);
193
194 status_entry = (struct status_struct *) &status_array;
195 while (status_entry->str)
196 {
197 if (vif->status & status_entry->bit)
198 vlib_cli_output (vm, " %s (%x)", status_entry->str,
199 status_entry->bit);
200 status_entry++;
201 }
202}
203
Mohsin Kazmi09a3bc52019-04-02 11:45:08 +0000204static int
Mohsin Kazmib977d3f2020-11-16 16:49:30 +0100205virtio_pci_send_ctrl_msg_packed (vlib_main_t * vm, virtio_if_t * vif,
206 virtio_ctrl_msg_t * data, u32 len)
207{
Mohsin Kazmi0f8912f2022-02-01 18:35:59 +0000208 vnet_virtio_vring_t *vring = vif->cxq_vring;
Mohsin Kazmib977d3f2020-11-16 16:49:30 +0100209 virtio_net_ctrl_ack_t status = VIRTIO_NET_ERR;
210 virtio_ctrl_msg_t result;
211 u32 buffer_index;
212 vlib_buffer_t *b;
213 u16 used, next;
Mohsin Kazmi0f8912f2022-02-01 18:35:59 +0000214 u16 sz = vring->queue_size;
Mohsin Kazmib977d3f2020-11-16 16:49:30 +0100215 u16 flags = 0, first_desc_flags = 0;
216
217 used = vring->desc_in_use;
218 next = vring->desc_next;
Mohsin Kazmi0f8912f2022-02-01 18:35:59 +0000219 vnet_virtio_vring_packed_desc_t *d = &vring->packed_desc[next];
Mohsin Kazmib977d3f2020-11-16 16:49:30 +0100220
221 if (vlib_buffer_alloc (vm, &buffer_index, 1))
222 b = vlib_get_buffer (vm, buffer_index);
223 else
224 return VIRTIO_NET_ERR;
225 /*
226 * current_data may not be initialized with 0 and may contain
227 * previous offset.
228 */
229 b->current_data = 0;
230 clib_memcpy (vlib_buffer_get_current (b), data, sizeof (virtio_ctrl_msg_t));
231
232 first_desc_flags = VRING_DESC_F_NEXT;
233 if (vring->avail_wrap_counter)
234 {
235 first_desc_flags |= VRING_DESC_F_AVAIL;
236 first_desc_flags &= ~VRING_DESC_F_USED;
237 }
238 else
239 {
240 first_desc_flags &= ~VRING_DESC_F_AVAIL;
241 first_desc_flags |= VRING_DESC_F_USED;
242 }
243 d->addr = vlib_buffer_get_current_pa (vm, b);
244 d->len = sizeof (virtio_net_ctrl_hdr_t);
245 d->id = next;
246
247 next++;
248 if (next >= sz)
249 {
250 next = 0;
251 vring->avail_wrap_counter ^= 1;
252 }
253 used++;
254
255 d = &vring->packed_desc[next];
256 flags = VRING_DESC_F_NEXT;
257 if (vring->avail_wrap_counter)
258 {
259 flags |= VRING_DESC_F_AVAIL;
260 flags &= ~VRING_DESC_F_USED;
261 }
262 else
263 {
264 flags &= ~VRING_DESC_F_AVAIL;
265 flags |= VRING_DESC_F_USED;
266 }
267 d->addr = vlib_buffer_get_current_pa (vm, b) +
268 STRUCT_OFFSET_OF (virtio_ctrl_msg_t, data);
269 d->len = len;
270 d->id = next;
271 d->flags = flags;
272
273 next++;
274 if (next >= sz)
275 {
276 next = 0;
277 vring->avail_wrap_counter ^= 1;
278 }
279 used++;
280
281 d = &vring->packed_desc[next];
282 flags = VRING_DESC_F_WRITE;
283 if (vring->avail_wrap_counter)
284 {
285 flags |= VRING_DESC_F_AVAIL;
286 flags &= ~VRING_DESC_F_USED;
287 }
288 else
289 {
290 flags &= ~VRING_DESC_F_AVAIL;
291 flags |= VRING_DESC_F_USED;
292 }
293 d->addr = vlib_buffer_get_current_pa (vm, b) +
294 STRUCT_OFFSET_OF (virtio_ctrl_msg_t, status);
295 d->len = sizeof (data->status);
296 d->id = next;
297 d->flags = flags;
298
299 next++;
300 if (next >= sz)
301 {
302 next = 0;
303 vring->avail_wrap_counter ^= 1;
304 }
305 used++;
306
307 CLIB_MEMORY_STORE_BARRIER ();
308 vring->packed_desc[vring->desc_next].flags = first_desc_flags;
309 vring->desc_next = next;
310 vring->desc_in_use = used;
311 CLIB_MEMORY_BARRIER ();
312 if (vring->device_event->flags != VRING_EVENT_F_DISABLE)
313 {
314 virtio_kick (vm, vring, vif);
315 }
316
317 u16 last = vring->last_used_idx;
318 d = &vring->packed_desc[last];
319 do
320 {
321 flags = d->flags;
322 }
323 while ((flags & VRING_DESC_F_AVAIL) != (vring->used_wrap_counter << 7)
324 || (flags & VRING_DESC_F_USED) != (vring->used_wrap_counter << 15));
325
326 last += 3;
Mohsin Kazmi0f8912f2022-02-01 18:35:59 +0000327 if (last >= vring->queue_size)
Mohsin Kazmib977d3f2020-11-16 16:49:30 +0100328 {
Mohsin Kazmi0f8912f2022-02-01 18:35:59 +0000329 last = last - vring->queue_size;
Mohsin Kazmib977d3f2020-11-16 16:49:30 +0100330 vring->used_wrap_counter ^= 1;
331 }
332 vring->desc_in_use -= 3;
333 vring->last_used_idx = last;
334
335 CLIB_MEMORY_BARRIER ();
336 clib_memcpy (&result, vlib_buffer_get_current (b),
337 sizeof (virtio_ctrl_msg_t));
338 virtio_log_debug (vif, "ctrl-queue: status %u", result.status);
339 status = result.status;
340 vlib_buffer_free (vm, &buffer_index, 1);
341 return status;
342}
343
344static int
345virtio_pci_send_ctrl_msg_split (vlib_main_t * vm, virtio_if_t * vif,
346 virtio_ctrl_msg_t * data, u32 len)
Mohsin Kazmi09a3bc52019-04-02 11:45:08 +0000347{
Mohsin Kazmi0f8912f2022-02-01 18:35:59 +0000348 vnet_virtio_vring_t *vring = vif->cxq_vring;
Mohsin Kazmia7a22812020-08-31 17:17:16 +0200349 virtio_net_ctrl_ack_t status = VIRTIO_NET_ERR;
350 virtio_ctrl_msg_t result;
Mohsin Kazmi09a3bc52019-04-02 11:45:08 +0000351 u32 buffer_index;
352 vlib_buffer_t *b;
353 u16 used, next, avail;
Mohsin Kazmi0f8912f2022-02-01 18:35:59 +0000354 u16 sz = vring->queue_size;
Mohsin Kazmi09a3bc52019-04-02 11:45:08 +0000355 u16 mask = sz - 1;
Mohsin Kazmi09a3bc52019-04-02 11:45:08 +0000356
357 used = vring->desc_in_use;
358 next = vring->desc_next;
359 avail = vring->avail->idx;
Mohsin Kazmi0f8912f2022-02-01 18:35:59 +0000360 vnet_virtio_vring_desc_t *d = &vring->desc[next];
Mohsin Kazmi09a3bc52019-04-02 11:45:08 +0000361
362 if (vlib_buffer_alloc (vm, &buffer_index, 1))
363 b = vlib_get_buffer (vm, buffer_index);
364 else
365 return VIRTIO_NET_ERR;
366 /*
367 * current_data may not be initialized with 0 and may contain
368 * previous offset.
369 */
370 b->current_data = 0;
Mohsin Kazmia7a22812020-08-31 17:17:16 +0200371 clib_memcpy (vlib_buffer_get_current (b), data, sizeof (virtio_ctrl_msg_t));
Mohsin Kazmi09a3bc52019-04-02 11:45:08 +0000372 d->flags = VRING_DESC_F_NEXT;
373 d->addr = vlib_buffer_get_current_pa (vm, b);
Mohsin Kazmia7a22812020-08-31 17:17:16 +0200374 d->len = sizeof (virtio_net_ctrl_hdr_t);
Mohsin Kazmi09a3bc52019-04-02 11:45:08 +0000375 vring->avail->ring[avail & mask] = next;
376 avail++;
377 next = (next + 1) & mask;
378 d->next = next;
379 used++;
380
381 d = &vring->desc[next];
382 d->flags = VRING_DESC_F_NEXT;
383 d->addr = vlib_buffer_get_current_pa (vm, b) +
Mohsin Kazmia7a22812020-08-31 17:17:16 +0200384 STRUCT_OFFSET_OF (virtio_ctrl_msg_t, data);
Mohsin Kazmi05493782019-05-01 14:26:17 +0200385 d->len = len;
Mohsin Kazmi09a3bc52019-04-02 11:45:08 +0000386 next = (next + 1) & mask;
387 d->next = next;
388 used++;
389
390 d = &vring->desc[next];
391 d->flags = VRING_DESC_F_WRITE;
392 d->addr = vlib_buffer_get_current_pa (vm, b) +
Mohsin Kazmia7a22812020-08-31 17:17:16 +0200393 STRUCT_OFFSET_OF (virtio_ctrl_msg_t, status);
Mohsin Kazmi05493782019-05-01 14:26:17 +0200394 d->len = sizeof (data->status);
Mohsin Kazmi09a3bc52019-04-02 11:45:08 +0000395 next = (next + 1) & mask;
396 used++;
397
398 CLIB_MEMORY_STORE_BARRIER ();
399 vring->avail->idx = avail;
400 vring->desc_next = next;
401 vring->desc_in_use = used;
402
403 if ((vring->used->flags & VIRTIO_RING_FLAG_MASK_INT) == 0)
404 {
405 virtio_kick (vm, vring, vif);
406 }
407
Mohsin Kazmi09a3bc52019-04-02 11:45:08 +0000408 u16 last = vring->last_used_idx, n_left = 0;
409 n_left = vring->used->idx - last;
410
411 while (n_left)
412 {
Mohsin Kazmi0f8912f2022-02-01 18:35:59 +0000413 vnet_virtio_vring_used_elem_t *e = &vring->used->ring[last & mask];
Mohsin Kazmi09a3bc52019-04-02 11:45:08 +0000414 u16 slot = e->id;
415
416 d = &vring->desc[slot];
417 while (d->flags & VRING_DESC_F_NEXT)
418 {
419 used--;
420 slot = d->next;
421 d = &vring->desc[slot];
422 }
423 used--;
424 last++;
425 n_left--;
426 }
427 vring->desc_in_use = used;
428 vring->last_used_idx = last;
429
430 CLIB_MEMORY_BARRIER ();
431 clib_memcpy (&result, vlib_buffer_get_current (b),
Mohsin Kazmia7a22812020-08-31 17:17:16 +0200432 sizeof (virtio_ctrl_msg_t));
Damjan Marionf41244f2019-11-08 17:41:06 +0100433 virtio_log_debug (vif, "ctrl-queue: status %u", result.status);
Mohsin Kazmi09a3bc52019-04-02 11:45:08 +0000434 status = result.status;
435 vlib_buffer_free (vm, &buffer_index, 1);
436 return status;
437}
438
Mohsin Kazmi05493782019-05-01 14:26:17 +0200439static int
Mohsin Kazmib977d3f2020-11-16 16:49:30 +0100440virtio_pci_send_ctrl_msg (vlib_main_t * vm, virtio_if_t * vif,
441 virtio_ctrl_msg_t * data, u32 len)
442{
443 if (vif->is_packed)
444 return virtio_pci_send_ctrl_msg_packed (vm, vif, data, len);
445 else
446 return virtio_pci_send_ctrl_msg_split (vm, vif, data, len);
447}
448
449static int
Mohsin Kazmi6d4af892020-01-03 15:11:53 +0000450virtio_pci_disable_offload (vlib_main_t * vm, virtio_if_t * vif)
451{
Mohsin Kazmia7a22812020-08-31 17:17:16 +0200452 virtio_ctrl_msg_t offload_hdr;
453 virtio_net_ctrl_ack_t status = VIRTIO_NET_ERR;
Mohsin Kazmi6d4af892020-01-03 15:11:53 +0000454
455 offload_hdr.ctrl.class = VIRTIO_NET_CTRL_GUEST_OFFLOADS;
456 offload_hdr.ctrl.cmd = VIRTIO_NET_CTRL_GUEST_OFFLOADS_SET;
457 offload_hdr.status = VIRTIO_NET_ERR;
458 u64 offloads = 0ULL;
459 clib_memcpy (offload_hdr.data, &offloads, sizeof (offloads));
460
461 status =
462 virtio_pci_send_ctrl_msg (vm, vif, &offload_hdr, sizeof (offloads));
463 virtio_log_debug (vif, "disable offloads");
Mohsin Kazmia0a68332020-07-16 12:55:42 +0000464 vif->remote_features = vif->virtio_pci_func->get_device_features (vm, vif);
465 vif->virtio_pci_func->get_driver_features (vm, vif);
Mohsin Kazmi6d4af892020-01-03 15:11:53 +0000466 return status;
467}
468
469static int
470virtio_pci_enable_checksum_offload (vlib_main_t * vm, virtio_if_t * vif)
471{
Mohsin Kazmia7a22812020-08-31 17:17:16 +0200472 virtio_ctrl_msg_t csum_offload_hdr;
473 virtio_net_ctrl_ack_t status = VIRTIO_NET_ERR;
Mohsin Kazmi6d4af892020-01-03 15:11:53 +0000474
475 csum_offload_hdr.ctrl.class = VIRTIO_NET_CTRL_GUEST_OFFLOADS;
476 csum_offload_hdr.ctrl.cmd = VIRTIO_NET_CTRL_GUEST_OFFLOADS_SET;
477 csum_offload_hdr.status = VIRTIO_NET_ERR;
478 u64 offloads = 0ULL;
479 offloads |= VIRTIO_FEATURE (VIRTIO_NET_F_GUEST_CSUM);
480 clib_memcpy (csum_offload_hdr.data, &offloads, sizeof (offloads));
481
482 status =
483 virtio_pci_send_ctrl_msg (vm, vif, &csum_offload_hdr, sizeof (offloads));
484 virtio_log_debug (vif, "enable checksum offload");
Mohsin Kazmia0a68332020-07-16 12:55:42 +0000485 vif->remote_features = vif->virtio_pci_func->get_device_features (vm, vif);
486 vif->features = vif->virtio_pci_func->get_driver_features (vm, vif);
Mohsin Kazmi6d4af892020-01-03 15:11:53 +0000487 return status;
488}
489
490static int
Mohsin Kazmibbd6b742019-05-02 13:54:59 +0200491virtio_pci_enable_gso (vlib_main_t * vm, virtio_if_t * vif)
492{
Mohsin Kazmia7a22812020-08-31 17:17:16 +0200493 virtio_ctrl_msg_t gso_hdr;
494 virtio_net_ctrl_ack_t status = VIRTIO_NET_ERR;
Mohsin Kazmibbd6b742019-05-02 13:54:59 +0200495
496 gso_hdr.ctrl.class = VIRTIO_NET_CTRL_GUEST_OFFLOADS;
497 gso_hdr.ctrl.cmd = VIRTIO_NET_CTRL_GUEST_OFFLOADS_SET;
498 gso_hdr.status = VIRTIO_NET_ERR;
499 u64 offloads = VIRTIO_FEATURE (VIRTIO_NET_F_GUEST_CSUM)
500 | VIRTIO_FEATURE (VIRTIO_NET_F_GUEST_TSO4)
Mohsin Kazmi6d4af892020-01-03 15:11:53 +0000501 | VIRTIO_FEATURE (VIRTIO_NET_F_GUEST_TSO6);
Mohsin Kazmibbd6b742019-05-02 13:54:59 +0200502 clib_memcpy (gso_hdr.data, &offloads, sizeof (offloads));
503
504 status = virtio_pci_send_ctrl_msg (vm, vif, &gso_hdr, sizeof (offloads));
Damjan Marionf41244f2019-11-08 17:41:06 +0100505 virtio_log_debug (vif, "enable gso");
Mohsin Kazmia0a68332020-07-16 12:55:42 +0000506 vif->remote_features = vif->virtio_pci_func->get_device_features (vm, vif);
507 vif->virtio_pci_func->get_driver_features (vm, vif);
Mohsin Kazmibbd6b742019-05-02 13:54:59 +0200508 return status;
509}
510
511static int
Mohsin Kazmi6d4af892020-01-03 15:11:53 +0000512virtio_pci_offloads (vlib_main_t * vm, virtio_if_t * vif, int gso_enabled,
513 int csum_offload_enabled)
514{
515 vnet_main_t *vnm = vnet_get_main ();
Damjan Marionc48ec5d2022-01-10 19:38:57 +0000516 vnet_hw_if_caps_change_t cc = {};
Mohsin Kazmi6d4af892020-01-03 15:11:53 +0000517
518 if ((vif->features & VIRTIO_FEATURE (VIRTIO_NET_F_CTRL_VQ)) &&
519 (vif->features & VIRTIO_FEATURE (VIRTIO_NET_F_CTRL_GUEST_OFFLOADS)))
520 {
521 if (gso_enabled
522 && (vif->features & (VIRTIO_FEATURE (VIRTIO_NET_F_HOST_TSO4) |
523 VIRTIO_FEATURE (VIRTIO_NET_F_HOST_TSO6))))
524 {
525 if (virtio_pci_enable_gso (vm, vif))
526 {
527 virtio_log_warning (vif, "gso is not enabled");
528 }
529 else
530 {
531 vif->gso_enabled = 1;
Damjan Marionc48ec5d2022-01-10 19:38:57 +0000532 vif->csum_offload_enabled = 1;
533 cc.val = cc.mask = VNET_HW_IF_CAP_TCP_GSO |
534 VNET_HW_IF_CAP_TX_TCP_CKSUM |
535 VNET_HW_IF_CAP_TX_UDP_CKSUM;
Mohsin Kazmi6d4af892020-01-03 15:11:53 +0000536 }
537 }
538 else if (csum_offload_enabled
539 && (vif->features & VIRTIO_FEATURE (VIRTIO_NET_F_CSUM)))
540 {
541 if (virtio_pci_enable_checksum_offload (vm, vif))
542 {
543 virtio_log_warning (vif, "checksum offload is not enabled");
544 }
545 else
546 {
547 vif->csum_offload_enabled = 1;
548 vif->gso_enabled = 0;
Damjan Marionc48ec5d2022-01-10 19:38:57 +0000549 cc.val =
Damjan Mariond4f88cc2022-01-05 01:52:38 +0100550 VNET_HW_IF_CAP_TX_TCP_CKSUM | VNET_HW_IF_CAP_TX_UDP_CKSUM;
Damjan Marionc48ec5d2022-01-10 19:38:57 +0000551 cc.mask = VNET_HW_IF_CAP_TCP_GSO | VNET_HW_IF_CAP_TX_TCP_CKSUM |
552 VNET_HW_IF_CAP_TX_UDP_CKSUM;
Mohsin Kazmi6d4af892020-01-03 15:11:53 +0000553 }
554 }
555 else
556 {
557 if (virtio_pci_disable_offload (vm, vif))
558 {
559 virtio_log_warning (vif, "offloads are not disabled");
560 }
561 else
562 {
563 vif->csum_offload_enabled = 0;
564 vif->gso_enabled = 0;
Damjan Marionc48ec5d2022-01-10 19:38:57 +0000565 cc.val = 0;
566 cc.mask = VNET_HW_IF_CAP_L4_TX_CKSUM | VNET_HW_IF_CAP_TCP_GSO;
Mohsin Kazmi6d4af892020-01-03 15:11:53 +0000567 }
568 }
569 }
570
Damjan Marionc48ec5d2022-01-10 19:38:57 +0000571 if (cc.mask)
572 vnet_hw_if_change_caps (vnm, vif->hw_if_index, &cc);
573
Mohsin Kazmi6d4af892020-01-03 15:11:53 +0000574 return 0;
575}
576
577static int
Mohsin Kazmi05493782019-05-01 14:26:17 +0200578virtio_pci_enable_multiqueue (vlib_main_t * vm, virtio_if_t * vif,
579 u16 num_queues)
580{
Mohsin Kazmia7a22812020-08-31 17:17:16 +0200581 virtio_ctrl_msg_t mq_hdr;
582 virtio_net_ctrl_ack_t status = VIRTIO_NET_ERR;
Mohsin Kazmi05493782019-05-01 14:26:17 +0200583
584 mq_hdr.ctrl.class = VIRTIO_NET_CTRL_MQ;
585 mq_hdr.ctrl.cmd = VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET;
586 mq_hdr.status = VIRTIO_NET_ERR;
587 clib_memcpy (mq_hdr.data, &num_queues, sizeof (num_queues));
588
589 status = virtio_pci_send_ctrl_msg (vm, vif, &mq_hdr, sizeof (num_queues));
Damjan Marionf41244f2019-11-08 17:41:06 +0100590 virtio_log_debug (vif, "multi-queue enable %u queues", num_queues);
Mohsin Kazmi05493782019-05-01 14:26:17 +0200591 return status;
592}
593
Steven Luonge9bc3322023-12-14 08:54:55 -0800594static int
595virtio_pci_enable_multiqueue_rss (vlib_main_t *vm, virtio_if_t *vif,
596 u16 num_queues)
597{
598 virtio_ctrl_msg_t mq_hdr;
599 virtio_net_rss_config *rss = (virtio_net_rss_config *) mq_hdr.data;
600 virtio_net_ctrl_ack_t status = VIRTIO_NET_ERR;
601
602 STATIC_ASSERT (sizeof (*rss) <= sizeof (mq_hdr.data),
603 "virtio_net_rss_config size too big");
604 mq_hdr.ctrl.class = VIRTIO_NET_CTRL_MQ;
605 mq_hdr.ctrl.cmd = VIRTIO_NET_CTRL_MQ_RSS_CONFIG;
606 mq_hdr.status = VIRTIO_NET_ERR;
607
608 rss->hash_types = VIRTIO_NET_HASH_TYPE_SUPPORTED;
609 rss->indirection_table_mask = VIRTIO_NET_RSS_MAX_TABLE_LEN - 1;
610 rss->unclassified_queue = 0;
611 for (int i = 0; i < VIRTIO_NET_RSS_MAX_TABLE_LEN; i++)
612 rss->indirection_table[i] = i % num_queues;
613 rss->max_tx_vq = num_queues;
614 rss->hash_key_length = VIRTIO_NET_RSS_MAX_KEY_SIZE;
615 clib_memcpy (rss->hash_key_data, virtio_rss_key,
616 VIRTIO_NET_RSS_MAX_KEY_SIZE);
617
618 status = virtio_pci_send_ctrl_msg (vm, vif, &mq_hdr, sizeof (*rss));
619 virtio_log_debug (vif, "multi-queue with rss enable %u queues", num_queues);
620 return status;
621}
622
Mohsin Kazmid6c15af2018-10-23 18:00:47 +0200623static u8
624virtio_pci_queue_size_valid (u16 qsz)
625{
626 if (qsz < 64 || qsz > 4096)
627 return 0;
628 if ((qsz % 64) != 0)
629 return 0;
630 return 1;
631}
632
633clib_error_t *
Mohsin Kazmib977d3f2020-11-16 16:49:30 +0100634virtio_pci_control_vring_packed_init (vlib_main_t * vm, virtio_if_t * vif,
635 u16 queue_num)
636{
637 clib_error_t *error = 0;
638 u16 queue_size = 0;
Mohsin Kazmi0f8912f2022-02-01 18:35:59 +0000639 vnet_virtio_vring_t *vring;
Mohsin Kazmib977d3f2020-11-16 16:49:30 +0100640 u32 i = 0;
641 void *ptr = NULL;
642
643 queue_size = vif->virtio_pci_func->get_queue_size (vm, vif, queue_num);
644
645 if (queue_size > 32768)
646 return clib_error_return (0, "ring size must be 32768 or lower");
647
648 if (queue_size == 0)
649 queue_size = 256;
650
651 vec_validate_aligned (vif->cxq_vring, 0, CLIB_CACHE_LINE_BYTES);
652 vring = vec_elt_at_index (vif->cxq_vring, 0);
653
Mohsin Kazmi0f8912f2022-02-01 18:35:59 +0000654 i = (((queue_size * sizeof (vnet_virtio_vring_packed_desc_t)) +
655 sizeof (vnet_virtio_vring_desc_event_t) + VNET_VIRTIO_PCI_VRING_ALIGN -
656 1) &
657 ~(VNET_VIRTIO_PCI_VRING_ALIGN - 1)) +
658 sizeof (vnet_virtio_vring_desc_event_t);
Mohsin Kazmib977d3f2020-11-16 16:49:30 +0100659
Mohsin Kazmi0f8912f2022-02-01 18:35:59 +0000660 ptr = vlib_physmem_alloc_aligned_on_numa (vm, i, VNET_VIRTIO_PCI_VRING_ALIGN,
661 vif->numa_node);
Mohsin Kazmib977d3f2020-11-16 16:49:30 +0100662 if (!ptr)
663 return vlib_physmem_last_error (vm);
664 clib_memset (ptr, 0, i);
665
666 vring->packed_desc = ptr;
667
Mohsin Kazmi0f8912f2022-02-01 18:35:59 +0000668 vring->driver_event =
669 ptr + (queue_size * sizeof (vnet_virtio_vring_packed_desc_t));
Mohsin Kazmib977d3f2020-11-16 16:49:30 +0100670 vring->driver_event->off_wrap = 0;
671 vring->driver_event->flags = VRING_EVENT_F_DISABLE;
672
673 vring->device_event =
Mohsin Kazmi0f8912f2022-02-01 18:35:59 +0000674 ptr + (((queue_size * sizeof (vnet_virtio_vring_packed_desc_t)) +
675 sizeof (vnet_virtio_vring_desc_event_t) +
676 VNET_VIRTIO_PCI_VRING_ALIGN - 1) &
677 ~(VNET_VIRTIO_PCI_VRING_ALIGN - 1));
Mohsin Kazmib977d3f2020-11-16 16:49:30 +0100678 vring->device_event->off_wrap = 0;
679 vring->device_event->flags = 0;
680
Mohsin Kazmidd0144a2022-09-14 11:25:54 +0000681 vring->total_packets = 0;
Mohsin Kazmib977d3f2020-11-16 16:49:30 +0100682 vring->queue_id = queue_num;
Mohsin Kazmi0f8912f2022-02-01 18:35:59 +0000683 vring->queue_size = queue_size;
Mohsin Kazmib977d3f2020-11-16 16:49:30 +0100684 vring->avail_wrap_counter = 1;
685 vring->used_wrap_counter = 1;
686
687 ASSERT (vring->buffers == 0);
688
689 virtio_log_debug (vif, "control-queue: number %u, size %u", queue_num,
690 queue_size);
Mohsin Kazmi0f8912f2022-02-01 18:35:59 +0000691 vif->virtio_pci_func->setup_queue (vm, vif, queue_num, vring);
Mohsin Kazmib977d3f2020-11-16 16:49:30 +0100692 vring->queue_notify_offset =
693 vif->notify_off_multiplier *
694 vif->virtio_pci_func->get_queue_notify_off (vm, vif, queue_num);
695 virtio_log_debug (vif, "queue-notify-offset: number %u, offset %u",
696 queue_num, vring->queue_notify_offset);
697 return error;
698}
699
700clib_error_t *
701virtio_pci_control_vring_split_init (vlib_main_t * vm, virtio_if_t * vif,
702 u16 queue_num)
Mohsin Kazmid6c15af2018-10-23 18:00:47 +0200703{
704 clib_error_t *error = 0;
705 u16 queue_size = 0;
Mohsin Kazmi0f8912f2022-02-01 18:35:59 +0000706 vnet_virtio_vring_t *vring;
Mohsin Kazmid6c15af2018-10-23 18:00:47 +0200707 u32 i = 0;
Mohsin Kazmi09a3bc52019-04-02 11:45:08 +0000708 void *ptr = NULL;
Mohsin Kazmid6c15af2018-10-23 18:00:47 +0200709
Mohsin Kazmia0a68332020-07-16 12:55:42 +0000710 queue_size = vif->virtio_pci_func->get_queue_size (vm, vif, queue_num);
Mohsin Kazmid6c15af2018-10-23 18:00:47 +0200711 if (!virtio_pci_queue_size_valid (queue_size))
712 clib_warning ("queue size is not valid");
713
714 if (!is_pow2 (queue_size))
715 return clib_error_return (0, "ring size must be power of 2");
716
717 if (queue_size > 32768)
718 return clib_error_return (0, "ring size must be 32768 or lower");
719
720 if (queue_size == 0)
721 queue_size = 256;
722
Mohsin Kazmi09a3bc52019-04-02 11:45:08 +0000723 vec_validate_aligned (vif->cxq_vring, 0, CLIB_CACHE_LINE_BYTES);
724 vring = vec_elt_at_index (vif->cxq_vring, 0);
Mohsin Kazmi0f8912f2022-02-01 18:35:59 +0000725 i = vnet_virtio_vring_size (queue_size, VNET_VIRTIO_PCI_VRING_ALIGN);
726 i = round_pow2 (i, VNET_VIRTIO_PCI_VRING_ALIGN);
727 ptr = vlib_physmem_alloc_aligned_on_numa (vm, i, VNET_VIRTIO_PCI_VRING_ALIGN,
728 vif->numa_node);
Mohsin Kazmi09a3bc52019-04-02 11:45:08 +0000729 if (!ptr)
730 return vlib_physmem_last_error (vm);
731 clib_memset (ptr, 0, i);
Mohsin Kazmi0f8912f2022-02-01 18:35:59 +0000732 vnet_virtio_vring_init (vring, queue_size, ptr, VNET_VIRTIO_PCI_VRING_ALIGN);
Mohsin Kazmi09a3bc52019-04-02 11:45:08 +0000733 vring->queue_id = queue_num;
Mohsin Kazmidd0144a2022-09-14 11:25:54 +0000734 vring->total_packets = 0;
Mohsin Kazmi09a3bc52019-04-02 11:45:08 +0000735
736 ASSERT (vring->buffers == 0);
Damjan Marionf41244f2019-11-08 17:41:06 +0100737 virtio_log_debug (vif, "control-queue: number %u, size %u", queue_num,
Mohsin Kazmi09a3bc52019-04-02 11:45:08 +0000738 queue_size);
Mohsin Kazmi0f8912f2022-02-01 18:35:59 +0000739 vif->virtio_pci_func->setup_queue (vm, vif, queue_num, vring);
Mohsin Kazmi162a2962020-09-29 10:01:25 +0000740 vring->queue_notify_offset =
741 vif->notify_off_multiplier *
742 vif->virtio_pci_func->get_queue_notify_off (vm, vif, queue_num);
743 virtio_log_debug (vif, "queue-notify-offset: number %u, offset %u",
744 queue_num, vring->queue_notify_offset);
Mohsin Kazmi09a3bc52019-04-02 11:45:08 +0000745
746 return error;
747}
748
749clib_error_t *
Mohsin Kazmib977d3f2020-11-16 16:49:30 +0100750virtio_pci_control_vring_init (vlib_main_t * vm, virtio_if_t * vif,
751 u16 queue_num)
752{
753 if (vif->is_packed)
754 return virtio_pci_control_vring_packed_init (vm, vif, queue_num);
755 else
756 return virtio_pci_control_vring_split_init (vm, vif, queue_num);
757}
758
759clib_error_t *
Mohsin Kazmia181eaa2023-08-29 09:18:20 +0000760virtio_pci_vring_split_init (vlib_main_t *vm, virtio_if_t *vif, u16 queue_num,
761 u16 txq_size)
Mohsin Kazmi09a3bc52019-04-02 11:45:08 +0000762{
763 clib_error_t *error = 0;
Mohsin Kazmi09a3bc52019-04-02 11:45:08 +0000764 u16 queue_size = 0;
Mohsin Kazmi0f8912f2022-02-01 18:35:59 +0000765 vnet_virtio_vring_t *vring;
Mohsin Kazmi09a3bc52019-04-02 11:45:08 +0000766 u32 i = 0;
767 void *ptr = NULL;
768
Mohsin Kazmia0a68332020-07-16 12:55:42 +0000769 queue_size = vif->virtio_pci_func->get_queue_size (vm, vif, queue_num);
Mohsin Kazmi09a3bc52019-04-02 11:45:08 +0000770 if (!virtio_pci_queue_size_valid (queue_size))
771 clib_warning ("queue size is not valid");
772
773 if (!is_pow2 (queue_size))
774 return clib_error_return (0, "ring size must be power of 2");
775
776 if (queue_size > 32768)
777 return clib_error_return (0, "ring size must be 32768 or lower");
778
779 if (queue_size == 0)
780 queue_size = 256;
781
782 if (queue_num % 2)
783 {
Mohsin Kazmia181eaa2023-08-29 09:18:20 +0000784 if (txq_size)
785 {
786 virtio_log_debug (vif, "tx-queue: number %u, default-size %u",
787 queue_num, queue_size);
788 vif->virtio_pci_func->set_queue_size (vm, vif, queue_num, txq_size);
789 queue_size =
790 vif->virtio_pci_func->get_queue_size (vm, vif, queue_num);
791 virtio_log_debug (vif, "tx-queue: number %u, new size %u", queue_num,
792 queue_size);
793 }
Mohsin Kazmi09a3bc52019-04-02 11:45:08 +0000794 vec_validate_aligned (vif->txq_vrings, TX_QUEUE_ACCESS (queue_num),
795 CLIB_CACHE_LINE_BYTES);
796 vring = vec_elt_at_index (vif->txq_vrings, TX_QUEUE_ACCESS (queue_num));
Mohsin Kazmib7e4e6d2021-12-13 18:32:42 +0000797 clib_spinlock_init (&vring->lockp);
Mohsin Kazmi09a3bc52019-04-02 11:45:08 +0000798 }
799 else
800 {
801 vec_validate_aligned (vif->rxq_vrings, RX_QUEUE_ACCESS (queue_num),
802 CLIB_CACHE_LINE_BYTES);
803 vring = vec_elt_at_index (vif->rxq_vrings, RX_QUEUE_ACCESS (queue_num));
804 }
Mohsin Kazmi0f8912f2022-02-01 18:35:59 +0000805 i = vnet_virtio_vring_size (queue_size, VNET_VIRTIO_PCI_VRING_ALIGN);
806 i = round_pow2 (i, VNET_VIRTIO_PCI_VRING_ALIGN);
807 ptr = vlib_physmem_alloc_aligned_on_numa (vm, i, VNET_VIRTIO_PCI_VRING_ALIGN,
808 vif->numa_node);
Mohsin Kazmi09a3bc52019-04-02 11:45:08 +0000809 if (!ptr)
810 return vlib_physmem_last_error (vm);
811 clib_memset (ptr, 0, i);
Mohsin Kazmi0f8912f2022-02-01 18:35:59 +0000812 vnet_virtio_vring_init (vring, queue_size, ptr, VNET_VIRTIO_PCI_VRING_ALIGN);
Mohsin Kazmi09a3bc52019-04-02 11:45:08 +0000813 vring->queue_id = queue_num;
Mohsin Kazmid6c15af2018-10-23 18:00:47 +0200814 vring->avail->flags = VIRTIO_RING_FLAG_MASK_INT;
Mohsin Kazmi9e2a7852020-08-13 18:57:26 +0200815 vring->flow_table = 0;
Mohsin Kazmidd0144a2022-09-14 11:25:54 +0000816 vring->total_packets = 0;
Mohsin Kazmid6c15af2018-10-23 18:00:47 +0200817
818 ASSERT (vring->buffers == 0);
819 vec_validate_aligned (vring->buffers, queue_size, CLIB_CACHE_LINE_BYTES);
Mohsin Kazmi09a3bc52019-04-02 11:45:08 +0000820 if (queue_num % 2)
Mohsin Kazmid6c15af2018-10-23 18:00:47 +0200821 {
Damjan Marionf41244f2019-11-08 17:41:06 +0100822 virtio_log_debug (vif, "tx-queue: number %u, size %u", queue_num,
Mohsin Kazmi09a3bc52019-04-02 11:45:08 +0000823 queue_size);
Mohsin Kazmi7f6d1452020-02-27 11:49:21 +0100824 clib_memset_u32 (vring->buffers, ~0, queue_size);
Mohsin Kazmid6c15af2018-10-23 18:00:47 +0200825 }
826 else
Mohsin Kazmi09a3bc52019-04-02 11:45:08 +0000827 {
Damjan Marionf41244f2019-11-08 17:41:06 +0100828 virtio_log_debug (vif, "rx-queue: number %u, size %u", queue_num,
Mohsin Kazmi09a3bc52019-04-02 11:45:08 +0000829 queue_size);
830 }
Mohsin Kazmi0f8912f2022-02-01 18:35:59 +0000831 vring->queue_size = queue_size;
832 if (vif->virtio_pci_func->setup_queue (vm, vif, queue_num, vring))
Mohsin Kazmi43b512c2019-04-30 17:25:26 +0200833 return clib_error_return (0, "error in queue address setup");
Mohsin Kazmid6c15af2018-10-23 18:00:47 +0200834
Mohsin Kazmi162a2962020-09-29 10:01:25 +0000835 vring->queue_notify_offset =
836 vif->notify_off_multiplier *
837 vif->virtio_pci_func->get_queue_notify_off (vm, vif, queue_num);
838 virtio_log_debug (vif, "queue-notify-offset: number %u, offset %u",
839 queue_num, vring->queue_notify_offset);
Mohsin Kazmid6c15af2018-10-23 18:00:47 +0200840 return error;
841}
842
Mohsin Kazmib977d3f2020-11-16 16:49:30 +0100843clib_error_t *
844virtio_pci_vring_packed_init (vlib_main_t * vm, virtio_if_t * vif,
845 u16 queue_num)
846{
Mohsin Kazmib977d3f2020-11-16 16:49:30 +0100847 clib_error_t *error = 0;
848 u16 queue_size = 0;
Mohsin Kazmi0f8912f2022-02-01 18:35:59 +0000849 vnet_virtio_vring_t *vring;
Mohsin Kazmib977d3f2020-11-16 16:49:30 +0100850 u32 i = 0;
851 void *ptr = NULL;
852
853 queue_size = vif->virtio_pci_func->get_queue_size (vm, vif, queue_num);
854
855 if (queue_size > 32768)
856 return clib_error_return (0, "ring size must be 32768 or lower");
857
858 if (queue_size == 0)
859 queue_size = 256;
860
861 if (queue_num % 2)
862 {
863 vec_validate_aligned (vif->txq_vrings, TX_QUEUE_ACCESS (queue_num),
864 CLIB_CACHE_LINE_BYTES);
865 vring = vec_elt_at_index (vif->txq_vrings, TX_QUEUE_ACCESS (queue_num));
Mohsin Kazmib7e4e6d2021-12-13 18:32:42 +0000866 clib_spinlock_init (&vring->lockp);
Mohsin Kazmib977d3f2020-11-16 16:49:30 +0100867 }
868 else
869 {
870 vec_validate_aligned (vif->rxq_vrings, RX_QUEUE_ACCESS (queue_num),
871 CLIB_CACHE_LINE_BYTES);
872 vring = vec_elt_at_index (vif->rxq_vrings, RX_QUEUE_ACCESS (queue_num));
873 }
874
Mohsin Kazmi0f8912f2022-02-01 18:35:59 +0000875 i = (((queue_size * sizeof (vnet_virtio_vring_packed_desc_t)) +
876 sizeof (vnet_virtio_vring_desc_event_t) + VNET_VIRTIO_PCI_VRING_ALIGN -
877 1) &
878 ~(VNET_VIRTIO_PCI_VRING_ALIGN - 1)) +
879 sizeof (vnet_virtio_vring_desc_event_t);
Mohsin Kazmib977d3f2020-11-16 16:49:30 +0100880
Mohsin Kazmi0f8912f2022-02-01 18:35:59 +0000881 ptr = vlib_physmem_alloc_aligned_on_numa (vm, i, VNET_VIRTIO_PCI_VRING_ALIGN,
882 vif->numa_node);
Mohsin Kazmib977d3f2020-11-16 16:49:30 +0100883 if (!ptr)
884 return vlib_physmem_last_error (vm);
885
886 clib_memset (ptr, 0, i);
887 vring->packed_desc = ptr;
888
Mohsin Kazmi0f8912f2022-02-01 18:35:59 +0000889 vring->driver_event =
890 ptr + (queue_size * sizeof (vnet_virtio_vring_packed_desc_t));
Mohsin Kazmib977d3f2020-11-16 16:49:30 +0100891 vring->driver_event->off_wrap = 0;
892 vring->driver_event->flags = VRING_EVENT_F_DISABLE;
893
894 vring->device_event =
Mohsin Kazmi0f8912f2022-02-01 18:35:59 +0000895 ptr + (((queue_size * sizeof (vnet_virtio_vring_packed_desc_t)) +
896 sizeof (vnet_virtio_vring_desc_event_t) +
897 VNET_VIRTIO_PCI_VRING_ALIGN - 1) &
898 ~(VNET_VIRTIO_PCI_VRING_ALIGN - 1));
Mohsin Kazmib977d3f2020-11-16 16:49:30 +0100899 vring->device_event->off_wrap = 0;
900 vring->device_event->flags = 0;
901
902 vring->queue_id = queue_num;
903
904 vring->avail_wrap_counter = 1;
905 vring->used_wrap_counter = 1;
Mohsin Kazmidd0144a2022-09-14 11:25:54 +0000906 vring->total_packets = 0;
Mohsin Kazmib977d3f2020-11-16 16:49:30 +0100907
908 ASSERT (vring->buffers == 0);
909 vec_validate_aligned (vring->buffers, queue_size, CLIB_CACHE_LINE_BYTES);
910 if (queue_num % 2)
911 {
912 virtio_log_debug (vif, "tx-queue: number %u, size %u", queue_num,
913 queue_size);
914 clib_memset_u32 (vring->buffers, ~0, queue_size);
915 }
916 else
917 {
918 virtio_log_debug (vif, "rx-queue: number %u, size %u", queue_num,
919 queue_size);
920 }
Mohsin Kazmi0f8912f2022-02-01 18:35:59 +0000921 vring->queue_size = queue_size;
922 if (vif->virtio_pci_func->setup_queue (vm, vif, queue_num, vring))
Mohsin Kazmib977d3f2020-11-16 16:49:30 +0100923 return clib_error_return (0, "error in queue address setup");
924
925 vring->queue_notify_offset =
926 vif->notify_off_multiplier *
927 vif->virtio_pci_func->get_queue_notify_off (vm, vif, queue_num);
928 virtio_log_debug (vif, "queue-notify-offset: number %u, offset %u",
929 queue_num, vring->queue_notify_offset);
930
931 return error;
932}
933
934clib_error_t *
Mohsin Kazmia181eaa2023-08-29 09:18:20 +0000935virtio_pci_vring_init (vlib_main_t *vm, virtio_if_t *vif, u16 queue_num,
936 u16 txq_size)
Mohsin Kazmib977d3f2020-11-16 16:49:30 +0100937{
938 if (vif->is_packed)
939 return virtio_pci_vring_packed_init (vm, vif, queue_num);
940 else
Mohsin Kazmia181eaa2023-08-29 09:18:20 +0000941 return virtio_pci_vring_split_init (vm, vif, queue_num, txq_size);
Mohsin Kazmib977d3f2020-11-16 16:49:30 +0100942}
943
Mohsin Kazmid6c15af2018-10-23 18:00:47 +0200944static void
945virtio_negotiate_features (vlib_main_t * vm, virtio_if_t * vif,
946 u64 req_features)
947{
948 /*
949 * if features are not requested
950 * default: all supported features
951 */
Mohsin Kazmibbd6b742019-05-02 13:54:59 +0200952 u64 supported_features = VIRTIO_FEATURE (VIRTIO_NET_F_CSUM)
953 | VIRTIO_FEATURE (VIRTIO_NET_F_GUEST_CSUM)
954 | VIRTIO_FEATURE (VIRTIO_NET_F_CTRL_GUEST_OFFLOADS)
955 | VIRTIO_FEATURE (VIRTIO_NET_F_MTU)
Mohsin Kazmid6c15af2018-10-23 18:00:47 +0200956 | VIRTIO_FEATURE (VIRTIO_NET_F_MAC)
Mohsin Kazmibbd6b742019-05-02 13:54:59 +0200957 | VIRTIO_FEATURE (VIRTIO_NET_F_GSO)
958 | VIRTIO_FEATURE (VIRTIO_NET_F_GUEST_TSO4)
959 | VIRTIO_FEATURE (VIRTIO_NET_F_GUEST_TSO6)
960 | VIRTIO_FEATURE (VIRTIO_NET_F_GUEST_UFO)
961 | VIRTIO_FEATURE (VIRTIO_NET_F_HOST_TSO4)
962 | VIRTIO_FEATURE (VIRTIO_NET_F_HOST_TSO6)
963 | VIRTIO_FEATURE (VIRTIO_NET_F_HOST_UFO)
Mohsin Kazmid6c15af2018-10-23 18:00:47 +0200964 | VIRTIO_FEATURE (VIRTIO_NET_F_MRG_RXBUF)
965 | VIRTIO_FEATURE (VIRTIO_NET_F_STATUS)
Mohsin Kazmi09a3bc52019-04-02 11:45:08 +0000966 | VIRTIO_FEATURE (VIRTIO_NET_F_CTRL_VQ)
967 | VIRTIO_FEATURE (VIRTIO_NET_F_MQ)
Mohsin Kazmib74fe322019-01-31 13:50:56 +0000968 | VIRTIO_FEATURE (VIRTIO_F_NOTIFY_ON_EMPTY)
Mohsin Kazmid6c15af2018-10-23 18:00:47 +0200969 | VIRTIO_FEATURE (VIRTIO_F_ANY_LAYOUT)
970 | VIRTIO_FEATURE (VIRTIO_RING_F_INDIRECT_DESC);
971
Steven Luonge9bc3322023-12-14 08:54:55 -0800972 if (vif->rss_enabled)
973 supported_features |= VIRTIO_FEATURE (VIRTIO_NET_F_RSS);
974
Mohsin Kazmi379aac32020-08-20 10:25:12 +0200975 if (vif->is_modern)
976 supported_features |= VIRTIO_FEATURE (VIRTIO_F_VERSION_1);
977
Mohsin Kazmib977d3f2020-11-16 16:49:30 +0100978 if (vif->is_packed)
979 {
980 supported_features |=
981 (VIRTIO_FEATURE (VIRTIO_F_RING_PACKED) |
982 VIRTIO_FEATURE (VIRTIO_F_IN_ORDER));
983 }
984
Mohsin Kazmid6c15af2018-10-23 18:00:47 +0200985 if (req_features == 0)
986 {
987 req_features = supported_features;
988 }
989
990 vif->features = req_features & vif->remote_features & supported_features;
991
Mohsin Kazmi09a3bc52019-04-02 11:45:08 +0000992 if (vif->features & VIRTIO_FEATURE (VIRTIO_NET_F_MTU))
Mohsin Kazmid6c15af2018-10-23 18:00:47 +0200993 {
Mohsin Kazmia0a68332020-07-16 12:55:42 +0000994 u16 mtu = 0;
995 mtu = vif->virtio_pci_func->get_mtu (vm, vif);
996
997 if (mtu < 64)
Mohsin Kazmid6c15af2018-10-23 18:00:47 +0200998 vif->features &= ~VIRTIO_FEATURE (VIRTIO_NET_F_MTU);
999 }
1000
Mohsin Kazmib977d3f2020-11-16 16:49:30 +01001001 if ((vif->features & (VIRTIO_FEATURE (VIRTIO_F_RING_PACKED))) == 0)
1002 vif->is_packed = 0;
1003
Mohsin Kazmia0a68332020-07-16 12:55:42 +00001004 vif->virtio_pci_func->set_driver_features (vm, vif, vif->features);
1005 vif->features = vif->virtio_pci_func->get_driver_features (vm, vif);
Mohsin Kazmid6c15af2018-10-23 18:00:47 +02001006}
1007
1008void
1009virtio_pci_read_device_feature (vlib_main_t * vm, virtio_if_t * vif)
1010{
Mohsin Kazmia0a68332020-07-16 12:55:42 +00001011 vif->remote_features = vif->virtio_pci_func->get_device_features (vm, vif);
Mohsin Kazmid6c15af2018-10-23 18:00:47 +02001012}
1013
1014int
1015virtio_pci_reset_device (vlib_main_t * vm, virtio_if_t * vif)
1016{
1017 u8 status = 0;
1018
1019 /*
1020 * Reset the device
1021 */
Mohsin Kazmia0a68332020-07-16 12:55:42 +00001022 status = vif->virtio_pci_func->device_reset (vm, vif);
Mohsin Kazmid6c15af2018-10-23 18:00:47 +02001023
1024 /*
1025 * Set the Acknowledge status bit
1026 */
Mohsin Kazmia0a68332020-07-16 12:55:42 +00001027 vif->virtio_pci_func->set_status (vm, vif, VIRTIO_CONFIG_STATUS_ACK);
Mohsin Kazmid6c15af2018-10-23 18:00:47 +02001028
1029 /*
1030 * Set the Driver status bit
1031 */
Mohsin Kazmia0a68332020-07-16 12:55:42 +00001032 vif->virtio_pci_func->set_status (vm, vif, VIRTIO_CONFIG_STATUS_DRIVER);
Mohsin Kazmid6c15af2018-10-23 18:00:47 +02001033
1034 /*
1035 * Read the status and verify it
1036 */
Mohsin Kazmia0a68332020-07-16 12:55:42 +00001037 status = vif->virtio_pci_func->get_status (vm, vif);
Mohsin Kazmi379aac32020-08-20 10:25:12 +02001038 if ((status & VIRTIO_CONFIG_STATUS_ACK)
1039 && (status & VIRTIO_CONFIG_STATUS_DRIVER))
1040 vif->status = status;
1041 else
Mohsin Kazmid6c15af2018-10-23 18:00:47 +02001042 return -1;
Mohsin Kazmid6c15af2018-10-23 18:00:47 +02001043
1044 return 0;
1045}
1046
1047clib_error_t *
Mohsin Kazmi379aac32020-08-20 10:25:12 +02001048virtio_pci_read_caps (vlib_main_t * vm, virtio_if_t * vif, void **bar)
Mohsin Kazmid6c15af2018-10-23 18:00:47 +02001049{
1050 clib_error_t *error = 0;
Mohsin Kazmia7a22812020-08-31 17:17:16 +02001051 virtio_pci_cap_t cap;
Mohsin Kazmi379aac32020-08-20 10:25:12 +02001052 u8 pos, common_cfg = 0, notify = 0, dev_cfg = 0, isr = 0, pci_cfg = 0;
Mohsin Kazmid6c15af2018-10-23 18:00:47 +02001053 vlib_pci_dev_handle_t h = vif->pci_dev_handle;
1054
1055 if ((error = vlib_pci_read_config_u8 (vm, h, PCI_CAPABILITY_LIST, &pos)))
Mohsin Kazmib74fe322019-01-31 13:50:56 +00001056 {
Damjan Marionf41244f2019-11-08 17:41:06 +01001057 virtio_log_error (vif, "error in reading capabilty list position");
Mohsin Kazmic96e64b2020-09-01 17:12:50 +02001058 return clib_error_return (error,
1059 "error in reading capabilty list position");
Mohsin Kazmib74fe322019-01-31 13:50:56 +00001060 }
Mohsin Kazmid6c15af2018-10-23 18:00:47 +02001061 while (pos)
1062 {
1063 if ((error =
1064 vlib_pci_read_write_config (vm, h, VLIB_READ, pos, &cap,
1065 sizeof (cap))))
Mohsin Kazmib74fe322019-01-31 13:50:56 +00001066 {
Damjan Marionf41244f2019-11-08 17:41:06 +01001067 virtio_log_error (vif, "%s [%2x]",
Mohsin Kazmib74fe322019-01-31 13:50:56 +00001068 "error in reading the capability at", pos);
Mohsin Kazmic96e64b2020-09-01 17:12:50 +02001069 return clib_error_return (error,
1070 "error in reading the capability at [%2x]",
1071 pos);
Mohsin Kazmib74fe322019-01-31 13:50:56 +00001072 }
Mohsin Kazmid6c15af2018-10-23 18:00:47 +02001073
1074 if (cap.cap_vndr == PCI_CAP_ID_MSIX)
1075 {
Mohsin Kazmib74fe322019-01-31 13:50:56 +00001076 u16 flags, table_size, table_size_mask = 0x07FF;
1077
Mohsin Kazmid6c15af2018-10-23 18:00:47 +02001078 if ((error =
1079 vlib_pci_read_write_config (vm, h, VLIB_READ, pos + 2, &flags,
1080 sizeof (flags))))
Mohsin Kazmic96e64b2020-09-01 17:12:50 +02001081 return clib_error_return (error,
1082 "error in reading the capability at [%2x]",
1083 pos + 2);
Mohsin Kazmid6c15af2018-10-23 18:00:47 +02001084
Mohsin Kazmib74fe322019-01-31 13:50:56 +00001085 table_size = flags & table_size_mask;
Damjan Marionf41244f2019-11-08 17:41:06 +01001086 virtio_log_debug (vif, "flags:0x%x %s 0x%x", flags,
Mohsin Kazmib74fe322019-01-31 13:50:56 +00001087 "msix interrupt vector table-size", table_size);
1088
Mohsin Kazmid6c15af2018-10-23 18:00:47 +02001089 if (flags & PCI_MSIX_ENABLE)
Mohsin Kazmib74fe322019-01-31 13:50:56 +00001090 {
Damjan Marionf41244f2019-11-08 17:41:06 +01001091 virtio_log_debug (vif, "msix interrupt enabled");
Mohsin Kazmib74fe322019-01-31 13:50:56 +00001092 vif->msix_enabled = VIRTIO_MSIX_ENABLED;
Mohsin Kazmi8046fdc2020-07-15 11:54:10 +00001093 vif->msix_table_size = table_size;
Mohsin Kazmib74fe322019-01-31 13:50:56 +00001094 }
Mohsin Kazmid6c15af2018-10-23 18:00:47 +02001095 else
Mohsin Kazmib74fe322019-01-31 13:50:56 +00001096 {
Damjan Marionf41244f2019-11-08 17:41:06 +01001097 virtio_log_debug (vif, "msix interrupt disabled");
Mohsin Kazmib74fe322019-01-31 13:50:56 +00001098 vif->msix_enabled = VIRTIO_MSIX_DISABLED;
Mohsin Kazmi8046fdc2020-07-15 11:54:10 +00001099 vif->msix_table_size = 0;
Mohsin Kazmib74fe322019-01-31 13:50:56 +00001100 }
Mohsin Kazmid6c15af2018-10-23 18:00:47 +02001101 }
1102
1103 if (cap.cap_vndr != PCI_CAP_ID_VNDR)
1104 {
Damjan Marionf41244f2019-11-08 17:41:06 +01001105 virtio_log_debug (vif, "[%2x] %s %2x ", pos,
Mohsin Kazmi33cc5cf2019-01-21 15:19:39 +00001106 "skipping non VNDR cap id:", cap.cap_vndr);
Mohsin Kazmid6c15af2018-10-23 18:00:47 +02001107 goto next;
1108 }
1109
Damjan Marionf41244f2019-11-08 17:41:06 +01001110 virtio_log_debug (vif,
Mohsin Kazmib74fe322019-01-31 13:50:56 +00001111 "[%4x] cfg type: %u, bar: %u, offset: %04x, len: %u",
1112 pos, cap.cfg_type, cap.bar, cap.offset, cap.length);
Mohsin Kazmi379aac32020-08-20 10:25:12 +02001113
Mohsin Kazmi0a507d72020-09-01 18:18:48 +02001114 if (cap.bar >= 0 && cap.bar <= 5)
Mohsin Kazmi133c91c12020-08-20 17:18:56 +02001115 {
1116 vif->bar = bar[cap.bar];
1117 vif->bar_id = cap.bar;
1118 }
1119 else
1120 return clib_error_return (error, "invalid bar %u", cap.bar);
Mohsin Kazmi379aac32020-08-20 10:25:12 +02001121
Mohsin Kazmid6c15af2018-10-23 18:00:47 +02001122 switch (cap.cfg_type)
1123 {
1124 case VIRTIO_PCI_CAP_COMMON_CFG:
Mohsin Kazmi379aac32020-08-20 10:25:12 +02001125 vif->common_offset = cap.offset;
Mohsin Kazmid6c15af2018-10-23 18:00:47 +02001126 common_cfg = 1;
1127 break;
1128 case VIRTIO_PCI_CAP_NOTIFY_CFG:
Mohsin Kazmi379aac32020-08-20 10:25:12 +02001129 if ((error =
1130 vlib_pci_read_write_config (vm, h, VLIB_READ,
1131 pos + sizeof (cap),
1132 &vif->notify_off_multiplier,
1133 sizeof
1134 (vif->notify_off_multiplier))))
1135 {
1136 virtio_log_error (vif, "notify off multiplier is not given");
1137 }
1138 else
1139 {
1140 virtio_log_debug (vif, "notify off multiplier is %u",
1141 vif->notify_off_multiplier);
1142 vif->notify_offset = cap.offset;
1143 notify = 1;
1144 }
Mohsin Kazmid6c15af2018-10-23 18:00:47 +02001145 break;
1146 case VIRTIO_PCI_CAP_DEVICE_CFG:
Mohsin Kazmi379aac32020-08-20 10:25:12 +02001147 vif->device_offset = cap.offset;
Mohsin Kazmid6c15af2018-10-23 18:00:47 +02001148 dev_cfg = 1;
1149 break;
1150 case VIRTIO_PCI_CAP_ISR_CFG:
Mohsin Kazmi379aac32020-08-20 10:25:12 +02001151 vif->isr_offset = cap.offset;
Mohsin Kazmid6c15af2018-10-23 18:00:47 +02001152 isr = 1;
1153 break;
Mohsin Kazmi22c0ece2019-01-28 19:30:21 +00001154 case VIRTIO_PCI_CAP_PCI_CFG:
1155 if (cap.bar == 0)
1156 pci_cfg = 1;
1157 break;
Mohsin Kazmid6c15af2018-10-23 18:00:47 +02001158 }
1159 next:
1160 pos = cap.cap_next;
1161 }
1162
Mohsin Kazmi379aac32020-08-20 10:25:12 +02001163 if (common_cfg == 0 || notify == 0 || dev_cfg == 0 || isr == 0)
Mohsin Kazmid6c15af2018-10-23 18:00:47 +02001164 {
Mohsin Kazmi379aac32020-08-20 10:25:12 +02001165 vif->virtio_pci_func = &virtio_pci_legacy_func;
Mohsin Kazmi162a2962020-09-29 10:01:25 +00001166 vif->notify_off_multiplier = 0;
Damjan Marionf41244f2019-11-08 17:41:06 +01001167 virtio_log_debug (vif, "legacy virtio pci device found");
Mohsin Kazmid6c15af2018-10-23 18:00:47 +02001168 return error;
1169 }
1170
Mohsin Kazmi379aac32020-08-20 10:25:12 +02001171 vif->is_modern = 1;
1172 vif->virtio_pci_func = &virtio_pci_modern_func;
1173
Mohsin Kazmi0e2bc632019-01-30 13:36:57 +00001174 if (!pci_cfg)
Mohsin Kazmi162a2962020-09-29 10:01:25 +00001175 {
1176 virtio_log_debug (vif, "modern virtio pci device found");
1177 }
1178 else
1179 {
1180 virtio_log_debug (vif, "transitional virtio pci device found");
1181 }
Mohsin Kazmi0e2bc632019-01-30 13:36:57 +00001182
Mohsin Kazmi33cc5cf2019-01-21 15:19:39 +00001183 return error;
Mohsin Kazmid6c15af2018-10-23 18:00:47 +02001184}
1185
1186static clib_error_t *
1187virtio_pci_device_init (vlib_main_t * vm, virtio_if_t * vif,
Mohsin Kazmi379aac32020-08-20 10:25:12 +02001188 virtio_pci_create_if_args_t * args, void **bar)
Mohsin Kazmid6c15af2018-10-23 18:00:47 +02001189{
1190 clib_error_t *error = 0;
1191 u8 status = 0;
1192
Mohsin Kazmi379aac32020-08-20 10:25:12 +02001193 if ((error = virtio_pci_read_caps (vm, vif, bar)))
Mohsin Kazmi57d73212020-03-05 12:22:41 +00001194 {
1195 args->rv = VNET_API_ERROR_UNSUPPORTED;
1196 virtio_log_error (vif, "Device is not supported");
Mohsin Kazmic96e64b2020-09-01 17:12:50 +02001197 return clib_error_return (error, "Device is not supported");
Mohsin Kazmi57d73212020-03-05 12:22:41 +00001198 }
Mohsin Kazmid6c15af2018-10-23 18:00:47 +02001199
1200 if (virtio_pci_reset_device (vm, vif) < 0)
Mohsin Kazmib74fe322019-01-31 13:50:56 +00001201 {
Mohsin Kazmi57d73212020-03-05 12:22:41 +00001202 args->rv = VNET_API_ERROR_INIT_FAILED;
Damjan Marionf41244f2019-11-08 17:41:06 +01001203 virtio_log_error (vif, "Failed to reset the device");
Mohsin Kazmic96e64b2020-09-01 17:12:50 +02001204 return clib_error_return (error, "Failed to reset the device");
Mohsin Kazmib74fe322019-01-31 13:50:56 +00001205 }
Mohsin Kazmid6c15af2018-10-23 18:00:47 +02001206 /*
1207 * read device features and negotiate (user) requested features
1208 */
1209 virtio_pci_read_device_feature (vm, vif);
Mohsin Kazmice215992020-04-10 14:57:06 +00001210 if ((vif->remote_features & VIRTIO_FEATURE (VIRTIO_RING_F_INDIRECT_DESC)) ==
1211 0)
1212 {
1213 virtio_log_warning (vif, "error encountered: vhost-net backend doesn't "
1214 "support VIRTIO_RING_F_INDIRECT_DESC features");
1215 }
1216 if ((vif->remote_features & VIRTIO_FEATURE (VIRTIO_NET_F_MRG_RXBUF)) == 0)
1217 {
1218 virtio_log_warning (vif, "error encountered: vhost-net backend doesn't "
1219 "support VIRTIO_NET_F_MRG_RXBUF features");
1220 }
Mohsin Kazmid6c15af2018-10-23 18:00:47 +02001221 virtio_negotiate_features (vm, vif, args->features);
1222
1223 /*
1224 * After FEATURE_OK, driver should not accept new feature bits
1225 */
Mohsin Kazmia0a68332020-07-16 12:55:42 +00001226 vif->virtio_pci_func->set_status (vm, vif,
1227 VIRTIO_CONFIG_STATUS_FEATURES_OK);
1228 status = vif->virtio_pci_func->get_status (vm, vif);
Mohsin Kazmid6c15af2018-10-23 18:00:47 +02001229 if (!(status & VIRTIO_CONFIG_STATUS_FEATURES_OK))
Mohsin Kazmib74fe322019-01-31 13:50:56 +00001230 {
Mohsin Kazmi57d73212020-03-05 12:22:41 +00001231 args->rv = VNET_API_ERROR_UNSUPPORTED;
Damjan Marionf41244f2019-11-08 17:41:06 +01001232 virtio_log_error (vif,
Mohsin Kazmib74fe322019-01-31 13:50:56 +00001233 "error encountered: Device doesn't support requested features");
Mohsin Kazmic96e64b2020-09-01 17:12:50 +02001234 return clib_error_return (error,
1235 "Device doesn't support requested features");
Mohsin Kazmib74fe322019-01-31 13:50:56 +00001236 }
Mohsin Kazmid6c15af2018-10-23 18:00:47 +02001237 vif->status = status;
1238
Mohsin Kazmi09a3bc52019-04-02 11:45:08 +00001239 /*
1240 * get or set the mac address
1241 */
Mohsin Kazmid6c15af2018-10-23 18:00:47 +02001242 if (virtio_pci_get_mac (vm, vif))
1243 {
1244 f64 now = vlib_time_now (vm);
1245 u32 rnd;
1246 rnd = (u32) (now * 1e6);
1247 rnd = random_u32 (&rnd);
1248
1249 memcpy (vif->mac_addr + 2, &rnd, sizeof (rnd));
1250 vif->mac_addr[0] = 2;
1251 vif->mac_addr[1] = 0xfe;
1252 virtio_pci_set_mac (vm, vif);
1253 }
1254
1255 virtio_set_net_hdr_size (vif);
1256
Mohsin Kazmi09a3bc52019-04-02 11:45:08 +00001257 /*
1258 * Initialize the virtqueues
1259 */
Mohsin Kazmid6c15af2018-10-23 18:00:47 +02001260 if ((error = virtio_pci_get_max_virtqueue_pairs (vm, vif)))
Mohsin Kazmi57d73212020-03-05 12:22:41 +00001261 {
1262 args->rv = VNET_API_ERROR_EXCEEDED_NUMBER_OF_RANGES_CAPACITY;
1263 goto err;
1264 }
Mohsin Kazmid6c15af2018-10-23 18:00:47 +02001265
Mohsin Kazmi8046fdc2020-07-15 11:54:10 +00001266 if (vif->msix_enabled == VIRTIO_MSIX_ENABLED)
1267 {
1268 if (vif->msix_table_size <= vif->max_queue_pairs)
1269 {
1270 virtio_log_error (vif,
1271 "error MSIX lines (%u) <= Number of RXQs (%u)",
1272 vif->msix_table_size, vif->max_queue_pairs);
1273 return clib_error_return (error,
1274 "error MSIX lines (%u) <= Number of RXQs (%u)",
1275 vif->msix_table_size,
1276 vif->max_queue_pairs);
1277 }
1278 }
1279
Mohsin Kazmi09a3bc52019-04-02 11:45:08 +00001280 for (int i = 0; i < vif->max_queue_pairs; i++)
1281 {
Mohsin Kazmia181eaa2023-08-29 09:18:20 +00001282 if ((error = virtio_pci_vring_init (vm, vif, RX_QUEUE (i), 0)))
Mohsin Kazmi43b512c2019-04-30 17:25:26 +02001283 {
Mohsin Kazmi57d73212020-03-05 12:22:41 +00001284 args->rv = VNET_API_ERROR_INIT_FAILED;
1285 virtio_log_error (vif, "%s (%u) %s", "error in rxq-queue",
1286 RX_QUEUE (i), "initialization");
Mohsin Kazmia0a68332020-07-16 12:55:42 +00001287 error =
1288 clib_error_return (error, "%s (%u) %s", "error in rxq-queue",
1289 RX_QUEUE (i), "initialization");
1290 goto err;
Mohsin Kazmi43b512c2019-04-30 17:25:26 +02001291 }
1292 else
1293 {
1294 vif->num_rxqs++;
1295 }
Mohsin Kazmid6c15af2018-10-23 18:00:47 +02001296
Mohsin Kazmia181eaa2023-08-29 09:18:20 +00001297 if ((error = virtio_pci_vring_init (vm, vif, TX_QUEUE (i),
1298 args->tx_queue_size)))
Mohsin Kazmi43b512c2019-04-30 17:25:26 +02001299 {
Mohsin Kazmi57d73212020-03-05 12:22:41 +00001300 args->rv = VNET_API_ERROR_INIT_FAILED;
1301 virtio_log_error (vif, "%s (%u) %s", "error in txq-queue",
1302 TX_QUEUE (i), "initialization");
Mohsin Kazmia0a68332020-07-16 12:55:42 +00001303 error =
1304 clib_error_return (error, "%s (%u) %s", "error in txq-queue",
1305 TX_QUEUE (i), "initialization");
1306 goto err;
Mohsin Kazmi43b512c2019-04-30 17:25:26 +02001307 }
1308 else
1309 {
1310 vif->num_txqs++;
1311 }
Mohsin Kazmi09a3bc52019-04-02 11:45:08 +00001312 }
Mohsin Kazmid6c15af2018-10-23 18:00:47 +02001313
Mohsin Kazmi09a3bc52019-04-02 11:45:08 +00001314 if (vif->features & VIRTIO_FEATURE (VIRTIO_NET_F_CTRL_VQ))
1315 {
1316 if ((error =
1317 virtio_pci_control_vring_init (vm, vif, vif->max_queue_pairs * 2)))
1318 {
Damjan Marionf41244f2019-11-08 17:41:06 +01001319 virtio_log_warning (vif, "%s (%u) %s", "error in control-queue",
Mohsin Kazmi09a3bc52019-04-02 11:45:08 +00001320 vif->max_queue_pairs * 2, "initialization");
1321 if (vif->features & VIRTIO_FEATURE (VIRTIO_NET_F_MQ))
1322 vif->features &= ~VIRTIO_FEATURE (VIRTIO_NET_F_MQ);
1323 }
1324 }
1325 else
1326 {
Damjan Marionf41244f2019-11-08 17:41:06 +01001327 virtio_log_debug (vif, "control queue is not available");
Mohsin Kazmi09a3bc52019-04-02 11:45:08 +00001328 vif->cxq_vring = NULL;
1329 }
1330
1331 /*
1332 * set the msix interrupts
1333 */
Mohsin Kazmib74fe322019-01-31 13:50:56 +00001334 if (vif->msix_enabled == VIRTIO_MSIX_ENABLED)
Mohsin Kazmid6c15af2018-10-23 18:00:47 +02001335 {
Mohsin Kazmi8046fdc2020-07-15 11:54:10 +00001336 int i, j;
Mohsin Kazmia0a68332020-07-16 12:55:42 +00001337 if (vif->virtio_pci_func->set_config_irq (vm, vif, 0) ==
Mohsin Kazmib74fe322019-01-31 13:50:56 +00001338 VIRTIO_MSI_NO_VECTOR)
Mohsin Kazmi8046fdc2020-07-15 11:54:10 +00001339 {
1340 virtio_log_warning (vif, "config vector 0 is not set");
1341 }
1342 else
1343 {
1344 virtio_log_debug (vif, "config msix vector is set at 0");
1345 }
1346 for (i = 0, j = 1; i < vif->max_queue_pairs; i++, j++)
1347 {
Mohsin Kazmia0a68332020-07-16 12:55:42 +00001348 if (vif->virtio_pci_func->set_queue_irq (vm, vif, j,
1349 RX_QUEUE (i)) ==
Mohsin Kazmi8046fdc2020-07-15 11:54:10 +00001350 VIRTIO_MSI_NO_VECTOR)
1351 {
1352 virtio_log_warning (vif, "queue (%u) vector is not set at %u",
1353 RX_QUEUE (i), j);
1354 }
1355 else
1356 {
1357 virtio_log_debug (vif, "%s (%u) %s %u", "queue",
1358 RX_QUEUE (i), "msix vector is set at", j);
1359 }
1360 }
Mohsin Kazmid6c15af2018-10-23 18:00:47 +02001361 }
Mohsin Kazmi09a3bc52019-04-02 11:45:08 +00001362
1363 /*
1364 * set the driver status OK
1365 */
Mohsin Kazmia0a68332020-07-16 12:55:42 +00001366 vif->virtio_pci_func->set_status (vm, vif, VIRTIO_CONFIG_STATUS_DRIVER_OK);
1367 vif->status = vif->virtio_pci_func->get_status (vm, vif);
Mohsin Kazmi46f877e2019-04-08 10:36:18 +02001368err:
Mohsin Kazmid6c15af2018-10-23 18:00:47 +02001369 return error;
1370}
1371
1372void
1373virtio_pci_create_if (vlib_main_t * vm, virtio_pci_create_if_args_t * args)
1374{
1375 vnet_main_t *vnm = vnet_get_main ();
Mohsin Kazmi33cc5cf2019-01-21 15:19:39 +00001376 virtio_main_t *vim = &virtio_main;
Mohsin Kazmid6c15af2018-10-23 18:00:47 +02001377 virtio_if_t *vif;
1378 vlib_pci_dev_handle_t h;
1379 clib_error_t *error = 0;
Mohsin Kazmi8046fdc2020-07-15 11:54:10 +00001380 u32 interrupt_count = 0;
Mohsin Kazmid6c15af2018-10-23 18:00:47 +02001381
Damjan Marionb2c31b62020-12-13 21:47:40 +01001382 pool_foreach (vif, vim->interfaces) {
Mohsin Kazmid6c15af2018-10-23 18:00:47 +02001383 if (vif->pci_addr.as_u32 == args->addr)
1384 {
Mohsin Kazmi57d73212020-03-05 12:22:41 +00001385 args->rv = VNET_API_ERROR_ADDRESS_IN_USE;
Mohsin Kazmid6c15af2018-10-23 18:00:47 +02001386 args->error =
1387 clib_error_return (error, "PCI address in use");
Mohsin Kazmi33cc5cf2019-01-21 15:19:39 +00001388 vlib_log (VLIB_LOG_LEVEL_ERR, vim->log_default, "%U: %s",
1389 format_vlib_pci_addr, &args->addr,
1390 " PCI address in use");
Mohsin Kazmid6c15af2018-10-23 18:00:47 +02001391 return;
1392 }
Damjan Marionb2c31b62020-12-13 21:47:40 +01001393 }
Mohsin Kazmid6c15af2018-10-23 18:00:47 +02001394
Benoît Gannec04d8c42022-10-13 14:01:03 +02001395 if (args->bind)
1396 {
1397 vlib_pci_addr_t pci = { .as_u32 = args->addr };
1398 error = vlib_pci_bind_to_uio (vm, &pci, (char *) "auto",
1399 VIRTIO_BIND_FORCE == args->bind);
1400 if (error)
1401 {
1402 args->rv = VNET_API_ERROR_INVALID_INTERFACE;
1403 args->error =
1404 clib_error_return (error, "%U: %s", format_vlib_pci_addr, &pci,
1405 "error encountered on binding pci device");
1406 vlib_log (VLIB_LOG_LEVEL_ERR, vim->log_default, "%U: %s",
1407 format_vlib_pci_addr, &pci,
1408 "error encountered on binding pci devicee");
1409 return;
1410 }
1411 }
1412
Mohsin Kazmi33cc5cf2019-01-21 15:19:39 +00001413 pool_get (vim->interfaces, vif);
1414 vif->dev_instance = vif - vim->interfaces;
Mohsin Kazmid6c15af2018-10-23 18:00:47 +02001415 vif->per_interface_next_index = ~0;
1416 vif->pci_addr.as_u32 = args->addr;
Steven Luonge9bc3322023-12-14 08:54:55 -08001417 vif->rss_enabled = args->rss_enabled;
Mohsin Kazmib977d3f2020-11-16 16:49:30 +01001418 if (args->virtio_flags & VIRTIO_FLAG_PACKED)
1419 vif->is_packed = 1;
Mohsin Kazmid6c15af2018-10-23 18:00:47 +02001420
Mohsin Kazmid6c15af2018-10-23 18:00:47 +02001421 if ((error =
1422 vlib_pci_device_open (vm, (vlib_pci_addr_t *) & vif->pci_addr,
1423 virtio_pci_device_ids, &h)))
1424 {
Mohsin Kazmid6c15af2018-10-23 18:00:47 +02001425 args->rv = VNET_API_ERROR_INVALID_INTERFACE;
1426 args->error =
1427 clib_error_return (error, "pci-addr %U", format_vlib_pci_addr,
1428 &vif->pci_addr);
Mohsin Kazmi33cc5cf2019-01-21 15:19:39 +00001429 vlib_log (VLIB_LOG_LEVEL_ERR, vim->log_default, "%U: %s",
1430 format_vlib_pci_addr, &vif->pci_addr,
1431 "error encountered on pci device open");
Benoît Ganne8f011832019-11-20 14:32:38 +01001432 pool_put (vim->interfaces, vif);
Mohsin Kazmid6c15af2018-10-23 18:00:47 +02001433 return;
1434 }
1435 vif->pci_dev_handle = h;
1436 vlib_pci_set_private_data (vm, h, vif->dev_instance);
Mohsin Kazmi09a3bc52019-04-02 11:45:08 +00001437 vif->numa_node = vlib_pci_get_numa_node (vm, h);
Damjan Marionf41244f2019-11-08 17:41:06 +01001438 vif->type = VIRTIO_IF_TYPE_PCI;
Mohsin Kazmid6c15af2018-10-23 18:00:47 +02001439
1440 if ((error = vlib_pci_bus_master_enable (vm, h)))
Mohsin Kazmi33cc5cf2019-01-21 15:19:39 +00001441 {
Damjan Marionf41244f2019-11-08 17:41:06 +01001442 virtio_log_error (vif, "error encountered on pci bus master enable");
Mohsin Kazmi33cc5cf2019-01-21 15:19:39 +00001443 goto error;
1444 }
Mohsin Kazmid6c15af2018-10-23 18:00:47 +02001445
Mohsin Kazmi379aac32020-08-20 10:25:12 +02001446 void *bar[6];
1447 for (u32 i = 0; i <= 5; i++)
1448 {
1449
1450 if ((error = vlib_pci_map_region (vm, h, i, &bar[i])))
1451 {
1452 virtio_log_debug (vif, "no pci map region for bar %u", i);
1453 }
1454 else
1455 {
1456 virtio_log_debug (vif, "pci map region for bar %u at %p", i,
1457 bar[i]);
1458 }
1459 }
1460
Mohsin Kazmid6c15af2018-10-23 18:00:47 +02001461 if ((error = vlib_pci_io_region (vm, h, 0)))
Mohsin Kazmi33cc5cf2019-01-21 15:19:39 +00001462 {
Damjan Marionf41244f2019-11-08 17:41:06 +01001463 virtio_log_error (vif, "error encountered on pci io region");
Mohsin Kazmi33cc5cf2019-01-21 15:19:39 +00001464 goto error;
1465 }
Mohsin Kazmid6c15af2018-10-23 18:00:47 +02001466
Mohsin Kazmi8046fdc2020-07-15 11:54:10 +00001467 interrupt_count = vlib_pci_get_num_msix_interrupts (vm, h);
1468 if (interrupt_count > 1)
Mohsin Kazmid6c15af2018-10-23 18:00:47 +02001469 {
1470 if ((error = vlib_pci_register_msix_handler (vm, h, 0, 1,
Mohsin Kazmi8046fdc2020-07-15 11:54:10 +00001471 &virtio_pci_irq_config_handler)))
Mohsin Kazmi33cc5cf2019-01-21 15:19:39 +00001472 {
Mohsin Kazmi57d73212020-03-05 12:22:41 +00001473 args->rv = VNET_API_ERROR_INVALID_REGISTRATION;
Damjan Marionf41244f2019-11-08 17:41:06 +01001474 virtio_log_error (vif,
Mohsin Kazmi33cc5cf2019-01-21 15:19:39 +00001475 "error encountered on pci register msix handler 0");
1476 goto error;
1477 }
Mohsin Kazmi8046fdc2020-07-15 11:54:10 +00001478
1479 if ((error =
1480 vlib_pci_register_msix_handler (vm, h, 1, (interrupt_count - 1),
1481 &virtio_pci_irq_queue_handler)))
Mohsin Kazmi33cc5cf2019-01-21 15:19:39 +00001482 {
Mohsin Kazmi57d73212020-03-05 12:22:41 +00001483 args->rv = VNET_API_ERROR_INVALID_REGISTRATION;
Damjan Marionf41244f2019-11-08 17:41:06 +01001484 virtio_log_error (vif,
Mohsin Kazmi33cc5cf2019-01-21 15:19:39 +00001485 "error encountered on pci register msix handler 1");
1486 goto error;
1487 }
Mohsin Kazmid6c15af2018-10-23 18:00:47 +02001488
Mohsin Kazmi8046fdc2020-07-15 11:54:10 +00001489 if ((error = vlib_pci_enable_msix_irq (vm, h, 0, interrupt_count)))
Mohsin Kazmi33cc5cf2019-01-21 15:19:39 +00001490 {
Damjan Marionf41244f2019-11-08 17:41:06 +01001491 virtio_log_error (vif, "error encountered on pci enable msix irq");
Mohsin Kazmi33cc5cf2019-01-21 15:19:39 +00001492 goto error;
1493 }
Mohsin Kazmib74fe322019-01-31 13:50:56 +00001494 vif->support_int_mode = 1;
Damjan Marionf41244f2019-11-08 17:41:06 +01001495 virtio_log_debug (vif, "device supports msix interrupts");
Mohsin Kazmib74fe322019-01-31 13:50:56 +00001496 }
Mohsin Kazmi5db2f4a2021-02-22 18:27:57 +00001497 else
Mohsin Kazmib74fe322019-01-31 13:50:56 +00001498 {
1499 /*
Mohsin Kazmi5db2f4a2021-02-22 18:27:57 +00001500 * WARN: performance will be sub-optimal.
1501 * Fall back to intX, if msix table-size is 1 or
1502 * if UIO driver is being used.
Mohsin Kazmib74fe322019-01-31 13:50:56 +00001503 */
1504 if ((error =
1505 vlib_pci_register_intx_handler (vm, h, &virtio_pci_irq_handler)))
1506 {
Damjan Marionf41244f2019-11-08 17:41:06 +01001507 virtio_log_error (vif,
Mohsin Kazmib74fe322019-01-31 13:50:56 +00001508 "error encountered on pci register interrupt handler");
1509 goto error;
1510 }
1511 vif->support_int_mode = 1;
Damjan Marionf41244f2019-11-08 17:41:06 +01001512 virtio_log_debug (vif, "pci register interrupt handler");
Mohsin Kazmid6c15af2018-10-23 18:00:47 +02001513 }
Mohsin Kazmid6c15af2018-10-23 18:00:47 +02001514
1515 if ((error = vlib_pci_intr_enable (vm, h)))
Mohsin Kazmi33cc5cf2019-01-21 15:19:39 +00001516 {
Damjan Marionf41244f2019-11-08 17:41:06 +01001517 virtio_log_error (vif, "error encountered on pci interrupt enable");
Mohsin Kazmi33cc5cf2019-01-21 15:19:39 +00001518 goto error;
1519 }
Mohsin Kazmid6c15af2018-10-23 18:00:47 +02001520
Mohsin Kazmi379aac32020-08-20 10:25:12 +02001521 if ((error = virtio_pci_device_init (vm, vif, args, bar)))
Mohsin Kazmib74fe322019-01-31 13:50:56 +00001522 {
Damjan Marionf41244f2019-11-08 17:41:06 +01001523 virtio_log_error (vif, "error encountered on device init");
Mohsin Kazmib74fe322019-01-31 13:50:56 +00001524 goto error;
1525 }
1526
Mohsin Kazmid6c15af2018-10-23 18:00:47 +02001527 /* create interface */
Damjan Marion5c954c42022-01-06 20:36:14 +01001528 vnet_eth_interface_registration_t eir = {};
1529 eir.dev_class_index = virtio_device_class.index;
1530 eir.dev_instance = vif->dev_instance;
1531 eir.address = vif->mac_addr;
1532 eir.cb.flag_change = virtio_pci_flag_change;
1533 vif->hw_if_index = vnet_eth_register_interface (vnm, &eir);
Mohsin Kazmid6c15af2018-10-23 18:00:47 +02001534
1535 vnet_sw_interface_t *sw = vnet_get_hw_sw_interface (vnm, vif->hw_if_index);
1536 vif->sw_if_index = sw->sw_if_index;
1537 args->sw_if_index = sw->sw_if_index;
1538
Damjan Marionc48ec5d2022-01-10 19:38:57 +00001539 vnet_hw_if_set_caps (vnm, vif->hw_if_index, VNET_HW_IF_CAP_INT_MODE);
Mohsin Kazmie347acb2020-09-28 10:26:33 +00001540
1541 if (args->virtio_flags & VIRTIO_FLAG_BUFFERING)
1542 {
1543 error = virtio_set_packet_buffering (vif, args->buffering_size);
1544 if (error)
1545 {
1546 args->rv = VNET_API_ERROR_INIT_FAILED;
1547 virtio_log_error (vif,
1548 "error encountered during packet buffering init");
1549 goto error;
1550 }
Mohsin Kazmi562ac2f2023-05-24 11:25:39 +00001551 /*
1552 * packet buffering flag needs to be set 1 before calling the
1553 * virtio_pre_input_node_enable but after the successful initialization
1554 * of buffering queues above.
1555 * Packet buffering flag set to 0 if there will be any error during
1556 * buffering initialization.
1557 */
1558 vif->packet_buffering = 1;
1559 virtio_pre_input_node_enable (vm, vif);
Mohsin Kazmie347acb2020-09-28 10:26:33 +00001560 }
1561
Damjan Marion94100532020-11-06 23:25:57 +01001562 virtio_vring_set_rx_queues (vm, vif);
Mohsin Kazmib7e4e6d2021-12-13 18:32:42 +00001563 virtio_vring_set_tx_queues (vm, vif);
Damjan Marion94100532020-11-06 23:25:57 +01001564
Mohsin Kazmid6c15af2018-10-23 18:00:47 +02001565 if (virtio_pci_is_link_up (vm, vif) & VIRTIO_NET_S_LINK_UP)
1566 {
Mohsin Kazmid6c15af2018-10-23 18:00:47 +02001567 vnet_hw_interface_set_flags (vnm, vif->hw_if_index,
1568 VNET_HW_INTERFACE_FLAG_LINK_UP);
1569 }
1570 else
1571 vnet_hw_interface_set_flags (vnm, vif->hw_if_index, 0);
Mohsin Kazmi09a3bc52019-04-02 11:45:08 +00001572
Mohsin Kazmi6d4af892020-01-03 15:11:53 +00001573 virtio_pci_offloads (vm, vif, args->gso_enabled,
1574 args->checksum_offload_enabled);
1575
1576 if ((vif->features & VIRTIO_FEATURE (VIRTIO_NET_F_CTRL_VQ)) &&
1577 (vif->features & VIRTIO_FEATURE (VIRTIO_NET_F_MQ)))
Mohsin Kazmi09a3bc52019-04-02 11:45:08 +00001578 {
Steven Luonge9bc3322023-12-14 08:54:55 -08001579 if (vif->features & VIRTIO_FEATURE (VIRTIO_NET_F_RSS))
1580 {
1581 if (virtio_pci_enable_multiqueue_rss (vm, vif, vif->max_queue_pairs))
1582 virtio_log_warning (vif, "multiqueue with rss is not set");
1583 }
1584 else
1585 {
1586 if (virtio_pci_enable_multiqueue (vm, vif, vif->max_queue_pairs))
1587 virtio_log_warning (vif, "multiqueue is not set");
1588 }
Mohsin Kazmi09a3bc52019-04-02 11:45:08 +00001589 }
Mohsin Kazmid6c15af2018-10-23 18:00:47 +02001590 return;
1591
1592error:
1593 virtio_pci_delete_if (vm, vif);
Mohsin Kazmi57d73212020-03-05 12:22:41 +00001594 if (args->rv == 0)
1595 args->rv = VNET_API_ERROR_INVALID_INTERFACE;
Mohsin Kazmid6c15af2018-10-23 18:00:47 +02001596 args->error = error;
1597}
1598
1599int
1600virtio_pci_delete_if (vlib_main_t * vm, virtio_if_t * vif)
1601{
1602 vnet_main_t *vnm = vnet_get_main ();
Mohsin Kazmi33cc5cf2019-01-21 15:19:39 +00001603 virtio_main_t *vim = &virtio_main;
Mohsin Kazmid6c15af2018-10-23 18:00:47 +02001604 u32 i = 0;
1605
1606 if (vif->type != VIRTIO_IF_TYPE_PCI)
1607 return VNET_API_ERROR_INVALID_INTERFACE;
1608
1609 vlib_pci_intr_disable (vm, vif->pci_dev_handle);
1610
Mohsin Kazmic79d7352020-09-01 17:45:56 +02001611 if (vif->virtio_pci_func)
Mohsin Kazmi562ac2f2023-05-24 11:25:39 +00001612 {
1613 for (i = 0; i < vif->max_queue_pairs; i++)
1614 {
1615 vif->virtio_pci_func->del_queue (vm, vif, RX_QUEUE (i));
1616 vif->virtio_pci_func->del_queue (vm, vif, TX_QUEUE (i));
1617 }
1618
1619 if (vif->features & VIRTIO_FEATURE (VIRTIO_NET_F_CTRL_VQ))
1620 vif->virtio_pci_func->del_queue (vm, vif, vif->max_queue_pairs * 2);
1621
1622 vif->virtio_pci_func->device_reset (vm, vif);
1623 }
Mohsin Kazmid6c15af2018-10-23 18:00:47 +02001624
1625 if (vif->hw_if_index)
1626 {
1627 vnet_hw_interface_set_flags (vnm, vif->hw_if_index, 0);
Mohsin Kazmid6c15af2018-10-23 18:00:47 +02001628 ethernet_delete_interface (vnm, vif->hw_if_index);
1629 }
1630
1631 vlib_pci_device_close (vm, vif->pci_dev_handle);
1632
Mohsin Kazmi09a3bc52019-04-02 11:45:08 +00001633 vec_foreach_index (i, vif->rxq_vrings)
Mohsin Kazmid6c15af2018-10-23 18:00:47 +02001634 {
Mohsin Kazmi0f8912f2022-02-01 18:35:59 +00001635 vnet_virtio_vring_t *vring = vec_elt_at_index (vif->rxq_vrings, i);
Mohsin Kazmid6c15af2018-10-23 18:00:47 +02001636 if (vring->used)
1637 {
Mohsin Kazmib977d3f2020-11-16 16:49:30 +01001638 virtio_free_buffers (vm, vring);
Mohsin Kazmi09a3bc52019-04-02 11:45:08 +00001639 }
1640 vec_free (vring->buffers);
Mohsin Kazmi09a3bc52019-04-02 11:45:08 +00001641 vlib_physmem_free (vm, vring->desc);
1642 }
1643
Mohsin Kazmi562ac2f2023-05-24 11:25:39 +00001644 if (vif->packet_buffering)
1645 virtio_pre_input_node_disable (vm, vif);
Mohsin Kazmib7e4e6d2021-12-13 18:32:42 +00001646
Mohsin Kazmi09a3bc52019-04-02 11:45:08 +00001647 vec_foreach_index (i, vif->txq_vrings)
1648 {
Mohsin Kazmi0f8912f2022-02-01 18:35:59 +00001649 vnet_virtio_vring_t *vring = vec_elt_at_index (vif->txq_vrings, i);
Mohsin Kazmi09a3bc52019-04-02 11:45:08 +00001650 if (vring->used)
1651 {
Mohsin Kazmib977d3f2020-11-16 16:49:30 +01001652 virtio_free_buffers (vm, vring);
Mohsin Kazmid6c15af2018-10-23 18:00:47 +02001653 }
Mohsin Kazmid6c15af2018-10-23 18:00:47 +02001654 vec_free (vring->buffers);
Mohsin Kazmib977d3f2020-11-16 16:49:30 +01001655 gro_flow_table_free (vring->flow_table);
1656 virtio_vring_buffering_free (vm, vring->buffering);
Steven Luonge5584962019-06-25 13:47:06 -07001657 clib_spinlock_free (&vring->lockp);
Mohsin Kazmid6c15af2018-10-23 18:00:47 +02001658 vlib_physmem_free (vm, vring->desc);
1659 }
1660
Mohsin Kazmi09a3bc52019-04-02 11:45:08 +00001661 if (vif->cxq_vring != NULL)
1662 {
1663 u16 last = vif->cxq_vring->last_used_idx;
1664 u16 n_left = vif->cxq_vring->used->idx - last;
1665 while (n_left)
1666 {
1667 last++;
1668 n_left--;
1669 }
1670
1671 vif->cxq_vring->last_used_idx = last;
1672 vlib_physmem_free (vm, vif->cxq_vring->desc);
1673 }
1674
1675 vec_free (vif->rxq_vrings);
1676 vec_free (vif->txq_vrings);
1677 vec_free (vif->cxq_vring);
Mohsin Kazmid6c15af2018-10-23 18:00:47 +02001678
Mohsin Kazmid6c15af2018-10-23 18:00:47 +02001679 clib_error_free (vif->error);
1680 memset (vif, 0, sizeof (*vif));
Mohsin Kazmi33cc5cf2019-01-21 15:19:39 +00001681 pool_put (vim->interfaces, vif);
Mohsin Kazmid6c15af2018-10-23 18:00:47 +02001682
1683 return 0;
1684}
1685
Mohsin Kazmi6d4af892020-01-03 15:11:53 +00001686int
1687virtio_pci_enable_disable_offloads (vlib_main_t * vm, virtio_if_t * vif,
1688 int gso_enabled,
1689 int checksum_offload_enabled,
1690 int offloads_disabled)
1691{
1692 if (vif->type != VIRTIO_IF_TYPE_PCI)
1693 return VNET_API_ERROR_INVALID_INTERFACE;
1694
1695 if (gso_enabled)
1696 virtio_pci_offloads (vm, vif, 1, 0);
1697 else if (checksum_offload_enabled)
1698 virtio_pci_offloads (vm, vif, 0, 1);
1699 else if (offloads_disabled)
1700 virtio_pci_offloads (vm, vif, 0, 0);
1701
1702 return 0;
1703}
1704
Mohsin Kazmid6c15af2018-10-23 18:00:47 +02001705/*
1706 * fd.io coding-style-patch-verification: ON
1707 *
1708 * Local Variables:
1709 * eval: (c-set-style "gnu")
1710 * End:
1711 */