bus/fslmc: support dynamic IOVA
[dpdk.git] / drivers / bus / fslmc / fslmc_bus.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  *
3  *   Copyright 2016 NXP
4  *
5  */
6
7 #include <string.h>
8 #include <dirent.h>
9 #include <stdbool.h>
10
11 #include <rte_log.h>
12 #include <rte_bus.h>
13 #include <rte_eal_memconfig.h>
14 #include <rte_malloc.h>
15 #include <rte_devargs.h>
16 #include <rte_memcpy.h>
17 #include <rte_ethdev.h>
18
19 #include <rte_fslmc.h>
20 #include <fslmc_vfio.h>
21
22 #define FSLMC_BUS_LOG(level, fmt, args...) \
23         RTE_LOG(level, EAL, fmt "\n", ##args)
24
25 #define VFIO_IOMMU_GROUP_PATH "/sys/kernel/iommu_groups"
26
27 struct rte_fslmc_bus rte_fslmc_bus;
28 uint8_t dpaa2_virt_mode;
29
30 static void
31 cleanup_fslmc_device_list(void)
32 {
33         struct rte_dpaa2_device *dev;
34         struct rte_dpaa2_device *t_dev;
35
36         TAILQ_FOREACH_SAFE(dev, &rte_fslmc_bus.device_list, next, t_dev) {
37                 TAILQ_REMOVE(&rte_fslmc_bus.device_list, dev, next);
38                 free(dev);
39                 dev = NULL;
40         }
41 }
42
43 static int
44 compare_dpaa2_devname(struct rte_dpaa2_device *dev1,
45                       struct rte_dpaa2_device *dev2)
46 {
47         int comp;
48
49         if (dev1->dev_type > dev2->dev_type) {
50                 comp = 1;
51         } else if (dev1->dev_type < dev2->dev_type) {
52                 comp = -1;
53         } else {
54                 /* Check the ID as types match */
55                 if (dev1->object_id > dev2->object_id)
56                         comp = 1;
57                 else if (dev1->object_id < dev2->object_id)
58                         comp = -1;
59                 else
60                         comp = 0; /* Duplicate device name */
61         }
62
63         return comp;
64 }
65
66 static void
67 insert_in_device_list(struct rte_dpaa2_device *newdev)
68 {
69         int comp, inserted = 0;
70         struct rte_dpaa2_device *dev = NULL;
71         struct rte_dpaa2_device *tdev = NULL;
72
73         TAILQ_FOREACH_SAFE(dev, &rte_fslmc_bus.device_list, next, tdev) {
74                 comp = compare_dpaa2_devname(newdev, dev);
75                 if (comp < 0) {
76                         TAILQ_INSERT_BEFORE(dev, newdev, next);
77                         inserted = 1;
78                         break;
79                 }
80         }
81
82         if (!inserted)
83                 TAILQ_INSERT_TAIL(&rte_fslmc_bus.device_list, newdev, next);
84 }
85
86 static int
87 scan_one_fslmc_device(char *dev_name)
88 {
89         char *dup_dev_name, *t_ptr;
90         struct rte_dpaa2_device *dev;
91
92         if (!dev_name)
93                 return -1;
94
95         /* Ignore the Container name itself */
96         if (!strncmp("dprc", dev_name, 4))
97                 return 0;
98
99         /* Creating a temporary copy to perform cut-parse over string */
100         dup_dev_name = strdup(dev_name);
101         if (!dup_dev_name) {
102                 FSLMC_BUS_LOG(ERR, "Out of memory.");
103                 return -ENOMEM;
104         }
105
106         /* For all other devices, we allocate rte_dpaa2_device.
107          * For those devices where there is no driver, probe would release
108          * the memory associated with the rte_dpaa2_device after necessary
109          * initialization.
110          */
111         dev = calloc(1, sizeof(struct rte_dpaa2_device));
112         if (!dev) {
113                 FSLMC_BUS_LOG(ERR, "Out of memory.");
114                 free(dup_dev_name);
115                 return -ENOMEM;
116         }
117
118         /* Parse the device name and ID */
119         t_ptr = strtok(dup_dev_name, ".");
120         if (!t_ptr) {
121                 FSLMC_BUS_LOG(ERR, "Incorrect device string observed.");
122                 goto cleanup;
123         }
124         if (!strncmp("dpni", t_ptr, 4))
125                 dev->dev_type = DPAA2_ETH;
126         else if (!strncmp("dpseci", t_ptr, 6))
127                 dev->dev_type = DPAA2_CRYPTO;
128         else if (!strncmp("dpcon", t_ptr, 5))
129                 dev->dev_type = DPAA2_CON;
130         else if (!strncmp("dpbp", t_ptr, 4))
131                 dev->dev_type = DPAA2_BPOOL;
132         else if (!strncmp("dpio", t_ptr, 4))
133                 dev->dev_type = DPAA2_IO;
134         else if (!strncmp("dpci", t_ptr, 5))
135                 dev->dev_type = DPAA2_CI;
136         else if (!strncmp("dpmcp", t_ptr, 5))
137                 dev->dev_type = DPAA2_MPORTAL;
138         else
139                 dev->dev_type = DPAA2_UNKNOWN;
140
141         t_ptr = strtok(NULL, ".");
142         if (!t_ptr) {
143                 FSLMC_BUS_LOG(ERR, "Incorrect device string observed (%s).",
144                               t_ptr);
145                 goto cleanup;
146         }
147
148         sscanf(t_ptr, "%hu", &dev->object_id);
149         dev->device.name = strdup(dev_name);
150         if (!dev->device.name) {
151                 FSLMC_BUS_LOG(ERR, "Out of memory.");
152                 goto cleanup;
153         }
154
155         /* Add device in the fslmc device list */
156         insert_in_device_list(dev);
157
158         /* Don't need the duplicated device filesystem entry anymore */
159         if (dup_dev_name)
160                 free(dup_dev_name);
161
162         return 0;
163 cleanup:
164         if (dup_dev_name)
165                 free(dup_dev_name);
166         if (dev)
167                 free(dev);
168         return -1;
169 }
170
171 static int
172 rte_fslmc_scan(void)
173 {
174         int ret;
175         int device_count = 0;
176         char fslmc_dirpath[PATH_MAX];
177         DIR *dir;
178         struct dirent *entry;
179         static int process_once;
180         int groupid;
181
182         if (process_once) {
183                 FSLMC_BUS_LOG(DEBUG,
184                               "Fslmc bus already scanned. Not rescanning");
185                 return 0;
186         }
187         process_once = 1;
188
189         ret = fslmc_get_container_group(&groupid);
190         if (ret != 0)
191                 goto scan_fail;
192
193         /* Scan devices on the group */
194         sprintf(fslmc_dirpath, "%s/%d/devices", VFIO_IOMMU_GROUP_PATH,
195                 groupid);
196         dir = opendir(fslmc_dirpath);
197         if (!dir) {
198                 FSLMC_BUS_LOG(ERR, "Unable to open VFIO group dir.");
199                 goto scan_fail;
200         }
201
202         while ((entry = readdir(dir)) != NULL) {
203                 if (entry->d_name[0] == '.' || entry->d_type != DT_LNK)
204                         continue;
205
206                 ret = scan_one_fslmc_device(entry->d_name);
207                 if (ret != 0) {
208                         /* Error in parsing directory - exit gracefully */
209                         goto scan_fail_cleanup;
210                 }
211                 device_count += 1;
212         }
213
214         FSLMC_BUS_LOG(INFO, "fslmc: Bus scan completed");
215
216         closedir(dir);
217         return 0;
218
219 scan_fail_cleanup:
220         closedir(dir);
221
222         /* Remove all devices in the list */
223         cleanup_fslmc_device_list();
224 scan_fail:
225         FSLMC_BUS_LOG(DEBUG, "FSLMC Bus Not Available. Skipping.");
226         /* Irrespective of failure, scan only return success */
227         return 0;
228 }
229
230 static int
231 rte_fslmc_match(struct rte_dpaa2_driver *dpaa2_drv,
232                 struct rte_dpaa2_device *dpaa2_dev)
233 {
234         if (dpaa2_drv->drv_type == dpaa2_dev->dev_type)
235                 return 0;
236
237         return 1;
238 }
239
240 static int
241 rte_fslmc_probe(void)
242 {
243         int ret = 0;
244         struct rte_dpaa2_device *dev;
245         struct rte_dpaa2_driver *drv;
246
247         if (TAILQ_EMPTY(&rte_fslmc_bus.device_list))
248                 return 0;
249
250         ret = fslmc_vfio_setup_group();
251         if (ret) {
252                 FSLMC_BUS_LOG(ERR, "Unable to setup VFIO %d", ret);
253                 return 0;
254         }
255
256         ret = fslmc_vfio_process_group();
257         if (ret) {
258                 FSLMC_BUS_LOG(ERR, "Unable to setup devices %d", ret);
259                 return 0;
260         }
261
262         TAILQ_FOREACH(dev, &rte_fslmc_bus.device_list, next) {
263                 TAILQ_FOREACH(drv, &rte_fslmc_bus.driver_list, next) {
264                         ret = rte_fslmc_match(drv, dev);
265                         if (ret)
266                                 continue;
267
268                         if (!drv->probe)
269                                 continue;
270
271                         ret = drv->probe(drv, dev);
272                         if (ret)
273                                 FSLMC_BUS_LOG(ERR, "Unable to probe.\n");
274                         break;
275                 }
276         }
277
278         if (rte_eal_iova_mode() == RTE_IOVA_VA)
279                 dpaa2_virt_mode = 1;
280
281         return 0;
282 }
283
284 static struct rte_device *
285 rte_fslmc_find_device(const struct rte_device *start, rte_dev_cmp_t cmp,
286                       const void *data)
287 {
288         struct rte_dpaa2_device *dev;
289
290         TAILQ_FOREACH(dev, &rte_fslmc_bus.device_list, next) {
291                 if (start && &dev->device == start) {
292                         start = NULL;  /* starting point found */
293                         continue;
294                 }
295
296                 if (cmp(&dev->device, data) == 0)
297                         return &dev->device;
298         }
299
300         return NULL;
301 }
302
303 /*register a fslmc bus based dpaa2 driver */
304 void
305 rte_fslmc_driver_register(struct rte_dpaa2_driver *driver)
306 {
307         RTE_VERIFY(driver);
308
309         TAILQ_INSERT_TAIL(&rte_fslmc_bus.driver_list, driver, next);
310         /* Update Bus references */
311         driver->fslmc_bus = &rte_fslmc_bus;
312 }
313
314 /*un-register a fslmc bus based dpaa2 driver */
315 void
316 rte_fslmc_driver_unregister(struct rte_dpaa2_driver *driver)
317 {
318         struct rte_fslmc_bus *fslmc_bus;
319
320         fslmc_bus = driver->fslmc_bus;
321
322         TAILQ_REMOVE(&fslmc_bus->driver_list, driver, next);
323         /* Update Bus references */
324         driver->fslmc_bus = NULL;
325 }
326
327 /*
328  * All device has iova as va
329  */
330 static inline int
331 fslmc_all_device_support_iova(void)
332 {
333         int ret = 0;
334         struct rte_dpaa2_device *dev;
335         struct rte_dpaa2_driver *drv;
336
337         TAILQ_FOREACH(dev, &rte_fslmc_bus.device_list, next) {
338                 TAILQ_FOREACH(drv, &rte_fslmc_bus.driver_list, next) {
339                         ret = rte_fslmc_match(drv, dev);
340                         if (ret)
341                                 continue;
342                         /* if the driver is not supporting IOVA */
343                         if (!(drv->drv_flags & RTE_DPAA2_DRV_IOVA_AS_VA))
344                                 return 0;
345                 }
346         }
347         return 1;
348 }
349
350 /*
351  * Get iommu class of DPAA2 devices on the bus.
352  */
353 static enum rte_iova_mode
354 rte_dpaa2_get_iommu_class(void)
355 {
356         bool is_vfio_noiommu_enabled = 1;
357         bool has_iova_va;
358
359         if (TAILQ_EMPTY(&rte_fslmc_bus.device_list))
360                 return RTE_IOVA_DC;
361
362         /* check if all devices on the bus support Virtual addressing or not */
363         has_iova_va = fslmc_all_device_support_iova();
364
365 #ifdef VFIO_PRESENT
366         is_vfio_noiommu_enabled = rte_vfio_noiommu_is_enabled() == true ?
367                                                 true : false;
368 #endif
369
370         if (has_iova_va && !is_vfio_noiommu_enabled)
371                 return RTE_IOVA_VA;
372
373         return RTE_IOVA_PA;
374 }
375
376 struct rte_fslmc_bus rte_fslmc_bus = {
377         .bus = {
378                 .scan = rte_fslmc_scan,
379                 .probe = rte_fslmc_probe,
380                 .find_device = rte_fslmc_find_device,
381                 .get_iommu_class = rte_dpaa2_get_iommu_class,
382         },
383         .device_list = TAILQ_HEAD_INITIALIZER(rte_fslmc_bus.device_list),
384         .driver_list = TAILQ_HEAD_INITIALIZER(rte_fslmc_bus.driver_list),
385 };
386
387 RTE_REGISTER_BUS(fslmc, rte_fslmc_bus.bus);