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