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