Again, a couple of directly related functions at once get adjusted to account for the segment number. Do we need to bump XEN_DOMCTL_INTERFACE_VERSION for the changes to the domctl interface (namely the renaming and bit-reassigment of the machine_bdf member of two of the interface structures)? If so, this can probably be done as the patch gets checked in (rather than me having to re-submit)? Signed-off-by: Jan Beulich --- 2011-09-20.orig/tools/libxc/xc_domain.c 2011-06-16 09:21:02.000000000 +0200 +++ 2011-09-20/tools/libxc/xc_domain.c 2011-09-15 16:51:12.000000000 +0200 @@ -1132,13 +1132,13 @@ int xc_domain_setdebugging(xc_interface int xc_assign_device( xc_interface *xch, uint32_t domid, - uint32_t machine_bdf) + uint32_t machine_sbdf) { DECLARE_DOMCTL; domctl.cmd = XEN_DOMCTL_assign_device; domctl.domain = domid; - domctl.u.assign_device.machine_bdf = machine_bdf; + domctl.u.assign_device.machine_sbdf = machine_sbdf; return do_domctl(xch, &domctl); } @@ -1146,7 +1146,7 @@ int xc_assign_device( int xc_get_device_group( xc_interface *xch, uint32_t domid, - uint32_t machine_bdf, + uint32_t machine_sbdf, uint32_t max_sdevs, uint32_t *num_sdevs, uint32_t *sdev_array) @@ -1164,7 +1164,7 @@ int xc_get_device_group( domctl.cmd = XEN_DOMCTL_get_device_group; domctl.domain = (domid_t)domid; - domctl.u.get_device_group.machine_bdf = machine_bdf; + domctl.u.get_device_group.machine_sbdf = machine_sbdf; domctl.u.get_device_group.max_sdevs = max_sdevs; set_xen_guest_handle(domctl.u.get_device_group.sdev_array, sdev_array); @@ -1181,13 +1181,13 @@ int xc_get_device_group( int xc_test_assign_device( xc_interface *xch, uint32_t domid, - uint32_t machine_bdf) + uint32_t machine_sbdf) { DECLARE_DOMCTL; domctl.cmd = XEN_DOMCTL_test_assign_device; domctl.domain = domid; - domctl.u.assign_device.machine_bdf = machine_bdf; + domctl.u.assign_device.machine_sbdf = machine_sbdf; return do_domctl(xch, &domctl); } @@ -1195,13 +1195,13 @@ int xc_test_assign_device( int xc_deassign_device( xc_interface *xch, uint32_t domid, - uint32_t machine_bdf) + uint32_t machine_sbdf) { DECLARE_DOMCTL; domctl.cmd = XEN_DOMCTL_deassign_device; domctl.domain = domid; - domctl.u.assign_device.machine_bdf = machine_bdf; + domctl.u.assign_device.machine_sbdf = machine_sbdf; return do_domctl(xch, &domctl); } --- 2011-09-20.orig/tools/libxl/libxl_pci.c 2011-09-05 09:12:30.000000000 +0200 +++ 2011-09-20/tools/libxl/libxl_pci.c 2011-09-15 15:40:28.000000000 +0200 @@ -45,10 +45,10 @@ static unsigned int pcidev_encode_bdf(li { unsigned int value; - value = 0; - value |= (pcidev->bus & 0xff) << 16; - value |= (pcidev->dev & 0x1f) << (8+3); - value |= (pcidev->func & 0x7) << (8+0); + value = pcidev->domain << 16; + value |= (pcidev->bus & 0xff) << 8; + value |= (pcidev->dev & 0x1f) << 3; + value |= (pcidev->func & 0x7); return value; } --- 2011-09-20.orig/tools/python/xen/lowlevel/xc/xc.c 2010-11-05 09:22:58.000000000 +0100 +++ 2011-09-20/tools/python/xen/lowlevel/xc/xc.c 2011-09-15 15:48:10.000000000 +0200 @@ -609,7 +609,7 @@ static PyObject *pyxc_test_assign_device { uint32_t dom; char *pci_str; - int32_t bdf = 0; + int32_t sbdf = 0; int seg, bus, dev, func; static char *kwd_list[] = { "domid", "pci", NULL }; @@ -619,20 +619,21 @@ static PyObject *pyxc_test_assign_device while ( next_bdf(&pci_str, &seg, &bus, &dev, &func) ) { - bdf |= (bus & 0xff) << 16; - bdf |= (dev & 0x1f) << 11; - bdf |= (func & 0x7) << 8; + sbdf = seg << 16; + sbdf |= (bus & 0xff) << 8; + sbdf |= (dev & 0x1f) << 3; + sbdf |= (func & 0x7); - if ( xc_test_assign_device(self->xc_handle, dom, bdf) != 0 ) + if ( xc_test_assign_device(self->xc_handle, dom, sbdf) != 0 ) { if (errno == ENOSYS) - bdf = -1; + sbdf = -1; break; } - bdf = 0; + sbdf = 0; } - return Py_BuildValue("i", bdf); + return Py_BuildValue("i", sbdf); } static PyObject *pyxc_assign_device(XcObject *self, @@ -641,7 +642,7 @@ static PyObject *pyxc_assign_device(XcOb { uint32_t dom; char *pci_str; - int32_t bdf = 0; + int32_t sbdf = 0; int seg, bus, dev, func; static char *kwd_list[] = { "domid", "pci", NULL }; @@ -651,20 +652,21 @@ static PyObject *pyxc_assign_device(XcOb while ( next_bdf(&pci_str, &seg, &bus, &dev, &func) ) { - bdf |= (bus & 0xff) << 16; - bdf |= (dev & 0x1f) << 11; - bdf |= (func & 0x7) << 8; + sbdf = seg << 16; + sbdf |= (bus & 0xff) << 8; + sbdf |= (dev & 0x1f) << 3; + sbdf |= (func & 0x7); - if ( xc_assign_device(self->xc_handle, dom, bdf) != 0 ) + if ( xc_assign_device(self->xc_handle, dom, sbdf) != 0 ) { if (errno == ENOSYS) - bdf = -1; + sbdf = -1; break; } - bdf = 0; + sbdf = 0; } - return Py_BuildValue("i", bdf); + return Py_BuildValue("i", sbdf); } static PyObject *pyxc_deassign_device(XcObject *self, @@ -673,7 +675,7 @@ static PyObject *pyxc_deassign_device(Xc { uint32_t dom; char *pci_str; - int32_t bdf = 0; + int32_t sbdf = 0; int seg, bus, dev, func; static char *kwd_list[] = { "domid", "pci", NULL }; @@ -683,26 +685,27 @@ static PyObject *pyxc_deassign_device(Xc while ( next_bdf(&pci_str, &seg, &bus, &dev, &func) ) { - bdf |= (bus & 0xff) << 16; - bdf |= (dev & 0x1f) << 11; - bdf |= (func & 0x7) << 8; + sbdf = seg << 16; + sbdf |= (bus & 0xff) << 8; + sbdf |= (dev & 0x1f) << 3; + sbdf |= (func & 0x7); - if ( xc_deassign_device(self->xc_handle, dom, bdf) != 0 ) + if ( xc_deassign_device(self->xc_handle, dom, sbdf) != 0 ) { if (errno == ENOSYS) - bdf = -1; + sbdf = -1; break; } - bdf = 0; + sbdf = 0; } - return Py_BuildValue("i", bdf); + return Py_BuildValue("i", sbdf); } static PyObject *pyxc_get_device_group(XcObject *self, PyObject *args) { - uint32_t bdf = 0; + uint32_t sbdf; uint32_t max_sdevs, num_sdevs; int domid, seg, bus, dev, func, rc, i; PyObject *Pystr; @@ -720,12 +723,13 @@ static PyObject *pyxc_get_device_group(X if (sdev_array == NULL) return PyErr_NoMemory(); - bdf |= (bus & 0xff) << 16; - bdf |= (dev & 0x1f) << 11; - bdf |= (func & 0x7) << 8; + sbdf = seg << 16; + sbdf |= (bus & 0xff) << 8; + sbdf |= (dev & 0x1f) << 3; + sbdf |= (func & 0x7); rc = xc_get_device_group(self->xc_handle, - domid, bdf, max_sdevs, &num_sdevs, sdev_array); + domid, sbdf, max_sdevs, &num_sdevs, sdev_array); if ( rc < 0 ) { --- 2011-09-20.orig/xen/arch/ia64/xen/dom0_ops.c 2011-09-19 10:58:18.000000000 +0200 +++ 2011-09-20/xen/arch/ia64/xen/dom0_ops.c 2011-09-15 16:32:59.000000000 +0200 @@ -258,138 +258,6 @@ long arch_do_domctl(xen_domctl_t *op, XE } break; - case XEN_DOMCTL_get_device_group: - { - struct domain *d; - u32 max_sdevs; - u8 bus, devfn; - XEN_GUEST_HANDLE_64(uint32) sdevs; - int num_sdevs; - - ret = -ENOSYS; - if ( !iommu_enabled ) - break; - - ret = -EINVAL; - if ( (d = rcu_lock_domain_by_id(op->domain)) == NULL ) - break; - - bus = (op->u.get_device_group.machine_bdf >> 16) & 0xff; - devfn = (op->u.get_device_group.machine_bdf >> 8) & 0xff; - max_sdevs = op->u.get_device_group.max_sdevs; - sdevs = op->u.get_device_group.sdev_array; - - num_sdevs = iommu_get_device_group(d, bus, devfn, sdevs, max_sdevs); - if ( num_sdevs < 0 ) - { - dprintk(XENLOG_ERR, "iommu_get_device_group() failed!\n"); - ret = -EFAULT; - op->u.get_device_group.num_sdevs = 0; - } - else - { - ret = 0; - op->u.get_device_group.num_sdevs = num_sdevs; - } - if ( copy_to_guest(u_domctl, op, 1) ) - ret = -EFAULT; - rcu_unlock_domain(d); - } - break; - - case XEN_DOMCTL_test_assign_device: - { - u8 bus, devfn; - - ret = -ENOSYS; - if ( !iommu_enabled ) - break; - - ret = -EINVAL; - bus = (op->u.assign_device.machine_bdf >> 16) & 0xff; - devfn = (op->u.assign_device.machine_bdf >> 8) & 0xff; - - if ( device_assigned(bus, devfn) ) - { - printk( "XEN_DOMCTL_test_assign_device: " - "%x:%x.%x already assigned, or non-existent\n", - bus, PCI_SLOT(devfn), PCI_FUNC(devfn)); - break; - } - ret = 0; - } - break; - - case XEN_DOMCTL_assign_device: - { - struct domain *d; - u8 bus, devfn; - - ret = -ENOSYS; - if ( !iommu_enabled ) - break; - - ret = -EINVAL; - if ( unlikely((d = get_domain_by_id(op->domain)) == NULL) ) - { - gdprintk(XENLOG_ERR, - "XEN_DOMCTL_assign_device: get_domain_by_id() failed\n"); - break; - } - bus = (op->u.assign_device.machine_bdf >> 16) & 0xff; - devfn = (op->u.assign_device.machine_bdf >> 8) & 0xff; - - if ( device_assigned(bus, devfn) ) - { - gdprintk(XENLOG_ERR, "XEN_DOMCTL_assign_device: " - "%x:%x.%x already assigned, or non-existent\n", - bus, PCI_SLOT(devfn), PCI_FUNC(devfn)); - break; - } - - ret = assign_device(d, bus, devfn); - if ( ret ) - gdprintk(XENLOG_ERR, "XEN_DOMCTL_assign_device: " - "assign device (%x:%x.%x) failed\n", - bus, PCI_SLOT(devfn), PCI_FUNC(devfn)); - put_domain(d); - } - break; - - case XEN_DOMCTL_deassign_device: - { - struct domain *d; - u8 bus, devfn; - - ret = -ENOSYS; - if ( !iommu_enabled ) - break; - - ret = -EINVAL; - if ( unlikely((d = get_domain_by_id(op->domain)) == NULL) ) - { - gdprintk(XENLOG_ERR, - "XEN_DOMCTL_deassign_device: get_domain_by_id() failed\n"); - break; - } - bus = (op->u.assign_device.machine_bdf >> 16) & 0xff; - devfn = (op->u.assign_device.machine_bdf >> 8) & 0xff; - - if ( !device_assigned(bus, devfn) ) - break; - - spin_lock(&pcidevs_lock); - ret = deassign_device(d, bus, devfn); - spin_unlock(&pcidevs_lock); - if ( ret ) - gdprintk(XENLOG_ERR, "XEN_DOMCTL_deassign_device: " - "deassign device (%x:%x.%x) failed\n", - bus, PCI_SLOT(devfn), PCI_FUNC(devfn)); - - put_domain(d); - } - break; - case XEN_DOMCTL_bind_pt_irq: { struct domain * d; @@ -707,8 +575,8 @@ long arch_do_domctl(xen_domctl_t *op, XE break; default: - printk("arch_do_domctl: unrecognized domctl: %d!!!\n",op->cmd); - ret = -ENOSYS; + ret = iommu_do_domctl(op, u_domctl); + break; } --- 2011-09-20.orig/xen/arch/x86/domctl.c 2011-06-16 09:21:02.000000000 +0200 +++ 2011-09-20/xen/arch/x86/domctl.c 2011-09-15 16:09:39.000000000 +0200 @@ -742,144 +742,6 @@ long arch_do_domctl( } break; - case XEN_DOMCTL_get_device_group: - { - struct domain *d; - u32 max_sdevs; - u8 bus, devfn; - XEN_GUEST_HANDLE_64(uint32) sdevs; - int num_sdevs; - - ret = -ENOSYS; - if ( !iommu_enabled ) - break; - - ret = -EINVAL; - if ( (d = rcu_lock_domain_by_id(domctl->domain)) == NULL ) - break; - - bus = (domctl->u.get_device_group.machine_bdf >> 16) & 0xff; - devfn = (domctl->u.get_device_group.machine_bdf >> 8) & 0xff; - max_sdevs = domctl->u.get_device_group.max_sdevs; - sdevs = domctl->u.get_device_group.sdev_array; - - num_sdevs = iommu_get_device_group(d, bus, devfn, sdevs, max_sdevs); - if ( num_sdevs < 0 ) - { - dprintk(XENLOG_ERR, "iommu_get_device_group() failed!\n"); - ret = -EFAULT; - domctl->u.get_device_group.num_sdevs = 0; - } - else - { - ret = 0; - domctl->u.get_device_group.num_sdevs = num_sdevs; - } - if ( copy_to_guest(u_domctl, domctl, 1) ) - ret = -EFAULT; - rcu_unlock_domain(d); - } - break; - - case XEN_DOMCTL_test_assign_device: - { - u8 bus, devfn; - - ret = -ENOSYS; - if ( !iommu_enabled ) - break; - - ret = xsm_test_assign_device(domctl->u.assign_device.machine_bdf); - if ( ret ) - break; - - ret = -EINVAL; - bus = (domctl->u.assign_device.machine_bdf >> 16) & 0xff; - devfn = (domctl->u.assign_device.machine_bdf >> 8) & 0xff; - - if ( device_assigned(bus, devfn) ) - { - gdprintk(XENLOG_ERR, "XEN_DOMCTL_test_assign_device: " - "%x:%x.%x already assigned, or non-existent\n", - bus, PCI_SLOT(devfn), PCI_FUNC(devfn)); - break; - } - ret = 0; - } - break; - - case XEN_DOMCTL_assign_device: - { - struct domain *d; - u8 bus, devfn; - - ret = -ENOSYS; - if ( !iommu_enabled ) - break; - - ret = -EINVAL; - if ( unlikely((d = get_domain_by_id(domctl->domain)) == NULL) ) - { - gdprintk(XENLOG_ERR, - "XEN_DOMCTL_assign_device: get_domain_by_id() failed\n"); - break; - } - - ret = xsm_assign_device(d, domctl->u.assign_device.machine_bdf); - if ( ret ) - goto assign_device_out; - - bus = (domctl->u.assign_device.machine_bdf >> 16) & 0xff; - devfn = (domctl->u.assign_device.machine_bdf >> 8) & 0xff; - - ret = assign_device(d, bus, devfn); - if ( ret ) - gdprintk(XENLOG_ERR, "XEN_DOMCTL_assign_device: " - "assign device (%x:%x.%x) failed\n", - bus, PCI_SLOT(devfn), PCI_FUNC(devfn)); - - assign_device_out: - put_domain(d); - } - break; - - case XEN_DOMCTL_deassign_device: - { - struct domain *d; - u8 bus, devfn; - - ret = -ENOSYS; - if ( !iommu_enabled ) - break; - - ret = -EINVAL; - if ( unlikely((d = get_domain_by_id(domctl->domain)) == NULL) ) - { - gdprintk(XENLOG_ERR, - "XEN_DOMCTL_deassign_device: get_domain_by_id() failed\n"); - break; - } - - ret = xsm_assign_device(d, domctl->u.assign_device.machine_bdf); - if ( ret ) - goto deassign_device_out; - - bus = (domctl->u.assign_device.machine_bdf >> 16) & 0xff; - devfn = (domctl->u.assign_device.machine_bdf >> 8) & 0xff; - - spin_lock(&pcidevs_lock); - ret = deassign_device(d, bus, devfn); - spin_unlock(&pcidevs_lock); - if ( ret ) - gdprintk(XENLOG_ERR, "XEN_DOMCTL_deassign_device: " - "deassign device (%x:%x.%x) failed\n", - bus, PCI_SLOT(devfn), PCI_FUNC(devfn)); - - deassign_device_out: - put_domain(d); - } - break; - case XEN_DOMCTL_bind_pt_irq: { struct domain * d; @@ -1601,7 +1463,7 @@ long arch_do_domctl( break; default: - ret = -ENOSYS; + ret = iommu_do_domctl(domctl, u_domctl); break; } --- 2011-09-20.orig/xen/drivers/passthrough/amd/pci_amd_iommu.c 2011-09-20 16:03:27.000000000 +0200 +++ 2011-09-20/xen/drivers/passthrough/amd/pci_amd_iommu.c 2011-09-20 16:04:06.000000000 +0200 @@ -305,7 +305,7 @@ static void amd_iommu_disable_domain_dev } static int reassign_device( struct domain *source, struct domain *target, - u8 bus, u8 devfn) + u16 seg, u8 bus, u8 devfn) { struct pci_dev *pdev; struct amd_iommu *iommu; @@ -313,7 +313,7 @@ static int reassign_device( struct domai struct hvm_iommu *t = domain_hvm_iommu(target); ASSERT(spin_is_locked(&pcidevs_lock)); - pdev = pci_get_pdev_by_domain(source, 0, bus, devfn); + pdev = pci_get_pdev_by_domain(source, seg, bus, devfn); if ( !pdev ) return -ENODEV; @@ -346,7 +346,7 @@ static int reassign_device( struct domai return 0; } -static int amd_iommu_assign_device(struct domain *d, u8 bus, u8 devfn) +static int amd_iommu_assign_device(struct domain *d, u16 seg, u8 bus, u8 devfn) { int bdf = (bus << 8) | devfn; int req_id = get_dma_requestor_id(bdf); @@ -361,7 +361,7 @@ static int amd_iommu_assign_device(struc ivrs_mappings[req_id].read_permission); } - return reassign_device(dom0, d, bus, devfn); + return reassign_device(dom0, d, seg, bus, devfn); } static void deallocate_next_page_table(struct page_info* pg, int level) @@ -426,9 +426,9 @@ static void amd_iommu_domain_destroy(str } static int amd_iommu_return_device( - struct domain *s, struct domain *t, u8 bus, u8 devfn) + struct domain *s, struct domain *t, u16 seg, u8 bus, u8 devfn) { - return reassign_device(s, t, bus, devfn); + return reassign_device(s, t, seg, bus, devfn); } static int amd_iommu_add_device(struct pci_dev *pdev) @@ -475,7 +475,7 @@ static int amd_iommu_remove_device(struc return 0; } -static int amd_iommu_group_id(u8 bus, u8 devfn) +static int amd_iommu_group_id(u16 seg, u8 bus, u8 devfn) { int rt; int bdf = (bus << 8) | devfn; --- 2011-09-20.orig/xen/drivers/passthrough/iommu.c 2011-08-25 15:06:35.000000000 +0200 +++ 2011-09-20/xen/drivers/passthrough/iommu.c 2011-09-15 17:00:38.000000000 +0200 @@ -19,6 +19,7 @@ #include #include #include +#include static void parse_iommu_param(char *s); static int iommu_populate_page_table(struct domain *d); @@ -165,7 +166,22 @@ int iommu_remove_device(struct pci_dev * return hd->platform_ops->remove_device(pdev); } -int assign_device(struct domain *d, u8 bus, u8 devfn) +/* + * If the device isn't owned by dom0, it means it already + * has been assigned to other domain, or it doesn't exist. + */ +static int device_assigned(u16 seg, u8 bus, u8 devfn) +{ + struct pci_dev *pdev; + + spin_lock(&pcidevs_lock); + pdev = pci_get_pdev_by_domain(dom0, seg, bus, devfn); + spin_unlock(&pcidevs_lock); + + return pdev ? 0 : -1; +} + +static int assign_device(struct domain *d, u16 seg, u8 bus, u8 devfn) { struct hvm_iommu *hd = domain_hvm_iommu(d); int rc = 0; @@ -174,7 +190,7 @@ int assign_device(struct domain *d, u8 b return 0; spin_lock(&pcidevs_lock); - if ( (rc = hd->platform_ops->assign_device(d, bus, devfn)) ) + if ( (rc = hd->platform_ops->assign_device(d, seg, bus, devfn)) ) goto done; if ( has_arch_pdevs(d) && !need_iommu(d) ) @@ -272,7 +288,7 @@ int iommu_unmap_page(struct domain *d, u } /* caller should hold the pcidevs_lock */ -int deassign_device(struct domain *d, u8 bus, u8 devfn) +int deassign_device(struct domain *d, u16 seg, u8 bus, u8 devfn) { struct hvm_iommu *hd = domain_hvm_iommu(d); struct pci_dev *pdev = NULL; @@ -282,7 +298,7 @@ int deassign_device(struct domain *d, u8 return -EINVAL; ASSERT(spin_is_locked(&pcidevs_lock)); - pdev = pci_get_pdev(0, bus, devfn); + pdev = pci_get_pdev(seg, bus, devfn); if ( !pdev ) return -ENODEV; @@ -293,12 +309,12 @@ int deassign_device(struct domain *d, u8 return -EINVAL; } - ret = hd->platform_ops->reassign_device(d, dom0, bus, devfn); + ret = hd->platform_ops->reassign_device(d, dom0, seg, bus, devfn); if ( ret ) { dprintk(XENLOG_ERR VTDPREFIX, - "d%d: Deassign device (%x:%x.%x) failed!\n", - d->domain_id, bus, PCI_SLOT(devfn), PCI_FUNC(devfn)); + "d%d: Deassign device (%04x:%02x:%02x.%u) failed!\n", + d->domain_id, seg, bus, PCI_SLOT(devfn), PCI_FUNC(devfn)); return ret; } @@ -347,7 +363,8 @@ int __init iommu_setup(void) return rc; } -int iommu_get_device_group(struct domain *d, u8 bus, u8 devfn, +static int iommu_get_device_group( + struct domain *d, u16 seg, u8 bus, u8 devfn, XEN_GUEST_HANDLE_64(uint32) buf, int max_sdevs) { struct hvm_iommu *hd = domain_hvm_iommu(d); @@ -360,15 +377,16 @@ int iommu_get_device_group(struct domain if ( !iommu_enabled || !ops || !ops->get_device_group_id ) return 0; - group_id = ops->get_device_group_id(bus, devfn); + group_id = ops->get_device_group_id(seg, bus, devfn); spin_lock(&pcidevs_lock); for_each_pdev( d, pdev ) { - if ( (pdev->bus == bus) && (pdev->devfn == devfn) ) + if ( (pdev->seg != seg) || + ((pdev->bus == bus) && (pdev->devfn == devfn)) ) continue; - sdev_id = ops->get_device_group_id(pdev->bus, pdev->devfn); + sdev_id = ops->get_device_group_id(seg, pdev->bus, pdev->devfn); if ( (sdev_id == group_id) && (i < max_sdevs) ) { bdf = 0; @@ -443,6 +461,154 @@ void iommu_crash_shutdown(void) iommu_enabled = 0; } +int iommu_do_domctl( + struct xen_domctl *domctl, + XEN_GUEST_HANDLE(xen_domctl_t) u_domctl) +{ + struct domain *d; + u16 seg; + u8 bus, devfn; + int ret = 0; + + if ( !iommu_enabled ) + return -ENOSYS; + + switch ( domctl->cmd ) + { + case XEN_DOMCTL_get_device_group: + { + u32 max_sdevs; + XEN_GUEST_HANDLE_64(uint32) sdevs; + + ret = -EINVAL; + if ( (d = rcu_lock_domain_by_id(domctl->domain)) == NULL ) + break; + + seg = domctl->u.get_device_group.machine_sbdf >> 16; + bus = (domctl->u.get_device_group.machine_sbdf >> 8) & 0xff; + devfn = domctl->u.get_device_group.machine_sbdf & 0xff; + max_sdevs = domctl->u.get_device_group.max_sdevs; + sdevs = domctl->u.get_device_group.sdev_array; + + ret = iommu_get_device_group(d, seg, bus, devfn, sdevs, max_sdevs); + if ( ret < 0 ) + { + dprintk(XENLOG_ERR, "iommu_get_device_group() failed!\n"); + ret = -EFAULT; + domctl->u.get_device_group.num_sdevs = 0; + } + else + { + domctl->u.get_device_group.num_sdevs = ret; + ret = 0; + } + if ( copy_to_guest(u_domctl, domctl, 1) ) + ret = -EFAULT; + rcu_unlock_domain(d); + } + break; + + case XEN_DOMCTL_test_assign_device: + ret = xsm_test_assign_device(domctl->u.assign_device.machine_sbdf); + if ( ret ) + break; + + seg = domctl->u.get_device_group.machine_sbdf >> 16; + bus = (domctl->u.assign_device.machine_sbdf >> 8) & 0xff; + devfn = domctl->u.assign_device.machine_sbdf & 0xff; + + if ( device_assigned(seg, bus, devfn) ) + { + gdprintk(XENLOG_ERR, "XEN_DOMCTL_test_assign_device: " + "%04x:%02x:%02x.%u already assigned, or non-existent\n", + seg, bus, PCI_SLOT(devfn), PCI_FUNC(devfn)); + ret = -EINVAL; + } + break; + + case XEN_DOMCTL_assign_device: + if ( unlikely((d = get_domain_by_id(domctl->domain)) == NULL) ) + { + gdprintk(XENLOG_ERR, + "XEN_DOMCTL_assign_device: get_domain_by_id() failed\n"); + ret = -EINVAL; + break; + } + + ret = xsm_assign_device(d, domctl->u.assign_device.machine_sbdf); + if ( ret ) + goto assign_device_out; + + seg = domctl->u.get_device_group.machine_sbdf >> 16; + bus = (domctl->u.assign_device.machine_sbdf >> 8) & 0xff; + devfn = domctl->u.assign_device.machine_sbdf & 0xff; + +#ifdef __ia64__ /* XXX Is this really needed? */ + if ( device_assigned(seg, bus, devfn) ) + { + gdprintk(XENLOG_ERR, "XEN_DOMCTL_assign_device: " + "%x:%x.%x already assigned, or non-existent\n", + bus, PCI_SLOT(devfn), PCI_FUNC(devfn)); + ret = -EINVAL; + goto assign_device_out; + } +#endif + + ret = assign_device(d, seg, bus, devfn); + if ( ret ) + gdprintk(XENLOG_ERR, "XEN_DOMCTL_assign_device: " + "assign device (%04x:%02x:%02x.%u) failed\n", + seg, bus, PCI_SLOT(devfn), PCI_FUNC(devfn)); + + assign_device_out: + put_domain(d); + break; + + case XEN_DOMCTL_deassign_device: + if ( unlikely((d = get_domain_by_id(domctl->domain)) == NULL) ) + { + gdprintk(XENLOG_ERR, + "XEN_DOMCTL_deassign_device: get_domain_by_id() failed\n"); + ret = -EINVAL; + break; + } + + ret = xsm_assign_device(d, domctl->u.assign_device.machine_sbdf); + if ( ret ) + goto deassign_device_out; + + seg = domctl->u.get_device_group.machine_sbdf >> 16; + bus = (domctl->u.assign_device.machine_sbdf >> 8) & 0xff; + devfn = domctl->u.assign_device.machine_sbdf & 0xff; + +#ifdef __ia64__ /* XXX Is this really needed? */ + if ( !device_assigned(seg, bus, devfn) ) + { + ret = -EINVAL; + goto deassign_device_out; + } +#endif + + spin_lock(&pcidevs_lock); + ret = deassign_device(d, seg, bus, devfn); + spin_unlock(&pcidevs_lock); + if ( ret ) + gdprintk(XENLOG_ERR, "XEN_DOMCTL_deassign_device: " + "deassign device (%04x:%02x:%02x.%u) failed\n", + seg, bus, PCI_SLOT(devfn), PCI_FUNC(devfn)); + + deassign_device_out: + put_domain(d); + break; + + default: + ret = -ENOSYS; + break; + } + + return ret; +} + /* * Local variables: * mode: C --- 2011-09-20.orig/xen/drivers/passthrough/pci.c 2011-08-25 15:06:35.000000000 +0200 +++ 2011-09-20/xen/drivers/passthrough/pci.c 2011-08-25 15:06:40.000000000 +0200 @@ -441,11 +441,12 @@ void pci_release_devices(struct domain * while ( (pdev = pci_get_pdev_by_domain(d, -1, -1, -1)) ) { pci_cleanup_msi(pdev); - bus = pdev->bus; devfn = pdev->devfn; - if ( deassign_device(d, bus, devfn) ) - printk("domain %d: deassign device (%02x:%02x.%x) failed!\n", - d->domain_id, pdev->bus, PCI_SLOT(pdev->devfn), - PCI_FUNC(pdev->devfn)); + bus = pdev->bus; + devfn = pdev->devfn; + if ( deassign_device(d, pdev->seg, bus, devfn) ) + printk("domain %d: deassign device (%04x:%02x:%02x.%u) failed!\n", + d->domain_id, pdev->seg, bus, + PCI_SLOT(devfn), PCI_FUNC(devfn)); } spin_unlock(&pcidevs_lock); } --- 2011-09-20.orig/xen/drivers/passthrough/vtd/iommu.c 2011-09-20 16:03:17.000000000 +0200 +++ 2011-09-20/xen/drivers/passthrough/vtd/iommu.c 2011-09-20 16:04:11.000000000 +0200 @@ -1626,13 +1626,13 @@ out: static int reassign_device_ownership( struct domain *source, struct domain *target, - u8 bus, u8 devfn) + u16 seg, u8 bus, u8 devfn) { struct pci_dev *pdev; int ret; ASSERT(spin_is_locked(&pcidevs_lock)); - pdev = pci_get_pdev_by_domain(source, 0, bus, devfn); + pdev = pci_get_pdev_by_domain(source, seg, bus, devfn); if (!pdev) return -ENODEV; @@ -2166,27 +2166,8 @@ int __init intel_vtd_setup(void) return ret; } -/* - * If the device isn't owned by dom0, it means it already - * has been assigned to other domain, or it's not exist. - */ -int device_assigned(u8 bus, u8 devfn) -{ - struct pci_dev *pdev; - - spin_lock(&pcidevs_lock); - pdev = pci_get_pdev_by_domain(dom0, 0, bus, devfn); - if (!pdev) - { - spin_unlock(&pcidevs_lock); - return -1; - } - - spin_unlock(&pcidevs_lock); - return 0; -} - -static int intel_iommu_assign_device(struct domain *d, u8 bus, u8 devfn) +static int intel_iommu_assign_device( + struct domain *d, u16 seg, u8 bus, u8 devfn) { struct acpi_rmrr_unit *rmrr; int ret = 0, i; @@ -2197,7 +2178,7 @@ static int intel_iommu_assign_device(str return -ENODEV; ASSERT(spin_is_locked(&pcidevs_lock)); - pdev = pci_get_pdev(0, bus, devfn); + pdev = pci_get_pdev(seg, bus, devfn); if (!pdev) return -ENODEV; @@ -2208,7 +2189,7 @@ static int intel_iommu_assign_device(str return -EBUSY; } - ret = reassign_device_ownership(dom0, d, bus, devfn); + ret = reassign_device_ownership(dom0, d, seg, bus, devfn); if ( ret ) goto done; @@ -2240,7 +2221,7 @@ done: return ret; } -static int intel_iommu_group_id(u8 bus, u8 devfn) +static int intel_iommu_group_id(u16 seg, u8 bus, u8 devfn) { u8 secbus; if ( find_upstream_bridge(&bus, &devfn, &secbus) < 0 ) --- 2011-09-20.orig/xen/include/public/domctl.h 2011-09-19 10:58:18.000000000 +0200 +++ 2011-09-20/xen/include/public/domctl.h 2011-09-15 15:39:21.000000000 +0200 @@ -455,15 +455,15 @@ DEFINE_XEN_GUEST_HANDLE(xen_domctl_sendt /* XEN_DOMCTL_test_assign_device */ /* XEN_DOMCTL_deassign_device */ struct xen_domctl_assign_device { - uint32_t machine_bdf; /* machine PCI ID of assigned device */ + uint32_t machine_sbdf; /* machine PCI ID of assigned device */ }; typedef struct xen_domctl_assign_device xen_domctl_assign_device_t; DEFINE_XEN_GUEST_HANDLE(xen_domctl_assign_device_t); -/* Retrieve sibling devices infomation of machine_bdf */ +/* Retrieve sibling devices infomation of machine_sbdf */ /* XEN_DOMCTL_get_device_group */ struct xen_domctl_get_device_group { - uint32_t machine_bdf; /* IN */ + uint32_t machine_sbdf; /* IN */ uint32_t max_sdevs; /* IN */ uint32_t num_sdevs; /* OUT */ XEN_GUEST_HANDLE_64(uint32) sdev_array; /* OUT */ --- 2011-09-20.orig/xen/include/xen/iommu.h 2011-08-25 15:06:23.000000000 +0200 +++ 2011-09-20/xen/include/xen/iommu.h 2011-09-15 16:46:28.000000000 +0200 @@ -74,11 +74,7 @@ int iommu_remove_device(struct pci_dev * int iommu_domain_init(struct domain *d); void iommu_dom0_init(struct domain *d); void iommu_domain_destroy(struct domain *d); -int device_assigned(u8 bus, u8 devfn); -int assign_device(struct domain *d, u8 bus, u8 devfn); -int deassign_device(struct domain *d, u8 bus, u8 devfn); -int iommu_get_device_group(struct domain *d, u8 bus, u8 devfn, - XEN_GUEST_HANDLE_64(uint32) buf, int max_sdevs); +int deassign_device(struct domain *d, u16 seg, u8 bus, u8 devfn); /* iommu_map_page() takes flags to direct the mapping operation. */ #define _IOMMUF_readable 0 @@ -125,14 +121,14 @@ struct iommu_ops { void (*dom0_init)(struct domain *d); int (*add_device)(struct pci_dev *pdev); int (*remove_device)(struct pci_dev *pdev); - int (*assign_device)(struct domain *d, u8 bus, u8 devfn); + int (*assign_device)(struct domain *d, u16 seg, u8 bus, u8 devfn); void (*teardown)(struct domain *d); int (*map_page)(struct domain *d, unsigned long gfn, unsigned long mfn, unsigned int flags); int (*unmap_page)(struct domain *d, unsigned long gfn); int (*reassign_device)(struct domain *s, struct domain *t, - u8 bus, u8 devfn); - int (*get_device_group_id)(u8 bus, u8 devfn); + u16 seg, u8 bus, u8 devfn); + int (*get_device_group_id)(u16 seg, u8 bus, u8 devfn); void (*update_ire_from_apic)(unsigned int apic, unsigned int reg, unsigned int value); void (*update_ire_from_msi)(struct msi_desc *msi_desc, struct msi_msg *msg); void (*read_msi_from_ire)(struct msi_desc *msi_desc, struct msi_msg *msg); @@ -155,4 +151,6 @@ void iommu_crash_shutdown(void); void iommu_set_dom0_mapping(struct domain *d); void iommu_share_p2m_table(struct domain *d); +int iommu_do_domctl(struct xen_domctl *, XEN_GUEST_HANDLE(xen_domctl_t)); + #endif /* _IOMMU_H_ */