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