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