[34] | 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") |
---|