ia64/xen-unstable
changeset 8880:7c720ccec00a
Tools changes for PCI front/back drivers.
Replace the old pciif DevController class with a new one that
configures the PCI backend. A util class detects the resource usage of
the specified PCI devices and pciif interacts with Xen to permit a
driver domain to directly access those physical I/O resources.
Signed-off-by: Ryan Wilson <hap9@epoch.ncsc.mil>
Replace the old pciif DevController class with a new one that
configures the PCI backend. A util class detects the resource usage of
the specified PCI devices and pciif interacts with Xen to permit a
driver domain to directly access those physical I/O resources.
Signed-off-by: Ryan Wilson <hap9@epoch.ncsc.mil>
author | kaf24@firebug.cl.cam.ac.uk |
---|---|
date | Thu Feb 16 23:46:51 2006 +0100 (2006-02-16) |
parents | 5b433b4fca34 |
children | 90ebc45e1bd8 |
files | tools/python/xen/util/pci.py tools/python/xen/xend/server/pciif.py tools/python/xen/xm/create.py |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/tools/python/xen/util/pci.py Thu Feb 16 23:46:51 2006 +0100 1.3 @@ -0,0 +1,192 @@ 1.4 +#!/usr/bin/env python 1.5 +# 1.6 +# PCI Device Information Class 1.7 +# - Helps obtain information about which I/O resources a PCI device needs 1.8 +# 1.9 +# Author: Ryan Wilson <hap9@epoch.ncsc.mil> 1.10 + 1.11 +import sys 1.12 +import os, os.path 1.13 + 1.14 +PROC_MNT_PATH = '/proc/mounts' 1.15 +PROC_PCI_PATH = '/proc/bus/pci/devices' 1.16 +PROC_PCI_NUM_RESOURCES = 7 1.17 + 1.18 +SYSFS_PCI_DEVS_PATH = '/bus/pci/devices' 1.19 +SYSFS_PCI_DEV_RESOURCE_PATH = '/resource' 1.20 +SYSFS_PCI_DEV_IRQ_PATH = '/irq' 1.21 +SYSFS_PCI_DEV_DRIVER_DIR_PATH = '/driver' 1.22 + 1.23 +PCI_BAR_IO = 0x01 1.24 +PCI_BAR_IO_MASK = ~0x03 1.25 +PCI_BAR_MEM_MASK = ~0x0f 1.26 + 1.27 +# Definitions from Linux: include/linux/pci.h 1.28 +def PCI_DEVFN(slot, func): 1.29 + return ((((slot) & 0x1f) << 3) | ((func) & 0x07)) 1.30 + 1.31 +def find_sysfs_mnt(): 1.32 + mounts_file = open(PROC_MNT_PATH,'r') 1.33 + 1.34 + for line in mounts_file: 1.35 + sline = line.split() 1.36 + if len(sline)<3: 1.37 + continue 1.38 + 1.39 + if sline[2]=='sysfs': 1.40 + return sline[1] 1.41 + 1.42 + return None 1.43 + 1.44 +class PciDeviceNotFoundError(Exception): 1.45 + def __init__(self,domain,bus,slot,func): 1.46 + self.domain = domain 1.47 + self.bus = bus 1.48 + self.slot = slot 1.49 + self.func = func 1.50 + self.name = "%04x:%02x:%02x.%01x"%(domain, bus, slot, func) 1.51 + 1.52 + def __str__(self): 1.53 + return ('PCI Device %s Not Found' % (self.name)) 1.54 + 1.55 +class PciDeviceParseError(Exception): 1.56 + def __init__(self,msg): 1.57 + self.message = msg 1.58 + def __str__(self): 1.59 + return 'Error Parsing PCI Device Info: '+self.message 1.60 + 1.61 +class PciDevice: 1.62 + def __init__(self, domain, bus, slot, func): 1.63 + self.domain = domain 1.64 + self.bus = bus 1.65 + self.slot = slot 1.66 + self.func = func 1.67 + self.name = "%04x:%02x:%02x.%01x"%(domain, bus, slot, func) 1.68 + self.irq = 0 1.69 + self.iomem = [] 1.70 + self.ioports = [] 1.71 + self.driver = None 1.72 + 1.73 + if not self.get_info_from_sysfs(): 1.74 + self.get_info_from_proc() 1.75 + 1.76 + def get_info_from_sysfs(self): 1.77 + try: 1.78 + sysfs_mnt = find_sysfs_mnt() 1.79 + except IOError, (errno, strerr): 1.80 + raise PciDeviceParseError(('Failed to locate sysfs mount: %s (%d)' % 1.81 + (PROC_PCI_PATH, strerr, errno))) 1.82 + 1.83 + if sysfs_mnt == None: 1.84 + return False 1.85 + 1.86 + path = sysfs_mnt+SYSFS_PCI_DEVS_PATH+'/'+ \ 1.87 + self.name+SYSFS_PCI_DEV_RESOURCE_PATH 1.88 + try: 1.89 + resource_file = open(path,'r') 1.90 + 1.91 + for i in range(7): 1.92 + line = resource_file.readline() 1.93 + sline = line.split() 1.94 + if len(sline)<3: 1.95 + continue 1.96 + 1.97 + start = int(sline[0],16) 1.98 + end = int(sline[1],16) 1.99 + flags = int(sline[2],16) 1.100 + size = end-start+1 1.101 + 1.102 + if start!=0: 1.103 + if flags&PCI_BAR_IO: 1.104 + self.ioports.append( (start,size) ) 1.105 + else: 1.106 + self.iomem.append( (start,size) ) 1.107 + 1.108 + except IOError, (errno, strerr): 1.109 + raise PciDeviceParseError(('Failed to open & read %s: %s (%d)' % 1.110 + (path, strerr, errno))) 1.111 + 1.112 + path = sysfs_mnt+SYSFS_PCI_DEVS_PATH+'/'+ \ 1.113 + self.name+SYSFS_PCI_DEV_IRQ_PATH 1.114 + try: 1.115 + self.irq = int(open(path,'r').readline()) 1.116 + except IOError, (errno, strerr): 1.117 + raise PciDeviceParseError(('Failed to open & read %s: %s (%d)' % 1.118 + (path, strerr, errno))) 1.119 + 1.120 + path = sysfs_mnt+SYSFS_PCI_DEVS_PATH+'/'+ \ 1.121 + self.name+SYSFS_PCI_DEV_DRIVER_DIR_PATH 1.122 + try: 1.123 + self.driver = os.path.basename(os.readlink(path)) 1.124 + except IOError, (errno, strerr): 1.125 + raise PciDeviceParseError(('Failed to read %s: %s (%d)' % 1.126 + (path, strerr, errno))) 1.127 + 1.128 + return True 1.129 + 1.130 + def get_info_from_proc(self): 1.131 + bus_devfn = '%02x%02x' % (self.bus,PCI_DEVFN(self.slot,self.func)) 1.132 + 1.133 + # /proc/bus/pci/devices doesn't expose domains 1.134 + if self.domain!=0: 1.135 + raise PciDeviceParseError("Can't yet detect resource usage by "+ 1.136 + "devices in other domains through proc!") 1.137 + 1.138 + try: 1.139 + proc_pci_file = open(PROC_PCI_PATH,'r') 1.140 + except IOError, (errno, strerr): 1.141 + raise PciDeviceParseError(('Failed to open %s: %s (%d)' % 1.142 + (PROC_PCI_PATH, strerr, errno))) 1.143 + 1.144 + for line in proc_pci_file: 1.145 + sline = line.split() 1.146 + if len(sline)<(PROC_PCI_NUM_RESOURCES*2+3): 1.147 + continue 1.148 + 1.149 + if sline[0]==bus_devfn: 1.150 + self.dissect_proc_pci_line(sline) 1.151 + break 1.152 + else: 1.153 + raise PciDeviceNotFoundError(self.domain, self.bus, 1.154 + self.slot, self.func) 1.155 + 1.156 + def dissect_proc_pci_line(self, sline): 1.157 + self.irq = int(sline[2],16) 1.158 + start_idx = 3 1.159 + for i in range(PROC_PCI_NUM_RESOURCES): 1.160 + flags = int(sline[start_idx+i],16) 1.161 + size = int(sline[start_idx+i+PROC_PCI_NUM_RESOURCES],16) 1.162 + if flags&PCI_BAR_IO: 1.163 + start = flags&PCI_BAR_IO_MASK 1.164 + if start!=0: 1.165 + self.ioports.append( (start,size) ) 1.166 + else: 1.167 + start = flags&PCI_BAR_MEM_MASK 1.168 + if start!=0: 1.169 + self.iomem.append( (start,size) ) 1.170 + 1.171 + # detect driver module name 1.172 + driver_idx = PROC_PCI_NUM_RESOURCES*2+3 1.173 + if len(sline)>driver_idx: 1.174 + self.driver = sline[driver_idx] 1.175 + 1.176 + def __str__(self): 1.177 + str = "PCI Device %s\n" % (self.name) 1.178 + for (start,size) in self.ioports: 1.179 + str = str + "IO Port 0x%02x [size=%d]\n"%(start,size) 1.180 + for (start,size) in self.iomem: 1.181 + str = str + "IO Mem 0x%02x [size=%d]\n"%(start,size) 1.182 + str = str + "IRQ %d"%(self.irq) 1.183 + return str 1.184 + 1.185 +def main(): 1.186 + if len(sys.argv)<5: 1.187 + print "Usage: %s <domain> <bus> <slot> <func>\n" 1.188 + sys.exit(2) 1.189 + 1.190 + dev = PciDevice(int(sys.argv[1],16), int(sys.argv[2],16), 1.191 + int(sys.argv[3],16), int(sys.argv[4],16)) 1.192 + print str(dev) 1.193 + 1.194 +if __name__=='__main__': 1.195 + main()
2.1 --- a/tools/python/xen/xend/server/pciif.py Thu Feb 16 23:44:41 2006 +0100 2.2 +++ b/tools/python/xen/xend/server/pciif.py Thu Feb 16 23:46:51 2006 +0100 2.3 @@ -19,29 +19,28 @@ 2.4 2.5 import types 2.6 2.7 -import xen.lowlevel.xc; 2.8 - 2.9 from xen.xend import sxp 2.10 from xen.xend.XendError import VmError 2.11 +from xen.xend.XendLogging import log 2.12 + 2.13 +from xen.xend.xenstore.xstransact import xstransact 2.14 2.15 from xen.xend.server.DevController import DevController 2.16 2.17 +import xen.lowlevel.xc 2.18 + 2.19 +from xen.util.pci import PciDevice 2.20 +import resource 2.21 2.22 xc = xen.lowlevel.xc.xc() 2.23 2.24 - 2.25 -def parse_pci(val): 2.26 - """Parse a pci field. 2.27 - """ 2.28 - if isinstance(val, types.StringType): 2.29 - radix = 10 2.30 - if val.startswith('0x') or val.startswith('0X'): 2.31 - radix = 16 2.32 - v = int(val, radix) 2.33 - else: 2.34 - v = val 2.35 - return v 2.36 - 2.37 +#Calculate PAGE_SHIFT: number of bits to shift an address to get the page number 2.38 +PAGE_SIZE = resource.getpagesize() 2.39 +PAGE_SHIFT = 0 2.40 +t = PAGE_SIZE 2.41 +while not (t&1): 2.42 + t>>=1 2.43 + PAGE_SHIFT+=1 2.44 2.45 class PciController(DevController): 2.46 2.47 @@ -51,32 +50,110 @@ class PciController(DevController): 2.48 2.49 def getDeviceDetails(self, config): 2.50 """@see DevController.getDeviceDetails""" 2.51 + #log.debug('pci config='+sxp.to_string(config)) 2.52 2.53 - def get_param(field): 2.54 + def get_param(config, field, default=None): 2.55 try: 2.56 val = sxp.child_value(config, field) 2.57 2.58 if not val: 2.59 - raise VmError('pci: Missing %s config setting' % field) 2.60 + if default==None: 2.61 + raise VmError('pci: Missing %s config setting' % field) 2.62 + else: 2.63 + return default 2.64 2.65 - return parse_pci(val) 2.66 + if isinstance(val, types.StringType): 2.67 + return int(val, 16) 2.68 + else: 2.69 + return val 2.70 except: 2.71 - raise VmError('pci: Invalid config setting %s: %s' % 2.72 + if default==None: 2.73 + raise VmError('pci: Invalid config setting %s: %s' % 2.74 (field, val)) 2.75 + else: 2.76 + return default 2.77 2.78 - bus = get_param('bus') 2.79 - dev = get_param('dev') 2.80 - func = get_param('func') 2.81 + back = {} 2.82 + 2.83 + val = sxp.child_value(config, 'dev') 2.84 + if isinstance(val, list): 2.85 + pcidevid = 0 2.86 + for dev_config in sxp.children(config, 'dev'): 2.87 + domain = get_param(dev_config, 'domain', 0) 2.88 + bus = get_param(dev_config,'bus') 2.89 + slot = get_param(dev_config,'slot') 2.90 + func = get_param(dev_config,'func') 2.91 + 2.92 + self.setupDevice(domain, bus, slot, func) 2.93 + 2.94 + back['dev-%i'%(pcidevid)]="%04x:%02x:%02x.%02x"% \ 2.95 + (domain, bus, slot, func) 2.96 + pcidevid+=1 2.97 + 2.98 + back['num_devs']=str(pcidevid) 2.99 + 2.100 + else: 2.101 + # Xen 2.0 configuration compatibility 2.102 + domain = get_param(dev_config, 'domain', 0) 2.103 + bus = get_param(config, 'bus') 2.104 + slot = get_param(config, 'dev') 2.105 + func = get_param(config, 'func') 2.106 + 2.107 + self.setupDevice(domain, bus, slot, func) 2.108 + 2.109 + back['dev-0']="%04x:%02x:%02x.%02x"%(domain, bus, slot, func) 2.110 + back['num_devs']=str(1) 2.111 + 2.112 + return (0, back, {}) 2.113 2.114 - rc = xc.physdev_pci_access_modify(dom = self.getDomid(), 2.115 - bus = bus, 2.116 - dev = dev, 2.117 - func = func, 2.118 - enable = True) 2.119 - if rc < 0: 2.120 - #todo non-fatal 2.121 - raise VmError( 2.122 - 'pci: Failed to configure device: bus=%s dev=%s func=%s' % 2.123 - (bus, dev, func)) 2.124 + def setupDevice(self, domain, bus, slot, func): 2.125 + """ Attach I/O resources for device to frontend domain 2.126 + """ 2.127 + fe_domid = self.getDomid() 2.128 + 2.129 + try: 2.130 + dev = PciDevice(domain, bus, slot, func) 2.131 + except Exception, e: 2.132 + raise VmError("pci: failed to locate device and "+ 2.133 + "parse it's resources - %s"+str(e)) 2.134 + 2.135 + if dev.driver!='pciback': 2.136 + raise VmError(("pci: PCI Backend does not own device "+ 2.137 + "%s\n"+ 2.138 + "See the pciback.hide kernel "+ 2.139 + "command-line parameter")%(dev.name)) 2.140 2.141 - return (dev, {}, {}) 2.142 + for (start, size) in dev.ioports: 2.143 + log.debug('pci: enabling ioport 0x%x/0x%x'%(start,size)) 2.144 + rc = xc.domain_ioport_permission(dom = fe_domid, first_port = start, 2.145 + nr_ports = size, allow_access = True) 2.146 + if rc<0: 2.147 + raise VmError(('pci: failed to configure I/O ports on device '+ 2.148 + '%s - errno=%d')&(dev.name,rc)) 2.149 + 2.150 + for (start, size) in dev.iomem: 2.151 + # Convert start/size from bytes to page frame sizes 2.152 + start_pfn = start>>PAGE_SHIFT 2.153 + # Round number of pages up to nearest page boundary (if not on one) 2.154 + nr_pfns = (size+(PAGE_SIZE-1))>>PAGE_SHIFT 2.155 + 2.156 + log.debug('pci: enabling iomem 0x%x/0x%x pfn 0x%x/0x%x'% \ 2.157 + (start,size,start_pfn,nr_pfns)) 2.158 + rc = xc.domain_iomem_permission(dom = fe_domid, 2.159 + first_pfn = start_pfn, 2.160 + nr_pfns = nr_pfns, 2.161 + allow_access = True) 2.162 + if rc<0: 2.163 + raise VmError(('pci: failed to configure I/O memory on device '+ 2.164 + '%s - errno=%d')&(dev.name,rc)) 2.165 + 2.166 + if dev.irq>0: 2.167 + log.debug('pci: enabling irq %d'%dev.irq) 2.168 + rc = xc.domain_irq_permission(dom = fe_domid, pirq = dev.irq, 2.169 + allow_access = True) 2.170 + if rc<0: 2.171 + raise VmError(('pci: failed to configure irq on device '+ 2.172 + '%s - errno=%d')&(dev.name,rc)) 2.173 + 2.174 + def waitForBackend(self,devid): 2.175 + return (0, "ok - no hotplug")
3.1 --- a/tools/python/xen/xm/create.py Thu Feb 16 23:44:41 2006 +0100 3.2 +++ b/tools/python/xen/xm/create.py Thu Feb 16 23:46:51 2006 +0100 3.3 @@ -26,6 +26,7 @@ import sys 3.4 import socket 3.5 import commands 3.6 import time 3.7 +import re 3.8 3.9 import xen.lowlevel.xc 3.10 3.11 @@ -240,10 +241,10 @@ gopts.var('disk', val='phy:DEV,VDEV,MODE 3.12 backend driver domain to use for the disk. 3.13 The option may be repeated to add more than one disk.""") 3.14 3.15 -gopts.var('pci', val='BUS,DEV,FUNC', 3.16 +gopts.var('pci', val='BUS:DEV.FUNC', 3.17 fn=append_value, default=[], 3.18 use="""Add a PCI device to a domain, using given params (in hex). 3.19 - For example '-pci c0,02,1a'. 3.20 + For example '-pci c0:02.1a'. 3.21 The option may be repeated to add more than one pci device.""") 3.22 3.23 gopts.var('ioports', val='FROM[-TO]', 3.24 @@ -461,8 +462,13 @@ def configure_disks(config_devs, vals): 3.25 def configure_pci(config_devs, vals): 3.26 """Create the config for pci devices. 3.27 """ 3.28 - for (bus, dev, func) in vals.pci: 3.29 - config_pci = ['pci', ['bus', bus], ['dev', dev], ['func', func]] 3.30 + config_pci = [] 3.31 + for (domain, bus, slot, func) in vals.pci: 3.32 + config_pci.append(['dev', ['domain', domain], ['bus', bus], \ 3.33 + ['slot', slot], ['func', func]]) 3.34 + 3.35 + if len(config_pci)>0: 3.36 + config_pci.insert(0, 'pci') 3.37 config_devs.append(['device', config_pci]) 3.38 3.39 def configure_ioports(config_devs, vals): 3.40 @@ -624,13 +630,20 @@ def preprocess_disk(vals): 3.41 def preprocess_pci(vals): 3.42 if not vals.pci: return 3.43 pci = [] 3.44 - for v in vals.pci: 3.45 - d = v.split(',') 3.46 - if len(d) != 3: 3.47 - err('Invalid pci specifier: ' + v) 3.48 - # Components are in hex: add hex specifier. 3.49 - hexd = map(lambda v: '0x'+v, d) 3.50 - pci.append(hexd) 3.51 + for pci_dev_str in vals.pci: 3.52 + pci_match = re.match(r"((?P<domain>[0-9a-fA-F]{1,4})[:,])?" + \ 3.53 + r"(?P<bus>[0-9a-fA-F]{1,2})[:,]" + \ 3.54 + r"(?P<slot>[0-9a-fA-F]{1,2})[.,]" + \ 3.55 + r"(?P<func>[0-9a-fA-F])", pci_dev_str) 3.56 + if pci_match!=None: 3.57 + pci_dev_info = pci_match.groupdict('0') 3.58 + try: 3.59 + pci.append( ('0x'+pci_dev_info['domain'], \ 3.60 + '0x'+pci_dev_info['bus'], \ 3.61 + '0x'+pci_dev_info['slot'], \ 3.62 + '0x'+pci_dev_info['func'])) 3.63 + except IndexError: 3.64 + err('Error in PCI slot syntax "%s"'%(pci_dev_str)) 3.65 vals.pci = pci 3.66 3.67 def preprocess_ioports(vals):