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>
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))