xm: vt-d: Add a command "xm pci-list-assignable-devices" to list all
authorKeir Fraser <keir.fraser@citrix.com>
Mon, 14 Jul 2008 09:12:07 +0000 (10:12 +0100)
committerKeir Fraser <keir.fraser@citrix.com>
Mon, 14 Jul 2008 09:12:07 +0000 (10:12 +0100)
the assignable devices.

Signed-off-by: Dexuan Cui <dexuan.cui@intel.com>
tools/python/xen/util/pci.py
tools/python/xen/xm/main.py

index e862341d88055db97b1fb518720486dcb0d3afee..42a0f81d8aaf13c1a5086c92f73bbb2d39aa9ba9 100644 (file)
@@ -27,6 +27,7 @@ SYSFS_PCI_DEV_DEVICE_PATH = '/device'
 SYSFS_PCI_DEV_SUBVENDOR_PATH = '/subsystem_vendor'
 SYSFS_PCI_DEV_SUBDEVICE_PATH = '/subsystem_device'
 SYSFS_PCI_DEV_CLASS_PATH = '/class'
+SYSFS_PCIBACK_PATH = '/bus/pci/drivers/pciback/'
 
 LSPCI_CMD = 'lspci'
 
@@ -210,6 +211,109 @@ def restore_pci_conf_space(pci_cfg_list):
             os.write(fd, dw)
         os.close(fd) 
 
+def find_all_devices_owned_by_pciback():
+    sysfs_mnt = find_sysfs_mnt()
+    pciback_path = sysfs_mnt + SYSFS_PCIBACK_PATH
+    pci_names = os.popen('ls ' + pciback_path).read()
+    pci_list = re.findall(PCI_DEV_REG_EXPRESS_STR, pci_names)
+    dev_list = []
+    for pci in pci_list:
+        (dom, b, d, f) = parse_pci_name(pci)
+        dev = PciDevice(dom, b, d, f)
+        dev_list = dev_list + [dev]
+    return dev_list
+
+def transform_list(target, src):
+    ''' src: its element is pci string (Format: xxxx:xx:xx:x).
+        target: its element is pci string, or a list of pci string.
+
+        If all the elements in src are in target, we remove them from target
+        and add src into target; otherwise, we remove from target all the
+        elements that also appear in src.
+    '''
+    result = []
+    target_contains_src = True
+    for e in src:
+        if not e in target:
+            target_contains_src = False
+            break
+
+    if target_contains_src:
+        result = result + [src]
+    for e in target:
+        if not e in src:
+             result = result + [e]
+    return  result
+
+def check_FLR_capability(dev_list):
+    i = len(dev_list)
+    if i == 0:
+        return []
+    i = i - 1;
+    while i >= 0:
+        dev = dev_list[i]
+        if dev.bus == 0:
+            if dev.dev_type == DEV_TYPE_PCIe_ENDPOINT and not dev.pcie_flr:
+                del dev_list[i]
+            elif dev.dev_type == DEV_TYPE_PCI and not dev.pci_af_flr:
+                del dev_list[i]
+        i = i - 1
+
+    pci_list = []
+    pci_dev_dict = {}
+    for dev in dev_list:
+        pci_list = pci_list + [dev.name]
+        pci_dev_dict[dev.name] = dev
+
+    while True:
+        need_transform = False
+        for pci in pci_list:
+            if isinstance(pci, types.StringTypes):
+                dev = pci_dev_dict[pci]
+                if dev.dev_type == DEV_TYPE_PCIe_ENDPOINT and not dev.pcie_flr:
+                    coassigned_pci_list = dev.find_all_the_multi_functions()
+                    need_transform = True
+                elif dev.dev_type == DEV_TYPE_PCI and not dev.pci_af_flr:
+                    coassigned_pci_list = dev.find_coassigned_devices(True)
+                    del coassigned_pci_list[0]
+                    need_transform = True
+
+                if need_transform:
+                    pci_list = transform_list(pci_list, coassigned_pci_list)
+        if not need_transform:
+            break
+
+    if len(pci_list) == 0:
+        return []
+
+    for i in range(0, len(pci_list)):
+        if isinstance(pci_list[i], types.StringTypes):
+            pci_list[i] = [pci_list[i]]
+    
+    # Now every element in pci_list is a list of pci string.
+
+    result = []
+    for pci_names in pci_list:
+        devs = []
+        for pci in pci_names:
+            devs = devs + [pci_dev_dict[pci]]
+        result = result + [devs]
+    return result
+
+def check_mmio_bar(devs_list):
+    result = []
+
+    for dev_list in devs_list:
+        non_aligned_bar_found = False
+        for dev in dev_list:
+            if dev.has_non_page_aligned_bar:
+                non_aligned_bar_found = True
+                break
+        if not non_aligned_bar_found:
+            result = result + [dev_list]
+
+    return result
+
 class PciDeviceNotFoundError(Exception):
     def __init__(self,domain,bus,slot,func):
         self.domain = domain
