New upstream version 18.11-rc1
[deb_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 /* 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         sprintf(uio_sys_root, "%s/%s%d", SEC_UIO_DEVICE_SYS_ATTR_PATH,
288                 "uio", uio_device_id);
289         /* Compose string: maps/mapY */
290         sprintf(uio_sys_map_subdir, "%s%d", SEC_UIO_DEVICE_SYS_MAP_ATTR,
291                 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 (!job_ring->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
393         sprintf(uio_device_file_name, "%s%d", SEC_UIO_DEVICE_FILE_NAME,
394                 job_ring->uio_minor_number);
395
396         /* Open device file */
397         job_ring->uio_fd = open(uio_device_file_name, O_RDWR);
398         SEC_ASSERT(job_ring->uio_fd > 0, NULL,
399                 "Failed to open UIO device file for job ring %d",
400                 job_ring->jr_id);
401
402         CAAM_JR_INFO("Open device(%s) file for job ring=%d , uio_fd = %d",
403                 uio_device_file_name, job_ring->jr_id, job_ring->uio_fd);
404
405         ASSERT(job_ring->register_base_addr == NULL);
406         job_ring->register_base_addr = uio_map_registers(
407                         job_ring->uio_fd, job_ring->uio_minor_number,
408                         SEC_UIO_MAP_ID, &job_ring->map_size);
409
410         SEC_ASSERT(job_ring->register_base_addr != NULL, NULL,
411                 "Failed to map SEC registers");
412         return job_ring;
413 }
414
415 int
416 sec_configure(void)
417 {
418         char uio_name[32];
419         int config_jr_no = 0, jr_id = -1;
420         int uio_minor_number = -1;
421         int ret;
422         DIR *d = NULL;
423         struct dirent *dir;
424
425         d = opendir(SEC_UIO_DEVICE_SYS_ATTR_PATH);
426         if (d == NULL) {
427                 printf("\nError opening directory '%s': %s\n",
428                         SEC_UIO_DEVICE_SYS_ATTR_PATH, strerror(errno));
429                 return -1;
430         }
431
432         /* Iterate through all subdirs */
433         while ((dir = readdir(d)) != NULL) {
434                 if (!strncmp(dir->d_name, ".", 1) ||
435                                 !strncmp(dir->d_name, "..", 2))
436                         continue;
437
438                 if (file_name_match_extract
439                         (dir->d_name, "uio", &uio_minor_number)) {
440                 /*
441                  * Open file uioX/name and read first line which contains
442                  * the name for the device. Based on the name check if this
443                  * UIO device is UIO device for job ring with id jr_id.
444                  */
445                         memset(uio_name, 0, sizeof(uio_name));
446                         ret = file_read_first_line(SEC_UIO_DEVICE_SYS_ATTR_PATH,
447                                         dir->d_name, "name", uio_name);
448                         CAAM_JR_INFO("sec device uio name: %s", uio_name);
449                         SEC_ASSERT(ret == 0, -1, "file_read_first_line failed");
450
451                         if (file_name_match_extract(uio_name,
452                                                 SEC_UIO_DEVICE_NAME,
453                                                 &jr_id)) {
454                                 g_uio_job_ring[config_jr_no].jr_id = jr_id;
455                                 g_uio_job_ring[config_jr_no].uio_minor_number =
456                                                         uio_minor_number;
457                                 CAAM_JR_INFO("Detected logical JRID:%d", jr_id);
458                                 config_jr_no++;
459
460                                 /* todo  find the actual ring id
461                                  * OF_FULLNAME=/soc/crypto@1700000/jr@20000
462                                  */
463                         }
464                 }
465         }
466         closedir(d);
467
468         if (config_jr_no == 0) {
469                 CAAM_JR_ERR("! No SEC Job Rings assigned for userspace usage!");
470                 return 0;
471         }
472         CAAM_JR_INFO("Total JR detected =%d", config_jr_no);
473         return config_jr_no;
474 }
475
476 int
477 sec_cleanup(void)
478 {
479         int i;
480         struct uio_job_ring *job_ring;
481
482         for (i = 0; i < g_uio_jr_num; i++) {
483                 job_ring = &g_uio_job_ring[i];
484                 /* munmap SEC's register memory */
485                 if (job_ring->register_base_addr) {
486                         munmap(job_ring->register_base_addr,
487                                 job_ring->map_size);
488                         job_ring->register_base_addr = NULL;
489                 }
490                 /* I need to close the fd after shutdown UIO commands need to be
491                  * sent using the fd
492                  */
493                 if (job_ring->uio_fd != 0) {
494                         CAAM_JR_INFO(
495                         "Closed device file for job ring %d , fd = %d",
496                         job_ring->jr_id, job_ring->uio_fd);
497                         close(job_ring->uio_fd);
498                 }
499         }
500         return 0;
501 }