07423d3cc1d0a9c7100b25dbf53d2b1c974077a3
[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 struct bcmfs_hw_queue_pair_ops_table bcmfs_hw_queue_pair_ops_table = {
48         .tl =  RTE_SPINLOCK_INITIALIZER,
49         .num_ops = 0
50 };
51
52 int bcmfs_hw_queue_pair_register_ops(const struct bcmfs_hw_queue_pair_ops *h)
53 {
54         struct bcmfs_hw_queue_pair_ops *ops;
55         int16_t ops_index;
56
57         rte_spinlock_lock(&bcmfs_hw_queue_pair_ops_table.tl);
58
59         if (h->enq_one_req == NULL || h->dequeue == NULL ||
60             h->ring_db == NULL || h->startq == NULL || h->stopq == NULL) {
61                 rte_spinlock_unlock(&bcmfs_hw_queue_pair_ops_table.tl);
62                 BCMFS_LOG(ERR,
63                           "Missing callback while registering device ops");
64                 return -EINVAL;
65         }
66
67         if (strlen(h->name) >= sizeof(ops->name) - 1) {
68                 rte_spinlock_unlock(&bcmfs_hw_queue_pair_ops_table.tl);
69                 BCMFS_LOG(ERR, "%s(): fs device_ops <%s>: name too long",
70                                 __func__, h->name);
71                 return -EEXIST;
72         }
73
74         ops_index = bcmfs_hw_queue_pair_ops_table.num_ops++;
75         ops = &bcmfs_hw_queue_pair_ops_table.qp_ops[ops_index];
76         strlcpy(ops->name, h->name, sizeof(ops->name));
77         ops->enq_one_req = h->enq_one_req;
78         ops->dequeue = h->dequeue;
79         ops->ring_db = h->ring_db;
80         ops->startq = h->startq;
81         ops->stopq = h->stopq;
82
83         rte_spinlock_unlock(&bcmfs_hw_queue_pair_ops_table.tl);
84
85         return ops_index;
86 }
87
88 TAILQ_HEAD(fsdev_list, bcmfs_device);
89 static struct fsdev_list fsdev_list = TAILQ_HEAD_INITIALIZER(fsdev_list);
90
91 static struct bcmfs_device *
92 fsdev_allocate_one_dev(struct rte_vdev_device *vdev,
93                        char *dirpath,
94                        char *devname,
95                        enum bcmfs_device_type dev_type __rte_unused)
96 {
97         struct bcmfs_device *fsdev;
98         uint32_t i;
99
100         fsdev = rte_calloc(__func__, 1, sizeof(*fsdev), 0);
101         if (!fsdev)
102                 return NULL;
103
104         if (strlen(dirpath) > sizeof(fsdev->dirname)) {
105                 BCMFS_LOG(ERR, "dir path name is too long");
106                 goto cleanup;
107         }
108
109         if (strlen(devname) > sizeof(fsdev->name)) {
110                 BCMFS_LOG(ERR, "devname is too long");
111                 goto cleanup;
112         }
113
114         /* check if registered ops name is present in directory path */
115         for (i = 0; i < bcmfs_hw_queue_pair_ops_table.num_ops; i++)
116                 if (strstr(dirpath,
117                            bcmfs_hw_queue_pair_ops_table.qp_ops[i].name))
118                         fsdev->sym_hw_qp_ops =
119                                 &bcmfs_hw_queue_pair_ops_table.qp_ops[i];
120         if (!fsdev->sym_hw_qp_ops)
121                 goto cleanup;
122
123         strcpy(fsdev->dirname, dirpath);
124         strcpy(fsdev->name, devname);
125
126         fsdev->vdev = vdev;
127
128         /* attach to VFIO */
129         if (bcmfs_attach_vfio(fsdev))
130                 goto cleanup;
131
132         /* Maximum number of QPs supported */
133         fsdev->max_hw_qps = fsdev->mmap_size / BCMFS_HW_QUEUE_IO_ADDR_LEN;
134
135         TAILQ_INSERT_TAIL(&fsdev_list, fsdev, next);
136
137         return fsdev;
138
139 cleanup:
140         free(fsdev);
141
142         return NULL;
143 }
144
145 static struct bcmfs_device *
146 find_fsdev(struct rte_vdev_device *vdev)
147 {
148         struct bcmfs_device *fsdev;
149
150         TAILQ_FOREACH(fsdev, &fsdev_list, next)
151                 if (fsdev->vdev == vdev)
152                         return fsdev;
153
154         return NULL;
155 }
156
157 static void
158 fsdev_release(struct bcmfs_device *fsdev)
159 {
160         if (fsdev == NULL)
161                 return;
162
163         TAILQ_REMOVE(&fsdev_list, fsdev, next);
164         free(fsdev);
165 }
166
167 static int
168 cmprator(const void *a, const void *b)
169 {
170         return (*(const unsigned int *)a - *(const unsigned int *)b);
171 }
172
173 static int
174 fsdev_find_all_devs(const char *path, const char *search,
175                     uint32_t *devs)
176 {
177         DIR *dir;
178         struct dirent *entry;
179         int count = 0;
180         char addr[BCMFS_MAX_NODES][BCMFS_MAX_PATH_LEN];
181         int i;
182
183         dir = opendir(path);
184         if (dir == NULL) {
185                 BCMFS_LOG(ERR, "Unable to open directory");
186                 return 0;
187         }
188
189         while ((entry = readdir(dir)) != NULL) {
190                 if (strstr(entry->d_name, search)) {
191                         strlcpy(addr[count], entry->d_name,
192                                 BCMFS_MAX_PATH_LEN);
193                         count++;
194                 }
195         }
196
197         closedir(dir);
198
199         for (i = 0 ; i < count; i++)
200                 devs[i] = (uint32_t)strtoul(addr[i], NULL, 16);
201         /* sort the devices based on IO addresses */
202         qsort(devs, count, sizeof(uint32_t), cmprator);
203
204         return count;
205 }
206
207 static bool
208 fsdev_find_sub_dir(char *path, const char *search, char *output)
209 {
210         DIR *dir;
211         struct dirent *entry;
212
213         dir = opendir(path);
214         if (dir == NULL) {
215                 BCMFS_LOG(ERR, "Unable to open directory");
216                 return -ENODEV;
217         }
218
219         while ((entry = readdir(dir)) != NULL) {
220                 if (!strcmp(entry->d_name, search)) {
221                         strlcpy(output, entry->d_name, BCMFS_MAX_PATH_LEN);
222                         closedir(dir);
223                         return true;
224                 }
225         }
226
227         closedir(dir);
228
229         return false;
230 }
231
232
233 static int
234 bcmfs_vdev_probe(struct rte_vdev_device *vdev)
235 {
236         struct bcmfs_device *fsdev;
237         char top_dirpath[BCMFS_MAX_PATH_LEN];
238         char sub_dirpath[BCMFS_MAX_PATH_LEN];
239         char out_dirpath[BCMFS_MAX_PATH_LEN];
240         char out_dirname[BCMFS_MAX_PATH_LEN];
241         uint32_t fsdev_dev[BCMFS_MAX_NODES];
242         enum bcmfs_device_type dtype;
243         int i = 0;
244         int dev_idx;
245         int count = 0;
246         bool found = false;
247
248         sprintf(top_dirpath, "%s", SYSFS_BCM_PLTFORM_DEVICES);
249         while (strlen(dev_table[i].name)) {
250                 found = fsdev_find_sub_dir(top_dirpath,
251                                            dev_table[i].name,
252                                            sub_dirpath);
253                 if (found)
254                         break;
255                 i++;
256         }
257         if (!found) {
258                 BCMFS_LOG(ERR, "No supported bcmfs dev found");
259                 return -ENODEV;
260         }
261
262         dev_idx = i;
263         dtype = dev_table[i].type;
264
265         snprintf(out_dirpath, sizeof(out_dirpath), "%s/%s",
266                  top_dirpath, sub_dirpath);
267         count = fsdev_find_all_devs(out_dirpath,
268                                     dev_table[dev_idx].suffix,
269                                     fsdev_dev);
270         if (!count) {
271                 BCMFS_LOG(ERR, "No supported bcmfs dev found");
272                 return -ENODEV;
273         }
274
275         i = 0;
276         while (count) {
277                 /* format the device name present in the patch */
278                 snprintf(out_dirname, sizeof(out_dirname), "%x.%s",
279                          fsdev_dev[i], dev_table[dev_idx].suffix);
280                 fsdev = fsdev_allocate_one_dev(vdev, out_dirpath,
281                                                out_dirname, dtype);
282                 if (!fsdev) {
283                         count--;
284                         i++;
285                         continue;
286                 }
287                 break;
288         }
289         if (fsdev == NULL) {
290                 BCMFS_LOG(ERR, "All supported devs busy");
291                 return -ENODEV;
292         }
293
294         return 0;
295 }
296
297 static int
298 bcmfs_vdev_remove(struct rte_vdev_device *vdev)
299 {
300         struct bcmfs_device *fsdev;
301
302         fsdev = find_fsdev(vdev);
303         if (fsdev == NULL)
304                 return -ENODEV;
305
306         fsdev_release(fsdev);
307         return 0;
308 }
309
310 /* Register with vdev */
311 static struct rte_vdev_driver rte_bcmfs_pmd = {
312         .probe = bcmfs_vdev_probe,
313         .remove = bcmfs_vdev_remove
314 };
315
316 RTE_PMD_REGISTER_VDEV(bcmfs_pmd,
317                       rte_bcmfs_pmd);