]> git.proxmox.com Git - ceph.git/blob - ceph/src/spdk/dpdk/drivers/crypto/caam_jr/caam_jr_uio.c
import 15.2.0 Octopus source
[ceph.git] / ceph / src / spdk / dpdk / 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 }