Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright(c) 2010-2016 Intel Corporation
3 : : */
4 : :
5 : : #include <stdint.h>
6 : : #include <stdio.h>
7 : : #include <stdlib.h>
8 : : #include <fcntl.h>
9 : : #include <string.h>
10 : : #include <errno.h>
11 : : #include <sys/mman.h>
12 : : #include <unistd.h>
13 : : #include <sys/eventfd.h>
14 : : #include <sys/types.h>
15 : : #include <sys/stat.h>
16 : :
17 : : #include <rte_alarm.h>
18 : : #include <rte_string_fns.h>
19 : : #include <rte_eal_memconfig.h>
20 : : #include <rte_malloc.h>
21 : : #include <rte_io.h>
22 : :
23 : : #include "vhost.h"
24 : : #include "virtio_user_dev.h"
25 : : #include "../virtio_ethdev.h"
26 : :
27 : : #define VIRTIO_USER_MEM_EVENT_CLB_NAME "virtio_user_mem_event_clb"
28 : :
29 : : const char * const virtio_user_backend_strings[] = {
30 : : [VIRTIO_USER_BACKEND_UNKNOWN] = "VIRTIO_USER_BACKEND_UNKNOWN",
31 : : [VIRTIO_USER_BACKEND_VHOST_USER] = "VHOST_USER",
32 : : [VIRTIO_USER_BACKEND_VHOST_KERNEL] = "VHOST_NET",
33 : : [VIRTIO_USER_BACKEND_VHOST_VDPA] = "VHOST_VDPA",
34 : : };
35 : :
36 : : static int
37 : 0 : virtio_user_create_queue(struct virtio_user_dev *dev, uint32_t queue_sel)
38 : : {
39 : : /* Of all per virtqueue MSGs, make sure VHOST_SET_VRING_CALL come
40 : : * firstly because vhost depends on this msg to allocate virtqueue
41 : : * pair.
42 : : */
43 : : struct vhost_vring_file file;
44 : : int ret;
45 : :
46 : 0 : file.index = queue_sel;
47 : 0 : file.fd = dev->callfds[queue_sel];
48 : 0 : ret = dev->ops->set_vring_call(dev, &file);
49 [ # # ]: 0 : if (ret < 0) {
50 : 0 : PMD_INIT_LOG(ERR, "(%s) Failed to create queue %u", dev->path, queue_sel);
51 : 0 : return -1;
52 : : }
53 : :
54 : : return 0;
55 : : }
56 : :
57 : : static int
58 : 0 : virtio_user_kick_queue(struct virtio_user_dev *dev, uint32_t queue_sel)
59 : : {
60 : : int ret;
61 : : struct vhost_vring_file file;
62 : : struct vhost_vring_state state;
63 : 0 : struct vring *vring = &dev->vrings.split[queue_sel];
64 : : struct vring_packed *pq_vring = &dev->vrings.packed[queue_sel];
65 : 0 : struct vhost_vring_addr addr = {
66 : : .index = queue_sel,
67 : : .log_guest_addr = 0,
68 : : .flags = 0, /* disable log */
69 : : };
70 : :
71 [ # # ]: 0 : if (queue_sel == dev->max_queue_pairs * 2) {
72 [ # # ]: 0 : if (!dev->scvq) {
73 : 0 : PMD_INIT_LOG(ERR, "(%s) Shadow control queue expected but missing",
74 : : dev->path);
75 : 0 : goto err;
76 : : }
77 : :
78 : : /* Use shadow control queue information */
79 : 0 : vring = &dev->scvq->vq_split.ring;
80 : 0 : pq_vring = &dev->scvq->vq_packed.ring;
81 : : }
82 : :
83 [ # # ]: 0 : if (dev->features & (1ULL << VIRTIO_F_RING_PACKED)) {
84 : 0 : addr.desc_user_addr =
85 : 0 : (uint64_t)(uintptr_t)pq_vring->desc;
86 : 0 : addr.avail_user_addr =
87 : 0 : (uint64_t)(uintptr_t)pq_vring->driver;
88 : 0 : addr.used_user_addr =
89 : 0 : (uint64_t)(uintptr_t)pq_vring->device;
90 : : } else {
91 : 0 : addr.desc_user_addr = (uint64_t)(uintptr_t)vring->desc;
92 : 0 : addr.avail_user_addr = (uint64_t)(uintptr_t)vring->avail;
93 : 0 : addr.used_user_addr = (uint64_t)(uintptr_t)vring->used;
94 : : }
95 : :
96 : 0 : state.index = queue_sel;
97 : 0 : state.num = vring->num;
98 : 0 : ret = dev->ops->set_vring_num(dev, &state);
99 [ # # ]: 0 : if (ret < 0)
100 : 0 : goto err;
101 : :
102 : 0 : state.index = queue_sel;
103 : 0 : state.num = 0; /* no reservation */
104 [ # # ]: 0 : if (dev->features & (1ULL << VIRTIO_F_RING_PACKED))
105 : 0 : state.num |= (1 << 15);
106 : 0 : ret = dev->ops->set_vring_base(dev, &state);
107 [ # # ]: 0 : if (ret < 0)
108 : 0 : goto err;
109 : :
110 : 0 : ret = dev->ops->set_vring_addr(dev, &addr);
111 [ # # ]: 0 : if (ret < 0)
112 : 0 : goto err;
113 : :
114 : : /* Of all per virtqueue MSGs, make sure VHOST_USER_SET_VRING_KICK comes
115 : : * lastly because vhost depends on this msg to judge if
116 : : * virtio is ready.
117 : : */
118 : 0 : file.index = queue_sel;
119 : 0 : file.fd = dev->kickfds[queue_sel];
120 : 0 : ret = dev->ops->set_vring_kick(dev, &file);
121 [ # # ]: 0 : if (ret < 0)
122 : 0 : goto err;
123 : :
124 : : return 0;
125 : 0 : err:
126 : 0 : PMD_INIT_LOG(ERR, "(%s) Failed to kick queue %u", dev->path, queue_sel);
127 : :
128 : 0 : return -1;
129 : : }
130 : :
131 : : static int
132 : 0 : virtio_user_queue_setup(struct virtio_user_dev *dev,
133 : : int (*fn)(struct virtio_user_dev *, uint32_t))
134 : : {
135 : : uint32_t i, nr_vq;
136 : :
137 : 0 : nr_vq = dev->max_queue_pairs * 2;
138 [ # # ]: 0 : if (dev->hw_cvq)
139 : 0 : nr_vq++;
140 : :
141 [ # # ]: 0 : for (i = 0; i < nr_vq; i++) {
142 [ # # ]: 0 : if (fn(dev, i) < 0) {
143 : 0 : PMD_DRV_LOG(ERR, "(%s) setup VQ %u failed", dev->path, i);
144 : 0 : return -1;
145 : : }
146 : : }
147 : :
148 : : return 0;
149 : : }
150 : :
151 : : int
152 : 0 : virtio_user_dev_set_features(struct virtio_user_dev *dev)
153 : : {
154 : : uint64_t features;
155 : : int ret = -1;
156 : :
157 : 0 : pthread_mutex_lock(&dev->mutex);
158 : :
159 : : /* Step 0: tell vhost to create queues */
160 [ # # ]: 0 : if (virtio_user_queue_setup(dev, virtio_user_create_queue) < 0)
161 : 0 : goto error;
162 : :
163 : 0 : features = dev->features;
164 : :
165 : : /* Strip VIRTIO_NET_F_MAC, as MAC address is handled in vdev init */
166 : 0 : features &= ~(1ull << VIRTIO_NET_F_MAC);
167 : : /* Strip VIRTIO_NET_F_CTRL_VQ if the devices does not really support control VQ */
168 [ # # ]: 0 : if (!dev->hw_cvq)
169 : 0 : features &= ~(1ull << VIRTIO_NET_F_CTRL_VQ);
170 : 0 : features &= ~(1ull << VIRTIO_NET_F_STATUS);
171 : 0 : ret = dev->ops->set_features(dev, features);
172 [ # # ]: 0 : if (ret < 0)
173 : 0 : goto error;
174 : 0 : PMD_DRV_LOG(INFO, "(%s) set features: 0x%" PRIx64, dev->path, features);
175 : 0 : error:
176 : 0 : pthread_mutex_unlock(&dev->mutex);
177 : :
178 : 0 : return ret;
179 : : }
180 : :
181 : : int
182 : 0 : virtio_user_start_device(struct virtio_user_dev *dev)
183 : : {
184 : : int ret;
185 : :
186 : : /*
187 : : * XXX workaround!
188 : : *
189 : : * We need to make sure that the locks will be
190 : : * taken in the correct order to avoid deadlocks.
191 : : *
192 : : * Before releasing this lock, this thread should
193 : : * not trigger any memory hotplug events.
194 : : *
195 : : * This is a temporary workaround, and should be
196 : : * replaced when we get proper supports from the
197 : : * memory subsystem in the future.
198 : : */
199 : 0 : rte_mcfg_mem_read_lock();
200 : 0 : pthread_mutex_lock(&dev->mutex);
201 : :
202 : : /* Step 2: share memory regions */
203 : 0 : ret = dev->ops->set_memory_table(dev);
204 [ # # ]: 0 : if (ret < 0)
205 : 0 : goto error;
206 : :
207 : : /* Step 3: kick queues */
208 : 0 : ret = virtio_user_queue_setup(dev, virtio_user_kick_queue);
209 [ # # ]: 0 : if (ret < 0)
210 : 0 : goto error;
211 : :
212 : : /* Step 4: enable queues
213 : : * we enable the 1st queue pair by default.
214 : : */
215 : 0 : ret = dev->ops->enable_qp(dev, 0, 1);
216 [ # # ]: 0 : if (ret < 0)
217 : 0 : goto error;
218 : :
219 [ # # ]: 0 : if (dev->scvq) {
220 : 0 : ret = dev->ops->cvq_enable(dev, 1);
221 [ # # ]: 0 : if (ret < 0)
222 : 0 : goto error;
223 : : }
224 : :
225 : 0 : dev->started = true;
226 : :
227 : 0 : pthread_mutex_unlock(&dev->mutex);
228 : 0 : rte_mcfg_mem_read_unlock();
229 : :
230 : 0 : return 0;
231 : 0 : error:
232 : 0 : pthread_mutex_unlock(&dev->mutex);
233 : 0 : rte_mcfg_mem_read_unlock();
234 : :
235 : 0 : PMD_INIT_LOG(ERR, "(%s) Failed to start device", dev->path);
236 : :
237 : : /* TODO: free resource here or caller to check */
238 : 0 : return -1;
239 : : }
240 : :
241 : 0 : int virtio_user_stop_device(struct virtio_user_dev *dev)
242 : : {
243 : : struct vhost_vring_state state;
244 : : uint32_t i;
245 : : int ret;
246 : :
247 : 0 : pthread_mutex_lock(&dev->mutex);
248 [ # # ]: 0 : if (!dev->started)
249 : 0 : goto out;
250 : :
251 [ # # ]: 0 : for (i = 0; i < dev->max_queue_pairs; ++i) {
252 : 0 : ret = dev->ops->enable_qp(dev, i, 0);
253 [ # # ]: 0 : if (ret < 0)
254 : 0 : goto err;
255 : : }
256 : :
257 [ # # ]: 0 : if (dev->scvq) {
258 : 0 : ret = dev->ops->cvq_enable(dev, 0);
259 [ # # ]: 0 : if (ret < 0)
260 : 0 : goto err;
261 : : }
262 : :
263 : : /* Stop the backend. */
264 [ # # ]: 0 : for (i = 0; i < dev->max_queue_pairs * 2; ++i) {
265 : 0 : state.index = i;
266 : 0 : ret = dev->ops->get_vring_base(dev, &state);
267 [ # # ]: 0 : if (ret < 0) {
268 : 0 : PMD_DRV_LOG(ERR, "(%s) get_vring_base failed, index=%u", dev->path, i);
269 : 0 : goto err;
270 : : }
271 : : }
272 : :
273 : 0 : dev->started = false;
274 : :
275 : 0 : out:
276 : 0 : pthread_mutex_unlock(&dev->mutex);
277 : :
278 : 0 : return 0;
279 : 0 : err:
280 : 0 : pthread_mutex_unlock(&dev->mutex);
281 : :
282 : 0 : PMD_INIT_LOG(ERR, "(%s) Failed to stop device", dev->path);
283 : :
284 : 0 : return -1;
285 : : }
286 : :
287 : : static int
288 : 0 : virtio_user_dev_init_max_queue_pairs(struct virtio_user_dev *dev, uint32_t user_max_qp)
289 : : {
290 : : int ret;
291 : :
292 [ # # ]: 0 : if (!(dev->device_features & (1ULL << VIRTIO_NET_F_MQ))) {
293 : 0 : dev->max_queue_pairs = 1;
294 : 0 : return 0;
295 : : }
296 : :
297 [ # # ]: 0 : if (!dev->ops->get_config) {
298 : 0 : dev->max_queue_pairs = user_max_qp;
299 : 0 : return 0;
300 : : }
301 : :
302 : 0 : ret = dev->ops->get_config(dev, (uint8_t *)&dev->max_queue_pairs,
303 : : offsetof(struct virtio_net_config, max_virtqueue_pairs),
304 : : sizeof(uint16_t));
305 [ # # ]: 0 : if (ret) {
306 : : /*
307 : : * We need to know the max queue pair from the device so that
308 : : * the control queue gets the right index.
309 : : */
310 : 0 : dev->max_queue_pairs = 1;
311 : 0 : PMD_DRV_LOG(ERR, "(%s) Failed to get max queue pairs from device", dev->path);
312 : :
313 : 0 : return ret;
314 : : }
315 : :
316 : : return 0;
317 : : }
318 : :
319 : : int
320 : 0 : virtio_user_dev_get_rss_config(struct virtio_user_dev *dev, void *dst, size_t offset, int length)
321 : : {
322 : : int ret = 0;
323 : :
324 [ # # ]: 0 : if (!(dev->device_features & (1ULL << VIRTIO_NET_F_RSS)))
325 : : return -ENOTSUP;
326 : :
327 [ # # ]: 0 : if (!dev->ops->get_config)
328 : : return -ENOTSUP;
329 : :
330 : 0 : ret = dev->ops->get_config(dev, dst, offset, length);
331 [ # # ]: 0 : if (ret)
332 : 0 : PMD_DRV_LOG(ERR, "(%s) Failed to get rss config in device", dev->path);
333 : :
334 : : return ret;
335 : : }
336 : :
337 : : int
338 : 0 : virtio_user_dev_set_mac(struct virtio_user_dev *dev)
339 : : {
340 : : int ret = 0;
341 : :
342 [ # # ]: 0 : if (!(dev->device_features & (1ULL << VIRTIO_NET_F_MAC)))
343 : : return -ENOTSUP;
344 : :
345 [ # # ]: 0 : if (!dev->ops->set_config)
346 : : return -ENOTSUP;
347 : :
348 : 0 : ret = dev->ops->set_config(dev, dev->mac_addr,
349 : : offsetof(struct virtio_net_config, mac),
350 : : RTE_ETHER_ADDR_LEN);
351 [ # # ]: 0 : if (ret)
352 : 0 : PMD_DRV_LOG(ERR, "(%s) Failed to set MAC address in device", dev->path);
353 : :
354 : : return ret;
355 : : }
356 : :
357 : : int
358 : 0 : virtio_user_dev_get_mac(struct virtio_user_dev *dev)
359 : : {
360 : : int ret = 0;
361 : :
362 [ # # ]: 0 : if (!(dev->device_features & (1ULL << VIRTIO_NET_F_MAC)))
363 : : return -ENOTSUP;
364 : :
365 [ # # ]: 0 : if (!dev->ops->get_config)
366 : : return -ENOTSUP;
367 : :
368 : 0 : ret = dev->ops->get_config(dev, dev->mac_addr,
369 : : offsetof(struct virtio_net_config, mac),
370 : : RTE_ETHER_ADDR_LEN);
371 [ # # ]: 0 : if (ret)
372 : 0 : PMD_DRV_LOG(ERR, "(%s) Failed to get MAC address from device", dev->path);
373 : :
374 : : return ret;
375 : : }
376 : :
377 : : static void
378 : 0 : virtio_user_dev_init_mac(struct virtio_user_dev *dev, const char *mac)
379 : : {
380 : : struct rte_ether_addr cmdline_mac;
381 : : char buf[RTE_ETHER_ADDR_FMT_SIZE];
382 : : int ret;
383 : :
384 [ # # # # ]: 0 : if (mac && rte_ether_unformat_addr(mac, &cmdline_mac) == 0) {
385 : : /*
386 : : * MAC address was passed from command-line, try to store
387 : : * it in the device if it supports it. Otherwise try to use
388 : : * the device one.
389 : : */
390 : 0 : memcpy(dev->mac_addr, &cmdline_mac, RTE_ETHER_ADDR_LEN);
391 : 0 : dev->mac_specified = 1;
392 : :
393 : : /* Setting MAC may fail, continue to get the device one in this case */
394 : 0 : virtio_user_dev_set_mac(dev);
395 : 0 : ret = virtio_user_dev_get_mac(dev);
396 [ # # ]: 0 : if (ret == -ENOTSUP)
397 : 0 : goto out;
398 : :
399 [ # # ]: 0 : if (memcmp(&cmdline_mac, dev->mac_addr, RTE_ETHER_ADDR_LEN))
400 : 0 : PMD_DRV_LOG(INFO, "(%s) Device MAC update failed", dev->path);
401 : : } else {
402 : 0 : ret = virtio_user_dev_get_mac(dev);
403 [ # # ]: 0 : if (ret) {
404 : 0 : PMD_DRV_LOG(ERR, "(%s) No valid MAC in devargs or device, use random",
405 : : dev->path);
406 : 0 : return;
407 : : }
408 : :
409 : 0 : dev->mac_specified = 1;
410 : : }
411 : 0 : out:
412 : 0 : rte_ether_format_addr(buf, RTE_ETHER_ADDR_FMT_SIZE,
413 : 0 : (struct rte_ether_addr *)dev->mac_addr);
414 : 0 : PMD_DRV_LOG(INFO, "(%s) MAC %s specified", dev->path, buf);
415 : : }
416 : :
417 : : static int
418 : 0 : virtio_user_dev_init_notify(struct virtio_user_dev *dev)
419 : : {
420 : : uint32_t i, j, nr_vq;
421 : : int callfd;
422 : : int kickfd;
423 : :
424 : 0 : nr_vq = dev->max_queue_pairs * 2;
425 [ # # ]: 0 : if (dev->hw_cvq)
426 : 0 : nr_vq++;
427 : :
428 [ # # ]: 0 : for (i = 0; i < nr_vq; i++) {
429 : : /* May use invalid flag, but some backend uses kickfd and
430 : : * callfd as criteria to judge if dev is alive. so finally we
431 : : * use real event_fd.
432 : : */
433 : 0 : callfd = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK);
434 [ # # ]: 0 : if (callfd < 0) {
435 : 0 : PMD_DRV_LOG(ERR, "(%s) callfd error, %s", dev->path, strerror(errno));
436 : 0 : goto err;
437 : : }
438 : 0 : kickfd = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK);
439 [ # # ]: 0 : if (kickfd < 0) {
440 : 0 : close(callfd);
441 : 0 : PMD_DRV_LOG(ERR, "(%s) kickfd error, %s", dev->path, strerror(errno));
442 : 0 : goto err;
443 : : }
444 : 0 : dev->callfds[i] = callfd;
445 : 0 : dev->kickfds[i] = kickfd;
446 : : }
447 : :
448 [ # # ]: 0 : if (dev->device_features & (1ULL << VIRTIO_F_NOTIFICATION_DATA))
449 [ # # # # ]: 0 : if (dev->ops->map_notification_area &&
450 : 0 : dev->ops->map_notification_area(dev))
451 : 0 : goto err;
452 : :
453 : : return 0;
454 : 0 : err:
455 [ # # ]: 0 : for (j = 0; j < i; j++) {
456 [ # # ]: 0 : if (dev->kickfds[j] >= 0) {
457 : 0 : close(dev->kickfds[j]);
458 : 0 : dev->kickfds[j] = -1;
459 : : }
460 [ # # ]: 0 : if (dev->callfds[j] >= 0) {
461 : 0 : close(dev->callfds[j]);
462 : 0 : dev->callfds[j] = -1;
463 : : }
464 : : }
465 : :
466 : : return -1;
467 : : }
468 : :
469 : : static void
470 : 0 : virtio_user_dev_uninit_notify(struct virtio_user_dev *dev)
471 : : {
472 : : uint32_t i;
473 : :
474 [ # # ]: 0 : for (i = 0; i < dev->max_queue_pairs * 2; ++i) {
475 [ # # ]: 0 : if (dev->kickfds[i] >= 0) {
476 : 0 : close(dev->kickfds[i]);
477 : 0 : dev->kickfds[i] = -1;
478 : : }
479 [ # # ]: 0 : if (dev->callfds[i] >= 0) {
480 : 0 : close(dev->callfds[i]);
481 : 0 : dev->callfds[i] = -1;
482 : : }
483 : : }
484 [ # # # # ]: 0 : if (dev->ops->unmap_notification_area && dev->notify_area)
485 : 0 : dev->ops->unmap_notification_area(dev);
486 : 0 : }
487 : :
488 : : static int
489 : 0 : virtio_user_fill_intr_handle(struct virtio_user_dev *dev)
490 : : {
491 : : uint32_t i;
492 : 0 : struct rte_eth_dev *eth_dev = &rte_eth_devices[dev->hw.port_id];
493 : :
494 [ # # ]: 0 : if (eth_dev->intr_handle == NULL) {
495 : 0 : eth_dev->intr_handle =
496 : 0 : rte_intr_instance_alloc(RTE_INTR_INSTANCE_F_PRIVATE);
497 [ # # ]: 0 : if (eth_dev->intr_handle == NULL) {
498 : 0 : PMD_DRV_LOG(ERR, "(%s) failed to allocate intr_handle", dev->path);
499 : 0 : return -1;
500 : : }
501 : : }
502 : :
503 [ # # ]: 0 : for (i = 0; i < dev->max_queue_pairs; ++i) {
504 [ # # ]: 0 : if (rte_intr_efds_index_set(eth_dev->intr_handle, i,
505 : 0 : dev->callfds[2 * i + VTNET_SQ_RQ_QUEUE_IDX]))
506 : 0 : return -rte_errno;
507 : : }
508 : :
509 [ # # ]: 0 : if (rte_intr_nb_efd_set(eth_dev->intr_handle, dev->max_queue_pairs))
510 : 0 : return -rte_errno;
511 : :
512 [ # # ]: 0 : if (rte_intr_max_intr_set(eth_dev->intr_handle,
513 : 0 : dev->max_queue_pairs + 1))
514 : 0 : return -rte_errno;
515 : :
516 [ # # ]: 0 : if (rte_intr_type_set(eth_dev->intr_handle, RTE_INTR_HANDLE_VDEV))
517 : 0 : return -rte_errno;
518 : :
519 : : /* For virtio vdev, no need to read counter for clean */
520 [ # # ]: 0 : if (rte_intr_efd_counter_size_set(eth_dev->intr_handle, 0))
521 : 0 : return -rte_errno;
522 : :
523 [ # # ]: 0 : if (rte_intr_fd_set(eth_dev->intr_handle, dev->ops->get_intr_fd(dev)))
524 : 0 : return -rte_errno;
525 : :
526 : : return 0;
527 : : }
528 : :
529 : : static void
530 : 0 : virtio_user_mem_event_cb(enum rte_mem_event type __rte_unused,
531 : : const void *addr,
532 : : size_t len __rte_unused,
533 : : void *arg)
534 : : {
535 : : struct virtio_user_dev *dev = arg;
536 : : struct rte_memseg_list *msl;
537 : : uint16_t i;
538 : : int ret = 0;
539 : :
540 : : /* ignore externally allocated memory */
541 : 0 : msl = rte_mem_virt2memseg_list(addr);
542 [ # # ]: 0 : if (msl->external)
543 : : return;
544 : :
545 : 0 : pthread_mutex_lock(&dev->mutex);
546 : :
547 [ # # ]: 0 : if (dev->started == false)
548 : 0 : goto exit;
549 : :
550 : : /* Step 1: pause the active queues */
551 [ # # ]: 0 : for (i = 0; i < dev->queue_pairs; i++) {
552 : 0 : ret = dev->ops->enable_qp(dev, i, 0);
553 [ # # ]: 0 : if (ret < 0)
554 : 0 : goto exit;
555 : : }
556 : :
557 : : /* Step 2: update memory regions */
558 : 0 : ret = dev->ops->set_memory_table(dev);
559 [ # # ]: 0 : if (ret < 0)
560 : 0 : goto exit;
561 : :
562 : : /* Step 3: resume the active queues */
563 [ # # ]: 0 : for (i = 0; i < dev->queue_pairs; i++) {
564 : 0 : ret = dev->ops->enable_qp(dev, i, 1);
565 [ # # ]: 0 : if (ret < 0)
566 : 0 : goto exit;
567 : : }
568 : :
569 : 0 : exit:
570 : 0 : pthread_mutex_unlock(&dev->mutex);
571 : :
572 [ # # ]: 0 : if (ret < 0)
573 : 0 : PMD_DRV_LOG(ERR, "(%s) Failed to update memory table", dev->path);
574 : : }
575 : :
576 : : static int
577 : 0 : virtio_user_dev_setup(struct virtio_user_dev *dev)
578 : : {
579 [ # # ]: 0 : if (dev->is_server) {
580 [ # # ]: 0 : if (dev->backend_type != VIRTIO_USER_BACKEND_VHOST_USER) {
581 : 0 : PMD_DRV_LOG(ERR, "Server mode only supports vhost-user!");
582 : 0 : return -1;
583 : : }
584 : : }
585 : :
586 [ # # # # ]: 0 : switch (dev->backend_type) {
587 : 0 : case VIRTIO_USER_BACKEND_VHOST_USER:
588 : 0 : dev->ops = &virtio_ops_user;
589 : 0 : break;
590 : 0 : case VIRTIO_USER_BACKEND_VHOST_KERNEL:
591 : 0 : dev->ops = &virtio_ops_kernel;
592 : 0 : break;
593 : 0 : case VIRTIO_USER_BACKEND_VHOST_VDPA:
594 : 0 : dev->ops = &virtio_ops_vdpa;
595 : 0 : break;
596 : 0 : default:
597 : 0 : PMD_DRV_LOG(ERR, "(%s) Unknown backend type", dev->path);
598 : 0 : return -1;
599 : : }
600 : :
601 [ # # ]: 0 : if (dev->ops->setup(dev) < 0) {
602 : 0 : PMD_INIT_LOG(ERR, "(%s) Failed to setup backend", dev->path);
603 : 0 : return -1;
604 : : }
605 : :
606 : : return 0;
607 : : }
608 : :
609 : : static int
610 : 0 : virtio_user_alloc_vrings(struct virtio_user_dev *dev)
611 : : {
612 : : int i, size, nr_vrings;
613 : 0 : bool packed_ring = !!(dev->device_features & (1ull << VIRTIO_F_RING_PACKED));
614 : :
615 : 0 : nr_vrings = dev->max_queue_pairs * 2;
616 [ # # ]: 0 : if (dev->device_features & (1ull << VIRTIO_NET_F_MQ))
617 : 0 : nr_vrings++;
618 : :
619 : 0 : dev->callfds = rte_zmalloc("virtio_user_dev", nr_vrings * sizeof(*dev->callfds), 0);
620 [ # # ]: 0 : if (!dev->callfds) {
621 : 0 : PMD_INIT_LOG(ERR, "(%s) Failed to alloc callfds", dev->path);
622 : 0 : return -1;
623 : : }
624 : :
625 : 0 : dev->kickfds = rte_zmalloc("virtio_user_dev", nr_vrings * sizeof(*dev->kickfds), 0);
626 [ # # ]: 0 : if (!dev->kickfds) {
627 : 0 : PMD_INIT_LOG(ERR, "(%s) Failed to alloc kickfds", dev->path);
628 : 0 : goto free_callfds;
629 : : }
630 : :
631 [ # # ]: 0 : for (i = 0; i < nr_vrings; i++) {
632 : 0 : dev->callfds[i] = -1;
633 : 0 : dev->kickfds[i] = -1;
634 : : }
635 : :
636 : : if (packed_ring)
637 : : size = sizeof(*dev->vrings.packed);
638 : : else
639 : : size = sizeof(*dev->vrings.split);
640 : 0 : dev->vrings.ptr = rte_zmalloc("virtio_user_dev", nr_vrings * size, 0);
641 [ # # ]: 0 : if (!dev->vrings.ptr) {
642 : 0 : PMD_INIT_LOG(ERR, "(%s) Failed to alloc vrings metadata", dev->path);
643 : 0 : goto free_kickfds;
644 : : }
645 : :
646 [ # # ]: 0 : if (packed_ring) {
647 : 0 : dev->packed_queues = rte_zmalloc("virtio_user_dev",
648 : : nr_vrings * sizeof(*dev->packed_queues), 0);
649 [ # # ]: 0 : if (!dev->packed_queues) {
650 : 0 : PMD_INIT_LOG(ERR, "(%s) Failed to alloc packed queues metadata",
651 : : dev->path);
652 : 0 : goto free_vrings;
653 : : }
654 : : }
655 : :
656 : 0 : dev->qp_enabled = rte_zmalloc("virtio_user_dev",
657 : 0 : dev->max_queue_pairs * sizeof(*dev->qp_enabled), 0);
658 [ # # ]: 0 : if (!dev->qp_enabled) {
659 : 0 : PMD_INIT_LOG(ERR, "(%s) Failed to alloc QP enable states", dev->path);
660 : 0 : goto free_packed_queues;
661 : : }
662 : :
663 : : return 0;
664 : :
665 : : free_packed_queues:
666 : 0 : rte_free(dev->packed_queues);
667 : 0 : dev->packed_queues = NULL;
668 : 0 : free_vrings:
669 : 0 : rte_free(dev->vrings.ptr);
670 : 0 : dev->vrings.ptr = NULL;
671 : 0 : free_kickfds:
672 : 0 : rte_free(dev->kickfds);
673 : 0 : dev->kickfds = NULL;
674 : 0 : free_callfds:
675 : 0 : rte_free(dev->callfds);
676 : 0 : dev->callfds = NULL;
677 : :
678 : 0 : return -1;
679 : : }
680 : :
681 : : static void
682 : 0 : virtio_user_free_vrings(struct virtio_user_dev *dev)
683 : : {
684 : 0 : rte_free(dev->qp_enabled);
685 : 0 : dev->qp_enabled = NULL;
686 : 0 : rte_free(dev->packed_queues);
687 : 0 : dev->packed_queues = NULL;
688 : 0 : rte_free(dev->vrings.ptr);
689 : 0 : dev->vrings.ptr = NULL;
690 : 0 : rte_free(dev->kickfds);
691 : 0 : dev->kickfds = NULL;
692 : 0 : rte_free(dev->callfds);
693 : 0 : dev->callfds = NULL;
694 : 0 : }
695 : :
696 : : /* Use below macro to filter features from vhost backend */
697 : : #define VIRTIO_USER_SUPPORTED_FEATURES \
698 : : (1ULL << VIRTIO_NET_F_MAC | \
699 : : 1ULL << VIRTIO_NET_F_STATUS | \
700 : : 1ULL << VIRTIO_NET_F_MQ | \
701 : : 1ULL << VIRTIO_NET_F_CTRL_MAC_ADDR | \
702 : : 1ULL << VIRTIO_NET_F_CTRL_VQ | \
703 : : 1ULL << VIRTIO_NET_F_CTRL_RX | \
704 : : 1ULL << VIRTIO_NET_F_CTRL_VLAN | \
705 : : 1ULL << VIRTIO_NET_F_CSUM | \
706 : : 1ULL << VIRTIO_NET_F_HOST_TSO4 | \
707 : : 1ULL << VIRTIO_NET_F_HOST_TSO6 | \
708 : : 1ULL << VIRTIO_NET_F_MRG_RXBUF | \
709 : : 1ULL << VIRTIO_RING_F_INDIRECT_DESC | \
710 : : 1ULL << VIRTIO_NET_F_GUEST_CSUM | \
711 : : 1ULL << VIRTIO_NET_F_GUEST_TSO4 | \
712 : : 1ULL << VIRTIO_NET_F_GUEST_TSO6 | \
713 : : 1ULL << VIRTIO_F_IN_ORDER | \
714 : : 1ULL << VIRTIO_F_VERSION_1 | \
715 : : 1ULL << VIRTIO_F_RING_PACKED | \
716 : : 1ULL << VIRTIO_F_NOTIFICATION_DATA | \
717 : : 1ULL << VIRTIO_NET_F_RSS)
718 : :
719 : : int
720 : 0 : virtio_user_dev_init(struct virtio_user_dev *dev, char *path, uint16_t queues,
721 : : int cq, int queue_size, const char *mac, char **ifname,
722 : : int server, int mrg_rxbuf, int in_order, int packed_vq,
723 : : enum virtio_user_backend_type backend_type)
724 : : {
725 : : uint64_t backend_features;
726 : :
727 : 0 : pthread_mutex_init(&dev->mutex, NULL);
728 : 0 : strlcpy(dev->path, path, PATH_MAX);
729 : :
730 : 0 : dev->started = 0;
731 : 0 : dev->queue_pairs = 1; /* mq disabled by default */
732 : 0 : dev->max_queue_pairs = queues; /* initialize to user requested value for kernel backend */
733 : 0 : dev->queue_size = queue_size;
734 : 0 : dev->is_server = server;
735 : 0 : dev->mac_specified = 0;
736 : 0 : dev->frontend_features = 0;
737 : 0 : dev->unsupported_features = 0;
738 : 0 : dev->backend_type = backend_type;
739 : 0 : dev->ifname = *ifname;
740 : :
741 [ # # ]: 0 : if (virtio_user_dev_setup(dev) < 0) {
742 : 0 : PMD_INIT_LOG(ERR, "(%s) backend set up fails", dev->path);
743 : 0 : return -1;
744 : : }
745 : :
746 [ # # ]: 0 : if (dev->ops->set_owner(dev) < 0) {
747 : 0 : PMD_INIT_LOG(ERR, "(%s) Failed to set backend owner", dev->path);
748 : 0 : goto destroy;
749 : : }
750 : :
751 [ # # ]: 0 : if (dev->ops->get_backend_features(&backend_features) < 0) {
752 : 0 : PMD_INIT_LOG(ERR, "(%s) Failed to get backend features", dev->path);
753 : 0 : goto destroy;
754 : : }
755 : :
756 : 0 : dev->unsupported_features = ~(VIRTIO_USER_SUPPORTED_FEATURES | backend_features);
757 : :
758 [ # # ]: 0 : if (dev->ops->get_features(dev, &dev->device_features) < 0) {
759 : 0 : PMD_INIT_LOG(ERR, "(%s) Failed to get device features", dev->path);
760 : 0 : goto destroy;
761 : : }
762 : :
763 : 0 : virtio_user_dev_init_mac(dev, mac);
764 : :
765 [ # # ]: 0 : if (virtio_user_dev_init_max_queue_pairs(dev, queues))
766 : 0 : dev->unsupported_features |= (1ull << VIRTIO_NET_F_MQ);
767 : :
768 [ # # # # ]: 0 : if (dev->max_queue_pairs > 1 || dev->hw_cvq)
769 : : cq = 1;
770 : :
771 [ # # ]: 0 : if (!mrg_rxbuf)
772 : 0 : dev->unsupported_features |= (1ull << VIRTIO_NET_F_MRG_RXBUF);
773 : :
774 [ # # ]: 0 : if (!in_order)
775 : 0 : dev->unsupported_features |= (1ull << VIRTIO_F_IN_ORDER);
776 : :
777 [ # # ]: 0 : if (!packed_vq)
778 : 0 : dev->unsupported_features |= (1ull << VIRTIO_F_RING_PACKED);
779 : :
780 [ # # ]: 0 : if (dev->mac_specified)
781 : 0 : dev->frontend_features |= (1ull << VIRTIO_NET_F_MAC);
782 : : else
783 : 0 : dev->unsupported_features |= (1ull << VIRTIO_NET_F_MAC);
784 : :
785 [ # # ]: 0 : if (cq) {
786 : : /* Except for vDPA, the device does not really need to know
787 : : * anything about CQ, so if necessary, we just claim to support
788 : : * control queue.
789 : : */
790 : 0 : dev->frontend_features |= (1ull << VIRTIO_NET_F_CTRL_VQ);
791 : : } else {
792 : 0 : dev->unsupported_features |= (1ull << VIRTIO_NET_F_CTRL_VQ);
793 : : /* Also disable features that depend on VIRTIO_NET_F_CTRL_VQ */
794 : 0 : dev->unsupported_features |= (1ull << VIRTIO_NET_F_CTRL_RX);
795 : 0 : dev->unsupported_features |= (1ull << VIRTIO_NET_F_CTRL_VLAN);
796 : 0 : dev->unsupported_features |=
797 : : (1ull << VIRTIO_NET_F_GUEST_ANNOUNCE);
798 : 0 : dev->unsupported_features |= (1ull << VIRTIO_NET_F_MQ);
799 : 0 : dev->unsupported_features |=
800 : : (1ull << VIRTIO_NET_F_CTRL_MAC_ADDR);
801 : : }
802 : :
803 : : /* The backend will not report this feature, we add it explicitly */
804 [ # # ]: 0 : if (dev->backend_type == VIRTIO_USER_BACKEND_VHOST_USER)
805 : 0 : dev->frontend_features |= (1ull << VIRTIO_NET_F_STATUS);
806 : :
807 : 0 : dev->frontend_features &= ~dev->unsupported_features;
808 : 0 : dev->device_features &= ~dev->unsupported_features;
809 : :
810 [ # # ]: 0 : if (virtio_user_alloc_vrings(dev) < 0) {
811 : 0 : PMD_INIT_LOG(ERR, "(%s) Failed to allocate vring metadata", dev->path);
812 : 0 : goto destroy;
813 : : }
814 : :
815 [ # # ]: 0 : if (virtio_user_dev_init_notify(dev) < 0) {
816 : 0 : PMD_INIT_LOG(ERR, "(%s) Failed to init notifiers", dev->path);
817 : 0 : goto free_vrings;
818 : : }
819 : :
820 [ # # ]: 0 : if (virtio_user_fill_intr_handle(dev) < 0) {
821 : 0 : PMD_INIT_LOG(ERR, "(%s) Failed to init interrupt handler", dev->path);
822 : 0 : goto notify_uninit;
823 : : }
824 : :
825 [ # # ]: 0 : if (rte_mem_event_callback_register(VIRTIO_USER_MEM_EVENT_CLB_NAME,
826 : : virtio_user_mem_event_cb, dev)) {
827 [ # # ]: 0 : if (rte_errno != ENOTSUP) {
828 : 0 : PMD_INIT_LOG(ERR, "(%s) Failed to register mem event callback",
829 : : dev->path);
830 : 0 : goto notify_uninit;
831 : : }
832 : : }
833 : :
834 : 0 : *ifname = NULL;
835 : 0 : return 0;
836 : :
837 : 0 : notify_uninit:
838 : 0 : virtio_user_dev_uninit_notify(dev);
839 : 0 : free_vrings:
840 : 0 : virtio_user_free_vrings(dev);
841 : 0 : destroy:
842 : 0 : dev->ops->destroy(dev);
843 : :
844 : 0 : return -1;
845 : : }
846 : :
847 : : void
848 : 0 : virtio_user_dev_uninit(struct virtio_user_dev *dev)
849 : : {
850 : 0 : struct rte_eth_dev *eth_dev = &rte_eth_devices[dev->hw.port_id];
851 : :
852 : 0 : rte_intr_instance_free(eth_dev->intr_handle);
853 : 0 : eth_dev->intr_handle = NULL;
854 : :
855 : 0 : virtio_user_stop_device(dev);
856 : :
857 : 0 : rte_mem_event_callback_unregister(VIRTIO_USER_MEM_EVENT_CLB_NAME, dev);
858 : :
859 : 0 : virtio_user_dev_uninit_notify(dev);
860 : :
861 : 0 : virtio_user_free_vrings(dev);
862 : :
863 : 0 : free(dev->ifname);
864 : :
865 [ # # ]: 0 : if (dev->is_server)
866 : 0 : unlink(dev->path);
867 : :
868 : 0 : dev->ops->destroy(dev);
869 : 0 : }
870 : :
871 : : static uint8_t
872 : 0 : virtio_user_handle_mq(struct virtio_user_dev *dev, uint16_t q_pairs)
873 : : {
874 : : uint16_t i;
875 : : uint8_t ret = 0;
876 : :
877 [ # # ]: 0 : if (q_pairs > dev->max_queue_pairs) {
878 : 0 : PMD_INIT_LOG(ERR, "(%s) multi-q config %u, but only %u supported",
879 : : dev->path, q_pairs, dev->max_queue_pairs);
880 : 0 : return -1;
881 : : }
882 : :
883 [ # # ]: 0 : for (i = 0; i < q_pairs; ++i)
884 : 0 : ret |= dev->ops->enable_qp(dev, i, 1);
885 [ # # ]: 0 : for (i = q_pairs; i < dev->max_queue_pairs; ++i)
886 : 0 : ret |= dev->ops->enable_qp(dev, i, 0);
887 : :
888 : 0 : dev->queue_pairs = q_pairs;
889 : :
890 : 0 : return ret;
891 : : }
892 : :
893 : : #define CVQ_MAX_DATA_DESCS 32
894 : :
895 : : static uint32_t
896 : 0 : virtio_user_handle_ctrl_msg_split(struct virtio_user_dev *dev, struct vring *vring,
897 : : uint16_t idx_hdr)
898 : : {
899 : : struct virtio_net_ctrl_hdr *hdr;
900 : : virtio_net_ctrl_ack status = ~0;
901 : : uint16_t i, idx_data, idx_status;
902 : : uint32_t n_descs = 0;
903 : : int dlen[CVQ_MAX_DATA_DESCS], nb_dlen = 0;
904 : :
905 : : /* locate desc for header, data, and status */
906 : 0 : idx_data = vring->desc[idx_hdr].next;
907 : : n_descs++;
908 : :
909 : : i = idx_data;
910 [ # # ]: 0 : while (vring->desc[i].flags == VRING_DESC_F_NEXT) {
911 : 0 : dlen[nb_dlen++] = vring->desc[i].len;
912 : 0 : i = vring->desc[i].next;
913 : 0 : n_descs++;
914 : : }
915 : :
916 : : /* locate desc for status */
917 : : idx_status = i;
918 : 0 : n_descs++;
919 : :
920 : 0 : hdr = (void *)(uintptr_t)vring->desc[idx_hdr].addr;
921 [ # # ]: 0 : if (hdr->class == VIRTIO_NET_CTRL_MQ &&
922 [ # # ]: 0 : hdr->cmd == VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET) {
923 : : uint16_t queues;
924 : :
925 : 0 : queues = *(uint16_t *)(uintptr_t)vring->desc[idx_data].addr;
926 : 0 : status = virtio_user_handle_mq(dev, queues);
927 [ # # # # ]: 0 : } else if (hdr->class == VIRTIO_NET_CTRL_MQ && hdr->cmd == VIRTIO_NET_CTRL_MQ_RSS_CONFIG) {
928 : : struct virtio_net_ctrl_rss *rss;
929 : :
930 : 0 : rss = (struct virtio_net_ctrl_rss *)(uintptr_t)vring->desc[idx_data].addr;
931 : 0 : status = virtio_user_handle_mq(dev, rss->max_tx_vq);
932 [ # # ]: 0 : } else if (hdr->class == VIRTIO_NET_CTRL_RX ||
933 : : hdr->class == VIRTIO_NET_CTRL_MAC ||
934 : : hdr->class == VIRTIO_NET_CTRL_VLAN) {
935 : : status = 0;
936 : : }
937 : :
938 [ # # # # ]: 0 : if (!status && dev->scvq)
939 : 0 : status = virtio_send_command(&dev->scvq->cq,
940 : : (struct virtio_pmd_ctrl *)hdr, dlen, nb_dlen);
941 : :
942 : : /* Update status */
943 : 0 : *(virtio_net_ctrl_ack *)(uintptr_t)vring->desc[idx_status].addr = status;
944 : :
945 : 0 : return n_descs;
946 : : }
947 : :
948 : : static inline int
949 : : desc_is_avail(struct vring_packed_desc *desc, bool wrap_counter)
950 : : {
951 : 0 : uint16_t flags = __atomic_load_n(&desc->flags, __ATOMIC_ACQUIRE);
952 : :
953 : 0 : return wrap_counter == !!(flags & VRING_PACKED_DESC_F_AVAIL) &&
954 [ # # ]: 0 : wrap_counter != !!(flags & VRING_PACKED_DESC_F_USED);
955 : : }
956 : :
957 : : static uint32_t
958 : 0 : virtio_user_handle_ctrl_msg_packed(struct virtio_user_dev *dev,
959 : : struct vring_packed *vring,
960 : : uint16_t idx_hdr)
961 : : {
962 : : struct virtio_net_ctrl_hdr *hdr;
963 : : virtio_net_ctrl_ack status = ~0;
964 : : uint16_t idx_data, idx_status;
965 : : /* initialize to one, header is first */
966 : : uint32_t n_descs = 1;
967 : : int dlen[CVQ_MAX_DATA_DESCS], nb_dlen = 0;
968 : :
969 : : /* locate desc for header, data, and status */
970 : 0 : idx_data = idx_hdr + 1;
971 [ # # ]: 0 : if (idx_data >= dev->queue_size)
972 : 0 : idx_data -= dev->queue_size;
973 : :
974 : : n_descs++;
975 : :
976 : : idx_status = idx_data;
977 [ # # ]: 0 : while (vring->desc[idx_status].flags & VRING_DESC_F_NEXT) {
978 : 0 : dlen[nb_dlen++] = vring->desc[idx_status].len;
979 : 0 : idx_status++;
980 [ # # ]: 0 : if (idx_status >= dev->queue_size)
981 : 0 : idx_status -= dev->queue_size;
982 : 0 : n_descs++;
983 : : }
984 : :
985 : 0 : hdr = (void *)(uintptr_t)vring->desc[idx_hdr].addr;
986 [ # # ]: 0 : if (hdr->class == VIRTIO_NET_CTRL_MQ &&
987 [ # # ]: 0 : hdr->cmd == VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET) {
988 : : uint16_t queues;
989 : :
990 : 0 : queues = *(uint16_t *)(uintptr_t)
991 : 0 : vring->desc[idx_data].addr;
992 : 0 : status = virtio_user_handle_mq(dev, queues);
993 [ # # # # ]: 0 : } else if (hdr->class == VIRTIO_NET_CTRL_MQ && hdr->cmd == VIRTIO_NET_CTRL_MQ_RSS_CONFIG) {
994 : : struct virtio_net_ctrl_rss *rss;
995 : :
996 : 0 : rss = (struct virtio_net_ctrl_rss *)(uintptr_t)vring->desc[idx_data].addr;
997 : 0 : status = virtio_user_handle_mq(dev, rss->max_tx_vq);
998 [ # # ]: 0 : } else if (hdr->class == VIRTIO_NET_CTRL_RX ||
999 : : hdr->class == VIRTIO_NET_CTRL_MAC ||
1000 : : hdr->class == VIRTIO_NET_CTRL_VLAN) {
1001 : : status = 0;
1002 : : }
1003 : :
1004 [ # # # # ]: 0 : if (!status && dev->scvq)
1005 : 0 : status = virtio_send_command(&dev->scvq->cq,
1006 : : (struct virtio_pmd_ctrl *)hdr, dlen, nb_dlen);
1007 : :
1008 : : /* Update status */
1009 : 0 : *(virtio_net_ctrl_ack *)(uintptr_t)
1010 : 0 : vring->desc[idx_status].addr = status;
1011 : :
1012 : : /* Update used descriptor */
1013 : 0 : vring->desc[idx_hdr].id = vring->desc[idx_status].id;
1014 : 0 : vring->desc[idx_hdr].len = sizeof(status);
1015 : :
1016 : 0 : return n_descs;
1017 : : }
1018 : :
1019 : : static void
1020 : 0 : virtio_user_handle_cq_packed(struct virtio_user_dev *dev, uint16_t queue_idx)
1021 : : {
1022 : 0 : struct virtio_user_queue *vq = &dev->packed_queues[queue_idx];
1023 : 0 : struct vring_packed *vring = &dev->vrings.packed[queue_idx];
1024 : : uint16_t n_descs, flags;
1025 : :
1026 : : /* Perform a load-acquire barrier in desc_is_avail to
1027 : : * enforce the ordering between desc flags and desc
1028 : : * content.
1029 : : */
1030 : 0 : while (desc_is_avail(&vring->desc[vq->used_idx],
1031 [ # # ]: 0 : vq->used_wrap_counter)) {
1032 : :
1033 : 0 : n_descs = virtio_user_handle_ctrl_msg_packed(dev, vring,
1034 : 0 : vq->used_idx);
1035 : :
1036 : : flags = VRING_DESC_F_WRITE;
1037 [ # # ]: 0 : if (vq->used_wrap_counter)
1038 : : flags |= VRING_PACKED_DESC_F_AVAIL_USED;
1039 : :
1040 : 0 : __atomic_store_n(&vring->desc[vq->used_idx].flags, flags,
1041 : : __ATOMIC_RELEASE);
1042 : :
1043 : 0 : vq->used_idx += n_descs;
1044 [ # # ]: 0 : if (vq->used_idx >= dev->queue_size) {
1045 : 0 : vq->used_idx -= dev->queue_size;
1046 : 0 : vq->used_wrap_counter ^= 1;
1047 : : }
1048 : : }
1049 : 0 : }
1050 : :
1051 : : static void
1052 : 0 : virtio_user_handle_cq_split(struct virtio_user_dev *dev, uint16_t queue_idx)
1053 : : {
1054 : : uint16_t avail_idx, desc_idx;
1055 : : struct vring_used_elem *uep;
1056 : : uint32_t n_descs;
1057 : 0 : struct vring *vring = &dev->vrings.split[queue_idx];
1058 : :
1059 : : /* Consume avail ring, using used ring idx as first one */
1060 : 0 : while (__atomic_load_n(&vring->used->idx, __ATOMIC_RELAXED)
1061 [ # # ]: 0 : != vring->avail->idx) {
1062 : 0 : avail_idx = __atomic_load_n(&vring->used->idx, __ATOMIC_RELAXED)
1063 : 0 : & (vring->num - 1);
1064 : 0 : desc_idx = vring->avail->ring[avail_idx];
1065 : :
1066 : 0 : n_descs = virtio_user_handle_ctrl_msg_split(dev, vring, desc_idx);
1067 : :
1068 : : /* Update used ring */
1069 : 0 : uep = &vring->used->ring[avail_idx];
1070 : 0 : uep->id = desc_idx;
1071 : 0 : uep->len = n_descs;
1072 : :
1073 : 0 : __atomic_fetch_add(&vring->used->idx, 1, __ATOMIC_RELAXED);
1074 : : }
1075 : 0 : }
1076 : :
1077 : : void
1078 [ # # ]: 0 : virtio_user_handle_cq(struct virtio_user_dev *dev, uint16_t queue_idx)
1079 : : {
1080 [ # # ]: 0 : if (virtio_with_packed_queue(&dev->hw))
1081 : 0 : virtio_user_handle_cq_packed(dev, queue_idx);
1082 : : else
1083 : 0 : virtio_user_handle_cq_split(dev, queue_idx);
1084 : 0 : }
1085 : :
1086 : : static void
1087 : 0 : virtio_user_control_queue_notify(struct virtqueue *vq, void *cookie)
1088 : : {
1089 : : struct virtio_user_dev *dev = cookie;
1090 : 0 : uint64_t notify_data = 1;
1091 : :
1092 [ # # ]: 0 : if (!dev->notify_area) {
1093 [ # # ]: 0 : if (write(dev->kickfds[vq->vq_queue_index], ¬ify_data, sizeof(notify_data)) < 0)
1094 : 0 : PMD_DRV_LOG(ERR, "failed to kick backend: %s",
1095 : : strerror(errno));
1096 : 0 : return;
1097 [ # # ]: 0 : } else if (!virtio_with_feature(&dev->hw, VIRTIO_F_NOTIFICATION_DATA)) {
1098 : 0 : rte_write16(vq->vq_queue_index, vq->notify_addr);
1099 : 0 : return;
1100 : : }
1101 : :
1102 [ # # ]: 0 : if (virtio_with_packed_queue(&dev->hw)) {
1103 : : /* Bit[0:15]: vq queue index
1104 : : * Bit[16:30]: avail index
1105 : : * Bit[31]: avail wrap counter
1106 : : */
1107 : 0 : notify_data = ((uint32_t)(!!(vq->vq_packed.cached_flags &
1108 : 0 : VRING_PACKED_DESC_F_AVAIL)) << 31) |
1109 : 0 : ((uint32_t)vq->vq_avail_idx << 16) |
1110 : 0 : vq->vq_queue_index;
1111 : : } else {
1112 : : /* Bit[0:15]: vq queue index
1113 : : * Bit[16:31]: avail index
1114 : : */
1115 : 0 : notify_data = ((uint32_t)vq->vq_avail_idx << 16) |
1116 : 0 : vq->vq_queue_index;
1117 : : }
1118 : 0 : rte_write32(notify_data, vq->notify_addr);
1119 : : }
1120 : :
1121 : : int
1122 : 0 : virtio_user_dev_create_shadow_cvq(struct virtio_user_dev *dev, struct virtqueue *vq)
1123 : : {
1124 : : char name[VIRTQUEUE_MAX_NAME_SZ];
1125 : : struct virtqueue *scvq;
1126 : :
1127 : 0 : snprintf(name, sizeof(name), "port%d_shadow_cvq", vq->hw->port_id);
1128 : 0 : scvq = virtqueue_alloc(&dev->hw, vq->vq_queue_index, vq->vq_nentries,
1129 : : VTNET_CQ, SOCKET_ID_ANY, name);
1130 [ # # ]: 0 : if (!scvq) {
1131 : 0 : PMD_INIT_LOG(ERR, "(%s) Failed to alloc shadow control vq\n", dev->path);
1132 : 0 : return -ENOMEM;
1133 : : }
1134 : :
1135 : 0 : scvq->cq.notify_queue = &virtio_user_control_queue_notify;
1136 : 0 : scvq->cq.notify_cookie = dev;
1137 : 0 : scvq->notify_addr = vq->notify_addr;
1138 : 0 : dev->scvq = scvq;
1139 : :
1140 : 0 : return 0;
1141 : : }
1142 : :
1143 : : void
1144 : 0 : virtio_user_dev_destroy_shadow_cvq(struct virtio_user_dev *dev)
1145 : : {
1146 [ # # ]: 0 : if (!dev->scvq)
1147 : : return;
1148 : :
1149 : 0 : virtqueue_free(dev->scvq);
1150 : 0 : dev->scvq = NULL;
1151 : : }
1152 : :
1153 : : int
1154 : 0 : virtio_user_dev_set_status(struct virtio_user_dev *dev, uint8_t status)
1155 : : {
1156 : : int ret;
1157 : :
1158 : 0 : pthread_mutex_lock(&dev->mutex);
1159 : 0 : dev->status = status;
1160 : 0 : ret = dev->ops->set_status(dev, status);
1161 [ # # ]: 0 : if (ret && ret != -ENOTSUP)
1162 : 0 : PMD_INIT_LOG(ERR, "(%s) Failed to set backend status", dev->path);
1163 : :
1164 : 0 : pthread_mutex_unlock(&dev->mutex);
1165 : 0 : return ret;
1166 : : }
1167 : :
1168 : : int
1169 : 0 : virtio_user_dev_update_status(struct virtio_user_dev *dev)
1170 : : {
1171 : : int ret;
1172 : : uint8_t status;
1173 : :
1174 : 0 : pthread_mutex_lock(&dev->mutex);
1175 : :
1176 : 0 : ret = dev->ops->get_status(dev, &status);
1177 [ # # ]: 0 : if (!ret) {
1178 : 0 : dev->status = status;
1179 : 0 : PMD_INIT_LOG(DEBUG, "Updated Device Status(0x%08x):\n"
1180 : : "\t-RESET: %u\n"
1181 : : "\t-ACKNOWLEDGE: %u\n"
1182 : : "\t-DRIVER: %u\n"
1183 : : "\t-DRIVER_OK: %u\n"
1184 : : "\t-FEATURES_OK: %u\n"
1185 : : "\t-DEVICE_NEED_RESET: %u\n"
1186 : : "\t-FAILED: %u",
1187 : : dev->status,
1188 : : (dev->status == VIRTIO_CONFIG_STATUS_RESET),
1189 : : !!(dev->status & VIRTIO_CONFIG_STATUS_ACK),
1190 : : !!(dev->status & VIRTIO_CONFIG_STATUS_DRIVER),
1191 : : !!(dev->status & VIRTIO_CONFIG_STATUS_DRIVER_OK),
1192 : : !!(dev->status & VIRTIO_CONFIG_STATUS_FEATURES_OK),
1193 : : !!(dev->status & VIRTIO_CONFIG_STATUS_DEV_NEED_RESET),
1194 : : !!(dev->status & VIRTIO_CONFIG_STATUS_FAILED));
1195 [ # # ]: 0 : } else if (ret != -ENOTSUP) {
1196 : 0 : PMD_INIT_LOG(ERR, "(%s) Failed to get backend status", dev->path);
1197 : : }
1198 : :
1199 : 0 : pthread_mutex_unlock(&dev->mutex);
1200 : 0 : return ret;
1201 : : }
1202 : :
1203 : : int
1204 : 0 : virtio_user_dev_update_link_state(struct virtio_user_dev *dev)
1205 : : {
1206 [ # # ]: 0 : if (dev->ops->update_link_state)
1207 : 0 : return dev->ops->update_link_state(dev);
1208 : :
1209 : : return 0;
1210 : : }
1211 : :
1212 : : static void
1213 : 0 : virtio_user_dev_reset_queues_packed(struct rte_eth_dev *eth_dev)
1214 : : {
1215 : 0 : struct virtio_user_dev *dev = eth_dev->data->dev_private;
1216 : : struct virtio_hw *hw = &dev->hw;
1217 : : struct virtnet_rx *rxvq;
1218 : : struct virtnet_tx *txvq;
1219 : : uint16_t i;
1220 : :
1221 : : /* Add lock to avoid queue contention. */
1222 : 0 : rte_spinlock_lock(&hw->state_lock);
1223 : 0 : hw->started = 0;
1224 : :
1225 : : /*
1226 : : * Waiting for datapath to complete before resetting queues.
1227 : : * 1 ms should be enough for the ongoing Tx/Rx function to finish.
1228 : : */
1229 : : rte_delay_ms(1);
1230 : :
1231 : : /* Vring reset for each Tx queue and Rx queue. */
1232 [ # # ]: 0 : for (i = 0; i < eth_dev->data->nb_rx_queues; i++) {
1233 : 0 : rxvq = eth_dev->data->rx_queues[i];
1234 : 0 : virtqueue_rxvq_reset_packed(virtnet_rxq_to_vq(rxvq));
1235 : 0 : virtio_dev_rx_queue_setup_finish(eth_dev, i);
1236 : : }
1237 : :
1238 [ # # ]: 0 : for (i = 0; i < eth_dev->data->nb_tx_queues; i++) {
1239 : 0 : txvq = eth_dev->data->tx_queues[i];
1240 : 0 : virtqueue_txvq_reset_packed(virtnet_txq_to_vq(txvq));
1241 : : }
1242 : :
1243 : 0 : hw->started = 1;
1244 : : rte_spinlock_unlock(&hw->state_lock);
1245 : 0 : }
1246 : :
1247 : : void
1248 : 0 : virtio_user_dev_delayed_disconnect_handler(void *param)
1249 : : {
1250 : : struct virtio_user_dev *dev = param;
1251 : 0 : struct rte_eth_dev *eth_dev = &rte_eth_devices[dev->hw.port_id];
1252 : :
1253 [ # # ]: 0 : if (rte_intr_disable(eth_dev->intr_handle) < 0) {
1254 : 0 : PMD_DRV_LOG(ERR, "interrupt disable failed");
1255 : 0 : return;
1256 : : }
1257 : 0 : PMD_DRV_LOG(DEBUG, "Unregistering intr fd: %d",
1258 : : rte_intr_fd_get(eth_dev->intr_handle));
1259 [ # # ]: 0 : if (rte_intr_callback_unregister(eth_dev->intr_handle,
1260 : : virtio_interrupt_handler,
1261 : : eth_dev) != 1)
1262 : 0 : PMD_DRV_LOG(ERR, "interrupt unregister failed");
1263 : :
1264 [ # # ]: 0 : if (dev->is_server) {
1265 [ # # ]: 0 : if (dev->ops->server_disconnect)
1266 : 0 : dev->ops->server_disconnect(dev);
1267 : :
1268 : 0 : rte_intr_fd_set(eth_dev->intr_handle,
1269 : 0 : dev->ops->get_intr_fd(dev));
1270 : :
1271 : 0 : PMD_DRV_LOG(DEBUG, "Registering intr fd: %d",
1272 : : rte_intr_fd_get(eth_dev->intr_handle));
1273 : :
1274 [ # # ]: 0 : if (rte_intr_callback_register(eth_dev->intr_handle,
1275 : : virtio_interrupt_handler,
1276 : : eth_dev))
1277 : 0 : PMD_DRV_LOG(ERR, "interrupt register failed");
1278 : :
1279 [ # # ]: 0 : if (rte_intr_enable(eth_dev->intr_handle) < 0) {
1280 : 0 : PMD_DRV_LOG(ERR, "interrupt enable failed");
1281 : 0 : return;
1282 : : }
1283 : : }
1284 : : }
1285 : :
1286 : : static void
1287 : 0 : virtio_user_dev_delayed_intr_reconfig_handler(void *param)
1288 : : {
1289 : : struct virtio_user_dev *dev = param;
1290 : 0 : struct rte_eth_dev *eth_dev = &rte_eth_devices[dev->hw.port_id];
1291 : :
1292 : 0 : PMD_DRV_LOG(DEBUG, "Unregistering intr fd: %d",
1293 : : rte_intr_fd_get(eth_dev->intr_handle));
1294 : :
1295 [ # # ]: 0 : if (rte_intr_callback_unregister(eth_dev->intr_handle,
1296 : : virtio_interrupt_handler,
1297 : : eth_dev) != 1)
1298 : 0 : PMD_DRV_LOG(ERR, "interrupt unregister failed");
1299 : :
1300 : 0 : rte_intr_fd_set(eth_dev->intr_handle, dev->ops->get_intr_fd(dev));
1301 : :
1302 : 0 : PMD_DRV_LOG(DEBUG, "Registering intr fd: %d",
1303 : : rte_intr_fd_get(eth_dev->intr_handle));
1304 : :
1305 [ # # ]: 0 : if (rte_intr_callback_register(eth_dev->intr_handle,
1306 : : virtio_interrupt_handler, eth_dev))
1307 : 0 : PMD_DRV_LOG(ERR, "interrupt register failed");
1308 : :
1309 [ # # ]: 0 : if (rte_intr_enable(eth_dev->intr_handle) < 0)
1310 : 0 : PMD_DRV_LOG(ERR, "interrupt enable failed");
1311 : 0 : }
1312 : :
1313 : : int
1314 : 0 : virtio_user_dev_server_reconnect(struct virtio_user_dev *dev)
1315 : : {
1316 : : int ret, old_status;
1317 : 0 : struct rte_eth_dev *eth_dev = &rte_eth_devices[dev->hw.port_id];
1318 : 0 : struct virtio_hw *hw = &dev->hw;
1319 : :
1320 [ # # ]: 0 : if (!dev->ops->server_reconnect) {
1321 : 0 : PMD_DRV_LOG(ERR, "(%s) Missing server reconnect callback", dev->path);
1322 : 0 : return -1;
1323 : : }
1324 : :
1325 [ # # ]: 0 : if (dev->ops->server_reconnect(dev)) {
1326 : 0 : PMD_DRV_LOG(ERR, "(%s) Reconnect callback call failed", dev->path);
1327 : 0 : return -1;
1328 : : }
1329 : :
1330 : 0 : old_status = dev->status;
1331 : :
1332 : 0 : virtio_reset(hw);
1333 : :
1334 : 0 : virtio_set_status(hw, VIRTIO_CONFIG_STATUS_ACK);
1335 : :
1336 : 0 : virtio_set_status(hw, VIRTIO_CONFIG_STATUS_DRIVER);
1337 : :
1338 [ # # ]: 0 : if (dev->ops->get_features(dev, &dev->device_features) < 0) {
1339 : 0 : PMD_INIT_LOG(ERR, "get_features failed: %s",
1340 : : strerror(errno));
1341 : 0 : return -1;
1342 : : }
1343 : :
1344 : : /* unmask vhost-user unsupported features */
1345 : 0 : dev->device_features &= ~(dev->unsupported_features);
1346 : :
1347 [ # # ]: 0 : dev->features &= (dev->device_features | dev->frontend_features);
1348 : :
1349 : : /* For packed ring, resetting queues is required in reconnection. */
1350 [ # # # # ]: 0 : if (virtio_with_packed_queue(hw) &&
1351 : : (old_status & VIRTIO_CONFIG_STATUS_DRIVER_OK)) {
1352 : 0 : PMD_INIT_LOG(NOTICE, "Packets on the fly will be dropped"
1353 : : " when packed ring reconnecting.");
1354 : 0 : virtio_user_dev_reset_queues_packed(eth_dev);
1355 : : }
1356 : :
1357 : 0 : virtio_set_status(hw, VIRTIO_CONFIG_STATUS_FEATURES_OK);
1358 : :
1359 : : /* Start the device */
1360 : 0 : virtio_set_status(hw, VIRTIO_CONFIG_STATUS_DRIVER_OK);
1361 [ # # ]: 0 : if (!dev->started)
1362 : : return -1;
1363 : :
1364 [ # # ]: 0 : if (dev->queue_pairs > 1) {
1365 : 0 : ret = virtio_user_handle_mq(dev, dev->queue_pairs);
1366 [ # # ]: 0 : if (ret != 0) {
1367 : 0 : PMD_INIT_LOG(ERR, "Fails to enable multi-queue pairs!");
1368 : 0 : return -1;
1369 : : }
1370 : : }
1371 [ # # ]: 0 : if (eth_dev->data->dev_flags & RTE_ETH_DEV_INTR_LSC) {
1372 [ # # ]: 0 : if (rte_intr_disable(eth_dev->intr_handle) < 0) {
1373 : 0 : PMD_DRV_LOG(ERR, "interrupt disable failed");
1374 : 0 : return -1;
1375 : : }
1376 : : /*
1377 : : * This function can be called from the interrupt handler, so
1378 : : * we can't unregister interrupt handler here. Setting
1379 : : * alarm to do that later.
1380 : : */
1381 : 0 : rte_eal_alarm_set(1,
1382 : : virtio_user_dev_delayed_intr_reconfig_handler,
1383 : : (void *)dev);
1384 : : }
1385 : 0 : PMD_INIT_LOG(NOTICE, "server mode virtio-user reconnection succeeds!");
1386 : 0 : return 0;
1387 : : }
|