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->container_fd = -1;
72 : 0 : vfio->iova_addr = START_VF_IOVA;
73 : :
74 : 0 : rte_pci_device_name(&dev->addr, devname, RTE_DEV_NAME_MAX_LEN);
75 : 0 : ret = rte_vfio_get_group_num(rte_pci_get_sysfs_path(), devname, &iommu_group_num);
76 [ # # ]: 0 : if (ret <= 0)
77 : : return -1;
78 : :
79 [ # # ]: 0 : if (vf_num == 0) {
80 : : /* use default container for pf0 */
81 : 0 : vfio->container_fd = RTE_VFIO_DEFAULT_CONTAINER_FD;
82 : :
83 : : } else {
84 : 0 : vfio->container_fd = rte_vfio_container_create();
85 : :
86 [ # # ]: 0 : if (vfio->container_fd < 0) {
87 : 0 : NT_LOG(ERR, NTNIC,
88 : : "VFIO device setup failed. VFIO container creation failed.");
89 : 0 : return -1;
90 : : }
91 : : }
92 : :
93 : 0 : vfio->group_fd = rte_vfio_container_group_bind(vfio->container_fd, iommu_group_num);
94 : :
95 [ # # ]: 0 : if (vfio->group_fd < 0) {
96 : 0 : NT_LOG(ERR, NTNIC,
97 : : "VFIO device setup failed. VFIO container group bind failed.");
98 : 0 : goto err;
99 : : }
100 : :
101 [ # # ]: 0 : if (vf_num > 0) {
102 [ # # ]: 0 : if (rte_pci_map_device(dev)) {
103 : 0 : NT_LOG(ERR, NTNIC,
104 : : "Map VFIO device failed. is the vfio-pci driver loaded?");
105 : 0 : goto err;
106 : : }
107 : : }
108 : :
109 : 0 : vfio->dev_fd = rte_intr_dev_fd_get(dev->intr_handle);
110 : :
111 : 0 : NT_LOG(DBG, NTNIC,
112 : : "%s: VFIO id=%d, dev_fd=%d, container_fd=%d, group_fd=%d, iommu_group_num=%d",
113 : : dev->name, vf_num, vfio->dev_fd, vfio->container_fd, vfio->group_fd,
114 : : iommu_group_num);
115 : :
116 : 0 : return vf_num;
117 : :
118 : 0 : err:
119 : :
120 [ # # ]: 0 : if (vfio->container_fd != RTE_VFIO_DEFAULT_CONTAINER_FD)
121 : 0 : rte_vfio_container_destroy(vfio->container_fd);
122 : :
123 : : return -1;
124 : : }
125 : :
126 : : int
127 : 0 : nt_vfio_remove(int vf_num)
128 : : {
129 : : struct vfio_dev *vfio;
130 : :
131 : 0 : NT_LOG(DBG, NTNIC, "NT VFIO device remove VF=%d", vf_num);
132 : :
133 : : vfio = vfio_get(vf_num);
134 : :
135 : : if (!vfio) {
136 : 0 : NT_LOG(ERR, NTNIC, "VFIO device remove failed. Illegal device id");
137 : 0 : return -1;
138 : : }
139 : :
140 : 0 : rte_vfio_container_destroy(vfio->container_fd);
141 : 0 : return 0;
142 : : }
143 : :
144 : : int
145 : 0 : nt_vfio_dma_map(int vf_num, void *virt_addr, uint64_t *iova_addr, uint64_t size)
146 : : {
147 : : uint64_t gp_virt_base;
148 : : uint64_t gp_offset;
149 : :
150 [ # # ]: 0 : if (size == ONE_G_SIZE) {
151 : 0 : gp_virt_base = (uint64_t)virt_addr & ~ONE_G_MASK;
152 : 0 : gp_offset = (uint64_t)virt_addr & ONE_G_MASK;
153 : :
154 : : } else {
155 : 0 : gp_virt_base = (uint64_t)virt_addr;
156 : : gp_offset = 0;
157 : : }
158 : :
159 : : struct vfio_dev *vfio;
160 : :
161 : : vfio = vfio_get(vf_num);
162 : :
163 : : if (vfio == NULL) {
164 : 0 : NT_LOG(ERR, NTNIC, "VFIO MAP: VF number %d invalid", vf_num);
165 : 0 : return -1;
166 : : }
167 : :
168 : 0 : NT_LOG(DBG, NTNIC,
169 : : "VFIO MMAP VF=%d VirtAddr=%p HPA=%" PRIX64 " VirtBase=%" PRIX64
170 : : " IOVA Addr=%" PRIX64 " size=%" PRIX64,
171 : : vf_num, virt_addr, rte_malloc_virt2iova(virt_addr), gp_virt_base, vfio->iova_addr,
172 : : size);
173 : :
174 : 0 : int res = rte_vfio_container_dma_map(vfio->container_fd, gp_virt_base, vfio->iova_addr,
175 : : size);
176 : :
177 : 0 : NT_LOG(DBG, NTNIC, "VFIO MMAP res %i, container_fd %i, vf_num %i", res,
178 : : vfio->container_fd, vf_num);
179 : :
180 [ # # ]: 0 : if (res) {
181 : 0 : NT_LOG(ERR, NTNIC, "rte_vfio_container_dma_map failed: res %d", res);
182 : 0 : return -1;
183 : : }
184 : :
185 : 0 : *iova_addr = vfio->iova_addr + gp_offset;
186 : :
187 : 0 : vfio->iova_addr += ONE_G_SIZE;
188 : :
189 : 0 : return 0;
190 : : }
191 : :
192 : : int
193 : 0 : nt_vfio_dma_unmap(int vf_num, void *virt_addr, uint64_t iova_addr, uint64_t size)
194 : : {
195 : : uint64_t gp_virt_base;
196 : : struct vfio_dev *vfio;
197 : :
198 [ # # ]: 0 : if (size == ONE_G_SIZE) {
199 : : uint64_t gp_offset;
200 : 0 : gp_virt_base = (uint64_t)virt_addr & ~ONE_G_MASK;
201 : 0 : gp_offset = (uint64_t)virt_addr & ONE_G_MASK;
202 : 0 : iova_addr -= gp_offset;
203 : :
204 : : } else {
205 : 0 : gp_virt_base = (uint64_t)virt_addr;
206 : : }
207 : :
208 : : vfio = vfio_get(vf_num);
209 : :
210 : : if (vfio == NULL) {
211 : 0 : NT_LOG(ERR, NTNIC, "VFIO UNMAP: VF number %d invalid", vf_num);
212 : 0 : return -1;
213 : : }
214 : :
215 [ # # ]: 0 : if (vfio->container_fd == -1)
216 : : return 0;
217 : :
218 : 0 : int res = rte_vfio_container_dma_unmap(vfio->container_fd, gp_virt_base, iova_addr, size);
219 : :
220 [ # # ]: 0 : if (res != 0) {
221 : 0 : NT_LOG(ERR, NTNIC,
222 : : "VFIO UNMMAP FAILED! res %i, container_fd %i, vf_num %i, virt_base=%" PRIX64
223 : : ", IOVA=%" PRIX64 ", size=%" PRIX64,
224 : : res, vfio->container_fd, vf_num, gp_virt_base, iova_addr, size);
225 : 0 : return -1;
226 : : }
227 : :
228 : : return 0;
229 : : }
230 : :
231 : : void
232 : 0 : nt_vfio_init(void)
233 : : {
234 : 0 : struct nt_util_vfio_impl s = { .vfio_dma_map = nt_vfio_dma_map,
235 : : .vfio_dma_unmap = nt_vfio_dma_unmap
236 : : };
237 : 0 : nt_util_vfio_init(&s);
238 : 0 : }
|