xref: /dpdk/drivers/common/ionic/ionic_common_uio.c (revision 4610ac932fcbcc6279095e927390bdf877f728ab)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright 2018-2024 Advanced Micro Devices, Inc.
3  */
4 
5 #include <stdio.h>
6 #include <stdint.h>
7 #include <string.h>
8 #include <unistd.h>
9 #include <stdarg.h>
10 #include <inttypes.h>
11 #include <sys/mman.h>
12 #include <sys/stat.h>
13 #include <dirent.h>
14 #include <stdlib.h>
15 #include <fcntl.h>
16 #include <stdbool.h>
17 
18 #include <rte_common.h>
19 #include <rte_eal.h>
20 #include <rte_string_fns.h>
21 
22 #include "ionic_common.h"
23 
24 #define IONIC_MDEV_UNK      "mdev_unknown"
25 #define IONIC_MNIC          "cpu_mnic"
26 #define IONIC_MCRYPT        "cpu_mcrypt"
27 
28 #define IONIC_MAX_NAME_LEN  20
29 #define IONIC_MAX_MNETS     5
30 #define IONIC_MAX_MCPTS     1
31 #define IONIC_MAX_DEVICES   (IONIC_MAX_MNETS + IONIC_MAX_MCPTS)
32 #define IONIC_MAX_U16_IDX   0xFFFF
33 #define IONIC_UIO_MAX_TRIES 32
34 
35 /*
36  * Note: the driver can assign any idx number
37  * in the range [0-IONIC_MAX_MDEV_SCAN)
38  */
39 #define IONIC_MAX_MDEV_SCAN 32
40 
41 struct ionic_map_tbl {
42 	char dev_name[IONIC_MAX_NAME_LEN];
43 	uint16_t dev_idx;
44 	uint16_t uio_idx;
45 	char mdev_name[IONIC_MAX_NAME_LEN];
46 };
47 
48 struct ionic_map_tbl ionic_mdev_map[IONIC_MAX_DEVICES] = {
49 	{ "net_ionic0", 0, IONIC_MAX_U16_IDX, IONIC_MDEV_UNK },
50 	{ "net_ionic1", 1, IONIC_MAX_U16_IDX, IONIC_MDEV_UNK },
51 	{ "net_ionic2", 2, IONIC_MAX_U16_IDX, IONIC_MDEV_UNK },
52 	{ "net_ionic3", 3, IONIC_MAX_U16_IDX, IONIC_MDEV_UNK },
53 	{ "net_ionic4", 4, IONIC_MAX_U16_IDX, IONIC_MDEV_UNK },
54 	{ "crypto_ionic0", 5, IONIC_MAX_U16_IDX, IONIC_MDEV_UNK },
55 };
56 
57 struct uio_name {
58 	uint16_t idx;
59 	char name[IONIC_MAX_NAME_LEN];
60 };
61 
62 static void
uio_fill_name_cache(struct uio_name * name_cache,const char * pfx)63 uio_fill_name_cache(struct uio_name *name_cache, const char *pfx)
64 {
65 	char file[64];
66 	FILE *fp;
67 	char *ret;
68 	int name_idx = 0;
69 	int i;
70 
71 	for (i = 0; i < IONIC_UIO_MAX_TRIES &&
72 			name_idx < IONIC_MAX_DEVICES; i++) {
73 		sprintf(file, "/sys/class/uio/uio%d/name", i);
74 
75 		fp = fopen(file, "r");
76 		if (fp == NULL)
77 			continue;
78 
79 		ret = fgets(name_cache[name_idx].name, IONIC_MAX_NAME_LEN, fp);
80 		if (ret == NULL) {
81 			fclose(fp);
82 			continue;
83 		}
84 
85 		name_cache[name_idx].idx = i;
86 
87 		fclose(fp);
88 
89 		if (strncmp(name_cache[name_idx].name, pfx, strlen(pfx)) == 0)
90 			name_idx++;
91 	}
92 }
93 
94 static int
uio_get_idx_for_devname(struct uio_name * name_cache,char * devname)95 uio_get_idx_for_devname(struct uio_name *name_cache, char *devname)
96 {
97 	int i;
98 
99 	for (i = 0; i < IONIC_MAX_DEVICES; i++)
100 		if (strncmp(name_cache[i].name, devname, strlen(devname)) == 0)
101 			return name_cache[i].idx;
102 
103 	return -1;
104 }
105 
106 void
ionic_uio_scan_mnet_devices(void)107 ionic_uio_scan_mnet_devices(void)
108 {
109 	struct ionic_map_tbl *map;
110 	char devname[IONIC_MAX_NAME_LEN];
111 	struct uio_name name_cache[IONIC_MAX_DEVICES];
112 	bool done;
113 	int mdev_idx = 0;
114 	int uio_idx;
115 	int i;
116 	static bool scan_done;
117 
118 	if (scan_done)
119 		return;
120 
121 	scan_done = true;
122 
123 	uio_fill_name_cache(name_cache, IONIC_MNIC);
124 
125 	for (i = 0; i < IONIC_MAX_MNETS; i++) {
126 		done = false;
127 
128 		while (!done) {
129 			if (mdev_idx > IONIC_MAX_MDEV_SCAN)
130 				break;
131 
132 			/* Look for a matching mnic */
133 			snprintf(devname, IONIC_MAX_NAME_LEN,
134 				IONIC_MNIC "%d", mdev_idx);
135 			uio_idx = uio_get_idx_for_devname(name_cache, devname);
136 			if (uio_idx >= 0) {
137 				map = &ionic_mdev_map[i];
138 				map->uio_idx = (uint16_t)uio_idx;
139 				strlcpy(map->mdev_name, devname,
140 					IONIC_MAX_NAME_LEN);
141 				done = true;
142 			}
143 
144 			mdev_idx++;
145 		}
146 	}
147 }
148 
149 void
ionic_uio_scan_mcrypt_devices(void)150 ionic_uio_scan_mcrypt_devices(void)
151 {
152 	struct ionic_map_tbl *map;
153 	char devname[IONIC_MAX_NAME_LEN];
154 	struct uio_name name_cache[IONIC_MAX_DEVICES];
155 	bool done;
156 	int mdev_idx = 0;
157 	int uio_idx;
158 	int i;
159 	static bool scan_done;
160 
161 	if (scan_done)
162 		return;
163 
164 	scan_done = true;
165 
166 	uio_fill_name_cache(name_cache, IONIC_MCRYPT);
167 
168 	for (i = IONIC_MAX_MNETS; i < IONIC_MAX_DEVICES; i++) {
169 		done = false;
170 
171 		while (!done) {
172 			if (mdev_idx > IONIC_MAX_MDEV_SCAN)
173 				break;
174 
175 			/* Look for a matching mcrypt */
176 			snprintf(devname, IONIC_MAX_NAME_LEN,
177 				IONIC_MCRYPT "%d", mdev_idx);
178 			uio_idx = uio_get_idx_for_devname(name_cache, devname);
179 			if (uio_idx >= 0) {
180 				map = &ionic_mdev_map[i];
181 				map->uio_idx = (uint16_t)uio_idx;
182 				strlcpy(map->mdev_name, devname,
183 					IONIC_MAX_NAME_LEN);
184 				done = true;
185 			}
186 
187 			mdev_idx++;
188 		}
189 	}
190 }
191 
192 static int
uio_get_multi_dev_uionum(const char * name)193 uio_get_multi_dev_uionum(const char *name)
194 {
195 	struct ionic_map_tbl *map;
196 	int i;
197 
198 	for (i = 0; i < IONIC_MAX_DEVICES; i++) {
199 		map = &ionic_mdev_map[i];
200 		if (strncmp(map->dev_name, name, IONIC_MAX_NAME_LEN) == 0) {
201 			if (map->uio_idx == IONIC_MAX_U16_IDX)
202 				return -1;
203 			else
204 				return map->uio_idx;
205 		}
206 	}
207 
208 	return -1;
209 }
210 
211 static unsigned long
uio_get_res_size(int uio_idx,int res_idx)212 uio_get_res_size(int uio_idx, int res_idx)
213 {
214 	unsigned long size;
215 	char file[64];
216 	FILE *fp;
217 
218 	sprintf(file, "/sys/class/uio/uio%d/maps/map%d/size",
219 		uio_idx, res_idx);
220 
221 	fp = fopen(file, "r");
222 	if (fp == NULL)
223 		return 0;
224 
225 	if (fscanf(fp, "0x%lx", &size) != 1)
226 		size = 0;
227 
228 	fclose(fp);
229 
230 	return size;
231 }
232 
233 static unsigned long
uio_get_res_phy_addr_offs(int uio_idx,int res_idx)234 uio_get_res_phy_addr_offs(int uio_idx, int res_idx)
235 {
236 	unsigned long offset;
237 	char file[64];
238 	FILE *fp;
239 
240 	sprintf(file, "/sys/class/uio/uio%d/maps/map%d/offset",
241 		uio_idx, res_idx);
242 
243 	fp = fopen(file, "r");
244 	if (fp == NULL)
245 		return 0;
246 
247 	if (fscanf(fp, "0x%lx", &offset) != 1)
248 		offset = 0;
249 
250 	fclose(fp);
251 
252 	return offset;
253 }
254 
255 static unsigned long
uio_get_res_phy_addr(int uio_idx,int res_idx)256 uio_get_res_phy_addr(int uio_idx, int res_idx)
257 {
258 	unsigned long addr;
259 	char file[64];
260 	FILE *fp;
261 
262 	sprintf(file, "/sys/class/uio/uio%d/maps/map%d/addr",
263 		uio_idx, res_idx);
264 
265 	fp = fopen(file, "r");
266 	if (fp == NULL)
267 		return 0;
268 
269 	if (fscanf(fp, "0x%lx", &addr) != 1)
270 		addr = 0;
271 
272 	fclose(fp);
273 
274 	return addr;
275 }
276 
277 static void *
uio_get_map_res_addr(int uio_idx,int size,int res_idx)278 uio_get_map_res_addr(int uio_idx, int size, int res_idx)
279 {
280 	char name[64];
281 	int fd;
282 	void *addr;
283 
284 	if (size == 0)
285 		return NULL;
286 
287 	sprintf(name, "/dev/uio%d", uio_idx);
288 
289 	fd = open(name, O_RDWR);
290 	if (fd < 0)
291 		return NULL;
292 
293 	if (size < getpagesize())
294 		size = getpagesize();
295 
296 	addr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED,
297 				fd, res_idx * getpagesize());
298 
299 	close(fd);
300 
301 	return addr;
302 }
303 
304 void
ionic_uio_get_rsrc(const char * name,int idx,struct ionic_dev_bar * bar)305 ionic_uio_get_rsrc(const char *name, int idx, struct ionic_dev_bar *bar)
306 {
307 	int num;
308 	int offs;
309 
310 	num = uio_get_multi_dev_uionum(name);
311 	if (num < 0)
312 		return;
313 
314 	bar->len = uio_get_res_size(num, idx);
315 	offs = uio_get_res_phy_addr_offs(num, idx);
316 	bar->bus_addr = uio_get_res_phy_addr(num, idx);
317 	bar->bus_addr += offs;
318 	bar->vaddr = uio_get_map_res_addr(num, bar->len, idx);
319 	bar->vaddr = ((char *)bar->vaddr) + offs;
320 }
321 
322 void
ionic_uio_rel_rsrc(const char * name,int idx,struct ionic_dev_bar * bar)323 ionic_uio_rel_rsrc(const char *name, int idx, struct ionic_dev_bar *bar)
324 {
325 	int num, offs;
326 
327 	num = uio_get_multi_dev_uionum(name);
328 	if (num < 0)
329 		return;
330 	if (bar->vaddr == NULL)
331 		return;
332 
333 	offs = uio_get_res_phy_addr_offs(num, idx);
334 	munmap(((char *)bar->vaddr) - offs, bar->len);
335 }
336