mirror of
https://github.com/xen-project/xen.git
synced 2026-10-28 10:11:27 +01:00
PCI multi-seg: adjust domctl interface
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>
This commit is contained in:
1 parent
1b0061ac2b
commit
6865e52b78
11 files changed
+254
-374
No files matched your search
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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 )
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
|
||||
}
|
||||
|
||||
|
||||
+1
-139
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
+177
-11
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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 )
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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_ */
|
||||