1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(C) 2023 Marvell. 3 */ 4 5 #include <dirent.h> 6 #include <inttypes.h> 7 #include <stdlib.h> 8 #include <string.h> 9 #include <sys/ioctl.h> 10 #include <sys/mman.h> 11 #include <sys/queue.h> 12 #include <unistd.h> 13 14 #include <bus_driver.h> 15 #include <bus_platform_driver.h> 16 #include <eal_filesystem.h> 17 #include <rte_bus.h> 18 #include <rte_devargs.h> 19 #include <rte_errno.h> 20 #include <rte_log.h> 21 #include <rte_memory.h> 22 #include <rte_string_fns.h> 23 #include <rte_vfio.h> 24 25 #include "private.h" 26 27 #ifdef VFIO_PRESENT 28 29 #define PLATFORM_BUS_DEVICES_PATH "/sys/bus/platform/devices" 30 31 void 32 rte_platform_register(struct rte_platform_driver *pdrv) 33 { 34 TAILQ_INSERT_TAIL(&platform_bus.driver_list, pdrv, next); 35 } 36 37 void 38 rte_platform_unregister(struct rte_platform_driver *pdrv) 39 { 40 TAILQ_REMOVE(&platform_bus.driver_list, pdrv, next); 41 } 42 43 static struct rte_devargs * 44 dev_devargs(const char *dev_name) 45 { 46 struct rte_devargs *devargs; 47 48 RTE_EAL_DEVARGS_FOREACH("platform", devargs) { 49 if (!strcmp(devargs->name, dev_name)) 50 return devargs; 51 } 52 53 return NULL; 54 } 55 56 static bool 57 dev_allowed(const char *dev_name) 58 { 59 struct rte_devargs *devargs; 60 61 devargs = dev_devargs(dev_name); 62 if (devargs == NULL) 63 return true; 64 65 switch (platform_bus.bus.conf.scan_mode) { 66 case RTE_BUS_SCAN_UNDEFINED: 67 case RTE_BUS_SCAN_ALLOWLIST: 68 if (devargs->policy == RTE_DEV_ALLOWED) 69 return true; 70 break; 71 case RTE_BUS_SCAN_BLOCKLIST: 72 if (devargs->policy == RTE_DEV_BLOCKED) 73 return false; 74 break; 75 } 76 77 return true; 78 } 79 80 static int 81 dev_add(const char *dev_name) 82 { 83 struct rte_platform_device *pdev, *tmp; 84 char path[PATH_MAX]; 85 unsigned long val; 86 87 pdev = calloc(1, sizeof(*pdev)); 88 if (pdev == NULL) 89 return -ENOMEM; 90 91 rte_strscpy(pdev->name, dev_name, sizeof(pdev->name)); 92 pdev->device.name = pdev->name; 93 pdev->device.devargs = dev_devargs(dev_name); 94 pdev->device.bus = &platform_bus.bus; 95 snprintf(path, sizeof(path), PLATFORM_BUS_DEVICES_PATH "/%s/numa_node", dev_name); 96 pdev->device.numa_node = eal_parse_sysfs_value(path, &val) ? rte_socket_id() : val; 97 98 FOREACH_DEVICE_ON_PLATFORM_BUS(tmp) { 99 if (!strcmp(tmp->name, pdev->name)) { 100 PLATFORM_LOG_LINE(INFO, "device %s already added", pdev->name); 101 102 if (tmp->device.devargs != pdev->device.devargs) 103 rte_devargs_remove(pdev->device.devargs); 104 105 free(pdev); 106 return -EEXIST; 107 } 108 } 109 110 TAILQ_INSERT_HEAD(&platform_bus.device_list, pdev, next); 111 112 PLATFORM_LOG_LINE(INFO, "adding device %s to the list", dev_name); 113 114 return 0; 115 } 116 117 static char * 118 dev_kernel_driver_name(const char *dev_name) 119 { 120 char path[PATH_MAX], buf[BUFSIZ] = { }; 121 char *kdrv; 122 int ret; 123 124 snprintf(path, sizeof(path), PLATFORM_BUS_DEVICES_PATH "/%s/driver", dev_name); 125 /* save space for NUL */ 126 ret = readlink(path, buf, sizeof(buf) - 1); 127 if (ret <= 0) 128 return NULL; 129 130 /* last token is kernel driver name */ 131 kdrv = strrchr(buf, '/'); 132 if (kdrv != NULL) 133 return strdup(kdrv + 1); 134 135 return NULL; 136 } 137 138 static bool 139 dev_is_bound_vfio_platform(const char *dev_name) 140 { 141 char *kdrv; 142 int ret; 143 144 kdrv = dev_kernel_driver_name(dev_name); 145 if (!kdrv) 146 return false; 147 148 ret = strcmp(kdrv, "vfio-platform"); 149 free(kdrv); 150 151 return ret == 0; 152 } 153 154 static int 155 platform_bus_scan(void) 156 { 157 const struct dirent *ent; 158 const char *dev_name; 159 int ret = 0; 160 DIR *dp; 161 162 dp = opendir(PLATFORM_BUS_DEVICES_PATH); 163 if (dp == NULL) { 164 PLATFORM_LOG_LINE(INFO, "failed to open %s", PLATFORM_BUS_DEVICES_PATH); 165 return -errno; 166 } 167 168 while ((ent = readdir(dp))) { 169 dev_name = ent->d_name; 170 if (dev_name[0] == '.') 171 continue; 172 173 if (!dev_allowed(dev_name)) 174 continue; 175 176 if (!dev_is_bound_vfio_platform(dev_name)) 177 continue; 178 179 ret = dev_add(dev_name); 180 if (ret) 181 break; 182 } 183 184 closedir(dp); 185 186 return ret; 187 } 188 189 static int 190 device_map_resource_offset(struct rte_platform_device *pdev, struct rte_platform_resource *res, 191 size_t offset) 192 { 193 res->mem.addr = mmap(NULL, res->mem.len, PROT_READ | PROT_WRITE, MAP_SHARED, pdev->dev_fd, 194 offset); 195 if (res->mem.addr == MAP_FAILED) 196 return -errno; 197 198 PLATFORM_LOG_LINE(DEBUG, "adding resource va = %p len = %"PRIu64" name = %s", res->mem.addr, 199 res->mem.len, res->name); 200 201 return 0; 202 } 203 204 static void 205 device_unmap_resources(struct rte_platform_device *pdev) 206 { 207 struct rte_platform_resource *res; 208 unsigned int i; 209 210 for (i = 0; i < pdev->num_resource; i++) { 211 res = &pdev->resource[i]; 212 munmap(res->mem.addr, res->mem.len); 213 free(res->name); 214 } 215 216 free(pdev->resource); 217 pdev->resource = NULL; 218 pdev->num_resource = 0; 219 } 220 221 static int 222 read_sysfs_string(const char *path, char *buf, size_t size) 223 { 224 FILE *f; 225 char *p; 226 227 f = fopen(path, "r"); 228 if (f == NULL) 229 return -errno; 230 231 if (fgets(buf, size, f) == NULL) { 232 fclose(f); 233 return -ENODATA; 234 } 235 236 fclose(f); 237 238 p = strrchr(buf, '\n'); 239 if (p != NULL) 240 *p = '\0'; 241 242 return 0; 243 } 244 245 static char * 246 of_resource_name(const char *dev_name, int index) 247 { 248 char path[PATH_MAX], buf[BUFSIZ] = { }; 249 int num = 0, ret; 250 char *name; 251 252 snprintf(path, sizeof(path), PLATFORM_BUS_DEVICES_PATH "/%s/of_node/reg-names", dev_name); 253 ret = read_sysfs_string(path, buf, sizeof(buf) - 1); 254 if (ret) 255 return NULL; 256 257 for (name = buf; *name != 0; name += strlen(name) + 1) { 258 if (num++ != index) 259 continue; 260 return strdup(name); 261 } 262 263 return NULL; 264 } 265 266 static int 267 device_map_resources(struct rte_platform_device *pdev, unsigned int num) 268 { 269 struct rte_platform_resource *res; 270 unsigned int i; 271 int ret; 272 273 if (num == 0) { 274 PLATFORM_LOG_LINE(WARNING, "device %s has no resources", pdev->name); 275 return 0; 276 } 277 278 pdev->resource = calloc(num, sizeof(*pdev->resource)); 279 if (pdev->resource == NULL) 280 return -ENOMEM; 281 282 for (i = 0; i < num; i++) { 283 struct vfio_region_info reg_info = { 284 .argsz = sizeof(reg_info), 285 .index = i, 286 }; 287 288 ret = ioctl(pdev->dev_fd, VFIO_DEVICE_GET_REGION_INFO, ®_info); 289 if (ret) { 290 PLATFORM_LOG_LINE(ERR, "failed to get region info at %d", i); 291 ret = -errno; 292 goto out; 293 } 294 295 res = &pdev->resource[i]; 296 res->name = of_resource_name(pdev->name, reg_info.index); 297 res->mem.len = reg_info.size; 298 ret = device_map_resource_offset(pdev, res, reg_info.offset); 299 if (ret) { 300 PLATFORM_LOG_LINE(ERR, "failed to ioremap resource at %d", i); 301 goto out; 302 } 303 304 pdev->num_resource++; 305 } 306 307 return 0; 308 out: 309 device_unmap_resources(pdev); 310 311 return ret; 312 } 313 314 static void 315 device_cleanup(struct rte_platform_device *pdev) 316 { 317 device_unmap_resources(pdev); 318 rte_vfio_release_device(PLATFORM_BUS_DEVICES_PATH, pdev->name, pdev->dev_fd); 319 } 320 321 static int 322 device_setup(struct rte_platform_device *pdev) 323 { 324 struct vfio_device_info dev_info = { .argsz = sizeof(dev_info), }; 325 const char *name = pdev->name; 326 int ret; 327 328 ret = rte_vfio_setup_device(PLATFORM_BUS_DEVICES_PATH, name, &pdev->dev_fd, &dev_info); 329 if (ret) { 330 PLATFORM_LOG_LINE(ERR, "failed to setup %s", name); 331 return -ENODEV; 332 } 333 334 /* This is an extra check to confirm that platform device was initialized 335 * by a kernel vfio-platform driver. On kernels that predate vfio-platform 336 * driver this flag obviously does not exist. In such scenarios this 337 * check needs to be removed otherwise compilation fails. 338 * 339 * Now, on such old kernels code will never reach here because 340 * there is another check much earlier which verifies whether 341 * device has been bound to vfio-platform driver. 342 */ 343 #ifdef VFIO_DEVICE_FLAGS_PLATFORM 344 if (!(dev_info.flags & VFIO_DEVICE_FLAGS_PLATFORM)) { 345 PLATFORM_LOG_LINE(ERR, "device not backed by vfio-platform"); 346 ret = -ENOTSUP; 347 goto out; 348 } 349 #endif 350 351 ret = device_map_resources(pdev, dev_info.num_regions); 352 if (ret) { 353 PLATFORM_LOG_LINE(ERR, "failed to setup platform resources"); 354 goto out; 355 } 356 357 return 0; 358 out: 359 device_cleanup(pdev); 360 361 return ret; 362 } 363 364 static int 365 driver_call_probe(struct rte_platform_driver *pdrv, struct rte_platform_device *pdev) 366 { 367 int ret; 368 369 if (rte_dev_is_probed(&pdev->device)) 370 return -EBUSY; 371 372 if (pdrv->probe != NULL) { 373 pdev->driver = pdrv; 374 ret = pdrv->probe(pdev); 375 if (ret) 376 return ret; 377 } 378 379 pdev->device.driver = &pdrv->driver; 380 381 return 0; 382 } 383 384 static int 385 driver_probe_device(struct rte_platform_driver *pdrv, struct rte_platform_device *pdev) 386 { 387 enum rte_iova_mode iova_mode; 388 int ret; 389 390 iova_mode = rte_eal_iova_mode(); 391 if (pdrv->drv_flags & RTE_PLATFORM_DRV_NEED_IOVA_AS_VA && iova_mode != RTE_IOVA_VA) { 392 PLATFORM_LOG_LINE(ERR, "driver %s expects VA IOVA mode but current mode is PA", 393 pdrv->driver.name); 394 return -EINVAL; 395 } 396 397 ret = device_setup(pdev); 398 if (ret) 399 return ret; 400 401 ret = driver_call_probe(pdrv, pdev); 402 if (ret) 403 device_cleanup(pdev); 404 405 return ret; 406 } 407 408 static bool 409 driver_match_device(struct rte_platform_driver *pdrv, struct rte_platform_device *pdev) 410 { 411 bool match = false; 412 char *kdrv; 413 414 kdrv = dev_kernel_driver_name(pdev->name); 415 if (!kdrv) 416 return false; 417 418 /* match by driver name */ 419 if (!strcmp(kdrv, pdrv->driver.name)) { 420 match = true; 421 goto out; 422 } 423 424 /* match by driver alias */ 425 if (pdrv->driver.alias != NULL && !strcmp(kdrv, pdrv->driver.alias)) { 426 match = true; 427 goto out; 428 } 429 430 /* match by device name */ 431 if (!strcmp(pdev->name, pdrv->driver.name)) 432 match = true; 433 434 out: 435 free(kdrv); 436 437 return match; 438 } 439 440 static int 441 device_attach(struct rte_platform_device *pdev) 442 { 443 struct rte_platform_driver *pdrv; 444 445 FOREACH_DRIVER_ON_PLATFORM_BUS(pdrv) { 446 if (driver_match_device(pdrv, pdev)) 447 break; 448 } 449 450 if (pdrv == NULL) 451 return -ENODEV; 452 453 return driver_probe_device(pdrv, pdev); 454 } 455 456 static int 457 platform_bus_probe(void) 458 { 459 struct rte_platform_device *pdev; 460 int ret; 461 462 FOREACH_DEVICE_ON_PLATFORM_BUS(pdev) { 463 ret = device_attach(pdev); 464 if (ret == -EBUSY) { 465 PLATFORM_LOG_LINE(DEBUG, "device %s already probed", pdev->name); 466 continue; 467 } 468 if (ret) 469 PLATFORM_LOG_LINE(ERR, "failed to probe %s", pdev->name); 470 } 471 472 return 0; 473 } 474 475 static struct rte_device * 476 platform_bus_find_device(const struct rte_device *start, rte_dev_cmp_t cmp, const void *data) 477 { 478 struct rte_platform_device *pdev; 479 480 pdev = start ? RTE_TAILQ_NEXT(RTE_DEV_TO_PLATFORM_DEV_CONST(start), next) : 481 RTE_TAILQ_FIRST(&platform_bus.device_list); 482 while (pdev) { 483 if (cmp(&pdev->device, data) == 0) 484 return &pdev->device; 485 486 pdev = RTE_TAILQ_NEXT(pdev, next); 487 } 488 489 return NULL; 490 } 491 492 static int 493 platform_bus_plug(struct rte_device *dev) 494 { 495 struct rte_platform_device *pdev; 496 497 if (!dev_allowed(dev->name)) 498 return -EPERM; 499 500 if (!dev_is_bound_vfio_platform(dev->name)) 501 return -EPERM; 502 503 pdev = RTE_DEV_TO_PLATFORM_DEV(dev); 504 if (pdev == NULL) 505 return -EINVAL; 506 507 return device_attach(pdev); 508 } 509 510 static void 511 device_release_driver(struct rte_platform_device *pdev) 512 { 513 struct rte_platform_driver *pdrv; 514 int ret; 515 516 pdrv = pdev->driver; 517 if (pdrv != NULL && pdrv->remove != NULL) { 518 ret = pdrv->remove(pdev); 519 if (ret) 520 PLATFORM_LOG_LINE(WARNING, "failed to remove %s", pdev->name); 521 } 522 523 pdev->device.driver = NULL; 524 pdev->driver = NULL; 525 } 526 527 static int 528 platform_bus_unplug(struct rte_device *dev) 529 { 530 struct rte_platform_device *pdev; 531 532 pdev = RTE_DEV_TO_PLATFORM_DEV(dev); 533 if (pdev == NULL) 534 return -EINVAL; 535 536 device_release_driver(pdev); 537 device_cleanup(pdev); 538 rte_devargs_remove(pdev->device.devargs); 539 free(pdev); 540 541 return 0; 542 } 543 544 static int 545 platform_bus_parse(const char *name, void *addr) 546 { 547 struct rte_platform_device pdev = { }; 548 struct rte_platform_driver *pdrv; 549 const char **out = addr; 550 551 rte_strscpy(pdev.name, name, sizeof(pdev.name)); 552 553 FOREACH_DRIVER_ON_PLATFORM_BUS(pdrv) { 554 if (driver_match_device(pdrv, &pdev)) 555 break; 556 } 557 558 if (pdrv != NULL && addr != NULL) 559 *out = name; 560 561 return pdrv != NULL ? 0 : -ENODEV; 562 } 563 564 static int 565 platform_bus_dma_map(struct rte_device *dev, void *addr, uint64_t iova, size_t len) 566 { 567 struct rte_platform_device *pdev; 568 569 pdev = RTE_DEV_TO_PLATFORM_DEV(dev); 570 if (pdev == NULL || pdev->driver == NULL) { 571 rte_errno = EINVAL; 572 return -1; 573 } 574 575 if (pdev->driver->dma_map != NULL) 576 return pdev->driver->dma_map(pdev, addr, iova, len); 577 578 return rte_vfio_container_dma_map(RTE_VFIO_DEFAULT_CONTAINER_FD, (uint64_t)addr, iova, len); 579 } 580 581 static int 582 platform_bus_dma_unmap(struct rte_device *dev, void *addr, uint64_t iova, size_t len) 583 { 584 struct rte_platform_device *pdev; 585 586 pdev = RTE_DEV_TO_PLATFORM_DEV(dev); 587 if (pdev == NULL || pdev->driver == NULL) { 588 rte_errno = EINVAL; 589 return -1; 590 } 591 592 if (pdev->driver->dma_unmap != NULL) 593 return pdev->driver->dma_unmap(pdev, addr, iova, len); 594 595 return rte_vfio_container_dma_unmap(RTE_VFIO_DEFAULT_CONTAINER_FD, (uint64_t)addr, iova, 596 len); 597 } 598 599 static enum rte_iova_mode 600 platform_bus_get_iommu_class(void) 601 { 602 struct rte_platform_driver *pdrv; 603 struct rte_platform_device *pdev; 604 605 FOREACH_DEVICE_ON_PLATFORM_BUS(pdev) { 606 pdrv = pdev->driver; 607 if (pdrv != NULL && pdrv->drv_flags & RTE_PLATFORM_DRV_NEED_IOVA_AS_VA) 608 return RTE_IOVA_VA; 609 } 610 611 return RTE_IOVA_DC; 612 } 613 614 static int 615 platform_bus_cleanup(void) 616 { 617 struct rte_platform_device *pdev, *tmp; 618 619 RTE_TAILQ_FOREACH_SAFE(pdev, &platform_bus.device_list, next, tmp) { 620 TAILQ_REMOVE(&platform_bus.device_list, pdev, next); 621 platform_bus_unplug(&pdev->device); 622 } 623 624 return 0; 625 } 626 627 struct rte_platform_bus platform_bus = { 628 .bus = { 629 .scan = platform_bus_scan, 630 .probe = platform_bus_probe, 631 .find_device = platform_bus_find_device, 632 .plug = platform_bus_plug, 633 .unplug = platform_bus_unplug, 634 .parse = platform_bus_parse, 635 .dma_map = platform_bus_dma_map, 636 .dma_unmap = platform_bus_dma_unmap, 637 .get_iommu_class = platform_bus_get_iommu_class, 638 .dev_iterate = platform_bus_dev_iterate, 639 .cleanup = platform_bus_cleanup, 640 }, 641 .device_list = TAILQ_HEAD_INITIALIZER(platform_bus.device_list), 642 .driver_list = TAILQ_HEAD_INITIALIZER(platform_bus.driver_list), 643 }; 644 645 RTE_REGISTER_BUS(platform, platform_bus.bus); 646 RTE_LOG_REGISTER_DEFAULT(platform_bus_logtype, NOTICE); 647 648 #endif /* VFIO_PRESENT */ 649