]> xenbits.xensource.com Git - xen.git/commitdiff
PCI multi-seg: adjust domctl interface
authorJan Beulich <jbeulich@suse.com>
Thu, 22 Sep 2011 17:26:54 +0000 (18:26 +0100)
committerJan Beulich <jbeulich@suse.com>
Thu, 22 Sep 2011 17:26:54 +0000 (18:26 +0100)
Again, a couple of directly related functions at once get adjusted to
account for the segment number.

Signed-off-by: Jan Beulich <jbeulich@suse.com>
tools/libxc/xc_domain.c
tools/libxl/libxl_pci.c
tools/python/xen/lowlevel/xc/xc.c
xen/arch/ia64/xen/dom0_ops.c
xen/arch/x86/domctl.c
xen/drivers/passthrough/amd/pci_amd_iommu.c
xen/drivers/passthrough/iommu.c
xen/drivers/passthrough/pci.c
xen/drivers/passthrough/vtd/iommu.c
xen/include/public/domctl.h
xen/include/xen/iommu.h

index a9c5cff6facd1ac1a55e19c0d0cf0ab9442f6a3c..d6f007df531c953a5998f58ef431f237b9c57471 100644 (file)
@@ -1132,13 +1132,13 @@ int xc_domain_setdebugging(xc_interface *xch,
 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);
 }
index 1669e17027b45c3098e07025f434a78834b30037..1523cf07e12c783d85f57ad1e7427718d0897d4c 100644 (file)
@@ -45,10 +45,10 @@ static unsigned int pcidev_encode_bdf(libxl_device_pci *pcidev)
 {
     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;
 }
index 2600b90060c905746b0c11646fd93ba092417170..c9e54b957c4077f3f823846eaf432686c0954cd4 100644 (file)
@@ -609,7 +609,7 @@ static PyObject *pyxc_test_assign_device(XcObject *self,
 {
     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(XcObject *self,
 
     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(XcObject *self,
 {
     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(XcObject *self,
 
     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(XcObject *self,
 {
     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(XcObject *self,
 
     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(XcObject *self,
     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 )
     {
index f6ba0e3e031206ad370db9d94c2332ea3344cf02..0cfa39f6135eb4c9b5989ef53c9af565806ddfdf 100644 (file)
@@ -258,138 +258,6 @@ long arch_do_domctl(xen_domctl_t *op, XEN_GUEST_HANDLE(xen_domctl_t) u_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(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, XEN_GUEST_HANDLE(xen_domctl_t) u_domctl)
     break;
 
     default:
-        printk("arch_do_domctl: unrecognized domctl: %d!!!\n",op->cmd);
-        ret = -ENOSYS;
+        ret = iommu_do_domctl(op, u_domctl);
+        break;
 
     }
 
index 54082ac35a4247c50d0d4e3102ce9ef69d08ad93..5d5cd3a01b7d32fd084cba7cbb7e60b3c62589f3 100644 (file)
@@ -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;
     }
 
index b3cde6e4efe0efd7da3ccc16f086bd903da3ad40..9736251cb11efa4273542d50bf26a4e7c2befe6e 100644 (file)
@@ -305,7 +305,7 @@ static void amd_iommu_disable_domain_device(
 }
 
 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 domain *source, struct domain *target,
     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 domain *source, struct domain *target,
     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(struct domain *d, u8 bus, u8 devfn)
             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(struct domain *d)
 }
 
 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(struct pci_dev *pdev)
     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;
index b91d694eef006ae177d17da5ebe20df8eb139fa7..46ca97813539268c0a195cefff652c2efa7c8dfb 100644 (file)
@@ -19,6 +19,7 @@
 #include <xen/paging.h>
 #include <xen/guest_access.h>
 #include <xen/softirq.h>
+#include <xsm/xsm.h>
 
 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 *pdev)
     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 bus, u8 devfn)
         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, unsigned long gfn)
 }
 
 /* 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 bus, u8 devfn)
         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 bus, u8 devfn)
         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 *d, u8 bus, u8 devfn,
     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
index 9700ef17e966b8a19f622eea8424f7a10e54fa5e..21db87fe2e862eddd9b296741606193631bc5a5e 100644 (file)
@@ -441,11 +441,12 @@ void pci_release_devices(struct domain *d)
     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);
 }
index 25ab7f7471f6541a22d9ae3afb4888e44dc1777a..ae79842c3de206df3be6f6ecace940e337ea888c 100644 (file)
@@ -1620,13 +1620,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;
@@ -2153,27 +2153,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;
@@ -2184,7 +2165,7 @@ static int intel_iommu_assign_device(struct domain *d, u8 bus, u8 devfn)
         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;
 
@@ -2195,7 +2176,7 @@ static int intel_iommu_assign_device(struct domain *d, u8 bus, u8 devfn)
        return -EBUSY;
     }
 
-    ret = reassign_device_ownership(dom0, d, bus, devfn);
+    ret = reassign_device_ownership(dom0, d, seg, bus, devfn);
     if ( ret )
         goto done;
 
@@ -2227,7 +2208,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 )
index 84f236d563deb55928b09dfe27758ba76e0edd0b..ae512aac10d7097428563ac38ded34240aef1309 100644 (file)
@@ -455,15 +455,15 @@ DEFINE_XEN_GUEST_HANDLE(xen_domctl_sendtrigger_t);
 /* 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 */
index c3f934b87e0cef1ce77d7f807e036c7e771ff87c..e659e497257cec0e46ffc96ee50f35cc640811a0 100644 (file)
@@ -74,11 +74,7 @@ int iommu_remove_device(struct pci_dev *pdev);
 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_ */