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