Mailing List Archive

Tools changes for PCI front/back drivers.
# HG changeset patch
# User kaf24@firebug.cl.cam.ac.uk
# Node ID 7c720ccec00a26a287eb2e9353e4aa2dd7b5f66b
# Parent 5b433b4fca34e8a9a3c2eb932ffa0e2ae8594e94
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>

diff -r 5b433b4fca34 -r 7c720ccec00a tools/python/xen/xend/server/pciif.py
--- a/tools/python/xen/xend/server/pciif.py Thu Feb 16 22:44:41 2006
+++ b/tools/python/xen/xend/server/pciif.py Thu Feb 16 22:46:51 2006
@@ -19,29 +19,28 @@

import types

-import xen.lowlevel.xc;
-
from xen.xend import sxp
from xen.xend.XendError import VmError
+from xen.xend.XendLogging import log
+
+from xen.xend.xenstore.xstransact import xstransact

from xen.xend.server.DevController import DevController

+import xen.lowlevel.xc
+
+from xen.util.pci import PciDevice
+import resource

xc = xen.lowlevel.xc.xc()

-
-def parse_pci(val):
- """Parse a pci field.
- """
- if isinstance(val, types.StringType):
- radix = 10
- if val.startswith('0x') or val.startswith('0X'):
- radix = 16
- v = int(val, radix)
- else:
- v = val
- return v
-
+#Calculate PAGE_SHIFT: number of bits to shift an address to get the page number
+PAGE_SIZE = resource.getpagesize()
+PAGE_SHIFT = 0
+t = PAGE_SIZE
+while not (t&1):
+ t>>=1
+ PAGE_SHIFT+=1

class PciController(DevController):

@@ -51,32 +50,110 @@

def getDeviceDetails(self, config):
"""@see DevController.getDeviceDetails"""
+ #log.debug('pci config='+sxp.to_string(config))

- def get_param(field):
+ def get_param(config, field, default=None):
try:
val = sxp.child_value(config, field)

if not val:
- raise VmError('pci: Missing %s config setting' % field)
+ if default==None:
+ raise VmError('pci: Missing %s config setting' % field)
+ else:
+ return default

