crypto/caam_jr: fix check of file descriptors
[dpdk.git] / drivers / crypto / caam_jr / caam_jr_uio.c
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 uint32_t
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 descripto
231  * @retval 0 for success
232  * @retval -1 value for error
233  *
234  */
235 uint32_t
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\n", 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\n");
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                 printf("\nError opening directory '%s': %s\n",
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\n");
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 }