Skip to contentSkip to conversation

amd iommu: support ats/gpgpu passthru on iommuv2 systems

PATCH Superseded Wei Wang 3 participants 11 messages Feb 10, 2012 – Feb 15, 2012

v5 of 6 Superseded Latest is v6 →

lore
Share & tools
lore

Wei Wang

author
#0 lore raw

PATCH v5 1/1 amd iommu: support ats/gpgpu passthru on iommuv2 systems

Hi,
This is patch set v5. It includes all pending patches that are needed to enable gpgpu passthrough and heterogeneous computing in guest OSes. Basically, this patch set gives guest VM the same capability of running openCL applications on amd platforms as native OSes. Upstream Linux 3.3 rc2 with amd iommuv2 kernel driver has been tested well as guest OS, and since last submission, lots of regression tests have been done to make sure this does not break non-iommuv2 systems. Please review it, feedbacks are appreciated.

Many thanks,
Wei

For more details, please refer to old thread.
http://lists.xen.org/archives/html/xen-devel/2012-01/msg01646.html

and, for an overview of the design, please refer to
http://www.amd64.org/pub/iommuv2.png

======================================================================
changes in v5:
* Remove patch 2 after upstream c/s 24729:6f6a6d1d2fb6

changes in v4:
* Only tool part in this version, since hypervisor patches have already been committed.
* rename guest config option from "iommu = {0,1}" to "guest_iommu = {0,1}"
* add description into docs/man/xl.cfg.pod.5

changes in v3:
* Use xenstore to receive guest iommu configuration instead of adding in a new field in hvm_info_table.
* Support pci segment in vbdf to mbdf bind.
* Make hypercalls visible for non-x86 platforms.
* A few code cleanups according to comments from Jan and Ian.

Changes in v2:
* Do not use linked list to access guest iommu tables.
* Do not parse iommu parameter in libxl_device_model_info again.
* Fix incorrect logical calculation in patch 11.
* Fix hypercall definition for non-x86 systems.

author
#1 lore raw

PATCH v5 1/1 amd iommu: Add 2 hypercalls for libxc

# HG changeset patch
# User Wei Wang <[email protected]>
# Date 1328885349 -3600
# Node ID 9cf24ad61936e5d9a6acac9de1dc1fac6694c31e # Parent 593deed8f62d73dc617f6dd0a95abd05755d002e amd iommu: Add 2 hypercalls for libxc

iommu_set_msi: used by qemu to inform hypervisor iommu vector number in guest space. Hypervisor needs this vector to inject msi into guest after write PPR log entry into guest buffer.

iommu_bind_bdf: used by xl to bind virtual bdf of passthru device to machine bdf. IOMMU emulator receives iommu cmd from guest OS and then forwards them to host iommu. But virtual device id in cmds from guest must be converted into physical id before sending them to real hardware.

xen/drivers/passthrough/amd/iommu_guest.c +68 -9
diff -r 593deed8f62d -r 9cf24ad61936 xen/drivers/passthrough/amd/iommu_guest.c
@@ -48,14 +48,31 @@
         (reg)->hi = (val) >> 32; \
     } while (0)
 
-static unsigned int machine_bdf(struct domain *d, uint16_t guest_bdf)
+static unsigned int machine_bdf(struct domain *d, uint16_t guest_seg,
+                                uint16_t guest_bdf)
 {
-    return guest_bdf;
+    struct pci_dev *pdev;
+    uint16_t mbdf = 0;
+
+    for_each_pdev( d, pdev )
+    {
+        if ( (pdev->gbdf == guest_bdf) && (pdev->gseg == guest_seg) )
+        {
+            mbdf = PCI_BDF2(pdev->bus, pdev->devfn);
+            break;
+        }
+    }
+    return mbdf;
 }
 
-static uint16_t guest_bdf(struct domain *d, uint16_t machine_bdf)
+static uint16_t guest_bdf(struct domain *d, uint16_t machine_seg,
+                          uint16_t machine_bdf)
 {
-    return machine_bdf;
+    struct pci_dev *pdev;
+
+    pdev = pci_get_pdev_by_domain(d, machine_seg, PCI_BUS(machine_bdf),
+                                  PCI_DEVFN2(machine_bdf));
+    return pdev->gbdf;
 }
 
 static inline struct guest_iommu *domain_iommu(struct domain *d)
