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