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
|