WARNING - OLD ARCHIVES

This is an archived copy of the Xen.org mailing list, which we have preserved to ensure that existing links to archives are not broken. The live archive, which contains the latest emails, can be found at http://lists.xen.org/
   
 
 
Xen 
 
Home Products Support Community News
 
   
 

xen-devel

[Xen-devel] [rfc 3/9] xend: pass-through: Allow multi-function device sp

To: xen-devel@xxxxxxxxxxxxxxxxxxx
Subject: [Xen-devel] [rfc 3/9] xend: pass-through: Allow multi-function device specifications to be parsed
From: Simon Horman <horms@xxxxxxxxxxxx>
Date: Wed, 17 Jun 2009 18:08:45 +1000
Cc: Keir Fraser <keir.fraser@xxxxxxxxxxxxx>, Akio Takebe <takebe_akio@xxxxxxxxxxxxxx>, Masaki Kanno <kanno.masaki@xxxxxxxxxxxxxx>, Dexuan Cui <dexuan.cui@xxxxxxxxx>
Delivery-date: Wed, 17 Jun 2009 01:16:01 -0700
Envelope-to: www-data@xxxxxxxxxxxxxxxxxxx
List-help: <mailto:xen-devel-request@lists.xensource.com?subject=help>
List-id: Xen developer discussion <xen-devel.lists.xensource.com>
List-post: <mailto:xen-devel@lists.xensource.com>
List-subscribe: <http://lists.xensource.com/mailman/listinfo/xen-devel>, <mailto:xen-devel-request@lists.xensource.com?subject=subscribe>
List-unsubscribe: <http://lists.xensource.com/mailman/listinfo/xen-devel>, <mailto:xen-devel-request@lists.xensource.com?subject=unsubscribe>
References: <20090617080842.095632501@xxxxxxxxxxxx>
Sender: xen-devel-bounces@xxxxxxxxxxxxxxxxxxx
User-agent: quilt/0.46-1
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