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

[Xen-devel] [rfc 3/9] xend: pass-through: Allow multi-function device specifications to be parsed



The general format is as follows:

  Now: SEQ:BUS:DEV.FUNC[@VSLOT][,OPT...]
  New: SEQ:BUS:DEV.FUNC0-FUNCN[@VSLOT][,OPT...]
       SEQ:BUS:DEV.FUNC0,FUNCM,FUNCN[@VSLOT][,OPT...]
       SEQ:BUS:DEV.*[@VSLOT][,OPT...]

  In the case of unplug the VSLOT and OPT must be omitted.

  Xm expands this notation notation out and passes
  more conventional parameters to qemu-xen.

  E.g:
       0000:00:01.00-03 becomes:
         0000:00:01.00
         0000:00:01.01
         0000:00:01.02
         0000:00:01.03

       0000:00:01.00,03,05,07 becomes:
         0000:00:01.00
         0000:00:01.03
         0000:00:01.05
         0000:00:01.07

       For a device that has functions 0, 1, 2, 3, 5 and 7,
       0000:00:01.* becomes:
         0000:00:01.00
         0000:00:01.01
         0000:00:01.02
         0000:00:01.03
         0000:00:01.05
         0000:00:01.07

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

--- 

Wed, 20 May 2009 23:28:45 +1000
* Update for recent changes to the preceeding patch
  "xm: Common parse_pci_name()"
* Enhance error reporting in parse_pci_name()

Fri, 29 May 2009 09:15:23 +1000
* Up-port

Tue, 16 Jun 2009 20:40:24 +1000
* pci_func_list_map_fn() bugs, thanks to Takebe-san
  - Fix syntax error in filter in pci_func_list_map_fn()
  - pci_list_cmp() should be pci_dict_cmp
  - return a list of integers not strings

Index: xen-unstable.hg/tools/python/xen/util/pci.py
===================================================================
--- xen-unstable.hg.orig/tools/python/xen/util/pci.py   2009-06-16 
22:04:14.000000000 +1000
+++ xen-unstable.hg/tools/python/xen/util/pci.py        2009-06-16 
22:05:18.000000000 +1000
@@ -16,7 +16,7 @@ import threading
 from xen.util import utils
 from xen.xend import uuid
 from xen.xend import sxp
-from xen.xend.XendConstants import AUTO_PHP_DEVFN
+from xen.xend.XendConstants import AUTO_PHP_SLOT
 from xen.xend.XendSXPDev import dev_dict_to_sxp
 
 PROC_PCI_PATH = '/proc/bus/pci/devices'
@@ -227,11 +227,39 @@ def parse_hex(val):
     except ValueError:
         return None
 
+def pci_func_list_map_fn(key, func_str):
+    if func_str == "*":
+        return map(lambda x: int(x['func'], 16),
+                   filter(lambda x:
+                          pci_dict_cmp(x, key, ['domain', 'bus', 'slot']),
+                          get_all_pci_dict()))
+    l = map(int, func_str.split("-"))
+    if len(l) == 1:
+        return l
+    if len(l) == 2:
+        if l[0] < l[1]:
+            return range(l[0], l[1] + 1)
+        else:
+            x = range(l[1], l[0] + 1)
+            x.reverse()
+            return x
+    return []
+
+def pci_func_list_process(pci_dev_str, template, func_str):
+    l = reduce(lambda x, y: x + y,
+               (map(lambda x: pci_func_list_map_fn(template, x),
+                    func_str.split(","))))
+
+    if len(l) != len(set(l)):
+        raise PciDeviceParseError("Duplicate functions: %s" % pci_dev_str)
+
+    return l
+
 def parse_pci_name_extended(pci_dev_str):
     pci_match = re.match(r"((?P<domain>[0-9a-fA-F]{1,4})[:,])?" +
                          r"(?P<bus>[0-9a-fA-F]{1,2})[:,]" +
                          r"(?P<slot>[0-9a-fA-F]{1,2})[.,]" +
-                         r"(?P<func>(\*|[0-7]))" +
+                         r"(?P<func>(\*|[0-7]([,-][0-7])*))" +
                          r"(@(?P<vslot>[01]?[0-9a-fA-F]))?" +
                          r"(,(?P<opts>.*))?$", pci_dev_str)
 
@@ -239,31 +267,65 @@ def parse_pci_name_extended(pci_dev_str)
         raise PciDeviceParseError("Failed to parse pci device: %s" %
                                   pci_dev_str)
 
-    out = {}
     pci_dev_info = pci_match.groupdict('')
-    if pci_dev_info['domain'] == '':
-        domain = 0
-    else:
+
+    template = {}
+    if pci_dev_info['domain'] != '':
         domain = int(pci_dev_info['domain'], 16)
