source: trunk/packages/xen-3.1/xen-3.1/tools/python/xen/xend/server/pciif.py @ 34

Last change on this file since 34 was 34, checked in by hartmans, 18 years ago

Add xen and xen-common

File size: 6.9 KB
Line 
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#============================================================================
18
19
20import types
21
22from xen.xend import sxp
23from xen.xend.XendError import VmError
24from xen.xend.XendLogging import log
25
26from xen.xend.xenstore.xstransact import xstransact
27
28from xen.xend.server.DevController import DevController
29
30import xen.lowlevel.xc
31
32from xen.util.pci import PciDevice
33import resource
34import re
35
36from xen.xend.server.pciquirk import *
37
38xc = xen.lowlevel.xc.xc()
39
40#Calculate PAGE_SHIFT: number of bits to shift an address to get the page number
41PAGE_SIZE = resource.getpagesize()
42PAGE_SHIFT = 0
43t = PAGE_SIZE
44while not (t&1):
45    t>>=1
46    PAGE_SHIFT+=1
47
48class PciController(DevController):
49
50    def __init__(self, vm):
51        DevController.__init__(self, vm)
52
53
54    def getDeviceDetails(self, config):
55        """@see DevController.getDeviceDetails"""
56        def parse_hex(val):
57            try:
58                if isinstance(val, types.StringTypes):
59                    return int(val, 16)
60                else:
61                    return val
62            except ValueError:
63                return None
64           
65        back = {}
66        pcidevid = 0
67        for pci_config in config.get('devs', []):
68            domain = parse_hex(pci_config.get('domain', 0))
69            bus = parse_hex(pci_config.get('bus', 0))
70            slot = parse_hex(pci_config.get('slot', 0))
71            func = parse_hex(pci_config.get('func', 0))           
72            self.setupDevice(domain, bus, slot, func)
73            back['dev-%i' % pcidevid] = "%04x:%02x:%02x.%02x" % \
74                                        (domain, bus, slot, func)
75            pcidevid += 1
76
77        back['num_devs']=str(pcidevid)
78        back['uuid'] = config.get('uuid','')
79        return (0, back, {})
80
81    def getDeviceConfiguration(self, devid):
82        result = DevController.getDeviceConfiguration(self, devid)
83        num_devs = self.readBackend(devid, 'num_devs')
84        pci_devs = []
85       
86        for i in range(int(num_devs)):
87            dev_config = self.readBackend(devid, 'dev-%d' % i)
88
89            pci_match = re.match(r"((?P<domain>[0-9a-fA-F]{1,4})[:,])?" +
90                                 r"(?P<bus>[0-9a-fA-F]{1,2})[:,]" + 
91                                 r"(?P<slot>[0-9a-fA-F]{1,2})[.,]" + 
92                                 r"(?P<func>[0-9a-fA-F]{1,2})", dev_config)
93           
94            if pci_match!=None:
95                pci_dev_info = pci_match.groupdict()
96                pci_devs.append({'domain': '0x%(domain)s' % pci_dev_info,
97                                 'bus': '0x%(bus)s' % pci_dev_info,
98                                 'slot': '0x%(slot)s' % pci_dev_info,
99                                 'func': '0x%(func)s' % pci_dev_info})
100
101        result['devs'] = pci_devs
102        result['uuid'] = self.readBackend(devid, 'uuid')
103        return result
104
105    def configuration(self, devid):
106        """Returns SXPR for devices on domain.
107
108        @note: we treat this dict especially to convert to
109        SXP because it is not a straight dict of strings."""
110       
111        configDict = self.getDeviceConfiguration(devid)
112        sxpr = [self.deviceClass]
113
114        # remove devs
115        devs = configDict.pop('devs', [])
116       
117        for dev in devs:
118            dev_sxpr = ['dev']
119            for dev_item in dev.items():
120                dev_sxpr.append(list(dev_item))
121            sxpr.append(dev_sxpr)
122       
123        for key, val in configDict.items():
124            if type(val) == type(list()):
125                for v in val:
126                    sxpr.append([key, v])
127            else:
128                sxpr.append([key, val])
129
130        return sxpr   
131
132    def setupDevice(self, domain, bus, slot, func):
133        """ Attach I/O resources for device to frontend domain
134        """
135        fe_domid = self.getDomid()
136
137        try:
138            dev = PciDevice(domain, bus, slot, func)
139        except Exception, e:
140            raise VmError("pci: failed to locate device and "+
141                    "parse it's resources - "+str(e))
142
143        if dev.driver!='pciback':
144            raise VmError(("pci: PCI Backend does not own device "+ \
145                    "%s\n"+ \
146                    "See the pciback.hide kernel "+ \
147                    "command-line parameter or\n"+ \
148                    "bind your slot/device to the PCI backend using sysfs" \
149                    )%(dev.name))
150
151        PCIQuirk(dev.vendor, dev.device, dev.subvendor, dev.subdevice, domain, 
152                bus, slot, func)
153
154        for (start, size) in dev.ioports:
155            log.debug('pci: enabling ioport 0x%x/0x%x'%(start,size))
156            rc = xc.domain_ioport_permission(domid = fe_domid, first_port = start,
157                    nr_ports = size, allow_access = True)
158            if rc<0:
159                raise VmError(('pci: failed to configure I/O ports on device '+
160                            '%s - errno=%d')%(dev.name,rc))
161           
162        for (start, size) in dev.iomem:
163            # Convert start/size from bytes to page frame sizes
164            start_pfn = start>>PAGE_SHIFT
165            # Round number of pages up to nearest page boundary (if not on one)
166            nr_pfns = (size+(PAGE_SIZE-1))>>PAGE_SHIFT
167
168            log.debug('pci: enabling iomem 0x%x/0x%x pfn 0x%x/0x%x'% \
169                    (start,size,start_pfn,nr_pfns))
170            rc = xc.domain_iomem_permission(domid =  fe_domid,
171                    first_pfn = start_pfn,
172                    nr_pfns = nr_pfns,
173                    allow_access = True)
174            if rc<0:
175                raise VmError(('pci: failed to configure I/O memory on device '+
176                            '%s - errno=%d')%(dev.name,rc))
177
178        if dev.irq>0:
179            log.debug('pci: enabling irq %d'%dev.irq)
180            rc = xc.domain_irq_permission(domid =  fe_domid, pirq = dev.irq,
181                    allow_access = True)
182            if rc<0:
183                raise VmError(('pci: failed to configure irq on device '+
184                            '%s - errno=%d')%(dev.name,rc))
185
186    def waitForBackend(self,devid):
187        return (0, "ok - no hotplug")
Note: See TracBrowser for help on using the repository browser.