Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright(c) 2018 Intel Corporation
3 : : */
4 : :
5 : : #include <uapi/linux/vfio.h>
6 : :
7 : : #include <unistd.h>
8 : : #include <pthread.h>
9 : : #include <fcntl.h>
10 : : #include <string.h>
11 : : #include <sys/ioctl.h>
12 : : #include <sys/epoll.h>
13 : : #include <linux/virtio_net.h>
14 : : #include <stdbool.h>
15 : :
16 : : #include <rte_eal_paging.h>
17 : : #include <rte_malloc.h>
18 : : #include <rte_memory.h>
19 : : #include <bus_pci_driver.h>
20 : : #include <rte_vhost.h>
21 : : #include <rte_vdpa.h>
22 : : #include <vdpa_driver.h>
23 : : #include <rte_vfio.h>
24 : : #include <rte_spinlock.h>
25 : : #include <rte_log.h>
26 : : #include <rte_kvargs.h>
27 : : #include <rte_devargs.h>
28 : :
29 : : #include "base/ifcvf.h"
30 : :
31 : : /*
32 : : * RTE_MIN() cannot be used since braced-group within expression allowed
33 : : * only inside a function.
34 : : */
35 : : #define MIN(v1, v2) ((v1) < (v2) ? (v1) : (v2))
36 : :
37 [ - + ]: 253 : RTE_LOG_REGISTER(ifcvf_vdpa_logtype, pmd.vdpa.ifcvf, NOTICE);
38 : : #define RTE_LOGTYPE_IFCVF_VDPA ifcvf_vdpa_logtype
39 : : #define DRV_LOG(level, ...) \
40 : : RTE_LOG_LINE_PREFIX(level, IFCVF_VDPA, "%s(): ", __func__, __VA_ARGS__)
41 : :
42 : : #define IFCVF_USED_RING_LEN(size) \
43 : : ((size) * sizeof(struct vring_used_elem) + sizeof(uint16_t) * 3)
44 : :
45 : : #define IFCVF_VDPA_MODE "vdpa"
46 : : #define IFCVF_SW_FALLBACK_LM "sw-live-migration"
47 : :
48 : : #define THREAD_NAME_LEN 16
49 : :
50 : : static const char * const ifcvf_valid_arguments[] = {
51 : : IFCVF_VDPA_MODE,
52 : : IFCVF_SW_FALLBACK_LM,
53 : : NULL
54 : : };
55 : :
56 : : struct ifcvf_internal {
57 : : struct rte_pci_device *pdev;
58 : : struct ifcvf_hw hw;
59 : : int configured;
60 : : int vfio_container_fd;
61 : : int vfio_group_fd;
62 : : int vfio_dev_fd;
63 : : rte_thread_t tid; /* thread for notify relay */
64 : : rte_thread_t intr_tid; /* thread for config space change interrupt relay */
65 : : int epfd;
66 : : int csc_epfd;
67 : : int vid;
68 : : struct rte_vdpa_device *vdev;
69 : : uint16_t max_queues;
70 : : uint64_t features;
71 : : rte_atomic32_t started;
72 : : rte_atomic32_t dev_attached;
73 : : rte_atomic32_t running;
74 : : rte_spinlock_t lock;
75 : : bool sw_lm;
76 : : bool sw_fallback_running;
77 : : /* mediated vring for sw fallback */
78 : : struct vring m_vring[IFCVF_MAX_QUEUES * 2];
79 : : /* eventfd for used ring interrupt */
80 : : int intr_fd[IFCVF_MAX_QUEUES * 2];
81 : : };
82 : :
83 : : struct internal_list {
84 : : TAILQ_ENTRY(internal_list) next;
85 : : struct ifcvf_internal *internal;
86 : : };
87 : :
88 : : /* vdpa device info includes device features and devcic operation. */
89 : : struct rte_vdpa_dev_info {
90 : : uint64_t features;
91 : : struct rte_vdpa_dev_ops *ops;
92 : : };
93 : :
94 : : TAILQ_HEAD(internal_list_head, internal_list);
95 : : static struct internal_list_head internal_list =
96 : : TAILQ_HEAD_INITIALIZER(internal_list);
97 : :
98 : : static pthread_mutex_t internal_list_lock = PTHREAD_MUTEX_INITIALIZER;
99 : :
100 : : static void update_used_ring(struct ifcvf_internal *internal, uint16_t qid);
101 : :
102 : : static struct internal_list *
103 : 0 : find_internal_resource_by_vdev(struct rte_vdpa_device *vdev)
104 : : {
105 : : int found = 0;
106 : : struct internal_list *list;
107 : :
108 : 0 : pthread_mutex_lock(&internal_list_lock);
109 : :
110 [ # # ]: 0 : TAILQ_FOREACH(list, &internal_list, next) {
111 [ # # ]: 0 : if (vdev == list->internal->vdev) {
112 : : found = 1;
113 : : break;
114 : : }
115 : : }
116 : :
117 : 0 : pthread_mutex_unlock(&internal_list_lock);
118 : :
119 [ # # ]: 0 : if (!found)
120 : 0 : return NULL;
121 : :
122 : : return list;
123 : : }
124 : :
125 : : static struct internal_list *
126 : 0 : find_internal_resource_by_pci_dev(struct rte_pci_device *pdev)
127 : : {
128 : : int found = 0;
129 : : struct internal_list *list;
130 : :
131 : 0 : pthread_mutex_lock(&internal_list_lock);
132 : :
133 [ # # ]: 0 : TAILQ_FOREACH(list, &internal_list, next) {
134 [ # # ]: 0 : if (!rte_pci_addr_cmp(&pdev->addr,
135 : 0 : &list->internal->pdev->addr)) {
136 : : found = 1;
137 : : break;
138 : : }
139 : : }
140 : :
141 : 0 : pthread_mutex_unlock(&internal_list_lock);
142 : :
143 [ # # ]: 0 : if (!found)
144 : 0 : return NULL;
145 : :
146 : : return list;
147 : : }
148 : :
149 : : static struct internal_list *
150 : 0 : find_internal_resource_by_rte_dev(struct rte_device *rte_dev)
151 : : {
152 : : int found = 0;
153 : : struct internal_list *list;
154 : :
155 : 0 : pthread_mutex_lock(&internal_list_lock);
156 : :
157 [ # # ]: 0 : TAILQ_FOREACH(list, &internal_list, next) {
158 [ # # ]: 0 : if (rte_dev == &list->internal->pdev->device) {
159 : : found = 1;
160 : : break;
161 : : }
162 : : }
163 : :
164 : 0 : pthread_mutex_unlock(&internal_list_lock);
165 : :
166 [ # # ]: 0 : if (!found)
167 : 0 : return NULL;
168 : :
169 : : return list;
170 : : }
171 : :
172 : : static int
173 : 0 : ifcvf_vfio_setup(struct ifcvf_internal *internal)
174 : : {
175 : 0 : struct rte_pci_device *dev = internal->pdev;
176 : 0 : char devname[RTE_DEV_NAME_MAX_LEN] = {0};
177 : : int iommu_group_num;
178 : : int i, ret;
179 : :
180 : 0 : internal->vfio_dev_fd = -1;
181 : 0 : internal->vfio_group_fd = -1;
182 : 0 : internal->vfio_container_fd = -1;
183 : :
184 : 0 : rte_pci_device_name(&dev->addr, devname, RTE_DEV_NAME_MAX_LEN);
185 : 0 : ret = rte_vfio_get_group_num(rte_pci_get_sysfs_path(), devname,
186 : : &iommu_group_num);
187 [ # # ]: 0 : if (ret <= 0) {
188 : 0 : DRV_LOG(ERR, "%s failed to get IOMMU group", devname);
189 : 0 : return -1;
190 : : }
191 : :
192 : 0 : internal->vfio_container_fd = rte_vfio_container_create();
193 [ # # ]: 0 : if (internal->vfio_container_fd < 0)
194 : : return -1;
195 : :
196 : 0 : internal->vfio_group_fd = rte_vfio_container_group_bind(
197 : : internal->vfio_container_fd, iommu_group_num);
198 [ # # ]: 0 : if (internal->vfio_group_fd < 0)
199 : 0 : goto err;
200 : :
201 [ # # ]: 0 : if (rte_pci_map_device(dev))
202 : 0 : goto err;
203 : :
204 : 0 : internal->vfio_dev_fd = rte_intr_dev_fd_get(dev->intr_handle);
205 : :
206 [ # # ]: 0 : for (i = 0; i < RTE_MIN(PCI_MAX_RESOURCE, IFCVF_PCI_MAX_RESOURCE);
207 : 0 : i++) {
208 : 0 : internal->hw.mem_resource[i].addr =
209 : 0 : internal->pdev->mem_resource[i].addr;
210 : 0 : internal->hw.mem_resource[i].phys_addr =
211 : 0 : internal->pdev->mem_resource[i].phys_addr;
212 : 0 : internal->hw.mem_resource[i].len =
213 : 0 : internal->pdev->mem_resource[i].len;
214 : : }
215 : :
216 : : return 0;
217 : :
218 : 0 : err:
219 : 0 : rte_vfio_container_destroy(internal->vfio_container_fd);
220 : 0 : return -1;
221 : : }
222 : :
223 : : static int
224 : 0 : ifcvf_dma_map(struct ifcvf_internal *internal, bool do_map)
225 : : {
226 : : uint32_t i;
227 : : int ret;
228 : 0 : struct rte_vhost_memory *mem = NULL;
229 : : int vfio_container_fd;
230 : :
231 : 0 : ret = rte_vhost_get_mem_table(internal->vid, &mem);
232 [ # # ]: 0 : if (ret < 0) {
233 : 0 : DRV_LOG(ERR, "failed to get VM memory layout.");
234 : 0 : goto exit;
235 : : }
236 : :
237 : 0 : vfio_container_fd = internal->vfio_container_fd;
238 : :
239 [ # # ]: 0 : for (i = 0; i < mem->nregions; i++) {
240 : : struct rte_vhost_mem_region *reg;
241 : :
242 : : reg = &mem->regions[i];
243 [ # # ]: 0 : DRV_LOG(INFO, "%s, region %u: HVA 0x%" PRIx64 ", "
244 : : "GPA 0x%" PRIx64 ", size 0x%" PRIx64 ".",
245 : : do_map ? "DMA map" : "DMA unmap", i,
246 : : reg->host_user_addr, reg->guest_phys_addr, reg->size);
247 : :
248 [ # # ]: 0 : if (do_map) {
249 : 0 : ret = rte_vfio_container_dma_map(vfio_container_fd,
250 : : reg->host_user_addr, reg->guest_phys_addr,
251 : : reg->size);
252 [ # # ]: 0 : if (ret < 0) {
253 : 0 : DRV_LOG(ERR, "DMA map failed.");
254 : 0 : goto exit;
255 : : }
256 : : } else {
257 : 0 : ret = rte_vfio_container_dma_unmap(vfio_container_fd,
258 : : reg->host_user_addr, reg->guest_phys_addr,
259 : : reg->size);
260 [ # # ]: 0 : if (ret < 0) {
261 : 0 : DRV_LOG(ERR, "DMA unmap failed.");
262 : 0 : goto exit;
263 : : }
264 : : }
265 : : }
266 : :
267 : 0 : exit:
268 : 0 : free(mem);
269 : 0 : return ret;
270 : : }
271 : :
272 : : static uint64_t
273 : 0 : hva_to_gpa(int vid, uint64_t hva)
274 : : {
275 : 0 : struct rte_vhost_memory *mem = NULL;
276 : : struct rte_vhost_mem_region *reg;
277 : : uint32_t i;
278 : : uint64_t gpa = 0;
279 : :
280 [ # # ]: 0 : if (rte_vhost_get_mem_table(vid, &mem) < 0)
281 : 0 : goto exit;
282 : :
283 [ # # ]: 0 : for (i = 0; i < mem->nregions; i++) {
284 : : reg = &mem->regions[i];
285 : :
286 [ # # ]: 0 : if (hva >= reg->host_user_addr &&
287 [ # # ]: 0 : hva < reg->host_user_addr + reg->size) {
288 : 0 : gpa = hva - reg->host_user_addr + reg->guest_phys_addr;
289 : 0 : break;
290 : : }
291 : : }
292 : :
293 : 0 : exit:
294 : 0 : free(mem);
295 : 0 : return gpa;
296 : : }
297 : :
298 : : static int
299 : 0 : vdpa_ifcvf_start(struct ifcvf_internal *internal)
300 : : {
301 : 0 : struct ifcvf_hw *hw = &internal->hw;
302 : : int i, nr_vring;
303 : : int vid;
304 : : struct rte_vhost_vring vq;
305 : : uint64_t gpa;
306 : :
307 : 0 : vid = internal->vid;
308 : 0 : nr_vring = rte_vhost_get_vring_num(vid);
309 : 0 : rte_vhost_get_negotiated_features(vid, &hw->req_features);
310 : :
311 [ # # ]: 0 : for (i = 0; i < nr_vring; i++) {
312 [ # # ]: 0 : if (!hw->vring[i].enable)
313 : 0 : continue;
314 : 0 : rte_vhost_get_vhost_vring(vid, i, &vq);
315 : 0 : gpa = hva_to_gpa(vid, (uint64_t)(uintptr_t)vq.desc);
316 [ # # ]: 0 : if (gpa == 0) {
317 : 0 : DRV_LOG(ERR, "Fail to get GPA for descriptor ring.");
318 : 0 : return -1;
319 : : }
320 : 0 : hw->vring[i].desc = gpa;
321 : :
322 : 0 : gpa = hva_to_gpa(vid, (uint64_t)(uintptr_t)vq.avail);
323 [ # # ]: 0 : if (gpa == 0) {
324 : 0 : DRV_LOG(ERR, "Fail to get GPA for available ring.");
325 : 0 : return -1;
326 : : }
327 : 0 : hw->vring[i].avail = gpa;
328 : :
329 : 0 : gpa = hva_to_gpa(vid, (uint64_t)(uintptr_t)vq.used);
330 [ # # ]: 0 : if (gpa == 0) {
331 : 0 : DRV_LOG(ERR, "Fail to get GPA for used ring.");
332 : 0 : return -1;
333 : : }
334 : 0 : hw->vring[i].used = gpa;
335 : :
336 : 0 : hw->vring[i].size = vq.size;
337 : 0 : rte_vhost_get_vring_base(vid, i, &hw->vring[i].last_avail_idx,
338 : 0 : &hw->vring[i].last_used_idx);
339 : : }
340 : 0 : hw->nr_vring = i;
341 : :
342 : 0 : return ifcvf_start_hw(&internal->hw);
343 : : }
344 : :
345 : : static void
346 : 0 : vdpa_ifcvf_stop(struct ifcvf_internal *internal)
347 : : {
348 : 0 : struct ifcvf_hw *hw = &internal->hw;
349 : : uint32_t i;
350 : : int vid;
351 : 0 : uint64_t features = 0;
352 : 0 : uint64_t log_base = 0, log_size = 0;
353 : : uint64_t len;
354 : : u32 ring_state = 0;
355 : :
356 : 0 : vid = internal->vid;
357 : :
358 : : /* to make sure no packet is lost for blk device
359 : : * do not stop until last_avail_idx == last_used_idx
360 : : */
361 [ # # ]: 0 : if (internal->hw.device_type == IFCVF_BLK) {
362 [ # # ]: 0 : for (i = 0; i < hw->nr_vring; i++) {
363 : : do {
364 [ # # ]: 0 : if (hw->lm_cfg != NULL)
365 : 0 : ring_state = *(u32 *)(hw->lm_cfg +
366 : 0 : IFCVF_LM_RING_STATE_OFFSET +
367 : 0 : i * IFCVF_LM_CFG_SIZE);
368 : 0 : hw->vring[i].last_avail_idx =
369 : 0 : (u16)(ring_state & IFCVF_16_BIT_MASK);
370 : 0 : hw->vring[i].last_used_idx =
371 : 0 : (u16)(ring_state >> 16);
372 : 0 : usleep(10);
373 : 0 : } while (hw->vring[i].last_avail_idx !=
374 [ # # ]: 0 : hw->vring[i].last_used_idx);
375 : : }
376 : : }
377 : :
378 : 0 : ifcvf_stop_hw(hw);
379 : :
380 [ # # ]: 0 : for (i = 0; i < hw->nr_vring; i++)
381 : 0 : rte_vhost_set_vring_base(vid, i, hw->vring[i].last_avail_idx,
382 : 0 : hw->vring[i].last_used_idx);
383 : :
384 [ # # ]: 0 : if (internal->sw_lm)
385 : 0 : return;
386 : :
387 : 0 : rte_vhost_get_negotiated_features(vid, &features);
388 [ # # ]: 0 : if (RTE_VHOST_NEED_LOG(features)) {
389 : 0 : ifcvf_disable_logging(hw);
390 : 0 : rte_vhost_get_log_base(internal->vid, &log_base, &log_size);
391 : 0 : rte_vfio_container_dma_unmap(internal->vfio_container_fd,
392 : : log_base, IFCVF_LOG_BASE, log_size);
393 : : /*
394 : : * IFCVF marks dirty memory pages for only packet buffer,
395 : : * SW helps to mark the used ring as dirty after device stops.
396 : : */
397 [ # # ]: 0 : for (i = 0; i < hw->nr_vring; i++) {
398 : 0 : len = IFCVF_USED_RING_LEN(hw->vring[i].size);
399 : 0 : rte_vhost_log_used_vring(vid, i, 0, len);
400 : : }
401 : : }
402 : : }
403 : :
404 : : #define MSIX_IRQ_SET_BUF_LEN (sizeof(struct vfio_irq_set) + \
405 : : sizeof(int) * (IFCVF_MAX_QUEUES * 2 + 1))
406 : : static int
407 : 0 : vdpa_enable_vfio_intr(struct ifcvf_internal *internal, bool m_rx)
408 : : {
409 : : int ret;
410 : : uint32_t i, nr_vring;
411 : : char irq_set_buf[MSIX_IRQ_SET_BUF_LEN];
412 : : struct vfio_irq_set *irq_set;
413 : : int *fd_ptr;
414 : : struct rte_vhost_vring vring;
415 : : int fd;
416 : :
417 : 0 : vring.callfd = -1;
418 : :
419 : 0 : nr_vring = rte_vhost_get_vring_num(internal->vid);
420 [ # # ]: 0 : if (nr_vring > IFCVF_MAX_QUEUES * 2)
421 : : return -1;
422 : :
423 : : irq_set = (struct vfio_irq_set *)irq_set_buf;
424 : 0 : irq_set->argsz = sizeof(irq_set_buf);
425 : 0 : irq_set->count = nr_vring + 1;
426 : 0 : irq_set->flags = VFIO_IRQ_SET_DATA_EVENTFD |
427 : : VFIO_IRQ_SET_ACTION_TRIGGER;
428 : 0 : irq_set->index = VFIO_PCI_MSIX_IRQ_INDEX;
429 : 0 : irq_set->start = 0;
430 : : fd_ptr = (int *)&irq_set->data;
431 : : /* The first interrupt is for the configure space change notification */
432 : 0 : fd_ptr[RTE_INTR_VEC_ZERO_OFFSET] =
433 : 0 : rte_intr_fd_get(internal->pdev->intr_handle);
434 : :
435 [ # # ]: 0 : for (i = 0; i < nr_vring; i++)
436 : 0 : internal->intr_fd[i] = -1;
437 : :
438 [ # # ]: 0 : for (i = 0; i < nr_vring; i++) {
439 : 0 : rte_vhost_get_vhost_vring(internal->vid, i, &vring);
440 : 0 : fd_ptr[RTE_INTR_VEC_RXTX_OFFSET + i] = vring.callfd;
441 [ # # ]: 0 : if (m_rx == true &&
442 [ # # # # ]: 0 : ((i & 1) == 0 || internal->hw.device_type == IFCVF_BLK)) {
443 : : /* For the net we only need to relay rx queue,
444 : : * which will change the mem of VM.
445 : : * For the blk we need to relay all the read cmd
446 : : * of each queue
447 : : */
448 : 0 : fd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
449 [ # # ]: 0 : if (fd < 0) {
450 : 0 : DRV_LOG(ERR, "can't setup eventfd: %s",
451 : : strerror(errno));
452 : 0 : return -1;
453 : : }
454 : 0 : internal->intr_fd[i] = fd;
455 : 0 : fd_ptr[RTE_INTR_VEC_RXTX_OFFSET + i] = fd;
456 : : }
457 : : }
458 : :
459 : 0 : ret = ioctl(internal->vfio_dev_fd, VFIO_DEVICE_SET_IRQS, irq_set);
460 [ # # ]: 0 : if (ret) {
461 : 0 : DRV_LOG(ERR, "Error enabling MSI-X interrupts: %s",
462 : : strerror(errno));
463 : 0 : return -1;
464 : : }
465 : :
466 : : return 0;
467 : : }
468 : :
469 : : static int
470 : 0 : vdpa_disable_vfio_intr(struct ifcvf_internal *internal)
471 : : {
472 : : int ret;
473 : : uint32_t i, nr_vring;
474 : : char irq_set_buf[MSIX_IRQ_SET_BUF_LEN];
475 : : struct vfio_irq_set *irq_set;
476 : :
477 : : irq_set = (struct vfio_irq_set *)irq_set_buf;
478 : 0 : irq_set->argsz = sizeof(irq_set_buf);
479 : 0 : irq_set->count = 0;
480 : 0 : irq_set->flags = VFIO_IRQ_SET_DATA_NONE | VFIO_IRQ_SET_ACTION_TRIGGER;
481 : 0 : irq_set->index = VFIO_PCI_MSIX_IRQ_INDEX;
482 : 0 : irq_set->start = 0;
483 : :
484 : 0 : nr_vring = rte_vhost_get_vring_num(internal->vid);
485 [ # # ]: 0 : for (i = 0; i < nr_vring; i++) {
486 [ # # ]: 0 : if (internal->intr_fd[i] >= 0)
487 : 0 : close(internal->intr_fd[i]);
488 : 0 : internal->intr_fd[i] = -1;
489 : : }
490 : :
491 : 0 : ret = ioctl(internal->vfio_dev_fd, VFIO_DEVICE_SET_IRQS, irq_set);
492 [ # # ]: 0 : if (ret) {
493 : 0 : DRV_LOG(ERR, "Error disabling MSI-X interrupts: %s",
494 : : strerror(errno));
495 : 0 : return -1;
496 : : }
497 : :
498 : : return 0;
499 : : }
500 : :
501 : : static uint32_t
502 : 0 : notify_relay(void *arg)
503 : : {
504 : : int i, kickfd, epfd, nfds = 0;
505 : : uint32_t qid, q_num;
506 : : struct epoll_event events[IFCVF_MAX_QUEUES * 2];
507 : : struct epoll_event ev;
508 : : uint64_t buf;
509 : : int nbytes;
510 : : struct rte_vhost_vring vring;
511 : : struct ifcvf_internal *internal = (struct ifcvf_internal *)arg;
512 : 0 : struct ifcvf_hw *hw = &internal->hw;
513 : :
514 : 0 : q_num = rte_vhost_get_vring_num(internal->vid);
515 : :
516 : 0 : epfd = epoll_create(IFCVF_MAX_QUEUES * 2);
517 [ # # ]: 0 : if (epfd < 0) {
518 : 0 : DRV_LOG(ERR, "failed to create epoll instance.");
519 : 0 : return 1;
520 : : }
521 : 0 : internal->epfd = epfd;
522 : :
523 : 0 : vring.kickfd = -1;
524 [ # # ]: 0 : for (qid = 0; qid < q_num; qid++) {
525 [ # # ]: 0 : if (!hw->vring[qid].enable)
526 : 0 : continue;
527 : 0 : ev.events = EPOLLIN | EPOLLPRI;
528 : 0 : rte_vhost_get_vhost_vring(internal->vid, qid, &vring);
529 : 0 : ev.data.u64 = qid | (uint64_t)vring.kickfd << 32;
530 [ # # ]: 0 : if (epoll_ctl(epfd, EPOLL_CTL_ADD, vring.kickfd, &ev) < 0) {
531 : 0 : DRV_LOG(ERR, "epoll add error: %s", strerror(errno));
532 : 0 : return 1;
533 : : }
534 : : }
535 : :
536 : : for (;;) {
537 : 0 : nfds = epoll_wait(epfd, events, q_num, -1);
538 [ # # ]: 0 : if (nfds < 0) {
539 [ # # ]: 0 : if (errno == EINTR)
540 : 0 : continue;
541 : 0 : DRV_LOG(ERR, "epoll_wait return fail");
542 : 0 : return 1;
543 : : }
544 : :
545 [ # # ]: 0 : for (i = 0; i < nfds; i++) {
546 : 0 : qid = events[i].data.u32;
547 : 0 : kickfd = (uint32_t)(events[i].data.u64 >> 32);
548 : : do {
549 : 0 : nbytes = read(kickfd, &buf, 8);
550 [ # # ]: 0 : if (nbytes < 0) {
551 [ # # ]: 0 : if (errno == EINTR ||
552 : : errno == EWOULDBLOCK ||
553 : : errno == EAGAIN)
554 : : continue;
555 : 0 : DRV_LOG(INFO, "Error reading "
556 : : "kickfd: %s",
557 : : strerror(errno));
558 : : }
559 : : break;
560 : : } while (1);
561 : :
562 : 0 : ifcvf_notify_queue(hw, qid);
563 : : }
564 : : }
565 : :
566 : : return 0;
567 : : }
568 : :
569 : : static int
570 : 0 : setup_notify_relay(struct ifcvf_internal *internal)
571 : : {
572 : : char name[RTE_THREAD_INTERNAL_NAME_SIZE];
573 : : int ret;
574 : :
575 : 0 : snprintf(name, sizeof(name), "ifc-noti%d", internal->vid);
576 : 0 : ret = rte_thread_create_internal_control(&internal->tid, name,
577 : : notify_relay, internal);
578 [ # # ]: 0 : if (ret != 0) {
579 : 0 : DRV_LOG(ERR, "failed to create notify relay pthread.");
580 : 0 : return -1;
581 : : }
582 : :
583 : : return 0;
584 : : }
585 : :
586 : : static int
587 : 0 : unset_notify_relay(struct ifcvf_internal *internal)
588 : : {
589 [ # # ]: 0 : if (internal->tid.opaque_id != 0) {
590 : 0 : pthread_cancel((pthread_t)internal->tid.opaque_id);
591 : 0 : rte_thread_join(internal->tid, NULL);
592 : : }
593 : 0 : internal->tid.opaque_id = 0;
594 : :
595 [ # # ]: 0 : if (internal->epfd >= 0)
596 : 0 : close(internal->epfd);
597 : 0 : internal->epfd = -1;
598 : :
599 : 0 : return 0;
600 : : }
601 : :
602 : : static void
603 : 0 : virtio_interrupt_handler(struct ifcvf_internal *internal)
604 : : {
605 : 0 : int vid = internal->vid;
606 : : int ret;
607 : :
608 : 0 : ret = rte_vhost_backend_config_change(vid, 1);
609 [ # # ]: 0 : if (ret)
610 : 0 : DRV_LOG(ERR, "failed to notify the guest about configuration space change.");
611 : 0 : }
612 : :
613 : : static uint32_t
614 : 0 : intr_relay(void *arg)
615 : : {
616 : : struct ifcvf_internal *internal = (struct ifcvf_internal *)arg;
617 : : struct epoll_event csc_event;
618 : : struct epoll_event ev;
619 : : uint64_t buf;
620 : : int nbytes;
621 : : int csc_epfd, csc_val = 0;
622 : :
623 : 0 : csc_epfd = epoll_create(1);
624 [ # # ]: 0 : if (csc_epfd < 0) {
625 : 0 : DRV_LOG(ERR, "failed to create epoll for config space change.");
626 : 0 : return 1;
627 : : }
628 : :
629 : 0 : ev.events = EPOLLIN | EPOLLPRI | EPOLLRDHUP | EPOLLHUP;
630 : 0 : ev.data.fd = rte_intr_fd_get(internal->pdev->intr_handle);
631 [ # # ]: 0 : if (epoll_ctl(csc_epfd, EPOLL_CTL_ADD,
632 : 0 : rte_intr_fd_get(internal->pdev->intr_handle), &ev) < 0) {
633 : 0 : DRV_LOG(ERR, "epoll add error: %s", strerror(errno));
634 : 0 : goto out;
635 : : }
636 : :
637 : 0 : internal->csc_epfd = csc_epfd;
638 : :
639 : : for (;;) {
640 : 0 : csc_val = epoll_wait(csc_epfd, &csc_event, 1, -1);
641 [ # # ]: 0 : if (csc_val < 0) {
642 [ # # ]: 0 : if (errno == EINTR)
643 : 0 : continue;
644 : 0 : DRV_LOG(ERR, "epoll_wait return fail.");
645 : 0 : goto out;
646 [ # # ]: 0 : } else if (csc_val == 0) {
647 : 0 : continue;
648 : : } else {
649 : : /* csc_val > 0 */
650 : 0 : nbytes = read(csc_event.data.fd, &buf, 8);
651 [ # # ]: 0 : if (nbytes < 0) {
652 [ # # ]: 0 : if (errno == EINTR ||
653 : : errno == EWOULDBLOCK ||
654 : : errno == EAGAIN)
655 : 0 : continue;
656 : 0 : DRV_LOG(ERR, "Error reading from file descriptor %d: %s",
657 : : csc_event.data.fd,
658 : : strerror(errno));
659 : 0 : goto out;
660 [ # # ]: 0 : } else if (nbytes == 0) {
661 : 0 : DRV_LOG(ERR, "Read nothing from file descriptor %d",
662 : : csc_event.data.fd);
663 : 0 : continue;
664 : : } else {
665 : 0 : virtio_interrupt_handler(internal);
666 : : }
667 : : }
668 : : }
669 : :
670 : 0 : out:
671 : : if (csc_epfd >= 0)
672 : 0 : close(csc_epfd);
673 : 0 : internal->csc_epfd = -1;
674 : :
675 : 0 : return 0;
676 : : }
677 : :
678 : : static int
679 : 0 : setup_intr_relay(struct ifcvf_internal *internal)
680 : : {
681 : : char name[RTE_THREAD_INTERNAL_NAME_SIZE];
682 : : int ret;
683 : :
684 : 0 : snprintf(name, sizeof(name), "ifc-int%d", internal->vid);
685 : 0 : ret = rte_thread_create_internal_control(&internal->intr_tid, name,
686 : : intr_relay, (void *)internal);
687 [ # # ]: 0 : if (ret) {
688 : 0 : DRV_LOG(ERR, "failed to create notify relay pthread.");
689 : 0 : return -1;
690 : : }
691 : : return 0;
692 : : }
693 : :
694 : : static void
695 : 0 : unset_intr_relay(struct ifcvf_internal *internal)
696 : : {
697 [ # # ]: 0 : if (internal->intr_tid.opaque_id != 0) {
698 : 0 : pthread_cancel((pthread_t)internal->intr_tid.opaque_id);
699 : 0 : rte_thread_join(internal->intr_tid, NULL);
700 : : }
701 : 0 : internal->intr_tid.opaque_id = 0;
702 : :
703 [ # # ]: 0 : if (internal->csc_epfd >= 0)
704 : 0 : close(internal->csc_epfd);
705 : 0 : internal->csc_epfd = -1;
706 : 0 : }
707 : :
708 : : static int
709 : 0 : update_datapath(struct ifcvf_internal *internal)
710 : : {
711 : : int ret;
712 : :
713 : 0 : rte_spinlock_lock(&internal->lock);
714 : :
715 [ # # # # ]: 0 : if (!rte_atomic32_read(&internal->running) &&
716 [ # # ]: 0 : (rte_atomic32_read(&internal->started) &&
717 : : rte_atomic32_read(&internal->dev_attached))) {
718 : 0 : ret = ifcvf_dma_map(internal, true);
719 [ # # ]: 0 : if (ret)
720 : 0 : goto err;
721 : :
722 : 0 : ret = vdpa_enable_vfio_intr(internal, false);
723 [ # # ]: 0 : if (ret)
724 : 0 : goto err;
725 : :
726 : 0 : ret = vdpa_ifcvf_start(internal);
727 [ # # ]: 0 : if (ret)
728 : 0 : goto err;
729 : :
730 : 0 : ret = setup_notify_relay(internal);
731 [ # # ]: 0 : if (ret)
732 : 0 : goto err;
733 : :
734 : 0 : ret = setup_intr_relay(internal);
735 [ # # ]: 0 : if (ret)
736 : 0 : goto err;
737 : :
738 : : rte_atomic32_set(&internal->running, 1);
739 [ # # # # ]: 0 : } else if (rte_atomic32_read(&internal->running) &&
740 [ # # ]: 0 : (!rte_atomic32_read(&internal->started) ||
741 : : !rte_atomic32_read(&internal->dev_attached))) {
742 : 0 : unset_intr_relay(internal);
743 : :
744 : 0 : ret = unset_notify_relay(internal);
745 [ # # ]: 0 : if (ret)
746 : 0 : goto err;
747 : :
748 : 0 : vdpa_ifcvf_stop(internal);
749 : :
750 : 0 : ret = vdpa_disable_vfio_intr(internal);
751 [ # # ]: 0 : if (ret)
752 : 0 : goto err;
753 : :
754 : 0 : ret = ifcvf_dma_map(internal, false);
755 [ # # ]: 0 : if (ret)
756 : 0 : goto err;
757 : :
758 : : rte_atomic32_set(&internal->running, 0);
759 : : }
760 : :
761 : : rte_spinlock_unlock(&internal->lock);
762 : 0 : return 0;
763 : 0 : err:
764 : : rte_spinlock_unlock(&internal->lock);
765 : 0 : return ret;
766 : : }
767 : :
768 : : static int
769 : 0 : m_ifcvf_start(struct ifcvf_internal *internal)
770 : : {
771 : 0 : struct ifcvf_hw *hw = &internal->hw;
772 : : uint32_t i, nr_vring;
773 : : int vid, ret;
774 : : struct rte_vhost_vring vq;
775 : : void *vring_buf;
776 : : uint64_t m_vring_iova = IFCVF_MEDIATED_VRING;
777 : : uint64_t size;
778 : : uint64_t gpa;
779 : :
780 : : memset(&vq, 0, sizeof(vq));
781 : 0 : vid = internal->vid;
782 : 0 : nr_vring = rte_vhost_get_vring_num(vid);
783 : 0 : rte_vhost_get_negotiated_features(vid, &hw->req_features);
784 : :
785 [ # # ]: 0 : for (i = 0; i < nr_vring; i++) {
786 : 0 : rte_vhost_get_vhost_vring(vid, i, &vq);
787 : :
788 : 0 : size = RTE_ALIGN_CEIL(vring_size(vq.size, rte_mem_page_size()),
789 : : rte_mem_page_size());
790 : 0 : vring_buf = rte_zmalloc("ifcvf", size, rte_mem_page_size());
791 : 0 : vring_init(&internal->m_vring[i], vq.size, vring_buf,
792 : : rte_mem_page_size());
793 : :
794 : 0 : ret = rte_vfio_container_dma_map(internal->vfio_container_fd,
795 : : (uint64_t)(uintptr_t)vring_buf, m_vring_iova, size);
796 [ # # ]: 0 : if (ret < 0) {
797 : 0 : DRV_LOG(ERR, "mediated vring DMA map failed.");
798 : 0 : goto error;
799 : : }
800 : :
801 : 0 : gpa = hva_to_gpa(vid, (uint64_t)(uintptr_t)vq.desc);
802 [ # # ]: 0 : if (gpa == 0) {
803 : 0 : DRV_LOG(ERR, "Fail to get GPA for descriptor ring.");
804 : 0 : return -1;
805 : : }
806 : 0 : hw->vring[i].desc = gpa;
807 : :
808 : 0 : gpa = hva_to_gpa(vid, (uint64_t)(uintptr_t)vq.avail);
809 [ # # ]: 0 : if (gpa == 0) {
810 : 0 : DRV_LOG(ERR, "Fail to get GPA for available ring.");
811 : 0 : return -1;
812 : : }
813 : 0 : hw->vring[i].avail = gpa;
814 : :
815 : : /* NET: Direct I/O for Tx queue, relay for Rx queue
816 : : * BLK: relay every queue
817 : : */
818 [ # # # # ]: 0 : if ((internal->hw.device_type == IFCVF_NET) && (i & 1)) {
819 : 0 : gpa = hva_to_gpa(vid, (uint64_t)(uintptr_t)vq.used);
820 [ # # ]: 0 : if (gpa == 0) {
821 : 0 : DRV_LOG(ERR, "Fail to get GPA for used ring.");
822 : 0 : return -1;
823 : : }
824 : 0 : hw->vring[i].used = gpa;
825 : : } else {
826 : 0 : hw->vring[i].used = m_vring_iova +
827 : 0 : (char *)internal->m_vring[i].used -
828 : 0 : (char *)internal->m_vring[i].desc;
829 : : }
830 : :
831 : 0 : hw->vring[i].size = vq.size;
832 : :
833 : 0 : rte_vhost_get_vring_base(vid, i,
834 : 0 : &internal->m_vring[i].avail->idx,
835 : 0 : &internal->m_vring[i].used->idx);
836 : :
837 : 0 : rte_vhost_get_vring_base(vid, i, &hw->vring[i].last_avail_idx,
838 : 0 : &hw->vring[i].last_used_idx);
839 : :
840 : 0 : m_vring_iova += size;
841 : : }
842 : 0 : hw->nr_vring = nr_vring;
843 : :
844 : 0 : return ifcvf_start_hw(&internal->hw);
845 : :
846 : : error:
847 [ # # ]: 0 : for (i = 0; i < nr_vring; i++)
848 : 0 : rte_free(internal->m_vring[i].desc);
849 : :
850 : : return -1;
851 : : }
852 : :
853 : : static int
854 : 0 : m_ifcvf_stop(struct ifcvf_internal *internal)
855 : : {
856 : : int vid;
857 : : uint32_t i;
858 : : struct rte_vhost_vring vq;
859 : 0 : struct ifcvf_hw *hw = &internal->hw;
860 : : uint64_t m_vring_iova = IFCVF_MEDIATED_VRING;
861 : : uint64_t size, len;
862 : : u32 ring_state = 0;
863 : :
864 : 0 : vid = internal->vid;
865 : :
866 : : /* to make sure no packet is lost for blk device
867 : : * do not stop until last_avail_idx == last_used_idx
868 : : */
869 [ # # ]: 0 : if (internal->hw.device_type == IFCVF_BLK) {
870 [ # # ]: 0 : for (i = 0; i < hw->nr_vring; i++) {
871 : : do {
872 [ # # ]: 0 : if (hw->lm_cfg != NULL)
873 : 0 : ring_state = *(u32 *)(hw->lm_cfg +
874 : 0 : IFCVF_LM_RING_STATE_OFFSET +
875 : 0 : i * IFCVF_LM_CFG_SIZE);
876 : 0 : hw->vring[i].last_avail_idx =
877 : 0 : (u16)(ring_state & IFCVF_16_BIT_MASK);
878 : 0 : hw->vring[i].last_used_idx =
879 : 0 : (u16)(ring_state >> 16);
880 : 0 : usleep(10);
881 : 0 : } while (hw->vring[i].last_avail_idx !=
882 [ # # ]: 0 : hw->vring[i].last_used_idx);
883 : : }
884 : : }
885 : :
886 : 0 : ifcvf_stop_hw(hw);
887 : :
888 [ # # ]: 0 : for (i = 0; i < hw->nr_vring; i++) {
889 : : /* synchronize remaining new used entries if any */
890 [ # # ]: 0 : if (internal->hw.device_type == IFCVF_NET) {
891 [ # # ]: 0 : if ((i & 1) == 0)
892 : 0 : update_used_ring(internal, i);
893 [ # # ]: 0 : } else if (internal->hw.device_type == IFCVF_BLK) {
894 : 0 : update_used_ring(internal, i);
895 : : }
896 : :
897 : 0 : rte_vhost_get_vhost_vring(vid, i, &vq);
898 : 0 : len = IFCVF_USED_RING_LEN(vq.size);
899 : 0 : rte_vhost_log_used_vring(vid, i, 0, len);
900 : :
901 : 0 : size = RTE_ALIGN_CEIL(vring_size(vq.size, rte_mem_page_size()),
902 : : rte_mem_page_size());
903 : 0 : rte_vfio_container_dma_unmap(internal->vfio_container_fd,
904 : 0 : (uint64_t)(uintptr_t)internal->m_vring[i].desc,
905 : : m_vring_iova, size);
906 : :
907 : 0 : rte_vhost_set_vring_base(vid, i, hw->vring[i].last_avail_idx,
908 : 0 : hw->vring[i].last_used_idx);
909 : 0 : rte_free(internal->m_vring[i].desc);
910 : 0 : m_vring_iova += size;
911 : : }
912 : :
913 : 0 : return 0;
914 : : }
915 : :
916 : : static void
917 : 0 : update_used_ring(struct ifcvf_internal *internal, uint16_t qid)
918 : : {
919 : 0 : rte_vdpa_relay_vring_used(internal->vid, qid, &internal->m_vring[qid]);
920 : 0 : rte_vhost_vring_call(internal->vid, qid);
921 : 0 : }
922 : :
923 : : static uint32_t
924 : 0 : vring_relay(void *arg)
925 : : {
926 : : int i, vid, epfd, fd, nfds;
927 : : struct ifcvf_internal *internal = (struct ifcvf_internal *)arg;
928 : : struct rte_vhost_vring vring;
929 : : uint16_t qid, q_num;
930 : : struct epoll_event events[IFCVF_MAX_QUEUES * 4];
931 : : struct epoll_event ev;
932 : : int nbytes;
933 : : uint64_t buf;
934 : :
935 : 0 : vid = internal->vid;
936 : 0 : q_num = rte_vhost_get_vring_num(vid);
937 : :
938 : : /* add notify fd and interrupt fd to epoll */
939 : 0 : epfd = epoll_create(IFCVF_MAX_QUEUES * 2);
940 [ # # ]: 0 : if (epfd < 0) {
941 : 0 : DRV_LOG(ERR, "failed to create epoll instance.");
942 : 0 : return 1;
943 : : }
944 : 0 : internal->epfd = epfd;
945 : :
946 : 0 : vring.kickfd = -1;
947 [ # # ]: 0 : for (qid = 0; qid < q_num; qid++) {
948 : 0 : ev.events = EPOLLIN | EPOLLPRI;
949 : 0 : rte_vhost_get_vhost_vring(vid, qid, &vring);
950 : 0 : ev.data.u64 = qid << 1 | (uint64_t)vring.kickfd << 32;
951 [ # # ]: 0 : if (epoll_ctl(epfd, EPOLL_CTL_ADD, vring.kickfd, &ev) < 0) {
952 : 0 : DRV_LOG(ERR, "epoll add error: %s", strerror(errno));
953 : 0 : return 1;
954 : : }
955 : : }
956 : :
957 [ # # ]: 0 : for (qid = 0; qid < q_num; qid += 1) {
958 [ # # # # ]: 0 : if ((internal->hw.device_type == IFCVF_NET) && (qid & 1))
959 : 0 : continue;
960 : 0 : ev.events = EPOLLIN | EPOLLPRI;
961 : : /* leave a flag to mark it's for interrupt */
962 : 0 : ev.data.u64 = 1 | qid << 1 |
963 : 0 : (uint64_t)internal->intr_fd[qid] << 32;
964 [ # # ]: 0 : if (epoll_ctl(epfd, EPOLL_CTL_ADD, internal->intr_fd[qid], &ev)
965 : : < 0) {
966 : 0 : DRV_LOG(ERR, "epoll add error: %s", strerror(errno));
967 : 0 : return 1;
968 : : }
969 : 0 : update_used_ring(internal, qid);
970 : : }
971 : :
972 : : /* start relay with a first kick */
973 [ # # ]: 0 : for (qid = 0; qid < q_num; qid++)
974 : 0 : ifcvf_notify_queue(&internal->hw, qid);
975 : :
976 : : /* listen to the events and react accordingly */
977 : : for (;;) {
978 : 0 : nfds = epoll_wait(epfd, events, q_num * 2, -1);
979 [ # # ]: 0 : if (nfds < 0) {
980 [ # # ]: 0 : if (errno == EINTR)
981 : 0 : continue;
982 : 0 : DRV_LOG(ERR, "epoll_wait return fail.");
983 : 0 : return 1;
984 : : }
985 : :
986 [ # # ]: 0 : for (i = 0; i < nfds; i++) {
987 : 0 : fd = (uint32_t)(events[i].data.u64 >> 32);
988 : : do {
989 : 0 : nbytes = read(fd, &buf, 8);
990 [ # # ]: 0 : if (nbytes < 0) {
991 [ # # ]: 0 : if (errno == EINTR ||
992 : : errno == EWOULDBLOCK ||
993 : : errno == EAGAIN)
994 : : continue;
995 : 0 : DRV_LOG(INFO, "Error reading "
996 : : "kickfd: %s",
997 : : strerror(errno));
998 : : }
999 : : break;
1000 : : } while (1);
1001 : :
1002 : 0 : qid = events[i].data.u32 >> 1;
1003 : :
1004 [ # # ]: 0 : if (events[i].data.u32 & 1)
1005 : 0 : update_used_ring(internal, qid);
1006 : : else
1007 : 0 : ifcvf_notify_queue(&internal->hw, qid);
1008 : : }
1009 : : }
1010 : :
1011 : : return 0;
1012 : : }
1013 : :
1014 : : static int
1015 : 0 : setup_vring_relay(struct ifcvf_internal *internal)
1016 : : {
1017 : : char name[RTE_THREAD_INTERNAL_NAME_SIZE];
1018 : : int ret;
1019 : :
1020 : 0 : snprintf(name, sizeof(name), "ifc-ring%d", internal->vid);
1021 : 0 : ret = rte_thread_create_internal_control(&internal->tid, name,
1022 : : vring_relay, internal);
1023 [ # # ]: 0 : if (ret != 0) {
1024 : 0 : DRV_LOG(ERR, "failed to create ring relay pthread.");
1025 : 0 : return -1;
1026 : : }
1027 : :
1028 : : return 0;
1029 : : }
1030 : :
1031 : : static int
1032 : 0 : unset_vring_relay(struct ifcvf_internal *internal)
1033 : : {
1034 [ # # ]: 0 : if (internal->tid.opaque_id != 0) {
1035 : 0 : pthread_cancel((pthread_t)internal->tid.opaque_id);
1036 : 0 : rte_thread_join(internal->tid, NULL);
1037 : : }
1038 : 0 : internal->tid.opaque_id = 0;
1039 : :
1040 [ # # ]: 0 : if (internal->epfd >= 0)
1041 : 0 : close(internal->epfd);
1042 : 0 : internal->epfd = -1;
1043 : :
1044 : 0 : return 0;
1045 : : }
1046 : :
1047 : : static int
1048 : 0 : ifcvf_sw_fallback_switchover(struct ifcvf_internal *internal)
1049 : : {
1050 : : int ret;
1051 : 0 : int vid = internal->vid;
1052 : :
1053 : : /* stop the direct IO data path */
1054 : 0 : unset_notify_relay(internal);
1055 : 0 : vdpa_ifcvf_stop(internal);
1056 : :
1057 : 0 : unset_intr_relay(internal);
1058 : :
1059 : 0 : vdpa_disable_vfio_intr(internal);
1060 : :
1061 : : rte_atomic32_set(&internal->running, 0);
1062 : :
1063 : 0 : ret = rte_vhost_host_notifier_ctrl(vid, RTE_VHOST_QUEUE_ALL, false);
1064 [ # # ]: 0 : if (ret && ret != -ENOTSUP)
1065 : 0 : goto error;
1066 : :
1067 : : /* set up interrupt for interrupt relay */
1068 : 0 : ret = vdpa_enable_vfio_intr(internal, true);
1069 [ # # ]: 0 : if (ret)
1070 : 0 : goto unmap;
1071 : :
1072 : : /* config the VF */
1073 : 0 : ret = m_ifcvf_start(internal);
1074 [ # # ]: 0 : if (ret)
1075 : 0 : goto unset_intr;
1076 : :
1077 : : /* set up vring relay thread */
1078 : 0 : ret = setup_vring_relay(internal);
1079 [ # # ]: 0 : if (ret)
1080 : 0 : goto stop_vf;
1081 : :
1082 : 0 : rte_vhost_host_notifier_ctrl(vid, RTE_VHOST_QUEUE_ALL, true);
1083 : :
1084 : 0 : internal->sw_fallback_running = true;
1085 : :
1086 : 0 : return 0;
1087 : :
1088 : : stop_vf:
1089 : 0 : m_ifcvf_stop(internal);
1090 : 0 : unset_intr:
1091 : 0 : vdpa_disable_vfio_intr(internal);
1092 : 0 : unmap:
1093 : 0 : ifcvf_dma_map(internal, false);
1094 : : error:
1095 : : return -1;
1096 : : }
1097 : :
1098 : : static int
1099 : 0 : ifcvf_dev_config(int vid)
1100 : : {
1101 : : struct rte_vdpa_device *vdev;
1102 : : struct internal_list *list;
1103 : : struct ifcvf_internal *internal;
1104 : : struct ifcvf_hw *hw;
1105 : : uint16_t i;
1106 : :
1107 : 0 : vdev = rte_vhost_get_vdpa_device(vid);
1108 : 0 : list = find_internal_resource_by_vdev(vdev);
1109 [ # # ]: 0 : if (list == NULL) {
1110 : 0 : DRV_LOG(ERR, "Invalid vDPA device: %p", vdev);
1111 : 0 : return -1;
1112 : : }
1113 : :
1114 : 0 : internal = list->internal;
1115 : 0 : internal->vid = vid;
1116 : : rte_atomic32_set(&internal->dev_attached, 1);
1117 [ # # ]: 0 : if (update_datapath(internal) < 0) {
1118 : 0 : DRV_LOG(ERR, "failed to update datapath for vDPA device %s",
1119 : : vdev->device->name);
1120 : : rte_atomic32_set(&internal->dev_attached, 0);
1121 : 0 : return -1;
1122 : : }
1123 : :
1124 : : hw = &internal->hw;
1125 [ # # ]: 0 : for (i = 0; i < hw->nr_vring; i++) {
1126 [ # # ]: 0 : if (!hw->vring[i].enable)
1127 : 0 : continue;
1128 [ # # ]: 0 : if (rte_vhost_host_notifier_ctrl(vid, i, true) != 0)
1129 : 0 : DRV_LOG(NOTICE, "vDPA (%s): software relay is used.",
1130 : : vdev->device->name);
1131 : : }
1132 : :
1133 : 0 : internal->configured = 1;
1134 : 0 : DRV_LOG(INFO, "vDPA device %s is configured", vdev->device->name);
1135 : 0 : return 0;
1136 : : }
1137 : :
1138 : : static int
1139 : 0 : ifcvf_dev_close(int vid)
1140 : : {
1141 : : struct rte_vdpa_device *vdev;
1142 : : struct internal_list *list;
1143 : : struct ifcvf_internal *internal;
1144 : :
1145 : 0 : vdev = rte_vhost_get_vdpa_device(vid);
1146 : 0 : list = find_internal_resource_by_vdev(vdev);
1147 [ # # ]: 0 : if (list == NULL) {
1148 : 0 : DRV_LOG(ERR, "Invalid vDPA device: %p", vdev);
1149 : 0 : return -1;
1150 : : }
1151 : :
1152 : 0 : internal = list->internal;
1153 : :
1154 [ # # ]: 0 : if (internal->sw_fallback_running) {
1155 : : /* unset ring relay */
1156 : 0 : unset_vring_relay(internal);
1157 : :
1158 : : /* reset VF */
1159 : 0 : m_ifcvf_stop(internal);
1160 : :
1161 : : /* remove interrupt setting */
1162 : 0 : vdpa_disable_vfio_intr(internal);
1163 : :
1164 : : /* unset DMA map for guest memory */
1165 : 0 : ifcvf_dma_map(internal, false);
1166 : :
1167 : 0 : internal->sw_fallback_running = false;
1168 : : } else {
1169 : : rte_atomic32_set(&internal->dev_attached, 0);
1170 [ # # ]: 0 : if (update_datapath(internal) < 0) {
1171 : 0 : DRV_LOG(ERR, "failed to update datapath for vDPA device %s",
1172 : : vdev->device->name);
1173 : 0 : internal->configured = 0;
1174 : 0 : return -1;
1175 : : }
1176 : : }
1177 : :
1178 : 0 : internal->configured = 0;
1179 : 0 : return 0;
1180 : : }
1181 : :
1182 : : static int
1183 : 0 : ifcvf_set_features(int vid)
1184 : : {
1185 : 0 : uint64_t features = 0;
1186 : : struct rte_vdpa_device *vdev;
1187 : : struct internal_list *list;
1188 : : struct ifcvf_internal *internal;
1189 : 0 : uint64_t log_base = 0, log_size = 0;
1190 : :
1191 : 0 : vdev = rte_vhost_get_vdpa_device(vid);
1192 : 0 : list = find_internal_resource_by_vdev(vdev);
1193 [ # # ]: 0 : if (list == NULL) {
1194 : 0 : DRV_LOG(ERR, "Invalid vDPA device: %p", vdev);
1195 : 0 : return -1;
1196 : : }
1197 : :
1198 : 0 : internal = list->internal;
1199 : 0 : rte_vhost_get_negotiated_features(vid, &features);
1200 : :
1201 [ # # ]: 0 : if (!RTE_VHOST_NEED_LOG(features))
1202 : : return 0;
1203 : :
1204 [ # # ]: 0 : if (internal->sw_lm) {
1205 : 0 : ifcvf_sw_fallback_switchover(internal);
1206 : : } else {
1207 : 0 : rte_vhost_get_log_base(vid, &log_base, &log_size);
1208 : 0 : rte_vfio_container_dma_map(internal->vfio_container_fd,
1209 : : log_base, IFCVF_LOG_BASE, log_size);
1210 : 0 : ifcvf_enable_logging(&internal->hw, IFCVF_LOG_BASE, log_size);
1211 : : }
1212 : :
1213 : : return 0;
1214 : : }
1215 : :
1216 : : static int
1217 : 0 : ifcvf_get_vfio_group_fd(int vid)
1218 : : {
1219 : : struct rte_vdpa_device *vdev;
1220 : : struct internal_list *list;
1221 : :
1222 : 0 : vdev = rte_vhost_get_vdpa_device(vid);
1223 : 0 : list = find_internal_resource_by_vdev(vdev);
1224 [ # # ]: 0 : if (list == NULL) {
1225 : 0 : DRV_LOG(ERR, "Invalid vDPA device: %p", vdev);
1226 : 0 : return -1;
1227 : : }
1228 : :
1229 : 0 : return list->internal->vfio_group_fd;
1230 : : }
1231 : :
1232 : : static int
1233 : 0 : ifcvf_get_vfio_device_fd(int vid)
1234 : : {
1235 : : struct rte_vdpa_device *vdev;
1236 : : struct internal_list *list;
1237 : :
1238 : 0 : vdev = rte_vhost_get_vdpa_device(vid);
1239 : 0 : list = find_internal_resource_by_vdev(vdev);
1240 [ # # ]: 0 : if (list == NULL) {
1241 : 0 : DRV_LOG(ERR, "Invalid vDPA device: %p", vdev);
1242 : 0 : return -1;
1243 : : }
1244 : :
1245 : 0 : return list->internal->vfio_dev_fd;
1246 : : }
1247 : :
1248 : : static int
1249 : 0 : ifcvf_get_notify_area(int vid, int qid, uint64_t *offset, uint64_t *size)
1250 : : {
1251 : : struct rte_vdpa_device *vdev;
1252 : : struct internal_list *list;
1253 : : struct ifcvf_internal *internal;
1254 : 0 : struct vfio_region_info reg = { .argsz = sizeof(reg) };
1255 : : int ret;
1256 : :
1257 : 0 : vdev = rte_vhost_get_vdpa_device(vid);
1258 : 0 : list = find_internal_resource_by_vdev(vdev);
1259 [ # # ]: 0 : if (list == NULL) {
1260 : 0 : DRV_LOG(ERR, "Invalid vDPA device: %p", vdev);
1261 : 0 : return -1;
1262 : : }
1263 : :
1264 : 0 : internal = list->internal;
1265 : :
1266 : 0 : reg.index = ifcvf_get_notify_region(&internal->hw);
1267 : 0 : ret = ioctl(internal->vfio_dev_fd, VFIO_DEVICE_GET_REGION_INFO, ®);
1268 [ # # ]: 0 : if (ret) {
1269 : 0 : DRV_LOG(ERR, "Get not get device region info: %s",
1270 : : strerror(errno));
1271 : 0 : return -1;
1272 : : }
1273 : :
1274 : 0 : *offset = ifcvf_get_queue_notify_off(&internal->hw, qid) + reg.offset;
1275 : 0 : *size = 0x1000;
1276 : :
1277 : 0 : return 0;
1278 : : }
1279 : :
1280 : : static int
1281 : 0 : ifcvf_get_queue_num(struct rte_vdpa_device *vdev, uint32_t *queue_num)
1282 : : {
1283 : : struct internal_list *list;
1284 : :
1285 : 0 : list = find_internal_resource_by_vdev(vdev);
1286 [ # # ]: 0 : if (list == NULL) {
1287 : 0 : DRV_LOG(ERR, "Invalid vDPA device: %p", vdev);
1288 : 0 : return -1;
1289 : : }
1290 : :
1291 : 0 : *queue_num = list->internal->max_queues;
1292 : :
1293 : 0 : return 0;
1294 : : }
1295 : :
1296 : : static int
1297 : 0 : ifcvf_get_vdpa_features(struct rte_vdpa_device *vdev, uint64_t *features)
1298 : : {
1299 : : struct internal_list *list;
1300 : :
1301 : 0 : list = find_internal_resource_by_vdev(vdev);
1302 [ # # ]: 0 : if (list == NULL) {
1303 : 0 : DRV_LOG(ERR, "Invalid vDPA device: %p", vdev);
1304 : 0 : return -1;
1305 : : }
1306 : :
1307 : 0 : *features = list->internal->features;
1308 : :
1309 : 0 : return 0;
1310 : : }
1311 : :
1312 : : #define VDPA_SUPPORTED_PROTOCOL_FEATURES \
1313 : : (1ULL << VHOST_USER_PROTOCOL_F_REPLY_ACK | \
1314 : : 1ULL << VHOST_USER_PROTOCOL_F_BACKEND_REQ | \
1315 : : 1ULL << VHOST_USER_PROTOCOL_F_BACKEND_SEND_FD | \
1316 : : 1ULL << VHOST_USER_PROTOCOL_F_HOST_NOTIFIER | \
1317 : : 1ULL << VHOST_USER_PROTOCOL_F_LOG_SHMFD | \
1318 : : 1ULL << VHOST_USER_PROTOCOL_F_MQ | \
1319 : : 1ULL << VHOST_USER_PROTOCOL_F_STATUS)
1320 : :
1321 : : #define VDPA_BLK_PROTOCOL_FEATURES \
1322 : : (1ULL << VHOST_USER_PROTOCOL_F_CONFIG)
1323 : :
1324 : : static int
1325 : 0 : ifcvf_get_protocol_features(struct rte_vdpa_device *vdev, uint64_t *features)
1326 : : {
1327 : : RTE_SET_USED(vdev);
1328 : :
1329 : 0 : *features = VDPA_SUPPORTED_PROTOCOL_FEATURES;
1330 : 0 : return 0;
1331 : : }
1332 : :
1333 : : static int
1334 : 0 : ifcvf_config_vring(struct ifcvf_internal *internal, int vring)
1335 : : {
1336 : 0 : struct ifcvf_hw *hw = &internal->hw;
1337 : 0 : int vid = internal->vid;
1338 : : struct rte_vhost_vring vq;
1339 : : uint64_t gpa;
1340 : :
1341 [ # # ]: 0 : if (hw->vring[vring].enable) {
1342 : 0 : rte_vhost_get_vhost_vring(vid, vring, &vq);
1343 : 0 : gpa = hva_to_gpa(vid, (uint64_t)(uintptr_t)vq.desc);
1344 [ # # ]: 0 : if (gpa == 0) {
1345 : 0 : DRV_LOG(ERR, "Fail to get GPA for descriptor ring.");
1346 : 0 : return -1;
1347 : : }
1348 : 0 : hw->vring[vring].desc = gpa;
1349 : :
1350 : 0 : gpa = hva_to_gpa(vid, (uint64_t)(uintptr_t)vq.avail);
1351 [ # # ]: 0 : if (gpa == 0) {
1352 : 0 : DRV_LOG(ERR, "Fail to get GPA for available ring.");
1353 : 0 : return -1;
1354 : : }
1355 : 0 : hw->vring[vring].avail = gpa;
1356 : :
1357 : 0 : gpa = hva_to_gpa(vid, (uint64_t)(uintptr_t)vq.used);
1358 [ # # ]: 0 : if (gpa == 0) {
1359 : 0 : DRV_LOG(ERR, "Fail to get GPA for used ring.");
1360 : 0 : return -1;
1361 : : }
1362 : 0 : hw->vring[vring].used = gpa;
1363 : :
1364 : 0 : hw->vring[vring].size = vq.size;
1365 : 0 : rte_vhost_get_vring_base(vid, vring,
1366 : 0 : &hw->vring[vring].last_avail_idx,
1367 : 0 : &hw->vring[vring].last_used_idx);
1368 : 0 : ifcvf_enable_vring_hw(&internal->hw, vring);
1369 : : } else {
1370 : 0 : ifcvf_disable_vring_hw(&internal->hw, vring);
1371 : 0 : rte_vhost_set_vring_base(vid, vring,
1372 : 0 : hw->vring[vring].last_avail_idx,
1373 : 0 : hw->vring[vring].last_used_idx);
1374 : : }
1375 : :
1376 : : return 0;
1377 : : }
1378 : :
1379 : : static int
1380 : 0 : ifcvf_set_vring_state(int vid, int vring, int state)
1381 : : {
1382 : : struct rte_vdpa_device *vdev;
1383 : : struct internal_list *list;
1384 : : struct ifcvf_internal *internal;
1385 : : struct ifcvf_hw *hw;
1386 : 0 : bool enable = !!state;
1387 : : int ret = 0;
1388 : :
1389 : 0 : vdev = rte_vhost_get_vdpa_device(vid);
1390 : 0 : list = find_internal_resource_by_vdev(vdev);
1391 [ # # ]: 0 : if (list == NULL) {
1392 : 0 : DRV_LOG(ERR, "Invalid vDPA device: %p", vdev);
1393 : 0 : return -1;
1394 : : }
1395 : :
1396 [ # # ]: 0 : DRV_LOG(INFO, "%s queue %d of vDPA device %s",
1397 : : enable ? "enable" : "disable", vring, vdev->device->name);
1398 : :
1399 : 0 : internal = list->internal;
1400 [ # # # # ]: 0 : if (vring < 0 || vring >= internal->max_queues * 2) {
1401 : 0 : DRV_LOG(ERR, "Vring index %d not correct", vring);
1402 : 0 : return -1;
1403 : : }
1404 : :
1405 : : hw = &internal->hw;
1406 : 0 : hw->vring[vring].enable = enable;
1407 : :
1408 [ # # ]: 0 : if (!internal->configured)
1409 : : return 0;
1410 : :
1411 : 0 : unset_notify_relay(internal);
1412 : :
1413 : 0 : ret = vdpa_enable_vfio_intr(internal, false);
1414 [ # # ]: 0 : if (ret) {
1415 : 0 : DRV_LOG(ERR, "failed to set vfio interrupt of vDPA device %s",
1416 : : vdev->device->name);
1417 : 0 : return ret;
1418 : : }
1419 : :
1420 : 0 : ret = ifcvf_config_vring(internal, vring);
1421 [ # # ]: 0 : if (ret) {
1422 : 0 : DRV_LOG(ERR, "failed to configure queue %d of vDPA device %s",
1423 : : vring, vdev->device->name);
1424 : 0 : return ret;
1425 : : }
1426 : :
1427 : 0 : ret = setup_notify_relay(internal);
1428 [ # # ]: 0 : if (ret) {
1429 : 0 : DRV_LOG(ERR, "failed to setup notify relay of vDPA device %s",
1430 : : vdev->device->name);
1431 : 0 : return ret;
1432 : : }
1433 : :
1434 : 0 : ret = rte_vhost_host_notifier_ctrl(vid, vring, enable);
1435 [ # # ]: 0 : if (ret) {
1436 : 0 : DRV_LOG(ERR, "vDPA device %s queue %d host notifier ctrl fail",
1437 : : vdev->device->name, vring);
1438 : 0 : return ret;
1439 : : }
1440 : :
1441 : : return 0;
1442 : : }
1443 : :
1444 : : static int
1445 : 0 : ifcvf_get_device_type(struct rte_vdpa_device *vdev,
1446 : : uint32_t *type)
1447 : : {
1448 : : struct ifcvf_internal *internal;
1449 : : struct internal_list *list;
1450 : 0 : struct rte_device *rte_dev = vdev->device;
1451 : :
1452 : 0 : list = find_internal_resource_by_rte_dev(rte_dev);
1453 [ # # ]: 0 : if (list == NULL) {
1454 : 0 : DRV_LOG(ERR, "Invalid rte device: %p", rte_dev);
1455 : 0 : return -1;
1456 : : }
1457 : :
1458 : 0 : internal = list->internal;
1459 : :
1460 [ # # ]: 0 : if (internal->hw.device_type == IFCVF_BLK)
1461 : 0 : *type = RTE_VHOST_VDPA_DEVICE_TYPE_BLK;
1462 : : else
1463 : 0 : *type = RTE_VHOST_VDPA_DEVICE_TYPE_NET;
1464 : :
1465 : : return 0;
1466 : : }
1467 : :
1468 : : static struct rte_vdpa_dev_ops ifcvf_net_ops = {
1469 : : .get_queue_num = ifcvf_get_queue_num,
1470 : : .get_features = ifcvf_get_vdpa_features,
1471 : : .get_protocol_features = ifcvf_get_protocol_features,
1472 : : .dev_conf = ifcvf_dev_config,
1473 : : .dev_close = ifcvf_dev_close,
1474 : : .set_vring_state = ifcvf_set_vring_state,
1475 : : .set_features = ifcvf_set_features,
1476 : : .migration_done = NULL,
1477 : : .get_vfio_group_fd = ifcvf_get_vfio_group_fd,
1478 : : .get_vfio_device_fd = ifcvf_get_vfio_device_fd,
1479 : : .get_notify_area = ifcvf_get_notify_area,
1480 : : .get_dev_type = ifcvf_get_device_type,
1481 : : };
1482 : :
1483 : : static inline int
1484 : 0 : open_int(const char *key __rte_unused, const char *value, void *extra_args)
1485 : : {
1486 : : uint16_t *n = extra_args;
1487 : :
1488 [ # # ]: 0 : if (value == NULL || extra_args == NULL)
1489 : : return -EINVAL;
1490 : :
1491 : 0 : *n = (uint16_t)strtoul(value, NULL, 0);
1492 [ # # # # ]: 0 : if (*n == USHRT_MAX && errno == ERANGE)
1493 : 0 : return -1;
1494 : :
1495 : : return 0;
1496 : : }
1497 : :
1498 : : static int16_t
1499 : 0 : ifcvf_pci_get_device_type(struct rte_pci_device *pci_dev)
1500 : : {
1501 : 0 : uint16_t pci_device_id = pci_dev->id.device_id;
1502 : : uint16_t device_id;
1503 : :
1504 [ # # ]: 0 : if (pci_device_id < 0x1000 || pci_device_id > 0x107f) {
1505 : 0 : DRV_LOG(ERR, "Probe device is not a virtio device");
1506 : 0 : return -1;
1507 : : }
1508 : :
1509 [ # # ]: 0 : if (pci_device_id < 0x1040) {
1510 : : /* Transitional devices: use the PCI subsystem device id as
1511 : : * virtio device id, same as legacy driver always did.
1512 : : */
1513 : 0 : device_id = pci_dev->id.subsystem_device_id;
1514 : : } else {
1515 : : /* Modern devices: simply use PCI device id,
1516 : : * but start from 0x1040.
1517 : : */
1518 : 0 : device_id = pci_device_id - 0x1040;
1519 : : }
1520 : :
1521 : 0 : return device_id;
1522 : : }
1523 : :
1524 : : static int
1525 : 0 : ifcvf_blk_get_config(int vid, uint8_t *config, uint32_t size)
1526 : : {
1527 : : struct virtio_blk_config *dev_cfg;
1528 : : struct ifcvf_internal *internal;
1529 : : struct rte_vdpa_device *vdev;
1530 : : struct internal_list *list;
1531 : : uint32_t i;
1532 : : uint64_t capacity = 0;
1533 : : uint8_t *byte;
1534 : :
1535 [ # # ]: 0 : if (size < sizeof(struct virtio_blk_config)) {
1536 : 0 : DRV_LOG(ERR, "Invalid len: %u, required: %u",
1537 : : size, (uint32_t)sizeof(struct virtio_blk_config));
1538 : 0 : return -1;
1539 : : }
1540 : :
1541 : 0 : vdev = rte_vhost_get_vdpa_device(vid);
1542 [ # # ]: 0 : if (vdev == NULL) {
1543 : 0 : DRV_LOG(ERR, "Invalid vDPA device vid: %d", vid);
1544 : 0 : return -1;
1545 : : }
1546 : :
1547 : 0 : list = find_internal_resource_by_vdev(vdev);
1548 [ # # ]: 0 : if (list == NULL) {
1549 : 0 : DRV_LOG(ERR, "Invalid vDPA device: %p", vdev);
1550 : 0 : return -1;
1551 : : }
1552 : :
1553 : 0 : internal = list->internal;
1554 : :
1555 [ # # ]: 0 : for (i = 0; i < sizeof(struct virtio_blk_config); i++)
1556 : 0 : config[i] = *((u8 *)internal->hw.blk_cfg + i);
1557 : :
1558 : 0 : dev_cfg = (struct virtio_blk_config *)internal->hw.blk_cfg;
1559 : :
1560 : : /* cannot read 64-bit register in one attempt, so read byte by byte. */
1561 [ # # ]: 0 : for (i = 0; i < sizeof(internal->hw.blk_cfg->capacity); i++) {
1562 : 0 : byte = (uint8_t *)&internal->hw.blk_cfg->capacity + i;
1563 : 0 : capacity |= (uint64_t)*byte << (i * 8);
1564 : : }
1565 : : /* The capacity is number of sectors in 512-byte.
1566 : : * So right shift 1 bit we get in K,
1567 : : * another right shift 10 bits we get in M,
1568 : : * right shift 10 more bits, we get in G.
1569 : : * To show capacity in G, we right shift 21 bits in total.
1570 : : */
1571 : 0 : DRV_LOG(DEBUG, "capacity : %"PRIu64"G", capacity >> 21);
1572 : :
1573 : 0 : DRV_LOG(DEBUG, "size_max : 0x%08x", dev_cfg->size_max);
1574 : 0 : DRV_LOG(DEBUG, "seg_max : 0x%08x", dev_cfg->seg_max);
1575 : 0 : DRV_LOG(DEBUG, "blk_size : 0x%08x", dev_cfg->blk_size);
1576 : 0 : DRV_LOG(DEBUG, "geometry");
1577 : 0 : DRV_LOG(DEBUG, " cylinders: %u", dev_cfg->geometry.cylinders);
1578 : 0 : DRV_LOG(DEBUG, " heads : %u", dev_cfg->geometry.heads);
1579 : 0 : DRV_LOG(DEBUG, " sectors : %u", dev_cfg->geometry.sectors);
1580 : 0 : DRV_LOG(DEBUG, "num_queues: 0x%08x", dev_cfg->num_queues);
1581 : :
1582 : 0 : DRV_LOG(DEBUG, "config: [%x] [%x] [%x] [%x] [%x] [%x] [%x] [%x]",
1583 : : config[0], config[1], config[2], config[3], config[4],
1584 : : config[5], config[6], config[7]);
1585 : 0 : return 0;
1586 : : }
1587 : :
1588 : : static int
1589 : 0 : ifcvf_blk_get_protocol_features(struct rte_vdpa_device *vdev,
1590 : : uint64_t *features)
1591 : : {
1592 : : RTE_SET_USED(vdev);
1593 : :
1594 : : *features = VDPA_SUPPORTED_PROTOCOL_FEATURES;
1595 : 0 : *features |= VDPA_BLK_PROTOCOL_FEATURES;
1596 : 0 : return 0;
1597 : : }
1598 : :
1599 : : static struct rte_vdpa_dev_ops ifcvf_blk_ops = {
1600 : : .get_queue_num = ifcvf_get_queue_num,
1601 : : .get_features = ifcvf_get_vdpa_features,
1602 : : .set_features = ifcvf_set_features,
1603 : : .get_protocol_features = ifcvf_blk_get_protocol_features,
1604 : : .dev_conf = ifcvf_dev_config,
1605 : : .dev_close = ifcvf_dev_close,
1606 : : .set_vring_state = ifcvf_set_vring_state,
1607 : : .migration_done = NULL,
1608 : : .get_vfio_group_fd = ifcvf_get_vfio_group_fd,
1609 : : .get_vfio_device_fd = ifcvf_get_vfio_device_fd,
1610 : : .get_notify_area = ifcvf_get_notify_area,
1611 : : .get_config = ifcvf_blk_get_config,
1612 : : .get_dev_type = ifcvf_get_device_type,
1613 : : };
1614 : :
1615 : : struct rte_vdpa_dev_info dev_info[] = {
1616 : : {
1617 : : .features = (1ULL << VIRTIO_NET_F_GUEST_ANNOUNCE) |
1618 : : (1ULL << VIRTIO_NET_F_CTRL_VQ) |
1619 : : (1ULL << VIRTIO_NET_F_STATUS) |
1620 : : (1ULL << VHOST_USER_F_PROTOCOL_FEATURES) |
1621 : : (1ULL << VHOST_F_LOG_ALL),
1622 : : .ops = &ifcvf_net_ops,
1623 : : },
1624 : : {
1625 : : .features = (1ULL << VHOST_USER_F_PROTOCOL_FEATURES) |
1626 : : (1ULL << VHOST_F_LOG_ALL),
1627 : : .ops = &ifcvf_blk_ops,
1628 : : },
1629 : : };
1630 : :
1631 : : static int
1632 : 0 : ifcvf_pci_probe(struct rte_pci_driver *pci_drv __rte_unused,
1633 : : struct rte_pci_device *pci_dev)
1634 : : {
1635 : : uint64_t features;
1636 : : struct ifcvf_internal *internal = NULL;
1637 : : struct internal_list *list = NULL;
1638 : 0 : int vdpa_mode = 0;
1639 : 0 : int sw_fallback_lm = 0;
1640 : : struct rte_kvargs *kvlist = NULL;
1641 : : int ret = 0;
1642 : : int16_t device_id;
1643 : : uint64_t capacity = 0;
1644 : : uint8_t *byte;
1645 : : uint32_t i;
1646 : : uint16_t queue_pairs;
1647 : :
1648 [ # # ]: 0 : if (rte_eal_process_type() != RTE_PROC_PRIMARY)
1649 : : return 0;
1650 : :
1651 [ # # ]: 0 : if (!pci_dev->device.devargs)
1652 : : return 1;
1653 : :
1654 : 0 : kvlist = rte_kvargs_parse(pci_dev->device.devargs->args,
1655 : : ifcvf_valid_arguments);
1656 [ # # ]: 0 : if (kvlist == NULL)
1657 : : return 1;
1658 : :
1659 : : /* probe only when vdpa mode is specified */
1660 [ # # ]: 0 : if (rte_kvargs_count(kvlist, IFCVF_VDPA_MODE) == 0) {
1661 : 0 : rte_kvargs_free(kvlist);
1662 : 0 : return 1;
1663 : : }
1664 : :
1665 : 0 : ret = rte_kvargs_process(kvlist, IFCVF_VDPA_MODE, &open_int,
1666 : : &vdpa_mode);
1667 [ # # # # ]: 0 : if (ret < 0 || vdpa_mode == 0) {
1668 : 0 : rte_kvargs_free(kvlist);
1669 : 0 : return 1;
1670 : : }
1671 : :
1672 : 0 : list = rte_zmalloc("ifcvf", sizeof(*list), 0);
1673 [ # # ]: 0 : if (list == NULL)
1674 : 0 : goto error;
1675 : :
1676 : 0 : internal = rte_zmalloc("ifcvf", sizeof(*internal), 0);
1677 [ # # ]: 0 : if (internal == NULL)
1678 : 0 : goto error;
1679 : :
1680 : 0 : internal->pdev = pci_dev;
1681 : : rte_spinlock_init(&internal->lock);
1682 : :
1683 [ # # ]: 0 : if (ifcvf_vfio_setup(internal) < 0) {
1684 : 0 : DRV_LOG(ERR, "failed to setup device %s", pci_dev->name);
1685 : 0 : goto error;
1686 : : }
1687 : :
1688 [ # # ]: 0 : if (ifcvf_init_hw(&internal->hw, internal->pdev) < 0) {
1689 : 0 : DRV_LOG(ERR, "failed to init device %s", pci_dev->name);
1690 : 0 : goto error;
1691 : : }
1692 : :
1693 : 0 : internal->configured = 0;
1694 : 0 : features = ifcvf_get_features(&internal->hw);
1695 : :
1696 : 0 : device_id = ifcvf_pci_get_device_type(pci_dev);
1697 [ # # ]: 0 : if (device_id < 0) {
1698 : 0 : DRV_LOG(ERR, "failed to get device %s type", pci_dev->name);
1699 : 0 : goto error;
1700 : : }
1701 : :
1702 [ # # ]: 0 : if (device_id == VIRTIO_ID_NET) {
1703 : 0 : internal->hw.device_type = IFCVF_NET;
1704 : : /*
1705 : : * ifc device always has CTRL_VQ,
1706 : : * and supports VIRTIO_NET_F_CTRL_VQ feature.
1707 : : */
1708 : 0 : queue_pairs = (internal->hw.common_cfg->num_queues - 1) / 2;
1709 : 0 : DRV_LOG(INFO, "%s support %u queue pairs", pci_dev->name,
1710 : : queue_pairs);
1711 : 0 : internal->max_queues = MIN(IFCVF_MAX_QUEUES, queue_pairs);
1712 : 0 : internal->features = features &
1713 : : ~(1ULL << VIRTIO_F_IOMMU_PLATFORM);
1714 : 0 : internal->features |= dev_info[IFCVF_NET].features;
1715 [ # # ]: 0 : } else if (device_id == VIRTIO_ID_BLOCK) {
1716 : 0 : internal->hw.device_type = IFCVF_BLK;
1717 : 0 : internal->features = features &
1718 : : ~(1ULL << VIRTIO_F_IOMMU_PLATFORM);
1719 : 0 : internal->features |= dev_info[IFCVF_BLK].features;
1720 : :
1721 : : /* cannot read 64-bit register in one attempt,
1722 : : * so read byte by byte.
1723 : : */
1724 [ # # ]: 0 : for (i = 0; i < sizeof(internal->hw.blk_cfg->capacity); i++) {
1725 : 0 : byte = (uint8_t *)&internal->hw.blk_cfg->capacity + i;
1726 : 0 : capacity |= (uint64_t)*byte << (i * 8);
1727 : : }
1728 : : /* The capacity is number of sectors in 512-byte.
1729 : : * So right shift 1 bit we get in K,
1730 : : * another right shift 10 bits we get in M,
1731 : : * right shift 10 more bits, we get in G.
1732 : : * To show capacity in G, we right shift 21 bits in total.
1733 : : */
1734 : 0 : DRV_LOG(DEBUG, "capacity : %"PRIu64"G", capacity >> 21);
1735 : :
1736 : 0 : DRV_LOG(DEBUG, "size_max : 0x%08x",
1737 : : internal->hw.blk_cfg->size_max);
1738 : 0 : DRV_LOG(DEBUG, "seg_max : 0x%08x",
1739 : : internal->hw.blk_cfg->seg_max);
1740 : 0 : DRV_LOG(DEBUG, "blk_size : 0x%08x",
1741 : : internal->hw.blk_cfg->blk_size);
1742 : 0 : DRV_LOG(DEBUG, "geometry");
1743 : 0 : DRV_LOG(DEBUG, " cylinders: %u",
1744 : : internal->hw.blk_cfg->geometry.cylinders);
1745 : 0 : DRV_LOG(DEBUG, " heads : %u",
1746 : : internal->hw.blk_cfg->geometry.heads);
1747 : 0 : DRV_LOG(DEBUG, " sectors : %u",
1748 : : internal->hw.blk_cfg->geometry.sectors);
1749 : 0 : DRV_LOG(DEBUG, "num_queues: 0x%08x",
1750 : : internal->hw.blk_cfg->num_queues);
1751 : :
1752 : 0 : internal->max_queues = MIN(IFCVF_MAX_QUEUES,
1753 : : internal->hw.blk_cfg->num_queues);
1754 : : }
1755 : :
1756 : 0 : list->internal = internal;
1757 : :
1758 [ # # ]: 0 : if (rte_kvargs_count(kvlist, IFCVF_SW_FALLBACK_LM)) {
1759 : 0 : ret = rte_kvargs_process(kvlist, IFCVF_SW_FALLBACK_LM,
1760 : : &open_int, &sw_fallback_lm);
1761 [ # # ]: 0 : if (ret < 0)
1762 : 0 : goto error;
1763 : : }
1764 : 0 : internal->sw_lm = sw_fallback_lm;
1765 [ # # # # ]: 0 : if (!internal->sw_lm && !internal->hw.lm_cfg) {
1766 : 0 : DRV_LOG(ERR, "Device %s does not support HW assist live migration, please enable sw-live-migration!",
1767 : : pci_dev->name);
1768 : 0 : goto error;
1769 : : }
1770 : :
1771 : 0 : pthread_mutex_lock(&internal_list_lock);
1772 : 0 : TAILQ_INSERT_TAIL(&internal_list, list, next);
1773 : 0 : pthread_mutex_unlock(&internal_list_lock);
1774 : :
1775 : 0 : internal->vdev = rte_vdpa_register_device(&pci_dev->device,
1776 : 0 : dev_info[internal->hw.device_type].ops);
1777 [ # # ]: 0 : if (internal->vdev == NULL) {
1778 : 0 : DRV_LOG(ERR, "failed to register device %s", pci_dev->name);
1779 : 0 : pthread_mutex_lock(&internal_list_lock);
1780 [ # # ]: 0 : TAILQ_REMOVE(&internal_list, list, next);
1781 : 0 : pthread_mutex_unlock(&internal_list_lock);
1782 : 0 : goto error;
1783 : : }
1784 : :
1785 : : rte_atomic32_set(&internal->started, 1);
1786 [ # # ]: 0 : if (update_datapath(internal) < 0) {
1787 : 0 : DRV_LOG(ERR, "failed to update datapath %s", pci_dev->name);
1788 : : rte_atomic32_set(&internal->started, 0);
1789 : 0 : rte_vdpa_unregister_device(internal->vdev);
1790 : 0 : pthread_mutex_lock(&internal_list_lock);
1791 [ # # ]: 0 : TAILQ_REMOVE(&internal_list, list, next);
1792 : 0 : pthread_mutex_unlock(&internal_list_lock);
1793 : 0 : goto error;
1794 : : }
1795 : :
1796 : 0 : rte_kvargs_free(kvlist);
1797 : 0 : return 0;
1798 : :
1799 : 0 : error:
1800 : 0 : rte_kvargs_free(kvlist);
1801 : 0 : rte_free(list);
1802 : 0 : rte_free(internal);
1803 : 0 : return -1;
1804 : : }
1805 : :
1806 : : static int
1807 : 0 : ifcvf_pci_remove(struct rte_pci_device *pci_dev)
1808 : : {
1809 : : struct ifcvf_internal *internal;
1810 : : struct internal_list *list;
1811 : :
1812 [ # # ]: 0 : if (rte_eal_process_type() != RTE_PROC_PRIMARY)
1813 : : return 0;
1814 : :
1815 : 0 : list = find_internal_resource_by_pci_dev(pci_dev);
1816 [ # # ]: 0 : if (list == NULL) {
1817 : 0 : DRV_LOG(ERR, "Invalid device: %s", pci_dev->name);
1818 : 0 : return -1;
1819 : : }
1820 : :
1821 : 0 : internal = list->internal;
1822 : : rte_atomic32_set(&internal->started, 0);
1823 [ # # ]: 0 : if (update_datapath(internal) < 0)
1824 : 0 : DRV_LOG(ERR, "failed to update datapath %s", pci_dev->name);
1825 : :
1826 : 0 : rte_pci_unmap_device(internal->pdev);
1827 : 0 : rte_vfio_container_destroy(internal->vfio_container_fd);
1828 : 0 : rte_vdpa_unregister_device(internal->vdev);
1829 : :
1830 : 0 : pthread_mutex_lock(&internal_list_lock);
1831 [ # # ]: 0 : TAILQ_REMOVE(&internal_list, list, next);
1832 : 0 : pthread_mutex_unlock(&internal_list_lock);
1833 : :
1834 : 0 : rte_free(list);
1835 : 0 : rte_free(internal);
1836 : :
1837 : 0 : return 0;
1838 : : }
1839 : :
1840 : : /*
1841 : : * IFCVF has the same vendor ID and device ID as virtio net PCI
1842 : : * device, with its specific subsystem vendor ID and device ID.
1843 : : */
1844 : : static const struct rte_pci_id pci_id_ifcvf_map[] = {
1845 : : { .class_id = RTE_CLASS_ANY_ID,
1846 : : .vendor_id = IFCVF_VENDOR_ID,
1847 : : .device_id = IFCVF_NET_MODERN_DEVICE_ID,
1848 : : .subsystem_vendor_id = IFCVF_SUBSYS_VENDOR_ID,
1849 : : .subsystem_device_id = IFCVF_SUBSYS_DEVICE_ID,
1850 : : },
1851 : :
1852 : : { .class_id = RTE_CLASS_ANY_ID,
1853 : : .vendor_id = IFCVF_VENDOR_ID,
1854 : : .device_id = IFCVF_NET_TRANSITIONAL_DEVICE_ID,
1855 : : .subsystem_vendor_id = IFCVF_SUBSYS_VENDOR_ID,
1856 : : .subsystem_device_id = IFCVF_SUBSYS_NET_DEVICE_ID,
1857 : : },
1858 : :
1859 : : { .class_id = RTE_CLASS_ANY_ID,
1860 : : .vendor_id = IFCVF_VENDOR_ID,
1861 : : .device_id = IFCVF_BLK_TRANSITIONAL_DEVICE_ID,
1862 : : .subsystem_vendor_id = IFCVF_SUBSYS_VENDOR_ID,
1863 : : .subsystem_device_id = IFCVF_SUBSYS_BLK_DEVICE_ID,
1864 : : },
1865 : :
1866 : : { .class_id = RTE_CLASS_ANY_ID,
1867 : : .vendor_id = IFCVF_VENDOR_ID,
1868 : : .device_id = IFCVF_BLK_MODERN_DEVICE_ID,
1869 : : .subsystem_vendor_id = IFCVF_SUBSYS_VENDOR_ID,
1870 : : .subsystem_device_id = IFCVF_SUBSYS_BLK_DEVICE_ID,
1871 : : },
1872 : :
1873 : : { .class_id = RTE_CLASS_ANY_ID,
1874 : : .vendor_id = IFCVF_VENDOR_ID,
1875 : : .device_id = IFCVF_BLK_MODERN_DEVICE_ID,
1876 : : .subsystem_vendor_id = IFCVF_SUBSYS_VENDOR_ID,
1877 : : .subsystem_device_id = IFCVF_SUBSYS_DEFAULT_DEVICE_ID,
1878 : : }, /* virtio-blk devices with default subsystem IDs */
1879 : :
1880 : : { .vendor_id = 0, /* sentinel */
1881 : : },
1882 : : };
1883 : :
1884 : : static struct rte_pci_driver rte_ifcvf_vdpa = {
1885 : : .id_table = pci_id_ifcvf_map,
1886 : : .drv_flags = 0,
1887 : : .probe = ifcvf_pci_probe,
1888 : : .remove = ifcvf_pci_remove,
1889 : : };
1890 : :
1891 : 253 : RTE_PMD_REGISTER_PCI(net_ifcvf, rte_ifcvf_vdpa);
1892 : : RTE_PMD_REGISTER_PCI_TABLE(net_ifcvf, pci_id_ifcvf_map);
1893 : : RTE_PMD_REGISTER_KMOD_DEP(net_ifcvf, "* vfio-pci");
|