1 /*- 2 * BSD LICENSE 3 * 4 * Copyright (c) Intel Corporation. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * * Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * * Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the 16 * distribution. 17 * * Neither the name of Intel Corporation nor the names of its 18 * contributors may be used to endorse or promote products derived 19 * from this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 #include "env_internal.h" 35 36 #include <rte_alarm.h> 37 #include "spdk/env.h" 38 39 #define SYSFS_PCI_DRIVERS "/sys/bus/pci/drivers" 40 41 #define PCI_CFG_SIZE 256 42 #define PCI_EXT_CAP_ID_SN 0x03 43 44 /* DPDK 18.11+ hotplug isn't robust. Multiple apps starting at the same time 45 * might cause the internal IPC to misbehave. Just retry in such case. 46 */ 47 #define DPDK_HOTPLUG_RETRY_COUNT 4 48 49 static pthread_mutex_t g_pci_mutex = PTHREAD_MUTEX_INITIALIZER; 50 static TAILQ_HEAD(, spdk_pci_device) g_pci_devices = TAILQ_HEAD_INITIALIZER(g_pci_devices); 51 static TAILQ_HEAD(, spdk_pci_driver) g_pci_drivers = TAILQ_HEAD_INITIALIZER(g_pci_drivers); 52 53 static int 54 spdk_map_bar_rte(struct spdk_pci_device *device, uint32_t bar, 55 void **mapped_addr, uint64_t *phys_addr, uint64_t *size) 56 { 57 struct rte_pci_device *dev = device->dev_handle; 58 59 *mapped_addr = dev->mem_resource[bar].addr; 60 *phys_addr = (uint64_t)dev->mem_resource[bar].phys_addr; 61 *size = (uint64_t)dev->mem_resource[bar].len; 62 63 return 0; 64 } 65 66 static int 67 spdk_unmap_bar_rte(struct spdk_pci_device *device, uint32_t bar, void *addr) 68 { 69 return 0; 70 } 71 72 static int 73 spdk_cfg_read_rte(struct spdk_pci_device *dev, void *value, uint32_t len, uint32_t offset) 74 { 75 int rc; 76 77 rc = rte_pci_read_config(dev->dev_handle, value, len, offset); 78 79 #if defined(__FreeBSD__) && RTE_VERSION < RTE_VERSION_NUM(18, 11, 0, 0) 80 /* Older DPDKs return 0 on success and -1 on failure */ 81 return rc; 82 #endif 83 return (rc > 0 && (uint32_t) rc == len) ? 0 : -1; 84 } 85 86 static int 87 spdk_cfg_write_rte(struct spdk_pci_device *dev, void *value, uint32_t len, uint32_t offset) 88 { 89 int rc; 90 91 rc = rte_pci_write_config(dev->dev_handle, value, len, offset); 92 93 #ifdef __FreeBSD__ 94 /* DPDK returns 0 on success and -1 on failure */ 95 return rc; 96 #endif 97 return (rc > 0 && (uint32_t) rc == len) ? 0 : -1; 98 } 99 100 static void 101 spdk_detach_rte_cb(void *_dev) 102 { 103 struct rte_pci_device *rte_dev = _dev; 104 105 #if RTE_VERSION >= RTE_VERSION_NUM(18, 11, 0, 0) 106 char bdf[32]; 107 int i = 0, rc; 108 109 snprintf(bdf, sizeof(bdf), "%s", rte_dev->device.name); 110 do { 111 rc = rte_eal_hotplug_remove("pci", bdf); 112 } while (rc == -ENOMSG && ++i <= DPDK_HOTPLUG_RETRY_COUNT); 113 #else 114 rte_eal_dev_detach(&rte_dev->device); 115 #endif 116 } 117 118 static void 119 spdk_detach_rte(struct spdk_pci_device *dev) 120 { 121 /* The device was already marked as available and could be attached 122 * again while we go asynchronous, so we explicitly forbid that. 123 */ 124 dev->internal.pending_removal = true; 125 if (spdk_process_is_primary()) { 126 rte_eal_alarm_set(10, spdk_detach_rte_cb, dev->dev_handle); 127 } else { 128 spdk_detach_rte_cb(dev->dev_handle); 129 } 130 } 131 132 void 133 spdk_pci_driver_register(struct spdk_pci_driver *driver) 134 { 135 TAILQ_INSERT_TAIL(&g_pci_drivers, driver, tailq); 136 } 137 138 #if RTE_VERSION >= RTE_VERSION_NUM(18, 5, 0, 0) 139 static void 140 spdk_pci_device_rte_hotremove(const char *device_name, 141 enum rte_dev_event_type event, 142 void *cb_arg) 143 { 144 struct spdk_pci_device *dev; 145 146 if (event != RTE_DEV_EVENT_REMOVE) { 147 return; 148 } 149 150 pthread_mutex_lock(&g_pci_mutex); 151 TAILQ_FOREACH(dev, &g_pci_devices, internal.tailq) { 152 struct rte_pci_device *rte_dev = dev->dev_handle; 153 154 if (strcmp(rte_dev->name, device_name) == 0) { 155 if (!dev->internal.pending_removal && 156 !dev->internal.attached) { 157 /* if device is not attached, we 158 * can remove it right away. 159 */ 160 spdk_detach_rte(dev); 161 } else { 162 /* otherwise we let the upper layers 163 * detach it first. 164 */ 165 dev->internal.pending_removal = true; 166 } 167 break; 168 } 169 } 170 pthread_mutex_unlock(&g_pci_mutex); 171 } 172 #endif 173 174 void 175 spdk_pci_init(void) 176 { 177 #if RTE_VERSION >= RTE_VERSION_NUM(18, 11, 0, 0) 178 struct spdk_pci_driver *driver; 179 180 /* We need to pre-register pci drivers for the pci devices to be 181 * attachable in multi-process with DPDK 18.11+. 182 * 183 * DPDK 18.11+ does its best to ensure all devices are equally 184 * attached or detached in all processes within a shared memory group. 185 * For SPDK it means that if a device is hotplugged in the primary, 186 * then DPDK will automatically send an IPC hotplug request to all other 187 * processes. Those other processes may not have the same SPDK PCI 188 * driver registered and may fail to attach the device. DPDK will send 189 * back the failure status, and the the primary process will also fail 190 * to hotplug the device. To prevent that, we need to pre-register the 191 * pci drivers here. 192 */ 193 TAILQ_FOREACH(driver, &g_pci_drivers, tailq) { 194 assert(!driver->is_registered); 195 driver->is_registered = true; 196 rte_pci_register(&driver->driver); 197 } 198 #endif 199 200 #if RTE_VERSION >= RTE_VERSION_NUM(18, 5, 0, 0) 201 /* Register a single hotremove callback for all devices. */ 202 if (spdk_process_is_primary()) { 203 rte_dev_event_callback_register(NULL, spdk_pci_device_rte_hotremove, NULL); 204 } 205 #endif 206 } 207 208 void 209 spdk_pci_fini(void) 210 { 211 struct spdk_pci_device *dev; 212 char bdf[32]; 213 214 TAILQ_FOREACH(dev, &g_pci_devices, internal.tailq) { 215 if (dev->internal.attached) { 216 spdk_pci_addr_fmt(bdf, sizeof(bdf), &dev->addr); 217 fprintf(stderr, "Device %s is still attached at shutdown!\n", bdf); 218 } 219 } 220 221 #if RTE_VERSION >= RTE_VERSION_NUM(18, 5, 0, 0) 222 if (spdk_process_is_primary()) { 223 rte_dev_event_callback_unregister(NULL, spdk_pci_device_rte_hotremove, NULL); 224 } 225 #endif 226 } 227 228 int 229 spdk_pci_device_init(struct rte_pci_driver *_drv, 230 struct rte_pci_device *_dev) 231 { 232 struct spdk_pci_driver *driver = (struct spdk_pci_driver *)_drv; 233 struct spdk_pci_device *dev; 234 int rc; 235 236 #if RTE_VERSION < RTE_VERSION_NUM(18, 11, 0, 0) 237 if (!driver->cb_fn) { 238 /* Return a positive value to indicate that this device does 239 * not belong to this driver, but this isn't an error. 240 */ 241 return 1; 242 } 243 #endif 244 245 dev = calloc(1, sizeof(*dev)); 246 if (dev == NULL) { 247 return -1; 248 } 249 250 dev->dev_handle = _dev; 251 252 dev->addr.domain = _dev->addr.domain; 253 dev->addr.bus = _dev->addr.bus; 254 dev->addr.dev = _dev->addr.devid; 255 dev->addr.func = _dev->addr.function; 256 dev->id.vendor_id = _dev->id.vendor_id; 257 dev->id.device_id = _dev->id.device_id; 258 dev->id.subvendor_id = _dev->id.subsystem_vendor_id; 259 dev->id.subdevice_id = _dev->id.subsystem_device_id; 260 dev->socket_id = _dev->device.numa_node; 261 262 dev->map_bar = spdk_map_bar_rte; 263 dev->unmap_bar = spdk_unmap_bar_rte; 264 dev->cfg_read = spdk_cfg_read_rte; 265 dev->cfg_write = spdk_cfg_write_rte; 266 dev->detach = spdk_detach_rte; 267 268 dev->internal.driver = driver; 269 270 if (driver->cb_fn != NULL) { 271 rc = driver->cb_fn(driver->cb_arg, dev); 272 if (rc != 0) { 273 free(dev); 274 return rc; 275 } 276 dev->internal.attached = true; 277 } 278 279 TAILQ_INSERT_TAIL(&g_pci_devices, dev, internal.tailq); 280 spdk_vtophys_pci_device_added(dev->dev_handle); 281 return 0; 282 } 283 284 int 285 spdk_pci_device_fini(struct rte_pci_device *_dev) 286 { 287 struct spdk_pci_device *dev; 288 289 TAILQ_FOREACH(dev, &g_pci_devices, internal.tailq) { 290 if (dev->dev_handle == _dev) { 291 break; 292 } 293 } 294 295 if (dev == NULL || dev->internal.attached) { 296 /* The device might be still referenced somewhere in SPDK. */ 297 return -1; 298 } 299 300 spdk_vtophys_pci_device_removed(dev->dev_handle); 301 TAILQ_REMOVE(&g_pci_devices, dev, internal.tailq); 302 free(dev); 303 return 0; 304 305 } 306 307 void 308 spdk_pci_device_detach(struct spdk_pci_device *dev) 309 { 310 assert(dev->internal.attached); 311 dev->internal.attached = false; 312 dev->detach(dev); 313 } 314 315 int 316 spdk_pci_device_attach(struct spdk_pci_driver *driver, 317 spdk_pci_enum_cb enum_cb, 318 void *enum_ctx, struct spdk_pci_addr *pci_address) 319 { 320 struct spdk_pci_device *dev; 321 int rc; 322 char bdf[32]; 323 324 spdk_pci_addr_fmt(bdf, sizeof(bdf), pci_address); 325 326 pthread_mutex_lock(&g_pci_mutex); 327 328 TAILQ_FOREACH(dev, &g_pci_devices, internal.tailq) { 329 if (spdk_pci_addr_compare(&dev->addr, pci_address) == 0) { 330 break; 331 } 332 } 333 334 if (dev != NULL && dev->internal.driver == driver) { 335 if (dev->internal.attached || dev->internal.pending_removal) { 336 pthread_mutex_unlock(&g_pci_mutex); 337 return -1; 338 } 339 340 rc = enum_cb(enum_ctx, dev); 341 if (rc == 0) { 342 dev->internal.attached = true; 343 } 344 pthread_mutex_unlock(&g_pci_mutex); 345 return rc; 346 } 347 348 if (!driver->is_registered) { 349 driver->is_registered = true; 350 rte_pci_register(&driver->driver); 351 } 352 353 driver->cb_fn = enum_cb; 354 driver->cb_arg = enum_ctx; 355 356 #if RTE_VERSION >= RTE_VERSION_NUM(18, 11, 0, 0) 357 int i = 0; 358 359 do { 360 rc = rte_eal_hotplug_add("pci", bdf, ""); 361 } while (rc == -ENOMSG && ++i <= DPDK_HOTPLUG_RETRY_COUNT); 362 363 if (i > 1 && rc == -EEXIST) { 364 /* Even though the previous request timed out, the device 365 * was attached successfully. 366 */ 367 rc = 0; 368 } 369 #else 370 rc = rte_eal_dev_attach(bdf, ""); 371 #endif 372 373 driver->cb_arg = NULL; 374 driver->cb_fn = NULL; 375 pthread_mutex_unlock(&g_pci_mutex); 376 377 return rc == 0 ? 0 : -1; 378 } 379 380 /* Note: You can call spdk_pci_enumerate from more than one thread 381 * simultaneously safely, but you cannot call spdk_pci_enumerate 382 * and rte_eal_pci_probe simultaneously. 383 */ 384 int 385 spdk_pci_enumerate(struct spdk_pci_driver *driver, 386 spdk_pci_enum_cb enum_cb, 387 void *enum_ctx) 388 { 389 struct spdk_pci_device *dev; 390 int rc; 391 392 pthread_mutex_lock(&g_pci_mutex); 393 394 TAILQ_FOREACH(dev, &g_pci_devices, internal.tailq) { 395 if (dev->internal.attached || 396 dev->internal.driver != driver || 397 dev->internal.pending_removal) { 398 continue; 399 } 400 401 rc = enum_cb(enum_ctx, dev); 402 if (rc == 0) { 403 dev->internal.attached = true; 404 } else if (rc < 0) { 405 pthread_mutex_unlock(&g_pci_mutex); 406 return -1; 407 } 408 } 409 410 if (!driver->is_registered) { 411 driver->is_registered = true; 412 rte_pci_register(&driver->driver); 413 } 414 415 driver->cb_fn = enum_cb; 416 driver->cb_arg = enum_ctx; 417 418 if (rte_bus_scan() != 0 || rte_bus_probe() != 0) { 419 driver->cb_arg = NULL; 420 driver->cb_fn = NULL; 421 pthread_mutex_unlock(&g_pci_mutex); 422 return -1; 423 } 424 425 driver->cb_arg = NULL; 426 driver->cb_fn = NULL; 427 pthread_mutex_unlock(&g_pci_mutex); 428 429 return 0; 430 } 431 432 int 433 spdk_pci_device_map_bar(struct spdk_pci_device *dev, uint32_t bar, 434 void **mapped_addr, uint64_t *phys_addr, uint64_t *size) 435 { 436 return dev->map_bar(dev, bar, mapped_addr, phys_addr, size); 437 } 438 439 int 440 spdk_pci_device_unmap_bar(struct spdk_pci_device *dev, uint32_t bar, void *addr) 441 { 442 return dev->unmap_bar(dev, bar, addr); 443 } 444 445 uint32_t 446 spdk_pci_device_get_domain(struct spdk_pci_device *dev) 447 { 448 return dev->addr.domain; 449 } 450 451 uint8_t 452 spdk_pci_device_get_bus(struct spdk_pci_device *dev) 453 { 454 return dev->addr.bus; 455 } 456 457 uint8_t 458 spdk_pci_device_get_dev(struct spdk_pci_device *dev) 459 { 460 return dev->addr.dev; 461 } 462 463 uint8_t 464 spdk_pci_device_get_func(struct spdk_pci_device *dev) 465 { 466 return dev->addr.func; 467 } 468 469 uint16_t 470 spdk_pci_device_get_vendor_id(struct spdk_pci_device *dev) 471 { 472 return dev->id.vendor_id; 473 } 474 475 uint16_t 476 spdk_pci_device_get_device_id(struct spdk_pci_device *dev) 477 { 478 return dev->id.device_id; 479 } 480 481 uint16_t 482 spdk_pci_device_get_subvendor_id(struct spdk_pci_device *dev) 483 { 484 return dev->id.subvendor_id; 485 } 486 487 uint16_t 488 spdk_pci_device_get_subdevice_id(struct spdk_pci_device *dev) 489 { 490 return dev->id.subdevice_id; 491 } 492 493 struct spdk_pci_id 494 spdk_pci_device_get_id(struct spdk_pci_device *dev) 495 { 496 return dev->id; 497 } 498 499 int 500 spdk_pci_device_get_socket_id(struct spdk_pci_device *dev) 501 { 502 return dev->socket_id; 503 } 504 505 int 506 spdk_pci_device_cfg_read(struct spdk_pci_device *dev, void *value, uint32_t len, uint32_t offset) 507 { 508 return dev->cfg_read(dev, value, len, offset); 509 } 510 511 int 512 spdk_pci_device_cfg_write(struct spdk_pci_device *dev, void *value, uint32_t len, uint32_t offset) 513 { 514 return dev->cfg_write(dev, value, len, offset); 515 } 516 517 int 518 spdk_pci_device_cfg_read8(struct spdk_pci_device *dev, uint8_t *value, uint32_t offset) 519 { 520 return spdk_pci_device_cfg_read(dev, value, 1, offset); 521 } 522 523 int 524 spdk_pci_device_cfg_write8(struct spdk_pci_device *dev, uint8_t value, uint32_t offset) 525 { 526 return spdk_pci_device_cfg_write(dev, &value, 1, offset); 527 } 528 529 int 530 spdk_pci_device_cfg_read16(struct spdk_pci_device *dev, uint16_t *value, uint32_t offset) 531 { 532 return spdk_pci_device_cfg_read(dev, value, 2, offset); 533 } 534 535 int 536 spdk_pci_device_cfg_write16(struct spdk_pci_device *dev, uint16_t value, uint32_t offset) 537 { 538 return spdk_pci_device_cfg_write(dev, &value, 2, offset); 539 } 540 541 int 542 spdk_pci_device_cfg_read32(struct spdk_pci_device *dev, uint32_t *value, uint32_t offset) 543 { 544 return spdk_pci_device_cfg_read(dev, value, 4, offset); 545 } 546 547 int 548 spdk_pci_device_cfg_write32(struct spdk_pci_device *dev, uint32_t value, uint32_t offset) 549 { 550 return spdk_pci_device_cfg_write(dev, &value, 4, offset); 551 } 552 553 int 554 spdk_pci_device_get_serial_number(struct spdk_pci_device *dev, char *sn, size_t len) 555 { 556 int err; 557 uint32_t pos, header = 0; 558 uint32_t i, buf[2]; 559 560 if (len < 17) { 561 return -1; 562 } 563 564 err = spdk_pci_device_cfg_read32(dev, &header, PCI_CFG_SIZE); 565 if (err || !header) { 566 return -1; 567 } 568 569 pos = PCI_CFG_SIZE; 570 while (1) { 571 if ((header & 0x0000ffff) == PCI_EXT_CAP_ID_SN) { 572 if (pos) { 573 /* skip the header */ 574 pos += 4; 575 for (i = 0; i < 2; i++) { 576 err = spdk_pci_device_cfg_read32(dev, &buf[i], pos + 4 * i); 577 if (err) { 578 return -1; 579 } 580 } 581 snprintf(sn, len, "%08x%08x", buf[1], buf[0]); 582 return 0; 583 } 584 } 585 pos = (header >> 20) & 0xffc; 586 /* 0 if no other items exist */ 587 if (pos < PCI_CFG_SIZE) { 588 return -1; 589 } 590 err = spdk_pci_device_cfg_read32(dev, &header, pos); 591 if (err) { 592 return -1; 593 } 594 } 595 return -1; 596 } 597 598 struct spdk_pci_addr 599 spdk_pci_device_get_addr(struct spdk_pci_device *dev) 600 { 601 return dev->addr; 602 } 603 604 bool 605 spdk_pci_device_is_removed(struct spdk_pci_device *dev) 606 { 607 return dev->internal.pending_removal; 608 } 609 610 int 611 spdk_pci_addr_compare(const struct spdk_pci_addr *a1, const struct spdk_pci_addr *a2) 612 { 613 if (a1->domain > a2->domain) { 614 return 1; 615 } else if (a1->domain < a2->domain) { 616 return -1; 617 } else if (a1->bus > a2->bus) { 618 return 1; 619 } else if (a1->bus < a2->bus) { 620 return -1; 621 } else if (a1->dev > a2->dev) { 622 return 1; 623 } else if (a1->dev < a2->dev) { 624 return -1; 625 } else if (a1->func > a2->func) { 626 return 1; 627 } else if (a1->func < a2->func) { 628 return -1; 629 } 630 631 return 0; 632 } 633 634 #ifdef __linux__ 635 int 636 spdk_pci_device_claim(const struct spdk_pci_addr *pci_addr) 637 { 638 int dev_fd; 639 char dev_name[64]; 640 int pid; 641 void *dev_map; 642 struct flock pcidev_lock = { 643 .l_type = F_WRLCK, 644 .l_whence = SEEK_SET, 645 .l_start = 0, 646 .l_len = 0, 647 }; 648 649 snprintf(dev_name, sizeof(dev_name), "/tmp/spdk_pci_lock_%04x:%02x:%02x.%x", pci_addr->domain, 650 pci_addr->bus, 651 pci_addr->dev, pci_addr->func); 652 653 dev_fd = open(dev_name, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR); 654 if (dev_fd == -1) { 655 fprintf(stderr, "could not open %s\n", dev_name); 656 return -1; 657 } 658 659 if (ftruncate(dev_fd, sizeof(int)) != 0) { 660 fprintf(stderr, "could not truncate %s\n", dev_name); 661 close(dev_fd); 662 return -1; 663 } 664 665 dev_map = mmap(NULL, sizeof(int), PROT_READ | PROT_WRITE, 666 MAP_SHARED, dev_fd, 0); 667 if (dev_map == MAP_FAILED) { 668 fprintf(stderr, "could not mmap dev %s (%d)\n", dev_name, errno); 669 close(dev_fd); 670 return -1; 671 } 672 673 if (fcntl(dev_fd, F_SETLK, &pcidev_lock) != 0) { 674 pid = *(int *)dev_map; 675 fprintf(stderr, "Cannot create lock on device %s, probably" 676 " process %d has claimed it\n", dev_name, pid); 677 munmap(dev_map, sizeof(int)); 678 close(dev_fd); 679 return -1; 680 } 681 682 *(int *)dev_map = (int)getpid(); 683 munmap(dev_map, sizeof(int)); 684 /* Keep dev_fd open to maintain the lock. */ 685 return dev_fd; 686 } 687 #endif /* __linux__ */ 688 689 #ifdef __FreeBSD__ 690 int 691 spdk_pci_device_claim(const struct spdk_pci_addr *pci_addr) 692 { 693 /* TODO */ 694 return 0; 695 } 696 #endif /* __FreeBSD__ */ 697 698 int 699 spdk_pci_addr_parse(struct spdk_pci_addr *addr, const char *bdf) 700 { 701 unsigned domain, bus, dev, func; 702 703 if (addr == NULL || bdf == NULL) { 704 return -EINVAL; 705 } 706 707 if ((sscanf(bdf, "%x:%x:%x.%x", &domain, &bus, &dev, &func) == 4) || 708 (sscanf(bdf, "%x.%x.%x.%x", &domain, &bus, &dev, &func) == 4)) { 709 /* Matched a full address - all variables are initialized */ 710 } else if (sscanf(bdf, "%x:%x:%x", &domain, &bus, &dev) == 3) { 711 func = 0; 712 } else if ((sscanf(bdf, "%x:%x.%x", &bus, &dev, &func) == 3) || 713 (sscanf(bdf, "%x.%x.%x", &bus, &dev, &func) == 3)) { 714 domain = 0; 715 } else if ((sscanf(bdf, "%x:%x", &bus, &dev) == 2) || 716 (sscanf(bdf, "%x.%x", &bus, &dev) == 2)) { 717 domain = 0; 718 func = 0; 719 } else { 720 return -EINVAL; 721 } 722 723 if (bus > 0xFF || dev > 0x1F || func > 7) { 724 return -EINVAL; 725 } 726 727 addr->domain = domain; 728 addr->bus = bus; 729 addr->dev = dev; 730 addr->func = func; 731 732 return 0; 733 } 734 735 int 736 spdk_pci_addr_fmt(char *bdf, size_t sz, const struct spdk_pci_addr *addr) 737 { 738 int rc; 739 740 rc = snprintf(bdf, sz, "%04x:%02x:%02x.%x", 741 addr->domain, addr->bus, 742 addr->dev, addr->func); 743 744 if (rc > 0 && (size_t)rc < sz) { 745 return 0; 746 } 747 748 return -1; 749 } 750 751 void 752 spdk_pci_hook_device(struct spdk_pci_driver *drv, struct spdk_pci_device *dev) 753 { 754 assert(dev->map_bar != NULL); 755 assert(dev->unmap_bar != NULL); 756 assert(dev->cfg_read != NULL); 757 assert(dev->cfg_write != NULL); 758 assert(dev->detach != NULL); 759 dev->internal.driver = drv; 760 TAILQ_INSERT_TAIL(&g_pci_devices, dev, internal.tailq); 761 } 762 763 void 764 spdk_pci_unhook_device(struct spdk_pci_device *dev) 765 { 766 assert(!dev->internal.attached); 767 TAILQ_REMOVE(&g_pci_devices, dev, internal.tailq); 768 } 769