1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright (c) 2018, Microsoft Corporation. 3 * All Rights Reserved. 4 */ 5 6 #include <string.h> 7 #include <unistd.h> 8 #include <fcntl.h> 9 #include <dirent.h> 10 #include <inttypes.h> 11 #include <sys/stat.h> 12 #include <sys/mman.h> 13 14 #include <rte_log.h> 15 #include <rte_bus.h> 16 #include <rte_memory.h> 17 #include <rte_eal_memconfig.h> 18 #include <rte_common.h> 19 #include <rte_malloc.h> 20 #include <rte_bus_vmbus.h> 21 #include <rte_string_fns.h> 22 23 #include "private.h" 24 25 /** Pathname of VMBUS devices directory. */ 26 #define SYSFS_VMBUS_DEVICES "/sys/bus/vmbus/devices" 27 28 static void *vmbus_map_addr; 29 30 /* Control interrupts */ 31 void vmbus_uio_irq_control(struct rte_vmbus_device *dev, int32_t onoff) 32 { 33 if (write(dev->intr_handle.fd, &onoff, sizeof(onoff)) < 0) { 34 VMBUS_LOG(ERR, "cannot write to %d:%s", 35 dev->intr_handle.fd, strerror(errno)); 36 } 37 } 38 39 int vmbus_uio_irq_read(struct rte_vmbus_device *dev) 40 { 41 int32_t count; 42 int cc; 43 44 cc = read(dev->intr_handle.fd, &count, sizeof(count)); 45 if (cc < (int)sizeof(count)) { 46 if (cc < 0) { 47 VMBUS_LOG(ERR, "IRQ read failed %s", 48 strerror(errno)); 49 return -errno; 50 } 51 VMBUS_LOG(ERR, "can't read IRQ count"); 52 return -EINVAL; 53 } 54 55 return count; 56 } 57 58 void 59 vmbus_uio_free_resource(struct rte_vmbus_device *dev, 60 struct mapped_vmbus_resource *uio_res) 61 { 62 rte_free(uio_res); 63 64 if (dev->intr_handle.uio_cfg_fd >= 0) { 65 close(dev->intr_handle.uio_cfg_fd); 66 dev->intr_handle.uio_cfg_fd = -1; 67 } 68 69 if (dev->intr_handle.fd >= 0) { 70 close(dev->intr_handle.fd); 71 dev->intr_handle.fd = -1; 72 dev->intr_handle.type = RTE_INTR_HANDLE_UNKNOWN; 73 } 74 } 75 76 int 77 vmbus_uio_alloc_resource(struct rte_vmbus_device *dev, 78 struct mapped_vmbus_resource **uio_res) 79 { 80 char devname[PATH_MAX]; /* contains the /dev/uioX */ 81 82 /* save fd if in primary process */ 83 snprintf(devname, sizeof(devname), "/dev/uio%u", dev->uio_num); 84 dev->intr_handle.fd = open(devname, O_RDWR); 85 if (dev->intr_handle.fd < 0) { 86 VMBUS_LOG(ERR, "Cannot open %s: %s", 87 devname, strerror(errno)); 88 goto error; 89 } 90 dev->intr_handle.type = RTE_INTR_HANDLE_UIO_INTX; 91 92 /* allocate the mapping details for secondary processes*/ 93 *uio_res = rte_zmalloc("UIO_RES", sizeof(**uio_res), 0); 94 if (*uio_res == NULL) { 95 VMBUS_LOG(ERR, "cannot store uio mmap details"); 96 goto error; 97 } 98 99 strlcpy((*uio_res)->path, devname, PATH_MAX); 100 rte_uuid_copy((*uio_res)->id, dev->device_id); 101 102 return 0; 103 104 error: 105 vmbus_uio_free_resource(dev, *uio_res); 106 return -1; 107 } 108 109 static int 110 find_max_end_va(const struct rte_memseg_list *msl, void *arg) 111 { 112 size_t sz = msl->memseg_arr.len * msl->page_sz; 113 void *end_va = RTE_PTR_ADD(msl->base_va, sz); 114 void **max_va = arg; 115 116 if (*max_va < end_va) 117 *max_va = end_va; 118 return 0; 119 } 120 121 /* 122 * TODO: this should be part of memseg api. 123 * code is duplicated from PCI. 124 */ 125 static void * 126 vmbus_find_max_end_va(void) 127 { 128 void *va = NULL; 129 130 rte_memseg_list_walk(find_max_end_va, &va); 131 return va; 132 } 133 134 int 135 vmbus_uio_map_resource_by_index(struct rte_vmbus_device *dev, int idx, 136 struct mapped_vmbus_resource *uio_res, 137 int flags) 138 { 139 size_t size = dev->resource[idx].len; 140 struct vmbus_map *maps = uio_res->maps; 141 void *mapaddr; 142 off_t offset; 143 int fd; 144 145 /* devname for mmap */ 146 fd = open(uio_res->path, O_RDWR); 147 if (fd < 0) { 148 VMBUS_LOG(ERR, "Cannot open %s: %s", 149 uio_res->path, strerror(errno)); 150 return -1; 151 } 152 153 /* try mapping somewhere close to the end of hugepages */ 154 if (vmbus_map_addr == NULL) 155 vmbus_map_addr = vmbus_find_max_end_va(); 156 157 /* offset is special in uio it indicates which resource */ 158 offset = idx * PAGE_SIZE; 159 160 mapaddr = vmbus_map_resource(vmbus_map_addr, fd, offset, size, flags); 161 close(fd); 162 163 if (mapaddr == MAP_FAILED) 164 return -1; 165 166 dev->resource[idx].addr = mapaddr; 167 vmbus_map_addr = RTE_PTR_ADD(mapaddr, size); 168 169 /* Record result of sucessful mapping for use by secondary */ 170 maps[idx].addr = mapaddr; 171 maps[idx].size = size; 172 173 return 0; 174 } 175 176 static int vmbus_uio_map_primary(struct vmbus_channel *chan, 177 void **ring_buf, uint32_t *ring_size) 178 { 179 struct mapped_vmbus_resource *uio_res; 180 181 uio_res = vmbus_uio_find_resource(chan->device); 182 if (!uio_res) { 183 VMBUS_LOG(ERR, "can not find resources!"); 184 return -ENOMEM; 185 } 186 187 if (uio_res->nb_maps < VMBUS_MAX_RESOURCE) { 188 VMBUS_LOG(ERR, "VMBUS: only %u resources found!", 189 uio_res->nb_maps); 190 return -EINVAL; 191 } 192 193 *ring_size = uio_res->maps[HV_TXRX_RING_MAP].size / 2; 194 *ring_buf = uio_res->maps[HV_TXRX_RING_MAP].addr; 195 return 0; 196 } 197 198 static int vmbus_uio_map_subchan(const struct rte_vmbus_device *dev, 199 const struct vmbus_channel *chan, 200 void **ring_buf, uint32_t *ring_size) 201 { 202 char ring_path[PATH_MAX]; 203 size_t file_size; 204 struct stat sb; 205 void *mapaddr; 206 int fd; 207 208 snprintf(ring_path, sizeof(ring_path), 209 "%s/%s/channels/%u/ring", 210 SYSFS_VMBUS_DEVICES, dev->device.name, 211 chan->relid); 212 213 fd = open(ring_path, O_RDWR); 214 if (fd < 0) { 215 VMBUS_LOG(ERR, "Cannot open %s: %s", 216 ring_path, strerror(errno)); 217 return -errno; 218 } 219 220 if (fstat(fd, &sb) < 0) { 221 VMBUS_LOG(ERR, "Cannot state %s: %s", 222 ring_path, strerror(errno)); 223 close(fd); 224 return -errno; 225 } 226 file_size = sb.st_size; 227 228 if (file_size == 0 || (file_size & (PAGE_SIZE - 1))) { 229 VMBUS_LOG(ERR, "incorrect size %s: %zu", 230 ring_path, file_size); 231 232 close(fd); 233 return -EINVAL; 234 } 235 236 mapaddr = vmbus_map_resource(vmbus_map_addr, fd, 237 0, file_size, 0); 238 close(fd); 239 240 if (mapaddr == MAP_FAILED) 241 return -EIO; 242 243 *ring_size = file_size / 2; 244 *ring_buf = mapaddr; 245 246 vmbus_map_addr = RTE_PTR_ADD(ring_buf, file_size); 247 return 0; 248 } 249 250 int 251 vmbus_uio_map_secondary_subchan(const struct rte_vmbus_device *dev, 252 const struct vmbus_channel *chan) 253 { 254 const struct vmbus_br *br = &chan->txbr; 255 char ring_path[PATH_MAX]; 256 void *mapaddr, *ring_buf; 257 uint32_t ring_size; 258 int fd; 259 260 snprintf(ring_path, sizeof(ring_path), 261 "%s/%s/channels/%u/ring", 262 SYSFS_VMBUS_DEVICES, dev->device.name, 263 chan->relid); 264 265 ring_buf = br->vbr; 266 ring_size = br->dsize + sizeof(struct vmbus_bufring); 267 VMBUS_LOG(INFO, "secondary ring_buf %p size %u", 268 ring_buf, ring_size); 269 270 fd = open(ring_path, O_RDWR); 271 if (fd < 0) { 272 VMBUS_LOG(ERR, "Cannot open %s: %s", 273 ring_path, strerror(errno)); 274 return -errno; 275 } 276 277 mapaddr = vmbus_map_resource(ring_buf, fd, 0, 2 * ring_size, 0); 278 close(fd); 279 280 if (mapaddr == ring_buf) 281 return 0; 282 283 if (mapaddr == MAP_FAILED) 284 VMBUS_LOG(ERR, 285 "mmap subchan %u in secondary failed", chan->relid); 286 else 287 VMBUS_LOG(ERR, 288 "mmap subchan %u in secondary address mismatch", 289 chan->relid); 290 return -1; 291 } 292 293 int vmbus_uio_map_rings(struct vmbus_channel *chan) 294 { 295 const struct rte_vmbus_device *dev = chan->device; 296 uint32_t ring_size; 297 void *ring_buf; 298 int ret; 299 300 /* Primary channel */ 301 if (chan->subchannel_id == 0) 302 ret = vmbus_uio_map_primary(chan, &ring_buf, &ring_size); 303 else 304 ret = vmbus_uio_map_subchan(dev, chan, &ring_buf, &ring_size); 305 306 if (ret) 307 return ret; 308 309 vmbus_br_setup(&chan->txbr, ring_buf, ring_size); 310 vmbus_br_setup(&chan->rxbr, (char *)ring_buf + ring_size, ring_size); 311 return 0; 312 } 313 314 static int vmbus_uio_sysfs_read(const char *dir, const char *name, 315 unsigned long *val, unsigned long max_range) 316 { 317 char path[PATH_MAX]; 318 FILE *f; 319 int ret; 320 321 snprintf(path, sizeof(path), "%s/%s", dir, name); 322 f = fopen(path, "r"); 323 if (!f) { 324 VMBUS_LOG(ERR, "can't open %s:%s", 325 path, strerror(errno)); 326 return -errno; 327 } 328 329 if (fscanf(f, "%lu", val) != 1) 330 ret = -EIO; 331 else if (*val > max_range) 332 ret = -ERANGE; 333 else 334 ret = 0; 335 fclose(f); 336 337 return ret; 338 } 339 340 static bool vmbus_uio_ring_present(const struct rte_vmbus_device *dev, 341 uint32_t relid) 342 { 343 char ring_path[PATH_MAX]; 344 345 /* Check if kernel has subchannel sysfs files */ 346 snprintf(ring_path, sizeof(ring_path), 347 "%s/%s/channels/%u/ring", 348 SYSFS_VMBUS_DEVICES, dev->device.name, relid); 349 350 return access(ring_path, R_OK|W_OK) == 0; 351 } 352 353 bool vmbus_uio_subchannels_supported(const struct rte_vmbus_device *dev, 354 const struct vmbus_channel *chan) 355 { 356 return vmbus_uio_ring_present(dev, chan->relid); 357 } 358 359 static bool vmbus_isnew_subchannel(struct vmbus_channel *primary, 360 unsigned long id) 361 { 362 const struct vmbus_channel *c; 363 364 STAILQ_FOREACH(c, &primary->subchannel_list, next) { 365 if (c->relid == id) 366 return false; 367 } 368 return true; 369 } 370 371 int vmbus_uio_get_subchan(struct vmbus_channel *primary, 372 struct vmbus_channel **subchan) 373 { 374 const struct rte_vmbus_device *dev = primary->device; 375 char chan_path[PATH_MAX], subchan_path[PATH_MAX]; 376 struct dirent *ent; 377 DIR *chan_dir; 378 int err; 379 380 snprintf(chan_path, sizeof(chan_path), 381 "%s/%s/channels", 382 SYSFS_VMBUS_DEVICES, dev->device.name); 383 384 chan_dir = opendir(chan_path); 385 if (!chan_dir) { 386 VMBUS_LOG(ERR, "cannot open %s: %s", 387 chan_path, strerror(errno)); 388 return -errno; 389 } 390 391 while ((ent = readdir(chan_dir))) { 392 unsigned long relid, subid, monid; 393 char *endp; 394 395 if (ent->d_name[0] == '.') 396 continue; 397 398 errno = 0; 399 relid = strtoul(ent->d_name, &endp, 0); 400 if (*endp || errno != 0 || relid > UINT16_MAX) { 401 VMBUS_LOG(NOTICE, "not a valid channel relid: %s", 402 ent->d_name); 403 continue; 404 } 405 406 if (!vmbus_isnew_subchannel(primary, relid)) { 407 VMBUS_LOG(DEBUG, "skip already found channel: %lu", 408 relid); 409 continue; 410 } 411 412 if (!vmbus_uio_ring_present(dev, relid)) { 413 VMBUS_LOG(DEBUG, "ring mmap not found (yet) for: %lu", 414 relid); 415 continue; 416 } 417 418 snprintf(subchan_path, sizeof(subchan_path), "%s/%lu", 419 chan_path, relid); 420 err = vmbus_uio_sysfs_read(subchan_path, "subchannel_id", 421 &subid, UINT16_MAX); 422 if (err) { 423 VMBUS_LOG(NOTICE, "no subchannel_id in %s:%s", 424 subchan_path, strerror(-err)); 425 goto fail; 426 } 427 428 if (subid == 0) 429 continue; /* skip primary channel */ 430 431 err = vmbus_uio_sysfs_read(subchan_path, "monitor_id", 432 &monid, UINT8_MAX); 433 if (err) { 434 VMBUS_LOG(NOTICE, "no monitor_id in %s:%s", 435 subchan_path, strerror(-err)); 436 goto fail; 437 } 438 439 err = vmbus_chan_create(dev, relid, subid, monid, subchan); 440 if (err) { 441 VMBUS_LOG(ERR, "subchannel setup failed"); 442 goto fail; 443 } 444 break; 445 } 446 closedir(chan_dir); 447 448 return (ent == NULL) ? -ENOENT : 0; 449 fail: 450 closedir(chan_dir); 451 return err; 452 } 453