Branch data Line data Source code
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 : 0 : file_name_match_extract(const char filename[], const char match[], int *number)
108 : : {
109 : : char *substr = NULL;
110 : :
111 : 0 : substr = strstr(filename, match);
112 [ # # ]: 0 : if (substr == NULL)
113 : : return false;
114 : :
115 : : /* substring <match> was found in <filename>
116 : : * read number following <match> substring in <filename>
117 : : */
118 [ # # ]: 0 : if (sscanf(filename + strlen(match), "%d", number) <= 0)
119 : 0 : 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 : 0 : 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 [ # # ]: 0 : 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 : 0 : ret = read(fd, line, SEC_UIO_MAX_DEVICE_FILE_NAME_LENGTH);
153 : 0 : close(fd);
154 : :
155 : : /* NULL-ify string */
156 : 0 : line[SEC_UIO_MAX_DEVICE_FILE_NAME_LENGTH - 1] = '\0';
157 : :
158 [ # # ]: 0 : if (ret <= 0) {
159 : 0 : CAAM_JR_ERR("Error reading from file %s", absolute_file_name);
160 : 0 : 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 : 0 : 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 : 0 : 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 : 0 : ret = sec_uio_send_command(uio_fd, SEC_UIO_ENABLE_IRQ_CMD);
215 [ # # ]: 0 : 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 : 0 : CAAM_JR_DEBUG("Enabled IRQs on jr with uio_fd %d", uio_fd);
220 : 0 : 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 : 0 : 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 : 0 : ret = sec_uio_send_command(uio_fd, SEC_UIO_DISABLE_IRQ_CMD);
247 [ # # ]: 0 : 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 : 0 : CAAM_JR_DEBUG("Disabled IRQs on jr with uio_fd %d", uio_fd);
252 : 0 : 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 : 0 : 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 : 0 : ret = file_read_first_line(uio_sys_root, uio_sys_map_subdir,
292 : : "size", uio_map_size_str);
293 [ # # ]: 0 : SEC_ASSERT(ret == 0, NULL, "file_read_first_line() failed");
294 : :
295 : : /* Read mapping size, expressed in hexa(base 16) */
296 : 0 : uio_map_size = strtol(uio_map_size_str, NULL, 16);
297 : :
298 : : /* Map the region in user space */
299 : 0 : 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 [ # # ]: 0 : if (mapped_address == MAP_FAILED) {
306 : 0 : 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 : 0 : return NULL;
311 : : }
312 : :
313 : : /*
314 : : * Save the map size to use it later on for munmap-ing.
315 : : */
316 : 0 : *map_size = uio_map_size;
317 : :
318 : 0 : 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 : 0 : return mapped_address;
322 : : }
323 : :
324 : : void
325 : 0 : free_job_ring(int uio_fd)
326 : : {
327 : : struct uio_job_ring *job_ring = NULL;
328 : : int i;
329 : :
330 [ # # ]: 0 : if (uio_fd == -1)
331 : : return;
332 : :
333 [ # # ]: 0 : for (i = 0; i < MAX_SEC_JOB_RINGS; i++) {
334 [ # # ]: 0 : if (g_uio_job_ring[i].uio_fd == uio_fd) {
335 : 0 : job_ring = &g_uio_job_ring[i];
336 : 0 : break;
337 : : }
338 : : }
339 : :
340 [ # # ]: 0 : if (job_ring == NULL) {
341 : 0 : CAAM_JR_ERR("JR not available for fd = %x\n", uio_fd);
342 : 0 : return;
343 : : }
344 : :
345 : : /* Open device file */
346 : 0 : CAAM_JR_INFO("Closed device file for job ring %d , fd = %d",
347 : : job_ring->jr_id, job_ring->uio_fd);
348 : 0 : close(job_ring->uio_fd);
349 : 0 : g_uio_jr_num--;
350 : 0 : job_ring->uio_fd = -1;
351 [ # # ]: 0 : if (job_ring->register_base_addr == NULL)
352 : : return;
353 : :
354 : : /* Unmap the PCI memory resource of device */
355 [ # # ]: 0 : if (munmap(job_ring->register_base_addr, job_ring->map_size)) {
356 : 0 : 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 : 0 : CAAM_JR_DEBUG("JR UIO memory is unmapped");
361 : :
362 : 0 : job_ring->register_base_addr = NULL;
363 : : }
364 : :
365 : : struct
366 : 0 : 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 [ # # ]: 0 : for (i = 0; i < MAX_SEC_JOB_RINGS; i++) {
373 [ # # ]: 0 : if (g_uio_job_ring[i].uio_fd == -1) {
374 : 0 : job_ring = &g_uio_job_ring[i];
375 : 0 : g_uio_jr_num++;
376 : 0 : break;
377 : : }
378 : : }
379 : :
380 [ # # ]: 0 : if (job_ring == NULL) {
381 : 0 : CAAM_JR_ERR("No free job ring\n");
382 : 0 : 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 : 0 : 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 : 0 : job_ring->uio_fd = open(uio_device_file_name, O_RDWR);
392 [ # # ]: 0 : 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 : 0 : 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 : 0 : 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 [ # # ]: 0 : SEC_ASSERT(job_ring->register_base_addr != NULL, NULL,
405 : : "Failed to map SEC registers");
406 : : return job_ring;
407 : : }
408 : :
409 : : int
410 : 0 : sec_configure(void)
411 : : {
412 : : char uio_name[32];
413 : 0 : int config_jr_no = 0, jr_id = -1;
414 : 0 : int uio_minor_number = -1;
415 : : int ret;
416 : : DIR *d = NULL;
417 : : struct dirent *dir;
418 : :
419 : 0 : d = opendir(SEC_UIO_DEVICE_SYS_ATTR_PATH);
420 [ # # ]: 0 : if (d == NULL) {
421 : 0 : printf("\nError opening directory '%s': %s\n",
422 : 0 : SEC_UIO_DEVICE_SYS_ATTR_PATH, strerror(errno));
423 : 0 : return -1;
424 : : }
425 : :
426 : : /* Iterate through all subdirs */
427 [ # # ]: 0 : while ((dir = readdir(d)) != NULL) {
428 [ # # ]: 0 : if (!strncmp(dir->d_name, ".", 1) ||
429 [ # # ]: 0 : !strncmp(dir->d_name, "..", 2))
430 : 0 : continue;
431 : :
432 [ # # ]: 0 : 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 : 0 : ret = file_read_first_line(SEC_UIO_DEVICE_SYS_ATTR_PATH,
441 : : dir->d_name, "name", uio_name);
442 : 0 : CAAM_JR_INFO("sec device uio name: %s", uio_name);
443 [ # # ]: 0 : if (ret != 0) {
444 : 0 : CAAM_JR_ERR("file_read_first_line failed\n");
445 : 0 : closedir(d);
446 : 0 : return -1;
447 : : }
448 : :
449 [ # # ]: 0 : if (file_name_match_extract(uio_name,
450 : : SEC_UIO_DEVICE_NAME,
451 : : &jr_id)) {
452 : 0 : g_uio_job_ring[config_jr_no].jr_id = jr_id;
453 : 0 : g_uio_job_ring[config_jr_no].uio_minor_number =
454 : : uio_minor_number;
455 : 0 : CAAM_JR_INFO("Detected logical JRID:%d", jr_id);
456 : 0 : config_jr_no++;
457 : :
458 : : /* todo find the actual ring id
459 : : * OF_FULLNAME=/soc/crypto@1700000/jr@20000
460 : : */
461 : : }
462 : : }
463 : : }
464 : 0 : closedir(d);
465 : :
466 [ # # ]: 0 : if (config_jr_no == 0) {
467 : 0 : CAAM_JR_ERR("! No SEC Job Rings assigned for userspace usage!");
468 : 0 : return 0;
469 : : }
470 : 0 : CAAM_JR_INFO("Total JR detected =%d", config_jr_no);
471 : 0 : return config_jr_no;
472 : : }
473 : :
474 : : int
475 : 0 : sec_cleanup(void)
476 : : {
477 : : int i;
478 : : struct uio_job_ring *job_ring;
479 : :
480 [ # # ]: 0 : for (i = 0; i < g_uio_jr_num; i++) {
481 : : job_ring = &g_uio_job_ring[i];
482 : : /* munmap SEC's register memory */
483 [ # # ]: 0 : if (job_ring->register_base_addr) {
484 : 0 : munmap(job_ring->register_base_addr,
485 : 0 : job_ring->map_size);
486 : 0 : 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 [ # # ]: 0 : if (job_ring->uio_fd != -1) {
492 : 0 : CAAM_JR_INFO(
493 : : "Closed device file for job ring %d , fd = %d",
494 : : job_ring->jr_id, job_ring->uio_fd);
495 : 0 : close(job_ring->uio_fd);
496 : 0 : job_ring->uio_fd = -1;
497 : : }
498 : : }
499 : 0 : return 0;
500 : : }
501 : :
502 : : void
503 : 235 : sec_uio_job_rings_init(void)
504 : : {
505 : : int i;
506 : :
507 [ + + ]: 1175 : for (i = 0; i < MAX_SEC_JOB_RINGS; i++)
508 : 940 : g_uio_job_ring[i].uio_fd = -1;
509 : 235 : }
|