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