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