- return parse_pci(val)
+ if isinstance(val, types.StringType):
+ return int(val, 16)
+ else:
+ return val
except:
- raise VmError('pci: Invalid config setting %s: %s' %
+ if default==None:
+ raise VmError('pci: Invalid config setting %s: %s' %
(field, val))
+ else:
+ return default

- bus = get_param('bus')
- dev = get_param('dev')
- func = get_param('func')
+ back = {}

- rc = xc.physdev_pci_access_modify(dom = self.getDomid(),
- bus = bus,
- dev = dev,
- func = func,
- enable = True)
- if rc < 0:
- #todo non-fatal
- raise VmError(
- 'pci: Failed to configure device: bus=%s dev=%s func=%s' %
- (bus, dev, func))
+ val = sxp.child_value(config, 'dev')
+ if isinstance(val, list):
+ pcidevid = 0
+ for dev_config in sxp.children(config, 'dev'):
+ domain = get_param(dev_config, 'domain', 0)
+ bus = get_param(dev_config,'bus')
+ slot = get_param(dev_config,'slot')
+ func = get_param(dev_config,'func')

- return (dev, {}, {})
+ self.setupDevice(domain, bus, slot, func)
+
+ back['dev-%i'%(pcidevid)]="%04x:%02x:%02x.%02x"% \
+ (domain, bus, slot, func)
+ pcidevid+=1
+
+ back['num_devs']=str(pcidevid)
+
+ else:
+ # Xen 2.0 configuration compatibility
+ domain = get_param(dev_config, 'domain', 0)
+ bus = get_param(config, 'bus')
+ slot = get_param(config, 'dev')
+ func = get_param(config, 'func')
+
+ self.setupDevice(domain, bus, slot, func)
+
+ back['dev-0']="%04x:%02x:%02x.%02x"%(domain, bus, slot, func)
+ back['num_devs']=str(1)
+
+ return (0, back, {})
+
+ def setupDevice(self, domain, bus, slot, func):
+ """ Attach I/O resources for device to frontend domain
+ """
+ fe_domid = self.getDomid()
+
+ try:
+ dev = PciDevice(domain, bus, slot, func)
+ except Exception, e:
+ raise VmError("pci: failed to locate device and "+
+ "parse it's resources - %s"+str(e))
+
+ if dev.driver!='pciback':
+ raise VmError(("pci: PCI Backend does not own device "+
+ "%s\n"+
+ "See the pciback.hide kernel "+
+ "command-line parameter")%(dev.name))
+
+ for (start, size) in dev.ioports:
+ log.debug('pci: enabling ioport 0x%x/0x%x'%(start,size))
+ rc = xc.domain_ioport_permission(dom = fe_domid, first_port = start,
+ nr_ports = size, allow_access = True)
+ if rc<0:
+ raise VmError(('pci: failed to configure I/O ports on device '+
+ '%s - errno=%d')&(dev.name,rc))
+
+ for (start, size) in dev.iomem:
+ # Convert start/size from bytes to page frame sizes
+ start_pfn = start>>PAGE_SHIFT
+ # Round number of pages up to nearest page boundary (if not on one)
+ nr_pfns = (size+(PAGE_SIZE-1))>>PAGE_SHIFT
+
+ log.debug('pci: enabling iomem 0x%x/0x%x pfn 0x%x/0x%x'% \
+ (start,size,start_pfn,nr_pfns))
+ rc = xc.domain_iomem_permission(dom = fe_domid,
+ first_pfn = start_pfn,
+ nr_pfns = nr_pfns,
+ allow_access = True)
+ if rc<0:
+ raise VmError(('pci: failed to configure I/O memory on device '+
+ '%s - errno=%d')&(dev.name,rc))
+
+ if dev.irq>0:
+ log.debug('pci: enabling irq %d'%dev.irq)
+ rc = xc.domain_irq_permission(dom = fe_domid, pirq = dev.irq,
+ allow_access = True)
+ if rc<0:
+ raise VmError(('pci: failed to configure irq on device '+
+ '%s - errno=%d')&(dev.name,rc))
+
+ def waitForBackend(self,devid):
+ return (0, "ok - no hotplug")
diff -r 5b433b4fca34 -r 7c720ccec00a tools/python/xen/xm/create.py
--- a/tools/python/xen/xm/create.py Thu Feb 16 22:44:41 2006
+++ b/tools/python/xen/xm/create.py Thu Feb 16 22:46:51 2006
@@ -26,6 +26,7 @@
import socket
import commands
import time
+import re

import xen.lowlevel.xc

@@ -240,10 +241,10 @@
backend driver domain to use for the disk.
The option may be repeated to add more than one disk.""")

-gopts.var('pci', val='BUS,DEV,FUNC',
+gopts.var('pci', val='BUS:DEV.FUNC',
fn=append_value, default=[],
use="""Add a PCI device to a domain, using given params (in hex).
- For example '-pci c0,02,1a'.
+ For example '-pci c0:02.1a'.
The option may be repeated to add more than one pci device.""")

gopts.var('ioports', val='FROM[-TO]',
@@ -461,8 +462,13 @@
def configure_pci(config_devs, vals):
"""Create the config for pci devices.
"""
- for (bus, dev, func) in vals.pci:
- config_pci = ['pci', ['bus', bus], ['dev', dev], ['func', func]]
+ config_pci = []
+ for (domain, bus, slot, func) in vals.pci:
+ config_pci.append(['dev', ['domain', domain], ['bus', bus], \
+ ['slot', slot], ['func', func]])
+
+ if len(config_pci)>0:
+ config_pci.insert(0, 'pci')
config_devs.append(['device', config_pci])

def configure_ioports(config_devs, vals):
@@ -624,13 +630,20 @@
def preprocess_pci(vals):
if not vals.pci: return
pci = []
- for v in vals.pci:
- d = v.split(',')
- if len(d) != 3:
- err('Invalid pci specifier: ' + v)
- # Components are in hex: add hex specifier.
- hexd = map(lambda v: '0x'+v, d)
- pci.append(hexd)
+ for pci_dev_str in vals.pci:
+ pci_match = re.match(r"((?P<domain>[0-9a-fA-F]{1,4})[:,])?" + \
+ r"(?P<bus>[0-9a-fA-F]{1,2})[:,]" + \
+ r"(?P<slot>[0-9a-fA-F]{1,2})[.,]" + \
+ r"(?P<func>[0-9a-fA-F])", pci_dev_str)
+ if pci_match!=None:
+ pci_dev_info = pci_match.groupdict('0')
+ try:
+ pci.append( ('0x'+pci_dev_info['domain'], \
+ '0x'+pci_dev_info['bus'], \
+ '0x'+pci_dev_info['slot'], \
+ '0x'+pci_dev_info['func']))
+ except IndexError:
+ err('Error in PCI slot syntax "%s"'%(pci_dev_str))
vals.pci = pci

def preprocess_ioports(vals):
diff -r 5b433b4fca34 -r 7c720ccec00a tools/python/xen/util/pci.py
--- /dev/null Thu Feb 16 22:44:41 2006
+++ b/tools/python/xen/util/pci.py Thu Feb 16 22:46:51 2006
@@ -0,0 +1,192 @@
+#!/usr/bin/env python
+#
+# PCI Device Information Class
+# - Helps obtain information about which I/O resources a PCI device needs
+#
+# Author: Ryan Wilson <hap9@epoch.ncsc.mil>
+
+import sys
+import os, os.path
+
+PROC_MNT_PATH = '/proc/mounts'
+PROC_PCI_PATH = '/proc/bus/pci/devices'
+PROC_PCI_NUM_RESOURCES = 7
+
+SYSFS_PCI_DEVS_PATH = '/bus/pci/devices'
+SYSFS_PCI_DEV_RESOURCE_PATH = '/resource'
+SYSFS_PCI_DEV_IRQ_PATH = '/irq'
+SYSFS_PCI_DEV_DRIVER_DIR_PATH = '/driver'
+
+PCI_BAR_IO = 0x01
+PCI_BAR_IO_MASK = ~0x03
+PCI_BAR_MEM_MASK = ~0x0f
+
+# Definitions from Linux: include/linux/pci.h
+def PCI_DEVFN(slot, func):
+ return ((((slot) & 0x1f) << 3) | ((func) & 0x07))
+
+def find_sysfs_mnt():
+ mounts_file = open(PROC_MNT_PATH,'r')
+
+ for line in mounts_file:
+ sline = line.split()
+ if len(sline)<3:
+ continue
+
+ if sline[2]=='sysfs':
+ return sline[1]
+
+ return None
+
+class PciDeviceNotFoundError(Exception):
+ def __init__(self,domain,bus,slot,func):
+ self.domain = domain
+ self.bus = bus
+ self.slot = slot
+ self.func = func
+ self.name = "%04x:%02x:%02x.%01x"%(domain, bus, slot, func)
+
+ def __str__(self):
+ return ('PCI Device %s Not Found' % (self.name))
+
+class PciDeviceParseError(Exception):
+ def __init__(self,msg):
+ self.message = msg
+ def __str__(self):
+ return 'Error Parsing PCI Device Info: '+self.message
+
+class PciDevice:
+ def __init__(self, domain, bus, slot, func):
+ self.domain = domain
+ self.bus = bus
+ self.slot = slot
+ self.func = func
+ self.name = "%04x:%02x:%02x.%01x"%(domain, bus, slot, func)
+ self.irq = 0
+ self.iomem = []
+ self.ioports = []
+ self.driver = None
+
+ if not self.get_info_from_sysfs():
+ self.get_info_from_proc()
+
+ def get_info_from_sysfs(self):
+ try:
+ sysfs_mnt = find_sysfs_mnt()
+ except IOError, (errno, strerr):
+ raise PciDeviceParseError(('Failed to locate sysfs mount: %s (%d)' %
+ (PROC_PCI_PATH, strerr, errno)))
+
+ if sysfs_mnt == None:
+ return False
+
+ path = sysfs_mnt+SYSFS_PCI_DEVS_PATH+'/'+ \
+ self.name+SYSFS_PCI_DEV_RESOURCE_PATH
+ try:
+ resource_file = open(path,'r')
+
+ for i in range(7):
+ line = resource_file.readline()
+ sline = line.split()
+ if len(sline)<3:
+ continue
+
+ start = int(sline[0],16)
+ end = int(sline[1],16)
+ flags = int(sline[2],16)
+ size = end-start+1
+
+ if start!=0:
+ if flags&PCI_BAR_IO:
+ self.ioports.append( (start,size) )
+ else:
+ self.iomem.append( (start,size) )
+
+ except IOError, (errno, strerr):
+ raise PciDeviceParseError(('Failed to open & read %s: %s (%d)' %
+ (path, strerr, errno)))
+
+ path = sysfs_mnt+SYSFS_PCI_DEVS_PATH+'/'+ \
+ self.name+SYSFS_PCI_DEV_IRQ_PATH
+ try:
+ self.irq = int(open(path,'r').readline())
+ except IOError, (errno, strerr):
+ raise PciDeviceParseError(('Failed to open & read %s: %s (%d)' %
+ (path, strerr, errno)))
+
+ path = sysfs_mnt+SYSFS_PCI_DEVS_PATH+'/'+ \
+ self.name+SYSFS_PCI_DEV_DRIVER_DIR_PATH
+ try:
+ self.driver = os.path.basename(os.readlink(path))
+ except IOError, (errno, strerr):
+ raise PciDeviceParseError(('Failed to read %s: %s (%d)' %
+ (path, strerr, errno)))
+
+ return True
+
+ def get_info_from_proc(self):
+ bus_devfn = '%02x%02x' % (self.bus,PCI_DEVFN(self.slot,self.func))
+
+ # /proc/bus/pci/devices doesn't expose domains
+ if self.domain!=0:
+ raise PciDeviceParseError("Can't yet detect resource usage by "+
+ "devices in other domains through proc!")
+
+ try:
+ proc_pci_file = open(PROC_PCI_PATH,'r')
+ except IOError, (errno, strerr):
+ raise PciDeviceParseError(('Failed to open %s: %s (%d)' %
+ (PROC_PCI_PATH, strerr, errno)))
+
+ for line in proc_pci_file:
+ sline = line.split()
+ if len(sline)<(PROC_PCI_NUM_RESOURCES*2+3):
+ continue
+
+ if sline[0]==bus_devfn:
+ self.dissect_proc_pci_line(sline)
+ break
+ else:
+ raise PciDeviceNotFoundError(self.domain, self.bus,
+ self.slot, self.func)
+
+ def dissect_proc_pci_line(self, sline):
+ self.irq = int(sline[2],16)
+ start_idx = 3
+ for i in range(PROC_PCI_NUM_RESOURCES):
+ flags = int(sline[start_idx+i],16)
+ size = int(sline[start_idx+i+PROC_PCI_NUM_RESOURCES],16)
+ if flags&PCI_BAR_IO:
+ start = flags&PCI_BAR_IO_MASK
+ if start!=0:
+ self.ioports.append( (start,size) )
+ else:
+ start = flags&PCI_BAR_MEM_MASK
+ if start!=0:
+ self.iomem.append( (start,size) )
+
+ # detect driver module name
+ driver_idx = PROC_PCI_NUM_RESOURCES*2+3
+ if len(sline)>driver_idx:
+ self.driver = sline[driver_idx]
+
+ def __str__(self):
+ str = "PCI Device %s\n" % (self.name)
+ for (start,size) in self.ioports:
+ str = str + "IO Port 0x%02x [size=%d]\n"%(start,size)
+ for (start,size) in self.iomem:
+ str = str + "IO Mem 0x%02x [size=%d]\n"%(start,size)
+ str = str + "IRQ %d"%(self.irq)
+ return str
+
+def main():
+ if len(sys.argv)<5:
+ print "Usage: %s <domain> <bus> <slot> <func>\n"
+ sys.exit(2)
+
+ dev = PciDevice(int(sys.argv[1],16), int(sys.argv[2],16),
+ int(sys.argv[3],16), int(sys.argv[4],16))
+ print str(dev)
+
+if __name__=='__main__':
+ main()

_______________________________________________
Xen-changelog mailing list
Xen-changelog@lists.xensource.com
http://lists.xensource.com/xen-changelog