-    out['domain'] = "0x%04x" % domain
-    out['bus']    = "0x%02x" % int(pci_dev_info['bus'], 16)
-    out['slot']   = "0x%02x" % int(pci_dev_info['slot'], 16)
-    out['func']   = "0x%x"   % int(pci_dev_info['func'], 16)
-    if pci_dev_info['vslot'] == '':
-        vslot = AUTO_PHP_DEVFN
     else:
-        vslot = PCI_DEVFN(int(pci_dev_info['vslot'], 16), 0)
-    out['vslot'] = "0x%02x" % vslot
+        domain = 0
+    template['domain'] = "0x%04x" % domain
+    template['bus']    = "0x%02x" % int(pci_dev_info['bus'], 16)
+    template['slot']   = "0x%02x" % int(pci_dev_info['slot'], 16)
+    template['func']   = "0x%x"   % int(pci_dev_info['func'], 16)
     if pci_dev_info['opts'] != '':
-        out['opts'] = split_pci_opts(pci_dev_info['opts'])
-        check_pci_opts(out['opts'])
+        template['opts'] = split_pci_opts(pci_dev_info['opts'])
+        check_pci_opts(template['opts'])
 
-    return out
+    # This is where virtual function assignment takes place
+    # Virtual slot assignment takes place here if specified in the bdf,
+    # else it is done inside qemu-xen, as it knows which slots are free
+    pci = []
+    func_list = pci_func_list_process(pci_dev_str, template,
+                                      pci_dev_info['func'])
+    for func in func_list:
+        pci_dev = template.copy()
+
+        if len(func_list) == 1:
+            # For single-function devices vfunc must be 0
+            vfunc = 0
+        else:
+            # For multi-function virtual devices,
+            # identity map the func to vfunc
+            vfunc = func
+        if pci_dev_info['vslot'] == '':
+            vslot = AUTO_PHP_SLOT | vfunc
+        else:
+            vslot = PCI_DEVFN(int(pci_dev_info['vslot'], 16), vfunc)
+        pci_dev['vslot'] = "0x%02x" % vslot
+
+        pci.append(pci_dev)
+
+    # For pci attachment and detachment is it important that virtual
+    # function 0 is done last. This is because is virtual function 0 that
+    # is used to singnal changes to the guest using ACPI
+    #
+    # By arranging things so that virtual function 0 is first,
+    # attachemnt can use the returned list as is. And detachment
+    # can just reverse the list.
+    pci.sort(None, lambda x: int(x['vslot'], 16), 1)
+    return pci
 
 def parse_pci_name(pci_name_string):
-    pci = parse_pci_name_extended(pci_name_string)
+    dev = parse_pci_name_extended(pci_name_string)
 
