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