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