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