[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-devel] [rfc 7/9] xend: pass-through: Parse command line for multi-function hot-plug and unplug



Hook things up to allow multi-function pass-through.

This includes making sure that request is valid.
In the case of pci-detach:

* All the functions requested must be attached to the same virtual slot * and;
* A request must include the functions attached to a virtual slot

Cc: Dexuan Cui <dexuan.cui@xxxxxxxxx>
Cc: Masaki Kanno <kanno.masaki@xxxxxxxxxxxxxx>
Signed-off-by: Simon Horman <horms@xxxxxxxxxxxx>

--- 

Wed, 20 May 2009 18:14:38 +1000
* Update for cset 19626:145e49b8574c

Fri, 22 May 2009 14:49:21 +1000
* Update for for bdf6->bdf4 changes in previous patches
* Remove bogus bdf6_to_bdf_string() hunk
* Move bdf6_to_sxp_request() call out of parse_pci_configuration()
  - This saves subsequently reversing the conversion
* Refactor bdf6_find_attached_devfn() to work on attached being
  a list of sprs
  - This saves a to bdf6 format
* Rename bdf6_find_attached_devfn bdf4_find_attached_devfn
* Move parse_pci_configuration() to main.py
  - It is only ever used in main.py

Fri, 29 May 2009 09:18:15 +1000
* Remove "from xen.xend import sxp" hunk from
  tools/python/xen/util/pci.py. It is present in an earlier patch
  by Kanno-san.

Index: xen-unstable.hg/tools/python/xen/xm/main.py
===================================================================
--- xen-unstable.hg.orig/tools/python/xen/xm/main.py    2009-06-14 
23:55:05.000000000 +1000
+++ xen-unstable.hg/tools/python/xen/xm/main.py 2009-06-14 23:55:09.000000000 
+1000
@@ -2222,8 +2222,9 @@ def xm_pci_list(args):
     if len(devs) == 0:
         return
 
-    devs.sort(None, lambda x: x['vslot'] << 32 | PCI_BDF(x['domain'], x['bus'],
-                                                         x['slot'], x['func']))
+    devs.sort(None,
+              lambda x: (x['vslot'] - PCI_FUNC(x['vslot'])) << 32 |
+                        PCI_BDF(x['domain'], x['bus'], x['slot'], x['func']))
 
     has_vslot = False
     for x in devs:
@@ -2501,7 +2502,7 @@ def xm_network_attach(args):
             vif.append(vif_param)
         server.xend.domain.device_create(dom, vif)
 
-def parse_pci_configuration(args, state, opts = ''):
+def parse_pci_configuration(args, opts = ''):
     dom = args[0]
     pci_dev_str = args[1]
     if len(args) == 3:
