diff options
author | Keir Fraser <keir.fraser@citrix.com> | 2009-06-27 09:53:56 +0100 |
---|---|---|
committer | Keir Fraser <keir.fraser@citrix.com> | 2009-06-27 09:53:56 +0100 |
commit | 2327a50d23f9dddcd8360deee5dd43ec74ec10ac (patch) | |
tree | c55c863eaf07b3983bf4d1d28487b76e7a5590fd /tools | |
parent | 83d82e6f35a8e2b67c097eca847e013196cb26eb (diff) | |
download | xen-2327a50d23f9dddcd8360deee5dd43ec74ec10ac.tar.gz xen-2327a50d23f9dddcd8360deee5dd43ec74ec10ac.tar.bz2 xen-2327a50d23f9dddcd8360deee5dd43ec74ec10ac.zip |
xend: pass-through: Allow multi-function device specifications to be parsed
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@intel.com>
Cc: Masaki Kanno <kanno.masaki@jp.fujitsu.com>
Cc: Akio Takebe <takebe_akio@jp.fujitsu.com>
Signed-off-by: Simon Horman <horms@verge.net.au>
Diffstat (limited to 'tools')
-rw-r--r-- | tools/python/xen/util/pci.py | 105 | ||||
-rw-r--r-- | tools/python/xen/xend/XendConfig.py | 5 | ||||
-rw-r--r-- | tools/python/xen/xend/XendConstants.py | 3 | ||||
-rw-r--r-- | tools/python/xen/xend/XendDomainInfo.py | 2 | ||||
-rw-r--r-- | tools/python/xen/xend/server/pciif.py | 3 | ||||
-rw-r--r-- | tools/python/xen/xm/create.py | 4 | ||||
-rw-r--r-- | tools/python/xen/xm/main.py | 4 |
7 files changed, 94 insertions, 32 deletions
diff --git a/tools/python/xen/util/pci.py b/tools/python/xen/util/pci.py index dc8dc64a7a..b612489092 100644 --- a/tools/python/xen/util/pci.py +++ b/tools/python/xen/util/pci.py @@ -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']) + + # 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) - return out + # 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. diff --git a/tools/python/xen/xend/XendConfig.py b/tools/python/xen/xend/XendConfig.py index 8842a902ad..6e5f7f0693 100644 --- a/tools/python/xen/xend/XendConfig.py +++ b/tools/python/xen/xend/XendConfig.py @@ -32,7 +32,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 @@ -1249,8 +1249,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') diff --git a/tools/python/xen/xend/XendConstants.py b/tools/python/xen/xend/XendConstants.py index 588470ab69..7082bd8c2e 100644 --- a/tools/python/xen/xend/XendConstants.py +++ b/tools/python/xen/xend/XendConstants.py @@ -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 diff --git a/tools/python/xen/xend/XendDomainInfo.py b/tools/python/xen/xend/XendDomainInfo.py index ee38023c1a..6a31503f17 100644 --- a/tools/python/xen/xend/XendDomainInfo.py +++ b/tools/python/xen/xend/XendDomainInfo.py @@ -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)): diff --git a/tools/python/xen/xend/server/pciif.py b/tools/python/xen/xend/server/pciif.py index 1b3a2cf29c..eed25470a1 100644 --- a/tools/python/xen/xend/server/pciif.py +++ b/tools/python/xen/xend/server/pciif.py @@ -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']) diff --git a/tools/python/xen/xm/create.py b/tools/python/xen/xm/create.py index 9a0ae3e306..a9b6326fe6 100644 --- a/tools/python/xen/xm/create.py +++ b/tools/python/xen/xm/create.py @@ -1090,8 +1090,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)) diff --git a/tools/python/xen/xm/main.py b/tools/python/xen/xm/main.py index 9688ba3d97..195221e40c 100644 --- a/tools/python/xen/xm/main.py +++ b/tools/python/xen/xm/main.py @@ -2214,7 +2214,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: @@ -2497,7 +2497,7 @@ def parse_pci_configuration(args, state, opts = ''): 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)) |