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] xend: pass-through: Extend multi-function mapping

To: xen-devel@xxxxxxxxxxxxxxxxxxx
Subject: [Xen-devel] [rfc] xend: pass-through: Extend multi-function mapping
From: Simon Horman <horms@xxxxxxxxxxxx>
Date: Mon, 3 Aug 2009 19:00:44 +1000
Cc: Dexuan Cui <dexuan.cui@xxxxxxxxx>
Delivery-date: Mon, 03 Aug 2009 02:01:15 -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>
Sender: xen-devel-bounces@xxxxxxxxxxxxxxxxxxx
User-agent: Mutt/1.5.18 (2008-05-17)
This extends the mapping between physical and virtual PCI functions
for multi-function pass-through in two ways. If neither of these
rules apply the existing identity-mapping of physical to virtual
functions is used.

1) If physical function zero is not present in a multi-function
   pass-through device then the numerically lowest physical function
   whose virtual function hasn't explicitly been set will be mapped
   to virtual function 0.

   This is to satisfy the requirement that a (virtual) device
   must always have function 0 present.

2) The virtual function to be used for a physical function may
   be explicitly set.

   e.g. 00:1d.2=0,1=1,0=2@7 will result in the following mapping:

        physical | virtual
        ---------+--------
        00:1d.2  | 00:07.0
        00:1d.1  | 00:07.1
        00:1d.0  | 00:07.2

   Ranges may also be used with explicit assignment.
   The following would result in the same mapping as above:

       00:1d.2=0-0=2@7

Please be aware that it is very likely that using these extensions
it is possible to create mappings that do not work. If in doubt
please use identity-mapping.

Cc: Dexuan Cui <dexuan.cui@xxxxxxxxx>
Signed-off-by: Simon Horman <horms@xxxxxxxxxxxx>

Index: xen-unstable.hg/tools/python/xen/util/pci.py
===================================================================
--- xen-unstable.hg.orig/tools/python/xen/util/pci.py   2009-08-03 
18:21:54.000000000 +1000
+++ xen-unstable.hg/tools/python/xen/util/pci.py        2009-08-03 
18:48:12.000000000 +1000
@@ -240,22 +240,52 @@ def parse_hex(val):
     except ValueError:
         return None
 
+AUTO_PHP_FUNC = 1
+MANUAL_PHP_FUNC = 2
+
+def parse_pci_pfunc_vfunc(func_str):
+    list = func_str.split('=')
+    l = len(list)
+    if l == 0 or l > 2:
+         raise PciDeviceParseError('Invalid function: ' + func_str)
+    p = int(list[0], 16)
+    if p < 0 or p > 7:
+        raise PciDeviceParseError('Invalid physical function in: ' + func_str)
+    if l == 1:
+       # This defaults to linear mapping of physical to virtual functions
+        return (p, p, AUTO_PHP_FUNC)
+    else:
+       v = int(list[1], 16)
+        if v < 0 or v > 7:
+            raise PciDeviceParseError('Invalid virtual function in: ' +
+                                     func_str)
+        return (p, v, MANUAL_PHP_FUNC)
+
+def pci_func_range(start, end):
+    if end < start:
+        x = pci_func_range(end, start)
+       x.reverse()
+       return x
+    return range(start, end + 1)
+
+def pci_pfunc_vfunc_range(orig, a, b):
+    phys = pci_func_range(a[0], b[0])
+    virt = pci_func_range(a[1], b[1])
+    if len(phys) != len(virt):
+        raise PciDeviceParseError('Invalid range in: ' + orig)
+    return map(lambda x: x + (MANUAL_PHP_FUNC,), zip(phys, virt))
+
 def pci_func_list_map_fn(key, func_str):
     if func_str == "*":
-        return map(lambda x: int(x['func'], 16),
+        return map(lambda x: parse_pci_pfunc_vfunc(x['func']),
                    filter(lambda x:
                           pci_dict_cmp(x, key, ['domain', 'bus', 'slot']),
                           get_all_pci_dict()))
-    l = map(int, func_str.split("-"))
+    l = map(parse_pci_pfunc_vfunc, 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 pci_pfunc_vfunc_range(func_str, l[0], l[1])
     return []
 
 def pci_func_list_process(pci_dev_str, template, func_str):
@@ -263,7 +293,9 @@ def pci_func_list_process(pci_dev_str, t
                (map(lambda x: pci_func_list_map_fn(template, x),
                     func_str.split(","))))
 
-    if len(l) != len(set(l)):
+    phys = map(lambda x: x[0], l)
+    virt = map(lambda x: x[1], l)
+    if len(phys) != len(set(phys)) or len(virt) != len(set(virt)):
         raise PciDeviceParseError("Duplicate functions: %s" % pci_dev_str)
 
     return l
@@ -272,7 +304,7 @@ 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]([,-][0-7])*))" +
+                         r"(?P<func>(\*|[0-7]([,-=][0-7])*))" +
                          r"(@(?P<vdevfn>[01]?[0-9a-fA-F]))?" +
                          r"(,(?P<opts>.*))?$", pci_dev_str)
 
@@ -296,22 +328,35 @@ def parse_pci_name_extended(pci_dev_str)
         check_pci_opts(template['opts'])
 
     # This is where virtual function assignment takes place
+    func_list = pci_func_list_process(pci_dev_str, template,
+                                      pci_dev_info['func'])
+    if len(func_list) == 0:
+        return []
+
+    # Set the virtual function of the numerically lowest physical function
+    # to zero if it has not been manually set
+    if not filter(lambda x: x[1] == 0, func_list):
+        auto   = filter(lambda x: x[2] == AUTO_PHP_FUNC, func_list)
+        manual = filter(lambda x: x[2] == MANUAL_PHP_FUNC, func_list)
+       if not auto:
+            raise PciDeviceParseError('Virtual device does not include '
+                                     'virtual function 0: ' + pci_dev_str)
+       auto.sort(lambda x,y: cmp(x[1], y[1]))
+       auto[0] = (auto[0][0], 0, AUTO_PHP_FUNC)
+       func_list = auto + manual
+
+    # 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
+    func_list.sort(lambda x,y: cmp(PCI_FUNC(y[1]), PCI_FUNC(x[1])))
+
     # 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:
+    for (pfunc, vfunc, auto) in func_list:
         pci_dev = template.copy()
-        pci_dev['func'] = "0x%x" % func
+        pci_dev['func'] = "0x%x" % pfunc
 
-        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['vdevfn'] == '':
             vdevfn = AUTO_PHP_SLOT | vfunc
         else:
@@ -320,14 +365,6 @@ def parse_pci_name_extended(pci_dev_str)
 
         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(lambda x,y: cmp(int(y['vdevfn'], 16), int(x['vdevfn'], 16)))
     return pci
 
 def parse_pci_name(pci_name_string):

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

<Prev in Thread] Current Thread [Next in Thread>
  • [Xen-devel] [rfc] xend: pass-through: Extend multi-function mapping, Simon Horman <=