net/mlx5: fix event handler uninstall
[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         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 is unmapped");
366
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                         if (ret != 0) {
449                                 CAAM_JR_ERR("file_read_first_line failed\n");
450                                 closedir(d);
451                                 return -1;
452                         }
453
454                         if (file_name_match_extract(uio_name,
455                                                 SEC_UIO_DEVICE_NAME,
456                                                 &jr_id)) {
457                                 g_uio_job_ring[config_jr_no].jr_id = jr_id;
458                                 g_uio_job_ring[config_jr_no].uio_minor_number =
459                                                         uio_minor_number;
460                                 CAAM_JR_INFO("Detected logical JRID:%d", jr_id);
461                                 config_jr_no++;
462
463                                 /* todo  find the actual ring id
464                                  * OF_FULLNAME=/soc/crypto@1700000/jr@20000
465                                  */
466                         }
467                 }
468         }
469         closedir(d);
470
471         if (config_jr_no == 0) {
472                 CAAM_JR_ERR("! No SEC Job Rings assigned for userspace usage!");
473                 return 0;
474         }
475         CAAM_JR_INFO("Total JR detected =%d", config_jr_no);
476         return config_jr_no;
477 }
478
479 int
480 sec_cleanup(void)
481 {
482         int i;
483         struct uio_job_ring *job_ring;
484
485         for (i = 0; i < g_uio_jr_num; i++) {
486                 job_ring = &g_uio_job_ring[i];
487                 /* munmap SEC's register memory */
488                 if (job_ring->register_base_addr) {
489                         munmap(job_ring->register_base_addr,
490                                 job_ring->map_size);
491                         job_ring->register_base_addr = NULL;
492                 }
493                 /* I need to close the fd after shutdown UIO commands need to be
494                  * sent using the fd
495                  */
496                 if (job_ring->uio_fd != 0) {
497                         CAAM_JR_INFO(
498                         "Closed device file for job ring %d , fd = %d",
499                         job_ring->jr_id, job_ring->uio_fd);
500                         close(job_ring->uio_fd);
501                 }
502         }
503         return 0;
504 }