xref: /spdk/lib/env_dpdk/pci.c (revision bb488d2829a9b7863daab45917dd2174905cc0ae)
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