xref: /spdk/lib/virtio/virtio.c (revision b02581a89058ebaebe03bd0e16e3b58adfe406c1)
1 /*   SPDX-License-Identifier: BSD-3-Clause
2  *   Copyright (C) 2010-2016 Intel Corporation. All rights reserved.
3  *   All rights reserved.
4  */
5 
6 #include "spdk/stdinc.h"
7 
8 #include "spdk/env.h"
9 #include "spdk/util.h"
10 #include "spdk/barrier.h"
11 
12 #include "spdk_internal/virtio.h"
13 
14 /* We use SMP memory barrier variants as all virtio_pci devices
15  * are purely virtual. All MMIO is executed on a CPU core, so
16  * there's no need to do full MMIO synchronization.
17  */
18 #define virtio_mb()	spdk_smp_mb()
19 #define virtio_rmb()	spdk_smp_rmb()
20 #define virtio_wmb()	spdk_smp_wmb()
21 
22 /* Chain all the descriptors in the ring with an END */
23 static inline void
24 vring_desc_init(struct vring_desc *dp, uint16_t n)
25 {
26 	uint16_t i;
27 
28 	for (i = 0; i < n - 1; i++) {
29 		dp[i].next = (uint16_t)(i + 1);
30 	}
31 	dp[i].next = VQ_RING_DESC_CHAIN_END;
32 }
33 
34 static void
35 virtio_init_vring(struct virtqueue *vq)
36 {
37 	int size = vq->vq_nentries;
38 	struct vring *vr = &vq->vq_ring;
39 	uint8_t *ring_mem = vq->vq_ring_virt_mem;
40 
41 	/*
42 	 * Reinitialise since virtio port might have been stopped and restarted
43 	 */
44 	memset(ring_mem, 0, vq->vq_ring_size);
45 	vring_init(vr, size, ring_mem, VIRTIO_PCI_VRING_ALIGN);
46 	vq->vq_used_cons_idx = 0;
47 	vq->vq_desc_head_idx = 0;
48 	vq->vq_avail_idx = 0;
49 	vq->vq_desc_tail_idx = (uint16_t)(vq->vq_nentries - 1);
50 	vq->vq_free_cnt = vq->vq_nentries;
51 	vq->req_start = VQ_RING_DESC_CHAIN_END;
52 	vq->req_end = VQ_RING_DESC_CHAIN_END;
53 	vq->reqs_finished = 0;
54 	memset(vq->vq_descx, 0, sizeof(struct vq_desc_extra) * vq->vq_nentries);
55 
56 	vring_desc_init(vr->desc, size);
57 
58 	/* Tell the backend not to interrupt us.
59 	 * If F_EVENT_IDX is negotiated, we will always set incredibly high
60 	 * used event idx, so that we will practically never receive an
61 	 * interrupt. See virtqueue_req_flush()
62 	 */
63 	if (vq->vdev->negotiated_features & (1ULL << VIRTIO_RING_F_EVENT_IDX)) {
64 		vring_used_event(&vq->vq_ring) = UINT16_MAX;
65 	} else {
66 		vq->vq_ring.avail->flags |= VRING_AVAIL_F_NO_INTERRUPT;
67 	}
68 }
69 
70 static int
71 virtio_init_queue(struct virtio_dev *dev, uint16_t vtpci_queue_idx)
72 {
73 	unsigned int vq_size, size;
74 	struct virtqueue *vq;
75 	int rc;
76 
77 	SPDK_DEBUGLOG(virtio_dev, "setting up queue: %"PRIu16"\n", vtpci_queue_idx);
78 
79 	/*
80 	 * Read the virtqueue size from the Queue Size field
81 	 * Always power of 2 and if 0 virtqueue does not exist
82 	 */
83 	vq_size = virtio_dev_backend_ops(dev)->get_queue_size(dev, vtpci_queue_idx);
84 	SPDK_DEBUGLOG(virtio_dev, "vq_size: %u\n", vq_size);
85 	if (vq_size == 0) {
86 		SPDK_ERRLOG("virtqueue %"PRIu16" does not exist\n", vtpci_queue_idx);
87 		return -EINVAL;
88 	}
89 
90 	if (!spdk_u32_is_pow2(vq_size)) {
91 		SPDK_ERRLOG("virtqueue %"PRIu16" size (%u) is not powerof 2\n",
92 			    vtpci_queue_idx, vq_size);
93 		return -EINVAL;
94 	}
95 
96 	size = sizeof(*vq) + vq_size * sizeof(struct vq_desc_extra);
97 
98 	if (posix_memalign((void **)&vq, SPDK_CACHE_LINE_SIZE, size)) {
99 		SPDK_ERRLOG("can not allocate vq\n");
100 		return -ENOMEM;
101 	}
102 	memset(vq, 0, size);
103 	dev->vqs[vtpci_queue_idx] = vq;
104 
105 	vq->vdev = dev;
106 	vq->vq_queue_index = vtpci_queue_idx;
107 	vq->vq_nentries = vq_size;
108 
109 	/*
110 	 * Reserve a memzone for vring elements
111 	 */
112 	size = vring_size(vq_size, VIRTIO_PCI_VRING_ALIGN);
113 	vq->vq_ring_size = SPDK_ALIGN_CEIL(size, VIRTIO_PCI_VRING_ALIGN);
114 	SPDK_DEBUGLOG(virtio_dev, "vring_size: %u, rounded_vring_size: %u\n",
115 		      size, vq->vq_ring_size);
116 
117 	vq->owner_thread = NULL;
118 
119 	rc = virtio_dev_backend_ops(dev)->setup_queue(dev, vq);
120 	if (rc < 0) {
121 		SPDK_ERRLOG("setup_queue failed\n");
122 		free(vq);
123 		dev->vqs[vtpci_queue_idx] = NULL;
124 		return rc;
125 	}
126 
127 	SPDK_DEBUGLOG(virtio_dev, "vq->vq_ring_mem:      0x%" PRIx64 "\n",
128 		      vq->vq_ring_mem);
129 	SPDK_DEBUGLOG(virtio_dev, "vq->vq_ring_virt_mem: 0x%" PRIx64 "\n",
130 		      (uint64_t)(uintptr_t)vq->vq_ring_virt_mem);
131 
132 	virtio_init_vring(vq);
133 	return 0;
134 }
135 
136 static void
137 virtio_free_queues(struct virtio_dev *dev)
138 {
139 	uint16_t nr_vq = dev->max_queues;
140 	struct virtqueue *vq;
141 	uint16_t i;
142 
143 	if (dev->vqs == NULL) {
144 		return;
145 	}
146 
147 	for (i = 0; i < nr_vq; i++) {
148 		vq = dev->vqs[i];
149 		if (!vq) {
150 			continue;
151 		}
152 
153 		virtio_dev_backend_ops(dev)->del_queue(dev, vq);
154 
155 		free(vq);
156 		dev->vqs[i] = NULL;
157 	}
158 
159 	free(dev->vqs);
160 	dev->vqs = NULL;
161 }
162 
163 static int
164 virtio_alloc_queues(struct virtio_dev *dev, uint16_t max_queues, uint16_t fixed_vq_num)
165 {
166 	uint16_t i;
167 	int ret;
168 
169 	if (max_queues == 0) {
170 		/* perfectly fine to have a device with no virtqueues. */
171 		return 0;
172 	}
173 
174 	assert(dev->vqs == NULL);
175 	dev->vqs = calloc(1, sizeof(struct virtqueue *) * max_queues);
176 	if (!dev->vqs) {
177 		SPDK_ERRLOG("failed to allocate %"PRIu16" vqs\n", max_queues);
178 		return -ENOMEM;
179 	}
180 
181 	for (i = 0; i < max_queues; i++) {
182 		ret = virtio_init_queue(dev, i);
183 		if (ret < 0) {
184 			virtio_free_queues(dev);
185 			return ret;
186 		}
187 	}
188 
189 	dev->max_queues = max_queues;
190 	dev->fixed_queues_num = fixed_vq_num;
191 	return 0;
192 }
193 
194 /**
195  * Negotiate virtio features. For virtio_user this will also set
196  * dev->modern flag if VIRTIO_F_VERSION_1 flag is negotiated.
197  */
198 static int
199 virtio_negotiate_features(struct virtio_dev *dev, uint64_t req_features)
200 {
201 	uint64_t host_features = virtio_dev_backend_ops(dev)->get_features(dev);
202 	int rc;
203 
204 	SPDK_DEBUGLOG(virtio_dev, "guest features = %" PRIx64 "\n", req_features);
205 	SPDK_DEBUGLOG(virtio_dev, "device features = %" PRIx64 "\n", host_features);
206 
207 	rc = virtio_dev_backend_ops(dev)->set_features(dev, req_features & host_features);
208 	if (rc != 0) {
209 		SPDK_ERRLOG("failed to negotiate device features.\n");
210 		return rc;
211 	}
212 
213 	SPDK_DEBUGLOG(virtio_dev, "negotiated features = %" PRIx64 "\n",
214 		      dev->negotiated_features);
215 
216 	virtio_dev_set_status(dev, VIRTIO_CONFIG_S_FEATURES_OK);
217 	if (!(virtio_dev_get_status(dev) & VIRTIO_CONFIG_S_FEATURES_OK)) {
218 		SPDK_ERRLOG("failed to set FEATURES_OK status!\n");
219 		/* either the device failed, or we offered some features that
220 		 * depend on other, not offered features.
221 		 */
222 		return -EINVAL;
223 	}
224 
225 	return 0;
226 }
227 
228 int
229 virtio_dev_construct(struct virtio_dev *vdev, const char *name,
230 		     const struct virtio_dev_ops *ops, void *ctx)
231 {
232 	int rc;
233 
234 	vdev->name = strdup(name);
235 	if (vdev->name == NULL) {
236 		return -ENOMEM;
237 	}
238 
239 	rc = pthread_mutex_init(&vdev->mutex, NULL);
240 	if (rc != 0) {
241 		free(vdev->name);
242 		return -rc;
243 	}
244 
245 	vdev->backend_ops = ops;
246 	vdev->ctx = ctx;
247 
248 	return 0;
249 }
250 
251 int
252 virtio_dev_reset(struct virtio_dev *dev, uint64_t req_features)
253 {
254 	req_features |= (1ULL << VIRTIO_F_VERSION_1);
255 
256 	virtio_dev_stop(dev);
257 
258 	virtio_dev_set_status(dev, VIRTIO_CONFIG_S_ACKNOWLEDGE);
259 	if (!(virtio_dev_get_status(dev) & VIRTIO_CONFIG_S_ACKNOWLEDGE)) {
260 		SPDK_ERRLOG("Failed to set VIRTIO_CONFIG_S_ACKNOWLEDGE status.\n");
261 		return -EIO;
262 	}
263 
264 	virtio_dev_set_status(dev, VIRTIO_CONFIG_S_DRIVER);
265 	if (!(virtio_dev_get_status(dev) & VIRTIO_CONFIG_S_DRIVER)) {
266 		SPDK_ERRLOG("Failed to set VIRTIO_CONFIG_S_DRIVER status.\n");
267 		return -EIO;
268 	}
269 
270 	return virtio_negotiate_features(dev, req_features);
271 }
272 
273 int
274 virtio_dev_start(struct virtio_dev *vdev, uint16_t max_queues, uint16_t fixed_queue_num)
275 {
276 	int ret;
277 
278 	ret = virtio_alloc_queues(vdev, max_queues, fixed_queue_num);
279 	if (ret < 0) {
280 		return ret;
281 	}
282 
283 	virtio_dev_set_status(vdev, VIRTIO_CONFIG_S_DRIVER_OK);
284 	if (!(virtio_dev_get_status(vdev) & VIRTIO_CONFIG_S_DRIVER_OK)) {
285 		SPDK_ERRLOG("Failed to set VIRTIO_CONFIG_S_DRIVER_OK status.\n");
286 		return -1;
287 	}
288 
289 	return 0;
290 }
291 
292 void
293 virtio_dev_destruct(struct virtio_dev *dev)
294 {
295 	virtio_dev_backend_ops(dev)->destruct_dev(dev);
296 	pthread_mutex_destroy(&dev->mutex);
297 	free(dev->name);
298 }
299 
300 static void
301 vq_ring_free_chain(struct virtqueue *vq, uint16_t desc_idx)
302 {
303 	struct vring_desc *dp, *dp_tail;
304 	struct vq_desc_extra *dxp;
305 	uint16_t desc_idx_last = desc_idx;
306 
307 	dp  = &vq->vq_ring.desc[desc_idx];
308 	dxp = &vq->vq_descx[desc_idx];
309 	vq->vq_free_cnt = (uint16_t)(vq->vq_free_cnt + dxp->ndescs);
310 	if ((dp->flags & VRING_DESC_F_INDIRECT) == 0) {
311 		while (dp->flags & VRING_DESC_F_NEXT) {
312 			desc_idx_last = dp->next;
313 			dp = &vq->vq_ring.desc[dp->next];
314 		}
315 	}
316 	dxp->ndescs = 0;
317 
318 	/*
319 	 * We must append the existing free chain, if any, to the end of
320 	 * newly freed chain. If the virtqueue was completely used, then
321 	 * head would be VQ_RING_DESC_CHAIN_END (ASSERTed above).
322 	 */
323 	if (vq->vq_desc_tail_idx == VQ_RING_DESC_CHAIN_END) {
324 		vq->vq_desc_head_idx = desc_idx;
325 	} else {
326 		dp_tail = &vq->vq_ring.desc[vq->vq_desc_tail_idx];
327 		dp_tail->next = desc_idx;
328 	}
329 
330 	vq->vq_desc_tail_idx = desc_idx_last;
331 	dp->next = VQ_RING_DESC_CHAIN_END;
332 }
333 
334 static uint16_t
335 virtqueue_dequeue_burst_rx(struct virtqueue *vq, void **rx_pkts,
336 			   uint32_t *len, uint16_t num)
337 {
338 	struct vring_used_elem *uep;
339 	void *cookie;
340 	uint16_t used_idx, desc_idx;
341 	uint16_t i;
342 
343 	/*  Caller does the check */
344 	for (i = 0; i < num ; i++) {
345 		used_idx = (uint16_t)(vq->vq_used_cons_idx & (vq->vq_nentries - 1));
346 		uep = &vq->vq_ring.used->ring[used_idx];
347 		desc_idx = (uint16_t) uep->id;
348 		len[i] = uep->len;
349 		cookie = vq->vq_descx[desc_idx].cookie;
350 
351 		if (spdk_unlikely(cookie == NULL)) {
352 			SPDK_WARNLOG("vring descriptor with no mbuf cookie at %"PRIu16"\n",
353 				     vq->vq_used_cons_idx);
354 			break;
355 		}
356 
357 		__builtin_prefetch(cookie);
358 
359 		rx_pkts[i]  = cookie;
360 		vq->vq_used_cons_idx++;
361 		vq_ring_free_chain(vq, desc_idx);
362 		vq->vq_descx[desc_idx].cookie = NULL;
363 	}
364 
365 	return i;
366 }
367 
368 static void
369 finish_req(struct virtqueue *vq)
370 {
371 	struct vring_desc *desc;
372 	uint16_t avail_idx;
373 
374 	desc = &vq->vq_ring.desc[vq->req_end];
375 	desc->flags &= ~VRING_DESC_F_NEXT;
376 
377 	/*
378 	 * Place the head of the descriptor chain into the next slot and make
379 	 * it usable to the host. The chain is made available now rather than
380 	 * deferring to virtqueue_req_flush() in the hopes that if the host is
381 	 * currently running on another CPU, we can keep it processing the new
382 	 * descriptor.
383 	 */
384 	avail_idx = (uint16_t)(vq->vq_avail_idx & (vq->vq_nentries - 1));
385 	vq->vq_ring.avail->ring[avail_idx] = vq->req_start;
386 	vq->vq_avail_idx++;
387 	vq->req_end = VQ_RING_DESC_CHAIN_END;
388 	virtio_wmb();
389 	vq->vq_ring.avail->idx = vq->vq_avail_idx;
390 	vq->reqs_finished++;
391 }
392 
393 int
394 virtqueue_req_start(struct virtqueue *vq, void *cookie, int iovcnt)
395 {
396 	struct vq_desc_extra *dxp;
397 
398 	/* Reserve enough entries to handle iov split */
399 	if (2 * iovcnt > vq->vq_free_cnt) {
400 		return iovcnt > vq->vq_nentries ? -EINVAL : -ENOMEM;
401 	}
402 
403 	if (vq->req_end != VQ_RING_DESC_CHAIN_END) {
404 		finish_req(vq);
405 	}
406 
407 	vq->req_start = vq->vq_desc_head_idx;
408 	dxp = &vq->vq_descx[vq->req_start];
409 	dxp->cookie = cookie;
410 	dxp->ndescs = 0;
411 
412 	return 0;
413 }
414 
415 void
416 virtqueue_req_flush(struct virtqueue *vq)
417 {
418 	uint16_t reqs_finished;
419 
420 	if (vq->req_end == VQ_RING_DESC_CHAIN_END) {
421 		/* no non-empty requests have been started */
422 		return;
423 	}
424 
425 	finish_req(vq);
426 	virtio_mb();
427 
428 	reqs_finished = vq->reqs_finished;
429 	vq->reqs_finished = 0;
430 
431 	if (vq->vdev->negotiated_features & (1ULL << VIRTIO_RING_F_EVENT_IDX)) {
432 		/* Set used event idx to a value the device will never reach.
433 		 * This effectively disables interrupts.
434 		 */
435 		vring_used_event(&vq->vq_ring) = vq->vq_used_cons_idx - vq->vq_nentries - 1;
436 
437 		if (!vring_need_event(vring_avail_event(&vq->vq_ring),
438 				      vq->vq_avail_idx,
439 				      vq->vq_avail_idx - reqs_finished)) {
440 			return;
441 		}
442 	} else if (vq->vq_ring.used->flags & VRING_USED_F_NO_NOTIFY) {
443 		return;
444 	}
445 
446 	virtio_dev_backend_ops(vq->vdev)->notify_queue(vq->vdev, vq);
447 	SPDK_DEBUGLOG(virtio_dev, "Notified backend after xmit\n");
448 }
449 
450 void
451 virtqueue_req_abort(struct virtqueue *vq)
452 {
453 	struct vring_desc *desc;
454 
455 	if (vq->req_start == VQ_RING_DESC_CHAIN_END) {
456 		/* no requests have been started */
457 		return;
458 	}
459 
460 	desc = &vq->vq_ring.desc[vq->req_end];
461 	desc->flags &= ~VRING_DESC_F_NEXT;
462 
463 	vq_ring_free_chain(vq, vq->req_start);
464 	vq->req_start = VQ_RING_DESC_CHAIN_END;
465 }
466 
467 void
468 virtqueue_req_add_iovs(struct virtqueue *vq, struct iovec *iovs, uint16_t iovcnt,
469 		       enum spdk_virtio_desc_type desc_type)
470 {
471 	struct vring_desc *desc;
472 	struct vq_desc_extra *dxp;
473 	uint16_t i, prev_head, new_head;
474 	uint64_t processed_length, iovec_length, current_length;
475 	void *current_base;
476 	uint16_t used_desc_count = 0;
477 
478 	assert(vq->req_start != VQ_RING_DESC_CHAIN_END);
479 	assert(iovcnt <= vq->vq_free_cnt);
480 
481 	/* TODO use indirect descriptors if iovcnt is high enough
482 	 * or the caller specifies SPDK_VIRTIO_DESC_F_INDIRECT
483 	 */
484 
485 	prev_head = vq->req_end;
486 	new_head = vq->vq_desc_head_idx;
487 	for (i = 0; i < iovcnt; ++i) {
488 		processed_length = 0;
489 		iovec_length = iovs[i].iov_len;
490 		current_base = iovs[i].iov_base;
491 
492 		while (processed_length < iovec_length) {
493 			desc = &vq->vq_ring.desc[new_head];
494 			current_length = iovec_length - processed_length;
495 
496 			if (!vq->vdev->is_hw) {
497 				desc->addr  = (uintptr_t)current_base;
498 			} else {
499 				desc->addr = spdk_vtophys(current_base, &current_length);
500 			}
501 
502 			desc->len = current_length;
503 			/* always set NEXT flag. unset it on the last descriptor
504 			 * in the request-ending function.
505 			 */
506 			desc->flags = desc_type | VRING_DESC_F_NEXT;
507 
508 			prev_head = new_head;
509 			new_head = desc->next;
510 			used_desc_count++;
511 
512 			processed_length += current_length;
513 			current_base += current_length;
514 		}
515 	}
516 
517 	dxp = &vq->vq_descx[vq->req_start];
518 	dxp->ndescs += used_desc_count;
519 
520 	vq->req_end = prev_head;
521 	vq->vq_desc_head_idx = new_head;
522 	vq->vq_free_cnt = (uint16_t)(vq->vq_free_cnt - used_desc_count);
523 	if (vq->vq_desc_head_idx == VQ_RING_DESC_CHAIN_END) {
524 		assert(vq->vq_free_cnt == 0);
525 		vq->vq_desc_tail_idx = VQ_RING_DESC_CHAIN_END;
526 	}
527 }
528 
529 #define DESC_PER_CACHELINE (SPDK_CACHE_LINE_SIZE / sizeof(struct vring_desc))
530 uint16_t
531 virtio_recv_pkts(struct virtqueue *vq, void **io, uint32_t *len, uint16_t nb_pkts)
532 {
533 	uint16_t nb_used, num;
534 
535 	nb_used = vq->vq_ring.used->idx - vq->vq_used_cons_idx;
536 	virtio_rmb();
537 
538 	num = (uint16_t)(spdk_likely(nb_used <= nb_pkts) ? nb_used : nb_pkts);
539 	if (spdk_likely(num > DESC_PER_CACHELINE)) {
540 		num = num - ((vq->vq_used_cons_idx + num) % DESC_PER_CACHELINE);
541 	}
542 
543 	return virtqueue_dequeue_burst_rx(vq, io, len, num);
544 }
545 
546 int
547 virtio_dev_acquire_queue(struct virtio_dev *vdev, uint16_t index)
548 {
549 	struct virtqueue *vq = NULL;
550 
551 	if (index >= vdev->max_queues) {
552 		SPDK_ERRLOG("requested vq index %"PRIu16" exceeds max queue count %"PRIu16".\n",
553 			    index, vdev->max_queues);
554 		return -1;
555 	}
556 
557 	pthread_mutex_lock(&vdev->mutex);
558 	vq = vdev->vqs[index];
559 	if (vq == NULL || vq->owner_thread != NULL) {
560 		pthread_mutex_unlock(&vdev->mutex);
561 		return -1;
562 	}
563 
564 	vq->owner_thread = spdk_get_thread();
565 	pthread_mutex_unlock(&vdev->mutex);
566 	return 0;
567 }
568 
569 int32_t
570 virtio_dev_find_and_acquire_queue(struct virtio_dev *vdev, uint16_t start_index)
571 {
572 	struct virtqueue *vq = NULL;
573 	uint16_t i;
574 
575 	pthread_mutex_lock(&vdev->mutex);
576 	for (i = start_index; i < vdev->max_queues; ++i) {
577 		vq = vdev->vqs[i];
578 		if (vq != NULL && vq->owner_thread == NULL) {
579 			break;
580 		}
581 	}
582 
583 	if (vq == NULL || i == vdev->max_queues) {
584 		SPDK_ERRLOG("no more unused virtio queues with idx >= %"PRIu16".\n", start_index);
585 		pthread_mutex_unlock(&vdev->mutex);
586 		return -1;
587 	}
588 
589 	vq->owner_thread = spdk_get_thread();
590 	pthread_mutex_unlock(&vdev->mutex);
591 	return i;
592 }
593 
594 struct spdk_thread *
595 virtio_dev_queue_get_thread(struct virtio_dev *vdev, uint16_t index)
596 {
597 	struct spdk_thread *thread = NULL;
598 
599 	if (index >= vdev->max_queues) {
600 		SPDK_ERRLOG("given vq index %"PRIu16" exceeds max queue count %"PRIu16"\n",
601 			    index, vdev->max_queues);
602 		abort(); /* This is not recoverable */
603 	}
604 
605 	pthread_mutex_lock(&vdev->mutex);
606 	thread = vdev->vqs[index]->owner_thread;
607 	pthread_mutex_unlock(&vdev->mutex);
608 
609 	return thread;
610 }
611 
612 bool
613 virtio_dev_queue_is_acquired(struct virtio_dev *vdev, uint16_t index)
614 {
615 	return virtio_dev_queue_get_thread(vdev, index) != NULL;
616 }
617 
618 void
619 virtio_dev_release_queue(struct virtio_dev *vdev, uint16_t index)
620 {
621 	struct virtqueue *vq = NULL;
622 
623 	if (index >= vdev->max_queues) {
624 		SPDK_ERRLOG("given vq index %"PRIu16" exceeds max queue count %"PRIu16".\n",
625 			    index, vdev->max_queues);
626 		return;
627 	}
628 
629 	pthread_mutex_lock(&vdev->mutex);
630 	vq = vdev->vqs[index];
631 	if (vq == NULL) {
632 		SPDK_ERRLOG("virtqueue at index %"PRIu16" is not initialized.\n", index);
633 		pthread_mutex_unlock(&vdev->mutex);
634 		return;
635 	}
636 
637 	assert(vq->owner_thread == spdk_get_thread());
638 	vq->owner_thread = NULL;
639 	pthread_mutex_unlock(&vdev->mutex);
640 }
641 
642 int
643 virtio_dev_read_dev_config(struct virtio_dev *dev, size_t offset,
644 			   void *dst, int length)
645 {
646 	return virtio_dev_backend_ops(dev)->read_dev_cfg(dev, offset, dst, length);
647 }
648 
649 int
650 virtio_dev_write_dev_config(struct virtio_dev *dev, size_t offset,
651 			    const void *src, int length)
652 {
653 	return virtio_dev_backend_ops(dev)->write_dev_cfg(dev, offset, src, length);
654 }
655 
656 void
657 virtio_dev_stop(struct virtio_dev *dev)
658 {
659 	virtio_dev_backend_ops(dev)->set_status(dev, VIRTIO_CONFIG_S_RESET);
660 	/* flush status write */
661 	virtio_dev_backend_ops(dev)->get_status(dev);
662 	virtio_free_queues(dev);
663 }
664 
665 void
666 virtio_dev_set_status(struct virtio_dev *dev, uint8_t status)
667 {
668 	if (status != VIRTIO_CONFIG_S_RESET) {
669 		status |= virtio_dev_backend_ops(dev)->get_status(dev);
670 	}
671 
672 	virtio_dev_backend_ops(dev)->set_status(dev, status);
673 }
674 
675 uint8_t
676 virtio_dev_get_status(struct virtio_dev *dev)
677 {
678 	return virtio_dev_backend_ops(dev)->get_status(dev);
679 }
680 
681 const struct virtio_dev_ops *
682 virtio_dev_backend_ops(struct virtio_dev *dev)
683 {
684 	return dev->backend_ops;
685 }
686 
687 void
688 virtio_dev_dump_json_info(struct virtio_dev *hw, struct spdk_json_write_ctx *w)
689 {
690 	spdk_json_write_named_object_begin(w, "virtio");
691 
692 	spdk_json_write_named_uint32(w, "vq_count", hw->max_queues);
693 
694 	spdk_json_write_named_uint32(w, "vq_size",
695 				     virtio_dev_backend_ops(hw)->get_queue_size(hw, 0));
696 
697 	virtio_dev_backend_ops(hw)->dump_json_info(hw, w);
698 
699 	spdk_json_write_object_end(w);
700 }
701 
702 SPDK_LOG_REGISTER_COMPONENT(virtio_dev)
703