Add vfio_pci_find_p2p_pair() to locate an initiator device with memcpy driver support and a distinct target device with a memory BAR of at least min_bar_size bytes from an array of VFIO PCI devices. Factor out vfio_pci_has_p2p_path() as the central place to validate PCI topology and P2P DMA reachability between the two devices in the future. Signed-off-by: David Matlack --- .../lib/include/libvfio/vfio_pci_device.h | 8 ++++ .../selftests/vfio/lib/vfio_pci_device.c | 48 +++++++++++++++++++ 2 files changed, 56 insertions(+) diff --git a/tools/testing/selftests/vfio/lib/include/libvfio/vfio_pci_device.h b/tools/testing/selftests/vfio/lib/include/libvfio/vfio_pci_device.h index fd130f680a2d..9bda93712859 100644 --- a/tools/testing/selftests/vfio/lib/include/libvfio/vfio_pci_device.h +++ b/tools/testing/selftests/vfio/lib/include/libvfio/vfio_pci_device.h @@ -42,6 +42,12 @@ struct vfio_pci_device { struct vfio_pci_driver driver; }; +struct vfio_pci_p2p_pair { + struct vfio_pci_device *initiator; + struct vfio_pci_device *target; + struct vfio_pci_mem_bar mem_bar; +}; + #define dev_info(_dev, _fmt, ...) printf("%s: " _fmt, (_dev)->bdf, ##__VA_ARGS__) #define dev_err(_dev, _fmt, ...) fprintf(stderr, "%s: " _fmt, (_dev)->bdf, ##__VA_ARGS__) @@ -171,6 +177,8 @@ static inline bool vfio_pci_device_match(struct vfio_pci_device *device, bool vfio_pci_find_mem_bar(struct vfio_pci_device *device, u64 min_size, struct vfio_pci_mem_bar *mem_bar); +bool vfio_pci_find_p2p_pair(struct vfio_pci_device **devices, int nr_devices, + u64 min_bar_size, struct vfio_pci_p2p_pair *pair); int __vfio_pci_dmabuf_create(struct vfio_pci_device *device, u32 region_index, u64 offset, u64 length, u32 open_flags); diff --git a/tools/testing/selftests/vfio/lib/vfio_pci_device.c b/tools/testing/selftests/vfio/lib/vfio_pci_device.c index eca6eb13d7f0..16fc98ed170b 100644 --- a/tools/testing/selftests/vfio/lib/vfio_pci_device.c +++ b/tools/testing/selftests/vfio/lib/vfio_pci_device.c @@ -378,6 +378,54 @@ bool vfio_pci_find_mem_bar(struct vfio_pci_device *device, u64 min_size, return false; } +static bool vfio_pci_has_p2p_path(struct vfio_pci_device *initiator, + struct vfio_pci_device *target) +{ + /* + * TODO: Check PCI topology / ACS / host bridge support to verify that + * P2P DMA transactions from @initiator can reach @target. + */ + return initiator != target; +} + +bool vfio_pci_find_p2p_pair(struct vfio_pci_device **devices, int nr_devices, + u64 min_bar_size, struct vfio_pci_p2p_pair *pair) +{ + struct vfio_pci_mem_bar mem_bar; + int i, j; + + for (i = 0; i < nr_devices; i++) { + struct vfio_pci_device *initiator = devices[i]; + const struct vfio_pci_driver_ops *ops = initiator->driver.ops; + + if (!ops || !ops->memcpy_start || !ops->memcpy_wait) + continue; + + for (j = 0; j < nr_devices; j++) { + struct vfio_pci_device *target = devices[j]; + + if (i == j) + continue; + + if (!vfio_pci_has_p2p_path(initiator, target)) + continue; + + if (!vfio_pci_find_mem_bar(target, min_bar_size, + &mem_bar)) + continue; + + *pair = (struct vfio_pci_p2p_pair){ + .initiator = initiator, + .target = target, + .mem_bar = mem_bar, + }; + return true; + } + } + + return false; +} + void vfio_pci_config_access(struct vfio_pci_device *device, bool write, size_t config, size_t size, void *data) { -- 2.56.0.567.gdb80ae8cd5-goog