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