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