xref: /dpdk/drivers/crypto/caam_jr/caam_jr_uio.c (revision f665790a5dbad7b645ff46f31d65e977324e7bfc)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright 2017-2018 NXP
3  */
4 
5 #include <stdbool.h>
6 #include <stdint.h>
7 #include <stdio.h>
8 #include <unistd.h>
9 #include <stdlib.h>
10 #include <dirent.h>
11 #include <string.h>
12 #include <sys/mman.h>
13 #include <errno.h>
14 #include <fcntl.h>
15 
16 #include <rte_common.h>
17 #include <rte_malloc.h>
18 #include <rte_crypto.h>
19 #include <rte_security.h>
20 
21 #include <caam_jr_config.h>
22 #include <caam_jr_hw_specific.h>
23 #include <caam_jr_pvt.h>
24 #include <caam_jr_log.h>
25 
26 /* Prefix path to sysfs directory where UIO device attributes are exported.
27  * Path for UIO device X is /sys/class/uio/uioX
28  */
29 #define SEC_UIO_DEVICE_SYS_ATTR_PATH    "/sys/class/uio"
30 
31 /* Subfolder in sysfs where mapping attributes are exported
32  * for each UIO device. Path for mapping Y for device X is:
33  *      /sys/class/uio/uioX/maps/mapY
34  */
35 #define SEC_UIO_DEVICE_SYS_MAP_ATTR     "maps/map"
36 
37 /* Name of UIO device file prefix. Each UIO device will have a device file
38  * /dev/uioX, where X is the minor device number.
39  */
40 #define SEC_UIO_DEVICE_FILE_NAME    "/dev/uio"
41 
42 /*
43  * Name of UIO device. Each user space SEC job ring will have a corresponding
44  * UIO device with the name sec-channelX, where X is the job ring id.
45  * Maximum length is #SEC_UIO_MAX_DEVICE_NAME_LENGTH.
46  *
47  * @note  Must be kept in synch with SEC kernel driver
48  * define #SEC_UIO_DEVICE_NAME !
49  */
50 #define SEC_UIO_DEVICE_NAME     "fsl-jr"
51 
52 /* Maximum length for the name of an UIO device file.
53  * Device file name format is: /dev/uioX.
54  */
55 #define SEC_UIO_MAX_DEVICE_FILE_NAME_LENGTH 30
56 
57 /* Maximum length for the name of an attribute file for an UIO device.
58  * Attribute files are exported in sysfs and have the name formatted as:
59  *      /sys/class/uio/uioX/<attribute_file_name>
60  */
61 #define SEC_UIO_MAX_ATTR_FILE_NAME  100
62 
63 /* Command that is used by SEC user space driver and SEC kernel driver
64  *  to signal a request from the former to the later to disable job DONE
65  *  and error IRQs on a certain job ring.
66  *  The configuration is done at SEC Controller's level.
67  *  @note   Need to be kept in synch with #SEC_UIO_DISABLE_IRQ_CMD from
68  *          linux/drivers/crypto/talitos.c !
69  */
70 #define SEC_UIO_DISABLE_IRQ_CMD     0
71 
72 /* Command that is used by SEC user space driver and SEC kernel driver
73  *  to signal a request from the former to the later to enable job DONE
74  *  and error IRQs on a certain job ring.
75  *  The configuration is done at SEC Controller's level.
76  *  @note   Need to be kept in synch with #SEC_UIO_ENABLE_IRQ_CMD from
77  *          linux/drivers/crypto/talitos.c !
78  */
79 #define SEC_UIO_ENABLE_IRQ_CMD      1
80 
81 /** Command that is used by SEC user space driver and SEC kernel driver
82  *  to signal a request from the former to the later to do a SEC engine reset.
83  *  @note   Need to be kept in synch with #SEC_UIO_RESET_SEC_ENGINE_CMD from
84  *          linux/drivers/crypto/talitos.c !
85  */
86 #define SEC_UIO_RESET_SEC_ENGINE_CMD    3
87 
88 /* The id for the mapping used to export SEC's registers to
89  * user space through UIO devices.
90  */
91 #define SEC_UIO_MAP_ID              0
92 
93 static struct uio_job_ring g_uio_job_ring[MAX_SEC_JOB_RINGS];
94 static int g_uio_jr_num;
95 
96 /** @brief Checks if a file name contains a certain substring.
97  * If so, it extracts the number following the substring.
98  * This function assumes a filename format of: [text][number].
99  * @param [in]  filename    File name
100  * @param [in]  match       String to match in file name
101  * @param [out] number      The number extracted from filename
102  *
103  * @retval true if file name matches the criteria
104  * @retval false if file name does not match the criteria
105  */
106 static bool
107 file_name_match_extract(const char filename[], const char match[], int *number)
108 {
109 	char *substr = NULL;
110 
111 	substr = strstr(filename, match);
112 	if (substr == NULL)
113 		return false;
114 
115 	/* substring <match> was found in <filename>
116 	 * read number following <match> substring in <filename>
117 	 */
118 	if (sscanf(filename + strlen(match), "%d", number) <= 0)
119 		return false;
120 
121 	return true;
122 }
123 
124 /** @brief Reads first line from a file.
125  * Composes file name as: root/subdir/filename
126  *
127  * @param [in]  root     Root path
128  * @param [in]  subdir   Subdirectory name
129  * @param [in]  filename File name
130  * @param [out] line     The first line read from file.
131  *
132  * @retval 0 for succes
133  * @retval other value for error
134  */
135 static int
136 file_read_first_line(const char root[], const char subdir[],
137 		     const char filename[], char *line)
138 {
139 	char absolute_file_name[SEC_UIO_MAX_ATTR_FILE_NAME];
140 	int fd = 0, ret = 0;
141 
142 	/*compose the file name: root/subdir/filename */
143 	memset(absolute_file_name, 0, sizeof(absolute_file_name));
144 	snprintf(absolute_file_name, SEC_UIO_MAX_ATTR_FILE_NAME,
145 		 "%s/%s/%s", root, subdir, filename);
146 
147 	fd = open(absolute_file_name, O_RDONLY);
148 	SEC_ASSERT(fd >= 0, fd, "Error opening file %s",
149 			absolute_file_name);
150 
151 	/* read UIO device name from first line in file */
152 	ret = read(fd, line, SEC_UIO_MAX_DEVICE_FILE_NAME_LENGTH);
153 	close(fd);
154 
155 	/* NULL-ify string */
156 	line[SEC_UIO_MAX_DEVICE_FILE_NAME_LENGTH - 1] = '\0';
157 
158 	if (ret <= 0) {
159 		CAAM_JR_ERR("Error reading from file %s", absolute_file_name);
160 		return ret;
161 	}
162 
163 	return 0;
164 }
165 
166 /** @brief Uses UIO control to send commands to SEC kernel driver.
167  * The mechanism is to write a command word into the file descriptor
168  * that the user-space driver obtained for each user-space SEC job ring.
169  * Both user-space driver and kernel driver must have the same understanding
170  * about the command codes.
171  *
172  * @param [in]  UIO FD		    The UIO file descriptor
173  * @param [in]  uio_command         Command word
174  *
175  * @retval Result of write operation on the job ring's UIO file descriptor.
176  *         Should be sizeof(int) for success operations.
177  *         Other values can be returned and used, if desired to add special
178  *         meaning to return values, but this has to be programmed in SEC
179  *         kernel driver as well. No special return values are used.
180  */
181 static int
182 sec_uio_send_command(int uio_fd, int32_t uio_command)
183 {
184 	int ret;
185 
186 	/* Use UIO file descriptor we have for this job ring.
187 	 * Writing a command code to this file descriptor will make the
188 	 * SEC kernel driver execute the desired command.
189 	 */
190 	ret = write(uio_fd, &uio_command, sizeof(int));
191 	return ret;
192 }
193 
194 /** @brief Request to SEC kernel driver to enable interrupts for
195  *         descriptor finished processing
196  *  Use UIO to communicate with SEC kernel driver: write command
197  *  value that indicates an IRQ enable action into UIO file descriptor
198  *  of this job ring.
199  *
200  * @param [in]  uio_fd     Job Ring UIO File descriptor
201  * @retval 0 for success
202  * @retval -1 value for error
203  */
204 int
205 caam_jr_enable_irqs(int uio_fd)
206 {
207 	int ret;
208 
209 	/* Use UIO file descriptor we have for this job ring.
210 	 * Writing a command code to this file descriptor will make the
211 	 * SEC kernel driver enable DONE and Error IRQs for this job ring,
212 	 * at Controller level.
213 	 */
214 	ret = sec_uio_send_command(uio_fd, SEC_UIO_ENABLE_IRQ_CMD);
215 	SEC_ASSERT(ret == sizeof(int), -1,
216 		"Failed to request SEC engine to enable job done and "
217 		"error IRQs through UIO control. UIO FD %d. Reset SEC driver!",
218 		uio_fd);
219 	CAAM_JR_DEBUG("Enabled IRQs on jr with uio_fd %d", uio_fd);
220 	return 0;
221 }
222 
223 
224 /** @brief Request to SEC kernel driver to disable interrupts for descriptor
225  *  finished processing
226  *  Use UIO to communicate with SEC kernel driver: write command
227  *  value that indicates an IRQ disable action into UIO file descriptor
228  *  of this job ring.
229  *
230  * @param [in]  uio_fd    UIO File descriptor
231  * @retval 0 for success
232  * @retval -1 value for error
233  *
234  */
235 int
236 caam_jr_disable_irqs(int uio_fd)
237 {
238 	int ret;
239 
240 	/* Use UIO file descriptor we have for this job ring.
241 	 * Writing a command code to this file descriptor will make the
242 	 * SEC kernel driver disable IRQs for this job ring,
243 	 * at Controller level.
244 	 */
245 
246 	ret = sec_uio_send_command(uio_fd, SEC_UIO_DISABLE_IRQ_CMD);
247 	SEC_ASSERT(ret == sizeof(int), -1,
248 		"Failed to request SEC engine to disable job done and "
249 		"IRQs through UIO control. UIO_FD %d Reset SEC driver!",
250 		uio_fd);
251 	CAAM_JR_DEBUG("Disabled IRQs on jr with uio_fd %d", uio_fd);
252 	return 0;
253 }
254 
255 /** @brief Maps register range assigned for a job ring.
256  *
257  * @param [in] uio_device_fd    UIO device file descriptor
258  * @param [in] uio_device_id    UIO device id
259  * @param [in] uio_map_id       UIO allows maximum 5 different mapping for
260 				each device. Maps start with id 0.
261  * @param [out] map_size        Map size.
262  * @retval  NULL if failed to map registers
263  * @retval  Virtual address for mapped register address range
264  */
265 static void *
266 uio_map_registers(int uio_device_fd, int uio_device_id,
267 		  int uio_map_id, int *map_size)
268 {
269 	void *mapped_address = NULL;
270 	unsigned int uio_map_size = 0;
271 	char uio_sys_root[SEC_UIO_MAX_ATTR_FILE_NAME];
272 	char uio_sys_map_subdir[SEC_UIO_MAX_ATTR_FILE_NAME];
273 	char uio_map_size_str[32];
274 	int ret = 0;
275 
276 	/* compose the file name: root/subdir/filename */
277 	memset(uio_sys_root, 0, sizeof(uio_sys_root));
278 	memset(uio_sys_map_subdir, 0, sizeof(uio_sys_map_subdir));
279 	memset(uio_map_size_str, 0, sizeof(uio_map_size_str));
280 
281 	/* Compose string: /sys/class/uio/uioX */
282 	snprintf(uio_sys_root, sizeof(uio_sys_root), "%s/%s%d",
283 			SEC_UIO_DEVICE_SYS_ATTR_PATH, "uio", uio_device_id);
284 	/* Compose string: maps/mapY */
285 	snprintf(uio_sys_map_subdir, sizeof(uio_sys_map_subdir), "%s%d",
286 			SEC_UIO_DEVICE_SYS_MAP_ATTR, uio_map_id);
287 
288 	/* Read first (and only) line from file
289 	 * /sys/class/uio/uioX/maps/mapY/size
290 	 */
291 	ret = file_read_first_line(uio_sys_root, uio_sys_map_subdir,
292 				 "size", uio_map_size_str);
293 	SEC_ASSERT(ret == 0, NULL, "file_read_first_line() failed");
294 
295 	/* Read mapping size, expressed in hexa(base 16) */
296 	uio_map_size = strtol(uio_map_size_str, NULL, 16);
297 
298 	/* Map the region in user space */
299 	mapped_address = mmap(0, /*dynamically choose virtual address */
300 		uio_map_size, PROT_READ | PROT_WRITE,
301 		MAP_SHARED, uio_device_fd, 0);
302 	/* offset = 0 because UIO device has only one mapping
303 	 * for the entire SEC register memory
304 	 */
305 	if (mapped_address == MAP_FAILED) {
306 		CAAM_JR_ERR(
307 			"Failed to map registers! errno = %d job ring fd  = %d,"
308 			"uio device id = %d, uio map id = %d", errno,
309 			uio_device_fd, uio_device_id, uio_map_id);
310 		return NULL;
311 	}
312 
313 	/*
314 	 * Save the map size to use it later on for munmap-ing.
315 	 */
316 	*map_size = uio_map_size;
317 
318 	CAAM_JR_INFO("UIO dev[%d] mapped region [id =%d] size 0x%x at %p",
319 		uio_device_id, uio_map_id, uio_map_size, mapped_address);
320 
321 	return mapped_address;
322 }
323 
324 void
325 free_job_ring(int uio_fd)
326 {
327 	struct uio_job_ring *job_ring = NULL;
328 	int i;
329 
330 	if (uio_fd == -1)
331 		return;
332 
333 	for (i = 0; i < MAX_SEC_JOB_RINGS; i++) {
334 		if (g_uio_job_ring[i].uio_fd == uio_fd) {
335 			job_ring = &g_uio_job_ring[i];
336 			break;
337 		}
338 	}
339 
340 	if (job_ring == NULL) {
341 		CAAM_JR_ERR("JR not available for fd = %x", uio_fd);
342 		return;
343 	}
344 
345 	/* Open device file */
346 	CAAM_JR_INFO("Closed device file for job ring %d , fd = %d",
347 			job_ring->jr_id, job_ring->uio_fd);
348 	close(job_ring->uio_fd);
349 	g_uio_jr_num--;
350 	job_ring->uio_fd = -1;
351 	if (job_ring->register_base_addr == NULL)
352 		return;
353 
354 	/* Unmap the PCI memory resource of device */
355 	if (munmap(job_ring->register_base_addr, job_ring->map_size)) {
356 		CAAM_JR_INFO("cannot munmap(%p, 0x%lx): %s",
357 			job_ring->register_base_addr,
358 			(unsigned long)job_ring->map_size, strerror(errno));
359 	} else
360 		CAAM_JR_DEBUG("JR UIO memory is unmapped");
361 
362 	job_ring->register_base_addr = NULL;
363 }
364 
365 struct
366 uio_job_ring *config_job_ring(void)
367 {
368 	char uio_device_file_name[32];
369 	struct uio_job_ring *job_ring = NULL;
370 	int i;
371 
372 	for (i = 0; i < MAX_SEC_JOB_RINGS; i++) {
373 		if (g_uio_job_ring[i].uio_fd == -1) {
374 			job_ring = &g_uio_job_ring[i];
375 			g_uio_jr_num++;
376 			break;
377 		}
378 	}
379 
380 	if (job_ring == NULL) {
381 		CAAM_JR_ERR("No free job ring");
382 		return NULL;
383 	}
384 
385 	/* Find UIO device created by SEC kernel driver for this job ring. */
386 	memset(uio_device_file_name, 0, sizeof(uio_device_file_name));
387 	snprintf(uio_device_file_name, sizeof(uio_device_file_name), "%s%d",
388 			SEC_UIO_DEVICE_FILE_NAME, job_ring->uio_minor_number);
389 
390 	/* Open device file */
391 	job_ring->uio_fd = open(uio_device_file_name, O_RDWR);
392 	SEC_ASSERT(job_ring->uio_fd >= 0, NULL,
393 		"Failed to open UIO device file for job ring %d",
394 		job_ring->jr_id);
395 
396 	CAAM_JR_INFO("Open device(%s) file for job ring=%d , uio_fd = %d",
397 		uio_device_file_name, job_ring->jr_id, job_ring->uio_fd);
398 
399 	ASSERT(job_ring->register_base_addr == NULL);
400 	job_ring->register_base_addr = uio_map_registers(
401 			job_ring->uio_fd, job_ring->uio_minor_number,
402 			SEC_UIO_MAP_ID, &job_ring->map_size);
403 
404 	SEC_ASSERT(job_ring->register_base_addr != NULL, NULL,
405 		"Failed to map SEC registers");
406 	return job_ring;
407 }
408 
409 int
410 sec_configure(void)
411 {
412 	char uio_name[32];
413 	int config_jr_no = 0, jr_id = -1;
414 	int uio_minor_number = -1;
415 	int ret;
416 	DIR *d = NULL;
417 	struct dirent *dir;
418 
419 	d = opendir(SEC_UIO_DEVICE_SYS_ATTR_PATH);
420 	if (d == NULL) {
421 		CAAM_JR_ERR("Error opening directory '%s': %s",
422 			SEC_UIO_DEVICE_SYS_ATTR_PATH, strerror(errno));
423 		return -1;
424 	}
425 
426 	/* Iterate through all subdirs */
427 	while ((dir = readdir(d)) != NULL) {
428 		if (!strncmp(dir->d_name, ".", 1) ||
429 				!strncmp(dir->d_name, "..", 2))
430 			continue;
431 
432 		if (file_name_match_extract
433 			(dir->d_name, "uio", &uio_minor_number)) {
434 		/*
435 		 * Open file uioX/name and read first line which contains
436 		 * the name for the device. Based on the name check if this
437 		 * UIO device is UIO device for job ring with id jr_id.
438 		 */
439 			memset(uio_name, 0, sizeof(uio_name));
440 			ret = file_read_first_line(SEC_UIO_DEVICE_SYS_ATTR_PATH,
441 					dir->d_name, "name", uio_name);
442 			CAAM_JR_INFO("sec device uio name: %s", uio_name);
443 			if (ret != 0) {
444 				CAAM_JR_ERR("file_read_first_line failed");
445 				closedir(d);
446 				return -1;
447 			}
448 
449 			if (file_name_match_extract(uio_name,
450 						SEC_UIO_DEVICE_NAME,
451 						&jr_id)) {
452 				g_uio_job_ring[config_jr_no].jr_id = jr_id;
453 				g_uio_job_ring[config_jr_no].uio_minor_number =
454 							uio_minor_number;
455 				CAAM_JR_INFO("Detected logical JRID:%d", jr_id);
456 				config_jr_no++;
457 
458 				/* todo  find the actual ring id
459 				 * OF_FULLNAME=/soc/crypto@1700000/jr@20000
460 				 */
461 			}
462 		}
463 	}
464 	closedir(d);
465 
466 	if (config_jr_no == 0) {
467 		CAAM_JR_ERR("! No SEC Job Rings assigned for userspace usage!");
468 		return 0;
469 	}
470 	CAAM_JR_INFO("Total JR detected =%d", config_jr_no);
471 	return config_jr_no;
472 }
473 
474 int
475 sec_cleanup(void)
476 {
477 	int i;
478 	struct uio_job_ring *job_ring;
479 
480 	for (i = 0; i < g_uio_jr_num; i++) {
481 		job_ring = &g_uio_job_ring[i];
482 		/* munmap SEC's register memory */
483 		if (job_ring->register_base_addr) {
484 			munmap(job_ring->register_base_addr,
485 				job_ring->map_size);
486 			job_ring->register_base_addr = NULL;
487 		}
488 		/* I need to close the fd after shutdown UIO commands need to be
489 		 * sent using the fd
490 		 */
491 		if (job_ring->uio_fd != -1) {
492 			CAAM_JR_INFO(
493 			"Closed device file for job ring %d , fd = %d",
494 			job_ring->jr_id, job_ring->uio_fd);
495 			close(job_ring->uio_fd);
496 			job_ring->uio_fd = -1;
497 		}
498 	}
499 	return 0;
500 }
501 
502 void
503 sec_uio_job_rings_init(void)
504 {
505 	int i;
506 
507 	for (i = 0; i < MAX_SEC_JOB_RINGS; i++)
508 		g_uio_job_ring[i].uio_fd = -1;
509 }
510