xref: /dpdk/drivers/common/ionic/ionic_common_uio.c (revision 4610ac932fcbcc6279095e927390bdf877f728ab)
1484027bfSAndrew Boyer /* SPDX-License-Identifier: BSD-3-Clause
2484027bfSAndrew Boyer  * Copyright 2018-2024 Advanced Micro Devices, Inc.
3484027bfSAndrew Boyer  */
4484027bfSAndrew Boyer 
5484027bfSAndrew Boyer #include <stdio.h>
6484027bfSAndrew Boyer #include <stdint.h>
7484027bfSAndrew Boyer #include <string.h>
8484027bfSAndrew Boyer #include <unistd.h>
9484027bfSAndrew Boyer #include <stdarg.h>
10484027bfSAndrew Boyer #include <inttypes.h>
11484027bfSAndrew Boyer #include <sys/mman.h>
12484027bfSAndrew Boyer #include <sys/stat.h>
13484027bfSAndrew Boyer #include <dirent.h>
14484027bfSAndrew Boyer #include <stdlib.h>
15484027bfSAndrew Boyer #include <fcntl.h>
16484027bfSAndrew Boyer #include <stdbool.h>
17484027bfSAndrew Boyer 
18484027bfSAndrew Boyer #include <rte_common.h>
19484027bfSAndrew Boyer #include <rte_eal.h>
20484027bfSAndrew Boyer #include <rte_string_fns.h>
21484027bfSAndrew Boyer 
22484027bfSAndrew Boyer #include "ionic_common.h"
23484027bfSAndrew Boyer 
24484027bfSAndrew Boyer #define IONIC_MDEV_UNK      "mdev_unknown"
25484027bfSAndrew Boyer #define IONIC_MNIC          "cpu_mnic"
26*4610ac93SAndrew Boyer #define IONIC_MCRYPT        "cpu_mcrypt"
27484027bfSAndrew Boyer 
28484027bfSAndrew Boyer #define IONIC_MAX_NAME_LEN  20
29484027bfSAndrew Boyer #define IONIC_MAX_MNETS     5
30*4610ac93SAndrew Boyer #define IONIC_MAX_MCPTS     1
31*4610ac93SAndrew Boyer #define IONIC_MAX_DEVICES   (IONIC_MAX_MNETS + IONIC_MAX_MCPTS)
32484027bfSAndrew Boyer #define IONIC_MAX_U16_IDX   0xFFFF
33484027bfSAndrew Boyer #define IONIC_UIO_MAX_TRIES 32
34484027bfSAndrew Boyer 
35484027bfSAndrew Boyer /*
36484027bfSAndrew Boyer  * Note: the driver can assign any idx number
37484027bfSAndrew Boyer  * in the range [0-IONIC_MAX_MDEV_SCAN)
38484027bfSAndrew Boyer  */
39484027bfSAndrew Boyer #define IONIC_MAX_MDEV_SCAN 32
40484027bfSAndrew Boyer 
41484027bfSAndrew Boyer struct ionic_map_tbl {
42484027bfSAndrew Boyer 	char dev_name[IONIC_MAX_NAME_LEN];
43484027bfSAndrew Boyer 	uint16_t dev_idx;
44484027bfSAndrew Boyer 	uint16_t uio_idx;
45484027bfSAndrew Boyer 	char mdev_name[IONIC_MAX_NAME_LEN];
46484027bfSAndrew Boyer };
47484027bfSAndrew Boyer 
48484027bfSAndrew Boyer struct ionic_map_tbl ionic_mdev_map[IONIC_MAX_DEVICES] = {
49484027bfSAndrew Boyer 	{ "net_ionic0", 0, IONIC_MAX_U16_IDX, IONIC_MDEV_UNK },
50484027bfSAndrew Boyer 	{ "net_ionic1", 1, IONIC_MAX_U16_IDX, IONIC_MDEV_UNK },
51484027bfSAndrew Boyer 	{ "net_ionic2", 2, IONIC_MAX_U16_IDX, IONIC_MDEV_UNK },
52484027bfSAndrew Boyer 	{ "net_ionic3", 3, IONIC_MAX_U16_IDX, IONIC_MDEV_UNK },
53484027bfSAndrew Boyer 	{ "net_ionic4", 4, IONIC_MAX_U16_IDX, IONIC_MDEV_UNK },
54*4610ac93SAndrew Boyer 	{ "crypto_ionic0", 5, IONIC_MAX_U16_IDX, IONIC_MDEV_UNK },
55484027bfSAndrew Boyer };
56484027bfSAndrew Boyer 
57484027bfSAndrew Boyer struct uio_name {
58484027bfSAndrew Boyer 	uint16_t idx;
59484027bfSAndrew Boyer 	char name[IONIC_MAX_NAME_LEN];
60484027bfSAndrew Boyer };
61484027bfSAndrew Boyer 
62484027bfSAndrew Boyer static void
uio_fill_name_cache(struct uio_name * name_cache,const char * pfx)63484027bfSAndrew Boyer uio_fill_name_cache(struct uio_name *name_cache, const char *pfx)
64484027bfSAndrew Boyer {
65484027bfSAndrew Boyer 	char file[64];
66484027bfSAndrew Boyer 	FILE *fp;
67484027bfSAndrew Boyer 	char *ret;
68484027bfSAndrew Boyer 	int name_idx = 0;
69484027bfSAndrew Boyer 	int i;
70484027bfSAndrew Boyer 
71484027bfSAndrew Boyer 	for (i = 0; i < IONIC_UIO_MAX_TRIES &&
72484027bfSAndrew Boyer 			name_idx < IONIC_MAX_DEVICES; i++) {
73484027bfSAndrew Boyer 		sprintf(file, "/sys/class/uio/uio%d/name", i);
74484027bfSAndrew Boyer 
75484027bfSAndrew Boyer 		fp = fopen(file, "r");
76484027bfSAndrew Boyer 		if (fp == NULL)
77484027bfSAndrew Boyer 			continue;
78484027bfSAndrew Boyer 
79484027bfSAndrew Boyer 		ret = fgets(name_cache[name_idx].name, IONIC_MAX_NAME_LEN, fp);
80484027bfSAndrew Boyer 		if (ret == NULL) {
81484027bfSAndrew Boyer 			fclose(fp);
82484027bfSAndrew Boyer 			continue;
83484027bfSAndrew Boyer 		}
84484027bfSAndrew Boyer 
85484027bfSAndrew Boyer 		name_cache[name_idx].idx = i;
86484027bfSAndrew Boyer 
87484027bfSAndrew Boyer 		fclose(fp);
88484027bfSAndrew Boyer 
89484027bfSAndrew Boyer 		if (strncmp(name_cache[name_idx].name, pfx, strlen(pfx)) == 0)
90484027bfSAndrew Boyer 			name_idx++;
91484027bfSAndrew Boyer 	}
92484027bfSAndrew Boyer }
93484027bfSAndrew Boyer 
94484027bfSAndrew Boyer static int
uio_get_idx_for_devname(struct uio_name * name_cache,char * devname)95484027bfSAndrew Boyer uio_get_idx_for_devname(struct uio_name *name_cache, char *devname)
96484027bfSAndrew Boyer {
97484027bfSAndrew Boyer 	int i;
98484027bfSAndrew Boyer 
99484027bfSAndrew Boyer 	for (i = 0; i < IONIC_MAX_DEVICES; i++)
100484027bfSAndrew Boyer 		if (strncmp(name_cache[i].name, devname, strlen(devname)) == 0)
101484027bfSAndrew Boyer 			return name_cache[i].idx;
102484027bfSAndrew Boyer 
103484027bfSAndrew Boyer 	return -1;
104484027bfSAndrew Boyer }
105484027bfSAndrew Boyer 
106484027bfSAndrew Boyer void
ionic_uio_scan_mnet_devices(void)107484027bfSAndrew Boyer ionic_uio_scan_mnet_devices(void)
108484027bfSAndrew Boyer {
109484027bfSAndrew Boyer 	struct ionic_map_tbl *map;
110484027bfSAndrew Boyer 	char devname[IONIC_MAX_NAME_LEN];
111484027bfSAndrew Boyer 	struct uio_name name_cache[IONIC_MAX_DEVICES];
112484027bfSAndrew Boyer 	bool done;
113484027bfSAndrew Boyer 	int mdev_idx = 0;
114484027bfSAndrew Boyer 	int uio_idx;
115484027bfSAndrew Boyer 	int i;
116484027bfSAndrew Boyer 	static bool scan_done;
117484027bfSAndrew Boyer 
118484027bfSAndrew Boyer 	if (scan_done)
119484027bfSAndrew Boyer 		return;
120484027bfSAndrew Boyer 
121484027bfSAndrew Boyer 	scan_done = true;
122484027bfSAndrew Boyer 
123484027bfSAndrew Boyer 	uio_fill_name_cache(name_cache, IONIC_MNIC);
124484027bfSAndrew Boyer 
125484027bfSAndrew Boyer 	for (i = 0; i < IONIC_MAX_MNETS; i++) {
126484027bfSAndrew Boyer 		done = false;
127484027bfSAndrew Boyer 
128484027bfSAndrew Boyer 		while (!done) {
129484027bfSAndrew Boyer 			if (mdev_idx > IONIC_MAX_MDEV_SCAN)
130484027bfSAndrew Boyer 				break;
131484027bfSAndrew Boyer 
132484027bfSAndrew Boyer 			/* Look for a matching mnic */
133484027bfSAndrew Boyer 			snprintf(devname, IONIC_MAX_NAME_LEN,
134484027bfSAndrew Boyer 				IONIC_MNIC "%d", mdev_idx);
135484027bfSAndrew Boyer 			uio_idx = uio_get_idx_for_devname(name_cache, devname);
136484027bfSAndrew Boyer 			if (uio_idx >= 0) {
137484027bfSAndrew Boyer 				map = &ionic_mdev_map[i];
138484027bfSAndrew Boyer 				map->uio_idx = (uint16_t)uio_idx;
139484027bfSAndrew Boyer 				strlcpy(map->mdev_name, devname,
140484027bfSAndrew Boyer 					IONIC_MAX_NAME_LEN);
141484027bfSAndrew Boyer 				done = true;
142484027bfSAndrew Boyer 			}
143484027bfSAndrew Boyer 
144484027bfSAndrew Boyer 			mdev_idx++;
145484027bfSAndrew Boyer 		}
146484027bfSAndrew Boyer 	}
147484027bfSAndrew Boyer }
148484027bfSAndrew Boyer 
149*4610ac93SAndrew Boyer void
ionic_uio_scan_mcrypt_devices(void)150*4610ac93SAndrew Boyer ionic_uio_scan_mcrypt_devices(void)
151*4610ac93SAndrew Boyer {
152*4610ac93SAndrew Boyer 	struct ionic_map_tbl *map;
153*4610ac93SAndrew Boyer 	char devname[IONIC_MAX_NAME_LEN];
154*4610ac93SAndrew Boyer 	struct uio_name name_cache[IONIC_MAX_DEVICES];
155*4610ac93SAndrew Boyer 	bool done;
156*4610ac93SAndrew Boyer 	int mdev_idx = 0;
157*4610ac93SAndrew Boyer 	int uio_idx;
158*4610ac93SAndrew Boyer 	int i;
159*4610ac93SAndrew Boyer 	static bool scan_done;
160*4610ac93SAndrew Boyer 
161*4610ac93SAndrew Boyer 	if (scan_done)
162*4610ac93SAndrew Boyer 		return;
163*4610ac93SAndrew Boyer 
164*4610ac93SAndrew Boyer 	scan_done = true;
165*4610ac93SAndrew Boyer 
166*4610ac93SAndrew Boyer 	uio_fill_name_cache(name_cache, IONIC_MCRYPT);
167*4610ac93SAndrew Boyer 
168*4610ac93SAndrew Boyer 	for (i = IONIC_MAX_MNETS; i < IONIC_MAX_DEVICES; i++) {
169*4610ac93SAndrew Boyer 		done = false;
170*4610ac93SAndrew Boyer 
171*4610ac93SAndrew Boyer 		while (!done) {
172*4610ac93SAndrew Boyer 			if (mdev_idx > IONIC_MAX_MDEV_SCAN)
173*4610ac93SAndrew Boyer 				break;
174*4610ac93SAndrew Boyer 
175*4610ac93SAndrew Boyer 			/* Look for a matching mcrypt */
176*4610ac93SAndrew Boyer 			snprintf(devname, IONIC_MAX_NAME_LEN,
177*4610ac93SAndrew Boyer 				IONIC_MCRYPT "%d", mdev_idx);
178*4610ac93SAndrew Boyer 			uio_idx = uio_get_idx_for_devname(name_cache, devname);
179*4610ac93SAndrew Boyer 			if (uio_idx >= 0) {
180*4610ac93SAndrew Boyer 				map = &ionic_mdev_map[i];
181*4610ac93SAndrew Boyer 				map->uio_idx = (uint16_t)uio_idx;
182*4610ac93SAndrew Boyer 				strlcpy(map->mdev_name, devname,
183*4610ac93SAndrew Boyer 					IONIC_MAX_NAME_LEN);
184*4610ac93SAndrew Boyer 				done = true;
185*4610ac93SAndrew Boyer 			}
186*4610ac93SAndrew Boyer 
187*4610ac93SAndrew Boyer 			mdev_idx++;
188*4610ac93SAndrew Boyer 		}
189*4610ac93SAndrew Boyer 	}
190*4610ac93SAndrew Boyer }
191*4610ac93SAndrew Boyer 
192484027bfSAndrew Boyer static int
uio_get_multi_dev_uionum(const char * name)193484027bfSAndrew Boyer uio_get_multi_dev_uionum(const char *name)
194484027bfSAndrew Boyer {
195484027bfSAndrew Boyer 	struct ionic_map_tbl *map;
196484027bfSAndrew Boyer 	int i;
197484027bfSAndrew Boyer 
198484027bfSAndrew Boyer 	for (i = 0; i < IONIC_MAX_DEVICES; i++) {
199484027bfSAndrew Boyer 		map = &ionic_mdev_map[i];
200484027bfSAndrew Boyer 		if (strncmp(map->dev_name, name, IONIC_MAX_NAME_LEN) == 0) {
201484027bfSAndrew Boyer 			if (map->uio_idx == IONIC_MAX_U16_IDX)
202484027bfSAndrew Boyer 				return -1;
203484027bfSAndrew Boyer 			else
204484027bfSAndrew Boyer 				return map->uio_idx;
205484027bfSAndrew Boyer 		}
206484027bfSAndrew Boyer 	}
207484027bfSAndrew Boyer 
208484027bfSAndrew Boyer 	return -1;
209484027bfSAndrew Boyer }
210484027bfSAndrew Boyer 
211484027bfSAndrew Boyer static unsigned long
uio_get_res_size(int uio_idx,int res_idx)212484027bfSAndrew Boyer uio_get_res_size(int uio_idx, int res_idx)
213484027bfSAndrew Boyer {
214484027bfSAndrew Boyer 	unsigned long size;
215484027bfSAndrew Boyer 	char file[64];
216484027bfSAndrew Boyer 	FILE *fp;
217484027bfSAndrew Boyer 
218484027bfSAndrew Boyer 	sprintf(file, "/sys/class/uio/uio%d/maps/map%d/size",
219484027bfSAndrew Boyer 		uio_idx, res_idx);
220484027bfSAndrew Boyer 
221484027bfSAndrew Boyer 	fp = fopen(file, "r");
222484027bfSAndrew Boyer 	if (fp == NULL)
223484027bfSAndrew Boyer 		return 0;
224484027bfSAndrew Boyer 
225484027bfSAndrew Boyer 	if (fscanf(fp, "0x%lx", &size) != 1)
226484027bfSAndrew Boyer 		size = 0;
227484027bfSAndrew Boyer 
228484027bfSAndrew Boyer 	fclose(fp);
229484027bfSAndrew Boyer 
230484027bfSAndrew Boyer 	return size;
231484027bfSAndrew Boyer }
232484027bfSAndrew Boyer 
233484027bfSAndrew Boyer static unsigned long
uio_get_res_phy_addr_offs(int uio_idx,int res_idx)234484027bfSAndrew Boyer uio_get_res_phy_addr_offs(int uio_idx, int res_idx)
235484027bfSAndrew Boyer {
236484027bfSAndrew Boyer 	unsigned long offset;
237484027bfSAndrew Boyer 	char file[64];
238484027bfSAndrew Boyer 	FILE *fp;
239484027bfSAndrew Boyer 
240484027bfSAndrew Boyer 	sprintf(file, "/sys/class/uio/uio%d/maps/map%d/offset",
241484027bfSAndrew Boyer 		uio_idx, res_idx);
242484027bfSAndrew Boyer 
243484027bfSAndrew Boyer 	fp = fopen(file, "r");
244484027bfSAndrew Boyer 	if (fp == NULL)
245484027bfSAndrew Boyer 		return 0;
246484027bfSAndrew Boyer 
247484027bfSAndrew Boyer 	if (fscanf(fp, "0x%lx", &offset) != 1)
248484027bfSAndrew Boyer 		offset = 0;
249484027bfSAndrew Boyer 
250484027bfSAndrew Boyer 	fclose(fp);
251484027bfSAndrew Boyer 
252484027bfSAndrew Boyer 	return offset;
253484027bfSAndrew Boyer }
254484027bfSAndrew Boyer 
255484027bfSAndrew Boyer static unsigned long
uio_get_res_phy_addr(int uio_idx,int res_idx)256484027bfSAndrew Boyer uio_get_res_phy_addr(int uio_idx, int res_idx)
257484027bfSAndrew Boyer {
258484027bfSAndrew Boyer 	unsigned long addr;
259484027bfSAndrew Boyer 	char file[64];
260484027bfSAndrew Boyer 	FILE *fp;
261484027bfSAndrew Boyer 
262484027bfSAndrew Boyer 	sprintf(file, "/sys/class/uio/uio%d/maps/map%d/addr",
263484027bfSAndrew Boyer 		uio_idx, res_idx);
264484027bfSAndrew Boyer 
265484027bfSAndrew Boyer 	fp = fopen(file, "r");
266484027bfSAndrew Boyer 	if (fp == NULL)
267484027bfSAndrew Boyer 		return 0;
268484027bfSAndrew Boyer 
269484027bfSAndrew Boyer 	if (fscanf(fp, "0x%lx", &addr) != 1)
270484027bfSAndrew Boyer 		addr = 0;
271484027bfSAndrew Boyer 
272484027bfSAndrew Boyer 	fclose(fp);
273484027bfSAndrew Boyer 
274484027bfSAndrew Boyer 	return addr;
275484027bfSAndrew Boyer }
276484027bfSAndrew Boyer 
277484027bfSAndrew Boyer static void *
uio_get_map_res_addr(int uio_idx,int size,int res_idx)278484027bfSAndrew Boyer uio_get_map_res_addr(int uio_idx, int size, int res_idx)
279484027bfSAndrew Boyer {
280484027bfSAndrew Boyer 	char name[64];
281484027bfSAndrew Boyer 	int fd;
282484027bfSAndrew Boyer 	void *addr;
283484027bfSAndrew Boyer 
284484027bfSAndrew Boyer 	if (size == 0)
285484027bfSAndrew Boyer 		return NULL;
286484027bfSAndrew Boyer 
287484027bfSAndrew Boyer 	sprintf(name, "/dev/uio%d", uio_idx);
288484027bfSAndrew Boyer 
289484027bfSAndrew Boyer 	fd = open(name, O_RDWR);
290484027bfSAndrew Boyer 	if (fd < 0)
291484027bfSAndrew Boyer 		return NULL;
292484027bfSAndrew Boyer 
293484027bfSAndrew Boyer 	if (size < getpagesize())
294484027bfSAndrew Boyer 		size = getpagesize();
295484027bfSAndrew Boyer 
296484027bfSAndrew Boyer 	addr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED,
297484027bfSAndrew Boyer 				fd, res_idx * getpagesize());
298484027bfSAndrew Boyer 
299484027bfSAndrew Boyer 	close(fd);
300484027bfSAndrew Boyer 
301484027bfSAndrew Boyer 	return addr;
302484027bfSAndrew Boyer }
303484027bfSAndrew Boyer 
304484027bfSAndrew Boyer void
ionic_uio_get_rsrc(const char * name,int idx,struct ionic_dev_bar * bar)305484027bfSAndrew Boyer ionic_uio_get_rsrc(const char *name, int idx, struct ionic_dev_bar *bar)
306484027bfSAndrew Boyer {
307484027bfSAndrew Boyer 	int num;
308484027bfSAndrew Boyer 	int offs;
309484027bfSAndrew Boyer 
310484027bfSAndrew Boyer 	num = uio_get_multi_dev_uionum(name);
311484027bfSAndrew Boyer 	if (num < 0)
312484027bfSAndrew Boyer 		return;
313484027bfSAndrew Boyer 
314484027bfSAndrew Boyer 	bar->len = uio_get_res_size(num, idx);
315484027bfSAndrew Boyer 	offs = uio_get_res_phy_addr_offs(num, idx);
316484027bfSAndrew Boyer 	bar->bus_addr = uio_get_res_phy_addr(num, idx);
317484027bfSAndrew Boyer 	bar->bus_addr += offs;
318484027bfSAndrew Boyer 	bar->vaddr = uio_get_map_res_addr(num, bar->len, idx);
319484027bfSAndrew Boyer 	bar->vaddr = ((char *)bar->vaddr) + offs;
320484027bfSAndrew Boyer }
321484027bfSAndrew Boyer 
322484027bfSAndrew Boyer void
ionic_uio_rel_rsrc(const char * name,int idx,struct ionic_dev_bar * bar)323484027bfSAndrew Boyer ionic_uio_rel_rsrc(const char *name, int idx, struct ionic_dev_bar *bar)
324484027bfSAndrew Boyer {
325484027bfSAndrew Boyer 	int num, offs;
326484027bfSAndrew Boyer 
327484027bfSAndrew Boyer 	num = uio_get_multi_dev_uionum(name);
328484027bfSAndrew Boyer 	if (num < 0)
329484027bfSAndrew Boyer 		return;
330484027bfSAndrew Boyer 	if (bar->vaddr == NULL)
331484027bfSAndrew Boyer 		return;
332484027bfSAndrew Boyer 
333484027bfSAndrew Boyer 	offs = uio_get_res_phy_addr_offs(num, idx);
334484027bfSAndrew Boyer 	munmap(((char *)bar->vaddr) - offs, bar->len);
335484027bfSAndrew Boyer }
336