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 int 44 spdk_pci_device_init(struct rte_pci_driver *driver, 45 struct rte_pci_device *device) 46 { 47 struct spdk_pci_enum_ctx *ctx = (struct spdk_pci_enum_ctx *)driver; 48 int rc; 49 50 if (!ctx->cb_fn) { 51 #if RTE_VERSION >= RTE_VERSION_NUM(17, 05, 0, 4) 52 rte_pci_unmap_device(device); 53 #elif RTE_VERSION >= RTE_VERSION_NUM(16, 11, 0, 0) 54 rte_eal_pci_unmap_device(device); 55 #endif 56 57 /* Return a positive value to indicate that this device does not belong to this driver, but 58 * this isn't an error. */ 59 return 1; 60 } 61 62 rc = ctx->cb_fn(ctx->cb_arg, (struct spdk_pci_device *)device); 63 if (rc != 0) { 64 return rc; 65 } 66 67 spdk_vtophys_pci_device_added(device); 68 return 0; 69 } 70 71 int 72 spdk_pci_device_fini(struct rte_pci_device *device) 73 { 74 spdk_vtophys_pci_device_removed(device); 75 return 0; 76 } 77 78 void 79 spdk_pci_device_detach(struct spdk_pci_device *device) 80 { 81 #if RTE_VERSION >= RTE_VERSION_NUM(16, 11, 0, 0) 82 #if RTE_VERSION < RTE_VERSION_NUM(17, 05, 0, 0) 83 rte_eal_device_remove(&device->device); 84 #endif 85 #endif 86 87 #if RTE_VERSION >= RTE_VERSION_NUM(17, 11, 0, 3) 88 struct spdk_pci_addr addr; 89 char bdf[32]; 90 91 addr.domain = device->addr.domain; 92 addr.bus = device->addr.bus; 93 addr.dev = device->addr.devid; 94 addr.func = device->addr.function; 95 96 spdk_pci_addr_fmt(bdf, sizeof(bdf), &addr); 97 if (rte_eal_dev_detach(&device->device) < 0) { 98 fprintf(stderr, "Failed to detach PCI device %s (device already removed?).\n", bdf); 99 } 100 #elif RTE_VERSION >= RTE_VERSION_NUM(17, 05, 0, 4) 101 rte_pci_detach(&device->addr); 102 #else 103 rte_eal_pci_detach(&device->addr); 104 #endif 105 } 106 107 int 108 spdk_pci_device_attach(struct spdk_pci_enum_ctx *ctx, 109 spdk_pci_enum_cb enum_cb, 110 void *enum_ctx, struct spdk_pci_addr *pci_address) 111 { 112 #if RTE_VERSION >= RTE_VERSION_NUM(17, 11, 0, 3) 113 char bdf[32]; 114 115 spdk_pci_addr_fmt(bdf, sizeof(bdf), pci_address); 116 #else 117 struct rte_pci_addr addr; 118 119 addr.domain = pci_address->domain; 120 addr.bus = pci_address->bus; 121 addr.devid = pci_address->dev; 122 addr.function = pci_address->func; 123 #endif 124 125 pthread_mutex_lock(&ctx->mtx); 126 127 if (!ctx->is_registered) { 128 ctx->is_registered = true; 129 #if RTE_VERSION >= RTE_VERSION_NUM(17, 05, 0, 4) 130 rte_pci_register(&ctx->driver); 131 #else 132 rte_eal_pci_register(&ctx->driver); 133 #endif 134 } 135 136 ctx->cb_fn = enum_cb; 137 ctx->cb_arg = enum_ctx; 138 139 #if RTE_VERSION >= RTE_VERSION_NUM(17, 11, 0, 3) 140 if (rte_eal_dev_attach(bdf, "") != 0) { 141 #elif RTE_VERSION >= RTE_VERSION_NUM(17, 05, 0, 4) 142 if (rte_pci_probe_one(&addr) != 0) { 143 #else 144 if (rte_eal_pci_probe_one(&addr) != 0) { 145 #endif 146 ctx->cb_arg = NULL; 147 ctx->cb_fn = NULL; 148 pthread_mutex_unlock(&ctx->mtx); 149 return -1; 150 } 151 152 ctx->cb_arg = NULL; 153 ctx->cb_fn = NULL; 154 pthread_mutex_unlock(&ctx->mtx); 155 156 return 0; 157 } 158 159 /* Note: You can call spdk_pci_enumerate from more than one thread 160 * simultaneously safely, but you cannot call spdk_pci_enumerate 161 * and rte_eal_pci_probe simultaneously. 162 */ 163 int 164 spdk_pci_enumerate(struct spdk_pci_enum_ctx *ctx, 165 spdk_pci_enum_cb enum_cb, 166 void *enum_ctx) 167 { 168 pthread_mutex_lock(&ctx->mtx); 169 170 if (!ctx->is_registered) { 171 ctx->is_registered = true; 172 #if RTE_VERSION >= RTE_VERSION_NUM(17, 05, 0, 4) 173 rte_pci_register(&ctx->driver); 174 #else 175 rte_eal_pci_register(&ctx->driver); 176 #endif 177 } 178 179 ctx->cb_fn = enum_cb; 180 ctx->cb_arg = enum_ctx; 181 182 #if RTE_VERSION >= RTE_VERSION_NUM(17, 11, 0, 3) 183 if (rte_bus_probe() != 0) { 184 #elif RTE_VERSION >= RTE_VERSION_NUM(17, 05, 0, 4) 185 if (rte_pci_probe() != 0) { 186 #else 187 if (rte_eal_pci_probe() != 0) { 188 #endif 189 ctx->cb_arg = NULL; 190 ctx->cb_fn = NULL; 191 pthread_mutex_unlock(&ctx->mtx); 192 return -1; 193 } 194 195 ctx->cb_arg = NULL; 196 ctx->cb_fn = NULL; 197 pthread_mutex_unlock(&ctx->mtx); 198 199 return 0; 200 } 201 202 int 203 spdk_pci_device_map_bar(struct spdk_pci_device *device, uint32_t bar, 204 void **mapped_addr, uint64_t *phys_addr, uint64_t *size) 205 { 206 struct rte_pci_device *dev = device; 207 208 *mapped_addr = dev->mem_resource[bar].addr; 209 *phys_addr = (uint64_t)dev->mem_resource[bar].phys_addr; 210 *size = (uint64_t)dev->mem_resource[bar].len; 211 212 return 0; 213 } 214 215 int 216 spdk_pci_device_unmap_bar(struct spdk_pci_device *device, uint32_t bar, void *addr) 217 { 218 return 0; 219 } 220 221 uint32_t 222 spdk_pci_device_get_domain(struct spdk_pci_device *dev) 223 { 224 return dev->addr.domain; 225 } 226 227 uint8_t 228 spdk_pci_device_get_bus(struct spdk_pci_device *dev) 229 { 230 return dev->addr.bus; 231 } 232 233 uint8_t 234 spdk_pci_device_get_dev(struct spdk_pci_device *dev) 235 { 236 return dev->addr.devid; 237 } 238 239 uint8_t 240 spdk_pci_device_get_func(struct spdk_pci_device *dev) 241 { 242 return dev->addr.function; 243 } 244 245 uint16_t 246 spdk_pci_device_get_vendor_id(struct spdk_pci_device *dev) 247 { 248 return dev->id.vendor_id; 249 } 250 251 uint16_t 252 spdk_pci_device_get_device_id(struct spdk_pci_device *dev) 253 { 254 return dev->id.device_id; 255 } 256 257 uint16_t 258 spdk_pci_device_get_subvendor_id(struct spdk_pci_device *dev) 259 { 260 return dev->id.subsystem_vendor_id; 261 } 262 263 uint16_t 264 spdk_pci_device_get_subdevice_id(struct spdk_pci_device *dev) 265 { 266 return dev->id.subsystem_device_id; 267 } 268 269 struct spdk_pci_id 270 spdk_pci_device_get_id(struct spdk_pci_device *pci_dev) 271 { 272 struct spdk_pci_id pci_id; 273 274 pci_id.vendor_id = spdk_pci_device_get_vendor_id(pci_dev); 275 pci_id.device_id = spdk_pci_device_get_device_id(pci_dev); 276 pci_id.subvendor_id = spdk_pci_device_get_subvendor_id(pci_dev); 277 pci_id.subdevice_id = spdk_pci_device_get_subdevice_id(pci_dev); 278 279 return pci_id; 280 } 281 282 int 283 spdk_pci_device_get_socket_id(struct spdk_pci_device *pci_dev) 284 { 285 #if RTE_VERSION >= RTE_VERSION_NUM(16, 11, 0, 0) 286 return pci_dev->device.numa_node; 287 #else 288 return pci_dev->numa_node; 289 #endif 290 } 291 292 int 293 spdk_pci_device_cfg_read(struct spdk_pci_device *dev, void *value, uint32_t len, uint32_t offset) 294 { 295 int rc; 296 297 #if RTE_VERSION >= RTE_VERSION_NUM(17, 05, 0, 4) 298 rc = rte_pci_read_config(dev, value, len, offset); 299 #else 300 rc = rte_eal_pci_read_config(dev, value, len, offset); 301 #endif 302 return (rc > 0 && (uint32_t) rc == len) ? 0 : -1; 303 } 304 305 int 306 spdk_pci_device_cfg_write(struct spdk_pci_device *dev, void *value, uint32_t len, uint32_t offset) 307 { 308 int rc; 309 310 #if RTE_VERSION >= RTE_VERSION_NUM(17, 05, 0, 4) 311 rc = rte_pci_write_config(dev, value, len, offset); 312 #else 313 rc = rte_eal_pci_write_config(dev, value, len, offset); 314 #endif 315 return (rc > 0 && (uint32_t) rc == len) ? 0 : -1; 316 } 317 318 int 319 spdk_pci_device_cfg_read8(struct spdk_pci_device *dev, uint8_t *value, uint32_t offset) 320 { 321 return spdk_pci_device_cfg_read(dev, value, 1, offset); 322 } 323 324 int 325 spdk_pci_device_cfg_write8(struct spdk_pci_device *dev, uint8_t value, uint32_t offset) 326 { 327 return spdk_pci_device_cfg_write(dev, &value, 1, offset); 328 } 329 330 int 331 spdk_pci_device_cfg_read16(struct spdk_pci_device *dev, uint16_t *value, uint32_t offset) 332 { 333 return spdk_pci_device_cfg_read(dev, value, 2, offset); 334 } 335 336 int 337 spdk_pci_device_cfg_write16(struct spdk_pci_device *dev, uint16_t value, uint32_t offset) 338 { 339 return spdk_pci_device_cfg_write(dev, &value, 2, offset); 340 } 341 342 int 343 spdk_pci_device_cfg_read32(struct spdk_pci_device *dev, uint32_t *value, uint32_t offset) 344 { 345 return spdk_pci_device_cfg_read(dev, value, 4, offset); 346 } 347 348 int 349 spdk_pci_device_cfg_write32(struct spdk_pci_device *dev, uint32_t value, uint32_t offset) 350 { 351 return spdk_pci_device_cfg_write(dev, &value, 4, offset); 352 } 353 354 int 355 spdk_pci_device_get_serial_number(struct spdk_pci_device *dev, char *sn, size_t len) 356 { 357 int err; 358 uint32_t pos, header = 0; 359 uint32_t i, buf[2]; 360 361 if (len < 17) { 362 return -1; 363 } 364 365 err = spdk_pci_device_cfg_read32(dev, &header, PCI_CFG_SIZE); 366 if (err || !header) { 367 return -1; 368 } 369 370 pos = PCI_CFG_SIZE; 371 while (1) { 372 if ((header & 0x0000ffff) == PCI_EXT_CAP_ID_SN) { 373 if (pos) { 374 /* skip the header */ 375 pos += 4; 376 for (i = 0; i < 2; i++) { 377 err = spdk_pci_device_cfg_read32(dev, &buf[i], pos + 4 * i); 378 if (err) { 379 return -1; 380 } 381 } 382 snprintf(sn, len, "%08x%08x", buf[1], buf[0]); 383 return 0; 384 } 385 } 386 pos = (header >> 20) & 0xffc; 387 /* 0 if no other items exist */ 388 if (pos < PCI_CFG_SIZE) { 389 return -1; 390 } 391 err = spdk_pci_device_cfg_read32(dev, &header, pos); 392 if (err) { 393 return -1; 394 } 395 } 396 return -1; 397 } 398 399 struct spdk_pci_addr 400 spdk_pci_device_get_addr(struct spdk_pci_device *pci_dev) 401 { 402 struct spdk_pci_addr pci_addr; 403 404 pci_addr.domain = spdk_pci_device_get_domain(pci_dev); 405 pci_addr.bus = spdk_pci_device_get_bus(pci_dev); 406 pci_addr.dev = spdk_pci_device_get_dev(pci_dev); 407 pci_addr.func = spdk_pci_device_get_func(pci_dev); 408 409 return pci_addr; 410 } 411 412 int 413 spdk_pci_addr_compare(const struct spdk_pci_addr *a1, const struct spdk_pci_addr *a2) 414 { 415 if (a1->domain > a2->domain) { 416 return 1; 417 } else if (a1->domain < a2->domain) { 418 return -1; 419 } else if (a1->bus > a2->bus) { 420 return 1; 421 } else if (a1->bus < a2->bus) { 422 return -1; 423 } else if (a1->dev > a2->dev) { 424 return 1; 425 } else if (a1->dev < a2->dev) { 426 return -1; 427 } else if (a1->func > a2->func) { 428 return 1; 429 } else if (a1->func < a2->func) { 430 return -1; 431 } 432 433 return 0; 434 } 435 436 #ifdef __linux__ 437 int 438 spdk_pci_device_claim(const struct spdk_pci_addr *pci_addr) 439 { 440 int dev_fd; 441 char dev_name[64]; 442 int pid; 443 void *dev_map; 444 struct flock pcidev_lock = { 445 .l_type = F_WRLCK, 446 .l_whence = SEEK_SET, 447 .l_start = 0, 448 .l_len = 0, 449 }; 450 451 snprintf(dev_name, sizeof(dev_name), "/tmp/spdk_pci_lock_%04x:%02x:%02x.%x", pci_addr->domain, 452 pci_addr->bus, 453 pci_addr->dev, pci_addr->func); 454 455 dev_fd = open(dev_name, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR); 456 if (dev_fd == -1) { 457 fprintf(stderr, "could not open %s\n", dev_name); 458 return -1; 459 } 460 461 if (ftruncate(dev_fd, sizeof(int)) != 0) { 462 fprintf(stderr, "could not truncate %s\n", dev_name); 463 close(dev_fd); 464 return -1; 465 } 466 467 dev_map = mmap(NULL, sizeof(int), PROT_READ | PROT_WRITE, 468 MAP_SHARED, dev_fd, 0); 469 if (dev_map == MAP_FAILED) { 470 fprintf(stderr, "could not mmap dev %s (%d)\n", dev_name, errno); 471 close(dev_fd); 472 return -1; 473 } 474 475 if (fcntl(dev_fd, F_SETLK, &pcidev_lock) != 0) { 476 pid = *(int *)dev_map; 477 fprintf(stderr, "Cannot create lock on device %s, probably" 478 " process %d has claimed it\n", dev_name, pid); 479 munmap(dev_map, sizeof(int)); 480 close(dev_fd); 481 return -1; 482 } 483 484 *(int *)dev_map = (int)getpid(); 485 munmap(dev_map, sizeof(int)); 486 /* Keep dev_fd open to maintain the lock. */ 487 return dev_fd; 488 } 489 #endif /* __linux__ */ 490 491 #ifdef __FreeBSD__ 492 int 493 spdk_pci_device_claim(const struct spdk_pci_addr *pci_addr) 494 { 495 /* TODO */ 496 return 0; 497 } 498 #endif /* __FreeBSD__ */ 499 500 int 501 spdk_pci_addr_parse(struct spdk_pci_addr *addr, const char *bdf) 502 { 503 unsigned domain, bus, dev, func; 504 505 if (addr == NULL || bdf == NULL) { 506 return -EINVAL; 507 } 508 509 if ((sscanf(bdf, "%x:%x:%x.%x", &domain, &bus, &dev, &func) == 4) || 510 (sscanf(bdf, "%x.%x.%x.%x", &domain, &bus, &dev, &func) == 4)) { 511 /* Matched a full address - all variables are initialized */ 512 } else if (sscanf(bdf, "%x:%x:%x", &domain, &bus, &dev) == 3) { 513 func = 0; 514 } else if ((sscanf(bdf, "%x:%x.%x", &bus, &dev, &func) == 3) || 515 (sscanf(bdf, "%x.%x.%x", &bus, &dev, &func) == 3)) { 516 domain = 0; 517 } else if ((sscanf(bdf, "%x:%x", &bus, &dev) == 2) || 518 (sscanf(bdf, "%x.%x", &bus, &dev) == 2)) { 519 domain = 0; 520 func = 0; 521 } else { 522 return -EINVAL; 523 } 524 525 if (bus > 0xFF || dev > 0x1F || func > 7) { 526 return -EINVAL; 527 } 528 529 addr->domain = domain; 530 addr->bus = bus; 531 addr->dev = dev; 532 addr->func = func; 533 534 return 0; 535 } 536 537 int 538 spdk_pci_addr_fmt(char *bdf, size_t sz, const struct spdk_pci_addr *addr) 539 { 540 int rc; 541 542 rc = snprintf(bdf, sz, "%04x:%02x:%02x.%x", 543 addr->domain, addr->bus, 544 addr->dev, addr->func); 545 546 if (rc > 0 && (size_t)rc < sz) { 547 return 0; 548 } 549 550 return -1; 551 } 552