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 <uapi/linux/vfio.h>
7 : :
8 : : #include <pthread.h>
9 : : #include <sys/epoll.h>
10 : : #include <sys/ioctl.h>
11 : : #include <unistd.h>
12 : :
13 : : #include <nfp_common_pci.h>
14 : : #include <nfp_dev.h>
15 : : #include <rte_vfio.h>
16 : : #include <rte_eal_paging.h>
17 : : #include <rte_malloc.h>
18 : : #include <vdpa_driver.h>
19 : :
20 : : #include "nfp_vdpa_core.h"
21 : : #include "nfp_vdpa_log.h"
22 : :
23 : : #define NFP_VDPA_DRIVER_NAME nfp_vdpa
24 : :
25 : : #define MSIX_IRQ_SET_BUF_LEN (sizeof(struct vfio_irq_set) + \
26 : : sizeof(int) * (NFP_VDPA_MAX_QUEUES * 2 + 1))
27 : :
28 : : #define NFP_VDPA_USED_RING_LEN(size) \
29 : : ((size) * sizeof(struct vring_used_elem) + sizeof(struct vring_used))
30 : :
31 : : #define EPOLL_DATA_INTR 1
32 : :
33 : : struct nfp_vdpa_dev {
34 : : struct rte_pci_device *pci_dev;
35 : : struct rte_vdpa_device *vdev;
36 : : struct nfp_vdpa_hw hw;
37 : :
38 : : int vfio_container_fd;
39 : : int vfio_group_fd;
40 : : int vfio_dev_fd;
41 : : int iommu_group;
42 : :
43 : : rte_thread_t tid; /**< Thread for notify relay */
44 : : int epoll_fd;
45 : :
46 : : int vid;
47 : : uint16_t max_queues;
48 : : RTE_ATOMIC(uint32_t) started;
49 : : RTE_ATOMIC(uint32_t) dev_attached;
50 : : RTE_ATOMIC(uint32_t) running;
51 : : rte_spinlock_t lock;
52 : :
53 : : /** Eventfd for used ring interrupt */
54 : : int intr_fd[NFP_VDPA_MAX_QUEUES * 2];
55 : : };
56 : :
57 : : struct nfp_vdpa_dev_node {
58 : : TAILQ_ENTRY(nfp_vdpa_dev_node) next;
59 : : struct nfp_vdpa_dev *device;
60 : : };
61 : :
62 : : TAILQ_HEAD(vdpa_dev_list_head, nfp_vdpa_dev_node);
63 : :
64 : : static struct vdpa_dev_list_head vdpa_dev_list =
65 : : TAILQ_HEAD_INITIALIZER(vdpa_dev_list);
66 : :
67 : : static pthread_mutex_t vdpa_list_lock = PTHREAD_MUTEX_INITIALIZER;
68 : :
69 : : static struct nfp_vdpa_dev_node *
70 : 0 : nfp_vdpa_find_node_by_vdev(struct rte_vdpa_device *vdev)
71 : : {
72 : : bool found = false;
73 : : struct nfp_vdpa_dev_node *node;
74 : :
75 : 0 : pthread_mutex_lock(&vdpa_list_lock);
76 : :
77 [ # # ]: 0 : TAILQ_FOREACH(node, &vdpa_dev_list, next) {
78 [ # # ]: 0 : if (vdev == node->device->vdev) {
79 : : found = true;
80 : : break;
81 : : }
82 : : }
83 : :
84 : 0 : pthread_mutex_unlock(&vdpa_list_lock);
85 : :
86 [ # # ]: 0 : if (found)
87 : 0 : return node;
88 : :
89 : : return NULL;
90 : : }
91 : :
92 : : static struct nfp_vdpa_dev_node *
93 : 0 : nfp_vdpa_find_node_by_pdev(struct rte_pci_device *pdev)
94 : : {
95 : : bool found = false;
96 : : struct nfp_vdpa_dev_node *node;
97 : :
98 : 0 : pthread_mutex_lock(&vdpa_list_lock);
99 : :
100 [ # # ]: 0 : TAILQ_FOREACH(node, &vdpa_dev_list, next) {
101 [ # # ]: 0 : if (pdev == node->device->pci_dev) {
102 : : found = true;
103 : : break;
104 : : }
105 : : }
106 : :
107 : 0 : pthread_mutex_unlock(&vdpa_list_lock);
108 : :
109 [ # # ]: 0 : if (found)
110 : 0 : return node;
111 : :
112 : : return NULL;
113 : : }
114 : :
115 : : static int
116 : 0 : nfp_vdpa_vfio_setup(struct nfp_vdpa_dev *device)
117 : : {
118 : : int ret;
119 : 0 : char dev_name[RTE_DEV_NAME_MAX_LEN] = {0};
120 : 0 : struct rte_pci_device *pci_dev = device->pci_dev;
121 : :
122 : 0 : rte_pci_unmap_device(pci_dev);
123 : :
124 : 0 : rte_pci_device_name(&pci_dev->addr, dev_name, RTE_DEV_NAME_MAX_LEN);
125 : 0 : ret = rte_vfio_get_group_num(rte_pci_get_sysfs_path(), dev_name,
126 : : &device->iommu_group);
127 [ # # ]: 0 : if (ret <= 0)
128 : : return -1;
129 : :
130 : 0 : device->vfio_container_fd = rte_vfio_container_create();
131 [ # # ]: 0 : if (device->vfio_container_fd < 0)
132 : : return -1;
133 : :
134 : 0 : device->vfio_group_fd = rte_vfio_container_group_bind(
135 : : device->vfio_container_fd, device->iommu_group);
136 [ # # ]: 0 : if (device->vfio_group_fd < 0)
137 : 0 : goto container_destroy;
138 : :
139 : 0 : DRV_VDPA_LOG(DEBUG, "The container_fd=%d, group_fd=%d.",
140 : : device->vfio_container_fd, device->vfio_group_fd);
141 : :
142 : 0 : ret = rte_pci_map_device(pci_dev);
143 [ # # ]: 0 : if (ret != 0)
144 : 0 : goto group_unbind;
145 : :
146 : 0 : device->vfio_dev_fd = rte_intr_dev_fd_get(pci_dev->intr_handle);
147 : :
148 : 0 : return 0;
149 : :
150 : : group_unbind:
151 : 0 : rte_vfio_container_group_unbind(device->vfio_container_fd, device->iommu_group);
152 : 0 : container_destroy:
153 : 0 : rte_vfio_container_destroy(device->vfio_container_fd);
154 : :
155 : 0 : return -1;
156 : : }
157 : :
158 : : static void
159 : 0 : nfp_vdpa_vfio_teardown(struct nfp_vdpa_dev *device)
160 : : {
161 : 0 : rte_pci_unmap_device(device->pci_dev);
162 : 0 : rte_vfio_container_group_unbind(device->vfio_container_fd, device->iommu_group);
163 : 0 : rte_vfio_container_destroy(device->vfio_container_fd);
164 : 0 : }
165 : :
166 : : static int
167 : 0 : nfp_vdpa_dma_do_unmap(struct rte_vhost_memory *mem,
168 : : uint32_t times,
169 : : int vfio_container_fd)
170 : : {
171 : : uint32_t i;
172 : : int ret = 0;
173 : : struct rte_vhost_mem_region *region;
174 : :
175 [ # # ]: 0 : for (i = 0; i < times; i++) {
176 : : region = &mem->regions[i];
177 : :
178 : 0 : ret = rte_vfio_container_dma_unmap(vfio_container_fd,
179 : : region->host_user_addr, region->guest_phys_addr,
180 : : region->size);
181 [ # # ]: 0 : if (ret < 0) {
182 : : /* Here should not return, even error happened. */
183 : 0 : DRV_VDPA_LOG(ERR, "DMA unmap failed. Times: %u.", i);
184 : : }
185 : : }
186 : :
187 : 0 : return ret;
188 : : }
189 : :
190 : : static int
191 : 0 : nfp_vdpa_dma_do_map(struct rte_vhost_memory *mem,
192 : : uint32_t times,
193 : : int vfio_container_fd)
194 : : {
195 : : int ret;
196 : : uint32_t i;
197 : : struct rte_vhost_mem_region *region;
198 : :
199 [ # # ]: 0 : for (i = 0; i < times; i++) {
200 : : region = &mem->regions[i];
201 : :
202 : 0 : ret = rte_vfio_container_dma_map(vfio_container_fd,
203 : : region->host_user_addr, region->guest_phys_addr,
204 : : region->size);
205 [ # # ]: 0 : if (ret < 0) {
206 : 0 : DRV_VDPA_LOG(ERR, "DMA map failed.");
207 : 0 : nfp_vdpa_dma_do_unmap(mem, i, vfio_container_fd);
208 : 0 : return ret;
209 : : }
210 : : }
211 : :
212 : : return 0;
213 : : }
214 : :
215 : : static int
216 : 0 : nfp_vdpa_dma_map(struct nfp_vdpa_dev *device,
217 : : bool do_map)
218 : : {
219 : : int ret;
220 : : int vfio_container_fd;
221 : 0 : struct rte_vhost_memory *mem = NULL;
222 : :
223 : 0 : ret = rte_vhost_get_mem_table(device->vid, &mem);
224 [ # # ]: 0 : if (ret < 0) {
225 : 0 : DRV_VDPA_LOG(ERR, "Failed to get memory layout.");
226 : 0 : return ret;
227 : : }
228 : :
229 : 0 : vfio_container_fd = device->vfio_container_fd;
230 : 0 : DRV_VDPA_LOG(DEBUG, "The vfio_container_fd %d.", vfio_container_fd);
231 : :
232 [ # # ]: 0 : if (do_map)
233 : 0 : ret = nfp_vdpa_dma_do_map(mem, mem->nregions, vfio_container_fd);
234 : : else
235 : 0 : ret = nfp_vdpa_dma_do_unmap(mem, mem->nregions, vfio_container_fd);
236 : :
237 : 0 : free(mem);
238 : :
239 : 0 : return ret;
240 : : }
241 : :
242 : : static uint64_t
243 : 0 : nfp_vdpa_qva_to_gpa(int vid,
244 : : uint64_t qva)
245 : : {
246 : : int ret;
247 : : uint32_t i;
248 : : uint64_t gpa = 0;
249 : 0 : struct rte_vhost_memory *mem = NULL;
250 : : struct rte_vhost_mem_region *region;
251 : :
252 : 0 : ret = rte_vhost_get_mem_table(vid, &mem);
253 [ # # ]: 0 : if (ret < 0) {
254 : 0 : DRV_VDPA_LOG(ERR, "Failed to get memory layout.");
255 : 0 : return gpa;
256 : : }
257 : :
258 [ # # ]: 0 : for (i = 0; i < mem->nregions; i++) {
259 : : region = &mem->regions[i];
260 : :
261 [ # # ]: 0 : if (qva >= region->host_user_addr &&
262 [ # # ]: 0 : qva < region->host_user_addr + region->size) {
263 : 0 : gpa = qva - region->host_user_addr + region->guest_phys_addr;
264 : 0 : break;
265 : : }
266 : : }
267 : :
268 : 0 : free(mem);
269 : :
270 : 0 : return gpa;
271 : : }
272 : :
273 : : static void
274 : 0 : nfp_vdpa_relay_vring_free(struct nfp_vdpa_dev *device,
275 : : uint16_t vring_index)
276 : : {
277 : : uint16_t i;
278 : : uint64_t size;
279 : : struct rte_vhost_vring vring;
280 : : uint64_t m_vring_iova = NFP_VDPA_RELAY_VRING;
281 : :
282 [ # # ]: 0 : for (i = 0; i < vring_index; i++) {
283 : 0 : rte_vhost_get_vhost_vring(device->vid, i, &vring);
284 : :
285 : 0 : size = RTE_ALIGN_CEIL(vring_size(vring.size, rte_mem_page_size()),
286 : : rte_mem_page_size());
287 : 0 : rte_vfio_container_dma_unmap(device->vfio_container_fd,
288 : 0 : (uint64_t)(uintptr_t)device->hw.m_vring[i].desc,
289 : : m_vring_iova, size);
290 : :
291 : 0 : rte_free(device->hw.m_vring[i].desc);
292 : 0 : m_vring_iova += size;
293 : : }
294 : 0 : }
295 : :
296 : : static int
297 : 0 : nfp_vdpa_relay_vring_alloc(struct nfp_vdpa_dev *device)
298 : : {
299 : : int ret;
300 : : uint16_t i;
301 : : uint64_t size;
302 : : void *vring_buf;
303 : : uint64_t page_size;
304 : : struct rte_vhost_vring vring;
305 : : struct nfp_vdpa_hw *vdpa_hw = &device->hw;
306 : : uint64_t m_vring_iova = NFP_VDPA_RELAY_VRING;
307 : :
308 : 0 : page_size = rte_mem_page_size();
309 : :
310 [ # # ]: 0 : for (i = 0; i < vdpa_hw->nr_vring; i++) {
311 : 0 : rte_vhost_get_vhost_vring(device->vid, i, &vring);
312 : :
313 : 0 : size = RTE_ALIGN_CEIL(vring_size(vring.size, page_size), page_size);
314 : 0 : vring_buf = rte_zmalloc("nfp_vdpa_relay", size, page_size);
315 [ # # ]: 0 : if (vring_buf == NULL)
316 : 0 : goto vring_free_all;
317 : :
318 : 0 : vring_init(&vdpa_hw->m_vring[i], vring.size, vring_buf, page_size);
319 : :
320 : 0 : ret = rte_vfio_container_dma_map(device->vfio_container_fd,
321 : : (uint64_t)(uintptr_t)vring_buf, m_vring_iova, size);
322 [ # # ]: 0 : if (ret != 0) {
323 : 0 : DRV_VDPA_LOG(ERR, "vDPA vring relay dma map failed.");
324 : 0 : goto vring_free_one;
325 : : }
326 : :
327 : 0 : m_vring_iova += size;
328 : : }
329 : :
330 : : return 0;
331 : :
332 : : vring_free_one:
333 : 0 : rte_free(device->hw.m_vring[i].desc);
334 : 0 : vring_free_all:
335 : 0 : nfp_vdpa_relay_vring_free(device, i);
336 : :
337 : 0 : return -ENOSPC;
338 : : }
339 : :
340 : : static int
341 : 0 : nfp_vdpa_start(struct nfp_vdpa_dev *device,
342 : : bool relay)
343 : : {
344 : : int ret;
345 : : int vid;
346 : : uint16_t i;
347 : : uint64_t gpa;
348 : : uint16_t size;
349 : : struct rte_vhost_vring vring;
350 : 0 : struct nfp_vdpa_hw *vdpa_hw = &device->hw;
351 : : uint64_t m_vring_iova = NFP_VDPA_RELAY_VRING;
352 : :
353 : 0 : vid = device->vid;
354 : 0 : vdpa_hw->nr_vring = rte_vhost_get_vring_num(vid);
355 : :
356 : 0 : ret = rte_vhost_get_negotiated_features(vid, &vdpa_hw->req_features);
357 [ # # ]: 0 : if (ret != 0)
358 : : return ret;
359 : :
360 [ # # ]: 0 : if (relay) {
361 : 0 : ret = nfp_vdpa_relay_vring_alloc(device);
362 [ # # ]: 0 : if (ret != 0)
363 : : return ret;
364 : : }
365 : :
366 [ # # ]: 0 : for (i = 0; i < vdpa_hw->nr_vring; i++) {
367 : 0 : ret = rte_vhost_get_vhost_vring(vid, i, &vring);
368 [ # # ]: 0 : if (ret != 0)
369 : 0 : goto relay_vring_free;
370 : :
371 : 0 : gpa = nfp_vdpa_qva_to_gpa(vid, (uint64_t)(uintptr_t)vring.desc);
372 [ # # ]: 0 : if (gpa == 0) {
373 : 0 : DRV_VDPA_LOG(ERR, "Fail to get GPA for descriptor ring.");
374 : 0 : goto relay_vring_free;
375 : : }
376 : :
377 : 0 : vdpa_hw->vring[i].desc = gpa;
378 : :
379 : 0 : gpa = nfp_vdpa_qva_to_gpa(vid, (uint64_t)(uintptr_t)vring.avail);
380 [ # # ]: 0 : if (gpa == 0) {
381 : 0 : DRV_VDPA_LOG(ERR, "Fail to get GPA for available ring.");
382 : 0 : goto relay_vring_free;
383 : : }
384 : :
385 : 0 : vdpa_hw->vring[i].avail = gpa;
386 : :
387 : : /* Direct I/O for Tx queue, relay for Rx queue */
388 [ # # # # ]: 0 : if (relay && ((i & 1) == 0)) {
389 : 0 : vdpa_hw->vring[i].used = m_vring_iova +
390 : 0 : (char *)vdpa_hw->m_vring[i].used -
391 : 0 : (char *)vdpa_hw->m_vring[i].desc;
392 : :
393 : 0 : ret = rte_vhost_get_vring_base(vid, i,
394 : 0 : &vdpa_hw->m_vring[i].avail->idx,
395 : 0 : &vdpa_hw->m_vring[i].used->idx);
396 [ # # ]: 0 : if (ret != 0)
397 : 0 : goto relay_vring_free;
398 : : } else {
399 : 0 : gpa = nfp_vdpa_qva_to_gpa(vid, (uint64_t)(uintptr_t)vring.used);
400 [ # # ]: 0 : if (gpa == 0) {
401 : 0 : DRV_VDPA_LOG(ERR, "Fail to get GPA for used ring.");
402 : 0 : goto relay_vring_free;
403 : : }
404 : :
405 : 0 : vdpa_hw->vring[i].used = gpa;
406 : : }
407 : :
408 : 0 : vdpa_hw->vring[i].size = vring.size;
409 : :
410 [ # # ]: 0 : if (relay) {
411 : 0 : size = RTE_ALIGN_CEIL(vring_size(vring.size,
412 : : rte_mem_page_size()), rte_mem_page_size());
413 : 0 : m_vring_iova += size;
414 : : }
415 : :
416 : 0 : ret = rte_vhost_get_vring_base(vid, i,
417 : : &vdpa_hw->vring[i].last_avail_idx,
418 : : &vdpa_hw->vring[i].last_used_idx);
419 [ # # ]: 0 : if (ret != 0)
420 : 0 : goto relay_vring_free;
421 : : }
422 : :
423 [ # # ]: 0 : if (relay)
424 : 0 : return nfp_vdpa_relay_hw_start(&device->hw, vid);
425 : : else
426 : 0 : return nfp_vdpa_hw_start(&device->hw, vid);
427 : :
428 : 0 : relay_vring_free:
429 [ # # ]: 0 : if (relay)
430 : 0 : nfp_vdpa_relay_vring_free(device, vdpa_hw->nr_vring);
431 : :
432 : : return -EFAULT;
433 : : }
434 : :
435 : : static void
436 : 0 : nfp_vdpa_update_used_ring(struct nfp_vdpa_dev *dev,
437 : : uint16_t qid)
438 : : {
439 : 0 : rte_vdpa_relay_vring_used(dev->vid, qid, &dev->hw.m_vring[qid]);
440 : 0 : rte_vhost_vring_call(dev->vid, qid);
441 : 0 : }
442 : :
443 : : static void
444 : 0 : nfp_vdpa_relay_stop(struct nfp_vdpa_dev *device)
445 : : {
446 : : int vid;
447 : : uint32_t i;
448 : : uint64_t len;
449 : : struct rte_vhost_vring vring;
450 : 0 : struct nfp_vdpa_hw *vdpa_hw = &device->hw;
451 : :
452 : 0 : nfp_vdpa_hw_stop(vdpa_hw);
453 : :
454 : 0 : vid = device->vid;
455 [ # # ]: 0 : for (i = 0; i < vdpa_hw->nr_vring; i++) {
456 : : /* Synchronize remaining new used entries if any */
457 [ # # ]: 0 : if ((i & 1) == 0)
458 : 0 : nfp_vdpa_update_used_ring(device, i);
459 : :
460 : 0 : rte_vhost_get_vhost_vring(vid, i, &vring);
461 : 0 : len = NFP_VDPA_USED_RING_LEN(vring.size);
462 : 0 : vdpa_hw->vring[i].last_avail_idx = vring.avail->idx;
463 : 0 : vdpa_hw->vring[i].last_used_idx = vring.used->idx;
464 : :
465 : 0 : rte_vhost_set_vring_base(vid, i,
466 : : vdpa_hw->vring[i].last_avail_idx,
467 : : vdpa_hw->vring[i].last_used_idx);
468 : :
469 : 0 : rte_vhost_log_used_vring(vid, i, 0, len);
470 : :
471 [ # # ]: 0 : if (vring.used->idx != vring.avail->idx)
472 : 0 : rte_atomic_store_explicit(
473 : : (unsigned short __rte_atomic *)&vring.used->idx,
474 : : vring.avail->idx, rte_memory_order_release);
475 : : }
476 : :
477 : 0 : nfp_vdpa_relay_vring_free(device, vdpa_hw->nr_vring);
478 : 0 : }
479 : :
480 : : static void
481 : 0 : nfp_vdpa_stop(struct nfp_vdpa_dev *device,
482 : : bool relay)
483 : : {
484 : : int vid;
485 : : uint32_t i;
486 : 0 : struct nfp_vdpa_hw *vdpa_hw = &device->hw;
487 : :
488 : 0 : nfp_vdpa_hw_stop(vdpa_hw);
489 : :
490 : 0 : vid = device->vid;
491 [ # # ]: 0 : if (relay)
492 : 0 : nfp_vdpa_relay_stop(device);
493 : : else
494 [ # # ]: 0 : for (i = 0; i < vdpa_hw->nr_vring; i++)
495 : 0 : rte_vhost_set_vring_base(vid, i,
496 : 0 : vdpa_hw->vring[i].last_avail_idx,
497 : 0 : vdpa_hw->vring[i].last_used_idx);
498 : :
499 : 0 : }
500 : :
501 : : static int
502 : 0 : nfp_vdpa_enable_vfio_intr(struct nfp_vdpa_dev *device,
503 : : bool relay)
504 : : {
505 : : int fd;
506 : : int ret;
507 : : uint16_t i;
508 : : int *fd_ptr;
509 : : uint16_t nr_vring;
510 : : struct vfio_irq_set *irq_set;
511 : : struct rte_vhost_vring vring;
512 : : char irq_set_buf[MSIX_IRQ_SET_BUF_LEN];
513 : :
514 : 0 : nr_vring = rte_vhost_get_vring_num(device->vid);
515 : :
516 : : irq_set = (struct vfio_irq_set *)irq_set_buf;
517 : 0 : irq_set->argsz = sizeof(irq_set_buf);
518 : 0 : irq_set->count = nr_vring + 1;
519 : 0 : irq_set->flags = VFIO_IRQ_SET_DATA_EVENTFD | VFIO_IRQ_SET_ACTION_TRIGGER;
520 : 0 : irq_set->index = VFIO_PCI_MSIX_IRQ_INDEX;
521 : 0 : irq_set->start = 0;
522 : :
523 : : fd_ptr = (int *)&irq_set->data;
524 : 0 : fd_ptr[RTE_INTR_VEC_ZERO_OFFSET] = rte_intr_fd_get(device->pci_dev->intr_handle);
525 : :
526 [ # # ]: 0 : for (i = 0; i < nr_vring; i++)
527 : 0 : device->intr_fd[i] = -1;
528 : :
529 [ # # ]: 0 : for (i = 0; i < nr_vring; i++) {
530 : 0 : rte_vhost_get_vhost_vring(device->vid, i, &vring);
531 : 0 : fd_ptr[RTE_INTR_VEC_RXTX_OFFSET + i] = vring.callfd;
532 : : }
533 : :
534 [ # # ]: 0 : if (relay) {
535 [ # # ]: 0 : for (i = 0; i < nr_vring; i += 2) {
536 : 0 : fd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
537 [ # # ]: 0 : if (fd < 0) {
538 : 0 : DRV_VDPA_LOG(ERR, "Can't setup eventfd.");
539 : 0 : return -EINVAL;
540 : : }
541 : :
542 : 0 : device->intr_fd[i] = fd;
543 : 0 : fd_ptr[RTE_INTR_VEC_RXTX_OFFSET + i] = fd;
544 : : }
545 : : }
546 : :
547 : 0 : ret = ioctl(device->vfio_dev_fd, VFIO_DEVICE_SET_IRQS, irq_set);
548 [ # # ]: 0 : if (ret != 0) {
549 : 0 : DRV_VDPA_LOG(ERR, "Error enabling MSI-X interrupts.");
550 : 0 : return -EIO;
551 : : }
552 : :
553 : : return 0;
554 : : }
555 : :
556 : : static int
557 : 0 : nfp_vdpa_disable_vfio_intr(struct nfp_vdpa_dev *device)
558 : : {
559 : : int ret;
560 : : struct vfio_irq_set *irq_set;
561 : : char irq_set_buf[MSIX_IRQ_SET_BUF_LEN];
562 : :
563 : : irq_set = (struct vfio_irq_set *)irq_set_buf;
564 : 0 : irq_set->argsz = sizeof(irq_set_buf);
565 : 0 : irq_set->count = 0;
566 : 0 : irq_set->flags = VFIO_IRQ_SET_DATA_NONE | VFIO_IRQ_SET_ACTION_TRIGGER;
567 : 0 : irq_set->index = VFIO_PCI_MSIX_IRQ_INDEX;
568 : 0 : irq_set->start = 0;
569 : :
570 : 0 : ret = ioctl(device->vfio_dev_fd, VFIO_DEVICE_SET_IRQS, irq_set);
571 [ # # ]: 0 : if (ret != 0) {
572 : 0 : DRV_VDPA_LOG(ERR, "Error disabling MSI-X interrupts.");
573 : 0 : return -EIO;
574 : : }
575 : :
576 : : return 0;
577 : : }
578 : :
579 : : static void
580 : 0 : nfp_vdpa_read_kickfd(int kickfd)
581 : : {
582 : : int bytes;
583 : : uint64_t buf;
584 : :
585 : : for (;;) {
586 : 0 : bytes = read(kickfd, &buf, 8);
587 [ # # ]: 0 : if (bytes >= 0)
588 : : break;
589 : :
590 [ # # ]: 0 : if (errno != EINTR && errno != EWOULDBLOCK &&
591 : : errno != EAGAIN) {
592 : 0 : DRV_VDPA_LOG(ERR, "Error reading kickfd.");
593 : 0 : break;
594 : : }
595 : : }
596 : 0 : }
597 : :
598 : : static int
599 : 0 : nfp_vdpa_notify_epoll_ctl(uint32_t queue_num,
600 : : struct nfp_vdpa_dev *device)
601 : : {
602 : : int ret;
603 : : uint32_t qid;
604 : :
605 [ # # ]: 0 : for (qid = 0; qid < queue_num; qid++) {
606 : : struct epoll_event ev;
607 : : struct rte_vhost_vring vring;
608 : :
609 : 0 : ev.events = EPOLLIN | EPOLLPRI;
610 : 0 : rte_vhost_get_vhost_vring(device->vid, qid, &vring);
611 : 0 : ev.data.u64 = qid | (uint64_t)vring.kickfd << 32;
612 : 0 : ret = epoll_ctl(device->epoll_fd, EPOLL_CTL_ADD, vring.kickfd, &ev);
613 [ # # ]: 0 : if (ret < 0) {
614 : 0 : DRV_VDPA_LOG(ERR, "Epoll add error for queue %d.", qid);
615 : 0 : return ret;
616 : : }
617 : : }
618 : :
619 : : return 0;
620 : : }
621 : :
622 : : static int
623 : 0 : nfp_vdpa_notify_epoll_wait(uint32_t queue_num,
624 : : struct nfp_vdpa_dev *device)
625 : : {
626 : : int i;
627 : : int fds;
628 : : int kickfd;
629 : : uint32_t qid;
630 : : struct epoll_event events[NFP_VDPA_MAX_QUEUES * 2];
631 : :
632 : : for (;;) {
633 : 0 : fds = epoll_wait(device->epoll_fd, events, queue_num, -1);
634 [ # # ]: 0 : if (fds < 0) {
635 [ # # ]: 0 : if (errno == EINTR)
636 : 0 : continue;
637 : :
638 : 0 : DRV_VDPA_LOG(ERR, "Epoll wait fail.");
639 : : return -EACCES;
640 : : }
641 : :
642 : 0 : for (i = 0; i < fds; i++) {
643 : 0 : qid = events[i].data.u32;
644 : 0 : kickfd = (uint32_t)(events[i].data.u64 >> 32);
645 : :
646 : 0 : nfp_vdpa_read_kickfd(kickfd);
647 : 0 : nfp_vdpa_notify_queue(&device->hw, qid);
648 : : }
649 : : }
650 : :
651 : : return 0;
652 : : }
653 : :
654 : : static uint32_t
655 : 0 : nfp_vdpa_notify_relay(void *arg)
656 : : {
657 : : int ret;
658 : : int epoll_fd;
659 : : uint32_t queue_num;
660 : : struct nfp_vdpa_dev *device = arg;
661 : :
662 : 0 : epoll_fd = epoll_create(NFP_VDPA_MAX_QUEUES * 2);
663 [ # # ]: 0 : if (epoll_fd < 0) {
664 : 0 : DRV_VDPA_LOG(ERR, "Failed to create epoll instance.");
665 : 0 : return 1;
666 : : }
667 : :
668 : 0 : device->epoll_fd = epoll_fd;
669 : :
670 : 0 : queue_num = rte_vhost_get_vring_num(device->vid);
671 : :
672 : 0 : ret = nfp_vdpa_notify_epoll_ctl(queue_num, device);
673 [ # # ]: 0 : if (ret != 0)
674 : 0 : goto notify_exit;
675 : :
676 : 0 : ret = nfp_vdpa_notify_epoll_wait(queue_num, device);
677 [ # # ]: 0 : if (ret != 0)
678 : 0 : goto notify_exit;
679 : :
680 : : return 0;
681 : :
682 : 0 : notify_exit:
683 : 0 : close(device->epoll_fd);
684 : 0 : device->epoll_fd = -1;
685 : :
686 : 0 : return 1;
687 : : }
688 : :
689 : : static int
690 : 0 : nfp_vdpa_setup_notify_relay(struct nfp_vdpa_dev *device)
691 : : {
692 : : int ret;
693 : : char name[RTE_THREAD_INTERNAL_NAME_SIZE];
694 : :
695 : 0 : snprintf(name, sizeof(name), "nfp-noti%d", device->vid);
696 : 0 : ret = rte_thread_create_internal_control(&device->tid, name,
697 : : nfp_vdpa_notify_relay, (void *)device);
698 [ # # ]: 0 : if (ret != 0) {
699 : 0 : DRV_VDPA_LOG(ERR, "Failed to create notify relay pthread.");
700 : 0 : return -1;
701 : : }
702 : :
703 : : return 0;
704 : : }
705 : :
706 : : static void
707 : 0 : nfp_vdpa_unset_notify_relay(struct nfp_vdpa_dev *device)
708 : : {
709 [ # # ]: 0 : if (device->tid.opaque_id != 0) {
710 : 0 : pthread_cancel((pthread_t)device->tid.opaque_id);
711 : 0 : rte_thread_join(device->tid, NULL);
712 : 0 : device->tid.opaque_id = 0;
713 : : }
714 : :
715 [ # # ]: 0 : if (device->epoll_fd >= 0) {
716 : 0 : close(device->epoll_fd);
717 : 0 : device->epoll_fd = -1;
718 : : }
719 : 0 : }
720 : :
721 : : static int
722 : 0 : update_datapath(struct nfp_vdpa_dev *device)
723 : : {
724 : : int ret;
725 : :
726 : 0 : rte_spinlock_lock(&device->lock);
727 : :
728 [ # # ]: 0 : if ((rte_atomic_load_explicit(&device->running, rte_memory_order_relaxed) == 0) &&
729 [ # # ]: 0 : (rte_atomic_load_explicit(&device->started,
730 : 0 : rte_memory_order_relaxed) != 0) &&
731 [ # # ]: 0 : (rte_atomic_load_explicit(&device->dev_attached,
732 : : rte_memory_order_relaxed) != 0)) {
733 : 0 : ret = nfp_vdpa_dma_map(device, true);
734 [ # # ]: 0 : if (ret != 0)
735 : 0 : goto unlock_exit;
736 : :
737 : 0 : ret = nfp_vdpa_enable_vfio_intr(device, false);
738 [ # # ]: 0 : if (ret != 0)
739 : 0 : goto dma_map_rollback;
740 : :
741 : 0 : ret = nfp_vdpa_start(device, false);
742 [ # # ]: 0 : if (ret != 0)
743 : 0 : goto disable_vfio_intr;
744 : :
745 : 0 : ret = nfp_vdpa_setup_notify_relay(device);
746 [ # # ]: 0 : if (ret != 0)
747 : 0 : goto vdpa_stop;
748 : :
749 : 0 : rte_atomic_store_explicit(&device->running, 1, rte_memory_order_relaxed);
750 [ # # ]: 0 : } else if ((rte_atomic_load_explicit(&device->running, rte_memory_order_relaxed) != 0) &&
751 [ # # ]: 0 : ((rte_atomic_load_explicit(&device->started,
752 : 0 : rte_memory_order_relaxed) != 0) ||
753 [ # # ]: 0 : (rte_atomic_load_explicit(&device->dev_attached,
754 : : rte_memory_order_relaxed) != 0))) {
755 : 0 : nfp_vdpa_unset_notify_relay(device);
756 : :
757 : 0 : nfp_vdpa_stop(device, false);
758 : :
759 : 0 : ret = nfp_vdpa_disable_vfio_intr(device);
760 [ # # ]: 0 : if (ret != 0)
761 : 0 : goto unlock_exit;
762 : :
763 : 0 : ret = nfp_vdpa_dma_map(device, false);
764 [ # # ]: 0 : if (ret != 0)
765 : 0 : goto unlock_exit;
766 : :
767 : 0 : rte_atomic_store_explicit(&device->running, 0, rte_memory_order_relaxed);
768 : : }
769 : :
770 : : rte_spinlock_unlock(&device->lock);
771 : 0 : return 0;
772 : :
773 : : vdpa_stop:
774 : 0 : nfp_vdpa_stop(device, false);
775 : 0 : disable_vfio_intr:
776 : 0 : nfp_vdpa_disable_vfio_intr(device);
777 : 0 : dma_map_rollback:
778 : 0 : nfp_vdpa_dma_map(device, false);
779 : 0 : unlock_exit:
780 : : rte_spinlock_unlock(&device->lock);
781 : 0 : return ret;
782 : : }
783 : :
784 : : static int
785 : 0 : nfp_vdpa_vring_epoll_ctl(uint32_t queue_num,
786 : : struct nfp_vdpa_dev *device)
787 : : {
788 : : int ret;
789 : : uint32_t qid;
790 : : struct epoll_event ev;
791 : : struct rte_vhost_vring vring;
792 : :
793 [ # # ]: 0 : for (qid = 0; qid < queue_num; qid++) {
794 : 0 : ev.events = EPOLLIN | EPOLLPRI;
795 : 0 : rte_vhost_get_vhost_vring(device->vid, qid, &vring);
796 : 0 : ev.data.u64 = qid << 1 | (uint64_t)vring.kickfd << 32;
797 : 0 : ret = epoll_ctl(device->epoll_fd, EPOLL_CTL_ADD, vring.kickfd, &ev);
798 [ # # ]: 0 : if (ret < 0) {
799 : 0 : DRV_VDPA_LOG(ERR, "Epoll add error for queue %u.", qid);
800 : 0 : return ret;
801 : : }
802 : : }
803 : :
804 : : /* vDPA driver interrupt */
805 [ # # ]: 0 : for (qid = 0; qid < queue_num; qid += 2) {
806 : 0 : ev.events = EPOLLIN | EPOLLPRI;
807 : : /* Leave a flag to mark it's for interrupt */
808 : 0 : ev.data.u64 = EPOLL_DATA_INTR | qid << 1 |
809 : 0 : (uint64_t)device->intr_fd[qid] << 32;
810 : 0 : ret = epoll_ctl(device->epoll_fd, EPOLL_CTL_ADD,
811 : : device->intr_fd[qid], &ev);
812 [ # # ]: 0 : if (ret < 0) {
813 : 0 : DRV_VDPA_LOG(ERR, "Epoll add error for queue %u.", qid);
814 : 0 : return ret;
815 : : }
816 : :
817 : 0 : nfp_vdpa_update_used_ring(device, qid);
818 : : }
819 : :
820 : : return 0;
821 : : }
822 : :
823 : : static int
824 : 0 : nfp_vdpa_vring_epoll_wait(uint32_t queue_num,
825 : : struct nfp_vdpa_dev *device)
826 : : {
827 : : int i;
828 : : int fds;
829 : : int kickfd;
830 : : uint32_t qid;
831 : : struct epoll_event events[NFP_VDPA_MAX_QUEUES * 2];
832 : :
833 : : for (;;) {
834 : 0 : fds = epoll_wait(device->epoll_fd, events, queue_num * 2, -1);
835 [ # # ]: 0 : if (fds < 0) {
836 [ # # ]: 0 : if (errno == EINTR)
837 : 0 : continue;
838 : :
839 : 0 : DRV_VDPA_LOG(ERR, "Epoll wait fail.");
840 : : return -EACCES;
841 : : }
842 : :
843 : 0 : for (i = 0; i < fds; i++) {
844 : 0 : qid = events[i].data.u32 >> 1;
845 : 0 : kickfd = (uint32_t)(events[i].data.u64 >> 32);
846 : :
847 : 0 : nfp_vdpa_read_kickfd(kickfd);
848 [ # # ]: 0 : if ((events[i].data.u32 & EPOLL_DATA_INTR) != 0) {
849 : 0 : nfp_vdpa_update_used_ring(device, qid);
850 : 0 : nfp_vdpa_irq_unmask(&device->hw);
851 : : } else {
852 : 0 : nfp_vdpa_notify_queue(&device->hw, qid);
853 : : }
854 : : }
855 : : }
856 : :
857 : : return 0;
858 : : }
859 : :
860 : : static uint32_t
861 : 0 : nfp_vdpa_vring_relay(void *arg)
862 : : {
863 : : int ret;
864 : : int epoll_fd;
865 : : uint16_t queue_id;
866 : : uint32_t queue_num;
867 : : struct nfp_vdpa_dev *device = arg;
868 : :
869 : 0 : epoll_fd = epoll_create(NFP_VDPA_MAX_QUEUES * 2);
870 [ # # ]: 0 : if (epoll_fd < 0) {
871 : 0 : DRV_VDPA_LOG(ERR, "failed to create epoll instance.");
872 : 0 : return 1;
873 : : }
874 : :
875 : 0 : device->epoll_fd = epoll_fd;
876 : :
877 : 0 : queue_num = rte_vhost_get_vring_num(device->vid);
878 : :
879 : 0 : ret = nfp_vdpa_vring_epoll_ctl(queue_num, device);
880 [ # # ]: 0 : if (ret != 0)
881 : 0 : goto notify_exit;
882 : :
883 : : /* Start relay with a first kick */
884 [ # # ]: 0 : for (queue_id = 0; queue_id < queue_num; queue_id++)
885 : 0 : nfp_vdpa_notify_queue(&device->hw, queue_id);
886 : :
887 : 0 : ret = nfp_vdpa_vring_epoll_wait(queue_num, device);
888 [ # # ]: 0 : if (ret != 0)
889 : 0 : goto notify_exit;
890 : :
891 : : return 0;
892 : :
893 : 0 : notify_exit:
894 : 0 : close(device->epoll_fd);
895 : 0 : device->epoll_fd = -1;
896 : :
897 : 0 : return 1;
898 : : }
899 : :
900 : : static int
901 : 0 : nfp_vdpa_setup_vring_relay(struct nfp_vdpa_dev *device)
902 : : {
903 : : int ret;
904 : : char name[RTE_THREAD_INTERNAL_NAME_SIZE];
905 : :
906 : 0 : snprintf(name, sizeof(name), "nfp_vring%d", device->vid);
907 : 0 : ret = rte_thread_create_internal_control(&device->tid, name,
908 : : nfp_vdpa_vring_relay, (void *)device);
909 [ # # ]: 0 : if (ret != 0) {
910 : 0 : DRV_VDPA_LOG(ERR, "Failed to create vring relay pthread.");
911 : 0 : return -EPERM;
912 : : }
913 : :
914 : : return 0;
915 : : }
916 : :
917 : : static int
918 : 0 : nfp_vdpa_sw_fallback(struct nfp_vdpa_dev *device)
919 : : {
920 : : int ret;
921 : 0 : int vid = device->vid;
922 : :
923 : : /* Stop the direct IO data path */
924 : 0 : nfp_vdpa_unset_notify_relay(device);
925 : 0 : nfp_vdpa_disable_vfio_intr(device);
926 : :
927 : 0 : ret = rte_vhost_host_notifier_ctrl(vid, RTE_VHOST_QUEUE_ALL, false);
928 [ # # ]: 0 : if ((ret != 0) && (ret != -ENOTSUP)) {
929 : 0 : DRV_VDPA_LOG(ERR, "Unset the host notifier failed.");
930 : 0 : goto error;
931 : : }
932 : :
933 : : /* Setup interrupt for vring relay */
934 : 0 : ret = nfp_vdpa_enable_vfio_intr(device, true);
935 [ # # ]: 0 : if (ret != 0)
936 : 0 : goto error;
937 : :
938 : : /* Config the VF */
939 : 0 : ret = nfp_vdpa_start(device, true);
940 [ # # ]: 0 : if (ret != 0)
941 : 0 : goto unset_intr;
942 : :
943 : : /* Setup vring relay thread */
944 : 0 : ret = nfp_vdpa_setup_vring_relay(device);
945 [ # # ]: 0 : if (ret != 0)
946 : 0 : goto stop_vf;
947 : :
948 : 0 : device->hw.sw_fallback_running = true;
949 : :
950 : 0 : return 0;
951 : :
952 : : stop_vf:
953 : 0 : nfp_vdpa_stop(device, true);
954 : 0 : unset_intr:
955 : 0 : nfp_vdpa_disable_vfio_intr(device);
956 : : error:
957 : : return ret;
958 : : }
959 : :
960 : : static int
961 : 0 : nfp_vdpa_dev_config(int vid)
962 : : {
963 : : int ret;
964 : : struct nfp_vdpa_dev *device;
965 : : struct rte_vdpa_device *vdev;
966 : : struct nfp_vdpa_dev_node *node;
967 : :
968 : 0 : vdev = rte_vhost_get_vdpa_device(vid);
969 : 0 : node = nfp_vdpa_find_node_by_vdev(vdev);
970 [ # # ]: 0 : if (node == NULL) {
971 : 0 : DRV_VDPA_LOG(ERR, "Invalid vDPA device: %p.", vdev);
972 : 0 : return -ENODEV;
973 : : }
974 : :
975 : 0 : device = node->device;
976 : 0 : device->vid = vid;
977 : 0 : rte_atomic_store_explicit(&device->dev_attached, 1, rte_memory_order_relaxed);
978 : 0 : update_datapath(device);
979 : :
980 : 0 : ret = rte_vhost_host_notifier_ctrl(vid, RTE_VHOST_QUEUE_ALL, true);
981 [ # # ]: 0 : if (ret != 0)
982 : 0 : DRV_VDPA_LOG(INFO, "vDPA (%s): software relay is used.",
983 : : vdev->device->name);
984 : :
985 : : return 0;
986 : : }
987 : :
988 : : static int
989 : 0 : nfp_vdpa_dev_close(int vid)
990 : : {
991 : : struct nfp_vdpa_dev *device;
992 : : struct rte_vdpa_device *vdev;
993 : : struct nfp_vdpa_dev_node *node;
994 : :
995 : 0 : vdev = rte_vhost_get_vdpa_device(vid);
996 : 0 : node = nfp_vdpa_find_node_by_vdev(vdev);
997 [ # # ]: 0 : if (node == NULL) {
998 : 0 : DRV_VDPA_LOG(ERR, "Invalid vDPA device: %p.", vdev);
999 : 0 : return -ENODEV;
1000 : : }
1001 : :
1002 : 0 : device = node->device;
1003 [ # # ]: 0 : if (device->hw.sw_fallback_running) {
1004 : : /* Reset VF */
1005 : 0 : nfp_vdpa_stop(device, true);
1006 : :
1007 : : /* Remove interrupt setting */
1008 : 0 : nfp_vdpa_disable_vfio_intr(device);
1009 : :
1010 : : /* Unset DMA map for guest memory */
1011 : 0 : nfp_vdpa_dma_map(device, false);
1012 : :
1013 : 0 : device->hw.sw_fallback_running = false;
1014 : :
1015 : 0 : rte_atomic_store_explicit(&device->dev_attached, 0,
1016 : : rte_memory_order_relaxed);
1017 : 0 : rte_atomic_store_explicit(&device->running, 0,
1018 : : rte_memory_order_relaxed);
1019 : : } else {
1020 : 0 : rte_atomic_store_explicit(&device->dev_attached, 0,
1021 : : rte_memory_order_relaxed);
1022 : 0 : update_datapath(device);
1023 : : }
1024 : :
1025 : : return 0;
1026 : : }
1027 : :
1028 : : static int
1029 : 0 : nfp_vdpa_get_vfio_group_fd(int vid)
1030 : : {
1031 : : struct rte_vdpa_device *vdev;
1032 : : struct nfp_vdpa_dev_node *node;
1033 : :
1034 : 0 : vdev = rte_vhost_get_vdpa_device(vid);
1035 : 0 : node = nfp_vdpa_find_node_by_vdev(vdev);
1036 [ # # ]: 0 : if (node == NULL) {
1037 : 0 : DRV_VDPA_LOG(ERR, "Invalid vDPA device: %p.", vdev);
1038 : 0 : return -ENODEV;
1039 : : }
1040 : :
1041 : 0 : return node->device->vfio_group_fd;
1042 : : }
1043 : :
1044 : : static int
1045 : 0 : nfp_vdpa_get_vfio_device_fd(int vid)
1046 : : {
1047 : : struct rte_vdpa_device *vdev;
1048 : : struct nfp_vdpa_dev_node *node;
1049 : :
1050 : 0 : vdev = rte_vhost_get_vdpa_device(vid);
1051 : 0 : node = nfp_vdpa_find_node_by_vdev(vdev);
1052 [ # # ]: 0 : if (node == NULL) {
1053 : 0 : DRV_VDPA_LOG(ERR, "Invalid vDPA device: %p.", vdev);
1054 : 0 : return -ENODEV;
1055 : : }
1056 : :
1057 : 0 : return node->device->vfio_dev_fd;
1058 : : }
1059 : :
1060 : : static int
1061 : 0 : nfp_vdpa_get_notify_area(int vid,
1062 : : int qid,
1063 : : uint64_t *offset,
1064 : : uint64_t *size)
1065 : : {
1066 : : int ret;
1067 : : struct nfp_vdpa_dev *device;
1068 : : struct rte_vdpa_device *vdev;
1069 : : struct nfp_vdpa_dev_node *node;
1070 : 0 : struct vfio_region_info region = {
1071 : : .argsz = sizeof(region)
1072 : : };
1073 : :
1074 : 0 : vdev = rte_vhost_get_vdpa_device(vid);
1075 : 0 : node = nfp_vdpa_find_node_by_vdev(vdev);
1076 [ # # ]: 0 : if (node == NULL) {
1077 : 0 : DRV_VDPA_LOG(ERR, "Invalid vDPA device: %p", vdev);
1078 : 0 : return -ENODEV;
1079 : : }
1080 : :
1081 : 0 : device = node->device;
1082 : 0 : region.index = device->hw.notify_region;
1083 : :
1084 : 0 : ret = ioctl(device->vfio_dev_fd, VFIO_DEVICE_GET_REGION_INFO, ®ion);
1085 [ # # ]: 0 : if (ret != 0) {
1086 : 0 : DRV_VDPA_LOG(ERR, "Get not get device region info.");
1087 : 0 : return -EIO;
1088 : : }
1089 : :
1090 : 0 : *offset = nfp_vdpa_get_queue_notify_offset(&device->hw, qid) + region.offset;
1091 : 0 : *size = NFP_VDPA_NOTIFY_ADDR_INTERVAL;
1092 : :
1093 : 0 : return 0;
1094 : : }
1095 : :
1096 : : static int
1097 : 0 : nfp_vdpa_get_queue_num(struct rte_vdpa_device *vdev,
1098 : : uint32_t *queue_num)
1099 : : {
1100 : : struct nfp_vdpa_dev_node *node;
1101 : :
1102 : 0 : node = nfp_vdpa_find_node_by_vdev(vdev);
1103 [ # # ]: 0 : if (node == NULL) {
1104 : 0 : DRV_VDPA_LOG(ERR, "Invalid vDPA device: %p.", vdev);
1105 : 0 : return -ENODEV;
1106 : : }
1107 : :
1108 : 0 : *queue_num = node->device->max_queues;
1109 : :
1110 : 0 : return 0;
1111 : : }
1112 : :
1113 : : static int
1114 : 0 : nfp_vdpa_get_vdpa_features(struct rte_vdpa_device *vdev,
1115 : : uint64_t *features)
1116 : : {
1117 : : struct nfp_vdpa_dev_node *node;
1118 : :
1119 : 0 : node = nfp_vdpa_find_node_by_vdev(vdev);
1120 [ # # ]: 0 : if (node == NULL) {
1121 : 0 : DRV_VDPA_LOG(ERR, "Invalid vDPA device: %p", vdev);
1122 : 0 : return -ENODEV;
1123 : : }
1124 : :
1125 : 0 : *features = node->device->hw.features;
1126 : :
1127 : 0 : return 0;
1128 : : }
1129 : :
1130 : : static int
1131 : 0 : nfp_vdpa_get_protocol_features(struct rte_vdpa_device *vdev __rte_unused,
1132 : : uint64_t *features)
1133 : : {
1134 : 0 : *features = 1ULL << VHOST_USER_PROTOCOL_F_LOG_SHMFD |
1135 : : 1ULL << VHOST_USER_PROTOCOL_F_REPLY_ACK |
1136 : : 1ULL << VHOST_USER_PROTOCOL_F_BACKEND_REQ |
1137 : : 1ULL << VHOST_USER_PROTOCOL_F_BACKEND_SEND_FD |
1138 : : 1ULL << VHOST_USER_PROTOCOL_F_HOST_NOTIFIER;
1139 : :
1140 : 0 : return 0;
1141 : : }
1142 : :
1143 : : static int
1144 : 0 : nfp_vdpa_set_features(int32_t vid)
1145 : : {
1146 : : int ret;
1147 : 0 : uint64_t features = 0;
1148 : : struct nfp_vdpa_dev *device;
1149 : : struct rte_vdpa_device *vdev;
1150 : : struct nfp_vdpa_dev_node *node;
1151 : :
1152 : 0 : DRV_VDPA_LOG(DEBUG, "Start vid=%d.", vid);
1153 : :
1154 : 0 : vdev = rte_vhost_get_vdpa_device(vid);
1155 : 0 : node = nfp_vdpa_find_node_by_vdev(vdev);
1156 [ # # ]: 0 : if (node == NULL) {
1157 : 0 : DRV_VDPA_LOG(ERR, "Invalid vDPA device: %p.", vdev);
1158 : 0 : return -ENODEV;
1159 : : }
1160 : :
1161 : 0 : rte_vhost_get_negotiated_features(vid, &features);
1162 : :
1163 [ # # ]: 0 : if (RTE_VHOST_NEED_LOG(features) == 0)
1164 : : return 0;
1165 : :
1166 : 0 : device = node->device;
1167 [ # # ]: 0 : if (device->hw.sw_lm) {
1168 : 0 : ret = nfp_vdpa_sw_fallback(device);
1169 [ # # ]: 0 : if (ret != 0) {
1170 : 0 : DRV_VDPA_LOG(ERR, "Software fallback start failed.");
1171 : 0 : return -1;
1172 : : }
1173 : : }
1174 : :
1175 : : return 0;
1176 : : }
1177 : :
1178 : : static int
1179 : 0 : nfp_vdpa_set_vring_state(int vid,
1180 : : int vring,
1181 : : int state)
1182 : : {
1183 : 0 : DRV_VDPA_LOG(DEBUG, "Start vid=%d, vring=%d, state=%d.", vid, vring, state);
1184 : 0 : return 0;
1185 : : }
1186 : :
1187 : : struct rte_vdpa_dev_ops nfp_vdpa_ops = {
1188 : : .get_queue_num = nfp_vdpa_get_queue_num,
1189 : : .get_features = nfp_vdpa_get_vdpa_features,
1190 : : .get_protocol_features = nfp_vdpa_get_protocol_features,
1191 : : .dev_conf = nfp_vdpa_dev_config,
1192 : : .dev_close = nfp_vdpa_dev_close,
1193 : : .set_vring_state = nfp_vdpa_set_vring_state,
1194 : : .set_features = nfp_vdpa_set_features,
1195 : : .get_vfio_group_fd = nfp_vdpa_get_vfio_group_fd,
1196 : : .get_vfio_device_fd = nfp_vdpa_get_vfio_device_fd,
1197 : : .get_notify_area = nfp_vdpa_get_notify_area,
1198 : : };
1199 : :
1200 : : static int
1201 : 0 : nfp_vdpa_pci_probe(struct rte_pci_device *pci_dev)
1202 : : {
1203 : : int ret;
1204 : : struct nfp_vdpa_dev *device;
1205 : : struct nfp_vdpa_dev_node *node;
1206 : :
1207 [ # # ]: 0 : if (rte_eal_process_type() != RTE_PROC_PRIMARY)
1208 : : return 0;
1209 : :
1210 : 0 : node = calloc(1, sizeof(*node));
1211 [ # # ]: 0 : if (node == NULL)
1212 : : return -ENOMEM;
1213 : :
1214 : 0 : device = calloc(1, sizeof(*device));
1215 [ # # ]: 0 : if (device == NULL)
1216 : 0 : goto free_node;
1217 : :
1218 : 0 : device->pci_dev = pci_dev;
1219 : :
1220 : 0 : ret = nfp_vdpa_vfio_setup(device);
1221 [ # # ]: 0 : if (ret != 0)
1222 : 0 : goto free_device;
1223 : :
1224 : 0 : ret = nfp_vdpa_hw_init(&device->hw, pci_dev);
1225 [ # # ]: 0 : if (ret != 0)
1226 : 0 : goto vfio_teardown;
1227 : :
1228 : 0 : device->max_queues = NFP_VDPA_MAX_QUEUES;
1229 : :
1230 : 0 : device->vdev = rte_vdpa_register_device(&pci_dev->device, &nfp_vdpa_ops);
1231 [ # # ]: 0 : if (device->vdev == NULL) {
1232 : 0 : DRV_VDPA_LOG(ERR, "Failed to register device %s.", pci_dev->name);
1233 : 0 : goto vfio_teardown;
1234 : : }
1235 : :
1236 : 0 : node->device = device;
1237 : 0 : pthread_mutex_lock(&vdpa_list_lock);
1238 : 0 : TAILQ_INSERT_TAIL(&vdpa_dev_list, node, next);
1239 : 0 : pthread_mutex_unlock(&vdpa_list_lock);
1240 : :
1241 : : rte_spinlock_init(&device->lock);
1242 : 0 : rte_atomic_store_explicit(&device->started, 1, rte_memory_order_relaxed);
1243 : 0 : update_datapath(device);
1244 : :
1245 : 0 : return 0;
1246 : :
1247 : 0 : vfio_teardown:
1248 : 0 : nfp_vdpa_vfio_teardown(device);
1249 : 0 : free_device:
1250 : 0 : free(device);
1251 : 0 : free_node:
1252 : 0 : free(node);
1253 : :
1254 : 0 : return -1;
1255 : : }
1256 : :
1257 : : static int
1258 : 0 : nfp_vdpa_pci_remove(struct rte_pci_device *pci_dev)
1259 : : {
1260 : : struct nfp_vdpa_dev *device;
1261 : : struct nfp_vdpa_dev_node *node;
1262 : :
1263 [ # # ]: 0 : if (rte_eal_process_type() != RTE_PROC_PRIMARY)
1264 : : return 0;
1265 : :
1266 : 0 : node = nfp_vdpa_find_node_by_pdev(pci_dev);
1267 [ # # ]: 0 : if (node == NULL) {
1268 : 0 : DRV_VDPA_LOG(ERR, "Invalid device: %s.", pci_dev->name);
1269 : 0 : return -ENODEV;
1270 : : }
1271 : :
1272 : 0 : device = node->device;
1273 : :
1274 : 0 : rte_atomic_store_explicit(&device->started, 0, rte_memory_order_relaxed);
1275 : 0 : update_datapath(device);
1276 : :
1277 : 0 : pthread_mutex_lock(&vdpa_list_lock);
1278 [ # # ]: 0 : TAILQ_REMOVE(&vdpa_dev_list, node, next);
1279 : 0 : pthread_mutex_unlock(&vdpa_list_lock);
1280 : :
1281 : 0 : rte_vdpa_unregister_device(device->vdev);
1282 : 0 : nfp_vdpa_vfio_teardown(device);
1283 : :
1284 : 0 : free(device);
1285 : 0 : free(node);
1286 : :
1287 : 0 : return 0;
1288 : : }
1289 : :
1290 : : static const struct rte_pci_id pci_id_nfp_vdpa_map[] = {
1291 : : {
1292 : : RTE_PCI_DEVICE(PCI_VENDOR_ID_NETRONOME,
1293 : : PCI_DEVICE_ID_NFP6000_VF_NIC)
1294 : : },
1295 : : {
1296 : : .vendor_id = 0,
1297 : : },
1298 : : };
1299 : :
1300 : : static struct nfp_class_driver nfp_vdpa = {
1301 : : .drv_class = NFP_CLASS_VDPA,
1302 : : .name = RTE_STR(NFP_VDPA_DRIVER_NAME),
1303 : : .id_table = pci_id_nfp_vdpa_map,
1304 : : .drv_flags = RTE_PCI_DRV_NEED_MAPPING | RTE_PCI_DRV_INTR_LSC,
1305 : : .probe = nfp_vdpa_pci_probe,
1306 : : .remove = nfp_vdpa_pci_remove,
1307 : : };
1308 : :
1309 : 253 : RTE_INIT(nfp_vdpa_init)
1310 : : {
1311 : 253 : nfp_class_driver_register(&nfp_vdpa);
1312 : 253 : }
1313 : :
1314 : : RTE_PMD_REGISTER_PCI_TABLE(NFP_VDPA_DRIVER_NAME, pci_id_nfp_vdpa_map);
1315 : : RTE_PMD_REGISTER_KMOD_DEP(NFP_VDPA_DRIVER_NAME, "* vfio-pci");
|