Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright (c) 2023 Corigine, Inc.
3 : : * All rights reserved.
4 : : */
5 : :
6 : : #include <pthread.h>
7 : : #include <sys/epoll.h>
8 : : #include <sys/ioctl.h>
9 : : #include <unistd.h>
10 : :
11 : : #include <nfp_common_pci.h>
12 : : #include <nfp_dev.h>
13 : : #include <rte_vfio.h>
14 : : #include <vdpa_driver.h>
15 : :
16 : : #include "nfp_vdpa_core.h"
17 : : #include "nfp_vdpa_log.h"
18 : :
19 : : #define NFP_VDPA_DRIVER_NAME nfp_vdpa
20 : :
21 : : #define MSIX_IRQ_SET_BUF_LEN (sizeof(struct vfio_irq_set) + \
22 : : sizeof(int) * (NFP_VDPA_MAX_QUEUES * 2 + 1))
23 : :
24 : : struct nfp_vdpa_dev {
25 : : struct rte_pci_device *pci_dev;
26 : : struct rte_vdpa_device *vdev;
27 : : struct nfp_vdpa_hw hw;
28 : :
29 : : int vfio_container_fd;
30 : : int vfio_group_fd;
31 : : int vfio_dev_fd;
32 : : int iommu_group;
33 : :
34 : : rte_thread_t tid; /**< Thread for notify relay */
35 : : int epoll_fd;
36 : :
37 : : int vid;
38 : : uint16_t max_queues;
39 : : RTE_ATOMIC(uint32_t) started;
40 : : RTE_ATOMIC(uint32_t) dev_attached;
41 : : RTE_ATOMIC(uint32_t) running;
42 : : rte_spinlock_t lock;
43 : :
44 : : /** Eventfd for used ring interrupt */
45 : : int intr_fd[NFP_VDPA_MAX_QUEUES * 2];
46 : : };
47 : :
48 : : struct nfp_vdpa_dev_node {
49 : : TAILQ_ENTRY(nfp_vdpa_dev_node) next;
50 : : struct nfp_vdpa_dev *device;
51 : : };
52 : :
53 : : TAILQ_HEAD(vdpa_dev_list_head, nfp_vdpa_dev_node);
54 : :
55 : : static struct vdpa_dev_list_head vdpa_dev_list =
56 : : TAILQ_HEAD_INITIALIZER(vdpa_dev_list);
57 : :
58 : : static pthread_mutex_t vdpa_list_lock = PTHREAD_MUTEX_INITIALIZER;
59 : :
60 : : static struct nfp_vdpa_dev_node *
61 : 0 : nfp_vdpa_find_node_by_vdev(struct rte_vdpa_device *vdev)
62 : : {
63 : : bool found = false;
64 : : struct nfp_vdpa_dev_node *node;
65 : :
66 : 0 : pthread_mutex_lock(&vdpa_list_lock);
67 : :
68 [ # # ]: 0 : TAILQ_FOREACH(node, &vdpa_dev_list, next) {
69 [ # # ]: 0 : if (vdev == node->device->vdev) {
70 : : found = true;
71 : : break;
72 : : }
73 : : }
74 : :
75 : 0 : pthread_mutex_unlock(&vdpa_list_lock);
76 : :
77 [ # # ]: 0 : if (found)
78 : 0 : return node;
79 : :
80 : : return NULL;
81 : : }
82 : :
83 : : static struct nfp_vdpa_dev_node *
84 : 0 : nfp_vdpa_find_node_by_pdev(struct rte_pci_device *pdev)
85 : : {
86 : : bool found = false;
87 : : struct nfp_vdpa_dev_node *node;
88 : :
89 : 0 : pthread_mutex_lock(&vdpa_list_lock);
90 : :
91 [ # # ]: 0 : TAILQ_FOREACH(node, &vdpa_dev_list, next) {
92 [ # # ]: 0 : if (pdev == node->device->pci_dev) {
93 : : found = true;
94 : : break;
95 : : }
96 : : }
97 : :
98 : 0 : pthread_mutex_unlock(&vdpa_list_lock);
99 : :
100 [ # # ]: 0 : if (found)
101 : 0 : return node;
102 : :
103 : : return NULL;
104 : : }
105 : :
106 : : static int
107 : 0 : nfp_vdpa_vfio_setup(struct nfp_vdpa_dev *device)
108 : : {
109 : : int ret;
110 : 0 : char dev_name[RTE_DEV_NAME_MAX_LEN] = {0};
111 : 0 : struct rte_pci_device *pci_dev = device->pci_dev;
112 : :
113 : 0 : rte_pci_unmap_device(pci_dev);
114 : :
115 : 0 : rte_pci_device_name(&pci_dev->addr, dev_name, RTE_DEV_NAME_MAX_LEN);
116 : 0 : ret = rte_vfio_get_group_num(rte_pci_get_sysfs_path(), dev_name,
117 : : &device->iommu_group);
118 [ # # ]: 0 : if (ret <= 0)
119 : : return -1;
120 : :
121 : 0 : device->vfio_container_fd = rte_vfio_container_create();
122 [ # # ]: 0 : if (device->vfio_container_fd < 0)
123 : : return -1;
124 : :
125 : 0 : device->vfio_group_fd = rte_vfio_container_group_bind(
126 : : device->vfio_container_fd, device->iommu_group);
127 [ # # ]: 0 : if (device->vfio_group_fd < 0)
128 : 0 : goto container_destroy;
129 : :
130 : 0 : DRV_VDPA_LOG(DEBUG, "container_fd=%d, group_fd=%d,\n",
131 : : device->vfio_container_fd, device->vfio_group_fd);
132 : :
133 : 0 : ret = rte_pci_map_device(pci_dev);
134 [ # # ]: 0 : if (ret != 0)
135 : 0 : goto group_unbind;
136 : :
137 : 0 : device->vfio_dev_fd = rte_intr_dev_fd_get(pci_dev->intr_handle);
138 : :
139 : 0 : return 0;
140 : :
141 : : group_unbind:
142 : 0 : rte_vfio_container_group_unbind(device->vfio_container_fd, device->iommu_group);
143 : 0 : container_destroy:
144 : 0 : rte_vfio_container_destroy(device->vfio_container_fd);
145 : :
146 : 0 : return -1;
147 : : }
148 : :
149 : : static void
150 : 0 : nfp_vdpa_vfio_teardown(struct nfp_vdpa_dev *device)
151 : : {
152 : 0 : rte_pci_unmap_device(device->pci_dev);
153 : 0 : rte_vfio_container_group_unbind(device->vfio_container_fd, device->iommu_group);
154 : 0 : rte_vfio_container_destroy(device->vfio_container_fd);
155 : 0 : }
156 : :
157 : : static int
158 : 0 : nfp_vdpa_dma_do_unmap(struct rte_vhost_memory *mem,
159 : : uint32_t times,
160 : : int vfio_container_fd)
161 : : {
162 : : uint32_t i;
163 : : int ret = 0;
164 : : struct rte_vhost_mem_region *region;
165 : :
166 [ # # ]: 0 : for (i = 0; i < times; i++) {
167 : : region = &mem->regions[i];
168 : :
169 : 0 : ret = rte_vfio_container_dma_unmap(vfio_container_fd,
170 : : region->host_user_addr, region->guest_phys_addr,
171 : : region->size);
172 [ # # ]: 0 : if (ret < 0) {
173 : : /* Here should not return, even error happened. */
174 : 0 : DRV_VDPA_LOG(ERR, "DMA unmap failed. Times: %u", i);
175 : : }
176 : : }
177 : :
178 : 0 : return ret;
179 : : }
180 : :
181 : : static int
182 : 0 : nfp_vdpa_dma_do_map(struct rte_vhost_memory *mem,
183 : : uint32_t times,
184 : : int vfio_container_fd)
185 : : {
186 : : int ret;
187 : : uint32_t i;
188 : : struct rte_vhost_mem_region *region;
189 : :
190 [ # # ]: 0 : for (i = 0; i < times; i++) {
191 : : region = &mem->regions[i];
192 : :
193 : 0 : ret = rte_vfio_container_dma_map(vfio_container_fd,
194 : : region->host_user_addr, region->guest_phys_addr,
195 : : region->size);
196 [ # # ]: 0 : if (ret < 0) {
197 : 0 : DRV_VDPA_LOG(ERR, "DMA map failed.");
198 : 0 : nfp_vdpa_dma_do_unmap(mem, i, vfio_container_fd);
199 : 0 : return ret;
200 : : }
201 : : }
202 : :
203 : : return 0;
204 : : }
205 : :
206 : : static int
207 : 0 : nfp_vdpa_dma_map(struct nfp_vdpa_dev *device,
208 : : bool do_map)
209 : : {
210 : : int ret;
211 : : int vfio_container_fd;
212 : 0 : struct rte_vhost_memory *mem = NULL;
213 : :
214 : 0 : ret = rte_vhost_get_mem_table(device->vid, &mem);
215 [ # # ]: 0 : if (ret < 0) {
216 : 0 : DRV_VDPA_LOG(ERR, "Failed to get memory layout.");
217 : 0 : return ret;
218 : : }
219 : :
220 : 0 : vfio_container_fd = device->vfio_container_fd;
221 : 0 : DRV_VDPA_LOG(DEBUG, "vfio_container_fd %d", vfio_container_fd);
222 : :
223 [ # # ]: 0 : if (do_map)
224 : 0 : ret = nfp_vdpa_dma_do_map(mem, mem->nregions, vfio_container_fd);
225 : : else
226 : 0 : ret = nfp_vdpa_dma_do_unmap(mem, mem->nregions, vfio_container_fd);
227 : :
228 : 0 : free(mem);
229 : :
230 : 0 : return ret;
231 : : }
232 : :
233 : : static uint64_t
234 : 0 : nfp_vdpa_qva_to_gpa(int vid,
235 : : uint64_t qva)
236 : : {
237 : : int ret;
238 : : uint32_t i;
239 : : uint64_t gpa = 0;
240 : 0 : struct rte_vhost_memory *mem = NULL;
241 : : struct rte_vhost_mem_region *region;
242 : :
243 : 0 : ret = rte_vhost_get_mem_table(vid, &mem);
244 [ # # ]: 0 : if (ret < 0) {
245 : 0 : DRV_VDPA_LOG(ERR, "Failed to get memory layout.");
246 : 0 : return gpa;
247 : : }
248 : :
249 [ # # ]: 0 : for (i = 0; i < mem->nregions; i++) {
250 : : region = &mem->regions[i];
251 : :
252 [ # # ]: 0 : if (qva >= region->host_user_addr &&
253 [ # # ]: 0 : qva < region->host_user_addr + region->size) {
254 : 0 : gpa = qva - region->host_user_addr + region->guest_phys_addr;
255 : 0 : break;
256 : : }
257 : : }
258 : :
259 : 0 : free(mem);
260 : :
261 : 0 : return gpa;
262 : : }
263 : :
264 : : static int
265 : 0 : nfp_vdpa_start(struct nfp_vdpa_dev *device)
266 : : {
267 : : int ret;
268 : : int vid;
269 : : uint16_t i;
270 : : uint64_t gpa;
271 : : struct rte_vhost_vring vring;
272 : 0 : struct nfp_vdpa_hw *vdpa_hw = &device->hw;
273 : :
274 : 0 : vid = device->vid;
275 : 0 : vdpa_hw->nr_vring = rte_vhost_get_vring_num(vid);
276 : :
277 : 0 : ret = rte_vhost_get_negotiated_features(vid, &vdpa_hw->req_features);
278 [ # # ]: 0 : if (ret != 0)
279 : : return ret;
280 : :
281 [ # # ]: 0 : for (i = 0; i < vdpa_hw->nr_vring; i++) {
282 : 0 : ret = rte_vhost_get_vhost_vring(vid, i, &vring);
283 [ # # ]: 0 : if (ret != 0)
284 : 0 : return ret;
285 : :
286 : 0 : gpa = nfp_vdpa_qva_to_gpa(vid, (uint64_t)(uintptr_t)vring.desc);
287 [ # # ]: 0 : if (gpa == 0) {
288 : 0 : DRV_VDPA_LOG(ERR, "Fail to get GPA for descriptor ring.");
289 : 0 : return -1;
290 : : }
291 : :
292 : 0 : vdpa_hw->vring[i].desc = gpa;
293 : :
294 : 0 : gpa = nfp_vdpa_qva_to_gpa(vid, (uint64_t)(uintptr_t)vring.avail);
295 [ # # ]: 0 : if (gpa == 0) {
296 : 0 : DRV_VDPA_LOG(ERR, "Fail to get GPA for available ring.");
297 : 0 : return -1;
298 : : }
299 : :
300 : 0 : vdpa_hw->vring[i].avail = gpa;
301 : :
302 : 0 : gpa = nfp_vdpa_qva_to_gpa(vid, (uint64_t)(uintptr_t)vring.used);
303 [ # # ]: 0 : if (gpa == 0) {
304 : 0 : DRV_VDPA_LOG(ERR, "Fail to get GPA for used ring.");
305 : 0 : return -1;
306 : : }
307 : :
308 : 0 : vdpa_hw->vring[i].used = gpa;
309 : :
310 : 0 : vdpa_hw->vring[i].size = vring.size;
311 : :
312 : 0 : ret = rte_vhost_get_vring_base(vid, i,
313 : : &vdpa_hw->vring[i].last_avail_idx,
314 : : &vdpa_hw->vring[i].last_used_idx);
315 [ # # ]: 0 : if (ret != 0)
316 : 0 : return ret;
317 : : }
318 : :
319 : 0 : return nfp_vdpa_hw_start(&device->hw, vid);
320 : : }
321 : :
322 : : static void
323 : 0 : nfp_vdpa_stop(struct nfp_vdpa_dev *device)
324 : : {
325 : : int vid;
326 : : uint32_t i;
327 : 0 : struct nfp_vdpa_hw *vdpa_hw = &device->hw;
328 : :
329 : 0 : nfp_vdpa_hw_stop(vdpa_hw);
330 : :
331 : 0 : vid = device->vid;
332 [ # # ]: 0 : for (i = 0; i < vdpa_hw->nr_vring; i++)
333 : 0 : rte_vhost_set_vring_base(vid, i,
334 : 0 : vdpa_hw->vring[i].last_avail_idx,
335 : 0 : vdpa_hw->vring[i].last_used_idx);
336 : 0 : }
337 : :
338 : : static int
339 : 0 : nfp_vdpa_enable_vfio_intr(struct nfp_vdpa_dev *device)
340 : : {
341 : : int ret;
342 : : uint16_t i;
343 : : int *fd_ptr;
344 : : uint16_t nr_vring;
345 : : struct vfio_irq_set *irq_set;
346 : : struct rte_vhost_vring vring;
347 : : char irq_set_buf[MSIX_IRQ_SET_BUF_LEN];
348 : :
349 : 0 : nr_vring = rte_vhost_get_vring_num(device->vid);
350 : :
351 : : irq_set = (struct vfio_irq_set *)irq_set_buf;
352 : 0 : irq_set->argsz = sizeof(irq_set_buf);
353 : 0 : irq_set->count = nr_vring + 1;
354 : 0 : irq_set->flags = VFIO_IRQ_SET_DATA_EVENTFD | VFIO_IRQ_SET_ACTION_TRIGGER;
355 : 0 : irq_set->index = VFIO_PCI_MSIX_IRQ_INDEX;
356 : 0 : irq_set->start = 0;
357 : :
358 : : fd_ptr = (int *)&irq_set->data;
359 : 0 : fd_ptr[RTE_INTR_VEC_ZERO_OFFSET] = rte_intr_fd_get(device->pci_dev->intr_handle);
360 : :
361 [ # # ]: 0 : for (i = 0; i < nr_vring; i++)
362 : 0 : device->intr_fd[i] = -1;
363 : :
364 [ # # ]: 0 : for (i = 0; i < nr_vring; i++) {
365 : 0 : rte_vhost_get_vhost_vring(device->vid, i, &vring);
366 : 0 : fd_ptr[RTE_INTR_VEC_RXTX_OFFSET + i] = vring.callfd;
367 : : }
368 : :
369 : 0 : ret = ioctl(device->vfio_dev_fd, VFIO_DEVICE_SET_IRQS, irq_set);
370 [ # # ]: 0 : if (ret != 0) {
371 : 0 : DRV_VDPA_LOG(ERR, "Error enabling MSI-X interrupts.");
372 : 0 : return -EIO;
373 : : }
374 : :
375 : : return 0;
376 : : }
377 : :
378 : : static int
379 : 0 : nfp_vdpa_disable_vfio_intr(struct nfp_vdpa_dev *device)
380 : : {
381 : : int ret;
382 : : struct vfio_irq_set *irq_set;
383 : : char irq_set_buf[MSIX_IRQ_SET_BUF_LEN];
384 : :
385 : : irq_set = (struct vfio_irq_set *)irq_set_buf;
386 : 0 : irq_set->argsz = sizeof(irq_set_buf);
387 : 0 : irq_set->count = 0;
388 : 0 : irq_set->flags = VFIO_IRQ_SET_DATA_NONE | VFIO_IRQ_SET_ACTION_TRIGGER;
389 : 0 : irq_set->index = VFIO_PCI_MSIX_IRQ_INDEX;
390 : 0 : irq_set->start = 0;
391 : :
392 : 0 : ret = ioctl(device->vfio_dev_fd, VFIO_DEVICE_SET_IRQS, irq_set);
393 [ # # ]: 0 : if (ret != 0) {
394 : 0 : DRV_VDPA_LOG(ERR, "Error disabling MSI-X interrupts.");
395 : 0 : return -EIO;
396 : : }
397 : :
398 : : return 0;
399 : : }
400 : :
401 : : static void
402 : 0 : nfp_vdpa_read_kickfd(int kickfd)
403 : : {
404 : : int bytes;
405 : : uint64_t buf;
406 : :
407 : : for (;;) {
408 : 0 : bytes = read(kickfd, &buf, 8);
409 [ # # ]: 0 : if (bytes >= 0)
410 : : break;
411 : :
412 [ # # ]: 0 : if (errno != EINTR && errno != EWOULDBLOCK &&
413 : : errno != EAGAIN) {
414 : 0 : DRV_VDPA_LOG(ERR, "Error reading kickfd");
415 : 0 : break;
416 : : }
417 : : }
418 : 0 : }
419 : :
420 : : static int
421 : 0 : nfp_vdpa_notify_epoll_ctl(uint32_t queue_num,
422 : : struct nfp_vdpa_dev *device)
423 : : {
424 : : int ret;
425 : : uint32_t qid;
426 : :
427 [ # # ]: 0 : for (qid = 0; qid < queue_num; qid++) {
428 : : struct epoll_event ev;
429 : : struct rte_vhost_vring vring;
430 : :
431 : 0 : ev.events = EPOLLIN | EPOLLPRI;
432 : 0 : rte_vhost_get_vhost_vring(device->vid, qid, &vring);
433 : 0 : ev.data.u64 = qid | (uint64_t)vring.kickfd << 32;
434 : 0 : ret = epoll_ctl(device->epoll_fd, EPOLL_CTL_ADD, vring.kickfd, &ev);
435 [ # # ]: 0 : if (ret < 0) {
436 : 0 : DRV_VDPA_LOG(ERR, "Epoll add error for queue %d", qid);
437 : 0 : return ret;
438 : : }
439 : : }
440 : :
441 : : return 0;
442 : : }
443 : :
444 : : static int
445 : 0 : nfp_vdpa_notify_epoll_wait(uint32_t queue_num,
446 : : struct nfp_vdpa_dev *device)
447 : : {
448 : : int i;
449 : : int fds;
450 : : int kickfd;
451 : : uint32_t qid;
452 : : struct epoll_event events[NFP_VDPA_MAX_QUEUES * 2];
453 : :
454 : : for (;;) {
455 : 0 : fds = epoll_wait(device->epoll_fd, events, queue_num, -1);
456 [ # # ]: 0 : if (fds < 0) {
457 [ # # ]: 0 : if (errno == EINTR)
458 : 0 : continue;
459 : :
460 : 0 : DRV_VDPA_LOG(ERR, "Epoll wait fail");
461 : : return -EACCES;
462 : : }
463 : :
464 : 0 : for (i = 0; i < fds; i++) {
465 : 0 : qid = events[i].data.u32;
466 : 0 : kickfd = (uint32_t)(events[i].data.u64 >> 32);
467 : :
468 : 0 : nfp_vdpa_read_kickfd(kickfd);
469 : 0 : nfp_vdpa_notify_queue(&device->hw, qid);
470 : : }
471 : : }
472 : :
473 : : return 0;
474 : : }
475 : :
476 : : static uint32_t
477 : 0 : nfp_vdpa_notify_relay(void *arg)
478 : : {
479 : : int ret;
480 : : int epoll_fd;
481 : : uint32_t queue_num;
482 : : struct nfp_vdpa_dev *device = arg;
483 : :
484 : 0 : epoll_fd = epoll_create(NFP_VDPA_MAX_QUEUES * 2);
485 [ # # ]: 0 : if (epoll_fd < 0) {
486 : 0 : DRV_VDPA_LOG(ERR, "failed to create epoll instance.");
487 : 0 : return 1;
488 : : }
489 : :
490 : 0 : device->epoll_fd = epoll_fd;
491 : :
492 : 0 : queue_num = rte_vhost_get_vring_num(device->vid);
493 : :
494 : 0 : ret = nfp_vdpa_notify_epoll_ctl(queue_num, device);
495 [ # # ]: 0 : if (ret != 0)
496 : 0 : goto notify_exit;
497 : :
498 : 0 : ret = nfp_vdpa_notify_epoll_wait(queue_num, device);
499 [ # # ]: 0 : if (ret != 0)
500 : 0 : goto notify_exit;
501 : :
502 : : return 0;
503 : :
504 : 0 : notify_exit:
505 : 0 : close(device->epoll_fd);
506 : 0 : device->epoll_fd = -1;
507 : :
508 : 0 : return 1;
509 : : }
510 : :
511 : : static int
512 : 0 : nfp_vdpa_setup_notify_relay(struct nfp_vdpa_dev *device)
513 : : {
514 : : int ret;
515 : : char name[RTE_THREAD_INTERNAL_NAME_SIZE];
516 : :
517 : 0 : snprintf(name, sizeof(name), "nfp-noti%d", device->vid);
518 : 0 : ret = rte_thread_create_internal_control(&device->tid, name,
519 : : nfp_vdpa_notify_relay, (void *)device);
520 [ # # ]: 0 : if (ret != 0) {
521 : 0 : DRV_VDPA_LOG(ERR, "Failed to create notify relay pthread.");
522 : 0 : return -1;
523 : : }
524 : :
525 : : return 0;
526 : : }
527 : :
528 : : static void
529 : 0 : nfp_vdpa_unset_notify_relay(struct nfp_vdpa_dev *device)
530 : : {
531 [ # # ]: 0 : if (device->tid.opaque_id != 0) {
532 : 0 : pthread_cancel((pthread_t)device->tid.opaque_id);
533 : 0 : rte_thread_join(device->tid, NULL);
534 : 0 : device->tid.opaque_id = 0;
535 : : }
536 : :
537 [ # # ]: 0 : if (device->epoll_fd >= 0) {
538 : 0 : close(device->epoll_fd);
539 : 0 : device->epoll_fd = -1;
540 : : }
541 : 0 : }
542 : :
543 : : static int
544 : 0 : update_datapath(struct nfp_vdpa_dev *device)
545 : : {
546 : : int ret;
547 : :
548 : 0 : rte_spinlock_lock(&device->lock);
549 : :
550 [ # # ]: 0 : if ((rte_atomic_load_explicit(&device->running, rte_memory_order_relaxed) == 0) &&
551 [ # # ]: 0 : (rte_atomic_load_explicit(&device->started,
552 : 0 : rte_memory_order_relaxed) != 0) &&
553 [ # # ]: 0 : (rte_atomic_load_explicit(&device->dev_attached,
554 : : rte_memory_order_relaxed) != 0)) {
555 : 0 : ret = nfp_vdpa_dma_map(device, true);
556 [ # # ]: 0 : if (ret != 0)
557 : 0 : goto unlock_exit;
558 : :
559 : 0 : ret = nfp_vdpa_enable_vfio_intr(device);
560 [ # # ]: 0 : if (ret != 0)
561 : 0 : goto dma_map_rollback;
562 : :
563 : 0 : ret = nfp_vdpa_start(device);
564 [ # # ]: 0 : if (ret != 0)
565 : 0 : goto disable_vfio_intr;
566 : :
567 : 0 : ret = nfp_vdpa_setup_notify_relay(device);
568 [ # # ]: 0 : if (ret != 0)
569 : 0 : goto vdpa_stop;
570 : :
571 : 0 : rte_atomic_store_explicit(&device->running, 1, rte_memory_order_relaxed);
572 [ # # ]: 0 : } else if ((rte_atomic_load_explicit(&device->running, rte_memory_order_relaxed) != 0) &&
573 [ # # ]: 0 : ((rte_atomic_load_explicit(&device->started,
574 : 0 : rte_memory_order_relaxed) != 0) ||
575 [ # # ]: 0 : (rte_atomic_load_explicit(&device->dev_attached,
576 : : rte_memory_order_relaxed) != 0))) {
577 : 0 : nfp_vdpa_unset_notify_relay(device);
578 : :
579 : 0 : nfp_vdpa_stop(device);
580 : :
581 : 0 : ret = nfp_vdpa_disable_vfio_intr(device);
582 [ # # ]: 0 : if (ret != 0)
583 : 0 : goto unlock_exit;
584 : :
585 : 0 : ret = nfp_vdpa_dma_map(device, false);
586 [ # # ]: 0 : if (ret != 0)
587 : 0 : goto unlock_exit;
588 : :
589 : 0 : rte_atomic_store_explicit(&device->running, 0, rte_memory_order_relaxed);
590 : : }
591 : :
592 : : rte_spinlock_unlock(&device->lock);
593 : 0 : return 0;
594 : :
595 : : vdpa_stop:
596 : 0 : nfp_vdpa_stop(device);
597 : 0 : disable_vfio_intr:
598 : 0 : nfp_vdpa_disable_vfio_intr(device);
599 : 0 : dma_map_rollback:
600 : 0 : nfp_vdpa_dma_map(device, false);
601 : 0 : unlock_exit:
602 : : rte_spinlock_unlock(&device->lock);
603 : 0 : return ret;
604 : : }
605 : :
606 : : static int
607 : 0 : nfp_vdpa_dev_config(int vid)
608 : : {
609 : : int ret;
610 : : struct nfp_vdpa_dev *device;
611 : : struct rte_vdpa_device *vdev;
612 : : struct nfp_vdpa_dev_node *node;
613 : :
614 : 0 : vdev = rte_vhost_get_vdpa_device(vid);
615 : 0 : node = nfp_vdpa_find_node_by_vdev(vdev);
616 [ # # ]: 0 : if (node == NULL) {
617 : 0 : DRV_VDPA_LOG(ERR, "Invalid vDPA device: %p", vdev);
618 : 0 : return -ENODEV;
619 : : }
620 : :
621 : 0 : device = node->device;
622 : 0 : device->vid = vid;
623 : 0 : rte_atomic_store_explicit(&device->dev_attached, 1, rte_memory_order_relaxed);
624 : 0 : update_datapath(device);
625 : :
626 : 0 : ret = rte_vhost_host_notifier_ctrl(vid, RTE_VHOST_QUEUE_ALL, true);
627 [ # # ]: 0 : if (ret != 0)
628 : 0 : DRV_VDPA_LOG(INFO, "vDPA (%s): software relay is used.",
629 : : vdev->device->name);
630 : :
631 : : return 0;
632 : : }
633 : :
634 : : static int
635 : 0 : nfp_vdpa_dev_close(int vid)
636 : : {
637 : : struct nfp_vdpa_dev *device;
638 : : struct rte_vdpa_device *vdev;
639 : : struct nfp_vdpa_dev_node *node;
640 : :
641 : 0 : vdev = rte_vhost_get_vdpa_device(vid);
642 : 0 : node = nfp_vdpa_find_node_by_vdev(vdev);
643 [ # # ]: 0 : if (node == NULL) {
644 : 0 : DRV_VDPA_LOG(ERR, "Invalid vDPA device: %p", vdev);
645 : 0 : return -ENODEV;
646 : : }
647 : :
648 : 0 : device = node->device;
649 : 0 : rte_atomic_store_explicit(&device->dev_attached, 0, rte_memory_order_relaxed);
650 : 0 : update_datapath(device);
651 : :
652 : 0 : return 0;
653 : : }
654 : :
655 : : static int
656 : 0 : nfp_vdpa_get_vfio_group_fd(int vid)
657 : : {
658 : : struct rte_vdpa_device *vdev;
659 : : struct nfp_vdpa_dev_node *node;
660 : :
661 : 0 : vdev = rte_vhost_get_vdpa_device(vid);
662 : 0 : node = nfp_vdpa_find_node_by_vdev(vdev);
663 [ # # ]: 0 : if (node == NULL) {
664 : 0 : DRV_VDPA_LOG(ERR, "Invalid vDPA device: %p", vdev);
665 : 0 : return -ENODEV;
666 : : }
667 : :
668 : 0 : return node->device->vfio_group_fd;
669 : : }
670 : :
671 : : static int
672 : 0 : nfp_vdpa_get_vfio_device_fd(int vid)
673 : : {
674 : : struct rte_vdpa_device *vdev;
675 : : struct nfp_vdpa_dev_node *node;
676 : :
677 : 0 : vdev = rte_vhost_get_vdpa_device(vid);
678 : 0 : node = nfp_vdpa_find_node_by_vdev(vdev);
679 [ # # ]: 0 : if (node == NULL) {
680 : 0 : DRV_VDPA_LOG(ERR, "Invalid vDPA device: %p", vdev);
681 : 0 : return -ENODEV;
682 : : }
683 : :
684 : 0 : return node->device->vfio_dev_fd;
685 : : }
686 : :
687 : : static int
688 : 0 : nfp_vdpa_get_notify_area(int vid,
689 : : int qid,
690 : : uint64_t *offset,
691 : : uint64_t *size)
692 : : {
693 : : int ret;
694 : : struct nfp_vdpa_dev *device;
695 : : struct rte_vdpa_device *vdev;
696 : : struct nfp_vdpa_dev_node *node;
697 : 0 : struct vfio_region_info region = {
698 : : .argsz = sizeof(region)
699 : : };
700 : :
701 : 0 : vdev = rte_vhost_get_vdpa_device(vid);
702 : 0 : node = nfp_vdpa_find_node_by_vdev(vdev);
703 [ # # ]: 0 : if (node == NULL) {
704 : 0 : DRV_VDPA_LOG(ERR, "Invalid vDPA device: %p", vdev);
705 : 0 : return -ENODEV;
706 : : }
707 : :
708 : 0 : device = node->device;
709 : 0 : region.index = device->hw.notify_region;
710 : :
711 : 0 : ret = ioctl(device->vfio_dev_fd, VFIO_DEVICE_GET_REGION_INFO, ®ion);
712 [ # # ]: 0 : if (ret != 0) {
713 : 0 : DRV_VDPA_LOG(ERR, "Get not get device region info.");
714 : 0 : return -EIO;
715 : : }
716 : :
717 : 0 : *offset = nfp_vdpa_get_queue_notify_offset(&device->hw, qid) + region.offset;
718 : 0 : *size = NFP_VDPA_NOTIFY_ADDR_INTERVAL;
719 : :
720 : 0 : return 0;
721 : : }
722 : :
723 : : static int
724 : 0 : nfp_vdpa_get_queue_num(struct rte_vdpa_device *vdev,
725 : : uint32_t *queue_num)
726 : : {
727 : : struct nfp_vdpa_dev_node *node;
728 : :
729 : 0 : node = nfp_vdpa_find_node_by_vdev(vdev);
730 [ # # ]: 0 : if (node == NULL) {
731 : 0 : DRV_VDPA_LOG(ERR, "Invalid vDPA device: %p", vdev);
732 : 0 : return -ENODEV;
733 : : }
734 : :
735 : 0 : *queue_num = node->device->max_queues;
736 : :
737 : 0 : return 0;
738 : : }
739 : :
740 : : static int
741 : 0 : nfp_vdpa_get_vdpa_features(struct rte_vdpa_device *vdev,
742 : : uint64_t *features)
743 : : {
744 : : struct nfp_vdpa_dev_node *node;
745 : :
746 : 0 : node = nfp_vdpa_find_node_by_vdev(vdev);
747 [ # # ]: 0 : if (node == NULL) {
748 : 0 : DRV_VDPA_LOG(ERR, "Invalid vDPA device: %p", vdev);
749 : 0 : return -ENODEV;
750 : : }
751 : :
752 : 0 : *features = node->device->hw.features;
753 : :
754 : 0 : return 0;
755 : : }
756 : :
757 : : static int
758 : 0 : nfp_vdpa_get_protocol_features(struct rte_vdpa_device *vdev __rte_unused,
759 : : uint64_t *features)
760 : : {
761 : 0 : *features = 1ULL << VHOST_USER_PROTOCOL_F_LOG_SHMFD |
762 : : 1ULL << VHOST_USER_PROTOCOL_F_REPLY_ACK |
763 : : 1ULL << VHOST_USER_PROTOCOL_F_BACKEND_REQ |
764 : : 1ULL << VHOST_USER_PROTOCOL_F_BACKEND_SEND_FD |
765 : : 1ULL << VHOST_USER_PROTOCOL_F_HOST_NOTIFIER;
766 : :
767 : 0 : return 0;
768 : : }
769 : :
770 : : static int
771 : 0 : nfp_vdpa_set_features(int32_t vid)
772 : : {
773 : 0 : DRV_VDPA_LOG(DEBUG, "Start vid=%d", vid);
774 : 0 : return 0;
775 : : }
776 : :
777 : : static int
778 : 0 : nfp_vdpa_set_vring_state(int vid,
779 : : int vring,
780 : : int state)
781 : : {
782 : 0 : DRV_VDPA_LOG(DEBUG, "Start vid=%d, vring=%d, state=%d", vid, vring, state);
783 : 0 : return 0;
784 : : }
785 : :
786 : : struct rte_vdpa_dev_ops nfp_vdpa_ops = {
787 : : .get_queue_num = nfp_vdpa_get_queue_num,
788 : : .get_features = nfp_vdpa_get_vdpa_features,
789 : : .get_protocol_features = nfp_vdpa_get_protocol_features,
790 : : .dev_conf = nfp_vdpa_dev_config,
791 : : .dev_close = nfp_vdpa_dev_close,
792 : : .set_vring_state = nfp_vdpa_set_vring_state,
793 : : .set_features = nfp_vdpa_set_features,
794 : : .get_vfio_group_fd = nfp_vdpa_get_vfio_group_fd,
795 : : .get_vfio_device_fd = nfp_vdpa_get_vfio_device_fd,
796 : : .get_notify_area = nfp_vdpa_get_notify_area,
797 : : };
798 : :
799 : : static int
800 : 0 : nfp_vdpa_pci_probe(struct rte_pci_device *pci_dev)
801 : : {
802 : : int ret;
803 : : struct nfp_vdpa_dev *device;
804 : : struct nfp_vdpa_dev_node *node;
805 : :
806 [ # # ]: 0 : if (rte_eal_process_type() != RTE_PROC_PRIMARY)
807 : : return 0;
808 : :
809 : 0 : node = calloc(1, sizeof(*node));
810 [ # # ]: 0 : if (node == NULL)
811 : : return -ENOMEM;
812 : :
813 : 0 : device = calloc(1, sizeof(*device));
814 [ # # ]: 0 : if (device == NULL)
815 : 0 : goto free_node;
816 : :
817 : 0 : device->pci_dev = pci_dev;
818 : :
819 : 0 : ret = nfp_vdpa_vfio_setup(device);
820 [ # # ]: 0 : if (ret != 0)
821 : 0 : goto free_device;
822 : :
823 : 0 : ret = nfp_vdpa_hw_init(&device->hw, pci_dev);
824 [ # # ]: 0 : if (ret != 0)
825 : 0 : goto vfio_teardown;
826 : :
827 : 0 : device->max_queues = NFP_VDPA_MAX_QUEUES;
828 : :
829 : 0 : device->vdev = rte_vdpa_register_device(&pci_dev->device, &nfp_vdpa_ops);
830 [ # # ]: 0 : if (device->vdev == NULL) {
831 : 0 : DRV_VDPA_LOG(ERR, "Failed to register device %s", pci_dev->name);
832 : 0 : goto vfio_teardown;
833 : : }
834 : :
835 : 0 : node->device = device;
836 : 0 : pthread_mutex_lock(&vdpa_list_lock);
837 : 0 : TAILQ_INSERT_TAIL(&vdpa_dev_list, node, next);
838 : 0 : pthread_mutex_unlock(&vdpa_list_lock);
839 : :
840 : : rte_spinlock_init(&device->lock);
841 : 0 : rte_atomic_store_explicit(&device->started, 1, rte_memory_order_relaxed);
842 : 0 : update_datapath(device);
843 : :
844 : 0 : return 0;
845 : :
846 : 0 : vfio_teardown:
847 : 0 : nfp_vdpa_vfio_teardown(device);
848 : 0 : free_device:
849 : 0 : free(device);
850 : 0 : free_node:
851 : 0 : free(node);
852 : :
853 : 0 : return -1;
854 : : }
855 : :
856 : : static int
857 : 0 : nfp_vdpa_pci_remove(struct rte_pci_device *pci_dev)
858 : : {
859 : : struct nfp_vdpa_dev *device;
860 : : struct nfp_vdpa_dev_node *node;
861 : :
862 [ # # ]: 0 : if (rte_eal_process_type() != RTE_PROC_PRIMARY)
863 : : return 0;
864 : :
865 : 0 : node = nfp_vdpa_find_node_by_pdev(pci_dev);
866 [ # # ]: 0 : if (node == NULL) {
867 : 0 : DRV_VDPA_LOG(ERR, "Invalid device: %s", pci_dev->name);
868 : 0 : return -ENODEV;
869 : : }
870 : :
871 : 0 : device = node->device;
872 : :
873 : 0 : rte_atomic_store_explicit(&device->started, 0, rte_memory_order_relaxed);
874 : 0 : update_datapath(device);
875 : :
876 : 0 : pthread_mutex_lock(&vdpa_list_lock);
877 [ # # ]: 0 : TAILQ_REMOVE(&vdpa_dev_list, node, next);
878 : 0 : pthread_mutex_unlock(&vdpa_list_lock);
879 : :
880 : 0 : rte_vdpa_unregister_device(device->vdev);
881 : 0 : nfp_vdpa_vfio_teardown(device);
882 : :
883 : 0 : free(device);
884 : 0 : free(node);
885 : :
886 : 0 : return 0;
887 : : }
888 : :
889 : : static const struct rte_pci_id pci_id_nfp_vdpa_map[] = {
890 : : {
891 : : RTE_PCI_DEVICE(PCI_VENDOR_ID_NETRONOME,
892 : : PCI_DEVICE_ID_NFP6000_VF_NIC)
893 : : },
894 : : {
895 : : .vendor_id = 0,
896 : : },
897 : : };
898 : :
899 : : static struct nfp_class_driver nfp_vdpa = {
900 : : .drv_class = NFP_CLASS_VDPA,
901 : : .name = RTE_STR(NFP_VDPA_DRIVER_NAME),
902 : : .id_table = pci_id_nfp_vdpa_map,
903 : : .drv_flags = RTE_PCI_DRV_NEED_MAPPING | RTE_PCI_DRV_INTR_LSC,
904 : : .probe = nfp_vdpa_pci_probe,
905 : : .remove = nfp_vdpa_pci_remove,
906 : : };
907 : :
908 : 238 : RTE_INIT(nfp_vdpa_init)
909 : : {
910 : 238 : nfp_class_driver_register(&nfp_vdpa);
911 : 238 : }
912 : :
913 : : RTE_PMD_REGISTER_PCI_TABLE(NFP_VDPA_DRIVER_NAME, pci_id_nfp_vdpa_map);
914 : : RTE_PMD_REGISTER_KMOD_DEP(NFP_VDPA_DRIVER_NAME, "* vfio-pci");
|