virt: acrn: Introduce interfaces for MMIO device passthrough
authorShuo Liu <shuo.a.liu@intel.com>
Thu, 23 Sep 2021 08:41:27 +0000 (16:41 +0800)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 5 Oct 2021 14:14:10 +0000 (16:14 +0200)
MMIO device passthrough enables an OS in a virtual machine to directly
access a MMIO device in the host. It promises almost the native
performance, which is required in performance-critical scenarios of
ACRN.

HSM provides the following ioctls:
  - Assign - ACRN_IOCTL_ASSIGN_MMIODEV
    Pass data struct acrn_mmiodev from userspace to the hypervisor, and
    inform the hypervisor to assign a MMIO device to a User VM.

  - De-assign - ACRN_IOCTL_DEASSIGN_PCIDEV
    Pass data struct acrn_mmiodev from userspace to the hypervisor, and
    inform the hypervisor to de-assign a MMIO device from a User VM.

These new APIs will be used by user space code vm_assign_mmiodev and
vm_deassign_mmiodev in
https://github.com/projectacrn/acrn-hypervisor/blob/master/devicemodel/core/vmmapi.c

Signed-off-by: Shuo Liu <shuo.a.liu@intel.com>
Signed-off-by: Fei Li <fei1.li@intel.com>
Link: https://lore.kernel.org/r/20210923084128.18902-2-fei1.li@intel.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/virt/acrn/hsm.c
drivers/virt/acrn/hypercall.h
include/uapi/linux/acrn.h

