To get the p2pdma_distance, this create a new privcmd ioctl to calculate p2pdma_distance for two pci devices on the host with pci notations sent from guest virtgpu driver. Signed-off-by: Julia Zhang <julia.zhang@xxxxxxx> --- drivers/xen/privcmd.c | 42 ++++++++++++++++++++++++++++++++++++++ include/uapi/xen/privcmd.h | 12 +++++++++++ 2 files changed, 54 insertions(+) diff --git a/drivers/xen/privcmd.c b/drivers/xen/privcmd.c index 72c161e94731..95f67815a2ef 100644 --- a/drivers/xen/privcmd.c +++ b/drivers/xen/privcmd.c @@ -31,6 +31,9 @@ #include <linux/miscdevice.h> #include <linux/moduleparam.h> #include <linux/virtio_mmio.h> +#include <linux/pci.h> +#include <linux/pci-p2pdma.h> +#include <linux/dma-map-ops.h> #include <asm/xen/hypervisor.h> #include <asm/xen/hypercall.h> @@ -977,6 +980,42 @@ static long privcmd_ioctl_map_hva_to_gpfns(struct file *file, void __user *udata return ret; } +static int privcmd_ioctl_p2pdma_distance(struct file *file, void __user *udata) +{ + struct privcmd_p2pdma_distance kdata; + struct pci_dev *provider = NULL; + struct pci_dev *client = NULL; + struct pci_dev *dev = NULL; + enum pci_p2pdma_map_type map; + + if (copy_from_user(&kdata, udata, sizeof(kdata))) + return -EFAULT; + + for_each_pci_dev(dev) { + if (dev->bus->number == kdata.provider_bus && + dev->devfn == PCI_DEVFN(kdata.provider_slot, kdata.provider_func)) { + provider = dev; + } else if (dev->bus->number == kdata.client_bus && + dev->devfn == PCI_DEVFN(kdata.client_slot, kdata.client_func)) { + client = dev; + } else { + continue; + } + } + + if (!provider || !client) { + pr_err("%s fail to get provider or client.\n", __func__); + return -EINVAL; + } + + kdata.distance = pci_p2pdma_distance(provider, &client->dev, false); + + if (copy_to_user(udata, &kdata, sizeof(kdata))) + return -EFAULT; + + return 0; +} + #ifdef CONFIG_XEN_PRIVCMD_EVENTFD /* Irqfd support */ static struct workqueue_struct *irqfd_cleanup_wq; @@ -1684,6 +1723,9 @@ static long privcmd_ioctl(struct file *file, ret = privcmd_ioctl_map_hva_to_gpfns(file, udata); break; + case IOCTL_PRIVCMD_P2PDMA_DISTANCE: + ret = privcmd_ioctl_p2pdma_distance(file, udata); + break; default: break; diff --git a/include/uapi/xen/privcmd.h b/include/uapi/xen/privcmd.h index d131002dd48f..a7ec3704519f 100644 --- a/include/uapi/xen/privcmd.h +++ b/include/uapi/xen/privcmd.h @@ -141,6 +141,16 @@ struct privcmd_map_hva_to_gpfns { int add_mapping; }; +struct privcmd_p2pdma_distance { + __u32 provider_bus; + __u32 provider_slot; + __u32 provider_func; + __u32 client_bus; + __u32 client_slot; + __u32 client_func; + __u32 distance; +}; + /* * @cmd: IOCTL_PRIVCMD_HYPERCALL * @arg: &privcmd_hypercall_t @@ -174,6 +184,8 @@ struct privcmd_map_hva_to_gpfns { _IOW('P', 9, struct privcmd_ioeventfd) #define IOCTL_PRIVCMD_PCIDEV_GET_GSI \ _IOC(_IOC_NONE, 'P', 10, sizeof(struct privcmd_pcidev_get_gsi)) +#define IOCTL_PRIVCMD_P2PDMA_DISTANCE \ + _IOC(_IOC_NONE, 'P', 11, sizeof(struct privcmd_p2pdma_distance)) #define IOCTL_PRIVCMD_MAP_HVA_TO_GPFNS \ _IOC(_IOC_NONE, 'P', 13, sizeof(struct privcmd_map_hva_to_gpfns)) -- 2.34.1