ia64/xen-unstable

changeset 18175:13690b68fd46

xend, pci passthru: Use Dstate transition to do FLR for integrated
devices without proper FLR capability.

Currently integrated devices without proper FLR capability are not
assignable. This is not nice since actually they may be assignable,
but due to old BIOS the proper FLR capability is not exposed. We can
use the previously-used Dstate transition method to do FLR for them.
This works well and looks few issues are reported AFAIK. Maybe we can
make a black list for the (rare) integrated devices that don't work
with this method.

Signed-off-by: Dexuan Cui <dexuan.cui@intel.com>
author Keir Fraser <keir.fraser@citrix.com>
date Mon Jul 28 11:29:23 2008 +0100 (2008-07-28)
parents c6502ade05f9
children b47e503f3282
files tools/python/xen/util/pci.py tools/python/xen/xend/server/pciif.py
line diff
     1.1 --- a/tools/python/xen/util/pci.py	Mon Jul 28 11:28:45 2008 +0100
     1.2 +++ b/tools/python/xen/util/pci.py	Mon Jul 28 11:29:23 2008 +0100
     1.3 @@ -57,6 +57,12 @@ PCI_EXP_DEVCAP_FLR = (0x1 << 28)
     1.4  PCI_EXP_DEVCTL = 0x8
     1.5  PCI_EXP_DEVCTL_FLR = (0x1 << 15)
     1.6  
     1.7 +PCI_CAP_ID_PM = 0x01
     1.8 +PCI_PM_CTRL = 4
     1.9 +PCI_PM_CTRL_NO_SOFT_RESET = 0x0004
    1.10 +PCI_PM_CTRL_STATE_MASK = 0x0003
    1.11 +PCI_D3hot = 3
    1.12 +
    1.13  PCI_CAP_ID_AF = 0x13
    1.14  PCI_AF_CAPs   = 0x3
    1.15  PCI_AF_CAPs_TP_FLR = 0x3
    1.16 @@ -246,18 +252,8 @@ def transform_list(target, src):
    1.17      return  result
    1.18  
    1.19  def check_FLR_capability(dev_list):
    1.20 -    i = len(dev_list)
    1.21 -    if i == 0:
    1.22 +    if len(dev_list) == 0:
    1.23          return []
    1.24 -    i = i - 1;
    1.25 -    while i >= 0:
    1.26 -        dev = dev_list[i]
    1.27 -        if dev.bus == 0:
    1.28 -            if dev.dev_type == DEV_TYPE_PCIe_ENDPOINT and not dev.pcie_flr:
    1.29 -                del dev_list[i]
    1.30 -            elif dev.dev_type == DEV_TYPE_PCI and not dev.pci_af_flr:
    1.31 -                del dev_list[i]
    1.32 -        i = i - 1
    1.33  
    1.34      pci_list = []
    1.35      pci_dev_dict = {}
    1.36 @@ -270,6 +266,8 @@ def check_FLR_capability(dev_list):
    1.37          for pci in pci_list:
    1.38              if isinstance(pci, types.StringTypes):
    1.39                  dev = pci_dev_dict[pci]
    1.40 +                if dev.bus == 0:
    1.41 +                    continue
    1.42                  if dev.dev_type == DEV_TYPE_PCIe_ENDPOINT and not dev.pcie_flr:
    1.43                      coassigned_pci_list = dev.find_all_the_multi_functions()
    1.44                      need_transform = True
    1.45 @@ -338,13 +336,6 @@ class PciDeviceAssignmentError(Exception
    1.46          return 'pci: impproper device assignment spcified: ' + \
    1.47              self.message
    1.48  
    1.49 -class PciDeviceFlrError(PciDeviceAssignmentError):
    1.50 -    def __init__(self,msg):
    1.51 -        self.message = msg
    1.52 -    def __str__(self):
    1.53 -        return 'Can not find a suitable FLR method for the device(s): ' + \
    1.54 -            self.message
    1.55 -
    1.56  class PciDevice:
    1.57      def __init__(self, domain, bus, slot, func):
    1.58          self.domain = domain
    1.59 @@ -480,6 +471,27 @@ class PciDevice:
    1.60          # Restore the config spaces
    1.61          restore_pci_conf_space((pci_list, cfg_list))
    1.62          
    1.63 +    def do_Dstate_transition(self):
    1.64 +        pos = self.find_cap_offset(PCI_CAP_ID_PM)
    1.65 +        if pos == 0:
    1.66 +            return 
    1.67 +        
    1.68 +        (pci_list, cfg_list) = save_pci_conf_space([self.name])
    1.69 +        
    1.70 +        # Enter D3hot without soft reset
    1.71 +        pm_ctl = self.pci_conf_read32(pos + PCI_PM_CTRL)
    1.72 +        pm_ctl |= PCI_PM_CTRL_NO_SOFT_RESET
    1.73 +        pm_ctl &= ~PCI_PM_CTRL_STATE_MASK
    1.74 +        pm_ctl |= PCI_D3hot
    1.75 +        self.pci_conf_write32(pos + PCI_PM_CTRL, pm_ctl)
    1.76 +        time.sleep(0.010)
    1.77 +
    1.78 +        # From D3hot to D0
    1.79 +        self.pci_conf_write32(pos + PCI_PM_CTRL, 0)
    1.80 +        time.sleep(0.010)
    1.81 +
    1.82 +        restore_pci_conf_space((pci_list, cfg_list))
    1.83 +
    1.84      def find_all_the_multi_functions(self):
    1.85          sysfs_mnt = find_sysfs_mnt()
    1.86          pci_names = os.popen('ls ' + sysfs_mnt + SYSFS_PCI_DEVS_PATH).read()
    1.87 @@ -650,13 +662,16 @@ class PciDevice:
    1.88                  time.sleep(0.200)
    1.89                  restore_pci_conf_space((pci_list, cfg_list))
    1.90              else:
    1.91 -                funcs = self.find_all_the_multi_functions()
    1.92 -                self.devs_check_driver(funcs)
    1.93 +                if self.bus == 0:
    1.94 +                    self.do_Dstate_transition()
    1.95 +                else:
    1.96 +                    funcs = self.find_all_the_multi_functions()
    1.97 +                    self.devs_check_driver(funcs)
    1.98  
    1.99 -                parent = '%04x:%02x:%02x.%01x' % self.find_parent()
   1.100 +                    parent = '%04x:%02x:%02x.%01x' % self.find_parent()
   1.101  
   1.102 -                # Do Secondary Bus Reset.
   1.103 -                self.do_secondary_bus_reset(parent, funcs)
   1.104 +                    # Do Secondary Bus Reset.
   1.105 +                    self.do_secondary_bus_reset(parent, funcs)
   1.106          # PCI devices
   1.107          else:
   1.108              # For PCI device on host bus, we test "PCI Advanced Capabilities".
   1.109 @@ -669,9 +684,7 @@ class PciDevice:
   1.110                  restore_pci_conf_space((pci_list, cfg_list))
   1.111              else:
   1.112                  if self.bus == 0:
   1.113 -                    err_msg = 'pci: %s is not assignable: it is on bus 0, '+ \
   1.114 -                        'but it has no PCI Advanced Capabilities.'
   1.115 -                    raise PciDeviceFlrError(err_msg % self.name)
   1.116 +                    self.do_Dstate_transition()
   1.117                  else:
   1.118                      devs = self.find_coassigned_devices(False)
   1.119                      # Remove the element 0 which is a bridge
     2.1 --- a/tools/python/xen/xend/server/pciif.py	Mon Jul 28 11:28:45 2008 +0100
     2.2 +++ b/tools/python/xen/xend/server/pciif.py	Mon Jul 28 11:29:23 2008 +0100
     2.3 @@ -375,23 +375,34 @@ class PciController(DevController):
     2.4                  raise VmError("pci: failed to locate device and "+
     2.5                          "parse it's resources - "+str(e))
     2.6              if (dev.dev_type == DEV_TYPE_PCIe_ENDPOINT) and not dev.pcie_flr:
     2.7 -                funcs = dev.find_all_the_multi_functions()
     2.8 -                for f in funcs:
     2.9 -                    if not f in pci_str_list:
    2.10 -                        (f_dom, f_bus, f_slot, f_func) = parse_pci_name(f)
    2.11 -                        f_pci_str = '0x%x,0x%x,0x%x,0x%x' % \
    2.12 -                            (f_dom, f_bus, f_slot, f_func)
    2.13 -                        # f has been assigned to other guest?
    2.14 -                        if xc.test_assign_device(0, f_pci_str) != 0:
    2.15 -                            err_msg = 'pci: %s must be co-assigned to the' + \
    2.16 -                                ' same guest with %s'
    2.17 -                            raise VmError(err_msg % (f, dev.name))
    2.18 +                if dev.bus == 0:
    2.19 +                    # We cope with this case by using the Dstate transition
    2.20 +                    # method for now.
    2.21 +                    err_msg = 'pci: %s: it is on bus 0, but has no PCIe' +\
    2.22 +                        ' FLR Capability. Will try the Dstate transition'+\
    2.23 +                        ' method if available.'
    2.24 +                    log.warn(err_msg % dev.name)
    2.25 +                else:
    2.26 +                    funcs = dev.find_all_the_multi_functions()
    2.27 +                    for f in funcs:
    2.28 +                        if not f in pci_str_list:
    2.29 +                            (f_dom, f_bus, f_slot, f_func) = parse_pci_name(f)
    2.30 +                            f_pci_str = '0x%x,0x%x,0x%x,0x%x' % \
    2.31 +                                (f_dom, f_bus, f_slot, f_func)
    2.32 +                            # f has been assigned to other guest?
    2.33 +                            if xc.test_assign_device(0, f_pci_str) != 0:
    2.34 +                                err_msg = 'pci: %s must be co-assigned to' + \
    2.35 +                                    ' the same guest with %s'
    2.36 +                                raise VmError(err_msg % (f, dev.name))
    2.37              elif dev.dev_type == DEV_TYPE_PCI:
    2.38                  if dev.bus == 0:
    2.39                      if not dev.pci_af_flr:
    2.40 -                        err_msg = 'pci: %s is not assignable: it is on ' + \
    2.41 -                            'bus 0,  but lacks of FLR capability'
    2.42 -                        raise VmError(err_msg % dev.name)
    2.43 +                        # We cope with this case by using the Dstate transition
    2.44 +                        # method for now.
    2.45 +                        err_msg = 'pci: %s: it is on bus 0, but has no PCI' +\
    2.46 +                            ' Advanced Capabilities for FLR. Will try the'+\
    2.47 +                            ' Dstate transition method if available.'
    2.48 +                        log.warn(err_msg % dev.name)
    2.49                  else:
    2.50                      # All devices behind the uppermost PCI/PCI-X bridge must be\
    2.51                      # co-assigned to the same guest.