# HG changeset patch
# User Keir Fraser <keir.fraser@xxxxxxxxxx>
# Date 1246092975 -3600
# Node ID f5f5905e6e1c79ccc156fdc36c77a85cb11030c1
# Parent 7bbc4433f2ef5f79861821c0b40542694f5452e7
xend: pass-through: Parse command line for multi-function hot-plug and unplug
Hook things up to allow multi-function pass-through.
This includes making sure that request is valid.
In the case of pci-detach:
* All the functions requested must be attached to the same virtual
slot * and;
* A request must include the functions attached to a virtual slot
Cc: Dexuan Cui <dexuan.cui@xxxxxxxxx>
Cc: Masaki Kanno <kanno.masaki@xxxxxxxxxxxxxx>
Signed-off-by: Simon Horman <horms@xxxxxxxxxxxx>
---
tools/python/xen/xend/XendDomainInfo.py | 54 ++++++++++++--
tools/python/xen/xm/main.py | 122 +++++++++++++++++++++++---------
2 files changed, 136 insertions(+), 40 deletions(-)
diff -r 7bbc4433f2ef -r f5f5905e6e1c tools/python/xen/xend/XendDomainInfo.py
--- a/tools/python/xen/xend/XendDomainInfo.py Sat Jun 27 09:55:42 2009 +0100
+++ b/tools/python/xen/xend/XendDomainInfo.py Sat Jun 27 09:56:15 2009 +0100
@@ -42,7 +42,7 @@ from xen.util.pci import serialise_pci_o
from xen.util.pci import serialise_pci_opts, pci_opts_list_to_sxp, \
pci_dict_to_bdf_str, pci_dict_to_xc_str, \
pci_convert_sxp_to_dict, pci_convert_dict_to_sxp, \
- pci_dict_cmp, PCI_FUNC
+ pci_dict_cmp, PCI_DEVFN, PCI_SLOT, PCI_FUNC
from xen.xend import balloon, sxp, uuid, image, arch
from xen.xend import XendOptions, XendNode, XendConfig
@@ -617,12 +617,52 @@ class XendDomainInfo:
dev_uuid = sxp.child_value(dev_info, 'uuid')
pci_conf = self.info['devices'][dev_uuid][1]
pci_devs = pci_conf['devs']
- request = map(lambda x:
- pci_convert_dict_to_sxp(x, 'Initialising', 'Booting'),
- pci_devs)
-
- for i in request:
- self.pci_device_configure(i)
+
+ # Keep a set of keys that are done rather than
+ # just itterating through set(map(..., pci_devs))
+ # to preserve any order information present.
+ done = set()
+ for key in map(lambda x: x['key'], pci_devs):
+ if key in done:
+ continue
+ done |= set([key])
+ dev = filter(lambda x: x['key'] == key, pci_devs)
+
+ head_dev = dev.pop()
+ dev_sxp = pci_convert_dict_to_sxp(head_dev, 'Initialising',
+ 'Booting')
+ self.pci_device_configure(dev_sxp)
+
+ # That is all for single-function virtual devices
+ if len(dev) == 0:
+ continue
+
+ if int(head_dev['vslot'], 16) & AUTO_PHP_SLOT:
+ new_dev_info = self._getDeviceInfo_pci(devid)
+ if new_dev_info is None:
+ continue
+ new_dev_uuid = sxp.child_value(new_dev_info, 'uuid')
+ new_pci_conf = self.info['devices'][new_dev_uuid][1]
+ new_pci_devs = new_pci_conf['devs']
+
+ new_head_dev = filter(lambda x: pci_dict_cmp(x, head_dev),
+ new_pci_devs)[0]
+
+ if int(new_head_dev['vslot'], 16) & AUTO_PHP_SLOT:
+ continue
+
+ vslot = PCI_SLOT(int(new_head_dev['vslot'], 16))
+ new_dev = []
+ for i in dev:
+ i['vslot'] = '0x%02x' % \
+ PCI_DEVFN(vslot, PCI_FUNC(int(i['vslot'],
16)))
+ new_dev.append(i)
+
+ dev = new_dev
+
+ for i in dev:
+ dev_sxp = pci_convert_dict_to_sxp(i, 'Initialising', 'Booting')
+ self.pci_device_configure(dev_sxp)
def hvm_pci_device_create(self, dev_config):
log.debug("XendDomainInfo.hvm_pci_device_create: %s"
diff -r 7bbc4433f2ef -r f5f5905e6e1c tools/python/xen/xm/main.py
--- a/tools/python/xen/xm/main.py Sat Jun 27 09:55:42 2009 +0100
+++ b/tools/python/xen/xm/main.py Sat Jun 27 09:56:15 2009 +0100
@@ -2226,8 +2226,9 @@ def xm_pci_list(args):
if len(devs) == 0:
return
- devs.sort(None, lambda x: x['vslot'] << 32 | PCI_BDF(x['domain'], x['bus'],
- x['slot'], x['func']))
+ devs.sort(None,
+ lambda x: (x['vslot'] - PCI_FUNC(x['vslot'])) << 32 |
+ PCI_BDF(x['domain'], x['bus'], x['slot'], x['func']))
has_vslot = False
for x in devs:
@@ -2505,7 +2506,7 @@ def xm_network_attach(args):
vif.append(vif_param)
server.xend.domain.device_create(dom, vif)
-def parse_pci_configuration(args, state, opts = ''):
+def parse_pci_configuration(args, opts = ''):
dom = args[0]
pci_dev_str = args[1]
if len(args) == 3:
@@ -2514,11 +2515,11 @@ def parse_pci_configuration(args, state,
pci_dev_str += ',' + serialise_pci_opts(opts)
try:
- pci_dev = parse_pci_name_extended(pci_dev_str)[0]
+ pci_dev = parse_pci_name_extended(pci_dev_str)
except PciDeviceParseError, ex:
raise OptionError(str(ex))
- return (dom, pci_convert_dict_to_sxp(pci_dev, state))
+ return (dom, pci_dev)
def xm_pci_attach(args):
config_pci_opts = []
@@ -2535,19 +2536,31 @@ def xm_pci_attach(args):
err("Invalid argument for 'xm pci-attach'")
usage('pci-attach')
- (dom, pci) = parse_pci_configuration(params, 'Initialising',
- config_pci_opts)
-
- if serverType == SERVER_XEN_API:
- pci_dev = sxp.children(pci, 'dev')[0]
- domain = int(sxp.child_value(pci_dev, 'domain'), 16)
- bus = int(sxp.child_value(pci_dev, 'bus'), 16)
- slot = int(sxp.child_value(pci_dev, 'slot'), 16)
- func = int(sxp.child_value(pci_dev, 'func'), 16)
- vslot = int(sxp.child_value(pci_dev, 'vslot'), 16)
- key = sxp.child_value(pci_dev, 'key')
- name = "%04x:%02x:%02x.%01x" % (domain, bus, slot, func)
-
+ (dom, dev) = parse_pci_configuration(params, config_pci_opts)
+
+ head_dev = dev.pop(0)
+ xm_pci_attach_one(dom, head_dev)
+
+ # That is all for single-function virtual devices
+ if len(dev) == 0:
+ return
+
+ # If the slot wasn't spefified in the args then use the slot
+ # assigned to the head by qemu-xen for the rest of the functions
+ if int(head_dev['vslot'], 16) & AUTO_PHP_SLOT:
+ vdevfn = int(find_attached_devfn(attached_pci_dict(dom), head_dev), 16)
+ if not vdevfn & AUTO_PHP_SLOT:
+ vslot = PCI_SLOT(vdevfn)
+ for i in dev:
+ i['vslot'] = '0x%02x' % \
+ PCI_DEVFN(vslot, PCI_FUNC(int(i['vslot'], 16)))
+
+ for i in dev:
+ xm_pci_attach_one(dom, i)
+
+def xm_pci_attach_one(dom, pci_dev):
+ if serverType == SERVER_XEN_API:
+ name = pci_dict_to_bdf_str(pci_dev)
target_ref = None
for ppci_ref in server.xenapi.PPCI.get_all():
if name == server.xenapi.PPCI.get_name(ppci_ref):
@@ -2559,13 +2572,14 @@ def xm_pci_attach(args):
dpci_record = {
"VM": get_single_vm(dom),
"PPCI": target_ref,
- "hotplug_slot": vslot,
- "options": dict(config_pci_opts),
- "key": key
+ "hotplug_slot": int(pci_dev['vslot'], 16),
+ "options": dict(pci_dev.get('opts', [])),
+ "key": pci_dev['key']
}
server.xenapi.DPCI.create(dpci_record)
else:
+ pci = pci_convert_dict_to_sxp(pci_dev, 'Initialising')
server.xend.domain.device_configure(dom, pci)
def parse_scsi_configuration(p_scsi, v_hctl, state):
@@ -2708,20 +2722,61 @@ def xm_network_detach(args):
arg_check(args, 'network-detach', 2, 3)
detach(args, 'vif')
+def find_attached(attached, key):
+ l = filter(lambda dev: pci_dict_cmp(dev, key), attached)
+
+ if len(l) == 0:
+ raise OptionError("pci: device is not attached: " +
+ pci_dict_to_bdf_str(key))
+
+ # There shouldn't ever be more than one match,
+ # but perhaps an exception should be thrown if there is
+ return l[0]
+
+def find_attached_devfn(attached, key):
+ pci_dev = find_attached(attached, key)
+ return pci_dev['vslot']
+
def xm_pci_detach(args):
arg_check(args, 'pci-detach', 2)
- (dom, pci) = parse_pci_configuration(args, 'Closing')
-
- if serverType == SERVER_XEN_API:
-
- pci_dev = sxp.children(pci, 'dev')[0]
- domain = int(sxp.child_value(pci_dev, 'domain'), 16)
- bus = int(sxp.child_value(pci_dev, 'bus'), 16)
- slot = int(sxp.child_value(pci_dev, 'slot'), 16)
- func = int(sxp.child_value(pci_dev, 'func'), 16)
- vslot = int(sxp.child_value(pci_dev, 'vslot'), 16)
- name = "%04x:%02x:%02x.%01x" % (domain, bus, slot, func)
-
+
+ (dom, dev) = parse_pci_configuration(args)
+ attached = attached_pci_dict(dom)
+
+ attached_dev = map(lambda x: find_attached(attached, x), dev)
+
+ def f(pci_dev):
+ vdevfn = int(pci_dev['vslot'], 16)
+ return PCI_SLOT(vdevfn) | (vdevfn & AUTO_PHP_SLOT)
+ vslots = map(f, attached_dev)
+ if len(set(vslots)) > 1:
+ err_str = map(lambda x: "\t%s is in slot 0x%02x\n" %
+ (pci_dict_to_bdf_str(x),
+ PCI_SLOT(int(x['vslot'], 16))), dev)
+ raise OptionError("More than one slot used by specified devices\n"
+ + ''.join(err_str))
+
+ attached_to_slot = filter(lambda x:
+ f(x) == vslots[0] and
+ attached_dev[0]["key"] ==
+ x["key"], attached_dev)
+
+ if len(attached_to_slot) != len(dev):
+ err_str_ = map(lambda x: '\t%s\n' % pci_dict_to_bdf_str(x), dev)
+ err_str = "Requested:\n" + ''.join(err_str_)
+ err_str_ = map(lambda x: '\t%s (%s)\n' %
+ (pci_dict_to_bdf_str(x), x['key']),
+ attached_to_slot)
+ err_str += "Present:\n" + ''.join(err_str_)
+ raise OptionError(("Not all functions in slot 0x%02x have had "
+ "detachment requested.\n" % vslots[0]) + err_str)
+
+ for i in dev:
+ xm_pci_detach_one(dom, i)
+
+def xm_pci_detach_one(dom, pci_dev):
+ if serverType == SERVER_XEN_API:
+ name = pci_dict_to_bdf_str(pci_dev)
target_ref = None
for dpci_ref in server.xenapi.VM.get_DPCIs(get_single_vm(dom)):
ppci_ref = server.xenapi.DPCI.get_PPCI(dpci_ref)
@@ -2733,6 +2788,7 @@ def xm_pci_detach(args):
raise OptionError("Device %s not assigned" % name)
else:
+ pci = pci_convert_dict_to_sxp(pci_dev, 'Closing')
server.xend.domain.device_configure(dom, pci)
def xm_scsi_detach(args):
_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog
|