@@ -207,7 +224,7 @@ void guest_iommu_add_ppr_log(struct doma
     log = log_base + tail % (PAGE_SIZE / sizeof(ppr_entry_t));
 
     /* Convert physical device id back into virtual device id */
-    gdev_id = guest_bdf(d, iommu_get_devid_from_cmd(entry[0]));
+    gdev_id = guest_bdf(d, 0, iommu_get_devid_from_cmd(entry[0]));
     iommu_set_devid_to_cmd(&entry[0], gdev_id);
 
     memcpy(log, entry, sizeof(ppr_entry_t));
@@ -256,7 +273,7 @@ void guest_iommu_add_event_log(struct do
     log = log_base + tail % (PAGE_SIZE / sizeof(event_entry_t));
 
     /* re-write physical device id into virtual device id */
-    dev_id = guest_bdf(d, iommu_get_devid_from_cmd(entry[0]));
+    dev_id = guest_bdf(d, 0, iommu_get_devid_from_cmd(entry[0]));
     iommu_set_devid_to_cmd(&entry[0], dev_id);
     memcpy(log, entry, sizeof(event_entry_t));
 
@@ -278,7 +295,7 @@ static int do_complete_ppr_request(struc
     uint16_t dev_id;
     struct amd_iommu *iommu;
 
-    dev_id = machine_bdf(d, iommu_get_devid_from_cmd(cmd->data[0]));
+    dev_id = machine_bdf(d, 0, iommu_get_devid_from_cmd(cmd->data[0]));
     iommu = find_iommu_for_device(0, dev_id);
 
     if ( !iommu )
@@ -330,7 +347,7 @@ static int do_invalidate_iotlb_pages(str
     struct amd_iommu *iommu;
     uint16_t dev_id;
 
-    dev_id = machine_bdf(d, iommu_get_devid_from_cmd(cmd->data[0]));
+    dev_id = machine_bdf(d, 0, iommu_get_devid_from_cmd(cmd->data[0]));
 
     iommu = find_iommu_for_device(0, dev_id);
     if ( !iommu )
@@ -409,7 +426,7 @@ static int do_invalidate_dte(struct doma
 
     g_iommu = domain_iommu(d);
     gbdf = iommu_get_devid_from_cmd(cmd->data[0]);
-    mbdf = machine_bdf(d, gbdf);
+    mbdf = machine_bdf(d, 0, gbdf);
 
     /* Guest can only update DTEs for its passthru devices */
     if ( mbdf == 0 || gbdf == 0 )
@@ -916,3 +933,45 @@ const struct hvm_mmio_handler iommu_mmio
     .read_handler = guest_iommu_mmio_read,
     .write_handler = guest_iommu_mmio_write
 };
+
+/* iommu hypercall handler */
+int iommu_bind_bdf(struct domain* d, uint16_t gseg, uint16_t gbdf,
+                   uint16_t mseg, uint16_t mbdf)
+{
+    struct pci_dev *pdev;
+    int ret = -ENODEV;
+
+    if ( !iommu_found() || !iommu_enabled || !iommuv2_enabled )
+        return ret;
+
+    spin_lock(&pcidevs_lock);
+
+    for_each_pdev( d, pdev )
+    {
+        if ( (pdev->seg != mseg) || (pdev->bus != PCI_BUS(mbdf) ) || 
+             (pdev->devfn != PCI_DEVFN2(mbdf)) )
+            continue;
+
+        pdev->gseg = gseg;
+        pdev->gbdf = gbdf;
+        ret = 0;
+    }
+
+    spin_unlock(&pcidevs_lock);
+    return ret;
+}
+
+void iommu_set_msi(struct domain* d, uint16_t vector, uint16_t dest,
+                   uint16_t dest_mode, uint16_t delivery_mode, 
+                   uint16_t trig_mode)
+{
+    struct guest_iommu *iommu = domain_iommu(d);
+
+    if ( !iommu )
+        return;
+
+    iommu->msi.vector = vector;
+    iommu->msi.dest = dest;
+    iommu->msi.dest_mode = dest_mode;
+    iommu->msi.trig_mode = trig_mode;
+}
xen/drivers/passthrough/iommu.c +34 -0
diff -r 593deed8f62d -r 9cf24ad61936 xen/drivers/passthrough/iommu.c
@@ -648,6 +648,40 @@ int iommu_do_domctl(
         put_domain(d);
         break;
 
+    case XEN_DOMCTL_guest_iommu_op:
+    {
+        xen_domctl_guest_iommu_op_t * guest_op;
+
+        if ( unlikely((d = get_domain_by_id(domctl->domain)) == NULL) )
+        {
+            gdprintk(XENLOG_ERR,
+                    "XEN_DOMCTL_guest_iommu_op: get_domain_by_id() failed\n");
+            ret = -EINVAL;
+            break;
+        }
+
+        guest_op = &(domctl->u.guest_iommu_op);
+        switch ( guest_op->op )
+        {
+            case XEN_DOMCTL_GUEST_IOMMU_OP_SET_MSI:
+                iommu_set_msi(d, guest_op->u.msi.vector, 
+                              guest_op->u.msi.dest,
+                              guest_op->u.msi.dest_mode, 
+                              guest_op->u.msi.delivery_mode,
+                              guest_op->u.msi.trig_mode);
+                ret = 0;
+                break;
+            case XEN_DOMCTL_GUEST_IOMMU_OP_BIND_BDF:
+                ret = iommu_bind_bdf(d, guest_op->u.bdf_bind.g_seg,
+                                     guest_op->u.bdf_bind.g_bdf,
+                                     guest_op->u.bdf_bind.m_seg,
+                                     guest_op->u.bdf_bind.m_bdf);
+                break;
+        }
+        put_domain(d);
+        break;
+    }
+
     default:
         ret = -ENOSYS;
         break;
xen/include/public/domctl.h +27 -0
diff -r 593deed8f62d -r 9cf24ad61936 xen/include/public/domctl.h
@@ -871,6 +871,31 @@ struct xen_domctl_set_access_required {
 typedef struct xen_domctl_set_access_required xen_domctl_set_access_required_t;
 DEFINE_XEN_GUEST_HANDLE(xen_domctl_set_access_required_t);
 
+/* Support for guest iommu emulation */
+struct xen_domctl_guest_iommu_op {
+    /* XEN_DOMCTL_GUEST_IOMMU_OP_* */
+#define XEN_DOMCTL_GUEST_IOMMU_OP_SET_MSI               0
+#define XEN_DOMCTL_GUEST_IOMMU_OP_BIND_BDF              1
+    uint8_t op;
+    union {
+        struct iommu_msi {
+        uint8_t  vector;
+        uint8_t  dest;
+        uint8_t  dest_mode;
+        uint8_t  delivery_mode;
+        uint8_t  trig_mode;
+        } msi;
+        struct bdf_bind {
+            uint16_t            g_seg;
+            uint16_t            g_bdf;
+            uint16_t            m_seg;
+            uint16_t            m_bdf;
+        } bdf_bind;
+    } u;
+};
+typedef struct xen_domctl_guest_iommu_op xen_domctl_guest_iommu_op_t;
+DEFINE_XEN_GUEST_HANDLE(xen_domctl_guest_iommu_op_t);
+
 struct xen_domctl {
     uint32_t cmd;
 #define XEN_DOMCTL_createdomain                   1
@@ -936,6 +961,7 @@ struct xen_domctl {
 #define XEN_DOMCTL_set_access_required           64
 #define XEN_DOMCTL_audit_p2m                     65
 #define XEN_DOMCTL_set_virq_handler              66
+#define XEN_DOMCTL_guest_iommu_op                67
 #define XEN_DOMCTL_gdbsx_guestmemio            1000
 #define XEN_DOMCTL_gdbsx_pausevcpu             1001
 #define XEN_DOMCTL_gdbsx_unpausevcpu           1002
@@ -984,6 +1010,7 @@ struct xen_domctl {
         struct xen_domctl_debug_op          debug_op;
         struct xen_domctl_mem_event_op      mem_event_op;
         struct xen_domctl_mem_sharing_op    mem_sharing_op;
+        struct xen_domctl_guest_iommu_op    guest_iommu_op;
 #if defined(__i386__) || defined(__x86_64__)
         struct xen_domctl_cpuid             cpuid;
         struct xen_domctl_vcpuextstate      vcpuextstate;
xen/include/xen/iommu.h +6 -0
diff -r 593deed8f62d -r 9cf24ad61936 xen/include/xen/iommu.h
@@ -164,6 +164,12 @@ int iommu_do_domctl(struct xen_domctl *,
 void iommu_iotlb_flush(struct domain *d, unsigned long gfn, unsigned int page_count);
 void iommu_iotlb_flush_all(struct domain *d);
 
+/* Only used by AMD IOMMU so far */
+void iommu_set_msi(struct domain* d, uint16_t vector, uint16_t dest,
+                   uint16_t dest_mode, uint16_t delivery_mode, 
+                   uint16_t trig_mode);
+int iommu_bind_bdf(struct domain* d, uint16_t gseg, uint16_t gbdf, 
+                   uint16_t mseg, uint16_t mbdf);
 /*
  * The purpose of the iommu_dont_flush_iotlb optional cpu flag is to
  * avoid unecessary iotlb_flush in the low level IOMMU code.
xen/include/xen/pci.h +5 -0
diff -r 593deed8f62d -r 9cf24ad61936 xen/include/xen/pci.h
@@ -62,6 +62,11 @@ struct pci_dev {
     const u16 seg;
     const u8 bus;
     const u8 devfn;
+
+    /* Used by iommu to represent virtual seg and bdf value in guest space */
+    u16 gseg;
+    u16 gbdf;
+
     struct pci_dev_info info;
     struct arch_pci_dev arch;
     u64 vf_rlen[6];
author
#4 lore raw

PATCH v5 1/1 amd iommu: Add a hypercall for hvmloader

In reply to Wei Wang

# HG changeset patch
# User Wei Wang <[email protected]>
# Date 1328885355 -3600
# Node ID 3c47f70c84e23b96e766c062a4bbae5bcf4f6dbe # Parent 9cf24ad61936e5d9a6acac9de1dc1fac6694c31e amd iommu: Add a hypercall for hvmloader.
IOMMU MMIO base address is dynamically allocated by firmware. This patch allows hvmloader to notify hypervisor where the iommu mmio pages are.

xen/arch/x86/hvm/hvm.c +4 -0
diff -r 9cf24ad61936 -r 3c47f70c84e2 xen/arch/x86/hvm/hvm.c
@@ -65,6 +65,7 @@
 #include <public/memory.h>
 #include <asm/mem_event.h>
 #include <public/mem_event.h>
+#include <asm/hvm/svm/amd-iommu-proto.h>
 
 bool_t __read_mostly hvm_enabled;
 
@@ -3775,6 +3776,9 @@ long do_hvm_op(unsigned long op, XEN_GUE
             case HVM_PARAM_BUFIOREQ_EVTCHN:
                 rc = -EINVAL;
                 break;
+            case HVM_PARAM_IOMMU_BASE:
+                rc = guest_iommu_set_base(d, a.value);
+                break;
             }
 
             if ( rc == 0 ) 
xen/include/public/hvm/params.h +2 -1
diff -r 9cf24ad61936 -r 3c47f70c84e2 xen/include/public/hvm/params.h
@@ -141,7 +141,8 @@
 
 /* Boolean: Enable nestedhvm (hvm only) */
 #define HVM_PARAM_NESTEDHVM    24
+#define HVM_PARAM_IOMMU_BASE   27
 
-#define HVM_NR_PARAMS          27
+#define HVM_NR_PARAMS          28
 
 #endif /* __XEN_PUBLIC_HVM_PARAMS_H__ */
author
#5 lore raw

PATCH v5 1/1 hvmloader: Build IVRS table

In reply to Wei Wang

# HG changeset patch
# User Wei Wang <[email protected]>
# Date 1328885357 -3600
# Node ID 16974b6159e13262126ad1e719727592184e5bea
# Parent 3c47f70c84e23b96e766c062a4bbae5bcf4f6dbe
hvmloader: Build IVRS table.
There are 32 ivrs padding entries allocated at the beginning. If a passthru device has been found from qemu bus, a padding entry will be replaced by the real device entry. Patch has been tested with both Rombios and Seabios

tools/firmware/hvmloader/acpi/acpi2_0.h +54 -0
diff -r 3c47f70c84e2 -r 16974b6159e1 tools/firmware/hvmloader/acpi/acpi2_0.h
@@ -389,6 +389,60 @@ struct acpi_20_madt_intsrcovr {
 #define ACPI_2_0_WAET_REVISION 0x01
 #define ACPI_1_0_FADT_REVISION 0x01
 
+#define IVRS_SIGNATURE ASCII32('I','V','R','S')
+#define IVRS_REVISION           1
+#define IVRS_VASIZE             64
+#define IVRS_PASIZE             52
+#define IVRS_GVASIZE            64
+
+#define IVHD_BLOCK_TYPE         0x10
+#define IVHD_FLAG_HTTUNEN       (1 << 0)
+#define IVHD_FLAG_PASSPW        (1 << 1)
+#define IVHD_FLAG_RESPASSPW     (1 << 2)
+#define IVHD_FLAG_ISOC          (1 << 3)
+#define IVHD_FLAG_IOTLBSUP      (1 << 4)
+#define IVHD_FLAG_COHERENT      (1 << 5)
+#define IVHD_FLAG_PREFSUP       (1 << 6)
+#define IVHD_FLAG_PPRSUP        (1 << 7)
+
+#define IVHD_EFR_GTSUP          (1 << 2)
+#define IVHD_EFR_IASUP          (1 << 5)
+
+#define IVHD_SELECT_4_BYTE      0x2
+
+struct ivrs_ivhd_block
+{
+    uint8_t    type;
+    uint8_t    flags;
+    uint16_t   length;
+    uint16_t   devid;
+    uint16_t   cap_offset;
+    uint64_t   iommu_base_addr;
+    uint16_t   pci_segment;
+    uint16_t   iommu_info;
+    uint32_t   reserved;
+};
+
+/* IVHD 4-byte device entries */
+struct ivrs_ivhd_device
+{
+   uint8_t  type;
+   uint16_t dev_id;
+   uint8_t  flags;
+};
+
+#define PT_DEV_MAX_NR           32
+#define IOMMU_CAP_OFFSET        0x40
+struct acpi_40_ivrs
+{
+    struct acpi_header                      header;
+    uint32_t                                iv_info;
+    uint32_t                                reserved[2];
+    struct ivrs_ivhd_block                  ivhd_block;
+    struct ivrs_ivhd_device                 ivhd_device[PT_DEV_MAX_NR];
+};
+
+
 #pragma pack ()
 
 struct acpi_config {
tools/firmware/hvmloader/acpi/build.c +91 -0

115 lines not on this page · raw message

tools/firmware/hvmloader/pci.c +29 -1
diff -r 3c47f70c84e2 -r 16974b6159e1 tools/firmware/hvmloader/pci.c
@@ -34,11 +34,17 @@ unsigned long pci_mem_end = PCI_MEM_END;
 enum virtual_vga virtual_vga = VGA_none;
 unsigned long igd_opregion_pgbase = 0;
 
+/* support up to 32 passthrough devices */
+#define PT_DEV_MAX_NR           32
+uint32_t ptdev_bdf[PT_DEV_MAX_NR];
+uint32_t ptdev_nr;
+uint32_t iommu_bdf = 0;
+
 void pci_setup(void)
 {
     uint32_t base, devfn, bar_reg, bar_data, bar_sz, cmd, mmio_total = 0;
     uint32_t vga_devfn = 256;
-    uint16_t class, vendor_id, device_id;
+    uint16_t class, vendor_id, device_id, sub_vendor_id;
     unsigned int bar, pin, link, isa_irq;
 
     /* Resources assignable to PCI devices via BARs. */
@@ -72,12 +78,34 @@ void pci_setup(void)
         class     = pci_readw(devfn, PCI_CLASS_DEVICE);
         vendor_id = pci_readw(devfn, PCI_VENDOR_ID);
         device_id = pci_readw(devfn, PCI_DEVICE_ID);
+        sub_vendor_id = pci_readw(devfn, PCI_SUBSYSTEM_VENDOR_ID);
+
         if ( (vendor_id == 0xffff) && (device_id == 0xffff) )
             continue;
 
         ASSERT((devfn != PCI_ISA_DEVFN) ||
                ((vendor_id == 0x8086) && (device_id == 0x7000)));
 
+        /* Found amd iommu device. */
+        if ( class == 0x0806 && vendor_id == 0x1022 )
+        {
+            iommu_bdf = devfn;
+            continue;
+        }
+        /* IVRS: Detecting passthrough devices.
+         * sub_vendor_id != citrix && sub_vendor_id != qemu */
+        if ( sub_vendor_id != 0x5853 && sub_vendor_id != 0x1af4 )
+        {
+            /* found amd iommu device */
+            if ( ptdev_nr < PT_DEV_MAX_NR )
+            {
+                ptdev_bdf[ptdev_nr] = devfn;
+                ptdev_nr++;
+            }
+            else
+                printf("Number of passthru devices > PT_DEV_MAX_NR \n");
+        }
+
         switch ( class )
         {
         case 0x0300:
author
#6 lore raw

PATCH v5 1/1 libxc: add wrappers for new hypercalls

In reply to Wei Wang

# HG changeset patch
# User Wei Wang <[email protected]>
# Date 1328885358 -3600
# Node ID db10bcca843c65260426800f9e05da8359faf439 # Parent 16974b6159e13262126ad1e719727592184e5bea
libxc: add wrappers for new hypercalls Please see patch 1 for hypercall description.

tools/libxc/xc_domain.c +53 -0
diff -r 16974b6159e1 -r db10bcca843c tools/libxc/xc_domain.c
@@ -1352,6 +1352,59 @@ int xc_domain_bind_pt_isa_irq(
                                   PT_IRQ_TYPE_ISA, 0, 0, 0, machine_irq));
 }
 
+int xc_domain_update_iommu_msi(
+    xc_interface *xch,
+    uint32_t domid,
+    uint8_t vector,
+    uint8_t dest,
+    uint8_t dest_mode,
+    uint8_t delivery_mode,
+    uint8_t trig_mode)
+{
+    int rc;
+    DECLARE_DOMCTL;
+    xen_domctl_guest_iommu_op_t * iommu_op;
+
+    domctl.cmd = XEN_DOMCTL_guest_iommu_op;
+    domctl.domain = (domid_t)domid;
+
+    iommu_op = &(domctl.u.guest_iommu_op);
+    iommu_op->op = XEN_DOMCTL_GUEST_IOMMU_OP_SET_MSI;
+    iommu_op->u.msi.vector = vector;
+    iommu_op->u.msi.dest = dest;
+    iommu_op->u.msi.dest_mode = dest_mode;
+    iommu_op->u.msi.delivery_mode = delivery_mode;
+    iommu_op->u.msi.trig_mode = trig_mode;
+
+    rc = do_domctl(xch, &domctl);
+    return rc;
+}
+
+int xc_domain_bind_pt_bdf(xc_interface *xch,
+    uint32_t domid,
+    uint16_t gseg,
+    uint16_t gbdf,
+    uint16_t mseg,
+    uint16_t mbdf)
+{
+    int rc;
+    DECLARE_DOMCTL;
+    xen_domctl_guest_iommu_op_t * guest_op;
+
+    domctl.cmd = XEN_DOMCTL_guest_iommu_op;
+    domctl.domain = (domid_t)domid;
+
+    guest_op = &(domctl.u.guest_iommu_op);
+    guest_op->op = XEN_DOMCTL_GUEST_IOMMU_OP_BIND_BDF;
+    guest_op->u.bdf_bind.g_seg = gseg;
+    guest_op->u.bdf_bind.g_bdf = gbdf;
+    guest_op->u.bdf_bind.m_seg = mseg;
+    guest_op->u.bdf_bind.m_bdf = mbdf;
+
+    rc = do_domctl(xch, &domctl);
+    return rc;
+}
+
 int xc_domain_memory_mapping(
     xc_interface *xch,
     uint32_t domid,
tools/libxc/xenctrl.h +15 -0
diff -r 16974b6159e1 -r db10bcca843c tools/libxc/xenctrl.h
@@ -1725,6 +1725,21 @@ int xc_domain_bind_pt_isa_irq(xc_interfa
                               uint32_t domid,
                               uint8_t machine_irq);
 
+int xc_domain_bind_pt_bdf(xc_interface *xch,
+                          uint32_t domid,
+                          uint16_t gseg,
+                          uint16_t gbdf,
+                          uint16_t mseg, 
+                          uint16_t mbdf);
+
+int xc_domain_update_iommu_msi(xc_interface *xch,
+                               uint32_t domid,
+                               uint8_t vector,
+                               uint8_t dest,
+                               uint8_t dest_mode,
+                               uint8_t delivery_mode,
+                               uint8_t trig_mode);
+
 int xc_domain_set_machine_address_size(xc_interface *xch,
 				       uint32_t domid,
 				       unsigned int width);
author
#7 lore raw

PATCH v5 1/1 libxl: bind virtual bdf to physical bdf after device assignment

In reply to Wei Wang

# HG changeset patch
# User Wei Wang <[email protected]>
# Date 1328885359 -3600
# Node ID c39f5736e36429091839a8db10179deeb6b0c622
# Parent db10bcca843c65260426800f9e05da8359faf439
libxl: bind virtual bdf to physical bdf after device assignment

tools/libxl/libxl_pci.c +7 -0
diff -r db10bcca843c -r c39f5736e364 tools/libxl/libxl_pci.c
@@ -721,6 +721,13 @@ out:
             LIBXL__LOG_ERRNOVAL(ctx, LIBXL__LOG_ERROR, rc, "xc_assign_device failed");
             return ERROR_FAIL;
         }
+        if (LIBXL__DOMAIN_IS_TYPE(gc,  domid, HVM)) {
+            rc = xc_domain_bind_pt_bdf(ctx->xch, domid, 0, pcidev->vdevfn, pcidev->domain, pcidev_encode_bdf(pcidev));
+            if ( rc ) {
+                LIBXL__LOG_ERRNOVAL(ctx, LIBXL__LOG_ERROR, rc, "xc_domain_bind_pt_bdf failed");
+                return ERROR_FAIL;
+            }
+        }
     }
 
     if (!starting)
author
#8 lore raw

PATCH v5 1/1 libxl: Introduce a new guest config file parameter

In reply to Wei Wang

# HG changeset patch
# User Wei Wang <[email protected]>
# Date 1328885360 -3600
# Node ID 09721a5ff84451b5a95d6cdc445867fa158dd449
# Parent c39f5736e36429091839a8db10179deeb6b0c622
libxl: Introduce a new guest config file parameter
Use guest_iommu = {1,0} to enable or disable guest iommu emulation. Default value is 0. Regression tests have been done to make sure it does not break non-iommuv2 systems.

docs/man/xl.cfg.pod.5 +4 -0
diff -r c39f5736e364 -r 09721a5ff844 docs/man/xl.cfg.pod.5
@@ -820,6 +820,10 @@ certainly belong in a more appropriate s
 
 Enable graphics device PCI passthrough. XXX which device is passed through ?
 
+=item B<guest_iommu=BOOLEAN>
+
+Enable virtual iommu device for hvm guest. It should be enabled to passthrough AMD GPGPU.
+
 =item B<nomigrate=BOOLEAN>
 
 Disable migration of this domain.  This enables certain other features
tools/libxl/libxl_create.c +4 -1
diff -r c39f5736e364 -r 09721a5ff844 tools/libxl/libxl_create.c
@@ -100,6 +100,7 @@ int libxl_init_build_info(libxl_ctx *ctx
         b_info->u.hvm.vpt_align = 1;
         b_info->u.hvm.timer_mode = 1;
         b_info->u.hvm.nested_hvm = 0;
+        b_info->u.hvm.guest_iommu = 0;
         b_info->u.hvm.no_incr_generationid = 0;
 
         b_info->u.hvm.stdvga = 0;
@@ -169,13 +170,15 @@ int libxl__domain_build(libxl__gc *gc,
         vments[4] = "start_time";
         vments[5] = libxl__sprintf(gc, "%lu.%02d", start_time.tv_sec,(int)start_time.tv_usec/10000);
 
-        localents = libxl__calloc(gc, 7, sizeof(char *));
+        localents = libxl__calloc(gc, 9, sizeof(char *));
         localents[0] = "platform/acpi";
         localents[1] = (info->u.hvm.acpi) ? "1" : "0";
         localents[2] = "platform/acpi_s3";
         localents[3] = (info->u.hvm.acpi_s3) ? "1" : "0";
         localents[4] = "platform/acpi_s4";
         localents[5] = (info->u.hvm.acpi_s4) ? "1" : "0";
+        localents[6] = "guest_iommu";
+        localents[7] = (info->u.hvm.guest_iommu) ? "1" : "0";
 
         break;
     case LIBXL_DOMAIN_TYPE_PV:
tools/libxl/libxl_types.idl +1 -0
diff -r c39f5736e364 -r 09721a5ff844 tools/libxl/libxl_types.idl
@@ -239,6 +239,7 @@ libxl_domain_build_info = Struct("domain
                                        ("vpt_align", bool),
                                        ("timer_mode", libxl_timer_mode),
                                        ("nested_hvm", bool),
+                                       ("guest_iommu", bool),
                                        ("no_incr_generationid", bool),
                                        ("nographic",        bool),
                                        ("stdvga",           bool),
tools/libxl/xl_cmdimpl.c +2 -0
diff -r c39f5736e364 -r 09721a5ff844 tools/libxl/xl_cmdimpl.c
@@ -748,6 +748,8 @@ static void parse_config_data(const char
 
         if (!xlu_cfg_get_long (config, "nestedhvm", &l, 0))
             b_info->u.hvm.nested_hvm = l;
+        if (!xlu_cfg_get_long (config, "guest_iommu", &l, 0))
+            b_info->u.hvm.guest_iommu = l;
         break;
     case LIBXL_DOMAIN_TYPE_PV:
     {
#2 lore raw

Re: [PATCH 1 of 6 V5] amd iommu: Add 2 hypercalls for libxc

In reply to Wei Wang
Quoted 26 lines
Quoted 1 line
Quoted 1 line · Wei Wang
xen/drivers/passthrough/amd/iommu_guest.c +21 -0
@@ -916,3 +933,45 @@ const struct hvm_mmio_handler iommu_mmio
     .read_handler = guest_iommu_mmio_read,
     .write_handler = guest_iommu_mmio_write
 };
+
+/* iommu hypercall handler */
+int iommu_bind_bdf(struct domain* d, uint16_t gseg, uint16_t gbdf,
+                   uint16_t mseg, uint16_t mbdf)
+{
+    struct pci_dev *pdev;
+    int ret = -ENODEV;
+
+    if ( !iommu_found() || !iommu_enabled || !iommuv2_enabled )
+        return ret;
+
+    spin_lock(&pcidevs_lock);
+
+    for_each_pdev( d, pdev )
+    {
+        if ( (pdev->seg != mseg) || (pdev->bus != PCI_BUS(mbdf) ) || 
+             (pdev->devfn != PCI_DEVFN2(mbdf)) )
+            continue;
+
+        pdev->gseg = gseg;
+        pdev->gbdf = gbdf;

xen/drivers/passthrough/amd/iommu_guest.c const struct hvm_mmio_handler iommu_mmio · line 966

Quoted 10 lines
xen/drivers/passthrough/amd/iommu_guest.c +10 -0
+        ret = 0;
+    }
+
+    spin_unlock(&pcidevs_lock);
+    return ret;
+}
+
+void iommu_set_msi(struct domain* d, uint16_t vector, uint16_t dest,
+                   uint16_t dest_mode, uint16_t delivery_mode, 
+                   uint16_t trig_mode)

Why are these all uint16_t?

Quoted 25 lines
xen/drivers/passthrough/amd/iommu_guest.c +11 -0
+{
+    struct guest_iommu *iommu = domain_iommu(d);
+
+    if ( !iommu )
+        return;
+
+    iommu->msi.vector = vector;
+    iommu->msi.dest = dest;
+    iommu->msi.dest_mode = dest_mode;
+    iommu->msi.trig_mode = trig_mode;
+}

diff -r 593deed8f62d -r 9cf24ad61936 xen/drivers/passthrough/iommu.c

xen/drivers/passthrough/iommu.c +7 -0
@@ -648,6 +648,40 @@ int iommu_do_domctl(
         put_domain(d);
         break;
 
+    case XEN_DOMCTL_guest_iommu_op:
+    {
+        xen_domctl_guest_iommu_op_t * guest_op;
+
+        if ( unlikely((d = get_domain_by_id(domctl->domain)) == NULL) )
+        {
+            gdprintk(XENLOG_ERR,

xen/drivers/passthrough/iommu.c int iommu_do_domctl( · line 667

Quoted 10 lines
xen/drivers/passthrough/iommu.c +9 -0
+                    "XEN_DOMCTL_guest_iommu_op: get_domain_by_id() 
 failed\n");
+            ret = -EINVAL;
+            break;
+        }
+
+        guest_op = &(domctl->u.guest_iommu_op);
+        switch ( guest_op->op )
+        {
+            case XEN_DOMCTL_GUEST_IOMMU_OP_SET_MSI:

Indentation.

Quoted 32 lines
xen/drivers/passthrough/iommu.c +18 -0
+                iommu_set_msi(d, guest_op->u.msi.vector, 
+                              guest_op->u.msi.dest,
+                              guest_op->u.msi.dest_mode, 
+                              guest_op->u.msi.delivery_mode,
+                              guest_op->u.msi.trig_mode);
+                ret = 0;
+                break;
+            case XEN_DOMCTL_GUEST_IOMMU_OP_BIND_BDF:
+                ret = iommu_bind_bdf(d, guest_op->u.bdf_bind.g_seg,
+                                     guest_op->u.bdf_bind.g_bdf,
+                                     guest_op->u.bdf_bind.m_seg,
+                                     guest_op->u.bdf_bind.m_bdf);
+                break;
+        }
+        put_domain(d);
+        break;
+    }
+
     default:
         ret = -ENOSYS;
         break;

diff -r 593deed8f62d -r 9cf24ad61936 xen/include/public/domctl.h

xen/include/public/domctl.h +3 -0
@@ -871,6 +871,31 @@ struct xen_domctl_set_access_required {
 typedef struct xen_domctl_set_access_required 
 xen_domctl_set_access_required_t;
 DEFINE_XEN_GUEST_HANDLE(xen_domctl_set_access_required_t);
 
+/* Support for guest iommu emulation */
+struct xen_domctl_guest_iommu_op {
+    /* XEN_DOMCTL_GUEST_IOMMU_OP_* */

xen/include/public/domctl.h struct xen_domctl_set_access_required { · line 887

Quoted 10 lines
xen/include/public/domctl.h +10 -0
+#define XEN_DOMCTL_GUEST_IOMMU_OP_SET_MSI               0
+#define XEN_DOMCTL_GUEST_IOMMU_OP_BIND_BDF              1
+    uint8_t op;
+    union {
+        struct iommu_msi {
+        uint8_t  vector;
+        uint8_t  dest;
+        uint8_t  dest_mode;
+        uint8_t  delivery_mode;
+        uint8_t  trig_mode;

Indentation again.

Jan

Quoted 15 lines
xen/include/public/domctl.h +12 -0
+        } msi;
+        struct bdf_bind {
+            uint16_t            g_seg;
+            uint16_t            g_bdf;
+            uint16_t            m_seg;
+            uint16_t            m_bdf;
+        } bdf_bind;
+    } u;
+};
+typedef struct xen_domctl_guest_iommu_op xen_domctl_guest_iommu_op_t;
+DEFINE_XEN_GUEST_HANDLE(xen_domctl_guest_iommu_op_t);
+
 struct xen_domctl {
     uint32_t cmd;

#define XEN_DOMCTL_createdomain 1

author
#3 lore raw

Re: [PATCH 1 of 6 V5] amd iommu: Add 2 hypercalls for libxc

Quoted 30 lines · Jan Beulich
Quoted 30 lines
Quoted 1 line
Quoted 1 line · Wei Wang
xen/drivers/passthrough/amd/iommu_guest.c +25 -0
@@ -916,3 +933,45 @@ const struct hvm_mmio_handler iommu_mmio
      .read_handler = guest_iommu_mmio_read,
      .write_handler = guest_iommu_mmio_write
  };
+
+/* iommu hypercall handler */
+int iommu_bind_bdf(struct domain* d, uint16_t gseg, uint16_t gbdf,
+                   uint16_t mseg, uint16_t mbdf)
+{
+    struct pci_dev *pdev;
+    int ret = -ENODEV;
+
+    if ( !iommu_found() || !iommu_enabled || !iommuv2_enabled )
+        return ret;
+
+    spin_lock(&pcidevs_lock);
+
+    for_each_pdev( d, pdev )
+    {
+        if ( (pdev->seg != mseg) || (pdev->bus != PCI_BUS(mbdf) ) ||
+             (pdev->devfn != PCI_DEVFN2(mbdf)) )
+            continue;
+
+        pdev->gseg = gseg;
+        pdev->gbdf = gbdf;
+        ret = 0;
+    }
+
+    spin_unlock(&pcidevs_lock);
Quoted 8 lines

xen/drivers/passthrough/amd/iommu_guest.c const struct hvm_mmio_handler iommu_mmio · line 966

Quoted 6 lines
xen/drivers/passthrough/amd/iommu_guest.c +6 -0
+    return ret;
+}
+
+void iommu_set_msi(struct domain* d, uint16_t vector, uint16_t dest,
+                   uint16_t dest_mode, uint16_t delivery_mode,
+                   uint16_t trig_mode)

Why are these all uint16_t?

uint8_t might better... I will change it.

Quoted 30 lines
Quoted 30 lines
xen/drivers/passthrough/amd/iommu_guest.c +11 -0
+{
+    struct guest_iommu *iommu = domain_iommu(d);
+
+    if ( !iommu )
+        return;
+
+    iommu->msi.vector = vector;
+    iommu->msi.dest = dest;
+    iommu->msi.dest_mode = dest_mode;
+    iommu->msi.trig_mode = trig_mode;
+}

diff -r 593deed8f62d -r 9cf24ad61936 xen/drivers/passthrough/iommu.c

xen/drivers/passthrough/iommu.c +10 -0
@@ -648,6 +648,40 @@ int iommu_do_domctl(
          put_domain(d);
          break;
 
+    case XEN_DOMCTL_guest_iommu_op:
+    {
+        xen_domctl_guest_iommu_op_t * guest_op;
+
+        if ( unlikely((d = get_domain_by_id(domctl->domain)) == NULL) )
+        {
+            gdprintk(XENLOG_ERR,
+                    "XEN_DOMCTL_guest_iommu_op: get_domain_by_id()
 failed\n");
+            ret = -EINVAL;
+            break;
Quoted 8 lines

xen/drivers/passthrough/iommu.c int iommu_do_domctl( · line 666

Quoted 6 lines
xen/drivers/passthrough/iommu.c +6 -0
+        }
+
+        guest_op =&(domctl->u.guest_iommu_op);
+        switch ( guest_op->op )
+        {
+            case XEN_DOMCTL_GUEST_IOMMU_OP_SET_MSI:

Indentation.

can be fixed.

Thanks,
Wei

Quoted 65 lines
Quoted 33 lines
xen/drivers/passthrough/iommu.c +18 -0
+                iommu_set_msi(d, guest_op->u.msi.vector,
+                              guest_op->u.msi.dest,
+                              guest_op->u.msi.dest_mode,
+                              guest_op->u.msi.delivery_mode,
+                              guest_op->u.msi.trig_mode);
+                ret = 0;
+                break;
+            case XEN_DOMCTL_GUEST_IOMMU_OP_BIND_BDF:
+                ret = iommu_bind_bdf(d, guest_op->u.bdf_bind.g_seg,
+                                     guest_op->u.bdf_bind.g_bdf,
+                                     guest_op->u.bdf_bind.m_seg,
+                                     guest_op->u.bdf_bind.m_bdf);
+                break;
+        }
+        put_domain(d);
+        break;
+    }
+
      default:
          ret = -ENOSYS;
          break;

diff -r 593deed8f62d -r 9cf24ad61936 xen/include/public/domctl.h

xen/include/public/domctl.h +3 -0
@@ -871,6 +871,31 @@ struct xen_domctl_set_access_required {
  typedef struct xen_domctl_set_access_required
 xen_domctl_set_access_required_t;
  DEFINE_XEN_GUEST_HANDLE(xen_domctl_set_access_required_t);
 
+/* Support for guest iommu emulation */
+struct xen_domctl_guest_iommu_op {
+    /* XEN_DOMCTL_GUEST_IOMMU_OP_* */

xen/include/public/domctl.h struct xen_domctl_set_access_required { · line 887

Quoted 10 lines
xen/include/public/domctl.h +10 -0
+#define XEN_DOMCTL_GUEST_IOMMU_OP_SET_MSI               0
+#define XEN_DOMCTL_GUEST_IOMMU_OP_BIND_BDF              1
+    uint8_t op;
+    union {
+        struct iommu_msi {
+        uint8_t  vector;
+        uint8_t  dest;
+        uint8_t  dest_mode;
+        uint8_t  delivery_mode;
+        uint8_t  trig_mode;

Indentation again.

Jan

Quoted 15 lines
xen/include/public/domctl.h +12 -0
+        } msi;
+        struct bdf_bind {
+            uint16_t            g_seg;
+            uint16_t            g_bdf;
+            uint16_t            m_seg;
+            uint16_t            m_bdf;
+        } bdf_bind;
+    } u;
+};
+typedef struct xen_domctl_guest_iommu_op xen_domctl_guest_iommu_op_t;
+DEFINE_XEN_GUEST_HANDLE(xen_domctl_guest_iommu_op_t);
+
  struct xen_domctl {
      uint32_t cmd;
  #define XEN_DOMCTL_createdomain                   1
Acked-by on v5 1/1
#9 lore raw
In reply to Wei Wang

Wei Wang writes ("[PATCH 0 of 6 V5] amd iommu: support ats/gpgpu passthru on iommuv2 systems"):

Quoted 1 line

This is patch set v5. It includes all pending patches that are needed to enable gpgpu passthrough and heterogeneous computing in guest OSes. Basically, this patch set gives guest VM the same capability of running openCL applications on amd platforms as native OSes. Upstream Linux 3.3 rc2 with amd iommuv2 kernel driver has been tested well as guest OS, and since last submission, lots of regression tests have been done to make sure this does not break non-iommuv2 systems. Please review it, feedbacks are appreciated.

Thanks. I'm not qualified to review the hypervisor parts, but the explanation seems to make sense and the tools parts look OK.

So as for these three:

[PATCH 4 of 6 V5] libxc: add wrappers for new hypercalls [PATCH 5 of 6 V5] libxl: bind virtual bdf to physical bdf ... [PATCH 6 of 6 V5] libxl: Introduce a new guest config file parameter

I do have a couple of minor niggles which you might like to address if you repost:

Quoted 4 lines

libxl: Introduce a new guest config file parameter
Use guest_iommu = {1,0} to enable or disable guest iommu emulation. Default value is 0. Regression tests have been done to make sure it does not break non-iommuv2 systems.

It's conventional to leave a blank line between the summary line and the bulk of the description.

Quoted 4 lines

diff -r c39f5736e364 -r 09721a5ff844 docs/man/xl.cfg.pod.5

docs/man/xl.cfg.pod.5 +0 -0
@@ -820,6 +820,10 @@ certainly belong in a more appropriate s

...

docs/man/xl.cfg.pod.5

Quoted 4 lines

+=item B<guest_iommu=BOOLEAN>

docs/man/xl.cfg.pod.5 +3 -0
+
+Enable virtual iommu device for hvm guest. It should be enabled to passthrough AMD GPGPU.
+

It would be nice for that line to be wrapped to fit within 75-80 columns.

Thanks,
Ian.

author
#10 lore raw
Quoted 6 lines · Ian Jackson

Wei Wang writes ("[PATCH 0 of 6 V5] amd iommu: support ats/gpgpu passthru on iommuv2 systems"):

Quoted 1 line

This is patch set v5. It includes all pending patches that are needed to enable gpgpu passthrough and heterogeneous computing in guest OSes. Basically, this patch set gives guest VM the same capability of running openCL applications on amd platforms as native OSes. Upstream Linux 3.3 rc2 with amd iommuv2 kernel driver has been tested well as guest OS, and since last submission, lots of regression tests have been done to make sure this does not break non-iommuv2 systems. Please review it, feedbacks are appreciated.

Thanks. I'm not qualified to review the hypervisor parts, but the explanation seems to make sense and the tools parts look OK.

Quoted 8 lines

So as for these three:

[PATCH 4 of 6 V5] libxc: add wrappers for new hypercalls [PATCH 5 of 6 V5] libxl: bind virtual bdf to physical bdf ... [PATCH 6 of 6 V5] libxl: Introduce a new guest config file parameter

Cool! thanks a lot for reviewing it and moving this forward. Issues you mentioned will be fixed in my next post.

Thanks,
Wei

Quoted 27 lines

I do have a couple of minor niggles which you might like to address if you repost:

Quoted 4 lines

libxl: Introduce a new guest config file parameter
Use guest_iommu = {1,0} to enable or disable guest iommu emulation. Default value is 0. Regression tests have been done to make sure it does not break non-iommuv2 systems.

It's conventional to leave a blank line between the summary line and the bulk of the description.

Quoted 4 lines

diff -r c39f5736e364 -r 09721a5ff844 docs/man/xl.cfg.pod.5

docs/man/xl.cfg.pod.5 +0 -0
@@ -820,6 +820,10 @@ certainly belong in a more appropriate s

...

docs/man/xl.cfg.pod.5

Quoted 4 lines

+=item B<guest_iommu=BOOLEAN>

docs/man/xl.cfg.pod.5 +3 -0
+
+Enable virtual iommu device for hvm guest. It should be enabled to passthrough AMD GPGPU.
+

It would be nice for that line to be wrapped to fit within 75-80 columns.

Thanks,
Ian.