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 | |
---|
20 | import types |
---|
21 | |
---|
22 | from xen.xend import sxp |
---|
23 | from xen.xend.XendError import VmError |
---|
24 | from xen.xend.XendLogging import log |
---|
25 | |
---|
26 | from xen.xend.xenstore.xstransact import xstransact |
---|
27 | |
---|
28 | from xen.xend.server.DevController import DevController |
---|
29 | |
---|
30 | import xen.lowlevel.xc |
---|
31 | |
---|
32 | from xen.util.pci import PciDevice |
---|
33 | import resource |
---|
34 | import re |
---|
35 | |
---|
36 | from xen.xend.server.pciquirk import * |
---|
37 | |
---|
38 | xc = xen.lowlevel.xc.xc() |
---|
39 | |
---|
40 | #Calculate PAGE_SHIFT: number of bits to shift an address to get the page number |
---|
41 | PAGE_SIZE = resource.getpagesize() |
---|
42 | PAGE_SHIFT = 0 |
---|
43 | t = PAGE_SIZE |
---|
44 | while not (t&1): |
---|
45 | t>>=1 |
---|
46 | PAGE_SHIFT+=1 |
---|
47 | |
---|
48 | class 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") |
---|