aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorKeir Fraser <keir.fraser@citrix.com>2009-06-27 09:53:56 +0100
committerKeir Fraser <keir.fraser@citrix.com>2009-06-27 09:53:56 +0100
commit2327a50d23f9dddcd8360deee5dd43ec74ec10ac (patch)
treec55c863eaf07b3983bf4d1d28487b76e7a5590fd /tools
parent83d82e6f35a8e2b67c097eca847e013196cb26eb (diff)
downloadxen-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.py105
-rw-r--r--tools/python/xen/xend/XendConfig.py5
-rw-r--r--tools/python/xen/xend/XendConstants.py3
-rw-r--r--tools/python/xen/xend/XendDomainInfo.py2
-rw-r--r--tools/python/xen/xend/server/pciif.py3
-rw-r--r--tools/python/xen/xm/create.py4
-rw-r--r--tools/python/xen/xm/main.py4
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))