ia64/xen-unstable

changeset 10844:8cd577110904

[PCI] xend parses the user-space PCI backend policy files and sends
the corresponding fields to the PCI bus manager via sysfs nodes:

/sys/bus/pci/drivers/pciback/quirks
/sys/bus/pci/drivers/pciback/permissive

xend reads the policy file every time it creates a new domain that was
assigned a PCI device.

Signed-off-by: Chris Bookholt <hap10@tycho.ncsc.mil>
author kfraser@localhost.localdomain
date Fri Jul 28 12:57:55 2006 +0100 (2006-07-28)
parents 4f6d858ea570
children df80de098d15
files tools/python/xen/util/pci.py tools/python/xen/xend/server/pciif.py tools/python/xen/xend/server/pciquirk.py
line diff
     1.1 --- a/tools/python/xen/util/pci.py	Fri Jul 28 12:56:10 2006 +0100
     1.2 +++ b/tools/python/xen/util/pci.py	Fri Jul 28 12:57:55 2006 +0100
     1.3 @@ -16,6 +16,10 @@ SYSFS_PCI_DEVS_PATH = '/bus/pci/devices'
     1.4  SYSFS_PCI_DEV_RESOURCE_PATH = '/resource'
     1.5  SYSFS_PCI_DEV_IRQ_PATH = '/irq'
     1.6  SYSFS_PCI_DEV_DRIVER_DIR_PATH = '/driver'
     1.7 +SYSFS_PCI_DEV_VENDOR_PATH = '/vendor'
     1.8 +SYSFS_PCI_DEV_DEVICE_PATH = '/device'
     1.9 +SYSFS_PCI_DEV_SUBVENDOR_PATH = '/subsystem_vendor'
    1.10 +SYSFS_PCI_DEV_SUBDEVICE_PATH = '/subsystem_device'
    1.11  
    1.12  PCI_BAR_IO = 0x01
    1.13  PCI_BAR_IO_MASK = ~0x03
    1.14 @@ -66,9 +70,12 @@ class PciDevice:
    1.15          self.iomem = []
    1.16          self.ioports = []
    1.17          self.driver = None
    1.18 +        self.vendor = None
    1.19 +        self.device = None
    1.20 +        self.subvendor = None
    1.21 +        self.subdevice = None
    1.22  
    1.23 -        if not self.get_info_from_sysfs():
    1.24 -            self.get_info_from_proc()
    1.25 +        self.get_info_from_sysfs()
    1.26  
    1.27      def get_info_from_sysfs(self):
    1.28          try:
    1.29 @@ -85,7 +92,7 @@ class PciDevice:
    1.30          try:
    1.31              resource_file = open(path,'r')
    1.32  
    1.33 -            for i in range(7):
    1.34 +            for i in range(PROC_PCI_NUM_RESOURCES):
    1.35                  line = resource_file.readline()
    1.36                  sline = line.split()
    1.37                  if len(sline)<3:
    1.38 @@ -122,53 +129,39 @@ class PciDevice:
    1.39              raise PciDeviceParseError(('Failed to read %s: %s (%d)' %
    1.40                  (path, strerr, errno)))
    1.41  
    1.42 -        return True
    1.43 -        
    1.44 -    def get_info_from_proc(self):
    1.45 -        bus_devfn = '%02x%02x' % (self.bus,PCI_DEVFN(self.slot,self.func))
    1.46 -
    1.47 -        # /proc/bus/pci/devices doesn't expose domains
    1.48 -        if self.domain!=0:
    1.49 -            raise PciDeviceParseError("Can't yet detect resource usage by "+
    1.50 -                    "devices in other domains through proc!")
    1.51 -
    1.52 +        path = sysfs_mnt+SYSFS_PCI_DEVS_PATH+'/'+ \
    1.53 +                self.name+SYSFS_PCI_DEV_VENDOR_PATH
    1.54          try:
    1.55 -            proc_pci_file = open(PROC_PCI_PATH,'r')
    1.56 +            self.vendor = int(open(path,'r').readline(), 16)
    1.57          except IOError, (errno, strerr):
    1.58 -            raise PciDeviceParseError(('Failed to open %s: %s (%d)' %
    1.59 -                (PROC_PCI_PATH, strerr, errno)))
    1.60 -
    1.61 -        for line in proc_pci_file:
    1.62 -            sline = line.split()
    1.63 -            if len(sline)<(PROC_PCI_NUM_RESOURCES*2+3):
    1.64 -                continue
    1.65 +            raise PciDeviceParseError(('Failed to open & read %s: %s (%d)' %
    1.66 +                (path, strerr, errno)))
    1.67  
    1.68 -            if sline[0]==bus_devfn:
    1.69 -                self.dissect_proc_pci_line(sline)
    1.70 -                break
    1.71 -        else:
    1.72 -            raise PciDeviceNotFoundError(self.domain, self.bus,
    1.73 -                    self.slot, self.func)
    1.74 +        path = sysfs_mnt+SYSFS_PCI_DEVS_PATH+'/'+ \
    1.75 +                self.name+SYSFS_PCI_DEV_DEVICE_PATH
    1.76 +        try:
    1.77 +            self.device = int(open(path,'r').readline(), 16)
    1.78 +        except IOError, (errno, strerr):
    1.79 +            raise PciDeviceParseError(('Failed to open & read %s: %s (%d)' %
    1.80 +                (path, strerr, errno)))
    1.81  
    1.82 -    def dissect_proc_pci_line(self, sline):
    1.83 -        self.irq = int(sline[2],16)
    1.84 -        start_idx = 3
    1.85 -        for i in range(PROC_PCI_NUM_RESOURCES):
    1.86 -            flags = int(sline[start_idx+i],16)
    1.87 -            size = int(sline[start_idx+i+PROC_PCI_NUM_RESOURCES],16)
    1.88 -            if flags&PCI_BAR_IO:
    1.89 -                start = flags&PCI_BAR_IO_MASK
    1.90 -                if start!=0:
    1.91 -                    self.ioports.append( (start,size) )
    1.92 -            else:
    1.93 -                start = flags&PCI_BAR_MEM_MASK
    1.94 -                if start!=0:
    1.95 -                    self.iomem.append( (start,size) )
    1.96 +        path = sysfs_mnt+SYSFS_PCI_DEVS_PATH+'/'+ \
    1.97 +                self.name+SYSFS_PCI_DEV_SUBVENDOR_PATH
    1.98 +        try:
    1.99 +            self.subvendor = int(open(path,'r').readline(), 16)
   1.100 +        except IOError, (errno, strerr):
   1.101 +            raise PciDeviceParseError(('Failed to open & read %s: %s (%d)' %
   1.102 +                (path, strerr, errno)))
   1.103  
   1.104 -        # detect driver module name
   1.105 -        driver_idx = PROC_PCI_NUM_RESOURCES*2+3
   1.106 -        if len(sline)>driver_idx:
   1.107 -            self.driver = sline[driver_idx]
   1.108 +        path = sysfs_mnt+SYSFS_PCI_DEVS_PATH+'/'+ \
   1.109 +                self.name+SYSFS_PCI_DEV_SUBDEVICE_PATH
   1.110 +        try:
   1.111 +            self.subdevice = int(open(path,'r').readline(), 16)
   1.112 +        except IOError, (errno, strerr):
   1.113 +            raise PciDeviceParseError(('Failed to open & read %s: %s (%d)' %
   1.114 +                (path, strerr, errno)))
   1.115 +
   1.116 +        return True
   1.117  
   1.118      def __str__(self):
   1.119          str = "PCI Device %s\n" % (self.name)
   1.120 @@ -176,7 +169,11 @@ class PciDevice:
   1.121              str = str + "IO Port 0x%02x [size=%d]\n"%(start,size)
   1.122          for (start,size) in self.iomem:
   1.123              str = str + "IO Mem 0x%02x [size=%d]\n"%(start,size)
   1.124 -        str = str + "IRQ %d"%(self.irq)
   1.125 +        str = str + "IRQ %d\n"%(self.irq)
   1.126 +        str = str + "Vendor ID 0x%04x\n"%(self.vendor)
   1.127 +        str = str + "Device ID 0x%04x\n"%(self.device)
   1.128 +        str = str + "Sybsystem Vendor ID 0x%04x\n"%(self.subvendor)
   1.129 +        str = str + "Subsystem Device ID 0x%04x"%(self.subdevice)
   1.130          return str
   1.131  
   1.132  def main():
     2.1 --- a/tools/python/xen/xend/server/pciif.py	Fri Jul 28 12:56:10 2006 +0100
     2.2 +++ b/tools/python/xen/xend/server/pciif.py	Fri Jul 28 12:57:55 2006 +0100
     2.3 @@ -33,6 +33,8 @@ from xen.util.pci import PciDevice
     2.4  import resource
     2.5  import re
     2.6  
     2.7 +from xen.xend.server.pciquirk import *
     2.8 +
     2.9  xc = xen.lowlevel.xc.xc()
    2.10  
    2.11  #Calculate PAGE_SHIFT: number of bits to shift an address to get the page number
    2.12 @@ -150,7 +152,10 @@ class PciController(DevController):
    2.13                      "bind your slot/device to the PCI backend using sysfs" \
    2.14                      )%(dev.name))
    2.15  
    2.16 -        for (start, size) in dev.ioports:
    2.17 +        PCIQuirk(dev.vendor, dev.device, dev.subvendor, dev.subdevice, domain, 
    2.18 +                bus, slot, func)
    2.19 +
    2.20 +	for (start, size) in dev.ioports:
    2.21              log.debug('pci: enabling ioport 0x%x/0x%x'%(start,size))
    2.22              rc = xc.domain_ioport_permission(dom = fe_domid, first_port = start,
    2.23                      nr_ports = size, allow_access = True)
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/tools/python/xen/xend/server/pciquirk.py	Fri Jul 28 12:57:55 2006 +0100
     3.3 @@ -0,0 +1,145 @@
     3.4 +from xen.xend.XendLogging import log
     3.5 +from xen.xend.XendError import XendError
     3.6 +import sys
     3.7 +import os.path
     3.8 +from xen.xend.sxp import *
     3.9 +
    3.10 +QUIRK_SYSFS_NODE = "/sys/bus/pci/drivers/pciback/quirks"
    3.11 +QUIRK_CONFIG_FILE = "/etc/xen/xend-pci-quirks.sxp"
    3.12 +PERMISSIVE_CONFIG_FILE = "/etc/xen/xend-pci-permissive.sxp"
    3.13 +PERMISSIVE_SYSFS_NODE = "/sys/bus/pci/drivers/pciback/permissive"
    3.14 +
    3.15 +class PCIQuirk:
    3.16 +    def __init__( self, vendor, device, subvendor, subdevice, domain, bus, slot, func):
    3.17 +        self.vendor = vendor
    3.18 +        self.device = device
    3.19 +        self.subvendor = subvendor
    3.20 +        self.subdevice = subdevice
    3.21 +	self.domain = domain
    3.22 +	self.bus = bus
    3.23 +	self.slot = slot
    3.24 +	self.func = func
    3.25 +
    3.26 +        self.devid = "%04x:%04x:%04x:%04x" % (vendor, device, subvendor, subdevice)
    3.27 +	self.pciid = "%04x:%02x:%02x.%01x" % (domain, bus, slot, func)
    3.28 +
    3.29 +        self.quirks = self.__getQuirksByID( )
    3.30 +
    3.31 +	self.__sendQuirks( )
    3.32 +	self.__sendPermDevs( )
    3.33 +
    3.34 +    def __matchPCIdev( self, list ):
    3.35 +        ret = False
    3.36 +        if list == None:
    3.37 +            return False
    3.38 +        for id in list:
    3.39 +            if id.startswith( self.devid[:9] ): # id's vendor and device ID match
    3.40 +                skey = id.split(':')
    3.41 +                size = len(skey)
    3.42 +                if (size == 2):		# subvendor/subdevice not suplied
    3.43 +                    ret = True
    3.44 +                    break
    3.45 +                elif (size == 4):	# check subvendor/subdevice
    3.46 +                    # check subvendor
    3.47 +		    subven = '%04x' % self.subvendor
    3.48 +                    if ((skey[2] != 'FFFF') and 
    3.49 +                        (skey[2] != 'ffff') and 
    3.50 +                        (skey[2] != subven)):
    3.51 +                            continue
    3.52 +                    # check subdevice
    3.53 +		    subdev = '%04x' % self.subdevice
    3.54 +                    if ((skey[3] != 'FFFF') and 
    3.55 +                        (skey[3] != 'ffff') and 
    3.56 +                        (skey[3] != subdev)):
    3.57 +                            continue
    3.58 +                    ret = True
    3.59 +                    break
    3.60 +                else:
    3.61 +                    log.debug("WARNING: invalid configuration entry: %s" % id)
    3.62 +                    ret = False
    3.63 +                    break
    3.64 +        return ret
    3.65 +        
    3.66 +    def __getQuirksByID( self ):
    3.67 +        if os.path.exists(QUIRK_CONFIG_FILE):
    3.68 +            try:
    3.69 +                fin = file(QUIRK_CONFIG_FILE, 'rb')
    3.70 +                try:
    3.71 +                    pci_quirks_config = parse(fin)
    3.72 +                finally:
    3.73 +                    fin.close()
    3.74 +                if pci_quirks_config is None:
    3.75 +                    pci_quirks_config = ['xend-pci-quirks']
    3.76 +                else:
    3.77 +                    pci_quirks_config.insert(0, 'xend-pci-quirks')
    3.78 +                self.pci_quirks_config = pci_quirks_config
    3.79 +            except Exception, ex:
    3.80 +                raise XendError("Reading config file %s: %s" %
    3.81 +				(QUIRK_CONFIG_FILE, str(ex)))
    3.82 +        else:
    3.83 +            log.info("Config file does not exist: %s" % QUIRK_CONFIG_FILE)
    3.84 +            self.pci_quirks_config = ['xend-pci-quirks']
    3.85 +
    3.86 +        devices = children(self.pci_quirks_config)
    3.87 +        for dev in devices:
    3.88 +            ids = child_at(child(dev,'pci_ids'),0)
    3.89 +            fields = child_at(child(dev,'pci_config_space_fields'),0)
    3.90 +	    if self.__matchPCIdev( ids ):
    3.91 +                log.info("Quirks found for PCI device [%s]" % self.devid)
    3.92 +                return fields
    3.93 +
    3.94 +        log.info("NO quirks found for PCI device [%s]" % self.devid)
    3.95 +        return []
    3.96 +
    3.97 +    def __sendQuirks(self):
    3.98 +        for quirk in self.quirks:
    3.99 +            log.debug("Quirk Info: %04x:%02x:%02x.%1x-%s" % (self.domain,
   3.100 +		    self.bus, self.slot, self.func, quirk))
   3.101 +            try:
   3.102 +                f = file(QUIRK_SYSFS_NODE ,"w")
   3.103 +                f.write( "%04x:%02x:%02x.%1x-%s" % (self.domain, self.bus,
   3.104 +			self.slot, self.func, quirk) )
   3.105 +                f.close()
   3.106 +            except Exception, e:
   3.107 +                raise VmError("pci: failed to open/write/close quirks sysfs " + \
   3.108 +			"node - " + str(e))
   3.109 +
   3.110 +    def __devIsUnconstrained( self ):
   3.111 +        if os.path.exists(PERMISSIVE_CONFIG_FILE):
   3.112 +            try:
   3.113 +                fin = file(PERMISSIVE_CONFIG_FILE, 'rb')
   3.114 +                try:
   3.115 +                    pci_perm_dev_config = parse(fin)
   3.116 +                finally:
   3.117 +                    fin.close()
   3.118 +                if pci_perm_dev_config is None:
   3.119 +                    pci_perm_dev_config = ['']
   3.120 +                else:
   3.121 +                    pci_perm_dev_config.insert(0, '')
   3.122 +                self.pci_perm_dev_config = pci_perm_dev_config
   3.123 +            except Exception, ex:
   3.124 +                raise XendError("Reading config file %s: %s" %
   3.125 +				(PERMISSIVE_CONFIG_FILE,str(ex)))
   3.126 +        else:
   3.127 +            log.info("Config file does not exist: %s" % PERMISSIVE_CONFIG_FILE)
   3.128 +            self.pci_perm_dev_config = ['xend-pci-perm-devs']
   3.129 +
   3.130 +        devices = child_at(child(pci_perm_dev_config, 'unconstrained_dev_ids'),0)
   3.131 +	if self.__matchPCIdev( devices ):
   3.132 +            log.debug("Permissive mode enabled for PCI device [%s]" % self.devid)
   3.133 +            return True
   3.134 +        log.debug("Permissive mode NOT enabled for PCI device [%s]" % self.devid)
   3.135 +        return False
   3.136 +
   3.137 +    def __sendPermDevs(self):
   3.138 +	if self.__devIsUnconstrained( ):
   3.139 +            log.debug("Unconstrained device: %04x:%02x:%02x.%1x" % (self.domain,
   3.140 +		    self.bus, self.slot, self.func))
   3.141 +            try:
   3.142 +                f = file(PERMISSIVE_SYSFS_NODE ,"w")
   3.143 +                f.write( "%04x:%02x:%02x.%1x" % (self.domain, self.bus,
   3.144 +			self.slot, self.func) )
   3.145 +                f.close()
   3.146 +            except Exception, e:
   3.147 +                raise VmError("pci: failed to open/write/close permissive " + \
   3.148 +		"sysfs node: " + str(e))