index fb432b140ee5bef8ed9fbc9b8fc21868729a28bb..b7383d21901c49908e31968fc1790b14e9663f69 100644 (file)
@@ -38,6 +38,7 @@ from select import select
 import xml.dom.minidom
 from xen.util.blkif import blkdev_name_to_number
 from xen.util import vscsi_util
+from xen.util.pci import *
 
 import warnings
 warnings.filterwarnings('ignore', category=FutureWarning)
@@ -56,6 +57,9 @@ from xen.util.acmpolicy import ACM_LABEL_UNLABELED_DISPLAY
 
 import XenAPI
 
+import xen.lowlevel.xc
+xc = xen.lowlevel.xc.xc()
+
 import inspect
 from xen.xend import XendOptions
 xoptions = XendOptions.instance()
@@ -183,6 +187,7 @@ SUBCOMMAND_HELP = {
                         'Remove a domain\'s pass-through pci device.'),
     'pci-list'      :  ('<Domain>',
                         'List pass-through pci devices for a domain.'),
+    'pci-list-assignable-devices' : ('', 'List all the assignable pci devices'),
     'scsi-attach'  :  ('<Domain> <PhysDevice> <VirtDevice> [BackDomain]',
                         'Attach a new SCSI device.'),
     'scsi-detach'  :  ('<Domain> <VirtDevice>',
@@ -355,6 +360,7 @@ device_commands = [
     "pci-attach",
     "pci-detach",
     "pci-list",
+    "pci-list-assignable-devices",
     "scsi-attach",
     "scsi-detach",
     "scsi-list",
@@ -2116,6 +2122,35 @@ def xm_pci_list(args):
             hdr = 1
         print ( fmt_str % x )
 
+def xm_pci_list_assignable_devices(args):
+    # Each element of dev_list is a PciDevice
+    dev_list = find_all_devices_owned_by_pciback()
+
+    # Each element of devs_list is a list of PciDevice
+    devs_list = check_FLR_capability(dev_list)
+
+    devs_list = check_mmio_bar(devs_list)
+
+    # Check if the devices have been assigned to guests.
+    final_devs_list = []
+    for dev_list in devs_list:
+        available = True
+        for d in dev_list:
+            pci_str = '0x%x,0x%x,0x%x,0x%x' %(d.domain, d.bus, d.slot, d.func)
+            # Xen doesn't care what the domid is, so we pass 0 here...
+            domid = 0
+            bdf = xc.test_assign_device(domid, pci_str)
+            if bdf != 0:
+                available = False
+                break
+        if available:
+            final_devs_list = final_devs_list + [dev_list]
+
+    for dev_list in final_devs_list:
+        for d in dev_list:
+            print d.name,
+        print
+
 def vscsi_convert_sxp_to_dict(dev_sxp):
     dev_dict = {}
     for opt_val in dev_sxp[1:]:
@@ -2645,6 +2680,7 @@ commands = {
     "pci-attach": xm_pci_attach,
     "pci-detach": xm_pci_detach,
     "pci-list": xm_pci_list,
+    "pci-list-assignable-devices": xm_pci_list_assignable_devices,
     # vscsi
     "scsi-attach": xm_scsi_attach,
     "scsi-detach": xm_scsi_detach,