1*831dba47SStephen Hemminger /* SPDX-License-Identifier: BSD-3-Clause 2*831dba47SStephen Hemminger * Copyright (c) 2018, Microsoft Corporation. 3*831dba47SStephen Hemminger * All Rights Reserved. 4*831dba47SStephen Hemminger */ 5*831dba47SStephen Hemminger 6*831dba47SStephen Hemminger #include <string.h> 7*831dba47SStephen Hemminger #include <unistd.h> 8*831dba47SStephen Hemminger #include <dirent.h> 9*831dba47SStephen Hemminger #include <fcntl.h> 10*831dba47SStephen Hemminger #include <sys/mman.h> 11*831dba47SStephen Hemminger #include <sys/stat.h> 12*831dba47SStephen Hemminger 13*831dba47SStephen Hemminger #include <rte_eal.h> 14*831dba47SStephen Hemminger #include <rte_uuid.h> 15*831dba47SStephen Hemminger #include <rte_tailq.h> 16*831dba47SStephen Hemminger #include <rte_log.h> 17*831dba47SStephen Hemminger #include <rte_devargs.h> 18*831dba47SStephen Hemminger #include <rte_memory.h> 19*831dba47SStephen Hemminger #include <rte_malloc.h> 20*831dba47SStephen Hemminger #include <rte_bus_vmbus.h> 21*831dba47SStephen Hemminger 22*831dba47SStephen Hemminger #include "eal_filesystem.h" 23*831dba47SStephen Hemminger #include "private.h" 24*831dba47SStephen Hemminger 25*831dba47SStephen Hemminger /** Pathname of VMBUS devices directory. */ 26*831dba47SStephen Hemminger #define SYSFS_VMBUS_DEVICES "/sys/bus/vmbus/devices" 27*831dba47SStephen Hemminger 28*831dba47SStephen Hemminger extern struct rte_vmbus_bus rte_vmbus_bus; 29*831dba47SStephen Hemminger 30*831dba47SStephen Hemminger /* Read sysfs file to get UUID */ 31*831dba47SStephen Hemminger static int 32*831dba47SStephen Hemminger parse_sysfs_uuid(const char *filename, rte_uuid_t uu) 33*831dba47SStephen Hemminger { 34*831dba47SStephen Hemminger char buf[BUFSIZ]; 35*831dba47SStephen Hemminger char *cp, *in = buf; 36*831dba47SStephen Hemminger FILE *f; 37*831dba47SStephen Hemminger 38*831dba47SStephen Hemminger f = fopen(filename, "r"); 39*831dba47SStephen Hemminger if (f == NULL) { 40*831dba47SStephen Hemminger VMBUS_LOG(ERR, "cannot open sysfs value %s: %s", 41*831dba47SStephen Hemminger filename, strerror(errno)); 42*831dba47SStephen Hemminger return -1; 43*831dba47SStephen Hemminger } 44*831dba47SStephen Hemminger 45*831dba47SStephen Hemminger if (fgets(buf, sizeof(buf), f) == NULL) { 46*831dba47SStephen Hemminger VMBUS_LOG(ERR, "cannot read sysfs value %s", 47*831dba47SStephen Hemminger filename); 48*831dba47SStephen Hemminger fclose(f); 49*831dba47SStephen Hemminger return -1; 50*831dba47SStephen Hemminger } 51*831dba47SStephen Hemminger fclose(f); 52*831dba47SStephen Hemminger 53*831dba47SStephen Hemminger cp = strchr(buf, '\n'); 54*831dba47SStephen Hemminger if (cp) 55*831dba47SStephen Hemminger *cp = '\0'; 56*831dba47SStephen Hemminger 57*831dba47SStephen Hemminger /* strip { } notation */ 58*831dba47SStephen Hemminger if (buf[0] == '{') { 59*831dba47SStephen Hemminger in = buf + 1; 60*831dba47SStephen Hemminger cp = strchr(in, '}'); 61*831dba47SStephen Hemminger if (cp) 62*831dba47SStephen Hemminger *cp = '\0'; 63*831dba47SStephen Hemminger } 64*831dba47SStephen Hemminger 65*831dba47SStephen Hemminger if (rte_uuid_parse(in, uu) < 0) { 66*831dba47SStephen Hemminger VMBUS_LOG(ERR, "%s %s not a valid UUID", 67*831dba47SStephen Hemminger filename, buf); 68*831dba47SStephen Hemminger return -1; 69*831dba47SStephen Hemminger } 70*831dba47SStephen Hemminger 71*831dba47SStephen Hemminger return 0; 72*831dba47SStephen Hemminger } 73*831dba47SStephen Hemminger 74*831dba47SStephen Hemminger static int 75*831dba47SStephen Hemminger get_sysfs_string(const char *filename, char *buf, size_t buflen) 76*831dba47SStephen Hemminger { 77*831dba47SStephen Hemminger char *cp; 78*831dba47SStephen Hemminger FILE *f; 79*831dba47SStephen Hemminger 80*831dba47SStephen Hemminger f = fopen(filename, "r"); 81*831dba47SStephen Hemminger if (f == NULL) { 82*831dba47SStephen Hemminger VMBUS_LOG(ERR, "cannot open sysfs value %s:%s", 83*831dba47SStephen Hemminger filename, strerror(errno)); 84*831dba47SStephen Hemminger return -1; 85*831dba47SStephen Hemminger } 86*831dba47SStephen Hemminger 87*831dba47SStephen Hemminger if (fgets(buf, buflen, f) == NULL) { 88*831dba47SStephen Hemminger VMBUS_LOG(ERR, "cannot read sysfs value %s", 89*831dba47SStephen Hemminger filename); 90*831dba47SStephen Hemminger fclose(f); 91*831dba47SStephen Hemminger return -1; 92*831dba47SStephen Hemminger } 93*831dba47SStephen Hemminger fclose(f); 94*831dba47SStephen Hemminger 95*831dba47SStephen Hemminger /* remove trailing newline */ 96*831dba47SStephen Hemminger cp = memchr(buf, '\n', buflen); 97*831dba47SStephen Hemminger if (cp) 98*831dba47SStephen Hemminger *cp = '\0'; 99*831dba47SStephen Hemminger 100*831dba47SStephen Hemminger return 0; 101*831dba47SStephen Hemminger } 102*831dba47SStephen Hemminger 103*831dba47SStephen Hemminger static int 104*831dba47SStephen Hemminger vmbus_get_uio_dev(const struct rte_vmbus_device *dev, 105*831dba47SStephen Hemminger char *dstbuf, size_t buflen) 106*831dba47SStephen Hemminger { 107*831dba47SStephen Hemminger char dirname[PATH_MAX]; 108*831dba47SStephen Hemminger unsigned int uio_num; 109*831dba47SStephen Hemminger struct dirent *e; 110*831dba47SStephen Hemminger DIR *dir; 111*831dba47SStephen Hemminger 112*831dba47SStephen Hemminger /* Assume recent kernel where uio is in uio/uioX */ 113*831dba47SStephen Hemminger snprintf(dirname, sizeof(dirname), 114*831dba47SStephen Hemminger SYSFS_VMBUS_DEVICES "/%s/uio", dev->device.name); 115*831dba47SStephen Hemminger 116*831dba47SStephen Hemminger dir = opendir(dirname); 117*831dba47SStephen Hemminger if (dir == NULL) 118*831dba47SStephen Hemminger return -1; /* Not a UIO device */ 119*831dba47SStephen Hemminger 120*831dba47SStephen Hemminger /* take the first file starting with "uio" */ 121*831dba47SStephen Hemminger while ((e = readdir(dir)) != NULL) { 122*831dba47SStephen Hemminger const int prefix_len = 3; 123*831dba47SStephen Hemminger char *endptr; 124*831dba47SStephen Hemminger 125*831dba47SStephen Hemminger if (strncmp(e->d_name, "uio", prefix_len) != 0) 126*831dba47SStephen Hemminger continue; 127*831dba47SStephen Hemminger 128*831dba47SStephen Hemminger /* try uio%d */ 129*831dba47SStephen Hemminger errno = 0; 130*831dba47SStephen Hemminger uio_num = strtoull(e->d_name + prefix_len, &endptr, 10); 131*831dba47SStephen Hemminger if (errno == 0 && endptr != (e->d_name + prefix_len)) { 132*831dba47SStephen Hemminger snprintf(dstbuf, buflen, "%s/uio%u", dirname, uio_num); 133*831dba47SStephen Hemminger break; 134*831dba47SStephen Hemminger } 135*831dba47SStephen Hemminger } 136*831dba47SStephen Hemminger closedir(dir); 137*831dba47SStephen Hemminger 138*831dba47SStephen Hemminger if (e == NULL) 139*831dba47SStephen Hemminger return -1; 140*831dba47SStephen Hemminger 141*831dba47SStephen Hemminger return uio_num; 142*831dba47SStephen Hemminger } 143*831dba47SStephen Hemminger 144*831dba47SStephen Hemminger /* Check map names with kernel names */ 145*831dba47SStephen Hemminger static const char *map_names[VMBUS_MAX_RESOURCE] = { 146*831dba47SStephen Hemminger [HV_TXRX_RING_MAP] = "txrx_rings", 147*831dba47SStephen Hemminger [HV_INT_PAGE_MAP] = "int_page", 148*831dba47SStephen Hemminger [HV_MON_PAGE_MAP] = "monitor_page", 149*831dba47SStephen Hemminger [HV_RECV_BUF_MAP] = "recv:", 150*831dba47SStephen Hemminger [HV_SEND_BUF_MAP] = "send:", 151*831dba47SStephen Hemminger }; 152*831dba47SStephen Hemminger 153*831dba47SStephen Hemminger 154*831dba47SStephen Hemminger /* map the resources of a vmbus device in virtual memory */ 155*831dba47SStephen Hemminger int 156*831dba47SStephen Hemminger rte_vmbus_map_device(struct rte_vmbus_device *dev) 157*831dba47SStephen Hemminger { 158*831dba47SStephen Hemminger char uioname[PATH_MAX], filename[PATH_MAX]; 159*831dba47SStephen Hemminger char dirname[PATH_MAX], mapname[64]; 160*831dba47SStephen Hemminger int i; 161*831dba47SStephen Hemminger 162*831dba47SStephen Hemminger dev->uio_num = vmbus_get_uio_dev(dev, uioname, sizeof(uioname)); 163*831dba47SStephen Hemminger if (dev->uio_num < 0) { 164*831dba47SStephen Hemminger VMBUS_LOG(DEBUG, "Not managed by UIO driver, skipped"); 165*831dba47SStephen Hemminger return 1; 166*831dba47SStephen Hemminger } 167*831dba47SStephen Hemminger 168*831dba47SStephen Hemminger /* Extract resource value */ 169*831dba47SStephen Hemminger for (i = 0; i < VMBUS_MAX_RESOURCE; i++) { 170*831dba47SStephen Hemminger struct rte_mem_resource *res = &dev->resource[i]; 171*831dba47SStephen Hemminger unsigned long len, gpad = 0; 172*831dba47SStephen Hemminger char *cp; 173*831dba47SStephen Hemminger 174*831dba47SStephen Hemminger snprintf(dirname, sizeof(dirname), 175*831dba47SStephen Hemminger "%s/maps/map%d", uioname, i); 176*831dba47SStephen Hemminger 177*831dba47SStephen Hemminger snprintf(filename, sizeof(filename), 178*831dba47SStephen Hemminger "%s/name", dirname); 179*831dba47SStephen Hemminger 180*831dba47SStephen Hemminger if (get_sysfs_string(filename, mapname, sizeof(mapname)) < 0) { 181*831dba47SStephen Hemminger VMBUS_LOG(ERR, "could not read %s", filename); 182*831dba47SStephen Hemminger return -1; 183*831dba47SStephen Hemminger } 184*831dba47SStephen Hemminger 185*831dba47SStephen Hemminger if (strncmp(map_names[i], mapname, strlen(map_names[i])) != 0) { 186*831dba47SStephen Hemminger VMBUS_LOG(ERR, 187*831dba47SStephen Hemminger "unexpected resource %s (expected %s)", 188*831dba47SStephen Hemminger mapname, map_names[i]); 189*831dba47SStephen Hemminger return -1; 190*831dba47SStephen Hemminger } 191*831dba47SStephen Hemminger 192*831dba47SStephen Hemminger snprintf(filename, sizeof(filename), 193*831dba47SStephen Hemminger "%s/size", dirname); 194*831dba47SStephen Hemminger if (eal_parse_sysfs_value(filename, &len) < 0) { 195*831dba47SStephen Hemminger VMBUS_LOG(ERR, 196*831dba47SStephen Hemminger "could not read %s", filename); 197*831dba47SStephen Hemminger return -1; 198*831dba47SStephen Hemminger } 199*831dba47SStephen Hemminger res->len = len; 200*831dba47SStephen Hemminger 201*831dba47SStephen Hemminger /* both send and receive buffers have gpad in name */ 202*831dba47SStephen Hemminger cp = memchr(mapname, ':', sizeof(mapname)); 203*831dba47SStephen Hemminger if (cp) 204*831dba47SStephen Hemminger gpad = strtoul(cp+1, NULL, 0); 205*831dba47SStephen Hemminger 206*831dba47SStephen Hemminger /* put the GPAD value in physical address */ 207*831dba47SStephen Hemminger res->phys_addr = gpad; 208*831dba47SStephen Hemminger } 209*831dba47SStephen Hemminger 210*831dba47SStephen Hemminger return vmbus_uio_map_resource(dev); 211*831dba47SStephen Hemminger } 212*831dba47SStephen Hemminger 213*831dba47SStephen Hemminger void 214*831dba47SStephen Hemminger rte_vmbus_unmap_device(struct rte_vmbus_device *dev) 215*831dba47SStephen Hemminger { 216*831dba47SStephen Hemminger vmbus_uio_unmap_resource(dev); 217*831dba47SStephen Hemminger } 218*831dba47SStephen Hemminger 219*831dba47SStephen Hemminger /* Scan one vmbus sysfs entry, and fill the devices list from it. */ 220*831dba47SStephen Hemminger static int 221*831dba47SStephen Hemminger vmbus_scan_one(const char *name) 222*831dba47SStephen Hemminger { 223*831dba47SStephen Hemminger struct rte_vmbus_device *dev, *dev2; 224*831dba47SStephen Hemminger char filename[PATH_MAX]; 225*831dba47SStephen Hemminger char dirname[PATH_MAX]; 226*831dba47SStephen Hemminger unsigned long tmp; 227*831dba47SStephen Hemminger 228*831dba47SStephen Hemminger dev = calloc(1, sizeof(*dev)); 229*831dba47SStephen Hemminger if (dev == NULL) 230*831dba47SStephen Hemminger return -1; 231*831dba47SStephen Hemminger 232*831dba47SStephen Hemminger dev->device.name = strdup(name); 233*831dba47SStephen Hemminger if (!dev->device.name) 234*831dba47SStephen Hemminger goto error; 235*831dba47SStephen Hemminger 236*831dba47SStephen Hemminger /* sysfs base directory 237*831dba47SStephen Hemminger * /sys/bus/vmbus/devices/7a08391f-f5a0-4ac0-9802-d13fd964f8df 238*831dba47SStephen Hemminger * or on older kernel 239*831dba47SStephen Hemminger * /sys/bus/vmbus/devices/vmbus_1 240*831dba47SStephen Hemminger */ 241*831dba47SStephen Hemminger snprintf(dirname, sizeof(dirname), "%s/%s", 242*831dba47SStephen Hemminger SYSFS_VMBUS_DEVICES, name); 243*831dba47SStephen Hemminger 244*831dba47SStephen Hemminger /* get device id */ 245*831dba47SStephen Hemminger snprintf(filename, sizeof(filename), "%s/device_id", dirname); 246*831dba47SStephen Hemminger if (parse_sysfs_uuid(filename, dev->device_id) < 0) 247*831dba47SStephen Hemminger goto error; 248*831dba47SStephen Hemminger 249*831dba47SStephen Hemminger /* get device class */ 250*831dba47SStephen Hemminger snprintf(filename, sizeof(filename), "%s/class_id", dirname); 251*831dba47SStephen Hemminger if (parse_sysfs_uuid(filename, dev->class_id) < 0) 252*831dba47SStephen Hemminger goto error; 253*831dba47SStephen Hemminger 254*831dba47SStephen Hemminger /* get relid */ 255*831dba47SStephen Hemminger snprintf(filename, sizeof(filename), "%s/id", dirname); 256*831dba47SStephen Hemminger if (eal_parse_sysfs_value(filename, &tmp) < 0) 257*831dba47SStephen Hemminger goto error; 258*831dba47SStephen Hemminger dev->relid = tmp; 259*831dba47SStephen Hemminger 260*831dba47SStephen Hemminger /* get monitor id */ 261*831dba47SStephen Hemminger snprintf(filename, sizeof(filename), "%s/monitor_id", dirname); 262*831dba47SStephen Hemminger if (eal_parse_sysfs_value(filename, &tmp) < 0) 263*831dba47SStephen Hemminger goto error; 264*831dba47SStephen Hemminger dev->monitor_id = tmp; 265*831dba47SStephen Hemminger 266*831dba47SStephen Hemminger /* get numa node (if present) */ 267*831dba47SStephen Hemminger snprintf(filename, sizeof(filename), "%s/numa_node", 268*831dba47SStephen Hemminger dirname); 269*831dba47SStephen Hemminger 270*831dba47SStephen Hemminger if (access(filename, R_OK) == 0) { 271*831dba47SStephen Hemminger if (eal_parse_sysfs_value(filename, &tmp) < 0) 272*831dba47SStephen Hemminger goto error; 273*831dba47SStephen Hemminger dev->device.numa_node = tmp; 274*831dba47SStephen Hemminger } else { 275*831dba47SStephen Hemminger /* if no NUMA support, set default to 0 */ 276*831dba47SStephen Hemminger dev->device.numa_node = SOCKET_ID_ANY; 277*831dba47SStephen Hemminger } 278*831dba47SStephen Hemminger 279*831dba47SStephen Hemminger /* device is valid, add in list (sorted) */ 280*831dba47SStephen Hemminger VMBUS_LOG(DEBUG, "Adding vmbus device %s", name); 281*831dba47SStephen Hemminger 282*831dba47SStephen Hemminger TAILQ_FOREACH(dev2, &rte_vmbus_bus.device_list, next) { 283*831dba47SStephen Hemminger int ret; 284*831dba47SStephen Hemminger 285*831dba47SStephen Hemminger ret = rte_uuid_compare(dev->device_id, dev2->device_id); 286*831dba47SStephen Hemminger if (ret > 0) 287*831dba47SStephen Hemminger continue; 288*831dba47SStephen Hemminger 289*831dba47SStephen Hemminger if (ret < 0) { 290*831dba47SStephen Hemminger vmbus_insert_device(dev2, dev); 291*831dba47SStephen Hemminger } else { /* already registered */ 292*831dba47SStephen Hemminger VMBUS_LOG(NOTICE, 293*831dba47SStephen Hemminger "%s already registered", name); 294*831dba47SStephen Hemminger free(dev); 295*831dba47SStephen Hemminger } 296*831dba47SStephen Hemminger return 0; 297*831dba47SStephen Hemminger } 298*831dba47SStephen Hemminger 299*831dba47SStephen Hemminger vmbus_add_device(dev); 300*831dba47SStephen Hemminger return 0; 301*831dba47SStephen Hemminger error: 302*831dba47SStephen Hemminger VMBUS_LOG(DEBUG, "failed"); 303*831dba47SStephen Hemminger 304*831dba47SStephen Hemminger free(dev); 305*831dba47SStephen Hemminger return -1; 306*831dba47SStephen Hemminger } 307*831dba47SStephen Hemminger 308*831dba47SStephen Hemminger /* 309*831dba47SStephen Hemminger * Scan the content of the vmbus, and the devices in the devices list 310*831dba47SStephen Hemminger */ 311*831dba47SStephen Hemminger int 312*831dba47SStephen Hemminger rte_vmbus_scan(void) 313*831dba47SStephen Hemminger { 314*831dba47SStephen Hemminger struct dirent *e; 315*831dba47SStephen Hemminger DIR *dir; 316*831dba47SStephen Hemminger 317*831dba47SStephen Hemminger dir = opendir(SYSFS_VMBUS_DEVICES); 318*831dba47SStephen Hemminger if (dir == NULL) { 319*831dba47SStephen Hemminger if (errno == ENOENT) 320*831dba47SStephen Hemminger return 0; 321*831dba47SStephen Hemminger 322*831dba47SStephen Hemminger VMBUS_LOG(ERR, "opendir %s failed: %s", 323*831dba47SStephen Hemminger SYSFS_VMBUS_DEVICES, strerror(errno)); 324*831dba47SStephen Hemminger return -1; 325*831dba47SStephen Hemminger } 326*831dba47SStephen Hemminger 327*831dba47SStephen Hemminger while ((e = readdir(dir)) != NULL) { 328*831dba47SStephen Hemminger if (e->d_name[0] == '.') 329*831dba47SStephen Hemminger continue; 330*831dba47SStephen Hemminger 331*831dba47SStephen Hemminger if (vmbus_scan_one(e->d_name) < 0) 332*831dba47SStephen Hemminger goto error; 333*831dba47SStephen Hemminger } 334*831dba47SStephen Hemminger closedir(dir); 335*831dba47SStephen Hemminger return 0; 336*831dba47SStephen Hemminger 337*831dba47SStephen Hemminger error: 338*831dba47SStephen Hemminger closedir(dir); 339*831dba47SStephen Hemminger return -1; 340*831dba47SStephen Hemminger } 341*831dba47SStephen Hemminger 342*831dba47SStephen Hemminger void rte_vmbus_irq_mask(struct rte_vmbus_device *device) 343*831dba47SStephen Hemminger { 344*831dba47SStephen Hemminger vmbus_uio_irq_control(device, 1); 345*831dba47SStephen Hemminger } 346*831dba47SStephen Hemminger 347*831dba47SStephen Hemminger void rte_vmbus_irq_unmask(struct rte_vmbus_device *device) 348*831dba47SStephen Hemminger { 349*831dba47SStephen Hemminger vmbus_uio_irq_control(device, 0); 350*831dba47SStephen Hemminger } 351*831dba47SStephen Hemminger 352*831dba47SStephen Hemminger int rte_vmbus_irq_read(struct rte_vmbus_device *device) 353*831dba47SStephen Hemminger { 354*831dba47SStephen Hemminger return vmbus_uio_irq_read(device); 355*831dba47SStephen Hemminger } 356