crypto/bcmfs: introduce BCMFS driver
[dpdk.git] / drivers / crypto / bcmfs / bcmfs_device.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(C) 2020 Broadcom.
3  * All rights reserved.
4  */
5
6 #include <dirent.h>
7 #include <stdbool.h>
8 #include <sys/queue.h>
9
10 #include <rte_malloc.h>
11 #include <rte_string_fns.h>
12
13 #include "bcmfs_device.h"
14 #include "bcmfs_logs.h"
15
16 struct bcmfs_device_attr {
17         const char name[BCMFS_MAX_PATH_LEN];
18         const char suffix[BCMFS_DEV_NAME_LEN];
19         const enum bcmfs_device_type type;
20         const uint32_t offset;
21         const uint32_t version;
22 };
23
24 /* BCMFS supported devices */
25 static struct bcmfs_device_attr dev_table[] = {
26         {
27                 .name = "fs4",
28                 .suffix = "crypto_mbox",
29                 .type = BCMFS_SYM_FS4,
30                 .offset = 0,
31                 .version = BCMFS_SYM_FS4_VERSION
32         },
33         {
34                 .name = "fs5",
35                 .suffix = "mbox",
36                 .type = BCMFS_SYM_FS5,
37                 .offset = 0,
38                 .version = BCMFS_SYM_FS5_VERSION
39         },
40         {
41                 /* sentinel */
42         }
43 };
44
45 TAILQ_HEAD(fsdev_list, bcmfs_device);
46 static struct fsdev_list fsdev_list = TAILQ_HEAD_INITIALIZER(fsdev_list);
47
48 static struct bcmfs_device *
49 fsdev_allocate_one_dev(struct rte_vdev_device *vdev,
50                        char *dirpath,
51                        char *devname,
52                        enum bcmfs_device_type dev_type __rte_unused)
53 {
54         struct bcmfs_device *fsdev;
55
56         fsdev = rte_calloc(__func__, 1, sizeof(*fsdev), 0);
57         if (!fsdev)
58                 return NULL;
59
60         if (strlen(dirpath) > sizeof(fsdev->dirname)) {
61                 BCMFS_LOG(ERR, "dir path name is too long");
62                 goto cleanup;
63         }
64
65         if (strlen(devname) > sizeof(fsdev->name)) {
66                 BCMFS_LOG(ERR, "devname is too long");
67                 goto cleanup;
68         }
69
70         strcpy(fsdev->dirname, dirpath);
71         strcpy(fsdev->name, devname);
72
73         fsdev->vdev = vdev;
74
75         TAILQ_INSERT_TAIL(&fsdev_list, fsdev, next);
76
77         return fsdev;
78
79 cleanup:
80         free(fsdev);
81
82         return NULL;
83 }
84
85 static struct bcmfs_device *
86 find_fsdev(struct rte_vdev_device *vdev)
87 {
88         struct bcmfs_device *fsdev;
89
90         TAILQ_FOREACH(fsdev, &fsdev_list, next)
91                 if (fsdev->vdev == vdev)
92                         return fsdev;
93
94         return NULL;
95 }
96
97 static void
98 fsdev_release(struct bcmfs_device *fsdev)
99 {
100         if (fsdev == NULL)
101                 return;
102
103         TAILQ_REMOVE(&fsdev_list, fsdev, next);
104         free(fsdev);
105 }
106
107 static int
108 cmprator(const void *a, const void *b)
109 {
110         return (*(const unsigned int *)a - *(const unsigned int *)b);
111 }
112
113 static int
114 fsdev_find_all_devs(const char *path, const char *search,
115                     uint32_t *devs)
116 {
117         DIR *dir;
118         struct dirent *entry;
119         int count = 0;
120         char addr[BCMFS_MAX_NODES][BCMFS_MAX_PATH_LEN];
121         int i;
122
123         dir = opendir(path);
124         if (dir == NULL) {
125                 BCMFS_LOG(ERR, "Unable to open directory");
126                 return 0;
127         }
128
129         while ((entry = readdir(dir)) != NULL) {
130                 if (strstr(entry->d_name, search)) {
131                         strlcpy(addr[count], entry->d_name,
132                                 BCMFS_MAX_PATH_LEN);
133                         count++;
134                 }
135         }
136
137         closedir(dir);
138
139         for (i = 0 ; i < count; i++)
140                 devs[i] = (uint32_t)strtoul(addr[i], NULL, 16);
141         /* sort the devices based on IO addresses */
142         qsort(devs, count, sizeof(uint32_t), cmprator);
143
144         return count;
145 }
146
147 static bool
148 fsdev_find_sub_dir(char *path, const char *search, char *output)
149 {
150         DIR *dir;
151         struct dirent *entry;
152
153         dir = opendir(path);
154         if (dir == NULL) {
155                 BCMFS_LOG(ERR, "Unable to open directory");
156                 return -ENODEV;
157         }
158
159         while ((entry = readdir(dir)) != NULL) {
160                 if (!strcmp(entry->d_name, search)) {
161                         strlcpy(output, entry->d_name, BCMFS_MAX_PATH_LEN);
162                         closedir(dir);
163                         return true;
164                 }
165         }
166
167         closedir(dir);
168
169         return false;
170 }
171
172
173 static int
174 bcmfs_vdev_probe(struct rte_vdev_device *vdev)
175 {
176         struct bcmfs_device *fsdev;
177         char top_dirpath[BCMFS_MAX_PATH_LEN];
178         char sub_dirpath[BCMFS_MAX_PATH_LEN];
179         char out_dirpath[BCMFS_MAX_PATH_LEN];
180         char out_dirname[BCMFS_MAX_PATH_LEN];
181         uint32_t fsdev_dev[BCMFS_MAX_NODES];
182         enum bcmfs_device_type dtype;
183         int i = 0;
184         int dev_idx;
185         int count = 0;
186         bool found = false;
187
188         sprintf(top_dirpath, "%s", SYSFS_BCM_PLTFORM_DEVICES);
189         while (strlen(dev_table[i].name)) {
190                 found = fsdev_find_sub_dir(top_dirpath,
191                                            dev_table[i].name,
192                                            sub_dirpath);
193                 if (found)
194                         break;
195                 i++;
196         }
197         if (!found) {
198                 BCMFS_LOG(ERR, "No supported bcmfs dev found");
199                 return -ENODEV;
200         }
201
202         dev_idx = i;
203         dtype = dev_table[i].type;
204
205         snprintf(out_dirpath, sizeof(out_dirpath), "%s/%s",
206                  top_dirpath, sub_dirpath);
207         count = fsdev_find_all_devs(out_dirpath,
208                                     dev_table[dev_idx].suffix,
209                                     fsdev_dev);
210         if (!count) {
211                 BCMFS_LOG(ERR, "No supported bcmfs dev found");
212                 return -ENODEV;
213         }
214
215         i = 0;
216         while (count) {
217                 /* format the device name present in the patch */
218                 snprintf(out_dirname, sizeof(out_dirname), "%x.%s",
219                          fsdev_dev[i], dev_table[dev_idx].suffix);
220                 fsdev = fsdev_allocate_one_dev(vdev, out_dirpath,
221                                                out_dirname, dtype);
222                 if (!fsdev) {
223                         count--;
224                         i++;
225                         continue;
226                 }
227                 break;
228         }
229         if (fsdev == NULL) {
230                 BCMFS_LOG(ERR, "All supported devs busy");
231                 return -ENODEV;
232         }
233
234         return 0;
235 }
236
237 static int
238 bcmfs_vdev_remove(struct rte_vdev_device *vdev)
239 {
240         struct bcmfs_device *fsdev;
241
242         fsdev = find_fsdev(vdev);
243         if (fsdev == NULL)
244                 return -ENODEV;
245
246         fsdev_release(fsdev);
247         return 0;
248 }
249
250 /* Register with vdev */
251 static struct rte_vdev_driver rte_bcmfs_pmd = {
252         .probe = bcmfs_vdev_probe,
253         .remove = bcmfs_vdev_remove
254 };
255
256 RTE_PMD_REGISTER_VDEV(bcmfs_pmd,
257                       rte_bcmfs_pmd);