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