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