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