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