1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright(c) 2020-2021 Xilinx, Inc.
3 */
4
5 #include <stdbool.h>
6 #include <stdint.h>
7 #include <pthread.h>
8 #include <sys/queue.h>
9
10 #include <rte_common.h>
11 #include <rte_devargs.h>
12 #include <rte_errno.h>
13 #include <rte_kvargs.h>
14 #include <rte_string_fns.h>
15 #include <rte_vfio.h>
16 #include <rte_vhost.h>
17
18 #include "efx.h"
19 #include "sfc_efx.h"
20 #include "sfc_vdpa.h"
21
22 TAILQ_HEAD(sfc_vdpa_adapter_list_head, sfc_vdpa_adapter);
23 static struct sfc_vdpa_adapter_list_head sfc_vdpa_adapter_list =
24 TAILQ_HEAD_INITIALIZER(sfc_vdpa_adapter_list);
25
26 static pthread_mutex_t sfc_vdpa_adapter_list_lock = PTHREAD_MUTEX_INITIALIZER;
27
28 struct sfc_vdpa_adapter *
sfc_vdpa_get_adapter_by_dev(struct rte_pci_device * pdev)29 sfc_vdpa_get_adapter_by_dev(struct rte_pci_device *pdev)
30 {
31 bool found = false;
32 struct sfc_vdpa_adapter *sva;
33
34 pthread_mutex_lock(&sfc_vdpa_adapter_list_lock);
35
36 TAILQ_FOREACH(sva, &sfc_vdpa_adapter_list, next) {
37 if (pdev == sva->pdev) {
38 found = true;
39 break;
40 }
41 }
42
43 pthread_mutex_unlock(&sfc_vdpa_adapter_list_lock);
44
45 return found ? sva : NULL;
46 }
47
48 struct sfc_vdpa_ops_data *
sfc_vdpa_get_data_by_dev(struct rte_vdpa_device * vdpa_dev)49 sfc_vdpa_get_data_by_dev(struct rte_vdpa_device *vdpa_dev)
50 {
51 bool found = false;
52 struct sfc_vdpa_adapter *sva;
53
54 pthread_mutex_lock(&sfc_vdpa_adapter_list_lock);
55
56 TAILQ_FOREACH(sva, &sfc_vdpa_adapter_list, next) {
57 if (vdpa_dev == sva->ops_data->vdpa_dev) {
58 found = true;
59 break;
60 }
61 }
62
63 pthread_mutex_unlock(&sfc_vdpa_adapter_list_lock);
64
65 return found ? sva->ops_data : NULL;
66 }
67
68 static int
sfc_vdpa_vfio_setup(struct sfc_vdpa_adapter * sva)69 sfc_vdpa_vfio_setup(struct sfc_vdpa_adapter *sva)
70 {
71 struct rte_pci_device *dev = sva->pdev;
72 char dev_name[RTE_DEV_NAME_MAX_LEN] = {0};
73 int rc;
74
75 rte_pci_device_name(&dev->addr, dev_name, RTE_DEV_NAME_MAX_LEN);
76
77 sva->vfio_container_fd = rte_vfio_container_create();
78 if (sva->vfio_container_fd < 0) {
79 sfc_vdpa_err(sva, "failed to create VFIO container");
80 goto fail_container_create;
81 }
82
83 rc = rte_vfio_get_group_num(rte_pci_get_sysfs_path(), dev_name,
84 &sva->iommu_group_num);
85 if (rc <= 0) {
86 sfc_vdpa_err(sva, "failed to get IOMMU group for %s : %s",
87 dev_name, rte_strerror(-rc));
88 goto fail_get_group_num;
89 }
90
91 sva->vfio_group_fd =
92 rte_vfio_container_group_bind(sva->vfio_container_fd,
93 sva->iommu_group_num);
94 if (sva->vfio_group_fd < 0) {
95 sfc_vdpa_err(sva,
96 "failed to bind IOMMU group %d to container %d",
97 sva->iommu_group_num, sva->vfio_container_fd);
98 goto fail_group_bind;
99 }
100
101 if (rte_pci_map_device(dev) != 0) {
102 sfc_vdpa_err(sva, "failed to map PCI device %s : %s",
103 dev_name, rte_strerror(rte_errno));
104 goto fail_pci_map_device;
105 }
106
107 sva->vfio_dev_fd = rte_intr_dev_fd_get(dev->intr_handle);
108
109 return 0;
110
111 fail_pci_map_device:
112 if (rte_vfio_container_group_unbind(sva->vfio_container_fd,
113 sva->iommu_group_num) != 0) {
114 sfc_vdpa_err(sva,
115 "failed to unbind IOMMU group %d from container %d",
116 sva->iommu_group_num, sva->vfio_container_fd);
117 }
118
119 fail_group_bind:
120 fail_get_group_num:
121 if (rte_vfio_container_destroy(sva->vfio_container_fd) != 0) {
122 sfc_vdpa_err(sva, "failed to destroy container %d",
123 sva->vfio_container_fd);
124 }
125
126 fail_container_create:
127 return -1;
128 }
129
130 static void
sfc_vdpa_vfio_teardown(struct sfc_vdpa_adapter * sva)131 sfc_vdpa_vfio_teardown(struct sfc_vdpa_adapter *sva)
132 {
133 rte_pci_unmap_device(sva->pdev);
134
135 if (rte_vfio_container_group_unbind(sva->vfio_container_fd,
136 sva->iommu_group_num) != 0) {
137 sfc_vdpa_err(sva,
138 "failed to unbind IOMMU group %d from container %d",
139 sva->iommu_group_num, sva->vfio_container_fd);
140 }
141
142 if (rte_vfio_container_destroy(sva->vfio_container_fd) != 0) {
143 sfc_vdpa_err(sva,
144 "failed to destroy container %d",
145 sva->vfio_container_fd);
146 }
147 }
148
149 static int
sfc_vdpa_set_log_prefix(struct sfc_vdpa_adapter * sva)150 sfc_vdpa_set_log_prefix(struct sfc_vdpa_adapter *sva)
151 {
152 struct rte_pci_device *pci_dev = sva->pdev;
153 int ret;
154
155 ret = snprintf(sva->log_prefix, sizeof(sva->log_prefix),
156 "PMD: sfc_vdpa " PCI_PRI_FMT " : ",
157 pci_dev->addr.domain, pci_dev->addr.bus,
158 pci_dev->addr.devid, pci_dev->addr.function);
159
160 if (ret < 0 || ret >= (int)sizeof(sva->log_prefix)) {
161 SFC_VDPA_GENERIC_LOG(ERR,
162 "reserved log prefix is too short for " PCI_PRI_FMT,
163 pci_dev->addr.domain, pci_dev->addr.bus,
164 pci_dev->addr.devid, pci_dev->addr.function);
165 return -EINVAL;
166 }
167
168 return 0;
169 }
170
171 uint32_t
sfc_vdpa_register_logtype(const struct rte_pci_addr * pci_addr,const char * lt_prefix_str,uint32_t ll_default)172 sfc_vdpa_register_logtype(const struct rte_pci_addr *pci_addr,
173 const char *lt_prefix_str, uint32_t ll_default)
174 {
175 size_t lt_prefix_str_size = strlen(lt_prefix_str);
176 size_t lt_str_size_max;
177 char *lt_str = NULL;
178 int ret;
179
180 if (SIZE_MAX - PCI_PRI_STR_SIZE - 1 > lt_prefix_str_size) {
181 ++lt_prefix_str_size; /* Reserve space for prefix separator */
182 lt_str_size_max = lt_prefix_str_size + PCI_PRI_STR_SIZE + 1;
183 } else {
184 return sfc_vdpa_logtype_driver;
185 }
186
187 lt_str = rte_zmalloc("logtype_str", lt_str_size_max, 0);
188 if (lt_str == NULL)
189 return sfc_vdpa_logtype_driver;
190
191 strncpy(lt_str, lt_prefix_str, lt_prefix_str_size);
192 lt_str[lt_prefix_str_size - 1] = '.';
193 rte_pci_device_name(pci_addr, lt_str + lt_prefix_str_size,
194 lt_str_size_max - lt_prefix_str_size);
195 lt_str[lt_str_size_max - 1] = '\0';
196
197 ret = rte_log_register_type_and_pick_level(lt_str, ll_default);
198 rte_free(lt_str);
199
200 return ret < 0 ? sfc_vdpa_logtype_driver : ret;
201 }
202
203 static int
sfc_vdpa_kvargs_parse(struct sfc_vdpa_adapter * sva)204 sfc_vdpa_kvargs_parse(struct sfc_vdpa_adapter *sva)
205 {
206 struct rte_pci_device *pci_dev = sva->pdev;
207 struct rte_devargs *devargs = pci_dev->device.devargs;
208 /*
209 * To get the device class a mandatory param 'class' is being
210 * used so included SFC_EFX_KVARG_DEV_CLASS in the param list.
211 */
212 const char **params = (const char *[]){
213 RTE_DEVARGS_KEY_CLASS,
214 SFC_VDPA_MAC_ADDR,
215 NULL,
216 };
217
218 if (devargs == NULL)
219 return 0;
220
221 sva->kvargs = rte_kvargs_parse(devargs->args, params);
222 if (sva->kvargs == NULL)
223 return -EINVAL;
224
225 return 0;
226 }
227
228 static struct rte_pci_id pci_id_sfc_vdpa_efx_map[] = {
229 { RTE_PCI_DEVICE(EFX_PCI_VENID_XILINX, EFX_PCI_DEVID_RIVERHEAD_VF) },
230 { .vendor_id = 0, /* sentinel */ },
231 };
232
233 static int
sfc_vdpa_pci_probe(struct rte_pci_driver * pci_drv __rte_unused,struct rte_pci_device * pci_dev)234 sfc_vdpa_pci_probe(struct rte_pci_driver *pci_drv __rte_unused,
235 struct rte_pci_device *pci_dev)
236 {
237 struct sfc_vdpa_adapter *sva = NULL;
238 uint32_t logtype_main;
239 int ret = 0;
240
241 if (sfc_efx_dev_class_get(pci_dev->device.devargs) !=
242 SFC_EFX_DEV_CLASS_VDPA) {
243 SFC_VDPA_GENERIC_LOG(INFO,
244 "Incompatible device class: skip probing, should be probed by other sfc driver.");
245 return 1;
246 }
247
248 /*
249 * It will not be probed in the secondary process. As device class
250 * is vdpa so return 0 to avoid probe by other sfc driver
251 */
252 if (rte_eal_process_type() != RTE_PROC_PRIMARY)
253 return 0;
254
255 logtype_main = sfc_vdpa_register_logtype(&pci_dev->addr,
256 SFC_VDPA_LOGTYPE_MAIN_STR,
257 RTE_LOG_NOTICE);
258
259 sva = rte_zmalloc("sfc_vdpa", sizeof(struct sfc_vdpa_adapter), 0);
260 if (sva == NULL)
261 goto fail_zmalloc;
262
263 sva->pdev = pci_dev;
264 sva->logtype_main = logtype_main;
265
266 ret = sfc_vdpa_set_log_prefix(sva);
267 if (ret != 0)
268 goto fail_set_log_prefix;
269
270 ret = sfc_vdpa_kvargs_parse(sva);
271 if (ret != 0)
272 goto fail_kvargs_parse;
273
274 sfc_vdpa_log_init(sva, "entry");
275
276 sfc_vdpa_adapter_lock_init(sva);
277
278 sfc_vdpa_log_init(sva, "vfio init");
279 if (sfc_vdpa_vfio_setup(sva) < 0) {
280 sfc_vdpa_err(sva, "failed to setup device %s", pci_dev->name);
281 goto fail_vfio_setup;
282 }
283
284 sfc_vdpa_log_init(sva, "hw init");
285 if (sfc_vdpa_hw_init(sva) != 0) {
286 sfc_vdpa_err(sva, "failed to init HW %s", pci_dev->name);
287 goto fail_hw_init;
288 }
289
290 sfc_vdpa_log_init(sva, "dev init");
291 sva->ops_data = sfc_vdpa_device_init(sva, SFC_VDPA_AS_VF);
292 if (sva->ops_data == NULL) {
293 sfc_vdpa_err(sva, "failed vDPA dev init %s", pci_dev->name);
294 goto fail_dev_init;
295 }
296
297 pthread_mutex_lock(&sfc_vdpa_adapter_list_lock);
298 TAILQ_INSERT_TAIL(&sfc_vdpa_adapter_list, sva, next);
299 pthread_mutex_unlock(&sfc_vdpa_adapter_list_lock);
300
301 sfc_vdpa_log_init(sva, "done");
302
303 return 0;
304
305 fail_dev_init:
306 sfc_vdpa_hw_fini(sva);
307
308 fail_hw_init:
309 sfc_vdpa_vfio_teardown(sva);
310
311 fail_vfio_setup:
312 sfc_vdpa_adapter_lock_fini(sva);
313
314 fail_kvargs_parse:
315 fail_set_log_prefix:
316 rte_free(sva);
317
318 fail_zmalloc:
319 return -1;
320 }
321
322 static int
sfc_vdpa_pci_remove(struct rte_pci_device * pci_dev)323 sfc_vdpa_pci_remove(struct rte_pci_device *pci_dev)
324 {
325 struct sfc_vdpa_adapter *sva = NULL;
326
327 if (rte_eal_process_type() != RTE_PROC_PRIMARY)
328 return -1;
329
330 sva = sfc_vdpa_get_adapter_by_dev(pci_dev);
331 if (sva == NULL) {
332 SFC_VDPA_GENERIC_LOG(INFO,
333 "Invalid device: %s.", pci_dev->name);
334 return -1;
335 }
336
337 pthread_mutex_lock(&sfc_vdpa_adapter_list_lock);
338 TAILQ_REMOVE(&sfc_vdpa_adapter_list, sva, next);
339 pthread_mutex_unlock(&sfc_vdpa_adapter_list_lock);
340
341 sfc_vdpa_device_fini(sva->ops_data);
342
343 sfc_vdpa_hw_fini(sva);
344
345 sfc_vdpa_vfio_teardown(sva);
346
347 sfc_vdpa_adapter_lock_fini(sva);
348
349 rte_free(sva);
350
351 return 0;
352 }
353
354 static struct rte_pci_driver rte_sfc_vdpa = {
355 .id_table = pci_id_sfc_vdpa_efx_map,
356 .drv_flags = 0,
357 .probe = sfc_vdpa_pci_probe,
358 .remove = sfc_vdpa_pci_remove,
359 };
360
361 RTE_PMD_REGISTER_PCI(net_sfc_vdpa, rte_sfc_vdpa);
362 RTE_PMD_REGISTER_PCI_TABLE(net_sfc_vdpa, pci_id_sfc_vdpa_efx_map);
363 RTE_PMD_REGISTER_KMOD_DEP(net_sfc_vdpa, "* vfio-pci");
364 RTE_LOG_REGISTER_SUFFIX(sfc_vdpa_logtype_driver, driver, NOTICE);
365