Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright (C) 2010-2014 Intel Corporation. All rights reserved.
3 : : * All rights reserved.
4 : : */
5 : :
6 : : #include "spdk/stdinc.h"
7 : :
8 : : #include "spdk/memory.h"
9 : : #include "spdk/mmio.h"
10 : : #include "spdk/string.h"
11 : : #include "spdk/env.h"
12 : :
13 : : #include "spdk_internal/virtio.h"
14 : : #include <linux/virtio_ids.h>
15 : :
16 : : struct virtio_hw {
17 : : uint8_t use_msix;
18 : : uint32_t notify_off_multiplier;
19 : : uint8_t *isr;
20 : : uint16_t *notify_base;
21 : :
22 : : struct {
23 : : /** Mem-mapped resources from given PCI BAR */
24 : : void *vaddr;
25 : :
26 : : /** Length of the address space */
27 : : uint32_t len;
28 : : } pci_bar[6];
29 : :
30 : : struct virtio_pci_common_cfg *common_cfg;
31 : : struct spdk_pci_device *pci_dev;
32 : :
33 : : /** Device-specific PCI config space */
34 : : void *dev_cfg;
35 : :
36 : : struct virtio_dev *vdev;
37 : : bool is_remapped;
38 : : bool is_removing;
39 : : TAILQ_ENTRY(virtio_hw) tailq;
40 : : };
41 : :
42 : : struct virtio_pci_probe_ctx {
43 : : virtio_pci_create_cb enum_cb;
44 : : void *enum_ctx;
45 : : uint16_t device_id;
46 : : };
47 : :
48 : : static TAILQ_HEAD(, virtio_hw) g_virtio_hws = TAILQ_HEAD_INITIALIZER(g_virtio_hws);
49 : : static pthread_mutex_t g_hw_mutex = PTHREAD_MUTEX_INITIALIZER;
50 : : __thread struct virtio_hw *g_thread_virtio_hw = NULL;
51 : : static uint16_t g_signal_lock;
52 : : static bool g_sigset = false;
53 : :
54 : : /*
55 : : * Following macros are derived from linux/pci_regs.h, however,
56 : : * we can't simply include that header here, as there is no such
57 : : * file for non-Linux platform.
58 : : */
59 : : #define PCI_CAPABILITY_LIST 0x34
60 : : #define PCI_CAP_ID_VNDR 0x09
61 : : #define PCI_CAP_ID_MSIX 0x11
62 : :
63 : : static void
64 : 0 : virtio_pci_dev_sigbus_handler(const void *failure_addr, void *ctx)
65 : : {
66 : 0 : void *map_address = NULL;
67 : 0 : uint16_t flag = 0;
68 : : int i;
69 : :
70 [ # # ]: 0 : if (!__atomic_compare_exchange_n(&g_signal_lock, &flag, 1, false, __ATOMIC_ACQUIRE,
71 : : __ATOMIC_RELAXED)) {
72 [ # # # # ]: 0 : SPDK_DEBUGLOG(virtio_pci, "request g_signal_lock failed\n");
73 : 0 : return;
74 : : }
75 : :
76 [ # # # # : 0 : if (g_thread_virtio_hw == NULL || g_thread_virtio_hw->is_remapped) {
# # ]
77 : 0 : __atomic_store_n(&g_signal_lock, 0, __ATOMIC_RELEASE);
78 : 0 : return;
79 : : }
80 : :
81 : : /* We remap each bar to the same VA to avoid subsequent sigbus error.
82 : : * Because it is mapped to the same VA, such as hw->common_cfg and so on
83 : : * do not need to be modified.
84 : : */
85 [ # # ]: 0 : for (i = 0; i < 6; ++i) {
86 [ # # ]: 0 : if (g_thread_virtio_hw->pci_bar[i].vaddr == NULL) {
87 : 0 : continue;
88 : : }
89 : :
90 : 0 : map_address = mmap(g_thread_virtio_hw->pci_bar[i].vaddr,
91 : 0 : g_thread_virtio_hw->pci_bar[i].len,
92 : : PROT_READ | PROT_WRITE,
93 : : MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0);
94 [ # # ]: 0 : if (map_address == MAP_FAILED) {
95 : 0 : SPDK_ERRLOG("mmap failed\n");
96 : 0 : goto fail;
97 : : }
98 [ # # ]: 0 : memset(map_address, 0xFF, g_thread_virtio_hw->pci_bar[i].len);
99 : : }
100 : :
101 : 0 : g_thread_virtio_hw->is_remapped = true;
102 : 0 : __atomic_store_n(&g_signal_lock, 0, __ATOMIC_RELEASE);
103 : 0 : return;
104 : 0 : fail:
105 [ # # ]: 0 : for (--i; i >= 0; i--) {
106 [ # # ]: 0 : if (g_thread_virtio_hw->pci_bar[i].vaddr == NULL) {
107 : 0 : continue;
108 : : }
109 : :
110 : 0 : munmap(g_thread_virtio_hw->pci_bar[i].vaddr, g_thread_virtio_hw->pci_bar[i].len);
111 : : }
112 : 0 : __atomic_store_n(&g_signal_lock, 0, __ATOMIC_RELEASE);
113 : : }
114 : :
115 : : static struct virtio_hw *
116 : 0 : virtio_pci_dev_get_by_addr(struct spdk_pci_addr *traddr)
117 : : {
118 : : struct virtio_hw *hw;
119 : 0 : struct spdk_pci_addr addr;
120 : :
121 [ # # ]: 0 : pthread_mutex_lock(&g_hw_mutex);
122 [ # # ]: 0 : TAILQ_FOREACH(hw, &g_virtio_hws, tailq) {
123 : 0 : addr = spdk_pci_device_get_addr(hw->pci_dev);
124 [ # # ]: 0 : if (!spdk_pci_addr_compare(&addr, traddr)) {
125 [ # # ]: 0 : pthread_mutex_unlock(&g_hw_mutex);
126 : 0 : return hw;
127 : : }
128 : : }
129 [ # # ]: 0 : pthread_mutex_unlock(&g_hw_mutex);
130 : :
131 : 0 : return NULL;
132 : : }
133 : :
134 : : static const char *
135 : 0 : virtio_pci_dev_check(struct virtio_hw *hw, uint16_t device_id_match)
136 : : {
137 : : uint16_t pci_device_id, device_id;
138 : :
139 : 0 : pci_device_id = spdk_pci_device_get_device_id(hw->pci_dev);
140 [ # # ]: 0 : if (pci_device_id < 0x1040) {
141 : : /* Transitional devices: use the PCI subsystem device id as
142 : : * virtio device id, same as legacy driver always did.
143 : : */
144 : 0 : device_id = spdk_pci_device_get_subdevice_id(hw->pci_dev);
145 : : } else {
146 : : /* Modern devices: simply use PCI device id, but start from 0x1040. */
147 : 0 : device_id = pci_device_id - 0x1040;
148 : : }
149 : :
150 [ # # ]: 0 : if (device_id == device_id_match) {
151 : 0 : hw->is_removing = true;
152 : 0 : return hw->vdev->name;
153 : : }
154 : :
155 : 0 : return NULL;
156 : : }
157 : :
158 : : const char *
159 : 0 : virtio_pci_dev_event_process(int fd, uint16_t device_id)
160 : : {
161 : 0 : struct spdk_pci_event event;
162 : : struct virtio_hw *hw, *tmp;
163 : : const char *vdev_name;
164 : :
165 : : /* UIO remove handler */
166 [ # # ]: 0 : if (spdk_pci_get_event(fd, &event) > 0) {
167 [ # # ]: 0 : if (event.action == SPDK_UEVENT_REMOVE) {
168 : 0 : hw = virtio_pci_dev_get_by_addr(&event.traddr);
169 [ # # # # : 0 : if (hw == NULL || hw->is_removing) {
# # ]
170 : 0 : return NULL;
171 : : }
172 : :
173 : 0 : vdev_name = virtio_pci_dev_check(hw, device_id);
174 [ # # ]: 0 : if (vdev_name != NULL) {
175 : 0 : return vdev_name;
176 : : }
177 : : }
178 : : }
179 : :
180 : : /* VFIO remove handler */
181 [ # # ]: 0 : pthread_mutex_lock(&g_hw_mutex);
182 [ # # ]: 0 : TAILQ_FOREACH_SAFE(hw, &g_virtio_hws, tailq, tmp) {
183 [ # # # # : 0 : if (spdk_pci_device_is_removed(hw->pci_dev) && !hw->is_removing) {
# # ]
184 : 0 : vdev_name = virtio_pci_dev_check(hw, device_id);
185 [ # # ]: 0 : if (vdev_name != NULL) {
186 [ # # ]: 0 : pthread_mutex_unlock(&g_hw_mutex);
187 : 0 : return vdev_name;
188 : : }
189 : : }
190 : : }
191 [ # # ]: 0 : pthread_mutex_unlock(&g_hw_mutex);
192 : :
193 : 0 : return NULL;
194 : : }
195 : :
196 : : static inline int
197 : 0 : check_vq_phys_addr_ok(struct virtqueue *vq)
198 : : {
199 : : /* Virtio PCI device VIRTIO_PCI_QUEUE_PF register is 32bit,
200 : : * and only accepts 32 bit page frame number.
201 : : * Check if the allocated physical memory exceeds 16TB.
202 : : */
203 [ # # ]: 0 : if ((vq->vq_ring_mem + vq->vq_ring_size - 1) >>
204 : : (VIRTIO_PCI_QUEUE_ADDR_SHIFT + 32)) {
205 : 0 : SPDK_ERRLOG("vring address shouldn't be above 16TB!\n");
206 : 0 : return 0;
207 : : }
208 : :
209 : 0 : return 1;
210 : : }
211 : :
212 : : static void
213 : 0 : free_virtio_hw(struct virtio_hw *hw)
214 : : {
215 : : unsigned i;
216 : :
217 [ # # ]: 0 : for (i = 0; i < 6; ++i) {
218 [ # # ]: 0 : if (hw->pci_bar[i].vaddr == NULL) {
219 : 0 : continue;
220 : : }
221 : :
222 : 0 : spdk_pci_device_unmap_bar(hw->pci_dev, i, hw->pci_bar[i].vaddr);
223 : : }
224 : :
225 : 0 : free(hw);
226 : 0 : }
227 : :
228 : : static void
229 : 0 : pci_dump_json_info(struct virtio_dev *dev, struct spdk_json_write_ctx *w)
230 : : {
231 : 0 : struct virtio_hw *hw = dev->ctx;
232 : 0 : struct spdk_pci_addr pci_addr = spdk_pci_device_get_addr((struct spdk_pci_device *)hw->pci_dev);
233 : 0 : char addr[32];
234 : :
235 : 0 : spdk_json_write_name(w, "type");
236 [ # # ]: 0 : if (dev->modern) {
237 : 0 : spdk_json_write_string(w, "pci-modern");
238 : : } else {
239 : 0 : spdk_json_write_string(w, "pci-legacy");
240 : : }
241 : :
242 : 0 : spdk_pci_addr_fmt(addr, sizeof(addr), &pci_addr);
243 : 0 : spdk_json_write_named_string(w, "pci_address", addr);
244 : 0 : }
245 : :
246 : : static void
247 : 0 : pci_write_json_config(struct virtio_dev *dev, struct spdk_json_write_ctx *w)
248 : : {
249 : 0 : struct virtio_hw *hw = dev->ctx;
250 : 0 : struct spdk_pci_addr pci_addr = spdk_pci_device_get_addr(hw->pci_dev);
251 : 0 : char addr[32];
252 : :
253 : 0 : spdk_pci_addr_fmt(addr, sizeof(addr), &pci_addr);
254 : :
255 : 0 : spdk_json_write_named_string(w, "trtype", "pci");
256 : 0 : spdk_json_write_named_string(w, "traddr", addr);
257 : 0 : }
258 : :
259 : : static inline void
260 : 0 : io_write64_twopart(uint64_t val, uint32_t *lo, uint32_t *hi)
261 : : {
262 : 0 : spdk_mmio_write_4(lo, val & ((1ULL << 32) - 1));
263 : 0 : spdk_mmio_write_4(hi, val >> 32);
264 : 0 : }
265 : :
266 : : static int
267 : 0 : modern_read_dev_config(struct virtio_dev *dev, size_t offset,
268 : : void *dst, int length)
269 : : {
270 : 0 : struct virtio_hw *hw = dev->ctx;
271 : : int i;
272 : : uint8_t *p;
273 : : uint8_t old_gen, new_gen;
274 : :
275 : 0 : g_thread_virtio_hw = hw;
276 : : do {
277 : 0 : old_gen = spdk_mmio_read_1(&hw->common_cfg->config_generation);
278 : :
279 : 0 : p = dst;
280 [ # # ]: 0 : for (i = 0; i < length; i++) {
281 : 0 : *p++ = spdk_mmio_read_1((uint8_t *)hw->dev_cfg + offset + i);
282 : : }
283 : :
284 : 0 : new_gen = spdk_mmio_read_1(&hw->common_cfg->config_generation);
285 [ # # ]: 0 : } while (old_gen != new_gen);
286 : 0 : g_thread_virtio_hw = NULL;
287 : :
288 : 0 : return 0;
289 : : }
290 : :
291 : : static int
292 : 0 : modern_write_dev_config(struct virtio_dev *dev, size_t offset,
293 : : const void *src, int length)
294 : : {
295 : 0 : struct virtio_hw *hw = dev->ctx;
296 : : int i;
297 : 0 : const uint8_t *p = src;
298 : :
299 : 0 : g_thread_virtio_hw = hw;
300 [ # # ]: 0 : for (i = 0; i < length; i++) {
301 : 0 : spdk_mmio_write_1(((uint8_t *)hw->dev_cfg) + offset + i, *p++);
302 : : }
303 : 0 : g_thread_virtio_hw = NULL;
304 : :
305 : 0 : return 0;
306 : : }
307 : :
308 : : static uint64_t
309 : 0 : modern_get_features(struct virtio_dev *dev)
310 : : {
311 : 0 : struct virtio_hw *hw = dev->ctx;
312 : : uint32_t features_lo, features_hi;
313 : :
314 : 0 : g_thread_virtio_hw = hw;
315 : 0 : spdk_mmio_write_4(&hw->common_cfg->device_feature_select, 0);
316 : 0 : features_lo = spdk_mmio_read_4(&hw->common_cfg->device_feature);
317 : :
318 : 0 : spdk_mmio_write_4(&hw->common_cfg->device_feature_select, 1);
319 : 0 : features_hi = spdk_mmio_read_4(&hw->common_cfg->device_feature);
320 : 0 : g_thread_virtio_hw = NULL;
321 : :
322 : 0 : return ((uint64_t)features_hi << 32) | features_lo;
323 : : }
324 : :
325 : : static int
326 : 0 : modern_set_features(struct virtio_dev *dev, uint64_t features)
327 : : {
328 : 0 : struct virtio_hw *hw = dev->ctx;
329 : :
330 [ # # ]: 0 : if ((features & (1ULL << VIRTIO_F_VERSION_1)) == 0) {
331 : 0 : SPDK_ERRLOG("VIRTIO_F_VERSION_1 feature is not enabled.\n");
332 : 0 : return -EINVAL;
333 : : }
334 : :
335 : 0 : g_thread_virtio_hw = hw;
336 : 0 : spdk_mmio_write_4(&hw->common_cfg->guest_feature_select, 0);
337 : 0 : spdk_mmio_write_4(&hw->common_cfg->guest_feature, features & ((1ULL << 32) - 1));
338 : :
339 : 0 : spdk_mmio_write_4(&hw->common_cfg->guest_feature_select, 1);
340 : 0 : spdk_mmio_write_4(&hw->common_cfg->guest_feature, features >> 32);
341 : 0 : g_thread_virtio_hw = NULL;
342 : :
343 : 0 : dev->negotiated_features = features;
344 : :
345 : 0 : return 0;
346 : : }
347 : :
348 : : static void
349 : 0 : modern_destruct_dev(struct virtio_dev *vdev)
350 : : {
351 : 0 : struct virtio_hw *hw = vdev->ctx;
352 : : struct spdk_pci_device *pci_dev;
353 : :
354 [ # # ]: 0 : if (hw != NULL) {
355 [ # # ]: 0 : pthread_mutex_lock(&g_hw_mutex);
356 [ # # ]: 0 : TAILQ_REMOVE(&g_virtio_hws, hw, tailq);
357 [ # # ]: 0 : pthread_mutex_unlock(&g_hw_mutex);
358 : 0 : pci_dev = hw->pci_dev;
359 : 0 : free_virtio_hw(hw);
360 [ # # ]: 0 : if (pci_dev) {
361 : 0 : spdk_pci_device_detach(pci_dev);
362 : : }
363 : : }
364 : 0 : }
365 : :
366 : : static uint8_t
367 : 0 : modern_get_status(struct virtio_dev *dev)
368 : : {
369 : 0 : struct virtio_hw *hw = dev->ctx;
370 : : uint8_t ret;
371 : :
372 : 0 : g_thread_virtio_hw = hw;
373 : 0 : ret = spdk_mmio_read_1(&hw->common_cfg->device_status);
374 : 0 : g_thread_virtio_hw = NULL;
375 : :
376 : 0 : return ret;
377 : : }
378 : :
379 : : static void
380 : 0 : modern_set_status(struct virtio_dev *dev, uint8_t status)
381 : : {
382 : 0 : struct virtio_hw *hw = dev->ctx;
383 : :
384 : 0 : g_thread_virtio_hw = hw;
385 : 0 : spdk_mmio_write_1(&hw->common_cfg->device_status, status);
386 : 0 : g_thread_virtio_hw = NULL;
387 : 0 : }
388 : :
389 : : static uint16_t
390 : 0 : modern_get_queue_size(struct virtio_dev *dev, uint16_t queue_id)
391 : : {
392 : 0 : struct virtio_hw *hw = dev->ctx;
393 : : uint16_t ret;
394 : :
395 : 0 : g_thread_virtio_hw = hw;
396 : 0 : spdk_mmio_write_2(&hw->common_cfg->queue_select, queue_id);
397 : 0 : ret = spdk_mmio_read_2(&hw->common_cfg->queue_size);
398 : 0 : g_thread_virtio_hw = NULL;
399 : :
400 : 0 : return ret;
401 : : }
402 : :
403 : : static int
404 : 0 : modern_setup_queue(struct virtio_dev *dev, struct virtqueue *vq)
405 : : {
406 : 0 : struct virtio_hw *hw = dev->ctx;
407 : : uint64_t desc_addr, avail_addr, used_addr;
408 : : uint16_t notify_off;
409 : : void *queue_mem;
410 : : uint64_t queue_mem_phys_addr;
411 : :
412 : : /* To ensure physical address contiguity we make the queue occupy
413 : : * only a single hugepage (2MB). As of Virtio 1.0, the queue size
414 : : * always falls within this limit.
415 : : */
416 [ # # ]: 0 : if (vq->vq_ring_size > VALUE_2MB) {
417 : 0 : return -ENOMEM;
418 : : }
419 : :
420 : 0 : queue_mem = spdk_zmalloc(vq->vq_ring_size, VALUE_2MB, NULL,
421 : : SPDK_ENV_LCORE_ID_ANY, SPDK_MALLOC_DMA);
422 [ # # ]: 0 : if (queue_mem == NULL) {
423 : 0 : return -ENOMEM;
424 : : }
425 : :
426 : 0 : queue_mem_phys_addr = spdk_vtophys(queue_mem, NULL);
427 [ # # ]: 0 : if (queue_mem_phys_addr == SPDK_VTOPHYS_ERROR) {
428 : 0 : spdk_free(queue_mem);
429 : 0 : return -EFAULT;
430 : : }
431 : :
432 : 0 : vq->vq_ring_mem = queue_mem_phys_addr;
433 : 0 : vq->vq_ring_virt_mem = queue_mem;
434 : :
435 [ # # ]: 0 : if (!check_vq_phys_addr_ok(vq)) {
436 : 0 : spdk_free(queue_mem);
437 : 0 : return -ENOMEM;
438 : : }
439 : :
440 : 0 : desc_addr = vq->vq_ring_mem;
441 : 0 : avail_addr = desc_addr + vq->vq_nentries * sizeof(struct vring_desc);
442 : 0 : used_addr = (avail_addr + offsetof(struct vring_avail, ring[vq->vq_nentries])
443 : 0 : + VIRTIO_PCI_VRING_ALIGN - 1) & ~(VIRTIO_PCI_VRING_ALIGN - 1);
444 : :
445 : 0 : g_thread_virtio_hw = hw;
446 : 0 : spdk_mmio_write_2(&hw->common_cfg->queue_select, vq->vq_queue_index);
447 : :
448 : 0 : io_write64_twopart(desc_addr, &hw->common_cfg->queue_desc_lo,
449 : 0 : &hw->common_cfg->queue_desc_hi);
450 : 0 : io_write64_twopart(avail_addr, &hw->common_cfg->queue_avail_lo,
451 : 0 : &hw->common_cfg->queue_avail_hi);
452 : 0 : io_write64_twopart(used_addr, &hw->common_cfg->queue_used_lo,
453 : 0 : &hw->common_cfg->queue_used_hi);
454 : :
455 : 0 : notify_off = spdk_mmio_read_2(&hw->common_cfg->queue_notify_off);
456 : 0 : vq->notify_addr = (void *)((uint8_t *)hw->notify_base +
457 : 0 : notify_off * hw->notify_off_multiplier);
458 : :
459 : 0 : spdk_mmio_write_2(&hw->common_cfg->queue_enable, 1);
460 : 0 : g_thread_virtio_hw = NULL;
461 : :
462 [ # # # # ]: 0 : SPDK_DEBUGLOG(virtio_pci, "queue %"PRIu16" addresses:\n", vq->vq_queue_index);
463 [ # # # # ]: 0 : SPDK_DEBUGLOG(virtio_pci, "\t desc_addr: %" PRIx64 "\n", desc_addr);
464 [ # # # # ]: 0 : SPDK_DEBUGLOG(virtio_pci, "\t aval_addr: %" PRIx64 "\n", avail_addr);
465 [ # # # # ]: 0 : SPDK_DEBUGLOG(virtio_pci, "\t used_addr: %" PRIx64 "\n", used_addr);
466 [ # # # # ]: 0 : SPDK_DEBUGLOG(virtio_pci, "\t notify addr: %p (notify offset: %"PRIu16")\n",
467 : : vq->notify_addr, notify_off);
468 : :
469 : 0 : return 0;
470 : : }
471 : :
472 : : static void
473 : 0 : modern_del_queue(struct virtio_dev *dev, struct virtqueue *vq)
474 : : {
475 : 0 : struct virtio_hw *hw = dev->ctx;
476 : :
477 : 0 : g_thread_virtio_hw = hw;
478 : 0 : spdk_mmio_write_2(&hw->common_cfg->queue_select, vq->vq_queue_index);
479 : :
480 : 0 : io_write64_twopart(0, &hw->common_cfg->queue_desc_lo,
481 : 0 : &hw->common_cfg->queue_desc_hi);
482 : 0 : io_write64_twopart(0, &hw->common_cfg->queue_avail_lo,
483 : 0 : &hw->common_cfg->queue_avail_hi);
484 : 0 : io_write64_twopart(0, &hw->common_cfg->queue_used_lo,
485 : 0 : &hw->common_cfg->queue_used_hi);
486 : :
487 : 0 : spdk_mmio_write_2(&hw->common_cfg->queue_enable, 0);
488 : 0 : g_thread_virtio_hw = NULL;
489 : :
490 : 0 : spdk_free(vq->vq_ring_virt_mem);
491 : 0 : }
492 : :
493 : : static void
494 : 0 : modern_notify_queue(struct virtio_dev *dev, struct virtqueue *vq)
495 : : {
496 : 0 : g_thread_virtio_hw = dev->ctx;
497 : 0 : spdk_mmio_write_2(vq->notify_addr, vq->vq_queue_index);
498 : 0 : g_thread_virtio_hw = NULL;
499 : 0 : }
500 : :
501 : : static const struct virtio_dev_ops modern_ops = {
502 : : .read_dev_cfg = modern_read_dev_config,
503 : : .write_dev_cfg = modern_write_dev_config,
504 : : .get_status = modern_get_status,
505 : : .set_status = modern_set_status,
506 : : .get_features = modern_get_features,
507 : : .set_features = modern_set_features,
508 : : .destruct_dev = modern_destruct_dev,
509 : : .get_queue_size = modern_get_queue_size,
510 : : .setup_queue = modern_setup_queue,
511 : : .del_queue = modern_del_queue,
512 : : .notify_queue = modern_notify_queue,
513 : : .dump_json_info = pci_dump_json_info,
514 : : .write_json_config = pci_write_json_config,
515 : : };
516 : :
517 : : static void *
518 : 0 : get_cfg_addr(struct virtio_hw *hw, struct virtio_pci_cap *cap)
519 : : {
520 : 0 : uint8_t bar = cap->bar;
521 : 0 : uint32_t length = cap->length;
522 : 0 : uint32_t offset = cap->offset;
523 : :
524 [ # # ]: 0 : if (bar > 5) {
525 : 0 : SPDK_ERRLOG("invalid bar: %"PRIu8"\n", bar);
526 : 0 : return NULL;
527 : : }
528 : :
529 [ # # ]: 0 : if (offset + length < offset) {
530 : 0 : SPDK_ERRLOG("offset(%"PRIu32") + length(%"PRIu32") overflows\n",
531 : : offset, length);
532 : 0 : return NULL;
533 : : }
534 : :
535 [ # # ]: 0 : if (offset + length > hw->pci_bar[bar].len) {
536 : 0 : SPDK_ERRLOG("invalid cap: overflows bar space: %"PRIu32" > %"PRIu32"\n",
537 : : offset + length, hw->pci_bar[bar].len);
538 : 0 : return NULL;
539 : : }
540 : :
541 [ # # ]: 0 : if (hw->pci_bar[bar].vaddr == NULL) {
542 : 0 : SPDK_ERRLOG("bar %"PRIu8" base addr is NULL\n", bar);
543 : 0 : return NULL;
544 : : }
545 : :
546 : 0 : return hw->pci_bar[bar].vaddr + offset;
547 : : }
548 : :
549 : : static int
550 : 0 : virtio_read_caps(struct virtio_hw *hw)
551 : : {
552 : 0 : uint8_t pos;
553 : 0 : struct virtio_pci_cap cap;
554 : : int ret;
555 : :
556 : 0 : ret = spdk_pci_device_cfg_read(hw->pci_dev, &pos, 1, PCI_CAPABILITY_LIST);
557 [ # # ]: 0 : if (ret < 0) {
558 [ # # # # ]: 0 : SPDK_DEBUGLOG(virtio_pci, "failed to read pci capability list\n");
559 : 0 : return ret;
560 : : }
561 : :
562 [ # # ]: 0 : while (pos) {
563 : 0 : ret = spdk_pci_device_cfg_read(hw->pci_dev, &cap, sizeof(cap), pos);
564 [ # # ]: 0 : if (ret < 0) {
565 : 0 : SPDK_ERRLOG("failed to read pci cap at pos: %"PRIx8"\n", pos);
566 : 0 : break;
567 : : }
568 : :
569 [ # # ]: 0 : if (cap.cap_vndr == PCI_CAP_ID_MSIX) {
570 : 0 : hw->use_msix = 1;
571 : : }
572 : :
573 [ # # ]: 0 : if (cap.cap_vndr != PCI_CAP_ID_VNDR) {
574 [ # # # # ]: 0 : SPDK_DEBUGLOG(virtio_pci,
575 : : "[%2"PRIx8"] skipping non VNDR cap id: %02"PRIx8"\n",
576 : : pos, cap.cap_vndr);
577 : 0 : goto next;
578 : : }
579 : :
580 [ # # # # ]: 0 : SPDK_DEBUGLOG(virtio_pci,
581 : : "[%2"PRIx8"] cfg type: %"PRIu8", bar: %"PRIu8", offset: %04"PRIx32", len: %"PRIu32"\n",
582 : : pos, cap.cfg_type, cap.bar, cap.offset, cap.length);
583 : :
584 [ # # # # : 0 : switch (cap.cfg_type) {
# ]
585 : 0 : case VIRTIO_PCI_CAP_COMMON_CFG:
586 : 0 : hw->common_cfg = get_cfg_addr(hw, &cap);
587 : 0 : break;
588 : 0 : case VIRTIO_PCI_CAP_NOTIFY_CFG:
589 : 0 : spdk_pci_device_cfg_read(hw->pci_dev, &hw->notify_off_multiplier,
590 : : 4, pos + sizeof(cap));
591 : 0 : hw->notify_base = get_cfg_addr(hw, &cap);
592 : 0 : break;
593 : 0 : case VIRTIO_PCI_CAP_DEVICE_CFG:
594 : 0 : hw->dev_cfg = get_cfg_addr(hw, &cap);
595 : 0 : break;
596 : 0 : case VIRTIO_PCI_CAP_ISR_CFG:
597 : 0 : hw->isr = get_cfg_addr(hw, &cap);
598 : 0 : break;
599 : : }
600 : :
601 : 0 : next:
602 : 0 : pos = cap.cap_next;
603 : : }
604 : :
605 [ # # # # ]: 0 : if (hw->common_cfg == NULL || hw->notify_base == NULL ||
606 [ # # # # ]: 0 : hw->dev_cfg == NULL || hw->isr == NULL) {
607 [ # # # # ]: 0 : SPDK_DEBUGLOG(virtio_pci, "no modern virtio pci device found.\n");
608 [ # # ]: 0 : if (ret < 0) {
609 : 0 : return ret;
610 : : } else {
611 : 0 : return -EINVAL;
612 : : }
613 : : }
614 : :
615 [ # # # # ]: 0 : SPDK_DEBUGLOG(virtio_pci, "found modern virtio pci device.\n");
616 : :
617 [ # # # # ]: 0 : SPDK_DEBUGLOG(virtio_pci, "common cfg mapped at: %p\n", hw->common_cfg);
618 [ # # # # ]: 0 : SPDK_DEBUGLOG(virtio_pci, "device cfg mapped at: %p\n", hw->dev_cfg);
619 [ # # # # ]: 0 : SPDK_DEBUGLOG(virtio_pci, "isr cfg mapped at: %p\n", hw->isr);
620 [ # # # # ]: 0 : SPDK_DEBUGLOG(virtio_pci, "notify base: %p, notify off multiplier: %u\n",
621 : : hw->notify_base, hw->notify_off_multiplier);
622 : :
623 : 0 : return 0;
624 : : }
625 : :
626 : : static int
627 : 0 : virtio_pci_dev_probe(struct spdk_pci_device *pci_dev, struct virtio_pci_probe_ctx *ctx)
628 : : {
629 : : struct virtio_hw *hw;
630 : 0 : uint8_t *bar_vaddr;
631 : 0 : uint64_t bar_paddr, bar_len;
632 : : int rc;
633 : : unsigned i;
634 : 0 : char bdf[32];
635 : 0 : struct spdk_pci_addr addr;
636 : :
637 : 0 : addr = spdk_pci_device_get_addr(pci_dev);
638 : 0 : rc = spdk_pci_addr_fmt(bdf, sizeof(bdf), &addr);
639 [ # # ]: 0 : if (rc != 0) {
640 : 0 : SPDK_ERRLOG("Ignoring a device with non-parseable PCI address\n");
641 : 0 : return -1;
642 : : }
643 : :
644 : 0 : hw = calloc(1, sizeof(*hw));
645 [ # # ]: 0 : if (hw == NULL) {
646 : 0 : SPDK_ERRLOG("%s: calloc failed\n", bdf);
647 : 0 : return -1;
648 : : }
649 : :
650 : 0 : hw->pci_dev = pci_dev;
651 : :
652 [ # # ]: 0 : for (i = 0; i < 6; ++i) {
653 : 0 : rc = spdk_pci_device_map_bar(pci_dev, i, (void *) &bar_vaddr, &bar_paddr,
654 : : &bar_len);
655 [ # # ]: 0 : if (rc != 0) {
656 : 0 : SPDK_ERRLOG("%s: failed to memmap PCI BAR %u\n", bdf, i);
657 : 0 : free_virtio_hw(hw);
658 : 0 : return -1;
659 : : }
660 : :
661 : 0 : hw->pci_bar[i].vaddr = bar_vaddr;
662 : 0 : hw->pci_bar[i].len = bar_len;
663 : : }
664 : :
665 : : /* Virtio PCI caps exist only on modern PCI devices.
666 : : * Legacy devices are not supported.
667 : : */
668 [ # # ]: 0 : if (virtio_read_caps(hw) != 0) {
669 : 0 : SPDK_NOTICELOG("Ignoring legacy PCI device at %s\n", bdf);
670 : 0 : free_virtio_hw(hw);
671 : 0 : return -1;
672 : : }
673 : :
674 : 0 : rc = ctx->enum_cb((struct virtio_pci_ctx *)hw, ctx->enum_ctx);
675 [ # # ]: 0 : if (rc != 0) {
676 : 0 : free_virtio_hw(hw);
677 : 0 : return rc;
678 : : }
679 : :
680 [ # # # # ]: 0 : if (g_sigset != true) {
681 : 0 : spdk_pci_register_error_handler(virtio_pci_dev_sigbus_handler,
682 : : NULL);
683 : 0 : g_sigset = true;
684 : : }
685 : :
686 [ # # ]: 0 : pthread_mutex_lock(&g_hw_mutex);
687 : 0 : TAILQ_INSERT_TAIL(&g_virtio_hws, hw, tailq);
688 [ # # ]: 0 : pthread_mutex_unlock(&g_hw_mutex);
689 : :
690 : 0 : return 0;
691 : : }
692 : :
693 : : static int
694 : 0 : virtio_pci_dev_probe_cb(void *probe_ctx, struct spdk_pci_device *pci_dev)
695 : : {
696 : 0 : struct virtio_pci_probe_ctx *ctx = probe_ctx;
697 : 0 : uint16_t pci_device_id = spdk_pci_device_get_device_id(pci_dev);
698 : : uint16_t device_id;
699 : :
700 [ # # # # ]: 0 : if (pci_device_id < 0x1000 || pci_device_id > 0x107f) {
701 : 0 : SPDK_ERRLOG("Probe device is not a virtio device\n");
702 : 0 : return 1;
703 : : }
704 : :
705 [ # # ]: 0 : if (pci_device_id < 0x1040) {
706 : : /* Transitional devices: use the PCI subsystem device id as
707 : : * virtio device id, same as legacy driver always did.
708 : : */
709 : 0 : device_id = spdk_pci_device_get_subdevice_id(pci_dev);
710 : : } else {
711 : : /* Modern devices: simply use PCI device id, but start from 0x1040. */
712 : 0 : device_id = pci_device_id - 0x1040;
713 : : }
714 : :
715 [ # # ]: 0 : if (device_id != ctx->device_id) {
716 : 0 : return 1;
717 : : }
718 : :
719 : 0 : return virtio_pci_dev_probe(pci_dev, ctx);
720 : : }
721 : :
722 : : int
723 : 0 : virtio_pci_dev_enumerate(virtio_pci_create_cb enum_cb, void *enum_ctx,
724 : : uint16_t pci_device_id)
725 : : {
726 : 0 : struct virtio_pci_probe_ctx ctx;
727 : :
728 [ # # ]: 0 : if (!spdk_process_is_primary()) {
729 : 0 : SPDK_WARNLOG("virtio_pci secondary process support is not implemented yet.\n");
730 : 0 : return 0;
731 : : }
732 : :
733 : 0 : ctx.enum_cb = enum_cb;
734 : 0 : ctx.enum_ctx = enum_ctx;
735 : 0 : ctx.device_id = pci_device_id;
736 : :
737 : 0 : return spdk_pci_enumerate(spdk_pci_virtio_get_driver(),
738 : : virtio_pci_dev_probe_cb, &ctx);
739 : : }
740 : :
741 : : int
742 : 0 : virtio_pci_dev_attach(virtio_pci_create_cb enum_cb, void *enum_ctx,
743 : : uint16_t device_id, struct spdk_pci_addr *pci_address)
744 : : {
745 : 0 : struct virtio_pci_probe_ctx ctx;
746 : :
747 [ # # ]: 0 : if (!spdk_process_is_primary()) {
748 : 0 : SPDK_WARNLOG("virtio_pci secondary process support is not implemented yet.\n");
749 : 0 : return 0;
750 : : }
751 : :
752 : 0 : ctx.enum_cb = enum_cb;
753 : 0 : ctx.enum_ctx = enum_ctx;
754 : 0 : ctx.device_id = device_id;
755 : :
756 : 0 : return spdk_pci_device_attach(spdk_pci_virtio_get_driver(),
757 : : virtio_pci_dev_probe_cb, &ctx, pci_address);
758 : : }
759 : :
760 : : int
761 : 0 : virtio_pci_dev_init(struct virtio_dev *vdev, const char *name,
762 : : struct virtio_pci_ctx *pci_ctx)
763 : : {
764 : : int rc;
765 : 0 : struct virtio_hw *hw = (struct virtio_hw *)pci_ctx;
766 : :
767 : 0 : rc = virtio_dev_construct(vdev, name, &modern_ops, pci_ctx);
768 [ # # ]: 0 : if (rc != 0) {
769 : 0 : return rc;
770 : : }
771 : :
772 : 0 : vdev->is_hw = 1;
773 : 0 : vdev->modern = 1;
774 : 0 : hw->vdev = vdev;
775 : :
776 : 0 : return 0;
777 : : }
778 : :
779 : 2079 : SPDK_LOG_REGISTER_COMPONENT(virtio_pci)
|