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-changelog

[Xen-changelog] [xen-unstable] xend: pass-through: Extend multi-function

To: xen-changelog@xxxxxxxxxxxxxxxxxxx
Subject: [Xen-changelog] [xen-unstable] xend: pass-through: Extend multi-function mapping
From: Xen patchbot-unstable <patchbot-unstable@xxxxxxxxxxxxxxxxxxx>
Date: Thu, 06 Aug 2009 05:35:10 -0700
Delivery-date: Thu, 06 Aug 2009 05:35:21 -0700
Envelope-to: www-data@xxxxxxxxxxxxxxxxxxx
List-help: <mailto:xen-changelog-request@lists.xensource.com?subject=help>
List-id: BK change log <xen-changelog.lists.xensource.com>
List-post: <mailto:xen-changelog@lists.xensource.com>
List-subscribe: <http://lists.xensource.com/mailman/listinfo/xen-changelog>, <mailto:xen-changelog-request@lists.xensource.com?subject=subscribe>
List-unsubscribe: <http://lists.xensource.com/mailman/listinfo/xen-changelog>, <mailto:xen-changelog-request@lists.xensource.com?subject=unsubscribe>
Reply-to: xen-devel@xxxxxxxxxxxxxxxxxxx
Sender: xen-changelog-bounces@xxxxxxxxxxxxxxxxxxx
# HG changeset patch
# User Keir Fraser <keir.fraser@xxxxxxxxxx>
# Date 1249470233 -3600
# Node ID 3242351f9c6766fe4fbc27d969b1b84a9926cbda
# Parent  30de3f3dbd4b4597063af48a08bcb3db2bed5667
xend: pass-through: Extend multi-function mapping

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=3D0,1=3D1,0=3D2@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=3D0-0=3D2@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>
---
 tools/python/xen/util/pci.py |   97 +++++++++++++++++++++++++++++--------------
 1 files changed, 67 insertions(+), 30 deletions(-)

diff -r 30de3f3dbd4b -r 3242351f9c67 tools/python/xen/util/pci.py
--- a/tools/python/xen/util/pci.py      Wed Aug 05 12:03:08 2009 +0100
+++ b/tools/python/xen/util/pci.py      Wed Aug 05 12:03:53 2009 +0100
@@ -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
-
-        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
+        pci_dev['func'] = "0x%x" % pfunc
+
         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-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog

<Prev in Thread] Current Thread [Next in Thread>
  • [Xen-changelog] [xen-unstable] xend: pass-through: Extend multi-function mapping, Xen patchbot-unstable <=