@@ -2510,11 +2511,11 @@ def parse_pci_configuration(args, state,
         pci_dev_str += ',' + serialise_pci_opts(opts)
 
     try:
-        pci_dev = parse_pci_name_extended(pci_dev_str)[0]
+        pci_dev = parse_pci_name_extended(pci_dev_str)
     except PciDeviceParseError, ex:
         raise OptionError(str(ex))
 
-    return (dom, pci_convert_dict_to_sxp(pci_dev, state))
+    return (dom, pci_dev)
 
 def xm_pci_attach(args):
     config_pci_opts = []
@@ -2531,19 +2532,31 @@ def xm_pci_attach(args):
         err("Invalid argument for 'xm pci-attach'")
         usage('pci-attach')
 
-    (dom, pci) = parse_pci_configuration(params, 'Initialising',
-                     config_pci_opts)
+    (dom, dev) = parse_pci_configuration(params, config_pci_opts)
 
-    if serverType == SERVER_XEN_API:
-        pci_dev = sxp.children(pci, 'dev')[0]
-        domain = int(sxp.child_value(pci_dev, 'domain'), 16)
-        bus = int(sxp.child_value(pci_dev, 'bus'), 16)
-        slot = int(sxp.child_value(pci_dev, 'slot'), 16)
-        func = int(sxp.child_value(pci_dev, 'func'), 16)
-        vslot = int(sxp.child_value(pci_dev, 'vslot'), 16)
-        key = sxp.child_value(pci_dev, 'key')
-        name = "%04x:%02x:%02x.%01x" % (domain, bus, slot, func)
+    head_dev = dev.pop(0)
+    xm_pci_attach_one(dom, head_dev)
+
+    # That is all for single-function virtual devices
+    if len(dev) == 0:
+        return
 
+    # If the slot wasn't spefified in the args then use the slot
+    # assigned to the head by qemu-xen for the rest of the functions
+    if int(head_dev['vslot'], 16) & AUTO_PHP_SLOT:
+        vdevfn = int(find_attached_devfn(attached_pci_dict(dom), head_dev), 16)
+        if not vdevfn & AUTO_PHP_SLOT:
+            vslot = PCI_SLOT(vdevfn)
+            for i in dev:
+                i['vslot'] = '0x%02x' % \
+                            PCI_DEVFN(vslot, PCI_FUNC(int(i['vslot'], 16)))
+
+    for i in dev:
+        xm_pci_attach_one(dom, i)
+
+def xm_pci_attach_one(dom, pci_dev):
+    if serverType == SERVER_XEN_API:
+        name = pci_dict_to_bdf_str(pci_dev)
         target_ref = None
         for ppci_ref in server.xenapi.PPCI.get_all():
             if name == server.xenapi.PPCI.get_name(ppci_ref):
@@ -2555,13 +2568,14 @@ def xm_pci_attach(args):
         dpci_record = {
             "VM":           get_single_vm(dom),
             "PPCI":         target_ref,
-            "hotplug_slot": vslot,
-            "options":      dict(config_pci_opts),
-            "key":          key
+            "hotplug_slot": int(pci_dev['vslot'], 16),
+            "options":      dict(pci_dev.get('opts', [])),
+            "key":          pci_dev['key']
         }
         server.xenapi.DPCI.create(dpci_record)
 
     else:
+        pci = pci_convert_dict_to_sxp(pci_dev, 'Initialising')
         server.xend.domain.device_configure(dom, pci)
 
 def parse_scsi_configuration(p_scsi, v_hctl, state):
@@ -2704,20 +2718,61 @@ def xm_network_detach(args):
         arg_check(args, 'network-detach', 2, 3)
         detach(args, 'vif')
 
+def find_attached(attached, key):
+    l = filter(lambda dev: pci_dict_cmp(dev, key), attached)
+
+    if len(l) == 0:
+         raise OptionError("pci: device is not attached: " +
+                           pci_dict_to_bdf_str(key))
+
+    # There shouldn't ever be more than one match,
+    # but perhaps an exception should be thrown if there is
+    return l[0]
+
+def find_attached_devfn(attached, key):
+    pci_dev = find_attached(attached, key)
+    return pci_dev['vslot']
+
 def xm_pci_detach(args):
     arg_check(args, 'pci-detach', 2)
-    (dom, pci) = parse_pci_configuration(args, 'Closing')
 
-    if serverType == SERVER_XEN_API:
+    (dom, dev) = parse_pci_configuration(args)
+    attached = attached_pci_dict(dom)
 
-        pci_dev = sxp.children(pci, 'dev')[0]
-        domain = int(sxp.child_value(pci_dev, 'domain'), 16)
-        bus = int(sxp.child_value(pci_dev, 'bus'), 16)
-        slot = int(sxp.child_value(pci_dev, 'slot'), 16)
-        func = int(sxp.child_value(pci_dev, 'func'), 16)
-        vslot = int(sxp.child_value(pci_dev, 'vslot'), 16)
-        name = "%04x:%02x:%02x.%01x" % (domain, bus, slot, func)
+    attached_dev = map(lambda x: find_attached(attached, x), dev)
 
+    def f(pci_dev):
+        vdevfn = int(pci_dev['vslot'], 16)
+        return PCI_SLOT(vdevfn) | (vdevfn & AUTO_PHP_SLOT)
+    vslots = map(f, attached_dev)
+    if len(set(vslots)) > 1:
+        err_str = map(lambda x: "\t%s is in slot 0x%02x\n" %
+                                (pci_dict_to_bdf_str(x),
+                                 PCI_SLOT(int(x['vslot'], 16))), dev)
+        raise OptionError("More than one slot used by specified devices\n"
+                          + ''.join(err_str))
+
+    attached_to_slot = filter(lambda x:
+                              f(x) == vslots[0] and
+                              attached_dev[0]["key"] ==
+                                      x["key"], attached_dev)
+
+    if len(attached_to_slot) != len(dev):
+        err_str_ = map(lambda x: '\t%s\n' % pci_dict_to_bdf_str(x), dev)
+        err_str = "Requested:\n" + ''.join(err_str_)
+        err_str_ = map(lambda x: '\t%s (%s)\n' %
+                       (pci_dict_to_bdf_str(x), x['key']),
+                       attached_to_slot)
+        err_str += "Present:\n" + ''.join(err_str_)
+        raise OptionError(("Not all functions in slot 0x%02x have had "
+                           "detachment requested.\n" % vslots[0]) + err_str)
+
+    for i in dev:
+        xm_pci_detach_one(dom, i)
+
+def xm_pci_detach_one(dom, pci_dev):
+    if serverType == SERVER_XEN_API:
+        name = pci_dict_to_bdf_str(pci_dev)
         target_ref = None
         for dpci_ref in server.xenapi.VM.get_DPCIs(get_single_vm(dom)):
             ppci_ref = server.xenapi.DPCI.get_PPCI(dpci_ref)
@@ -2729,6 +2784,7 @@ def xm_pci_detach(args):
             raise OptionError("Device %s not assigned" % name)
 
     else:
+        pci = pci_convert_dict_to_sxp(pci_dev, 'Closing')
         server.xend.domain.device_configure(dom, pci)
 
 def xm_scsi_detach(args):
Index: xen-unstable.hg/tools/python/xen/xend/XendDomainInfo.py
===================================================================
--- xen-unstable.hg.orig/tools/python/xen/xend/XendDomainInfo.py        
2009-06-14 23:55:05.000000000 +1000
+++ xen-unstable.hg/tools/python/xen/xend/XendDomainInfo.py     2009-06-14 
23:55:09.000000000 +1000
@@ -42,7 +42,7 @@ from xen.util import xsconstants
 from xen.util.pci import serialise_pci_opts, pci_opts_list_to_sxp, \
                          pci_dict_to_bdf_str, pci_dict_to_xc_str, \
                          pci_convert_sxp_to_dict, pci_convert_dict_to_sxp, \
-                         pci_dict_cmp, PCI_FUNC
+                         pci_dict_cmp, PCI_DEVFN, PCI_SLOT, PCI_FUNC
 
 from xen.xend import balloon, sxp, uuid, image, arch
 from xen.xend import XendOptions, XendNode, XendConfig
@@ -617,12 +617,52 @@ class XendDomainInfo:
         dev_uuid = sxp.child_value(dev_info, 'uuid')
         pci_conf = self.info['devices'][dev_uuid][1]
         pci_devs = pci_conf['devs']
-        request = map(lambda x:
-                      pci_convert_dict_to_sxp(x, 'Initialising', 'Booting'),
-                      pci_devs)
 
-        for i in request:
-                self.pci_device_configure(i)
+        # Keep a set of keys that are done rather than
+        # just itterating through set(map(..., pci_devs))
+        # to preserve any order information present.
+        done = set()
+        for key in map(lambda x: x['key'], pci_devs):
+            if key in done:
+                continue
+            done |= set([key])
+            dev = filter(lambda x: x['key'] == key, pci_devs)
+
+            head_dev = dev.pop()
+            dev_sxp = pci_convert_dict_to_sxp(head_dev, 'Initialising',
+                                              'Booting')
+            self.pci_device_configure(dev_sxp)
+
+            # That is all for single-function virtual devices
+            if len(dev) == 0:
+                continue
+
+            if int(head_dev['vslot'], 16) & AUTO_PHP_SLOT:
+                new_dev_info = self._getDeviceInfo_pci(devid)
+                if new_dev_info is None:
+                    continue
+                new_dev_uuid = sxp.child_value(new_dev_info, 'uuid')
+                new_pci_conf = self.info['devices'][new_dev_uuid][1]
+                new_pci_devs = new_pci_conf['devs']
+
+                new_head_dev = filter(lambda x: pci_dict_cmp(x, head_dev),
+                                      new_pci_devs)[0]
+
+                if int(new_head_dev['vslot'], 16) & AUTO_PHP_SLOT:
+                    continue
+
+                vslot = PCI_SLOT(int(new_head_dev['vslot'], 16))
+                new_dev = []
+                for i in dev:
+                    i['vslot'] = '0x%02x' % \
+                                 PCI_DEVFN(vslot, PCI_FUNC(int(i['vslot'], 
16)))
+                    new_dev.append(i)
+
+                dev = new_dev
+
+            for i in dev:
+                dev_sxp = pci_convert_dict_to_sxp(i, 'Initialising', 'Booting')
+                self.pci_device_configure(dev_sxp)
 
     def hvm_pci_device_create(self, dev_config):
         log.debug("XendDomainInfo.hvm_pci_device_create: %s"

-- 

_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.