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