ia64/xen-unstable

view tools/python/xen/xend/server/pciif.py @ 10036:4b4d16fe0b05

The PciController class lacks a configuration method to re-generate the
configuration of an existing domain. This is needed for a domain to be
able to reboot and retain its PCI device configuration. This patch adds
such support.

Thanks to Mike Wright for reporting this problem and working with me to
fix it.

Signed-off-by: Ryan Wilson <hap9@epoch.ncsc.mil>
author kaf24@firebug.cl.cam.ac.uk
date Wed May 10 16:07:46 2006 +0100 (2006-05-10)
parents 7801e09f518c
children 8cd577110904
line source
1 #============================================================================
2 # This library is free software; you can redistribute it and/or
3 # modify it under the terms of version 2.1 of the GNU Lesser General Public
4 # License as published by the Free Software Foundation.
5 #
6 # This library is distributed in the hope that it will be useful,
7 # but WITHOUT ANY WARRANTY; without even the implied warranty of
8 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
9 # Lesser General Public License for more details.
10 #
11 # You should have received a copy of the GNU Lesser General Public
12 # License along with this library; if not, write to the Free Software
13 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
14 #============================================================================
15 # Copyright (C) 2004, 2005 Mike Wray <mike.wray@hp.com>
16 # Copyright (C) 2005 XenSource Ltd
17 #============================================================================
20 import types
22 from xen.xend import sxp
23 from xen.xend.XendError import VmError
24 from xen.xend.XendLogging import log
26 from xen.xend.xenstore.xstransact import xstransact
28 from xen.xend.server.DevController import DevController
30 import xen.lowlevel.xc
32 from xen.util.pci import PciDevice
33 import resource
34 import re
36 xc = xen.lowlevel.xc.xc()
38 #Calculate PAGE_SHIFT: number of bits to shift an address to get the page number
39 PAGE_SIZE = resource.getpagesize()
40 PAGE_SHIFT = 0
41 t = PAGE_SIZE
42 while not (t&1):
43 t>>=1
44 PAGE_SHIFT+=1
46 class PciController(DevController):
48 def __init__(self, vm):
49 DevController.__init__(self, vm)
52 def getDeviceDetails(self, config):
53 """@see DevController.getDeviceDetails"""
54 #log.debug('pci config='+sxp.to_string(config))
56 def get_param(config, field, default=None):
57 try:
58 val = sxp.child_value(config, field)
60 if not val:
61 if default==None:
62 raise VmError('pci: Missing %s config setting' % field)
63 else:
64 return default
66 if isinstance(val, types.StringType):
67 return int(val, 16)
68 else:
69 return val
70 except:
71 if default==None:
72 raise VmError('pci: Invalid config setting %s: %s' %
73 (field, val))
74 else:
75 return default
77 back = {}
79 val = sxp.child_value(config, 'dev')
80 if isinstance(val, list):
81 pcidevid = 0
82 for dev_config in sxp.children(config, 'dev'):
83 domain = get_param(dev_config, 'domain', 0)
84 bus = get_param(dev_config,'bus')
85 slot = get_param(dev_config,'slot')
86 func = get_param(dev_config,'func')
88 self.setupDevice(domain, bus, slot, func)
90 back['dev-%i'%(pcidevid)]="%04x:%02x:%02x.%02x"% \
91 (domain, bus, slot, func)
92 pcidevid+=1
94 back['num_devs']=str(pcidevid)
96 else:
97 # Xen 2.0 configuration compatibility
98 domain = get_param(config, 'domain', 0)
99 bus = get_param(config, 'bus')
100 slot = get_param(config, 'dev')
101 func = get_param(config, 'func')
103 self.setupDevice(domain, bus, slot, func)
105 back['dev-0']="%04x:%02x:%02x.%02x"%(domain, bus, slot, func)
106 back['num_devs']=str(1)
108 return (0, back, {})
110 def configuration(self, devid):
111 """@see DevController.configuration"""
113 result = DevController.configuration(self, devid)
115 (num_devs) = self.readBackend(devid, 'num_devs')
117 for i in range(int(num_devs)):
118 (dev_config) = self.readBackend(devid, 'dev-%d'%(i))
120 pci_match = re.match(r"((?P<domain>[0-9a-fA-F]{1,4})[:,])?" + \
121 r"(?P<bus>[0-9a-fA-F]{1,2})[:,]" + \
122 r"(?P<slot>[0-9a-fA-F]{1,2})[.,]" + \
123 r"(?P<func>[0-9a-fA-F]{1,2})", dev_config)
124 if pci_match!=None:
125 pci_dev_info = pci_match.groupdict('0')
126 result.append( ['dev', \
127 ['domain', '0x'+pci_dev_info['domain']], \
128 ['bus', '0x'+pci_dev_info['bus']], \
129 ['slot', '0x'+pci_dev_info['slot']], \
130 ['func', '0x'+pci_dev_info['func']]])
132 return result
134 def setupDevice(self, domain, bus, slot, func):
135 """ Attach I/O resources for device to frontend domain
136 """
137 fe_domid = self.getDomid()
139 try:
140 dev = PciDevice(domain, bus, slot, func)
141 except Exception, e:
142 raise VmError("pci: failed to locate device and "+
143 "parse it's resources - "+str(e))
145 if dev.driver!='pciback':
146 raise VmError(("pci: PCI Backend does not own device "+ \
147 "%s\n"+ \
148 "See the pciback.hide kernel "+ \
149 "command-line parameter or\n"+ \
150 "bind your slot/device to the PCI backend using sysfs" \
151 )%(dev.name))
153 for (start, size) in dev.ioports:
154 log.debug('pci: enabling ioport 0x%x/0x%x'%(start,size))
155 rc = xc.domain_ioport_permission(dom = fe_domid, first_port = start,
156 nr_ports = size, allow_access = True)
157 if rc<0:
158 raise VmError(('pci: failed to configure I/O ports on device '+
159 '%s - errno=%d')%(dev.name,rc))
161 for (start, size) in dev.iomem:
162 # Convert start/size from bytes to page frame sizes
163 start_pfn = start>>PAGE_SHIFT
164 # Round number of pages up to nearest page boundary (if not on one)
165 nr_pfns = (size+(PAGE_SIZE-1))>>PAGE_SHIFT
167 log.debug('pci: enabling iomem 0x%x/0x%x pfn 0x%x/0x%x'% \
168 (start,size,start_pfn,nr_pfns))
169 rc = xc.domain_iomem_permission(dom = fe_domid,
170 first_pfn = start_pfn,
171 nr_pfns = nr_pfns,
172 allow_access = True)
173 if rc<0:
174 raise VmError(('pci: failed to configure I/O memory on device '+
175 '%s - errno=%d')%(dev.name,rc))
177 if dev.irq>0:
178 log.debug('pci: enabling irq %d'%dev.irq)
179 rc = xc.domain_irq_permission(dom = fe_domid, pirq = dev.irq,
180 allow_access = True)
181 if rc<0:
182 raise VmError(('pci: failed to configure irq on device '+
183 '%s - errno=%d')%(dev.name,rc))
185 def waitForBackend(self,devid):
186 return (0, "ok - no hotplug")