[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-changelog] [xen-unstable] xend: pass-through: Extend multi-function mapping
# 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
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |