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