-    if int(pci['vslot'], 16) != AUTO_PHP_DEVFN:
+    if len(dev) != 1:
+        raise PciDeviceParseError(("Failed to parse pci device: %s: "
+                                   "multiple functions specified prohibited") %
+                                    pci_name_string)
+
+    pci = dev[0]
+    if not int(pci['vslot'], 16) & AUTO_PHP_SLOT:
         raise PciDeviceParseError(("Failed to parse pci device: %s: " +
                                    "vslot provided where prohibited: 0x%02x") %
                                   (pci_name_string,
@@ -321,8 +383,11 @@ def get_all_pci_names():
     pci_names = os.popen('ls ' + sysfs_mnt + 
SYSFS_PCI_DEVS_PATH).read().split()
     return pci_names
 
+def get_all_pci_dict():
+    return map(parse_pci_name, get_all_pci_names())
+
 def get_all_pci_devices():
-    return map(PciDevice, map(parse_pci_name, get_all_pci_names()))
+    return map(PciDevice, get_all_pci_dict())
 
 def _create_lspci_info():
     """Execute 'lspci' command and parse the result.
Index: xen-unstable.hg/tools/python/xen/xm/create.py
===================================================================
--- xen-unstable.hg.orig/tools/python/xen/xm/create.py  2009-06-16 
22:04:14.000000000 +1000
+++ xen-unstable.hg/tools/python/xen/xm/create.py       2009-06-16 
22:04:16.000000000 +1000
@@ -1060,8 +1060,8 @@ def preprocess_pci(vals):
     if not vals.pci:
         return
     try:
-        vals.pci = map(pci_dict_to_tuple,
-                       map(parse_pci_name_extended, vals.pci))
+        vals.pci = map(pci_dict_to_tuple, reduce(lambda x, y: x + y,
+                       map(parse_pci_name_extended, vals.pci)))
     except PciDeviceParseError, ex:
         err(str(ex))
 
Index: xen-unstable.hg/tools/python/xen/xend/XendConstants.py
===================================================================
--- xen-unstable.hg.orig/tools/python/xen/xend/XendConstants.py 2009-06-16 
22:04:14.000000000 +1000
+++ xen-unstable.hg/tools/python/xen/xend/XendConstants.py      2009-06-16 
22:04:16.000000000 +1000
@@ -141,8 +141,7 @@ XS_VMROOT = "/vm/"
 NR_PCI_FUNC = 8
 NR_PCI_DEV = 32
 NR_PCI_DEVFN = NR_PCI_FUNC * NR_PCI_DEV
-AUTO_PHP_DEVFN = NR_PCI_DEVFN
-AUTO_PHP_DEVFN_STR = "%02x" % NR_PCI_DEVFN
+AUTO_PHP_SLOT = 0x100
 
 #
 # tmem
Index: xen-unstable.hg/tools/python/xen/xend/XendDomainInfo.py
===================================================================
--- xen-unstable.hg.orig/tools/python/xen/xend/XendDomainInfo.py        
2009-06-16 22:04:14.000000000 +1000
+++ xen-unstable.hg/tools/python/xen/xend/XendDomainInfo.py     2009-06-16 
22:04:16.000000000 +1000
@@ -644,7 +644,7 @@ class XendDomainInfo:
             pci_devs = pci_conf['devs']
             for x in pci_devs:
                 if (int(x['vslot'], 16) == int(new_dev['vslot'], 16) and
-                   int(x['vslot'], 16) != AUTO_PHP_DEVFN):
+                    not int(x['vslot'], 16) & AUTO_PHP_SLOT):
                     raise VmError("vslot %s already have a device." % 
(new_dev['vslot']))
 
                 if (pci_dict_cmp(x, new_dev)):
Index: xen-unstable.hg/tools/python/xen/xm/main.py
===================================================================
--- xen-unstable.hg.orig/tools/python/xen/xm/main.py    2009-06-16 
22:04:14.000000000 +1000
+++ xen-unstable.hg/tools/python/xen/xm/main.py 2009-06-16 22:04:16.000000000 
+1000
@@ -2210,7 +2210,7 @@ def xm_pci_list(args):
 
     has_vslot = False
     for x in devs:
-        if x['vslot'] == AUTO_PHP_DEVFN:
+        if x['vslot'] & AUTO_PHP_SLOT:
             x['show_vslot'] = '-'
             x['show_vfunc'] = '-'
         else:
@@ -2493,7 +2493,7 @@ def parse_pci_configuration(args, state,
         pci_dev_str += ',' + serialise_pci_opts(opts)
 
     try:
-        pci_dev = parse_pci_name_extended(pci_dev_str)
+        pci_dev = parse_pci_name_extended(pci_dev_str)[0]
     except PciDeviceParseError, ex:
         raise OptionError(str(ex))
 
Index: xen-unstable.hg/tools/python/xen/xend/XendConfig.py
===================================================================
--- xen-unstable.hg.orig/tools/python/xen/xend/XendConfig.py    2009-06-16 
22:04:14.000000000 +1000
+++ xen-unstable.hg/tools/python/xen/xend/XendConfig.py 2009-06-16 
22:04:16.000000000 +1000
@@ -31,7 +31,7 @@ from xen.xend.XendDSCSI import XendDSCSI
 from xen.xend.XendError import VmError
 from xen.xend.XendDevices import XendDevices
 from xen.xend.PrettyPrint import prettyprintstring
-from xen.xend.XendConstants import DOM_STATE_HALTED, AUTO_PHP_DEVFN_STR
+from xen.xend.XendConstants import DOM_STATE_HALTED, AUTO_PHP_SLOT
 from xen.xend.xenstore.xstransact import xstransact
 from xen.xend.server.BlktapController import blktap_disk_types
 from xen.xend.server.netif import randomMAC
@@ -1237,8 +1237,7 @@ class XendConfig(dict):
             dpci_record = {
                 'VM': self['uuid'],
                 'PPCI': ppci_uuid,
-                'hotplug_slot': pci_dev.get('vslot',
-                                            '0x' + AUTO_PHP_DEVFN_STR)
+                'hotplug_slot': pci_dev.get('vslot', '0x%02x' % AUTO_PHP_SLOT)
             }
 
             dpci_opts = pci_dev.get('opts')
Index: xen-unstable.hg/tools/python/xen/xend/server/pciif.py
===================================================================
--- xen-unstable.hg.orig/tools/python/xen/xend/server/pciif.py  2009-06-16 
22:04:14.000000000 +1000
+++ xen-unstable.hg/tools/python/xen/xend/server/pciif.py       2009-06-16 
22:04:16.000000000 +1000
@@ -74,8 +74,7 @@ class PciController(DevController):
             bus = parse_hex(pci_config.get('bus', 0))
             slot = parse_hex(pci_config.get('slot', 0))
             func = parse_hex(pci_config.get('func', 0))            
-            vslot = parse_hex(pci_config.get('vslot',
-                                             '0x' + AUTO_PHP_DEVFN_STR))
+            vslot = parse_hex(pci_config.get('vslot', '0x%02x' % 
AUTO_PHP_SLOT))
 
             if pci_config.has_key('opts'):
                 opts = serialise_pci_opts(pci_config['opts'])

-- 

_______________________________________________
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®.