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 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 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 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 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 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 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 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 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 * 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 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 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