1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright 2017-2018 NXP
16 #include <rte_common.h>
17 #include <rte_malloc.h>
18 #include <rte_crypto.h>
19 #include <rte_security.h>
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>
26 /* Prefix path to sysfs directory where UIO device attributes are exported.
27 * Path for UIO device X is /sys/class/uio/uioX
29 #define SEC_UIO_DEVICE_SYS_ATTR_PATH "/sys/class/uio"
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
35 #define SEC_UIO_DEVICE_SYS_MAP_ATTR "maps/map"
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.
40 #define SEC_UIO_DEVICE_FILE_NAME "/dev/uio"
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.
47 * @note Must be kept in synch with SEC kernel driver
48 * define #SEC_UIO_DEVICE_NAME !
50 #define SEC_UIO_DEVICE_NAME "fsl-jr"
52 /* Maximum length for the name of an UIO device file.
53 * Device file name format is: /dev/uioX.
55 #define SEC_UIO_MAX_DEVICE_FILE_NAME_LENGTH 30
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>
61 #define SEC_UIO_MAX_ATTR_FILE_NAME 100
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 !
70 #define SEC_UIO_DISABLE_IRQ_CMD 0
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 !
79 #define SEC_UIO_ENABLE_IRQ_CMD 1
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 !
86 #define SEC_UIO_RESET_SEC_ENGINE_CMD 3
88 /* The id for the mapping used to export SEC's registers to
89 * user space through UIO devices.
91 #define SEC_UIO_MAP_ID 0
93 static struct uio_job_ring g_uio_job_ring[MAX_SEC_JOB_RINGS];
94 static int g_uio_jr_num;
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
103 * @retval true if file name matches the criteria
104 * @retval false if file name does not match the criteria
107 file_name_match_extract(const char filename[], const char match[], int *number)
111 substr = strstr(filename, match);
115 /* substring <match> was found in <filename>
116 * read number following <match> substring in <filename>
118 if (sscanf(filename + strlen(match), "%d", number) <= 0)
124 /** @brief Reads first line from a file.
125 * Composes file name as: root/subdir/filename
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.
132 * @retval 0 for succes
133 * @retval other value for error
136 file_read_first_line(const char root[], const char subdir[],
137 const char filename[], char *line)
139 char absolute_file_name[SEC_UIO_MAX_ATTR_FILE_NAME];
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);
147 fd = open(absolute_file_name, O_RDONLY);
148 SEC_ASSERT(fd > 0, fd, "Error opening file %s",
151 /* read UIO device name from first line in file */
152 ret = read(fd, line, SEC_UIO_MAX_DEVICE_FILE_NAME_LENGTH);
155 /* NULL-ify string */
156 line[SEC_UIO_MAX_DEVICE_FILE_NAME_LENGTH - 1] = '\0';
159 CAAM_JR_ERR("Error reading from file %s", absolute_file_name);
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.
172 * @param [in] UIO FD The UIO file descriptor
173 * @param [in] uio_command Command word
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.
182 sec_uio_send_command(uint32_t uio_fd, int32_t uio_command)
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.
190 ret = write(uio_fd, &uio_command, sizeof(int));
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
200 * @param [in] uio_fd Job Ring UIO File descriptor
201 * @retval 0 for success
202 * @retval -1 value for error
205 caam_jr_enable_irqs(uint32_t uio_fd)
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.
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!",
219 CAAM_JR_DEBUG("Enabled IRQs on jr with uio_fd %d", uio_fd);
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
230 * @param [in] uio_fd UIO File descripto
231 * @retval 0 for success
232 * @retval -1 value for error
236 caam_jr_disable_irqs(uint32_t uio_fd)
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.
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!",
251 CAAM_JR_DEBUG("Disabled IRQs on jr with uio_fd %d", uio_fd);
255 /** @brief Maps register range assigned for a job ring.
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
266 uio_map_registers(int uio_device_fd, int uio_device_id,
267 int uio_map_id, int *map_size)
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];
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));
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);
288 /* Read first (and only) line from file
289 * /sys/class/uio/uioX/maps/mapY/size
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");
295 /* Read mapping size, expressed in hexa(base 16) */
296 uio_map_size = strtol(uio_map_size_str, NULL, 16);
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
305 if (mapped_address == MAP_FAILED) {
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);
314 * Save the map size to use it later on for munmap-ing.
316 *map_size = uio_map_size;
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);
321 return mapped_address;
325 free_job_ring(uint32_t uio_fd)
327 struct uio_job_ring *job_ring = NULL;
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];
340 if (job_ring == NULL) {
341 CAAM_JR_ERR("JR not available for fd = %x\n", uio_fd);
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);
350 job_ring->uio_fd = 0;
351 if (job_ring->register_base_addr == NULL)
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));
360 CAAM_JR_DEBUG("JR UIO memory is unmapped");
362 job_ring->register_base_addr = NULL;
366 uio_job_ring *config_job_ring(void)
368 char uio_device_file_name[32];
369 struct uio_job_ring *job_ring = NULL;
372 for (i = 0; i < MAX_SEC_JOB_RINGS; i++) {
373 if (g_uio_job_ring[i].uio_fd == 0) {
374 job_ring = &g_uio_job_ring[i];
380 if (job_ring == NULL) {
381 CAAM_JR_ERR("No free job ring\n");
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);
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",
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);
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);
404 SEC_ASSERT(job_ring->register_base_addr != NULL, NULL,
405 "Failed to map SEC registers");
413 int config_jr_no = 0, jr_id = -1;
414 int uio_minor_number = -1;
419 d = opendir(SEC_UIO_DEVICE_SYS_ATTR_PATH);
421 printf("\nError opening directory '%s': %s\n",
422 SEC_UIO_DEVICE_SYS_ATTR_PATH, strerror(errno));
426 /* Iterate through all subdirs */
427 while ((dir = readdir(d)) != NULL) {
428 if (!strncmp(dir->d_name, ".", 1) ||
429 !strncmp(dir->d_name, "..", 2))
432 if (file_name_match_extract
433 (dir->d_name, "uio", &uio_minor_number)) {
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.
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);
444 CAAM_JR_ERR("file_read_first_line failed\n");
449 if (file_name_match_extract(uio_name,
452 g_uio_job_ring[config_jr_no].jr_id = jr_id;
453 g_uio_job_ring[config_jr_no].uio_minor_number =
455 CAAM_JR_INFO("Detected logical JRID:%d", jr_id);
458 /* todo find the actual ring id
459 * OF_FULLNAME=/soc/crypto@1700000/jr@20000
466 if (config_jr_no == 0) {
467 CAAM_JR_ERR("! No SEC Job Rings assigned for userspace usage!");
470 CAAM_JR_INFO("Total JR detected =%d", config_jr_no);
478 struct uio_job_ring *job_ring;
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,
486 job_ring->register_base_addr = NULL;
488 /* I need to close the fd after shutdown UIO commands need to be
491 if (job_ring->uio_fd != 0) {
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);