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