Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright (C) 2022 Intel Corporation.
3 : : * All rights reserved.
4 : : */
5 : :
6 : : /*
7 : : * virtio over vfio-user common library
8 : : */
9 : : #include "spdk/env.h"
10 : : #include "spdk/bdev.h"
11 : : #include "spdk/bdev_module.h"
12 : : #include "spdk/stdinc.h"
13 : : #include "spdk/assert.h"
14 : : #include "spdk/barrier.h"
15 : : #include "spdk/thread.h"
16 : : #include "spdk/memory.h"
17 : : #include "spdk/util.h"
18 : : #include "spdk/log.h"
19 : : #include "spdk/string.h"
20 : : #include "spdk/likely.h"
21 : :
22 : : #include "vfu_virtio_internal.h"
23 : :
24 : : static int vfu_virtio_dev_start(struct vfu_virtio_dev *dev);
25 : : static int vfu_virtio_dev_stop(struct vfu_virtio_dev *dev);
26 : :
27 : : static inline void
28 : 114 : vfu_virtio_unmap_q(struct vfu_virtio_dev *dev, struct q_mapping *mapping)
29 : : {
30 : 114 : struct vfu_virtio_endpoint *virtio_endpoint = dev->virtio_endpoint;
31 : :
32 [ + + ]: 114 : if (mapping->addr != NULL) {
33 : 78 : spdk_vfu_unmap_sg(virtio_endpoint->endpoint, mapping->sg,
34 : : &mapping->iov, 1);
35 : 78 : mapping->addr = NULL;
36 : 78 : mapping->len = 0;
37 : : }
38 : 114 : }
39 : :
40 : : static inline int
41 : 98 : vfu_virtio_map_q(struct vfu_virtio_dev *dev, struct q_mapping *mapping, uint64_t phys_addr,
42 : : uint64_t len)
43 : : {
44 : 98 : struct vfu_virtio_endpoint *virtio_endpoint = dev->virtio_endpoint;
45 : : void *addr;
46 : :
47 [ + - + - : 98 : if (!mapping->addr && len && phys_addr) {
+ - ]
48 : 98 : addr = spdk_vfu_map_one(virtio_endpoint->endpoint, phys_addr, len,
49 : : mapping->sg, &mapping->iov, PROT_READ | PROT_WRITE);
50 [ + + ]: 98 : if (addr == NULL) {
51 : 20 : return -EINVAL;
52 : : }
53 : 78 : mapping->phys_addr = phys_addr;
54 : 78 : mapping->len = len;
55 : 78 : mapping->addr = addr;
56 : : }
57 : :
58 : 78 : return 0;
59 : : }
60 : :
61 : : static int
62 : 220 : virtio_dev_map_vq(struct vfu_virtio_dev *dev, struct vfu_virtio_vq *vq)
63 : : {
64 : : int ret;
65 : : uint64_t phys_addr, len;
66 : :
67 [ - + + + : 220 : if (!vq->enabled || (vq->q_state == VFU_VQ_ACTIVE)) {
+ + ]
68 : 174 : return 0;
69 : : }
70 : :
71 [ - + + + ]: 46 : SPDK_DEBUGLOG(vfu_virtio, "%s: try to map vq %u\n", dev->name, vq->id);
72 : :
73 : 46 : len = virtio_queue_desc_size(dev, vq);
74 : 46 : phys_addr = ((((uint64_t)vq->desc_hi) << 32) | vq->desc_lo);
75 : 46 : ret = vfu_virtio_map_q(dev, &vq->desc, phys_addr, len);
76 [ + + ]: 46 : if (ret) {
77 [ - + - + ]: 20 : SPDK_DEBUGLOG(vfu_virtio, "Error to map descs\n");
78 : 20 : return ret;
79 : : }
80 : :
81 : 26 : len = virtio_queue_avail_size(dev, vq);
82 : 26 : phys_addr = ((((uint64_t)vq->avail_hi) << 32) | vq->avail_lo);
83 : 26 : ret = vfu_virtio_map_q(dev, &vq->avail, phys_addr, len);
84 [ - + ]: 26 : if (ret) {
85 : 0 : vfu_virtio_unmap_q(dev, &vq->desc);
86 [ # # # # ]: 0 : SPDK_DEBUGLOG(vfu_virtio, "Error to map available ring\n");
87 : 0 : return ret;
88 : : }
89 : :
90 : 26 : len = virtio_queue_used_size(dev, vq);
91 : 26 : phys_addr = ((((uint64_t)vq->used_hi) << 32) | vq->used_lo);
92 : 26 : ret = vfu_virtio_map_q(dev, &vq->used, phys_addr, len);
93 [ - + ]: 26 : if (ret) {
94 : 0 : vfu_virtio_unmap_q(dev, &vq->desc);
95 : 0 : vfu_virtio_unmap_q(dev, &vq->avail);
96 [ # # # # ]: 0 : SPDK_DEBUGLOG(vfu_virtio, "Error to map used ring\n");
97 : 0 : return ret;
98 : : }
99 : :
100 : : /* We're running with polling mode */
101 [ + + ]: 26 : if (virtio_guest_has_feature(dev, VIRTIO_F_RING_PACKED)) {
102 : 12 : vq->used.device_event->flags = VRING_PACKED_EVENT_FLAG_DISABLE;
103 : : } else {
104 : 14 : vq->used.used->flags = VRING_USED_F_NO_NOTIFY;
105 : : }
106 : :
107 [ - + + + ]: 26 : SPDK_DEBUGLOG(vfu_virtio, "%s: map vq %u successfully\n", dev->name, vq->id);
108 : 26 : vq->q_state = VFU_VQ_ACTIVE;
109 : :
110 : 26 : return 0;
111 : : }
112 : :
113 : : static void
114 : 38 : virtio_dev_unmap_vq(struct vfu_virtio_dev *dev, struct vfu_virtio_vq *vq)
115 : : {
116 [ - + + + ]: 38 : SPDK_DEBUGLOG(vfu_virtio, "%s: unmap vq %u\n", dev->name, vq->id);
117 : 38 : vq->q_state = VFU_VQ_INACTIVE;
118 : :
119 : 38 : vfu_virtio_unmap_q(dev, &vq->desc);
120 : 38 : vfu_virtio_unmap_q(dev, &vq->avail);
121 : 38 : vfu_virtio_unmap_q(dev, &vq->used);
122 : 38 : }
123 : :
124 : : static bool
125 : 118 : vfu_virtio_vq_should_unmap(struct vfu_virtio_vq *vq, void *map_start, void *map_end)
126 : : {
127 : : /* always do unmap when stopping the device */
128 [ + + - + ]: 118 : if (!map_start || !map_end) {
129 : 22 : return true;
130 : : }
131 : :
132 [ + + + - ]: 96 : if (vq->desc.addr >= map_start && vq->desc.addr < map_end) {
133 : 16 : return true;
134 : : }
135 : :
136 [ - + - - ]: 80 : if (vq->avail.addr >= map_start && vq->avail.addr < map_end) {
137 : 0 : return true;
138 : : }
139 : :
140 [ - + - - ]: 80 : if (vq->used.addr >= map_start && vq->used.addr < map_end) {
141 : 0 : return true;
142 : : }
143 : :
144 : 80 : return false;
145 : : }
146 : :
147 : : static void
148 : 76 : vfu_virtio_dev_unmap_vqs(struct vfu_virtio_dev *dev, void *map_start, void *map_end)
149 : : {
150 : : uint32_t i;
151 : : struct vfu_virtio_vq *vq;
152 : :
153 [ + + ]: 304 : for (i = 0; i < dev->num_queues; i++) {
154 : 228 : vq = &dev->vqs[i];
155 [ - + + + ]: 228 : if (!vq->enabled) {
156 : 110 : continue;
157 : : }
158 : :
159 [ + + ]: 118 : if (!vfu_virtio_vq_should_unmap(vq, map_start, map_end)) {
160 : 80 : continue;
161 : : }
162 : 38 : virtio_dev_unmap_vq(dev, vq);
163 : : }
164 : 76 : }
165 : :
166 : : /* This function is used to notify VM that the device
167 : : * configuration space has been changed.
168 : : */
169 : : void
170 : 0 : vfu_virtio_notify_config(struct vfu_virtio_endpoint *virtio_endpoint)
171 : : {
172 : 0 : struct spdk_vfu_endpoint *endpoint = virtio_endpoint->endpoint;
173 : :
174 [ # # ]: 0 : if (virtio_endpoint->dev == NULL) {
175 : 0 : return;
176 : : }
177 : :
178 : 0 : virtio_endpoint->dev->cfg.isr = 1;
179 : 0 : virtio_endpoint->dev->cfg.config_generation++;
180 : :
181 : 0 : vfu_irq_trigger(spdk_vfu_get_vfu_ctx(endpoint), virtio_endpoint->dev->cfg.msix_config);
182 : : }
183 : :
184 : : static void
185 : 22 : vfu_virtio_dev_reset(struct vfu_virtio_dev *dev)
186 : : {
187 : : uint32_t i;
188 : : struct vfu_virtio_vq *vq;
189 : :
190 [ - + + + ]: 22 : SPDK_DEBUGLOG(vfu_virtio, "device %s resetting\n", dev->name);
191 : :
192 [ + + ]: 88 : for (i = 0; i < dev->num_queues; i++) {
193 : 66 : vq = &dev->vqs[i];
194 : :
195 : 66 : vq->q_state = VFU_VQ_CREATED;
196 : 66 : vq->vector = 0;
197 : 66 : vq->enabled = false;
198 : 66 : vq->last_avail_idx = 0;
199 : 66 : vq->last_used_idx = 0;
200 : :
201 : 66 : vq->packed.packed_ring = false;
202 : 66 : vq->packed.avail_phase = 0;
203 : 66 : vq->packed.used_phase = 0;
204 : : }
205 : :
206 [ - + ]: 22 : memset(&dev->cfg, 0, sizeof(struct virtio_pci_cfg));
207 : 22 : }
208 : :
209 : : static int
210 : 48 : virtio_dev_set_status(struct vfu_virtio_dev *dev, uint8_t status)
211 : : {
212 : 48 : int ret = 0;
213 : :
214 [ - + + + ]: 48 : SPDK_DEBUGLOG(vfu_virtio, "device current status %x, set status %x\n", dev->cfg.device_status,
215 : : status);
216 : :
217 [ + + ]: 48 : if (!(virtio_dev_is_started(dev))) {
218 [ + + ]: 42 : if (status & VIRTIO_CONFIG_S_DRIVER_OK) {
219 : 10 : ret = vfu_virtio_dev_start(dev);
220 : : }
221 : : } else {
222 [ + - ]: 6 : if (!(status & VIRTIO_CONFIG_S_DRIVER_OK)) {
223 : 6 : ret = vfu_virtio_dev_stop(dev);
224 : : }
225 : : }
226 : :
227 [ - + ]: 48 : if (ret) {
228 : 0 : SPDK_ERRLOG("Failed to start/stop device\n");
229 : 0 : return ret;
230 : : }
231 : :
232 : 48 : dev->cfg.device_status = status;
233 : :
234 [ + + ]: 48 : if (status == 0) {
235 : 12 : vfu_virtio_dev_reset(dev);
236 : : }
237 : :
238 : 48 : return 0;
239 : : }
240 : :
241 : : static int
242 : 20 : virtio_dev_set_features(struct vfu_virtio_dev *dev, uint64_t features)
243 : : {
244 [ - + ]: 20 : if (dev->cfg.device_status & VIRTIO_CONFIG_S_FEATURES_OK) {
245 : 0 : SPDK_ERRLOG("Feature negotiation has finished\n");
246 : 0 : return -EINVAL;
247 : : }
248 : :
249 [ - + ]: 20 : if (features & ~dev->host_features) {
250 : 0 : SPDK_ERRLOG("Host features 0x%"PRIx64", guest features 0x%"PRIx64"\n",
251 : : dev->host_features, features);
252 : 0 : return -ENOTSUP;
253 : : }
254 : :
255 [ - + + + ]: 20 : SPDK_DEBUGLOG(vfu_virtio, "%s: negotiated features 0x%"PRIx64"\n", dev->name,
256 : : features);
257 : 20 : dev->cfg.guest_features = features;
258 : :
259 : 20 : return 0;
260 : : }
261 : :
262 : : static int
263 : 22 : virtio_dev_enable_vq(struct vfu_virtio_dev *dev, uint16_t qid)
264 : : {
265 : : struct vfu_virtio_vq *vq;
266 : :
267 [ - + + + ]: 22 : SPDK_DEBUGLOG(vfu_virtio, "%s: enable vq %u\n", dev->name, qid);
268 : :
269 : 22 : vq = &dev->vqs[qid];
270 [ - + - + ]: 22 : if (vq->enabled) {
271 : 0 : SPDK_ERRLOG("Queue %u is enabled\n", qid);
272 : 0 : return -EINVAL;
273 : : }
274 : 22 : vq->enabled = true;
275 : :
276 [ - + ]: 22 : if (virtio_dev_map_vq(dev, vq)) {
277 : 0 : SPDK_ERRLOG("Queue %u failed to map\n", qid);
278 : 0 : return 0;
279 : : }
280 : :
281 : 22 : vq->avail.avail->idx = 0;
282 : 22 : vq->last_avail_idx = 0;
283 : 22 : vq->used.used->idx = 0;
284 : 22 : vq->last_used_idx = 0;
285 : :
286 [ + + ]: 22 : if (virtio_guest_has_feature(dev, VIRTIO_F_RING_PACKED)) {
287 [ - + - + ]: 12 : SPDK_DEBUGLOG(vfu_virtio, "%s: vq %u PACKED RING ENABLED\n", dev->name, qid);
288 : 12 : vq->packed.packed_ring = true;
289 : 12 : vq->packed.avail_phase = true;
290 : 12 : vq->packed.used_phase = true;
291 : : }
292 : :
293 : 22 : return 0;
294 : : }
295 : :
296 : : static int
297 : 6 : virtio_dev_disable_vq(struct vfu_virtio_dev *dev, uint16_t qid)
298 : : {
299 : : struct vfu_virtio_vq *vq;
300 : :
301 [ - + + - ]: 6 : SPDK_DEBUGLOG(vfu_virtio, "%s: disable vq %u\n", dev->name, qid);
302 : :
303 : 6 : vq = &dev->vqs[qid];
304 [ - + + - ]: 6 : if (!vq->enabled) {
305 : 6 : SPDK_NOTICELOG("Queue %u isn't enabled\n", qid);
306 : 6 : return 0;
307 : : }
308 : :
309 : 0 : virtio_dev_unmap_vq(dev, vq);
310 : :
311 : 0 : vq->q_state = VFU_VQ_CREATED;
312 : 0 : vq->vector = 0;
313 : 0 : vq->enabled = false;
314 : 0 : vq->last_avail_idx = 0;
315 : 0 : vq->last_used_idx = 0;
316 : 0 : vq->packed.packed_ring = false;
317 : 0 : vq->packed.avail_phase = 0;
318 : 0 : vq->packed.used_phase = 0;
319 : :
320 : 0 : return 0;
321 : : }
322 : :
323 : : static int
324 : 2619518 : virtio_dev_split_get_avail_reqs(struct vfu_virtio_dev *dev, struct vfu_virtio_vq *vq,
325 : : uint16_t *reqs, uint16_t max_reqs)
326 : : {
327 : : uint16_t count, i, avail_idx, last_idx;
328 : :
329 : 2619518 : last_idx = vq->last_avail_idx;
330 : 2619518 : avail_idx = vq->avail.avail->idx;
331 : :
332 : 2619518 : spdk_smp_rmb();
333 : :
334 : 2619518 : count = avail_idx - last_idx;
335 [ + + ]: 2619518 : if (count == 0) {
336 : 2507730 : return 0;
337 : : }
338 : :
339 : 111788 : count = spdk_min(count, max_reqs);
340 : 111788 : vq->last_avail_idx += count;
341 : :
342 [ + + ]: 3670078 : for (i = 0; i < count; i++) {
343 : 3558290 : reqs[i] = vq->avail.avail->ring[(last_idx + i) & (vq->qsize - 1)];
344 : : }
345 : :
346 [ - + - + ]: 111788 : SPDK_DEBUGLOG(vfu_virtio_io,
347 : : "AVAIL: vq %u last_idx=%"PRIu16" avail_idx=%"PRIu16" count=%"PRIu16"\n",
348 : : vq->id, last_idx, avail_idx, count);
349 : :
350 : 111788 : return count;
351 : : }
352 : :
353 : : static int
354 : 10674866 : virtio_vring_split_desc_get_next(struct vring_desc **desc,
355 : : struct vring_desc *desc_table,
356 : : uint32_t desc_table_size)
357 : : {
358 : 10674866 : struct vring_desc *old_desc = *desc;
359 : : uint16_t next_idx;
360 : :
361 [ + + ]: 10674866 : if ((old_desc->flags & VRING_DESC_F_NEXT) == 0) {
362 : 3558290 : *desc = NULL;
363 : 3558290 : return 0;
364 : : }
365 : :
366 : 7116576 : next_idx = old_desc->next;
367 [ - + ]: 7116576 : if (spdk_unlikely(next_idx >= desc_table_size)) {
368 : 0 : *desc = NULL;
369 : 0 : return -1;
370 : : }
371 : :
372 : 7116576 : *desc = &desc_table[next_idx];
373 : 7116576 : return 0;
374 : : }
375 : :
376 : : static inline void *
377 : 10674866 : virtio_vring_desc_to_iov(struct vfu_virtio_dev *dev, struct vring_desc *desc,
378 : : dma_sg_t *sg, struct iovec *iov)
379 : : {
380 : 10674866 : struct vfu_virtio_endpoint *virtio_endpoint = dev->virtio_endpoint;
381 : :
382 : 10674866 : return spdk_vfu_map_one(virtio_endpoint->endpoint, desc->addr, desc->len,
383 : : sg, iov, PROT_READ | PROT_WRITE);
384 : : }
385 : :
386 : : static int
387 : 3558290 : virtio_split_vring_get_desc(struct vfu_virtio_dev *dev, struct vfu_virtio_vq *vq, uint16_t desc_idx,
388 : : struct vring_desc **desc, struct vring_desc **desc_table,
389 : : uint32_t *desc_table_size,
390 : : dma_sg_t *sg, struct iovec *iov)
391 : : {
392 : 3558290 : *desc = &vq->desc.desc[desc_idx];
393 : :
394 [ - + ]: 3558290 : if (virtio_vring_split_desc_is_indirect(*desc)) {
395 : 0 : *desc_table_size = (*desc)->len / sizeof(struct vring_desc);
396 : 0 : *desc_table = virtio_vring_desc_to_iov(dev, *desc, sg, iov);
397 : 0 : *desc = *desc_table;
398 [ # # ]: 0 : if (*desc == NULL) {
399 : 0 : return -EINVAL;
400 : : }
401 : 0 : return 0;
402 : : }
403 : :
404 : 3558290 : *desc_table = vq->desc.desc;
405 : 3558290 : *desc_table_size = vq->qsize;
406 : :
407 : 3558290 : return 0;
408 : : }
409 : :
410 : : static inline dma_sg_t *
411 : 14537123 : virtio_req_to_sg_t(struct vfu_virtio_req *req, uint32_t iovcnt)
412 : : {
413 : 14537123 : return (dma_sg_t *)(req->sg + iovcnt * dma_sg_size());
414 : : }
415 : :
416 : : static inline struct vfu_virtio_req *
417 : 3608173 : vfu_virtio_dev_get_req(struct vfu_virtio_endpoint *virtio_endpoint, struct vfu_virtio_vq *vq)
418 : : {
419 : : struct vfu_virtio_req *req;
420 : :
421 : 3608173 : req = STAILQ_FIRST(&vq->free_reqs);
422 [ - + ]: 3608173 : if (req == NULL) {
423 : 0 : return NULL;
424 : : }
425 [ - + ]: 3608173 : STAILQ_REMOVE_HEAD(&vq->free_reqs, link);
426 : :
427 : 3608173 : req->iovcnt = 0;
428 : 3608173 : req->used_len = 0;
429 : 3608173 : req->payload_size = 0;
430 : 3608173 : req->req_idx = 0;
431 : 3608173 : req->buffer_id = 0;
432 : 3608173 : req->num_descs = 0;
433 : :
434 : 3608173 : return req;
435 : : }
436 : :
437 : : void
438 : 3608173 : vfu_virtio_dev_put_req(struct vfu_virtio_req *req)
439 : : {
440 : 3608173 : struct vfu_virtio_dev *dev = req->dev;
441 : 3608173 : struct vfu_virtio_endpoint *virtio_endpoint = dev->virtio_endpoint;
442 : 3608173 : vfu_ctx_t *vfu_ctx = spdk_vfu_get_vfu_ctx(virtio_endpoint->endpoint);
443 : :
444 [ + + ]: 3608173 : if (req->indirect_iov->iov_base) {
445 : 49883 : vfu_sgl_put(vfu_ctx, req->indirect_sg, req->indirect_iov, 1);
446 : 49883 : req->indirect_iov->iov_base = NULL;
447 : 49883 : req->indirect_iov->iov_len = 0;
448 : : }
449 : :
450 [ + - ]: 3608173 : if (req->iovcnt) {
451 : 3608173 : vfu_sgl_put(vfu_ctx, virtio_req_to_sg_t(req, 0), req->iovs, req->iovcnt);
452 : 3608173 : req->iovcnt = 0;
453 : : }
454 : :
455 [ - + ]: 3608173 : STAILQ_INSERT_HEAD(&req->vq->free_reqs, req, link);
456 : 3608173 : }
457 : :
458 : : void
459 : 3608173 : vfu_virtio_finish_req(struct vfu_virtio_req *req)
460 : : {
461 : 3608173 : struct vfu_virtio_dev *dev = req->dev;
462 : 3608173 : struct vfu_virtio_endpoint *virtio_endpoint = dev->virtio_endpoint;
463 : :
464 [ - + ]: 3608173 : assert(virtio_endpoint->io_outstanding);
465 : 3608173 : virtio_endpoint->io_outstanding--;
466 : :
467 [ + + ]: 3608173 : if (!virtio_guest_has_feature(req->dev, VIRTIO_F_RING_PACKED)) {
468 : 3558290 : virtio_vq_used_ring_split_enqueue(req->vq, req->req_idx, req->used_len);
469 : : } else {
470 : 49883 : virtio_vq_used_ring_packed_enqueue(req->vq, req->buffer_id, req->num_descs, req->used_len);
471 : : }
472 : :
473 : 3608173 : vfu_virtio_dev_put_req(req);
474 : 3608173 : }
475 : :
476 : : static inline void
477 : 6 : vfu_virtio_dev_free_reqs(struct vfu_virtio_endpoint *virtio_endpoint, struct vfu_virtio_dev *dev)
478 : : {
479 : : struct vfu_virtio_req *req;
480 : : struct vfu_virtio_vq *vq;
481 : : uint32_t i;
482 : :
483 [ + + ]: 24 : for (i = 0; i < dev->num_queues; i++) {
484 : 18 : vq = &dev->vqs[i];
485 [ + + ]: 7716 : while (!STAILQ_EMPTY(&vq->free_reqs)) {
486 : 7698 : req = STAILQ_FIRST(&vq->free_reqs);
487 [ + + ]: 7698 : STAILQ_REMOVE_HEAD(&vq->free_reqs, link);
488 : 7698 : vfu_virtio_vq_free_req(virtio_endpoint, vq, req);
489 : : }
490 : : }
491 : 6 : }
492 : :
493 : : static int
494 : 3558290 : virtio_dev_split_iovs_setup(struct vfu_virtio_dev *dev, struct vfu_virtio_vq *vq,
495 : : uint16_t desc_idx, struct vfu_virtio_req *req)
496 : : {
497 : 3558290 : struct vring_desc *desc, *desc_table;
498 : 3558290 : uint32_t desc_table_size, len = 0;
499 : 3558290 : uint32_t desc_handled_cnt = 0;
500 : : int rc;
501 : :
502 : 3558290 : rc = virtio_split_vring_get_desc(dev, vq, desc_idx, &desc,
503 : : &desc_table, &desc_table_size,
504 : : req->indirect_sg, req->indirect_iov);
505 [ - + ]: 3558290 : if (spdk_unlikely(rc)) {
506 : 0 : SPDK_ERRLOG("Invalid descriptor at index %"PRIu16".\n", desc_idx);
507 : 0 : return rc;
508 : : }
509 : :
510 [ - + ]: 3558290 : assert(req->iovcnt == 0);
511 : :
512 : : while (true) {
513 [ - + ]: 10674866 : if (spdk_unlikely(!virtio_vring_desc_to_iov(dev, desc, virtio_req_to_sg_t(req, req->iovcnt),
514 : : &req->iovs[req->iovcnt]))) {
515 : 0 : return -EINVAL;
516 : : }
517 : 10674866 : req->desc_writeable[req->iovcnt] = false;
518 [ + + ]: 10674866 : if (virtio_vring_split_desc_is_wr(desc)) {
519 : 5339023 : req->desc_writeable[req->iovcnt] = true;
520 : : }
521 : :
522 : 10674866 : req->iovcnt++;
523 : 10674866 : len += desc->len;
524 : :
525 : 10674866 : rc = virtio_vring_split_desc_get_next(&desc, desc_table, desc_table_size);
526 [ - + ]: 10674866 : if (spdk_unlikely(rc)) {
527 : 0 : return rc;
528 [ + + ]: 10674866 : } else if (desc == NULL) {
529 : 3558290 : break;
530 : : }
531 : :
532 : 7116576 : desc_handled_cnt++;
533 [ - + ]: 7116576 : if (spdk_unlikely(desc_handled_cnt > desc_table_size)) {
534 : 0 : return -EINVAL;
535 : : }
536 : : }
537 : :
538 : 3558290 : req->payload_size = len;
539 : :
540 : 3558290 : return 0;
541 : : }
542 : :
543 : : void
544 : 3558290 : virtio_vq_used_ring_split_enqueue(struct vfu_virtio_vq *vq, uint16_t req_idx, uint32_t used_len)
545 : : {
546 : 3558290 : uint16_t last_idx = vq->last_used_idx & (vq->qsize - 1);
547 : :
548 [ - + - + ]: 3558290 : SPDK_DEBUGLOG(vfu_virtio_io,
549 : : "Queue %u - USED RING: last_idx=%"PRIu16" req_idx=%"PRIu16" used_len=%"PRIu32"\n",
550 : : vq->id, last_idx, req_idx, used_len);
551 : :
552 : 3558290 : vq->used.used->ring[last_idx].id = req_idx;
553 : 3558290 : vq->used.used->ring[last_idx].len = used_len;
554 : 3558290 : vq->last_used_idx++;
555 : :
556 : 3558290 : spdk_smp_wmb();
557 : :
558 : 3558290 : *(volatile uint16_t *)&vq->used.used->idx = vq->last_used_idx;
559 : :
560 : 3558290 : vq->used_req_cnt++;
561 : 3558290 : }
562 : :
563 : : void
564 : 49883 : virtio_vq_used_ring_packed_enqueue(struct vfu_virtio_vq *vq, uint16_t buffer_id, uint32_t num_descs,
565 : : uint32_t used_len)
566 : : {
567 : 49883 : struct vring_packed_desc *desc = &vq->desc.desc_packed[vq->last_used_idx];
568 : :
569 [ - + - + ]: 49883 : SPDK_DEBUGLOG(vfu_virtio_io,
570 : : "Queue %u - USED RING: buffer_id=%"PRIu16" num_descs=%u used_len=%"PRIu32"\n",
571 : : vq->id, buffer_id, num_descs, used_len);
572 : :
573 [ - + ]: 49883 : if (spdk_unlikely(virtio_vring_packed_is_used(desc, vq->packed.used_phase))) {
574 : 0 : SPDK_ERRLOG("descriptor has been used before\n");
575 : 0 : return;
576 : : }
577 : :
578 : : /* In used desc addr is unused and len specifies the buffer length
579 : : * that has been written to by the device.
580 : : */
581 : 49883 : desc->addr = 0;
582 : 49883 : desc->len = used_len;
583 : :
584 : : /* This bit specifies whether any data has been written by the device */
585 [ + + ]: 49883 : if (used_len != 0) {
586 : 49877 : desc->flags |= VRING_DESC_F_WRITE;
587 : : }
588 : :
589 : : /* Buffer ID is included in the last descriptor in the list.
590 : : * The driver needs to keep track of the size of the list corresponding
591 : : * to each buffer ID.
592 : : */
593 : 49883 : desc->id = buffer_id;
594 : :
595 : : /* A device MUST NOT make the descriptor used before buffer_id is
596 : : * written to the descriptor.
597 : : */
598 : 49883 : spdk_smp_wmb();
599 : :
600 : : /* To mark a desc as used, the device sets the F_USED bit in flags to match
601 : : * the internal Device ring wrap counter. It also sets the F_AVAIL bit to
602 : : * match the same value.
603 : : */
604 [ + + ]: 49883 : if (vq->packed.used_phase) {
605 : 25265 : desc->flags |= (1 << VRING_PACKED_DESC_F_AVAIL);
606 : 25265 : desc->flags |= (1 << VRING_PACKED_DESC_F_USED);
607 : : } else {
608 : 24618 : desc->flags &= ~(1 << VRING_PACKED_DESC_F_AVAIL);
609 : 24618 : desc->flags &= ~(1 << VRING_PACKED_DESC_F_USED);
610 : : }
611 : :
612 : 49883 : vq->last_used_idx += num_descs;
613 [ + + ]: 49883 : if (vq->last_used_idx >= vq->qsize) {
614 : 134 : vq->last_used_idx -= vq->qsize;
615 : 134 : vq->packed.used_phase = !vq->packed.used_phase;
616 : : }
617 : :
618 : 49883 : vq->used_req_cnt++;
619 : : }
620 : :
621 : : static int
622 : 26776 : vfu_virtio_vq_post_irq(struct vfu_virtio_dev *dev, struct vfu_virtio_vq *vq)
623 : : {
624 : 26776 : struct vfu_virtio_endpoint *virtio_endpoint = dev->virtio_endpoint;
625 : 26776 : vfu_ctx_t *vfu_ctx = spdk_vfu_get_vfu_ctx(virtio_endpoint->endpoint);
626 : :
627 : 26776 : vq->used_req_cnt = 0;
628 : :
629 [ + - ]: 26776 : if (spdk_vfu_endpoint_msix_enabled(virtio_endpoint->endpoint)) {
630 [ - + - + ]: 26776 : SPDK_DEBUGLOG(vfu_virtio_io, "%s: Queue %u post MSIX IV %u\n",
631 : : spdk_vfu_get_endpoint_id(virtio_endpoint->endpoint),
632 : : vq->id, vq->vector);
633 : 26776 : return vfu_irq_trigger(vfu_ctx, vq->vector);
634 : : } else {
635 [ # # ]: 0 : if (!spdk_vfu_endpoint_intx_enabled(virtio_endpoint->endpoint)) {
636 [ # # # # ]: 0 : SPDK_DEBUGLOG(vfu_virtio_io, "%s: IRQ disabled\n",
637 : : spdk_vfu_get_endpoint_id(virtio_endpoint->endpoint));
638 : 0 : return 0;
639 : : }
640 : :
641 [ # # # # ]: 0 : SPDK_DEBUGLOG(vfu_virtio_io, "%s: Queue %u post ISR\n",
642 : : spdk_vfu_get_endpoint_id(virtio_endpoint->endpoint), vq->id);
643 : 0 : dev->cfg.isr = 1;
644 : 0 : return vfu_irq_trigger(vfu_ctx, 0);
645 : : }
646 : : }
647 : :
648 : : void
649 : 12799812 : vfu_virtio_vq_flush_irq(struct vfu_virtio_dev *dev, struct vfu_virtio_vq *vq)
650 : : {
651 : 12799812 : struct vfu_virtio_endpoint *virtio_endpoint = dev->virtio_endpoint;
652 : : uint32_t delay_us;
653 : :
654 [ + + ]: 12799812 : if (vq->used_req_cnt == 0) {
655 : 11343088 : return;
656 : : }
657 : :
658 : : /* No need to notify client */
659 [ + + ]: 1456724 : if (virtio_queue_event_is_suppressed(dev, vq)) {
660 : 1429948 : return;
661 : : }
662 : :
663 : : /* Interrupt coalescing disabled */
664 [ + - ]: 26776 : if (!virtio_endpoint->coalescing_delay_us) {
665 : 26776 : vfu_virtio_vq_post_irq(dev, vq);
666 : 26776 : return;
667 : : }
668 : :
669 : : /* No need for event right now */
670 [ # # ]: 0 : if (spdk_get_ticks() < vq->next_event_time) {
671 : 0 : return;
672 : : }
673 : :
674 : 0 : vfu_virtio_vq_post_irq(dev, vq);
675 : :
676 : 0 : delay_us = virtio_endpoint->coalescing_delay_us;
677 : 0 : vq->next_event_time = spdk_get_ticks() + delay_us * spdk_get_ticks_hz() / (1000000ULL);
678 : : }
679 : :
680 : : int
681 : 2619518 : vfu_virito_dev_process_split_ring(struct vfu_virtio_dev *dev, struct vfu_virtio_vq *vq)
682 : : {
683 : 2619518 : struct vfu_virtio_endpoint *virtio_endpoint = dev->virtio_endpoint;
684 : : struct vfu_virtio_req *req;
685 : 2619518 : uint16_t reqs_idx[VIRTIO_DEV_VRING_MAX_REQS];
686 : : uint16_t reqs_cnt, i;
687 : : int ret;
688 : :
689 : 2619518 : reqs_cnt = virtio_dev_split_get_avail_reqs(dev, vq, reqs_idx, VIRTIO_DEV_VRING_MAX_REQS);
690 [ + + ]: 2619518 : if (!reqs_cnt) {
691 : 2507730 : return 0;
692 : : }
693 : :
694 [ - + - + ]: 111788 : SPDK_DEBUGLOG(vfu_virtio_io, "%s: get %u descriptors\n", dev->name, reqs_cnt);
695 : :
696 [ + + ]: 3670078 : for (i = 0; i < reqs_cnt; i++) {
697 : 3558290 : req = vfu_virtio_dev_get_req(virtio_endpoint, vq);
698 [ - + ]: 3558290 : if (spdk_unlikely(!req)) {
699 : 0 : SPDK_ERRLOG("Error to get request\n");
700 : : /* TODO: address the error case */
701 : 0 : return -EIO;
702 : : }
703 : :
704 : 3558290 : req->req_idx = reqs_idx[i];
705 : 3558290 : ret = virtio_dev_split_iovs_setup(dev, vq, req->req_idx, req);
706 [ - + ]: 3558290 : if (spdk_unlikely(ret)) {
707 : : /* let the device to response this error */
708 : 0 : SPDK_ERRLOG("Split vring setup failed with index %u\n", i);
709 : : }
710 : :
711 [ - + ]: 3558290 : assert(virtio_endpoint->virtio_ops.exec_request);
712 : 3558290 : virtio_endpoint->io_outstanding++;
713 : 3558290 : virtio_endpoint->virtio_ops.exec_request(virtio_endpoint, vq, req);
714 : : }
715 : :
716 : 111788 : return i;
717 : : }
718 : :
719 : : struct vfu_virtio_req *
720 : 0 : virito_dev_split_ring_get_next_avail_req(struct vfu_virtio_dev *dev, struct vfu_virtio_vq *vq)
721 : : {
722 : 0 : struct vfu_virtio_endpoint *virtio_endpoint = dev->virtio_endpoint;
723 : : struct vfu_virtio_req *req;
724 : 0 : uint16_t reqs_idx[VIRTIO_DEV_VRING_MAX_REQS];
725 : : uint16_t reqs_cnt;
726 : : int ret;
727 : :
728 : 0 : reqs_cnt = virtio_dev_split_get_avail_reqs(dev, vq, reqs_idx, 1);
729 [ # # ]: 0 : if (!reqs_cnt) {
730 : 0 : return NULL;
731 : : }
732 [ # # ]: 0 : assert(reqs_cnt == 1);
733 : :
734 [ # # # # ]: 0 : SPDK_DEBUGLOG(vfu_virtio_io, "%s: get 1 descriptors\n", dev->name);
735 : :
736 : 0 : req = vfu_virtio_dev_get_req(virtio_endpoint, vq);
737 [ # # ]: 0 : if (!req) {
738 : 0 : SPDK_ERRLOG("Error to get request\n");
739 : 0 : return NULL;
740 : : }
741 : :
742 : 0 : req->req_idx = reqs_idx[0];
743 : 0 : ret = virtio_dev_split_iovs_setup(dev, vq, req->req_idx, req);
744 [ # # ]: 0 : if (ret) {
745 : 0 : SPDK_ERRLOG("Split vring setup failed\n");
746 : 0 : vfu_virtio_dev_put_req(req);
747 : 0 : return NULL;
748 : : }
749 : :
750 : 0 : return req;
751 : : }
752 : :
753 : : static inline void *
754 : 296269 : virtio_vring_packed_desc_to_iov(struct vfu_virtio_dev *dev, struct vring_packed_desc *desc,
755 : : dma_sg_t *sg, struct iovec *iov)
756 : : {
757 : 296269 : struct vfu_virtio_endpoint *virtio_endpoint = dev->virtio_endpoint;
758 : :
759 : 296269 : return spdk_vfu_map_one(virtio_endpoint->endpoint, desc->addr, desc->len,
760 : : sg, iov, PROT_READ | PROT_WRITE);
761 : : }
762 : :
763 : : static int
764 : 49883 : virtio_dev_packed_iovs_setup(struct vfu_virtio_dev *dev, struct vfu_virtio_vq *vq,
765 : : uint16_t last_avail_idx,
766 : : struct vring_packed_desc *current_desc, struct vfu_virtio_req *req)
767 : : {
768 : 49883 : struct vring_packed_desc *desc, *desc_table = NULL;
769 : 49883 : uint16_t new_idx, num_descs, desc_table_size = 0;
770 : 49883 : uint32_t len = 0;
771 : :
772 [ - + - + ]: 49883 : SPDK_DEBUGLOG(vfu_virtio_io, "%s: last avail idx %u, req %p\n", dev->name, last_avail_idx, req);
773 : :
774 : 49883 : desc = NULL;
775 : 49883 : num_descs = 1;
776 [ + - ]: 49883 : if (virtio_vring_packed_desc_is_indirect(current_desc)) {
777 : 49883 : req->buffer_id = current_desc->id;
778 : 49883 : desc_table = virtio_vring_packed_desc_to_iov(dev, current_desc, req->indirect_sg,
779 : : req->indirect_iov);
780 [ - + ]: 49883 : if (spdk_unlikely(desc_table == NULL)) {
781 : 0 : SPDK_ERRLOG("Map Indirect Desc to IOV failed\n");
782 : 0 : return -EINVAL;
783 : : }
784 : 49883 : desc_table_size = current_desc->len / sizeof(struct vring_packed_desc);
785 : 49883 : desc = desc_table;
786 [ - + - + ]: 49883 : SPDK_DEBUGLOG(vfu_virtio_io, "%s: indirect desc %p, desc size %u, req %p\n",
787 : : dev->name, desc_table, desc_table_size, req);
788 : : } else {
789 : 0 : desc = current_desc;
790 : : }
791 : :
792 [ - + ]: 49883 : assert(req->iovcnt == 0);
793 : : /* Map descs to IOVs */
794 : 49883 : new_idx = last_avail_idx;
795 : : while (1) {
796 [ - + ]: 246386 : assert(desc != NULL);
797 [ - + ]: 246386 : if (spdk_unlikely(req->iovcnt == VIRTIO_DEV_MAX_IOVS)) {
798 : 0 : SPDK_ERRLOG("Max IOVs in request reached (iovcnt = %d).\n", req->iovcnt);
799 : 0 : return -EINVAL;
800 : : }
801 : :
802 [ - + ]: 246386 : if (spdk_unlikely(!virtio_vring_packed_desc_to_iov(dev, desc, virtio_req_to_sg_t(req, req->iovcnt),
803 : : &req->iovs[req->iovcnt]))) {
804 : 0 : SPDK_ERRLOG("Map Desc to IOV failed (iovcnt = %d).\n", req->iovcnt);
805 : 0 : return -EINVAL;
806 : : }
807 : 246386 : req->desc_writeable[req->iovcnt] = false;
808 [ + + ]: 246386 : if (virtio_vring_packed_desc_is_wr(desc)) {
809 : 125037 : req->desc_writeable[req->iovcnt] = true;
810 : : }
811 : :
812 : 246386 : req->iovcnt++;
813 : 246386 : len += desc->len;
814 : :
815 : : /* get next desc */
816 [ + - ]: 246386 : if (desc_table) {
817 [ + + ]: 246386 : if (req->iovcnt < desc_table_size) {
818 : 196503 : desc = &desc_table[req->iovcnt];
819 : : } else {
820 : 49883 : desc = NULL;
821 : : }
822 : : } else {
823 [ # # ]: 0 : if ((desc->flags & VRING_DESC_F_NEXT) == 0) {
824 : 0 : req->buffer_id = desc->id;
825 : 0 : desc = NULL;
826 : : } else {
827 [ # # ]: 0 : new_idx = (new_idx + 1) % vq->qsize;
828 : 0 : desc = &vq->desc.desc_packed[new_idx];
829 : 0 : num_descs++;
830 : 0 : req->buffer_id = desc->id;
831 : : }
832 : : }
833 : :
834 [ + + ]: 246386 : if (desc == NULL) {
835 : 49883 : break;
836 : : }
837 : : }
838 : :
839 : 49883 : req->num_descs = num_descs;
840 [ - + ]: 49883 : vq->last_avail_idx = (new_idx + 1) % vq->qsize;
841 [ + + ]: 49883 : if (vq->last_avail_idx < last_avail_idx) {
842 : 134 : vq->packed.avail_phase = !vq->packed.avail_phase;
843 : : }
844 : :
845 : 49883 : req->payload_size = len;
846 : :
847 [ - + - + ]: 49883 : SPDK_DEBUGLOG(vfu_virtio_io, "%s: req %p, iovcnt %u, num_descs %u\n",
848 : : dev->name, req, req->iovcnt, num_descs);
849 : 49883 : return 0;
850 : : }
851 : :
852 : : int
853 : 10180294 : vfu_virito_dev_process_packed_ring(struct vfu_virtio_dev *dev, struct vfu_virtio_vq *vq)
854 : : {
855 : 10180294 : struct vfu_virtio_endpoint *virtio_endpoint = dev->virtio_endpoint;
856 : : struct vring_packed_desc *desc;
857 : : int ret;
858 : : struct vfu_virtio_req *req;
859 : : uint16_t i, max_reqs;
860 : :
861 : 10180294 : max_reqs = VIRTIO_DEV_VRING_MAX_REQS;
862 [ + + ]: 10230177 : for (i = 0; i < max_reqs; i++) {
863 : 10228778 : desc = &vq->desc.desc_packed[vq->last_avail_idx];
864 [ + + ]: 10228778 : if (!virtio_vring_packed_is_avail(desc, vq->packed.avail_phase)) {
865 : 10178895 : return i;
866 : : }
867 : :
868 : 49883 : req = vfu_virtio_dev_get_req(virtio_endpoint, vq);
869 [ - + ]: 49883 : if (spdk_unlikely(!req)) {
870 : 0 : SPDK_ERRLOG("Error to get request\n");
871 : : /* TODO: address the error case */
872 : 0 : assert(false);
873 : : return -EIO;
874 : : }
875 : :
876 : 49883 : ret = virtio_dev_packed_iovs_setup(dev, vq, vq->last_avail_idx, desc, req);
877 [ - + ]: 49883 : if (spdk_unlikely(ret)) {
878 : : /* let the device to response the error */
879 : 0 : SPDK_ERRLOG("virtio_dev_packed_iovs_setup failed\n");
880 : : }
881 : :
882 [ - + ]: 49883 : assert(virtio_endpoint->virtio_ops.exec_request);
883 : 49883 : virtio_endpoint->io_outstanding++;
884 : 49883 : virtio_endpoint->virtio_ops.exec_request(virtio_endpoint, vq, req);
885 : : }
886 : :
887 : 1399 : return i;
888 : : }
889 : :
890 : : struct vfu_virtio_req *
891 : 0 : virito_dev_packed_ring_get_next_avail_req(struct vfu_virtio_dev *dev, struct vfu_virtio_vq *vq)
892 : : {
893 : 0 : struct vfu_virtio_endpoint *virtio_endpoint = dev->virtio_endpoint;
894 : : struct vring_packed_desc *desc;
895 : : int ret;
896 : : struct vfu_virtio_req *req;
897 : :
898 : 0 : desc = &vq->desc.desc_packed[vq->last_avail_idx];
899 [ # # ]: 0 : if (!virtio_vring_packed_is_avail(desc, vq->packed.avail_phase)) {
900 : 0 : return NULL;
901 : : }
902 : :
903 [ # # # # ]: 0 : SPDK_DEBUGLOG(vfu_virtio_io, "%s: get 1 descriptors\n", dev->name);
904 : :
905 : 0 : req = vfu_virtio_dev_get_req(virtio_endpoint, vq);
906 [ # # ]: 0 : if (!req) {
907 : 0 : SPDK_ERRLOG("Error to get request\n");
908 : 0 : return NULL;
909 : : }
910 : :
911 : 0 : ret = virtio_dev_packed_iovs_setup(dev, vq, vq->last_avail_idx, desc, req);
912 [ # # ]: 0 : if (ret) {
913 : 0 : SPDK_ERRLOG("virtio_dev_packed_iovs_setup failed\n");
914 : 0 : vfu_virtio_dev_put_req(req);
915 : 0 : return NULL;
916 : : }
917 : :
918 : 0 : return req;
919 : : }
920 : :
921 : : static int
922 : 574 : virtio_vfu_pci_common_cfg(struct vfu_virtio_endpoint *virtio_endpoint, char *buf,
923 : : size_t count, loff_t pos, bool is_write)
924 : : {
925 : 574 : struct vfu_virtio_dev *dev = virtio_endpoint->dev;
926 : 574 : uint32_t offset, value = 0;
927 : : int ret;
928 : :
929 [ - + ]: 574 : assert(count <= 4);
930 : 574 : offset = pos - VIRTIO_PCI_COMMON_CFG_OFFSET;
931 : :
932 [ + + ]: 574 : if (is_write) {
933 [ - + ]: 406 : memcpy(&value, buf, count);
934 [ + + + + : 406 : switch (offset) {
+ + + + +
+ + + + +
+ - ]
935 : 20 : case VIRTIO_PCI_COMMON_DFSELECT:
936 : 20 : dev->cfg.host_feature_select = value;
937 [ - + + + ]: 20 : SPDK_DEBUGLOG(vfu_virtio, "%s: WRITE PCI_COMMON_DFSELECT with 0x%x\n",
938 : : spdk_vfu_get_endpoint_id(virtio_endpoint->endpoint),
939 : : value);
940 : 20 : break;
941 : 20 : case VIRTIO_PCI_COMMON_GFSELECT:
942 : 20 : dev->cfg.guest_feature_select = value;
943 [ - + + + ]: 20 : SPDK_DEBUGLOG(vfu_virtio, "%s: WRITE PCI_COMMON_GFSELECT with 0x%x\n",
944 : : spdk_vfu_get_endpoint_id(virtio_endpoint->endpoint),
945 : : value);
946 : 20 : break;
947 : 20 : case VIRTIO_PCI_COMMON_GF:
948 [ - + ]: 20 : assert(dev->cfg.guest_feature_select <= 1);
949 [ + + ]: 20 : if (dev->cfg.guest_feature_select) {
950 : 10 : dev->cfg.guest_feat_hi = value;
951 [ - + + + ]: 10 : SPDK_DEBUGLOG(vfu_virtio, "%s: WRITE PCI_COMMON_GF_HI with 0x%x\n",
952 : : spdk_vfu_get_endpoint_id(virtio_endpoint->endpoint),
953 : : value);
954 : : } else {
955 : 10 : dev->cfg.guest_feat_lo = value;
956 [ - + + + ]: 10 : SPDK_DEBUGLOG(vfu_virtio, "%s: WRITE PCI_COMMON_GF_LO with 0x%x\n",
957 : : spdk_vfu_get_endpoint_id(virtio_endpoint->endpoint),
958 : : value);
959 : : }
960 : :
961 : 20 : ret = virtio_dev_set_features(dev,
962 : 20 : (((uint64_t)dev->cfg.guest_feat_hi << 32) | dev->cfg.guest_feat_lo));
963 [ - + ]: 20 : if (ret) {
964 : 0 : return ret;
965 : : }
966 : 20 : break;
967 : 4 : case VIRTIO_PCI_COMMON_MSIX:
968 : 4 : dev->cfg.msix_config = value;
969 [ - + - + ]: 4 : SPDK_DEBUGLOG(vfu_virtio, "%s: WRITE PCI_COMMON_MSIX with 0x%x\n",
970 : : spdk_vfu_get_endpoint_id(virtio_endpoint->endpoint),
971 : : value);
972 : 4 : break;
973 : 48 : case VIRTIO_PCI_COMMON_STATUS:
974 [ - + + + ]: 48 : SPDK_DEBUGLOG(vfu_virtio, "%s: WRITE PCI_COMMON_STATUS with 0x%x\n",
975 : : spdk_vfu_get_endpoint_id(virtio_endpoint->endpoint),
976 : : value);
977 : 48 : ret = virtio_dev_set_status(dev, value);
978 [ - + ]: 48 : if (ret) {
979 : 0 : return ret;
980 : : }
981 : 48 : break;
982 : 106 : case VIRTIO_PCI_COMMON_Q_SELECT:
983 [ + - ]: 106 : if (value < VIRTIO_DEV_MAX_VQS) {
984 : 106 : dev->cfg.queue_select = value;
985 : : }
986 [ - + + + ]: 106 : SPDK_DEBUGLOG(vfu_virtio, "%s: WRITE PCI_COMMON_Q_SELECT with 0x%x\n",
987 : : spdk_vfu_get_endpoint_id(virtio_endpoint->endpoint),
988 : : value);
989 : 106 : break;
990 : 16 : case VIRTIO_PCI_COMMON_Q_SIZE:
991 : 16 : dev->vqs[dev->cfg.queue_select].qsize = value;
992 [ - + - + ]: 16 : SPDK_DEBUGLOG(vfu_virtio, "%s: WRITE PCI_COMMON_Q_SIZE with 0x%x\n",
993 : : spdk_vfu_get_endpoint_id(virtio_endpoint->endpoint),
994 : : value);
995 : 16 : break;
996 : 12 : case VIRTIO_PCI_COMMON_Q_MSIX:
997 : 12 : dev->vqs[dev->cfg.queue_select].vector = value;
998 [ - + - + ]: 12 : SPDK_DEBUGLOG(vfu_virtio, "%s: WRITE PCI_COMMON_Q_MSIX with 0x%x\n",
999 : : spdk_vfu_get_endpoint_id(virtio_endpoint->endpoint),
1000 : : value);
1001 : 12 : break;
1002 : 28 : case VIRTIO_PCI_COMMON_Q_ENABLE:
1003 [ - + + + ]: 28 : SPDK_DEBUGLOG(vfu_virtio, "%s: WRITE PCI_COMMON_Q_ENABLE with 0x%x\n",
1004 : : spdk_vfu_get_endpoint_id(virtio_endpoint->endpoint),
1005 : : value);
1006 [ + + ]: 28 : if (value == 1) {
1007 : 22 : ret = virtio_dev_enable_vq(dev, dev->cfg.queue_select);
1008 [ - + ]: 22 : if (ret) {
1009 : 0 : return ret;
1010 : : }
1011 : : } else {
1012 : 6 : ret = virtio_dev_disable_vq(dev, dev->cfg.queue_select);
1013 [ - + ]: 6 : if (ret) {
1014 : 0 : return ret;
1015 : : }
1016 : : }
1017 : 28 : break;
1018 : 22 : case VIRTIO_PCI_COMMON_Q_DESCLO:
1019 : 22 : dev->vqs[dev->cfg.queue_select].desc_lo = value;
1020 [ - + + + ]: 22 : SPDK_DEBUGLOG(vfu_virtio, "%s: WRITE queue %u PCI_COMMON_Q_DESCLO with 0x%x\n",
1021 : : spdk_vfu_get_endpoint_id(virtio_endpoint->endpoint), dev->cfg.queue_select, value);
1022 : 22 : break;
1023 : 22 : case VIRTIO_PCI_COMMON_Q_DESCHI:
1024 : 22 : dev->vqs[dev->cfg.queue_select].desc_hi = value;
1025 [ - + + + ]: 22 : SPDK_DEBUGLOG(vfu_virtio, "%s: WRITE queue %u PCI_COMMON_Q_DESCHI with 0x%x\n",
1026 : : spdk_vfu_get_endpoint_id(virtio_endpoint->endpoint), dev->cfg.queue_select, value);
1027 : 22 : break;
1028 : 22 : case VIRTIO_PCI_COMMON_Q_AVAILLO:
1029 : 22 : dev->vqs[dev->cfg.queue_select].avail_lo = value;
1030 [ - + + + ]: 22 : SPDK_DEBUGLOG(vfu_virtio, "%s: WRITE queue %u PCI_COMMON_Q_AVAILLO with 0x%x\n",
1031 : : spdk_vfu_get_endpoint_id(virtio_endpoint->endpoint), dev->cfg.queue_select, value);
1032 : 22 : break;
1033 : 22 : case VIRTIO_PCI_COMMON_Q_AVAILHI:
1034 : 22 : dev->vqs[dev->cfg.queue_select].avail_hi = value;
1035 [ - + + + ]: 22 : SPDK_DEBUGLOG(vfu_virtio, "%s: WRITE queue %u PCI_COMMON_Q_AVAILHI with 0x%x\n",
1036 : : spdk_vfu_get_endpoint_id(virtio_endpoint->endpoint), dev->cfg.queue_select, value);
1037 : 22 : break;
1038 : 22 : case VIRTIO_PCI_COMMON_Q_USEDLO:
1039 : 22 : dev->vqs[dev->cfg.queue_select].used_lo = value;
1040 [ - + + + ]: 22 : SPDK_DEBUGLOG(vfu_virtio, "%s: WRITE queue %u PCI_COMMON_Q_USEDLO with 0x%x\n",
1041 : : spdk_vfu_get_endpoint_id(virtio_endpoint->endpoint), dev->cfg.queue_select, value);
1042 : 22 : break;
1043 : 22 : case VIRTIO_PCI_COMMON_Q_USEDHI:
1044 : 22 : dev->vqs[dev->cfg.queue_select].used_hi = value;
1045 [ - + + + ]: 22 : SPDK_DEBUGLOG(vfu_virtio, "%s: WRITE queue %u PCI_COMMON_Q_USEDHI with 0x%x\n",
1046 : : spdk_vfu_get_endpoint_id(virtio_endpoint->endpoint), dev->cfg.queue_select, value);
1047 : 22 : break;
1048 : :
1049 : 0 : default:
1050 : 0 : SPDK_ERRLOG("%s: WRITE UNSUPPORTED offset 0x%x\n",
1051 : : spdk_vfu_get_endpoint_id(virtio_endpoint->endpoint), offset);
1052 : 0 : errno = EIO;
1053 : 0 : return -1;
1054 : : }
1055 : : } else {
1056 [ - + - - : 168 : switch (offset) {
+ + + + +
- + + + -
- - - - -
- ]
1057 : 0 : case VIRTIO_PCI_COMMON_DFSELECT:
1058 : 0 : value = dev->cfg.host_feature_select;
1059 [ # # # # ]: 0 : SPDK_DEBUGLOG(vfu_virtio, "%s: READ PCI_COMMON_DFSELECT with 0x%x\n",
1060 : : spdk_vfu_get_endpoint_id(virtio_endpoint->endpoint),
1061 : : value);
1062 : 0 : break;
1063 : 20 : case VIRTIO_PCI_COMMON_DF:
1064 [ - + ]: 20 : assert(dev->cfg.host_feature_select <= 1);
1065 [ + + ]: 20 : if (dev->cfg.host_feature_select) {
1066 : 10 : value = dev->host_features >> 32;
1067 [ - + + + ]: 10 : SPDK_DEBUGLOG(vfu_virtio, "%s: READ PCI_COMMON_DF_HI with 0x%x\n",
1068 : : spdk_vfu_get_endpoint_id(virtio_endpoint->endpoint),
1069 : : value);
1070 : : } else {
1071 : 10 : value = dev->host_features;
1072 [ - + + + ]: 10 : SPDK_DEBUGLOG(vfu_virtio, "%s: READ PCI_COMMON_DF_LO with 0x%x\n",
1073 : : spdk_vfu_get_endpoint_id(virtio_endpoint->endpoint),
1074 : : value);
1075 : : }
1076 : 20 : break;
1077 : 0 : case VIRTIO_PCI_COMMON_GFSELECT:
1078 : 0 : value = dev->cfg.guest_feature_select;
1079 [ # # # # ]: 0 : SPDK_DEBUGLOG(vfu_virtio, "%s: READ PCI_COMMON_GFSELECT with 0x%x\n",
1080 : : spdk_vfu_get_endpoint_id(virtio_endpoint->endpoint),
1081 : : value);
1082 : 0 : break;
1083 : 0 : case VIRTIO_PCI_COMMON_GF:
1084 [ # # ]: 0 : assert(dev->cfg.guest_feature_select <= 1);
1085 [ # # ]: 0 : if (dev->cfg.guest_feature_select) {
1086 : 0 : value = dev->cfg.guest_feat_hi;
1087 [ # # # # ]: 0 : SPDK_DEBUGLOG(vfu_virtio, "%s: READ PCI_COMMON_GF_HI with 0x%x\n",
1088 : : spdk_vfu_get_endpoint_id(virtio_endpoint->endpoint),
1089 : : value);
1090 : : } else {
1091 : 0 : value = dev->cfg.guest_feat_lo;
1092 [ # # # # ]: 0 : SPDK_DEBUGLOG(vfu_virtio, "%s: READ PCI_COMMON_GF_LO with 0x%x\n",
1093 : : spdk_vfu_get_endpoint_id(virtio_endpoint->endpoint),
1094 : : value);
1095 : : }
1096 : 0 : break;
1097 : 4 : case VIRTIO_PCI_COMMON_MSIX:
1098 : 4 : value = dev->cfg.msix_config;
1099 [ - + - + ]: 4 : SPDK_DEBUGLOG(vfu_virtio, "%s: READ PCI_COMMON_MSIX with 0x%x\n",
1100 : : spdk_vfu_get_endpoint_id(virtio_endpoint->endpoint),
1101 : : value);
1102 : 4 : break;
1103 : 12 : case VIRTIO_PCI_COMMON_NUMQ:
1104 : 12 : value = dev->num_queues;
1105 [ - + - + ]: 12 : SPDK_DEBUGLOG(vfu_virtio, "%s: READ PCI_COMMON_NUMQ with 0x%x\n",
1106 : : spdk_vfu_get_endpoint_id(virtio_endpoint->endpoint),
1107 : : value);
1108 : 12 : break;
1109 : 52 : case VIRTIO_PCI_COMMON_STATUS:
1110 : 52 : value = dev->cfg.device_status;
1111 [ - + + + ]: 52 : SPDK_DEBUGLOG(vfu_virtio, "%s: READ PCI_COMMON_STATUS with 0x%x\n",
1112 : : spdk_vfu_get_endpoint_id(virtio_endpoint->endpoint),
1113 : : value);
1114 : 52 : break;
1115 : 4 : case VIRTIO_PCI_COMMON_CFGGENERATION:
1116 : 4 : value = dev->cfg.config_generation;
1117 [ - + - + ]: 4 : SPDK_DEBUGLOG(vfu_virtio, "%s: READ PCI_COMMON_CFGGENERATION with 0x%x\n",
1118 : : spdk_vfu_get_endpoint_id(virtio_endpoint->endpoint),
1119 : : value);
1120 : 4 : break;
1121 : 22 : case VIRTIO_PCI_COMMON_Q_NOFF:
1122 : 22 : value = dev->cfg.queue_select;
1123 [ - + + + ]: 22 : SPDK_DEBUGLOG(vfu_virtio, "%s: READ PCI_COMMON_Q_NOFF with 0x%x\n",
1124 : : spdk_vfu_get_endpoint_id(virtio_endpoint->endpoint),
1125 : : value);
1126 : 22 : break;
1127 : 0 : case VIRTIO_PCI_COMMON_Q_SELECT:
1128 : 0 : value = dev->cfg.queue_select;
1129 [ # # # # ]: 0 : SPDK_DEBUGLOG(vfu_virtio, "%s: READ PCI_COMMON_Q_SELECT with 0x%x\n",
1130 : : spdk_vfu_get_endpoint_id(virtio_endpoint->endpoint),
1131 : : value);
1132 : 0 : break;
1133 : 26 : case VIRTIO_PCI_COMMON_Q_SIZE:
1134 : 26 : value = dev->vqs[dev->cfg.queue_select].qsize;
1135 [ - + + + ]: 26 : SPDK_DEBUGLOG(vfu_virtio, "%s: READ queue %u PCI_COMMON_Q_SIZE with 0x%x\n",
1136 : : spdk_vfu_get_endpoint_id(virtio_endpoint->endpoint),
1137 : : dev->cfg.queue_select, value);
1138 : 26 : break;
1139 : 12 : case VIRTIO_PCI_COMMON_Q_MSIX:
1140 : 12 : value = dev->vqs[dev->cfg.queue_select].vector;
1141 [ - + - + ]: 12 : SPDK_DEBUGLOG(vfu_virtio, "%s: READ queue %u PCI_COMMON_Q_MSIX with 0x%x\n",
1142 : : spdk_vfu_get_endpoint_id(virtio_endpoint->endpoint),
1143 : : dev->cfg.queue_select, value);
1144 : 12 : break;
1145 : 16 : case VIRTIO_PCI_COMMON_Q_ENABLE:
1146 [ - + ]: 16 : value = dev->vqs[dev->cfg.queue_select].enabled;
1147 [ - + - + ]: 16 : SPDK_DEBUGLOG(vfu_virtio, "%s: READ queue %u PCI_COMMON_Q_ENABLE with 0x%x\n",
1148 : : spdk_vfu_get_endpoint_id(virtio_endpoint->endpoint), dev->cfg.queue_select, value);
1149 : 16 : break;
1150 : 0 : case VIRTIO_PCI_COMMON_Q_DESCLO:
1151 : 0 : value = dev->vqs[dev->cfg.queue_select].desc_lo;
1152 [ # # # # ]: 0 : SPDK_DEBUGLOG(vfu_virtio, "%s: READ queue %u PCI_COMMON_Q_DESCLO with 0x%x\n",
1153 : : spdk_vfu_get_endpoint_id(virtio_endpoint->endpoint), dev->cfg.queue_select, value);
1154 : 0 : break;
1155 : 0 : case VIRTIO_PCI_COMMON_Q_DESCHI:
1156 : 0 : value = dev->vqs[dev->cfg.queue_select].desc_hi;
1157 [ # # # # ]: 0 : SPDK_DEBUGLOG(vfu_virtio, "%s: READ queue %u PCI_COMMON_Q_DESCHI with 0x%x\n",
1158 : : spdk_vfu_get_endpoint_id(virtio_endpoint->endpoint), dev->cfg.queue_select, value);
1159 : 0 : break;
1160 : 0 : case VIRTIO_PCI_COMMON_Q_AVAILLO:
1161 : 0 : value = dev->vqs[dev->cfg.queue_select].avail_lo;
1162 [ # # # # ]: 0 : SPDK_DEBUGLOG(vfu_virtio, "%s: READ queue %u PCI_COMMON_Q_AVAILLO with 0x%x\n",
1163 : : spdk_vfu_get_endpoint_id(virtio_endpoint->endpoint), dev->cfg.queue_select, value);
1164 : 0 : break;
1165 : 0 : case VIRTIO_PCI_COMMON_Q_AVAILHI:
1166 : 0 : value = dev->vqs[dev->cfg.queue_select].avail_hi;
1167 [ # # # # ]: 0 : SPDK_DEBUGLOG(vfu_virtio, "%s: READ queue %u PCI_COMMON_Q_AVAILHI with 0x%x\n",
1168 : : spdk_vfu_get_endpoint_id(virtio_endpoint->endpoint), dev->cfg.queue_select, value);
1169 : 0 : break;
1170 : 0 : case VIRTIO_PCI_COMMON_Q_USEDLO:
1171 : 0 : value = dev->vqs[dev->cfg.queue_select].used_lo;
1172 [ # # # # ]: 0 : SPDK_DEBUGLOG(vfu_virtio, "%s: READ queue %u PCI_COMMON_Q_USEDLO with 0x%x\n",
1173 : : spdk_vfu_get_endpoint_id(virtio_endpoint->endpoint), dev->cfg.queue_select, value);
1174 : 0 : break;
1175 : 0 : case VIRTIO_PCI_COMMON_Q_USEDHI:
1176 : 0 : value = dev->vqs[dev->cfg.queue_select].used_hi;
1177 [ # # # # ]: 0 : SPDK_DEBUGLOG(vfu_virtio, "%s: READ queue %u PCI_COMMON_Q_USEDHI with 0x%x\n",
1178 : : spdk_vfu_get_endpoint_id(virtio_endpoint->endpoint), dev->cfg.queue_select, value);
1179 : 0 : break;
1180 : 0 : default:
1181 : 0 : SPDK_ERRLOG("%s: READ UNSUPPORTED offset 0x%x\n",
1182 : : spdk_vfu_get_endpoint_id(virtio_endpoint->endpoint), offset);
1183 : 0 : errno = EIO;
1184 : 0 : return -1;
1185 : : }
1186 [ - + ]: 168 : memcpy(buf, &value, count);
1187 : : }
1188 : :
1189 : 574 : return count;
1190 : : }
1191 : :
1192 : : static int
1193 : 67 : virtio_vfu_device_specific_cfg(struct vfu_virtio_endpoint *virtio_endpoint, char *buf,
1194 : : size_t count, loff_t pos, bool is_write)
1195 : : {
1196 : : loff_t offset;
1197 : 67 : int ret = -1;
1198 : :
1199 [ - + ]: 67 : assert(count <= 8);
1200 : 67 : offset = pos - VIRTIO_PCI_SPECIFIC_CFG_OFFSET;
1201 [ + + ]: 67 : if (!is_write) {
1202 [ + - ]: 63 : if (virtio_endpoint->virtio_ops.get_config) {
1203 : 63 : ret = virtio_endpoint->virtio_ops.get_config(virtio_endpoint, buf, offset, count);
1204 : : }
1205 : : } else {
1206 [ + - ]: 4 : if (virtio_endpoint->virtio_ops.set_config) {
1207 : 4 : ret = virtio_endpoint->virtio_ops.set_config(virtio_endpoint, buf, offset, count);
1208 : : }
1209 : : }
1210 : :
1211 [ - + ]: 67 : if (ret < 0) {
1212 : 0 : return ret;
1213 : : }
1214 : :
1215 : 67 : return count;
1216 : : }
1217 : :
1218 : : static int
1219 : 526 : virtio_vfu_pci_isr(struct vfu_virtio_endpoint *virtio_endpoint, char *buf,
1220 : : size_t count, bool is_write)
1221 : : {
1222 : : uint8_t *isr;
1223 : :
1224 [ - + ]: 526 : if (count != 1) {
1225 : 0 : SPDK_ERRLOG("ISR register is 1 byte\n");
1226 : 0 : errno = EIO;
1227 : 0 : return -1;
1228 : : }
1229 : :
1230 : 526 : isr = buf;
1231 : :
1232 [ + - ]: 526 : if (!is_write) {
1233 [ - + - + ]: 526 : SPDK_DEBUGLOG(vfu_virtio, "READ PCI ISR\n");
1234 : : /* Read-Acknowledge Clear */
1235 : 526 : *isr = virtio_endpoint->dev->cfg.isr;
1236 : 526 : virtio_endpoint->dev->cfg.isr = 0;
1237 : : } else {
1238 : 0 : SPDK_ERRLOG("ISR register is RO\n");
1239 : 0 : errno = EIO;
1240 : 0 : return -1;
1241 : : }
1242 : :
1243 : 526 : return count;
1244 : : }
1245 : :
1246 : : static ssize_t
1247 : 1167 : virtio_vfu_access_bar4(vfu_ctx_t *vfu_ctx, char *buf, size_t count,
1248 : : loff_t pos,
1249 : : bool is_write)
1250 : : {
1251 : 1167 : struct spdk_vfu_endpoint *endpoint = vfu_get_private(vfu_ctx);
1252 : 1167 : struct vfu_virtio_endpoint *virtio_endpoint = spdk_vfu_get_endpoint_private(endpoint);
1253 : : uint64_t start, end;
1254 : :
1255 : 1167 : start = pos;
1256 : 1167 : end = start + count;
1257 [ - + + + : 1167 : SPDK_DEBUGLOG(vfu_virtio, "%s: %s bar4 0x%"PRIX64"-0x%"PRIX64", len = %lu\n",
+ + ]
1258 : : spdk_vfu_get_endpoint_id(virtio_endpoint->endpoint),
1259 : : is_write ? "write" : "read", start, end - 1, count);
1260 : :
1261 [ + + ]: 1167 : if (end < VIRTIO_PCI_COMMON_CFG_OFFSET + VIRTIO_PCI_COMMON_CFG_LENGTH) {
1262 : : /* virtio PCI common configuration */
1263 : 574 : return virtio_vfu_pci_common_cfg(virtio_endpoint, buf, count, pos, is_write);
1264 [ + - + + ]: 593 : } else if (start >= VIRTIO_PCI_ISR_ACCESS_OFFSET &&
1265 : : end < VIRTIO_PCI_ISR_ACCESS_OFFSET + VIRTIO_PCI_ISR_ACCESS_LENGTH) {
1266 : : /* ISR access */
1267 : 526 : return virtio_vfu_pci_isr(virtio_endpoint, buf, count, is_write);
1268 [ + - + - ]: 67 : } else if (start >= VIRTIO_PCI_SPECIFIC_CFG_OFFSET &&
1269 : : end < VIRTIO_PCI_SPECIFIC_CFG_OFFSET + VIRTIO_PCI_SPECIFIC_CFG_LENGTH) {
1270 : : /* Device specific configuration */
1271 : 67 : return virtio_vfu_device_specific_cfg(virtio_endpoint, buf, count, pos, is_write);
1272 [ # # # # ]: 0 : } else if (start >= VIRTIO_PCI_NOTIFICATIONS_OFFSET &&
1273 : : end < VIRTIO_PCI_NOTIFICATIONS_OFFSET + VIRTIO_PCI_NOTIFICATIONS_LENGTH) {
1274 : : /* Notifications */
1275 : : /* Sparse mmap region by default, there are no MMIO R/W messages */
1276 : 0 : assert(false);
1277 : : return count;
1278 : : } else {
1279 : 0 : assert(false);
1280 : : }
1281 : :
1282 : : return 0;
1283 : : }
1284 : :
1285 : : int
1286 : 66 : vfu_virtio_post_memory_add(struct spdk_vfu_endpoint *endpoint, void *map_start, void *map_end)
1287 : : {
1288 : 66 : struct vfu_virtio_endpoint *virtio_endpoint = spdk_vfu_get_endpoint_private(endpoint);
1289 : 66 : struct vfu_virtio_dev *dev = virtio_endpoint->dev;
1290 : : uint32_t i;
1291 : :
1292 [ - + ]: 66 : if (!dev) {
1293 : 0 : return 0;
1294 : : }
1295 : :
1296 [ + + ]: 264 : for (i = 0; i < dev->num_queues; i++) {
1297 : : /* Try to remap VQs if necessary */
1298 : 198 : virtio_dev_map_vq(dev, &dev->vqs[i]);
1299 : : }
1300 : :
1301 : 66 : return 0;
1302 : : }
1303 : :
1304 : : int
1305 : 66 : vfu_virtio_pre_memory_remove(struct spdk_vfu_endpoint *endpoint, void *map_start, void *map_end)
1306 : : {
1307 : 66 : struct vfu_virtio_endpoint *virtio_endpoint = spdk_vfu_get_endpoint_private(endpoint);
1308 : :
1309 [ + - ]: 66 : if (virtio_endpoint->dev != NULL) {
1310 : 66 : vfu_virtio_dev_unmap_vqs(virtio_endpoint->dev, map_start, map_end);
1311 : : }
1312 : :
1313 : 66 : return 0;
1314 : : }
1315 : :
1316 : : int
1317 : 14 : vfu_virtio_pci_reset_cb(struct spdk_vfu_endpoint *endpoint)
1318 : : {
1319 : 14 : struct vfu_virtio_endpoint *virtio_endpoint = spdk_vfu_get_endpoint_private(endpoint);
1320 : :
1321 [ + + ]: 14 : if (virtio_endpoint->dev) {
1322 : 10 : vfu_virtio_dev_stop(virtio_endpoint->dev);
1323 : 10 : vfu_virtio_dev_reset(virtio_endpoint->dev);
1324 : : }
1325 : :
1326 : 14 : return 0;
1327 : : }
1328 : :
1329 : : static ssize_t
1330 : 0 : access_pci_config(vfu_ctx_t *vfu_ctx, char *buf, size_t count, loff_t offset,
1331 : : bool is_write)
1332 : : {
1333 : 0 : struct spdk_vfu_endpoint *endpoint = vfu_get_private(vfu_ctx);
1334 : 0 : void *pci_config = spdk_vfu_endpoint_get_pci_config(endpoint);
1335 : :
1336 [ # # # # : 0 : SPDK_DEBUGLOG(vfu_virtio,
# # ]
1337 : : "%s: PCI_CFG %s %#lx-%#lx\n",
1338 : : spdk_vfu_get_endpoint_id(endpoint), is_write ? "write" : "read",
1339 : : offset, offset + count);
1340 : :
1341 [ # # ]: 0 : if (is_write) {
1342 : 0 : SPDK_ERRLOG("write %#lx-%#lx not supported\n",
1343 : : offset, offset + count);
1344 : 0 : errno = EINVAL;
1345 : 0 : return -1;
1346 : : }
1347 : :
1348 [ # # ]: 0 : if (offset + count > 0x1000) {
1349 : 0 : SPDK_ERRLOG("access past end of extended PCI configuration space, want=%ld+%ld, max=%d\n",
1350 : : offset, count, 0x1000);
1351 : 0 : errno = ERANGE;
1352 : 0 : return -1;
1353 : : }
1354 : :
1355 [ # # # # ]: 0 : memcpy(buf, ((unsigned char *)pci_config) + offset, count);
1356 : 0 : return count;
1357 : : }
1358 : :
1359 : : static int
1360 : 10 : vfu_virtio_dev_start(struct vfu_virtio_dev *dev)
1361 : : {
1362 : 10 : struct vfu_virtio_endpoint *virtio_endpoint = dev->virtio_endpoint;
1363 : 10 : int ret = 0;
1364 : :
1365 [ - + + + ]: 10 : SPDK_DEBUGLOG(vfu_virtio, "start %s\n", dev->name);
1366 : :
1367 [ - + ]: 10 : if (virtio_dev_is_started(dev)) {
1368 : 0 : SPDK_ERRLOG("Device %s is already started\n", dev->name);
1369 : 0 : return -EFAULT;
1370 : : }
1371 : :
1372 [ + - ]: 10 : if (virtio_endpoint->virtio_ops.start_device) {
1373 : 10 : virtio_endpoint->io_outstanding = 0;
1374 : 10 : ret = virtio_endpoint->virtio_ops.start_device(virtio_endpoint);
1375 : : }
1376 : :
1377 [ - + + + ]: 10 : SPDK_DEBUGLOG(vfu_virtio, "%s is started with ret %d\n", dev->name, ret);
1378 : :
1379 : 10 : return ret;
1380 : : }
1381 : :
1382 : : static int
1383 : 22 : vfu_virtio_dev_stop(struct vfu_virtio_dev *dev)
1384 : : {
1385 : 22 : struct vfu_virtio_endpoint *virtio_endpoint = dev->virtio_endpoint;
1386 : 22 : int ret = 0;
1387 : :
1388 [ - + + + ]: 22 : SPDK_DEBUGLOG(vfu_virtio, "stop %s\n", dev->name);
1389 : :
1390 [ + + ]: 22 : if (!virtio_dev_is_started(dev)) {
1391 [ - + + + ]: 12 : SPDK_DEBUGLOG(vfu_virtio, "%s isn't started\n", dev->name);
1392 : 12 : return 0;
1393 : : }
1394 : :
1395 [ + - ]: 10 : if (virtio_endpoint->virtio_ops.stop_device) {
1396 : 10 : ret = virtio_endpoint->virtio_ops.stop_device(virtio_endpoint);
1397 [ - + ]: 10 : assert(ret == 0);
1398 : : }
1399 : :
1400 : : /* Unmap all VQs */
1401 : 10 : vfu_virtio_dev_unmap_vqs(dev, NULL, NULL);
1402 : :
1403 : 10 : return ret;
1404 : : }
1405 : :
1406 : : int
1407 : 10 : vfu_virtio_detach_device(struct spdk_vfu_endpoint *endpoint)
1408 : : {
1409 : 10 : struct vfu_virtio_endpoint *virtio_endpoint = spdk_vfu_get_endpoint_private(endpoint);
1410 : 10 : struct vfu_virtio_dev *dev = virtio_endpoint->dev;
1411 : :
1412 [ + + ]: 10 : if (virtio_endpoint->dev == NULL) {
1413 : 4 : return 0;
1414 : : }
1415 : :
1416 [ - + + + ]: 6 : SPDK_DEBUGLOG(vfu_virtio, "detach device %s\n", dev->name);
1417 : :
1418 : 6 : vfu_virtio_dev_stop(dev);
1419 : 6 : vfu_virtio_dev_free_reqs(virtio_endpoint, dev);
1420 : 6 : virtio_endpoint->dev = NULL;
1421 : 6 : free(dev);
1422 : :
1423 : 6 : return 0;
1424 : : }
1425 : :
1426 : : int
1427 : 6 : vfu_virtio_attach_device(struct spdk_vfu_endpoint *endpoint)
1428 : : {
1429 : 6 : struct vfu_virtio_endpoint *virtio_endpoint = spdk_vfu_get_endpoint_private(endpoint);
1430 : 6 : uint64_t supported_features = 0;
1431 : : struct vfu_virtio_dev *dev;
1432 : : struct vfu_virtio_vq *vq;
1433 : : struct vfu_virtio_req *req;
1434 : : uint32_t i, j;
1435 : 6 : int ret = 0;
1436 : :
1437 : 6 : dev = calloc(1, sizeof(*dev) + virtio_endpoint->num_queues * 3 * dma_sg_size());
1438 [ - + ]: 6 : if (dev == NULL) {
1439 : 0 : return -ENOMEM;
1440 : : }
1441 : :
1442 : 6 : dev->num_queues = virtio_endpoint->num_queues;
1443 [ + + ]: 24 : for (i = 0; i < dev->num_queues; i++) {
1444 : 18 : vq = &dev->vqs[i];
1445 : 18 : vq->id = i;
1446 : 18 : vq->qsize = virtio_endpoint->qsize;
1447 : 18 : vq->avail.sg = (dma_sg_t *)(dev->sg + i * dma_sg_size() * 3);
1448 : 18 : vq->used.sg = (dma_sg_t *)((uint8_t *)vq->avail.sg + dma_sg_size());
1449 : 18 : vq->desc.sg = (dma_sg_t *)((uint8_t *)vq->used.sg + dma_sg_size());
1450 : :
1451 : 18 : STAILQ_INIT(&vq->free_reqs);
1452 [ + + ]: 7716 : for (j = 0; j <= vq->qsize; j++) {
1453 : 7698 : req = vfu_virtio_vq_alloc_req(virtio_endpoint, vq);
1454 [ - + ]: 7698 : if (!req) {
1455 : 0 : SPDK_ERRLOG("Error to allocate req\n");
1456 : 0 : ret = -ENOMEM;
1457 : 0 : goto out;
1458 : : }
1459 : 7698 : req->indirect_iov = &req->iovs[VIRTIO_DEV_MAX_IOVS];
1460 : 7698 : req->indirect_sg = virtio_req_to_sg_t(req, VIRTIO_DEV_MAX_IOVS);
1461 : 7698 : req->dev = dev;
1462 : 7698 : req->vq = vq;
1463 : 7698 : STAILQ_INSERT_TAIL(&vq->free_reqs, req, link);
1464 : : }
1465 : : }
1466 : :
1467 [ + - ]: 6 : if (virtio_endpoint->virtio_ops.get_device_features) {
1468 : 6 : supported_features = virtio_endpoint->virtio_ops.get_device_features(virtio_endpoint);
1469 : : }
1470 : 6 : dev->host_features = supported_features;
1471 : :
1472 [ - + ]: 6 : snprintf(dev->name, SPDK_VFU_MAX_NAME_LEN, "%s",
1473 : : spdk_vfu_get_endpoint_name(virtio_endpoint->endpoint));
1474 : 6 : virtio_endpoint->dev = dev;
1475 : 6 : dev->virtio_endpoint = virtio_endpoint;
1476 : 6 : virtio_endpoint->thread = spdk_get_thread();
1477 : 6 : return 0;
1478 : :
1479 : 0 : out:
1480 : 0 : vfu_virtio_dev_free_reqs(virtio_endpoint, dev);
1481 : 0 : return ret;
1482 : : }
1483 : :
1484 : : int
1485 : 4 : vfu_virtio_endpoint_setup(struct vfu_virtio_endpoint *virtio_endpoint,
1486 : : struct spdk_vfu_endpoint *endpoint,
1487 : : char *basename, const char *endpoint_name,
1488 : : struct vfu_virtio_ops *ops)
1489 : : {
1490 : 4 : char path[PATH_MAX] = "";
1491 : : int ret;
1492 : :
1493 [ - + ]: 4 : if (!ops) {
1494 : 0 : return -EINVAL;
1495 : : }
1496 : :
1497 : 4 : ret = snprintf(path, PATH_MAX, "%s%s_bar4", basename, endpoint_name);
1498 [ + - - + ]: 4 : if (ret < 0 || ret >= PATH_MAX) {
1499 : 0 : SPDK_ERRLOG("%s: error to get socket path: %s.\n", basename, spdk_strerror(errno));
1500 : 0 : return -EINVAL;
1501 : : }
1502 : :
1503 : 4 : ret = open(path, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
1504 [ - + ]: 4 : if (ret == -1) {
1505 : 0 : SPDK_ERRLOG("%s: failed to open device memory at %s.\n",
1506 : : path, spdk_strerror(errno));
1507 : 0 : return ret;
1508 : : }
1509 : 4 : unlink(path);
1510 : :
1511 : 4 : virtio_endpoint->devmem_fd = ret;
1512 : 4 : ret = ftruncate(virtio_endpoint->devmem_fd, VIRTIO_PCI_BAR4_LENGTH);
1513 [ - + ]: 4 : if (ret != 0) {
1514 : 0 : SPDK_ERRLOG("%s: error to ftruncate file %s.\n", path,
1515 : : spdk_strerror(errno));
1516 : 0 : close(virtio_endpoint->devmem_fd);
1517 : 0 : return ret;
1518 : : }
1519 : :
1520 : 4 : virtio_endpoint->doorbells = mmap(NULL, VIRTIO_PCI_NOTIFICATIONS_LENGTH, PROT_READ | PROT_WRITE,
1521 : : MAP_SHARED,
1522 : : virtio_endpoint->devmem_fd, VIRTIO_PCI_NOTIFICATIONS_OFFSET);
1523 [ - + ]: 4 : if (virtio_endpoint->doorbells == MAP_FAILED) {
1524 : 0 : SPDK_ERRLOG("%s: error to mmap file %s.\n", path, spdk_strerror(errno));
1525 : 0 : close(virtio_endpoint->devmem_fd);
1526 : 0 : return -EFAULT;
1527 : : }
1528 : 4 : virtio_endpoint->endpoint = endpoint;
1529 : 4 : virtio_endpoint->virtio_ops = *ops;
1530 : 4 : virtio_endpoint->num_queues = VIRTIO_DEV_MAX_VQS;
1531 : 4 : virtio_endpoint->qsize = VIRTIO_VQ_DEFAULT_SIZE;
1532 : :
1533 [ - + + + ]: 4 : SPDK_DEBUGLOG(vfu_virtio, "mmap file %s, devmem_fd %d\n", path, virtio_endpoint->devmem_fd);
1534 : 4 : return 0;
1535 : : }
1536 : :
1537 : : int
1538 : 4 : vfu_virtio_endpoint_destruct(struct vfu_virtio_endpoint *virtio_endpoint)
1539 : : {
1540 [ + - ]: 4 : if (virtio_endpoint->doorbells) {
1541 : 4 : munmap((void *)virtio_endpoint->doorbells, VIRTIO_PCI_NOTIFICATIONS_LENGTH);
1542 : : }
1543 : :
1544 [ + - ]: 4 : if (virtio_endpoint->devmem_fd) {
1545 : 4 : close(virtio_endpoint->devmem_fd);
1546 : : }
1547 : :
1548 : 4 : return 0;
1549 : : }
1550 : :
1551 : : static int
1552 : 0 : vfu_virtio_quiesce_poll(void *ctx)
1553 : : {
1554 : 0 : struct vfu_virtio_endpoint *virtio_endpoint = ctx;
1555 : 0 : vfu_ctx_t *vfu_ctx = spdk_vfu_get_vfu_ctx(virtio_endpoint->endpoint);
1556 : :
1557 [ # # ]: 0 : if (virtio_endpoint->io_outstanding) {
1558 : 0 : return SPDK_POLLER_IDLE;
1559 : : }
1560 : :
1561 : 0 : spdk_poller_unregister(&virtio_endpoint->quiesce_poller);
1562 : 0 : virtio_endpoint->quiesce_in_progress = false;
1563 : 0 : vfu_device_quiesced(vfu_ctx, 0);
1564 : :
1565 : 0 : return SPDK_POLLER_BUSY;
1566 : : }
1567 : :
1568 : : int
1569 : 290 : vfu_virtio_quiesce_cb(struct spdk_vfu_endpoint *endpoint)
1570 : : {
1571 : 290 : struct vfu_virtio_endpoint *virtio_endpoint = spdk_vfu_get_endpoint_private(endpoint);
1572 : :
1573 [ - + - + ]: 290 : if (virtio_endpoint->quiesce_in_progress) {
1574 : 0 : return -EBUSY;
1575 : : }
1576 : :
1577 [ + - ]: 290 : if (!virtio_endpoint->io_outstanding) {
1578 : 290 : return 0;
1579 : : }
1580 : :
1581 : 0 : virtio_endpoint->quiesce_in_progress = true;
1582 : 0 : virtio_endpoint->quiesce_poller = SPDK_POLLER_REGISTER(vfu_virtio_quiesce_poll, virtio_endpoint,
1583 : : 10);
1584 : :
1585 : 0 : return -EBUSY;
1586 : : }
1587 : :
1588 : : static struct spdk_vfu_pci_device vfu_virtio_device_info = {
1589 : : .id = {
1590 : : .vid = SPDK_PCI_VID_VIRTIO,
1591 : : /* Realize when calling get device information */
1592 : : .did = 0x0,
1593 : : .ssvid = SPDK_PCI_VID_VIRTIO,
1594 : : .ssid = 0x0,
1595 : : },
1596 : :
1597 : : .class = {
1598 : : /* 0x01, mass storage controller */
1599 : : .bcc = 0x01,
1600 : : /* 0x00, SCSI controller */
1601 : : .scc = 0x00,
1602 : : /* 0x00, SCSI controller - vendor specific interface */
1603 : : .pi = 0x00,
1604 : : },
1605 : :
1606 : : .pmcap = {
1607 : : .hdr.id = PCI_CAP_ID_PM,
1608 : : .pmcs.nsfrst = 0x1,
1609 : : },
1610 : :
1611 : : .pxcap = {
1612 : : .hdr.id = PCI_CAP_ID_EXP,
1613 : : .pxcaps.ver = 0x2,
1614 : : .pxdcap = {.rer = 0x1, .flrc = 0x1},
1615 : : .pxdcap2.ctds = 0x1,
1616 : : },
1617 : :
1618 : : .msixcap = {
1619 : : .hdr.id = PCI_CAP_ID_MSIX,
1620 : : .mxc.ts = VIRTIO_DEV_MAX_VQS - 1,
1621 : : .mtab = {.tbir = 0x1, .to = 0x0},
1622 : : .mpba = {.pbir = 0x2, .pbao = 0x0},
1623 : : },
1624 : :
1625 : : .nr_vendor_caps = 4,
1626 : :
1627 : : .intr_ipin = 0x1,
1628 : : .nr_int_irqs = 0x1,
1629 : : .nr_msix_irqs = VIRTIO_DEV_MAX_VQS,
1630 : :
1631 : : .regions = {
1632 : : /* BAR0 */
1633 : : {0},
1634 : : /* BAR1 */
1635 : : {
1636 : : .access_cb = NULL,
1637 : : .offset = 0,
1638 : : .fd = -1,
1639 : : .len = 0x1000,
1640 : : .flags = VFU_REGION_FLAG_RW,
1641 : : .nr_sparse_mmaps = 0,
1642 : : },
1643 : : /* BAR2 */
1644 : : {
1645 : : .access_cb = NULL,
1646 : : .offset = 0,
1647 : : .fd = -1,
1648 : : .len = 0x1000,
1649 : : .flags = VFU_REGION_FLAG_RW,
1650 : : .nr_sparse_mmaps = 0,
1651 : : },
1652 : : /* BAR3 */
1653 : : {0},
1654 : : /* BAR4 */
1655 : : {
1656 : : .access_cb = virtio_vfu_access_bar4,
1657 : : .offset = 0,
1658 : : .fd = -1,
1659 : : .len = VIRTIO_PCI_BAR4_LENGTH,
1660 : : .flags = VFU_REGION_FLAG_RW | VFU_REGION_FLAG_MEM,
1661 : : .nr_sparse_mmaps = 1,
1662 : : .mmaps = {
1663 : : {
1664 : : .offset = VIRTIO_PCI_NOTIFICATIONS_OFFSET,
1665 : : .len = VIRTIO_PCI_NOTIFICATIONS_LENGTH,
1666 : : },
1667 : : },
1668 : : },
1669 : : /* BAR5 */
1670 : : {0},
1671 : : /* BAR6 */
1672 : : {0},
1673 : : /* ROM */
1674 : : {0},
1675 : : /* PCI Config */
1676 : : {
1677 : : .access_cb = access_pci_config,
1678 : : .offset = 0,
1679 : : .fd = -1,
1680 : : .len = 0x1000,
1681 : : .flags = VFU_REGION_FLAG_RW,
1682 : : .nr_sparse_mmaps = 0,
1683 : : },
1684 : : },
1685 : : };
1686 : :
1687 : : void
1688 : 4 : vfu_virtio_get_device_info(struct vfu_virtio_endpoint *virtio_endpoint,
1689 : : struct spdk_vfu_pci_device *device_info)
1690 : : {
1691 [ - + - + ]: 4 : memcpy(device_info, &vfu_virtio_device_info, sizeof(*device_info));
1692 : :
1693 : : /* BAR4 Region FD */
1694 : 4 : device_info->regions[VFU_PCI_DEV_BAR4_REGION_IDX].fd = virtio_endpoint->devmem_fd;
1695 [ - + + + ]: 4 : SPDK_DEBUGLOG(vfu_virtio, "%s: get device information, fd %d\n",
1696 : : spdk_vfu_get_endpoint_id(virtio_endpoint->endpoint),
1697 : : virtio_endpoint->devmem_fd);
1698 : 4 : }
1699 : :
1700 : : static struct virtio_pci_cap common_cap = {
1701 : : .cap_vndr = PCI_CAP_ID_VNDR,
1702 : : .cap_len = sizeof(common_cap),
1703 : : .cfg_type = VIRTIO_PCI_CAP_COMMON_CFG,
1704 : : .bar = 4,
1705 : : .offset = VIRTIO_PCI_COMMON_CFG_OFFSET,
1706 : : .length = VIRTIO_PCI_COMMON_CFG_LENGTH,
1707 : : };
1708 : :
1709 : : static struct virtio_pci_cap isr_cap = {
1710 : : .cap_vndr = PCI_CAP_ID_VNDR,
1711 : : .cap_len = sizeof(isr_cap),
1712 : : .cfg_type = VIRTIO_PCI_CAP_ISR_CFG,
1713 : : .bar = 4,
1714 : : .offset = VIRTIO_PCI_ISR_ACCESS_OFFSET,
1715 : : .length = VIRTIO_PCI_ISR_ACCESS_LENGTH,
1716 : : };
1717 : :
1718 : : static struct virtio_pci_cap dev_cap = {
1719 : : .cap_vndr = PCI_CAP_ID_VNDR,
1720 : : .cap_len = sizeof(dev_cap),
1721 : : .cfg_type = VIRTIO_PCI_CAP_DEVICE_CFG,
1722 : : .bar = 4,
1723 : : .offset = VIRTIO_PCI_SPECIFIC_CFG_OFFSET,
1724 : : .length = VIRTIO_PCI_SPECIFIC_CFG_LENGTH,
1725 : : };
1726 : :
1727 : : static struct virtio_pci_notify_cap notify_cap = {
1728 : : .cap = {
1729 : : .cap_vndr = PCI_CAP_ID_VNDR,
1730 : : .cap_len = sizeof(notify_cap),
1731 : : .cfg_type = VIRTIO_PCI_CAP_NOTIFY_CFG,
1732 : : .bar = 4,
1733 : : .offset = VIRTIO_PCI_NOTIFICATIONS_OFFSET,
1734 : : .length = VIRTIO_PCI_NOTIFICATIONS_LENGTH,
1735 : : },
1736 : : .notify_off_multiplier = 4,
1737 : : };
1738 : :
1739 : : uint16_t
1740 : 16 : vfu_virtio_get_vendor_capability(struct spdk_vfu_endpoint *endpoint, char *buf,
1741 : : uint16_t buf_len,
1742 : : uint16_t idx)
1743 : : {
1744 : : uint16_t len;
1745 : :
1746 [ - + + + ]: 16 : SPDK_DEBUGLOG(vfu_virtio, "%s: get vendor capability, idx %u\n",
1747 : : spdk_vfu_get_endpoint_id(endpoint), idx);
1748 : :
1749 [ + + + + : 16 : switch (idx) {
- ]
1750 : 4 : case 0:
1751 [ - + ]: 4 : assert(buf_len > sizeof(common_cap));
1752 : 4 : memcpy(buf, &common_cap, sizeof(common_cap));
1753 : 4 : len = sizeof(common_cap);
1754 : 4 : break;
1755 : 4 : case 1:
1756 [ - + ]: 4 : assert(buf_len > sizeof(isr_cap));
1757 : 4 : memcpy(buf, &isr_cap, sizeof(isr_cap));
1758 : 4 : len = sizeof(isr_cap);
1759 : 4 : break;
1760 : 4 : case 2:
1761 [ - + ]: 4 : assert(buf_len > sizeof(dev_cap));
1762 : 4 : memcpy(buf, &dev_cap, sizeof(dev_cap));
1763 : 4 : len = sizeof(dev_cap);
1764 : 4 : break;
1765 : 4 : case 3:
1766 [ - + ]: 4 : assert(buf_len > sizeof(notify_cap));
1767 [ - + - + ]: 4 : memcpy(buf, ¬ify_cap, sizeof(notify_cap));
1768 : 4 : len = sizeof(notify_cap);
1769 : 4 : break;
1770 : 0 : default:
1771 : 0 : return 0;
1772 : : }
1773 : :
1774 : 16 : return len;
1775 : : }
1776 : :
1777 : 201 : SPDK_LOG_REGISTER_COMPONENT(vfu_virtio)
1778 : 201 : SPDK_LOG_REGISTER_COMPONENT(vfu_virtio_io)
|