xref: /f-stack/dpdk/drivers/crypto/ccp/ccp_pci.c (revision d30ea906)
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
ccp_check_pci_uio_module(void)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
ccp_parse_pci_addr_format(const char * buf,int bufsize,uint16_t * domain,uint8_t * bus,uint8_t * devid,uint8_t * function)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
ccp_pci_parse_sysfs_value(const char * filename,unsigned long * val)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
ccp_pci_parse_one_sysfs_resource(char * line,size_t len,uint64_t * phys_addr,uint64_t * end_addr,uint64_t * flags)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
ccp_pci_parse_sysfs_resource(const char * filename,struct rte_pci_device * dev)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
ccp_find_uio_devname(const char * dirname)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 }
240