index 130e12b8652a691e5bb58a63acee382f21c0b3d5..f567ca59d7c20d5330f43b8b6aa5add377b02602 100644 (file)
@@ -114,6 +114,7 @@ static long acrn_dev_ioctl(struct file *filp, unsigned int cmd,
        struct acrn_ptdev_irq *irq_info;
        struct acrn_ioeventfd ioeventfd;
        struct acrn_vm_memmap memmap;
+       struct acrn_mmiodev *mmiodev;
        struct acrn_msi_entry *msi;
        struct acrn_pcidev *pcidev;
        struct acrn_irqfd irqfd;
@@ -217,6 +218,30 @@ static long acrn_dev_ioctl(struct file *filp, unsigned int cmd,
 
                ret = acrn_vm_memseg_unmap(vm, &memmap);
                break;
+       case ACRN_IOCTL_ASSIGN_MMIODEV:
+               mmiodev = memdup_user((void __user *)ioctl_param,
+                                     sizeof(struct acrn_mmiodev));
+               if (IS_ERR(mmiodev))
+                       return PTR_ERR(mmiodev);
+
+               ret = hcall_assign_mmiodev(vm->vmid, virt_to_phys(mmiodev));
+               if (ret < 0)
+                       dev_dbg(acrn_dev.this_device,
+                               "Failed to assign MMIO device!\n");
+               kfree(mmiodev);
+               break;
+       case ACRN_IOCTL_DEASSIGN_MMIODEV:
+               mmiodev = memdup_user((void __user *)ioctl_param,
+                                     sizeof(struct acrn_mmiodev));
+               if (IS_ERR(mmiodev))
+                       return PTR_ERR(mmiodev);
+
+               ret = hcall_deassign_mmiodev(vm->vmid, virt_to_phys(mmiodev));
+               if (ret < 0)
+                       dev_dbg(acrn_dev.this_device,
+                               "Failed to deassign MMIO device!\n");
+               kfree(mmiodev);
+               break;
        case ACRN_IOCTL_ASSIGN_PCIDEV:
                pcidev = memdup_user((void __user *)ioctl_param,
                                     sizeof(struct acrn_pcidev));
index 0cfad05bd1a93333c8b09da7c53cd219f39c4340..f0c78e52cebb71388d7de03f3d7ca79f58e26610 100644 (file)
@@ -41,6 +41,8 @@
 #define HC_RESET_PTDEV_INTR            _HC_ID(HC_ID, HC_ID_PCI_BASE + 0x04)
 #define HC_ASSIGN_PCIDEV               _HC_ID(HC_ID, HC_ID_PCI_BASE + 0x05)
 #define HC_DEASSIGN_PCIDEV             _HC_ID(HC_ID, HC_ID_PCI_BASE + 0x06)
+#define HC_ASSIGN_MMIODEV              _HC_ID(HC_ID, HC_ID_PCI_BASE + 0x07)
+#define HC_DEASSIGN_MMIODEV            _HC_ID(HC_ID, HC_ID_PCI_BASE + 0x08)
 
 #define HC_ID_PM_BASE                  0x80UL
 #define HC_PM_GET_CPU_STATE            _HC_ID(HC_ID, HC_ID_PM_BASE + 0x00)
@@ -194,6 +196,30 @@ static inline long hcall_set_memory_regions(u64 regions_pa)
        return acrn_hypercall1(HC_VM_SET_MEMORY_REGIONS, regions_pa);
 }
 
+/**
+ * hcall_assign_mmiodev() - Assign a MMIO device to a User VM
+ * @vmid:      User VM ID
+ * @addr:      Service VM GPA of the &struct acrn_mmiodev
+ *
+ * Return: 0 on success, <0 on failure
+ */
+static inline long hcall_assign_mmiodev(u64 vmid, u64 addr)
+{
+       return acrn_hypercall2(HC_ASSIGN_MMIODEV, vmid, addr);
+}
+
+/**
+ * hcall_deassign_mmiodev() - De-assign a PCI device from a User VM
+ * @vmid:      User VM ID
+ * @addr:      Service VM GPA of the &struct acrn_mmiodev
+ *
+ * Return: 0 on success, <0 on failure
+ */
+static inline long hcall_deassign_mmiodev(u64 vmid, u64 addr)
+{
+       return acrn_hypercall2(HC_DEASSIGN_MMIODEV, vmid, addr);
+}
+
 /**
  * hcall_assign_pcidev() - Assign a PCI device to a User VM
  * @vmid:      User VM ID
index 353b2a2e4536b866529aed46a3285ab7030ccfd4..470036d6b1acced3a58148ca634da95d3da10c51 100644 (file)
@@ -396,6 +396,7 @@ struct acrn_ptdev_irq {
 /* Type of PCI device assignment */
 #define ACRN_PTDEV_QUIRK_ASSIGN        (1U << 0)
 
+#define ACRN_MMIODEV_RES_NUM   3
 #define ACRN_PCI_NUM_BARS      6
 /**
  * struct acrn_pcidev - Info for assigning or de-assigning a PCI device
@@ -417,6 +418,29 @@ struct acrn_pcidev {
        __u32   bar[ACRN_PCI_NUM_BARS];
 };
 
+/**
+ * struct acrn_mmiodev - Info for assigning or de-assigning a MMIO device
+ * @name:                      Name of the MMIO device.
+ * @res[].user_vm_pa:          Physical address of User VM of the MMIO region
+ *                             for the MMIO device.
+ * @res[].service_vm_pa:       Physical address of Service VM of the MMIO
+ *                             region for the MMIO device.
+ * @res[].size:                        Size of the MMIO region for the MMIO device.
+ * @res[].mem_type:            Memory type of the MMIO region for the MMIO
+ *                             device.
+ *
+ * This structure will be passed to hypervisor directly.
+ */
+struct acrn_mmiodev {
+       __u8    name[8];
+       struct {
+               __u64   user_vm_pa;
+               __u64   service_vm_pa;
+               __u64   size;
+               __u64   mem_type;
+       } res[ACRN_MMIODEV_RES_NUM];
+};
+
 /**
  * struct acrn_msi_entry - Info for injecting a MSI interrupt to a VM
  * @msi_addr:  MSI addr[19:12] with dest vCPU ID
@@ -568,6 +592,10 @@ struct acrn_irqfd {
        _IOW(ACRN_IOCTL_TYPE, 0x55, struct acrn_pcidev)
 #define ACRN_IOCTL_DEASSIGN_PCIDEV     \
        _IOW(ACRN_IOCTL_TYPE, 0x56, struct acrn_pcidev)
+#define ACRN_IOCTL_ASSIGN_MMIODEV      \
+       _IOW(ACRN_IOCTL_TYPE, 0x57, struct acrn_mmiodev)
+#define ACRN_IOCTL_DEASSIGN_MMIODEV    \
+       _IOW(ACRN_IOCTL_TYPE, 0x58, struct acrn_mmiodev)
 
 #define ACRN_IOCTL_PM_GET_CPU_STATE    \
        _IOWR(ACRN_IOCTL_TYPE, 0x60, __u64)