Branch data Line data Source code
1 : : /*
2 : : * SPDX-License-Identifier: BSD-3-Clause
3 : : * Copyright(c) 2023 Napatech A/S
4 : : */
5 : :
6 : : #include <sys/ioctl.h>
7 : :
8 : : #include <rte_malloc.h>
9 : : #include <rte_memory.h>
10 : : #include <rte_vfio.h>
11 : : #include <rte_dev.h>
12 : : #include <rte_bus_pci.h>
13 : : #include <rte_spinlock.h>
14 : :
15 : : #include <ntlog.h>
16 : : #include <nt_util.h>
17 : : #include "ntnic_vfio.h"
18 : :
19 : : #define ONE_G_SIZE 0x40000000
20 : : #define ONE_G_MASK (ONE_G_SIZE - 1)
21 : : #define START_VF_IOVA 0x220000000000
22 : :
23 : : int
24 : 0 : nt_vfio_vf_num(const struct rte_pci_device *pdev)
25 : : {
26 : 0 : return ((pdev->addr.devid & 0x1f) << 3) + ((pdev->addr.function) & 0x7);
27 : : }
28 : :
29 : : /* Internal API */
30 : : struct vfio_dev {
31 : : int container_fd;
32 : : int group_fd;
33 : : int dev_fd;
34 : : uint64_t iova_addr;
35 : : };
36 : :
37 : : static struct vfio_dev vfio_list[256];
38 : :
39 : : static struct vfio_dev *
40 : : vfio_get(int vf_num)
41 : : {
42 [ # # # # : 0 : if (vf_num < 0 || vf_num > 255)
# # # # ]
43 : : return NULL;
44 : :
45 : 0 : return &vfio_list[vf_num];
46 : : }
47 : :
48 : : /* External API */
49 : : int
50 : 0 : nt_vfio_setup(struct rte_pci_device *dev)
51 : : {
52 : : int ret;
53 : 0 : char devname[RTE_DEV_NAME_MAX_LEN] = { 0 };
54 : : int iommu_group_num;
55 : : int vf_num;
56 : : struct vfio_dev *vfio;
57 : :
58 : 0 : NT_LOG(INF, NTNIC, "NT VFIO device setup %s", dev->name);
59 : :
60 : 0 : vf_num = nt_vfio_vf_num(dev);
61 : :
62 : : vfio = vfio_get(vf_num);
63 : :
64 : : if (vfio == NULL) {
65 : 0 : NT_LOG(ERR, NTNIC, "VFIO device setup failed. Illegal device id");
66 : 0 : return -1;
67 : : }
68 : :
69 : 0 : vfio->dev_fd = -1;
70 : 0 : vfio->group_fd = -1;
71 : 0 : vfio->iova_addr = START_VF_IOVA;
72 : :
73 : 0 : rte_pci_device_name(&dev->addr, devname, RTE_DEV_NAME_MAX_LEN);
74 : 0 : ret = rte_vfio_get_group_num(rte_pci_get_sysfs_path(), devname, &iommu_group_num);
75 [ # # ]: 0 : if (ret <= 0)
76 : : return -1;
77 : :
78 [ # # ]: 0 : if (vf_num == 0) {
79 : : /* use default container for pf0 */
80 : 0 : vfio->container_fd = RTE_VFIO_DEFAULT_CONTAINER_FD;
81 : :
82 : : } else {
83 : 0 : vfio->container_fd = rte_vfio_container_create();
84 : :
85 [ # # ]: 0 : if (vfio->container_fd < 0) {
86 : 0 : NT_LOG(ERR, NTNIC,
87 : : "VFIO device setup failed. VFIO container creation failed.");
88 : 0 : return -1;
89 : : }
90 : : }
91 : :
92 : 0 : vfio->group_fd = rte_vfio_container_group_bind(vfio->container_fd, iommu_group_num);
93 : :
94 [ # # ]: 0 : if (vfio->group_fd < 0) {
95 : 0 : NT_LOG(ERR, NTNIC,
96 : : "VFIO device setup failed. VFIO container group bind failed.");
97 : 0 : goto err;
98 : : }
99 : :
100 [ # # ]: 0 : if (vf_num > 0) {
101 [ # # ]: 0 : if (rte_pci_map_device(dev)) {
102 : 0 : NT_LOG(ERR, NTNIC,
103 : : "Map VFIO device failed. is the vfio-pci driver loaded?");
104 : 0 : goto err;
105 : : }
106 : : }
107 : :
108 : 0 : vfio->dev_fd = rte_intr_dev_fd_get(dev->intr_handle);
109 : :
110 : 0 : NT_LOG(DBG, NTNIC,
111 : : "%s: VFIO id=%d, dev_fd=%d, container_fd=%d, group_fd=%d, iommu_group_num=%d",
112 : : dev->name, vf_num, vfio->dev_fd, vfio->container_fd, vfio->group_fd,
113 : : iommu_group_num);
114 : :
115 : 0 : return vf_num;
116 : :
117 : 0 : err:
118 : :
119 [ # # ]: 0 : if (vfio->container_fd != RTE_VFIO_DEFAULT_CONTAINER_FD)
120 : 0 : rte_vfio_container_destroy(vfio->container_fd);
121 : :
122 : : return -1;
123 : : }
124 : :
125 : : int
126 : 0 : nt_vfio_remove(int vf_num)
127 : : {
128 : : struct vfio_dev *vfio;
129 : :
130 : 0 : NT_LOG(DBG, NTNIC, "NT VFIO device remove VF=%d", vf_num);
131 : :
132 : : vfio = vfio_get(vf_num);
133 : :
134 : : if (!vfio) {
135 : 0 : NT_LOG(ERR, NTNIC, "VFIO device remove failed. Illegal device id");
136 : 0 : return -1;
137 : : }
138 : :
139 : 0 : rte_vfio_container_destroy(vfio->container_fd);
140 : 0 : return 0;
141 : : }
142 : :
143 : : int
144 : 0 : nt_vfio_dma_map(int vf_num, void *virt_addr, uint64_t *iova_addr, uint64_t size)
145 : : {
146 : : uint64_t gp_virt_base;
147 : : uint64_t gp_offset;
148 : :
149 [ # # ]: 0 : if (size == ONE_G_SIZE) {
150 : 0 : gp_virt_base = (uint64_t)virt_addr & ~ONE_G_MASK;
151 : 0 : gp_offset = (uint64_t)virt_addr & ONE_G_MASK;
152 : :
153 : : } else {
154 : 0 : gp_virt_base = (uint64_t)virt_addr;
155 : : gp_offset = 0;
156 : : }
157 : :
158 : : struct vfio_dev *vfio;
159 : :
160 : : vfio = vfio_get(vf_num);
161 : :
162 : : if (vfio == NULL) {
163 : 0 : NT_LOG(ERR, NTNIC, "VFIO MAP: VF number %d invalid", vf_num);
164 : 0 : return -1;
165 : : }
166 : :
167 : 0 : NT_LOG(DBG, NTNIC,
168 : : "VFIO MMAP VF=%d VirtAddr=%p HPA=%" PRIX64 " VirtBase=%" PRIX64
169 : : " IOVA Addr=%" PRIX64 " size=%" PRIX64,
170 : : vf_num, virt_addr, rte_malloc_virt2iova(virt_addr), gp_virt_base, vfio->iova_addr,
171 : : size);
172 : :
173 : 0 : int res = rte_vfio_container_dma_map(vfio->container_fd, gp_virt_base, vfio->iova_addr,
174 : : size);
175 : :
176 : 0 : NT_LOG(DBG, NTNIC, "VFIO MMAP res %i, container_fd %i, vf_num %i", res,
177 : : vfio->container_fd, vf_num);
178 : :
179 [ # # ]: 0 : if (res) {
180 : 0 : NT_LOG(ERR, NTNIC, "rte_vfio_container_dma_map failed: res %d", res);
181 : 0 : return -1;
182 : : }
183 : :
184 : 0 : *iova_addr = vfio->iova_addr + gp_offset;
185 : :
186 : 0 : vfio->iova_addr += ONE_G_SIZE;
187 : :
188 : 0 : return 0;
189 : : }
190 : :
191 : : int
192 : 0 : nt_vfio_dma_unmap(int vf_num, void *virt_addr, uint64_t iova_addr, uint64_t size)
193 : : {
194 : : uint64_t gp_virt_base;
195 : : struct vfio_dev *vfio;
196 : :
197 [ # # ]: 0 : if (size == ONE_G_SIZE) {
198 : : uint64_t gp_offset;
199 : 0 : gp_virt_base = (uint64_t)virt_addr & ~ONE_G_MASK;
200 : 0 : gp_offset = (uint64_t)virt_addr & ONE_G_MASK;
201 : 0 : iova_addr -= gp_offset;
202 : :
203 : : } else {
204 : 0 : gp_virt_base = (uint64_t)virt_addr;
205 : : }
206 : :
207 : : vfio = vfio_get(vf_num);
208 : :
209 : : if (vfio == NULL) {
210 : 0 : NT_LOG(ERR, NTNIC, "VFIO UNMAP: VF number %d invalid", vf_num);
211 : 0 : return -1;
212 : : }
213 : :
214 [ # # ]: 0 : if (vfio->container_fd == -1)
215 : : return 0;
216 : :
217 : 0 : int res = rte_vfio_container_dma_unmap(vfio->container_fd, gp_virt_base, iova_addr, size);
218 : :
219 [ # # ]: 0 : if (res != 0) {
220 : 0 : NT_LOG(ERR, NTNIC,
221 : : "VFIO UNMMAP FAILED! res %i, container_fd %i, vf_num %i, virt_base=%" PRIX64
222 : : ", IOVA=%" PRIX64 ", size=%" PRIX64,
223 : : res, vfio->container_fd, vf_num, gp_virt_base, iova_addr, size);
224 : 0 : return -1;
225 : : }
226 : :
227 : : return 0;
228 : : }
229 : :
230 : : void
231 : 0 : nt_vfio_init(void)
232 : : {
233 : 0 : struct nt_util_vfio_impl s = { .vfio_dma_map = nt_vfio_dma_map,
234 : : .vfio_dma_unmap = nt_vfio_dma_unmap
235 : : };
236 : 0 : nt_util_vfio_init(&s);
237 : 0 : }
|