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