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