New upstream version 18.08
[deb_dpdk.git] / drivers / net / ifc / ifcvf_vdpa.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2018 Intel Corporation
3  */
4
5 #include <unistd.h>
6 #include <pthread.h>
7 #include <fcntl.h>
8 #include <sys/ioctl.h>
9 #include <sys/epoll.h>
10
11 #include <rte_malloc.h>
12 #include <rte_memory.h>
13 #include <rte_bus_pci.h>
14 #include <rte_vhost.h>
15 #include <rte_vdpa.h>
16 #include <rte_vfio.h>
17 #include <rte_spinlock.h>
18 #include <rte_log.h>
19
20 #include "base/ifcvf.h"
21
22 #define DRV_LOG(level, fmt, args...) \
23         rte_log(RTE_LOG_ ## level, ifcvf_vdpa_logtype, \
24                 "%s(): " fmt "\n", __func__, ##args)
25
26 #ifndef PAGE_SIZE
27 #define PAGE_SIZE 4096
28 #endif
29
30 static int ifcvf_vdpa_logtype;
31
32 struct ifcvf_internal {
33         struct rte_vdpa_dev_addr dev_addr;
34         struct rte_pci_device *pdev;
35         struct ifcvf_hw hw;
36         int vfio_container_fd;
37         int vfio_group_fd;
38         int vfio_dev_fd;
39         pthread_t tid;  /* thread for notify relay */
40         int epfd;
41         int vid;
42         int did;
43         uint16_t max_queues;
44         uint64_t features;
45         rte_atomic32_t started;
46         rte_atomic32_t dev_attached;
47         rte_atomic32_t running;
48         rte_spinlock_t lock;
49 };
50
51 struct internal_list {
52         TAILQ_ENTRY(internal_list) next;
53         struct ifcvf_internal *internal;
54 };
55
56 TAILQ_HEAD(internal_list_head, internal_list);
57 static struct internal_list_head internal_list =
58         TAILQ_HEAD_INITIALIZER(internal_list);
59
60 static pthread_mutex_t internal_list_lock = PTHREAD_MUTEX_INITIALIZER;
61
62 static struct internal_list *
63 find_internal_resource_by_did(int did)
64 {
65         int found = 0;
66         struct internal_list *list;
67
68         pthread_mutex_lock(&internal_list_lock);
69
70         TAILQ_FOREACH(list, &internal_list, next) {
71                 if (did == list->internal->did) {
72                         found = 1;
73                         break;
74                 }
75         }
76
77         pthread_mutex_unlock(&internal_list_lock);
78
79         if (!found)
80                 return NULL;
81
82         return list;
83 }
84
85 static struct internal_list *
86 find_internal_resource_by_dev(struct rte_pci_device *pdev)
87 {
88         int found = 0;
89         struct internal_list *list;
90
91         pthread_mutex_lock(&internal_list_lock);
92
93         TAILQ_FOREACH(list, &internal_list, next) {
94                 if (pdev == list->internal->pdev) {
95                         found = 1;
96                         break;
97                 }
98         }
99
100         pthread_mutex_unlock(&internal_list_lock);
101
102         if (!found)
103                 return NULL;
104
105         return list;
106 }
107
108 static int
109 ifcvf_vfio_setup(struct ifcvf_internal *internal)
110 {
111         struct rte_pci_device *dev = internal->pdev;
112         char devname[RTE_DEV_NAME_MAX_LEN] = {0};
113         int iommu_group_num;
114         int ret = 0;
115         int i;
116
117         internal->vfio_dev_fd = -1;
118         internal->vfio_group_fd = -1;
119         internal->vfio_container_fd = -1;
120
121         rte_pci_device_name(&dev->addr, devname, RTE_DEV_NAME_MAX_LEN);
122         rte_vfio_get_group_num(rte_pci_get_sysfs_path(), devname,
123                         &iommu_group_num);
124
125         internal->vfio_container_fd = rte_vfio_container_create();
126         if (internal->vfio_container_fd < 0)
127                 return -1;
128
129         internal->vfio_group_fd = rte_vfio_container_group_bind(
130                         internal->vfio_container_fd, iommu_group_num);
131         if (internal->vfio_group_fd < 0)
132                 goto err;
133
134         if (rte_pci_map_device(dev))
135                 goto err;
136
137         internal->vfio_dev_fd = dev->intr_handle.vfio_dev_fd;
138
139         for (i = 0; i < RTE_MIN(PCI_MAX_RESOURCE, IFCVF_PCI_MAX_RESOURCE);
140                         i++) {
141                 internal->hw.mem_resource[i].addr =
142                         internal->pdev->mem_resource[i].addr;
143                 internal->hw.mem_resource[i].phys_addr =
144                         internal->pdev->mem_resource[i].phys_addr;
145                 internal->hw.mem_resource[i].len =
146                         internal->pdev->mem_resource[i].len;
147         }
148         ret = ifcvf_init_hw(&internal->hw, internal->pdev);
149
150         return ret;
151
152 err:
153         rte_vfio_container_destroy(internal->vfio_container_fd);
154         return -1;
155 }
156
157 static int
158 ifcvf_dma_map(struct ifcvf_internal *internal, int do_map)
159 {
160         uint32_t i;
161         int ret;
162         struct rte_vhost_memory *mem = NULL;
163         int vfio_container_fd;
164
165         ret = rte_vhost_get_mem_table(internal->vid, &mem);
166         if (ret < 0) {
167                 DRV_LOG(ERR, "failed to get VM memory layout.");
168                 goto exit;
169         }
170
171         vfio_container_fd = internal->vfio_container_fd;
172
173         for (i = 0; i < mem->nregions; i++) {
174                 struct rte_vhost_mem_region *reg;
175
176                 reg = &mem->regions[i];
177                 DRV_LOG(INFO, "%s, region %u: HVA 0x%" PRIx64 ", "
178                         "GPA 0x%" PRIx64 ", size 0x%" PRIx64 ".",
179                         do_map ? "DMA map" : "DMA unmap", i,
180                         reg->host_user_addr, reg->guest_phys_addr, reg->size);
181
182                 if (do_map) {
183                         ret = rte_vfio_container_dma_map(vfio_container_fd,
184                                 reg->host_user_addr, reg->guest_phys_addr,
185                                 reg->size);
186                         if (ret < 0) {
187                                 DRV_LOG(ERR, "DMA map failed.");
188                                 goto exit;
189                         }
190                 } else {
191                         ret = rte_vfio_container_dma_unmap(vfio_container_fd,
192                                 reg->host_user_addr, reg->guest_phys_addr,
193                                 reg->size);
194                         if (ret < 0) {
195                                 DRV_LOG(ERR, "DMA unmap failed.");
196                                 goto exit;
197                         }
198                 }
199         }
200
201 exit:
202         if (mem)
203                 free(mem);
204         return ret;
205 }
206
207 static uint64_t
208 qva_to_gpa(int vid, uint64_t qva)
209 {
210         struct rte_vhost_memory *mem = NULL;
211         struct rte_vhost_mem_region *reg;
212         uint32_t i;
213         uint64_t gpa = 0;
214
215         if (rte_vhost_get_mem_table(vid, &mem) < 0)
216                 goto exit;
217
218         for (i = 0; i < mem->nregions; i++) {
219                 reg = &mem->regions[i];
220
221                 if (qva >= reg->host_user_addr &&
222                                 qva < reg->host_user_addr + reg->size) {
223                         gpa = qva - reg->host_user_addr + reg->guest_phys_addr;
224                         break;
225                 }
226         }
227
228 exit:
229         if (mem)
230                 free(mem);
231         return gpa;
232 }
233
234 static int
235 vdpa_ifcvf_start(struct ifcvf_internal *internal)
236 {
237         struct ifcvf_hw *hw = &internal->hw;
238         int i, nr_vring;
239         int vid;
240         struct rte_vhost_vring vq;
241         uint64_t gpa;
242
243         vid = internal->vid;
244         nr_vring = rte_vhost_get_vring_num(vid);
245         rte_vhost_get_negotiated_features(vid, &hw->req_features);
246
247         for (i = 0; i < nr_vring; i++) {
248                 rte_vhost_get_vhost_vring(vid, i, &vq);
249                 gpa = qva_to_gpa(vid, (uint64_t)(uintptr_t)vq.desc);
250                 if (gpa == 0) {
251                         DRV_LOG(ERR, "Fail to get GPA for descriptor ring.");
252                         return -1;
253                 }
254                 hw->vring[i].desc = gpa;
255
256                 gpa = qva_to_gpa(vid, (uint64_t)(uintptr_t)vq.avail);
257                 if (gpa == 0) {
258                         DRV_LOG(ERR, "Fail to get GPA for available ring.");
259                         return -1;
260                 }
261                 hw->vring[i].avail = gpa;
262
263                 gpa = qva_to_gpa(vid, (uint64_t)(uintptr_t)vq.used);
264                 if (gpa == 0) {
265                         DRV_LOG(ERR, "Fail to get GPA for used ring.");
266                         return -1;
267                 }
268                 hw->vring[i].used = gpa;
269
270                 hw->vring[i].size = vq.size;
271                 rte_vhost_get_vring_base(vid, i, &hw->vring[i].last_avail_idx,
272                                 &hw->vring[i].last_used_idx);
273         }
274         hw->nr_vring = i;
275
276         return ifcvf_start_hw(&internal->hw);
277 }
278
279 static void
280 vdpa_ifcvf_stop(struct ifcvf_internal *internal)
281 {
282         struct ifcvf_hw *hw = &internal->hw;
283         uint32_t i;
284         int vid;
285
286         vid = internal->vid;
287         ifcvf_stop_hw(hw);
288
289         for (i = 0; i < hw->nr_vring; i++)
290                 rte_vhost_set_vring_base(vid, i, hw->vring[i].last_avail_idx,
291                                 hw->vring[i].last_used_idx);
292 }
293
294 #define MSIX_IRQ_SET_BUF_LEN (sizeof(struct vfio_irq_set) + \
295                 sizeof(int) * (IFCVF_MAX_QUEUES * 2 + 1))
296 static int
297 vdpa_enable_vfio_intr(struct ifcvf_internal *internal)
298 {
299         int ret;
300         uint32_t i, nr_vring;
301         char irq_set_buf[MSIX_IRQ_SET_BUF_LEN];
302         struct vfio_irq_set *irq_set;
303         int *fd_ptr;
304         struct rte_vhost_vring vring;
305
306         nr_vring = rte_vhost_get_vring_num(internal->vid);
307
308         irq_set = (struct vfio_irq_set *)irq_set_buf;
309         irq_set->argsz = sizeof(irq_set_buf);
310         irq_set->count = nr_vring + 1;
311         irq_set->flags = VFIO_IRQ_SET_DATA_EVENTFD |
312                          VFIO_IRQ_SET_ACTION_TRIGGER;
313         irq_set->index = VFIO_PCI_MSIX_IRQ_INDEX;
314         irq_set->start = 0;
315         fd_ptr = (int *)&irq_set->data;
316         fd_ptr[RTE_INTR_VEC_ZERO_OFFSET] = internal->pdev->intr_handle.fd;
317
318         for (i = 0; i < nr_vring; i++) {
319                 rte_vhost_get_vhost_vring(internal->vid, i, &vring);
320                 fd_ptr[RTE_INTR_VEC_RXTX_OFFSET + i] = vring.callfd;
321         }
322
323         ret = ioctl(internal->vfio_dev_fd, VFIO_DEVICE_SET_IRQS, irq_set);
324         if (ret) {
325                 DRV_LOG(ERR, "Error enabling MSI-X interrupts: %s",
326                                 strerror(errno));
327                 return -1;
328         }
329
330         return 0;
331 }
332
333 static int
334 vdpa_disable_vfio_intr(struct ifcvf_internal *internal)
335 {
336         int ret;
337         char irq_set_buf[MSIX_IRQ_SET_BUF_LEN];
338         struct vfio_irq_set *irq_set;
339
340         irq_set = (struct vfio_irq_set *)irq_set_buf;
341         irq_set->argsz = sizeof(irq_set_buf);
342         irq_set->count = 0;
343         irq_set->flags = VFIO_IRQ_SET_DATA_NONE | VFIO_IRQ_SET_ACTION_TRIGGER;
344         irq_set->index = VFIO_PCI_MSIX_IRQ_INDEX;
345         irq_set->start = 0;
346
347         ret = ioctl(internal->vfio_dev_fd, VFIO_DEVICE_SET_IRQS, irq_set);
348         if (ret) {
349                 DRV_LOG(ERR, "Error disabling MSI-X interrupts: %s",
350                                 strerror(errno));
351                 return -1;
352         }
353
354         return 0;
355 }
356
357 static void *
358 notify_relay(void *arg)
359 {
360         int i, kickfd, epfd, nfds = 0;
361         uint32_t qid, q_num;
362         struct epoll_event events[IFCVF_MAX_QUEUES * 2];
363         struct epoll_event ev;
364         uint64_t buf;
365         int nbytes;
366         struct rte_vhost_vring vring;
367         struct ifcvf_internal *internal = (struct ifcvf_internal *)arg;
368         struct ifcvf_hw *hw = &internal->hw;
369
370         q_num = rte_vhost_get_vring_num(internal->vid);
371
372         epfd = epoll_create(IFCVF_MAX_QUEUES * 2);
373         if (epfd < 0) {
374                 DRV_LOG(ERR, "failed to create epoll instance.");
375                 return NULL;
376         }
377         internal->epfd = epfd;
378
379         for (qid = 0; qid < q_num; qid++) {
380                 ev.events = EPOLLIN | EPOLLPRI;
381                 rte_vhost_get_vhost_vring(internal->vid, qid, &vring);
382                 ev.data.u64 = qid | (uint64_t)vring.kickfd << 32;
383                 if (epoll_ctl(epfd, EPOLL_CTL_ADD, vring.kickfd, &ev) < 0) {
384                         DRV_LOG(ERR, "epoll add error: %s", strerror(errno));
385                         return NULL;
386                 }
387         }
388
389         for (;;) {
390                 nfds = epoll_wait(epfd, events, q_num, -1);
391                 if (nfds < 0) {
392                         if (errno == EINTR)
393                                 continue;
394                         DRV_LOG(ERR, "epoll_wait return fail\n");
395                         return NULL;
396                 }
397
398                 for (i = 0; i < nfds; i++) {
399                         qid = events[i].data.u32;
400                         kickfd = (uint32_t)(events[i].data.u64 >> 32);
401                         do {
402                                 nbytes = read(kickfd, &buf, 8);
403                                 if (nbytes < 0) {
404                                         if (errno == EINTR ||
405                                             errno == EWOULDBLOCK ||
406                                             errno == EAGAIN)
407                                                 continue;
408                                         DRV_LOG(INFO, "Error reading "
409                                                 "kickfd: %s",
410                                                 strerror(errno));
411                                 }
412                                 break;
413                         } while (1);
414
415                         ifcvf_notify_queue(hw, qid);
416                 }
417         }
418
419         return NULL;
420 }
421
422 static int
423 setup_notify_relay(struct ifcvf_internal *internal)
424 {
425         int ret;
426
427         ret = pthread_create(&internal->tid, NULL, notify_relay,
428                         (void *)internal);
429         if (ret) {
430                 DRV_LOG(ERR, "failed to create notify relay pthread.");
431                 return -1;
432         }
433         return 0;
434 }
435
436 static int
437 unset_notify_relay(struct ifcvf_internal *internal)
438 {
439         void *status;
440
441         if (internal->tid) {
442                 pthread_cancel(internal->tid);
443                 pthread_join(internal->tid, &status);
444         }
445         internal->tid = 0;
446
447         if (internal->epfd >= 0)
448                 close(internal->epfd);
449         internal->epfd = -1;
450
451         return 0;
452 }
453
454 static int
455 update_datapath(struct ifcvf_internal *internal)
456 {
457         int ret;
458
459         rte_spinlock_lock(&internal->lock);
460
461         if (!rte_atomic32_read(&internal->running) &&
462             (rte_atomic32_read(&internal->started) &&
463              rte_atomic32_read(&internal->dev_attached))) {
464                 ret = ifcvf_dma_map(internal, 1);
465                 if (ret)
466                         goto err;
467
468                 ret = vdpa_enable_vfio_intr(internal);
469                 if (ret)
470                         goto err;
471
472                 ret = setup_notify_relay(internal);
473                 if (ret)
474                         goto err;
475
476                 ret = vdpa_ifcvf_start(internal);
477                 if (ret)
478                         goto err;
479
480                 rte_atomic32_set(&internal->running, 1);
481         } else if (rte_atomic32_read(&internal->running) &&
482                    (!rte_atomic32_read(&internal->started) ||
483                     !rte_atomic32_read(&internal->dev_attached))) {
484                 vdpa_ifcvf_stop(internal);
485
486                 ret = unset_notify_relay(internal);
487                 if (ret)
488                         goto err;
489
490                 ret = vdpa_disable_vfio_intr(internal);
491                 if (ret)
492                         goto err;
493
494                 ret = ifcvf_dma_map(internal, 0);
495                 if (ret)
496                         goto err;
497
498                 rte_atomic32_set(&internal->running, 0);
499         }
500
501         rte_spinlock_unlock(&internal->lock);
502         return 0;
503 err:
504         rte_spinlock_unlock(&internal->lock);
505         return ret;
506 }
507
508 static int
509 ifcvf_dev_config(int vid)
510 {
511         int did;
512         struct internal_list *list;
513         struct ifcvf_internal *internal;
514
515         did = rte_vhost_get_vdpa_device_id(vid);
516         list = find_internal_resource_by_did(did);
517         if (list == NULL) {
518                 DRV_LOG(ERR, "Invalid device id: %d", did);
519                 return -1;
520         }
521
522         internal = list->internal;
523         internal->vid = vid;
524         rte_atomic32_set(&internal->dev_attached, 1);
525         update_datapath(internal);
526
527         return 0;
528 }
529
530 static int
531 ifcvf_dev_close(int vid)
532 {
533         int did;
534         struct internal_list *list;
535         struct ifcvf_internal *internal;
536
537         did = rte_vhost_get_vdpa_device_id(vid);
538         list = find_internal_resource_by_did(did);
539         if (list == NULL) {
540                 DRV_LOG(ERR, "Invalid device id: %d", did);
541                 return -1;
542         }
543
544         internal = list->internal;
545         rte_atomic32_set(&internal->dev_attached, 0);
546         update_datapath(internal);
547
548         return 0;
549 }
550
551 static int
552 ifcvf_get_vfio_group_fd(int vid)
553 {
554         int did;
555         struct internal_list *list;
556
557         did = rte_vhost_get_vdpa_device_id(vid);
558         list = find_internal_resource_by_did(did);
559         if (list == NULL) {
560                 DRV_LOG(ERR, "Invalid device id: %d", did);
561                 return -1;
562         }
563
564         return list->internal->vfio_group_fd;
565 }
566
567 static int
568 ifcvf_get_vfio_device_fd(int vid)
569 {
570         int did;
571         struct internal_list *list;
572
573         did = rte_vhost_get_vdpa_device_id(vid);
574         list = find_internal_resource_by_did(did);
575         if (list == NULL) {
576                 DRV_LOG(ERR, "Invalid device id: %d", did);
577                 return -1;
578         }
579
580         return list->internal->vfio_dev_fd;
581 }
582
583 static int
584 ifcvf_get_notify_area(int vid, int qid, uint64_t *offset, uint64_t *size)
585 {
586         int did;
587         struct internal_list *list;
588         struct ifcvf_internal *internal;
589         struct vfio_region_info reg = { .argsz = sizeof(reg) };
590         int ret;
591
592         did = rte_vhost_get_vdpa_device_id(vid);
593         list = find_internal_resource_by_did(did);
594         if (list == NULL) {
595                 DRV_LOG(ERR, "Invalid device id: %d", did);
596                 return -1;
597         }
598
599         internal = list->internal;
600
601         reg.index = ifcvf_get_notify_region(&internal->hw);
602         ret = ioctl(internal->vfio_dev_fd, VFIO_DEVICE_GET_REGION_INFO, &reg);
603         if (ret) {
604                 DRV_LOG(ERR, "Get not get device region info: %s",
605                                 strerror(errno));
606                 return -1;
607         }
608
609         *offset = ifcvf_get_queue_notify_off(&internal->hw, qid) + reg.offset;
610         *size = 0x1000;
611
612         return 0;
613 }
614
615 static int
616 ifcvf_get_queue_num(int did, uint32_t *queue_num)
617 {
618         struct internal_list *list;
619
620         list = find_internal_resource_by_did(did);
621         if (list == NULL) {
622                 DRV_LOG(ERR, "Invalid device id: %d", did);
623                 return -1;
624         }
625
626         *queue_num = list->internal->max_queues;
627
628         return 0;
629 }
630
631 static int
632 ifcvf_get_vdpa_features(int did, uint64_t *features)
633 {
634         struct internal_list *list;
635
636         list = find_internal_resource_by_did(did);
637         if (list == NULL) {
638                 DRV_LOG(ERR, "Invalid device id: %d", did);
639                 return -1;
640         }
641
642         *features = list->internal->features;
643
644         return 0;
645 }
646
647 #define VDPA_SUPPORTED_PROTOCOL_FEATURES \
648                 (1ULL << VHOST_USER_PROTOCOL_F_REPLY_ACK | \
649                  1ULL << VHOST_USER_PROTOCOL_F_SLAVE_REQ | \
650                  1ULL << VHOST_USER_PROTOCOL_F_SLAVE_SEND_FD | \
651                  1ULL << VHOST_USER_PROTOCOL_F_HOST_NOTIFIER | \
652                  1ULL << VHOST_USER_PROTOCOL_F_LOG_SHMFD)
653 static int
654 ifcvf_get_protocol_features(int did __rte_unused, uint64_t *features)
655 {
656         *features = VDPA_SUPPORTED_PROTOCOL_FEATURES;
657         return 0;
658 }
659
660 struct rte_vdpa_dev_ops ifcvf_ops = {
661         .get_queue_num = ifcvf_get_queue_num,
662         .get_features = ifcvf_get_vdpa_features,
663         .get_protocol_features = ifcvf_get_protocol_features,
664         .dev_conf = ifcvf_dev_config,
665         .dev_close = ifcvf_dev_close,
666         .set_vring_state = NULL,
667         .set_features = NULL,
668         .migration_done = NULL,
669         .get_vfio_group_fd = ifcvf_get_vfio_group_fd,
670         .get_vfio_device_fd = ifcvf_get_vfio_device_fd,
671         .get_notify_area = ifcvf_get_notify_area,
672 };
673
674 static int
675 ifcvf_pci_probe(struct rte_pci_driver *pci_drv __rte_unused,
676                 struct rte_pci_device *pci_dev)
677 {
678         uint64_t features;
679         struct ifcvf_internal *internal = NULL;
680         struct internal_list *list = NULL;
681
682         if (rte_eal_process_type() != RTE_PROC_PRIMARY)
683                 return 0;
684
685         list = rte_zmalloc("ifcvf", sizeof(*list), 0);
686         if (list == NULL)
687                 goto error;
688
689         internal = rte_zmalloc("ifcvf", sizeof(*internal), 0);
690         if (internal == NULL)
691                 goto error;
692
693         internal->pdev = pci_dev;
694         rte_spinlock_init(&internal->lock);
695         if (ifcvf_vfio_setup(internal) < 0)
696                 return -1;
697
698         internal->max_queues = IFCVF_MAX_QUEUES;
699         features = ifcvf_get_features(&internal->hw);
700         internal->features = (features &
701                 ~(1ULL << VIRTIO_F_IOMMU_PLATFORM)) |
702                 (1ULL << VHOST_USER_F_PROTOCOL_FEATURES);
703
704         internal->dev_addr.pci_addr = pci_dev->addr;
705         internal->dev_addr.type = PCI_ADDR;
706         list->internal = internal;
707
708         pthread_mutex_lock(&internal_list_lock);
709         TAILQ_INSERT_TAIL(&internal_list, list, next);
710         pthread_mutex_unlock(&internal_list_lock);
711
712         internal->did = rte_vdpa_register_device(&internal->dev_addr,
713                                 &ifcvf_ops);
714         if (internal->did < 0)
715                 goto error;
716
717         rte_atomic32_set(&internal->started, 1);
718         update_datapath(internal);
719
720         return 0;
721
722 error:
723         rte_free(list);
724         rte_free(internal);
725         return -1;
726 }
727
728 static int
729 ifcvf_pci_remove(struct rte_pci_device *pci_dev)
730 {
731         struct ifcvf_internal *internal;
732         struct internal_list *list;
733
734         if (rte_eal_process_type() != RTE_PROC_PRIMARY)
735                 return 0;
736
737         list = find_internal_resource_by_dev(pci_dev);
738         if (list == NULL) {
739                 DRV_LOG(ERR, "Invalid device: %s", pci_dev->name);
740                 return -1;
741         }
742
743         internal = list->internal;
744         rte_atomic32_set(&internal->started, 0);
745         update_datapath(internal);
746
747         rte_pci_unmap_device(internal->pdev);
748         rte_vfio_container_destroy(internal->vfio_container_fd);
749         rte_vdpa_unregister_device(internal->did);
750
751         pthread_mutex_lock(&internal_list_lock);
752         TAILQ_REMOVE(&internal_list, list, next);
753         pthread_mutex_unlock(&internal_list_lock);
754
755         rte_free(list);
756         rte_free(internal);
757
758         return 0;
759 }
760
761 /*
762  * IFCVF has the same vendor ID and device ID as virtio net PCI
763  * device, with its specific subsystem vendor ID and device ID.
764  */
765 static const struct rte_pci_id pci_id_ifcvf_map[] = {
766         { .class_id = RTE_CLASS_ANY_ID,
767           .vendor_id = IFCVF_VENDOR_ID,
768           .device_id = IFCVF_DEVICE_ID,
769           .subsystem_vendor_id = IFCVF_SUBSYS_VENDOR_ID,
770           .subsystem_device_id = IFCVF_SUBSYS_DEVICE_ID,
771         },
772
773         { .vendor_id = 0, /* sentinel */
774         },
775 };
776
777 static struct rte_pci_driver rte_ifcvf_vdpa = {
778         .id_table = pci_id_ifcvf_map,
779         .drv_flags = 0,
780         .probe = ifcvf_pci_probe,
781         .remove = ifcvf_pci_remove,
782 };
783
784 RTE_PMD_REGISTER_PCI(net_ifcvf, rte_ifcvf_vdpa);
785 RTE_PMD_REGISTER_PCI_TABLE(net_ifcvf, pci_id_ifcvf_map);
786 RTE_PMD_REGISTER_KMOD_DEP(net_ifcvf, "* vfio-pci");
787
788 RTE_INIT(ifcvf_vdpa_init_log)
789 {
790         ifcvf_vdpa_logtype = rte_log_register("pmd.net.ifcvf_vdpa");
791         if (ifcvf_vdpa_logtype >= 0)
792                 rte_log_set_level(ifcvf_vdpa_logtype, RTE_LOG_NOTICE);
793 }