ia64/xen-unstable

changeset 17728:28083093cc5d

Handle IOMMU device assignment for PV guests

Added more informative error codes for device assignment domctls.
Introduced python bindings for device assignment and enable xend to
also perform IOMMU device assignment when assigning PCI devices.

Signed-off-by: Espen Skoglund <espen.skoglund@netronome.com>
author Keir Fraser <keir.fraser@citrix.com>
date Sat May 24 09:45:37 2008 +0100 (2008-05-24)
parents c684cf331f94
children c0c0f4fa8850
files tools/python/xen/lowlevel/xc/xc.c tools/python/xen/xend/server/pciif.py xen/arch/x86/domctl.c
line diff
     1.1 --- a/tools/python/xen/lowlevel/xc/xc.c	Sat May 24 09:42:02 2008 +0100
     1.2 +++ b/tools/python/xen/lowlevel/xc/xc.c	Sat May 24 09:45:37 2008 +0100
     1.3 @@ -106,7 +106,7 @@ static PyObject *pyxc_domain_create(XcOb
     1.4      static char *kwd_list[] = { "domid", "ssidref", "handle", "flags", "target", NULL };
     1.5  
     1.6      if ( !PyArg_ParseTupleAndKeywords(args, kwds, "|iiOii", kwd_list,
     1.7 -				      &dom, &ssidref, &pyhandle, &flags, &target))
     1.8 +                                      &dom, &ssidref, &pyhandle, &flags, &target))
     1.9          return NULL;
    1.10      if ( pyhandle != NULL )
    1.11      {
    1.12 @@ -434,44 +434,44 @@ static PyObject *pyxc_linux_build(XcObje
    1.13      dom->vhpt_size_log2 = vhpt;
    1.14  
    1.15      if ( xc_dom_linux_build(self->xc_handle, dom, domid, mem_mb, image,
    1.16 -			    ramdisk, flags, store_evtchn, &store_mfn,
    1.17 -			    console_evtchn, &console_mfn) != 0 ) {
    1.18 -	goto out;
    1.19 +                            ramdisk, flags, store_evtchn, &store_mfn,
    1.20 +                            console_evtchn, &console_mfn) != 0 ) {
    1.21 +        goto out;
    1.22      }
    1.23  
    1.24      if ( !(elfnote_dict = PyDict_New()) )
    1.25 -	goto out;
    1.26 +        goto out;
    1.27      
    1.28      for ( i = 0; i < ARRAY_SIZE(dom->parms.elf_notes); i++ )
    1.29      {
    1.30 -	switch ( dom->parms.elf_notes[i].type )
    1.31 +        switch ( dom->parms.elf_notes[i].type )
    1.32          {
    1.33 -	case XEN_ENT_NONE:
    1.34 -	    continue;
    1.35 -	case XEN_ENT_LONG:
    1.36 -	    elfnote = Py_BuildValue("k", dom->parms.elf_notes[i].data.num);
    1.37 -	    break;
    1.38 -	case XEN_ENT_STR:
    1.39 -	    elfnote = Py_BuildValue("s", dom->parms.elf_notes[i].data.str);
    1.40 -	    break;
    1.41 -	}
    1.42 -	PyDict_SetItemString(elfnote_dict,
    1.43 -			     dom->parms.elf_notes[i].name,
    1.44 -			     elfnote);
    1.45 -	Py_DECREF(elfnote);
    1.46 +        case XEN_ENT_NONE:
    1.47 +            continue;
    1.48 +        case XEN_ENT_LONG:
    1.49 +            elfnote = Py_BuildValue("k", dom->parms.elf_notes[i].data.num);
    1.50 +            break;
    1.51 +        case XEN_ENT_STR:
    1.52 +            elfnote = Py_BuildValue("s", dom->parms.elf_notes[i].data.str);
    1.53 +            break;
    1.54 +        }
    1.55 +        PyDict_SetItemString(elfnote_dict,
    1.56 +                             dom->parms.elf_notes[i].name,
    1.57 +                             elfnote);
    1.58 +        Py_DECREF(elfnote);
    1.59      }
    1.60  
    1.61      ret = Py_BuildValue("{s:i,s:i,s:N}",
    1.62 -			"store_mfn", store_mfn,
    1.63 -			"console_mfn", console_mfn,
    1.64 -			"notes", elfnote_dict);
    1.65 +                        "store_mfn", store_mfn,
    1.66 +                        "console_mfn", console_mfn,
    1.67 +                        "notes", elfnote_dict);
    1.68  
    1.69      if ( dom->arch_hooks->native_protocol )
    1.70      {
    1.71 -	PyObject *native_protocol =
    1.72 -	    Py_BuildValue("s", dom->arch_hooks->native_protocol);
    1.73 -	PyDict_SetItemString(ret, "native_protocol", native_protocol);
    1.74 -	Py_DECREF(native_protocol);
    1.75 +        PyObject *native_protocol =
    1.76 +            Py_BuildValue("s", dom->arch_hooks->native_protocol);
    1.77 +        PyDict_SetItemString(ret, "native_protocol", native_protocol);
    1.78 +        Py_DECREF(native_protocol);
    1.79      }
    1.80  
    1.81      xc_dom_release(dom);
    1.82 @@ -556,7 +556,7 @@ static PyObject *pyxc_test_assign_device
    1.83  {
    1.84      uint32_t dom;
    1.85      char *pci_str;
    1.86 -    uint32_t bdf = 0;
    1.87 +    int32_t bdf = 0;
    1.88      int seg, bus, dev, func;
    1.89  
    1.90      static char *kwd_list[] = { "domid", "pci", NULL };
    1.91 @@ -571,8 +571,75 @@ static PyObject *pyxc_test_assign_device
    1.92          bdf |= (func & 0x7) << 8;
    1.93  
    1.94          if ( xc_test_assign_device(self->xc_handle, dom, bdf) != 0 )
    1.95 +        {
    1.96 +            if (errno == ENOSYS)
    1.97 +                bdf = -1;
    1.98              break;
    1.99 +        }
   1.100 +        bdf = 0;
   1.101 +    }
   1.102  
   1.103 +    return Py_BuildValue("i", bdf);
   1.104 +}
   1.105 +
   1.106 +static PyObject *pyxc_assign_device(XcObject *self,
   1.107 +                                    PyObject *args,
   1.108 +                                    PyObject *kwds)
   1.109 +{
   1.110 +    uint32_t dom;
   1.111 +    char *pci_str;
   1.112 +    int32_t bdf = 0;
   1.113 +    int seg, bus, dev, func;
   1.114 +
   1.115 +    static char *kwd_list[] = { "domid", "pci", NULL };
   1.116 +    if ( !PyArg_ParseTupleAndKeywords(args, kwds, "is", kwd_list,
   1.117 +                                      &dom, &pci_str) )
   1.118 +        return NULL;
   1.119 +
   1.120 +    while ( next_bdf(&pci_str, &seg, &bus, &dev, &func) )
   1.121 +    {
   1.122 +        bdf |= (bus & 0xff) << 16;
   1.123 +        bdf |= (dev & 0x1f) << 11;
   1.124 +        bdf |= (func & 0x7) << 8;
   1.125 +
   1.126 +        if ( xc_assign_device(self->xc_handle, dom, bdf) != 0 )
   1.127 +        {
   1.128 +            if (errno == ENOSYS)
   1.129 +                bdf = -1;
   1.130 +            break;
   1.131 +        }
   1.132 +        bdf = 0;
   1.133 +    }
   1.134 +
   1.135 +    return Py_BuildValue("i", bdf);
   1.136 +}
   1.137 +
   1.138 +static PyObject *pyxc_deassign_device(XcObject *self,
   1.139 +                                      PyObject *args,
   1.140 +                                      PyObject *kwds)
   1.141 +{
   1.142 +    uint32_t dom;
   1.143 +    char *pci_str;
   1.144 +    int32_t bdf = 0;
   1.145 +    int seg, bus, dev, func;
   1.146 +
   1.147 +    static char *kwd_list[] = { "domid", "pci", NULL };
   1.148 +    if ( !PyArg_ParseTupleAndKeywords(args, kwds, "is", kwd_list,
   1.149 +                                      &dom, &pci_str) )
   1.150 +        return NULL;
   1.151 +
   1.152 +    while ( next_bdf(&pci_str, &seg, &bus, &dev, &func) )
   1.153 +    {
   1.154 +        bdf |= (bus & 0xff) << 16;
   1.155 +        bdf |= (dev & 0x1f) << 11;
   1.156 +        bdf |= (func & 0x7) << 8;
   1.157 +
   1.158 +        if ( xc_deassign_device(self->xc_handle, dom, bdf) != 0 )
   1.159 +        {
   1.160 +            if (errno == ENOSYS)
   1.161 +                bdf = -1;
   1.162 +            break;
   1.163 +        }
   1.164          bdf = 0;
   1.165      }
   1.166  
   1.167 @@ -729,8 +796,8 @@ static PyObject *pyxc_hvm_build(XcObject
   1.168      int memsize, vcpus = 1, acpi = 0, apic = 1;
   1.169  
   1.170      static char *kwd_list[] = { "domid",
   1.171 -				"memsize", "image", "vcpus", "acpi",
   1.172 -				"apic", NULL };
   1.173 +                                "memsize", "image", "vcpus", "acpi",
   1.174 +                                "apic", NULL };
   1.175      if ( !PyArg_ParseTupleAndKeywords(args, kwds, "iis|iii", kwd_list,
   1.176                                        &dom, &memsize,
   1.177                                        &image, &vcpus, &acpi, &apic) )
   1.178 @@ -782,8 +849,8 @@ static PyObject *pyxc_evtchn_alloc_unbou
   1.179  }
   1.180  
   1.181  static PyObject *pyxc_evtchn_reset(XcObject *self,
   1.182 -				   PyObject *args,
   1.183 -				   PyObject *kwds)
   1.184 +                                   PyObject *args,
   1.185 +                                   PyObject *kwds)
   1.186  {
   1.187      uint32_t dom;
   1.188  
   1.189 @@ -947,11 +1014,11 @@ static PyObject *pyxc_physinfo(XcObject 
   1.190  
   1.191      for ( i = 0; i < info.nr_nodes; i++ )
   1.192      {
   1.193 -	xc_availheap(self->xc_handle, 0, 0, i, &free_heap);
   1.194 -	PyList_Append(node_to_memory_obj,
   1.195 -	    PyInt_FromLong(free_heap / 1024));
   1.196 +        xc_availheap(self->xc_handle, 0, 0, i, &free_heap);
   1.197 +        PyList_Append(node_to_memory_obj,
   1.198 +                      PyInt_FromLong(free_heap / 1024));
   1.199      }
   1.200 -	
   1.201 +
   1.202      PyDict_SetItemString(ret_obj, "node_to_cpu", node_to_cpu_obj);
   1.203      PyDict_SetItemString(ret_obj, "node_to_memory", node_to_memory_obj);
   1.204   
   1.205 @@ -1524,6 +1591,22 @@ static PyMethodDef pyxc_methods[] = {
   1.206         " dom     [int]:      Identifier of domain to build into.\n"
   1.207         " pci_str [str]:      PCI devices.\n"
   1.208         "Returns: [int] 0 on success, or device bdf that can't be assigned.\n" },
   1.209 +
   1.210 +     { "assign_device",
   1.211 +       (PyCFunction)pyxc_assign_device,
   1.212 +       METH_VARARGS | METH_KEYWORDS, "\n"
   1.213 +       "Assign device to IOMMU domain.\n"
   1.214 +       " dom     [int]:      Domain to assign device to.\n"
   1.215 +       " pci_str [str]:      PCI devices.\n"
   1.216 +       "Returns: [int] 0 on success, or device bdf that can't be assigned.\n" },
   1.217 +
   1.218 +     { "deassign_device",
   1.219 +       (PyCFunction)pyxc_deassign_device,
   1.220 +       METH_VARARGS | METH_KEYWORDS, "\n"
   1.221 +       "Deassign device from IOMMU domain.\n"
   1.222 +       " dom     [int]:      Domain to deassign device from.\n"
   1.223 +       " pci_str [str]:      PCI devices.\n"
   1.224 +       "Returns: [int] 0 on success, or device bdf that can't be deassigned.\n" },
   1.225    
   1.226      { "sched_id_get",
   1.227        (PyCFunction)pyxc_sched_id_get,
     2.1 --- a/tools/python/xen/xend/server/pciif.py	Sat May 24 09:42:02 2008 +0100
     2.2 +++ b/tools/python/xen/xend/server/pciif.py	Sat May 24 09:45:37 2008 +0100
     2.3 @@ -248,6 +248,15 @@ class PciController(DevController):
     2.4          PCIQuirk(dev.vendor, dev.device, dev.subvendor, dev.subdevice, domain, 
     2.5                  bus, slot, func)
     2.6  
     2.7 +        if not self.vm.info.is_hvm():
     2.8 +            # Setup IOMMU device assignment
     2.9 +            pci_str = "0x%x, 0x%x, 0x%x, 0x%x" % (domain, bus, slot, func)
    2.10 +            bdf = xc.assign_device(fe_domid, pci_str)
    2.11 +            if bdf > 0:
    2.12 +                raise VmError("Failed to assign device to IOMMU (%x:%x.%x)"
    2.13 +                              % (bus, slot, func))
    2.14 +            log.debug("pci: assign device %x:%x.%x" % (bus, slot, func))
    2.15 +
    2.16          for (start, size) in dev.ioports:
    2.17              log.debug('pci: enabling ioport 0x%x/0x%x'%(start,size))
    2.18              rc = xc.domain_ioport_permission(domid = fe_domid, first_port = start,
    2.19 @@ -330,6 +339,14 @@ class PciController(DevController):
    2.20                      "bind your slot/device to the PCI backend using sysfs" \
    2.21                      )%(dev.name))
    2.22  
    2.23 +        if not self.vm.info.is_hvm():
    2.24 +            pci_str = "0x%x, 0x%x, 0x%x, 0x%x" % (domain, bus, slot, func)
    2.25 +            bdf = xc.deassign_device(fe_domid, pci_str)
    2.26 +            if bdf > 0:
    2.27 +                raise VmError("Failed to deassign device from IOMMU (%x:%x.%x)"
    2.28 +                              % (bus, slot, func))
    2.29 +            log.debug("pci: deassign device %x:%x.%x" % (bus, slot, func))
    2.30 +
    2.31          for (start, size) in dev.ioports:
    2.32              log.debug('pci: disabling ioport 0x%x/0x%x'%(start,size))
    2.33              rc = xc.domain_ioport_permission(domid = fe_domid, first_port = start,
     3.1 --- a/xen/arch/x86/domctl.c	Sat May 24 09:42:02 2008 +0100
     3.2 +++ b/xen/arch/x86/domctl.c	Sat May 24 09:45:37 2008 +0100
     3.3 @@ -530,10 +530,11 @@ long arch_do_domctl(
     3.4      {
     3.5          u8 bus, devfn;
     3.6  
     3.7 -        ret = -EINVAL;
     3.8 +        ret = -ENOSYS;
     3.9          if ( !iommu_enabled )
    3.10              break;
    3.11  
    3.12 +        ret = -EINVAL;
    3.13          bus = (domctl->u.assign_device.machine_bdf >> 16) & 0xff;
    3.14          devfn = (domctl->u.assign_device.machine_bdf >> 8) & 0xff;
    3.15  
    3.16 @@ -553,10 +554,11 @@ long arch_do_domctl(
    3.17          struct domain *d;
    3.18          u8 bus, devfn;
    3.19  
    3.20 -        ret = -EINVAL;
    3.21 +        ret = -ENOSYS;
    3.22          if ( !iommu_enabled )
    3.23              break;
    3.24  
    3.25 +        ret = -EINVAL;
    3.26          if ( unlikely((d = get_domain_by_id(domctl->domain)) == NULL) )
    3.27          {
    3.28              gdprintk(XENLOG_ERR,
    3.29 @@ -566,6 +568,12 @@ long arch_do_domctl(
    3.30          bus = (domctl->u.assign_device.machine_bdf >> 16) & 0xff;
    3.31          devfn = (domctl->u.assign_device.machine_bdf >> 8) & 0xff;
    3.32  
    3.33 +        if ( !iommu_pv_enabled && !is_hvm_domain(d) )
    3.34 +        {
    3.35 +            ret = -ENOSYS;
    3.36 +            break;
    3.37 +        }
    3.38 +
    3.39          if ( device_assigned(bus, devfn) )
    3.40          {
    3.41              gdprintk(XENLOG_ERR, "XEN_DOMCTL_assign_device: "
    3.42 @@ -576,7 +584,7 @@ long arch_do_domctl(
    3.43  
    3.44          ret = assign_device(d, bus, devfn);
    3.45          gdprintk(XENLOG_INFO, "XEN_DOMCTL_assign_device: bdf = %x:%x:%x\n",
    3.46 -            bus, PCI_SLOT(devfn), PCI_FUNC(devfn));
    3.47 +                 bus, PCI_SLOT(devfn), PCI_FUNC(devfn));
    3.48          put_domain(d);
    3.49      }
    3.50      break;
    3.51 @@ -586,10 +594,11 @@ long arch_do_domctl(
    3.52          struct domain *d;
    3.53          u8 bus, devfn;
    3.54  
    3.55 -        ret = -EINVAL;
    3.56 +        ret = -ENOSYS;
    3.57          if ( !iommu_enabled )
    3.58              break;
    3.59  
    3.60 +        ret = -EINVAL;
    3.61          if ( unlikely((d = get_domain_by_id(domctl->domain)) == NULL) )
    3.62          {
    3.63              gdprintk(XENLOG_ERR,
    3.64 @@ -599,9 +608,16 @@ long arch_do_domctl(
    3.65          bus = (domctl->u.assign_device.machine_bdf >> 16) & 0xff;
    3.66          devfn = (domctl->u.assign_device.machine_bdf >> 8) & 0xff;
    3.67  
    3.68 +        if ( !iommu_pv_enabled && !is_hvm_domain(d) )
    3.69 +        {
    3.70 +            ret = -ENOSYS;
    3.71 +            break;
    3.72 +        }
    3.73 +
    3.74          if ( !device_assigned(bus, devfn) )
    3.75              break;
    3.76  
    3.77 +        ret = 0;
    3.78          deassign_device(d, bus, devfn);
    3.79          gdprintk(XENLOG_INFO, "XEN_DOMCTL_deassign_device: bdf = %x:%x:%x\n",
    3.80              bus, PCI_SLOT(devfn), PCI_FUNC(devfn));