crypto/ccp: enable IOMMU
[dpdk.git] / drivers / crypto / ccp / ccp_pci.c
1 /*   SPDX-License-Identifier: BSD-3-Clause
2  *   Copyright(c) 2018 Advanced Micro Devices, Inc. All rights reserved.
3  */
4
5 #include <dirent.h>
6 #include <fcntl.h>
7 #include <stdio.h>
8 #include <string.h>
9 #include <unistd.h>
10
11 #include <rte_string_fns.h>
12
13 #include "ccp_pci.h"
14
15 static const char * const uio_module_names[] = {
16         "igb_uio",
17         "uio_pci_generic",
18         "vfio_pci"
19 };
20
21 int
22 ccp_check_pci_uio_module(void)
23 {
24         FILE *fp;
25         int i;
26         char buf[BUFSIZ];
27
28         fp = fopen(PROC_MODULES, "r");
29         if (fp == NULL)
30                 return -1;
31         i = 0;
32         while (uio_module_names[i] != NULL) {
33                 while (fgets(buf, sizeof(buf), fp) != NULL) {
34                         if (!strncmp(buf, uio_module_names[i],
35                                      strlen(uio_module_names[i]))) {
36                                 fclose(fp);
37                                 return i;
38                         }
39                 }
40                 i++;
41                 rewind(fp);
42         }
43         fclose(fp);
44         printf("Insert igb_uio or uio_pci_generic kernel module(s)");
45         return -1;/* uio not inserted */
46 }
47
48 /*
49  * split up a pci address into its constituent parts.
50  */
51 int
52 ccp_parse_pci_addr_format(const char *buf, int bufsize, uint16_t *domain,
53                           uint8_t *bus, uint8_t *devid, uint8_t *function)
54 {
55         /* first split on ':' */
56         union splitaddr {
57                 struct {
58                         char *domain;
59                         char *bus;
60                         char *devid;
61                         char *function;
62                 };
63                 char *str[PCI_FMT_NVAL];
64                 /* last element-separator is "." not ":" */
65         } splitaddr;
66
67         char *buf_copy = strndup(buf, bufsize);
68
69         if (buf_copy == NULL)
70                 return -1;
71
72         if (rte_strsplit(buf_copy, bufsize, splitaddr.str, PCI_FMT_NVAL, ':')
73                         != PCI_FMT_NVAL - 1)
74                 goto error;
75         /* final split is on '.' between devid and function */
76         splitaddr.function = strchr(splitaddr.devid, '.');
77         if (splitaddr.function == NULL)
78                 goto error;
79         *splitaddr.function++ = '\0';
80
81         /* now convert to int values */
82         errno = 0;
83         *domain = (uint8_t)strtoul(splitaddr.domain, NULL, 16);
84         *bus = (uint8_t)strtoul(splitaddr.bus, NULL, 16);
85         *devid = (uint8_t)strtoul(splitaddr.devid, NULL, 16);
86         *function = (uint8_t)strtoul(splitaddr.function, NULL, 10);
87         if (errno != 0)
88                 goto error;
89
90         free(buf_copy); /* free the copy made with strdup */
91         return 0;
92 error:
93         free(buf_copy);
94         return -1;
95 }
96
97 int
98 ccp_pci_parse_sysfs_value(const char *filename, unsigned long *val)
99 {
100         FILE *f;
101         char buf[BUFSIZ];
102         char *end = NULL;
103
104         f = fopen(filename, "r");
105         if (f == NULL)
106                 return -1;
107         if (fgets(buf, sizeof(buf), f) == NULL) {
108                 fclose(f);
109                 return -1;
110         }
111         *val = strtoul(buf, &end, 0);
112         if ((buf[0] == '\0') || (end == NULL) || (*end != '\n')) {
113                 fclose(f);
114                 return -1;
115         }
116         fclose(f);
117         return 0;
118 }
119
120 /** IO resource type: */
121 #define IORESOURCE_IO         0x00000100
122 #define IORESOURCE_MEM        0x00000200
123
124 /* parse one line of the "resource" sysfs file (note that the 'line'
125  * string is modified)
126  */
127 static int
128 ccp_pci_parse_one_sysfs_resource(char *line, size_t len, uint64_t *phys_addr,
129                                  uint64_t *end_addr, uint64_t *flags)
130 {
131         union pci_resource_info {
132                 struct {
133                         char *phys_addr;
134                         char *end_addr;
135                         char *flags;
136                 };
137                 char *ptrs[PCI_RESOURCE_FMT_NVAL];
138         } res_info;
139
140         if (rte_strsplit(line, len, res_info.ptrs, 3, ' ') != 3)
141                 return -1;
142         errno = 0;
143         *phys_addr = strtoull(res_info.phys_addr, NULL, 16);
144         *end_addr = strtoull(res_info.end_addr, NULL, 16);
145         *flags = strtoull(res_info.flags, NULL, 16);
146         if (errno != 0)
147                 return -1;
148
149         return 0;
150 }
151
152 /* parse the "resource" sysfs file */
153 int
154 ccp_pci_parse_sysfs_resource(const char *filename, struct rte_pci_device *dev)
155 {
156         FILE *fp;
157         char buf[BUFSIZ];
158         int i;
159         uint64_t phys_addr, end_addr, flags;
160
161         fp = fopen(filename, "r");
162         if (fp == NULL)
163                 return -1;
164
165         for (i = 0; i < PCI_MAX_RESOURCE; i++) {
166                 if (fgets(buf, sizeof(buf), fp) == NULL)
167                         goto error;
168                 if (ccp_pci_parse_one_sysfs_resource(buf, sizeof(buf),
169                                 &phys_addr, &end_addr, &flags) < 0)
170                         goto error;
171
172                 if (flags & IORESOURCE_MEM) {
173                         dev->mem_resource[i].phys_addr = phys_addr;
174                         dev->mem_resource[i].len = end_addr - phys_addr + 1;
175                         /* not mapped for now */
176                         dev->mem_resource[i].addr = NULL;
177                 }
178         }
179         fclose(fp);
180         return 0;
181
182 error:
183         fclose(fp);
184         return -1;
185 }
186
187 int
188 ccp_find_uio_devname(const char *dirname)
189 {
190
191         DIR *dir;
192         struct dirent *e;
193         char dirname_uio[PATH_MAX];
194         unsigned int uio_num;
195         int ret = -1;
196
197         /* depending on kernel version, uio can be located in uio/uioX
198          * or uio:uioX
199          */
200         snprintf(dirname_uio, sizeof(dirname_uio), "%s/uio", dirname);
201         dir = opendir(dirname_uio);
202         if (dir == NULL) {
203         /* retry with the parent directory might be different kernel version*/
204                 dir = opendir(dirname);
205                 if (dir == NULL)
206                         return -1;
207         }
208
209         /* take the first file starting with "uio" */
210         while ((e = readdir(dir)) != NULL) {
211                 /* format could be uio%d ...*/
212                 int shortprefix_len = sizeof("uio") - 1;
213                 /* ... or uio:uio%d */
214                 int longprefix_len = sizeof("uio:uio") - 1;
215                 char *endptr;
216
217                 if (strncmp(e->d_name, "uio", 3) != 0)
218                         continue;
219
220                 /* first try uio%d */
221                 errno = 0;
222                 uio_num = strtoull(e->d_name + shortprefix_len, &endptr, 10);
223                 if (errno == 0 && endptr != (e->d_name + shortprefix_len)) {
224                         ret = uio_num;
225                         break;
226                 }
227
228                 /* then try uio:uio%d */
229                 errno = 0;
230                 uio_num = strtoull(e->d_name + longprefix_len, &endptr, 10);
231                 if (errno == 0 && endptr != (e->d_name + longprefix_len)) {
232                         ret = uio_num;
233                         break;
234                 }
235         }
236         closedir(dir);
237         return ret;
238
239
240 }