ia64/xen-unstable

annotate tools/python/xen/util/pci.py @ 19758:0573bbe19499

xend: pass-through: sxp.merge() cant deal with values being a list

sxp.merge() can't deal with values being a list so instead
of storing pci options as:

[ 'opts', [ 'key1' 'value1'], [ 'key2', 'value2'], ...]

store them as:

[ 'opts', [ 'key1' 'value1'], ['opts', [ 'key2', 'value2']], ...

Signed-off-by: Simon Horman <horms@verge.net.au>
author Keir Fraser <keir.fraser@citrix.com>
date Tue Jun 16 11:37:41 2009 +0100 (2009-06-16)
parents 08de8ec655c2
children 11c3f4e786b3
rev   line source
kaf24@8880 1 #!/usr/bin/env python
kaf24@8880 2 #
kaf24@8880 3 # PCI Device Information Class
kaf24@8880 4 # - Helps obtain information about which I/O resources a PCI device needs
kaf24@8880 5 #
kaf24@8880 6 # Author: Ryan Wilson <hap9@epoch.ncsc.mil>
kaf24@8880 7
kaf24@8880 8 import sys
kaf24@8880 9 import os, os.path
keir@17543 10 import resource
keir@17954 11 import re
keir@17954 12 import types
keir@18049 13 import struct
keir@18049 14 import time
keir@19363 15 import threading
keir@18642 16 from xen.util import utils
keir@19669 17 from xen.xend import sxp
kaf24@8880 18
kaf24@8880 19 PROC_PCI_PATH = '/proc/bus/pci/devices'
kaf24@8880 20 PROC_PCI_NUM_RESOURCES = 7
kaf24@8880 21
kaf24@8880 22 SYSFS_PCI_DEVS_PATH = '/bus/pci/devices'
kaf24@8880 23 SYSFS_PCI_DEV_RESOURCE_PATH = '/resource'
keir@17543 24 SYSFS_PCI_DEV_CONFIG_PATH = '/config'
kaf24@8880 25 SYSFS_PCI_DEV_IRQ_PATH = '/irq'
kaf24@8880 26 SYSFS_PCI_DEV_DRIVER_DIR_PATH = '/driver'
kfraser@10844 27 SYSFS_PCI_DEV_VENDOR_PATH = '/vendor'
kfraser@10844 28 SYSFS_PCI_DEV_DEVICE_PATH = '/device'
kfraser@10844 29 SYSFS_PCI_DEV_SUBVENDOR_PATH = '/subsystem_vendor'
kfraser@10844 30 SYSFS_PCI_DEV_SUBDEVICE_PATH = '/subsystem_device'
keir@17954 31 SYSFS_PCI_DEV_CLASS_PATH = '/class'
keir@18050 32 SYSFS_PCIBACK_PATH = '/bus/pci/drivers/pciback/'
keir@17954 33
keir@17954 34 LSPCI_CMD = 'lspci'
kaf24@8880 35
keir@18049 36 PCI_DEV_REG_EXPRESS_STR = r"[0-9a-fA-F]{4}:[0-9a-fA-F]{2}:[0-9a-fA-F]{2}."+ \
keir@18049 37 r"[0-9a-fA-F]{1}"
keir@18049 38 PCI_DEV_FORMAT_STR = '%04x:%02x:%02x.%01x'
keir@18049 39
keir@18049 40 DEV_TYPE_PCIe_ENDPOINT = 0
keir@18049 41 DEV_TYPE_PCIe_BRIDGE = 1
keir@18049 42 DEV_TYPE_PCI_BRIDGE = 2
keir@18049 43 DEV_TYPE_PCI = 3
keir@18049 44
keir@18374 45 PCI_VENDOR_ID = 0x0
keir@18049 46 PCI_STATUS = 0x6
keir@18049 47 PCI_CLASS_DEVICE = 0x0a
keir@18049 48 PCI_CLASS_BRIDGE_PCI = 0x0604
keir@18049 49
keir@18242 50 PCI_HEADER_TYPE = 0x0e
keir@18242 51 PCI_HEADER_TYPE_MASK = 0x7f
keir@18242 52 PCI_HEADER_TYPE_NORMAL = 0
keir@18242 53 PCI_HEADER_TYPE_BRIDGE = 1
keir@18242 54 PCI_HEADER_TYPE_CARDBUS = 2
keir@18242 55
keir@18049 56 PCI_CAPABILITY_LIST = 0x34
keir@18049 57 PCI_CB_BRIDGE_CONTROL = 0x3e
keir@18049 58 PCI_BRIDGE_CTL_BUS_RESET= 0x40
keir@18049 59
keir@18049 60 PCI_CAP_ID_EXP = 0x10
keir@18049 61 PCI_EXP_FLAGS = 0x2
keir@18049 62 PCI_EXP_FLAGS_TYPE = 0x00f0
keir@18049 63 PCI_EXP_TYPE_PCI_BRIDGE = 0x7
keir@18049 64 PCI_EXP_DEVCAP = 0x4
keir@18049 65 PCI_EXP_DEVCAP_FLR = (0x1 << 28)
keir@18049 66 PCI_EXP_DEVCTL = 0x8
keir@18049 67 PCI_EXP_DEVCTL_FLR = (0x1 << 15)
keir@18049 68
keir@18175 69 PCI_CAP_ID_PM = 0x01
keir@18175 70 PCI_PM_CTRL = 4
keir@19247 71 PCI_PM_CTRL_NO_SOFT_RESET = 0x0008
keir@18175 72 PCI_PM_CTRL_STATE_MASK = 0x0003
keir@18175 73 PCI_D3hot = 3
keir@19247 74 PCI_D0hot = 0
keir@18175 75
keir@18374 76 VENDOR_INTEL = 0x8086
keir@18374 77 PCI_CAP_ID_VENDOR_SPECIFIC_CAP = 0x09
keir@18374 78 PCI_CLASS_ID_USB = 0x0c03
keir@18374 79 PCI_USB_FLRCTRL = 0x4
keir@18374 80
keir@18049 81 PCI_CAP_ID_AF = 0x13
keir@18049 82 PCI_AF_CAPs = 0x3
keir@18049 83 PCI_AF_CAPs_TP_FLR = 0x3
keir@18049 84 PCI_AF_CTL = 0x4
keir@18049 85 PCI_AF_CTL_FLR = 0x1
keir@18049 86
keir@18049 87 PCI_BAR_0 = 0x10
keir@18049 88 PCI_BAR_5 = 0x24
keir@18049 89 PCI_BAR_SPACE = 0x01
kaf24@8880 90 PCI_BAR_IO = 0x01
kaf24@8880 91 PCI_BAR_IO_MASK = ~0x03
keir@18049 92 PCI_BAR_MEM = 0x00
kaf24@8880 93 PCI_BAR_MEM_MASK = ~0x0f
keir@17543 94 PCI_STATUS_CAP_MASK = 0x10
keir@17543 95 PCI_STATUS_OFFSET = 0x6
keir@17543 96 PCI_CAP_OFFSET = 0x34
keir@17543 97 MSIX_BIR_MASK = 0x7
keir@17590 98 MSIX_SIZE_MASK = 0x7ff
kaf24@8880 99
keir@17954 100 # Global variable to store information from lspci
keir@17954 101 lspci_info = None
keir@19363 102 lspci_info_lock = threading.RLock()
keir@17954 103
keir@17543 104 #Calculate PAGE_SHIFT: number of bits to shift an address to get the page number
keir@17543 105 PAGE_SIZE = resource.getpagesize()
keir@17543 106 PAGE_SHIFT = 0
keir@17543 107 t = PAGE_SIZE
keir@17543 108 while not (t&1):
keir@17543 109 t>>=1
keir@17543 110 PAGE_SHIFT+=1
keir@17543 111
keir@17543 112 PAGE_MASK=~(PAGE_SIZE - 1)
kaf24@8880 113 # Definitions from Linux: include/linux/pci.h
kaf24@8880 114 def PCI_DEVFN(slot, func):
kaf24@8880 115 return ((((slot) & 0x1f) << 3) | ((func) & 0x07))
kaf24@8880 116
keir@19723 117 def PCI_BDF(domain, bus, slot, func):
keir@19723 118 return (((domain & 0xffff) << 16) | ((bus & 0xff) << 8) |
keir@19723 119 PCI_DEVFN(slot, func))
keir@19723 120
keir@19758 121 def check_pci_opts(opts):
keir@19758 122 def f((k, v)):
keir@19758 123 if k not in ['msitranslate', 'power_mgmt'] or \
keir@19758 124 not v.lower() in ['0', '1', 'yes', 'no']:
keir@19758 125 raise PciDeviceParseError('Invalid pci option %s=%s: ' % (k, v))
keir@19758 126
keir@19758 127 map(f, opts)
keir@19758 128
keir@19681 129 def serialise_pci_opts(opts):
keir@19758 130 return ','.join(map(lambda x: '='.join(x), opts))
keir@19681 131
keir@19681 132 def split_pci_opts(opts):
keir@19758 133 return map(lambda x: x.split('='),
keir@19758 134 filter(lambda x: x != '', opts.split(',')))
keir@19681 135
keir@19755 136 def pci_opts_list_to_sxp(list):
keir@19758 137 return ['dev'] + map(lambda x: ['opts', x], list)
keir@19758 138
keir@19758 139 def pci_opts_list_from_sxp(dev):
keir@19758 140 return map(lambda x: sxp.children(x)[0], sxp.children(dev, 'opts'))
keir@19717 141
keir@17954 142 def parse_hex(val):
keir@17954 143 try:
keir@17954 144 if isinstance(val, types.StringTypes):
keir@17954 145 return int(val, 16)
keir@17954 146 else:
keir@17954 147 return val
keir@17954 148 except ValueError:
keir@17954 149 return None
keir@17954 150
keir@18049 151 def parse_pci_name(pci_name_string):
keir@18216 152 pci_match = re.match(r"((?P<domain>[0-9a-fA-F]{1,4})[:,])?" + \
keir@18216 153 r"(?P<bus>[0-9a-fA-F]{1,2})[:,]" + \
keir@18216 154 r"(?P<slot>[0-9a-fA-F]{1,2})[.,]" + \
keir@18216 155 r"(?P<func>[0-7])$", pci_name_string)
keir@18216 156 if pci_match is None:
keir@18216 157 raise PciDeviceParseError(('Failed to parse pci device name: %s' %
keir@18216 158 pci_name_string))
keir@18216 159 pci_dev_info = pci_match.groupdict('0')
keir@18216 160
keir@18216 161 domain = parse_hex(pci_dev_info['domain'])
keir@18216 162 bus = parse_hex(pci_dev_info['bus'])
keir@18216 163 slot = parse_hex(pci_dev_info['slot'])
keir@18216 164 func = parse_hex(pci_dev_info['func'])
keir@18216 165
keir@18216 166 return (domain, bus, slot, func)
keir@19642 167
keir@19726 168 def extract_the_exact_pci_names(pci_names):
keir@19726 169 result = []
keir@19739 170
keir@19739 171 if isinstance(pci_names, types.StringTypes):
keir@19739 172 pci_names = pci_names.split()
keir@19739 173 elif isinstance(pci_names, types.ListType):
keir@19739 174 pci_names = re.findall(PCI_DEV_REG_EXPRESS_STR, '%s' % pci_names)
keir@19739 175 else:
keir@19739 176 raise PciDeviceParseError('Invalid argument: %s' % pci_names)
keir@19739 177
keir@19726 178 for pci in pci_names:
keir@19726 179 # The length of DDDD:bb:dd.f is 12.
keir@19726 180 if len(pci) != 12:
keir@19726 181 continue
keir@19726 182 if re.match(PCI_DEV_REG_EXPRESS_STR, pci) is None:
keir@19726 183 continue
keir@19726 184 result = result + [pci]
keir@19726 185 return result
keir@19726 186
kaf24@8880 187 def find_sysfs_mnt():
keir@18047 188 try:
keir@18642 189 return utils.find_sysfs_mount()
keir@18047 190 except IOError, (errno, strerr):
keir@18047 191 raise PciDeviceParseError(('Failed to locate sysfs mount: %s: %s (%d)'%
keir@18047 192 (PROC_PCI_PATH, strerr, errno)))
kaf24@8880 193 return None
kaf24@8880 194
keir@17954 195 def get_all_pci_names():
keir@18047 196 sysfs_mnt = find_sysfs_mnt()
keir@17954 197 pci_names = os.popen('ls ' + sysfs_mnt + SYSFS_PCI_DEVS_PATH).read().split()
keir@17954 198 return pci_names
keir@17954 199
keir@17954 200 def get_all_pci_devices():
keir@17954 201 pci_devs = []
keir@17954 202 for pci_name in get_all_pci_names():
keir@17954 203 pci_match = re.match(r"((?P<domain>[0-9a-fA-F]{1,4})[:,])?" + \
keir@17954 204 r"(?P<bus>[0-9a-fA-F]{1,2})[:,]" + \
keir@17954 205 r"(?P<slot>[0-9a-fA-F]{1,2})[.,]" + \
keir@17954 206 r"(?P<func>[0-7])$", pci_name)
keir@17954 207 if pci_match is None:
keir@17954 208 raise PciDeviceParseError(('Failed to parse pci device name: %s' %
keir@17954 209 pci_name))
keir@17954 210 pci_dev_info = pci_match.groupdict('0')
keir@17954 211 domain = parse_hex(pci_dev_info['domain'])
keir@17954 212 bus = parse_hex(pci_dev_info['bus'])
keir@17954 213 slot = parse_hex(pci_dev_info['slot'])
keir@17954 214 func = parse_hex(pci_dev_info['func'])
keir@17954 215 try:
keir@17954 216 pci_dev = PciDevice(domain, bus, slot, func)
keir@17954 217 except:
keir@17954 218 continue
keir@17954 219 pci_devs.append(pci_dev)
keir@17954 220
keir@17954 221 return pci_devs
keir@17954 222
keir@19363 223 def _create_lspci_info():
keir@19363 224 """Execute 'lspci' command and parse the result.
keir@19363 225 If the command does not exist, lspci_info will be kept blank ({}).
keir@19363 226
keir@19363 227 Expects to be protected by lspci_info_lock.
keir@19363 228 """
keir@17954 229 global lspci_info
keir@19363 230
keir@17954 231 lspci_info = {}
keir@17954 232
keir@18216 233 for paragraph in os.popen(LSPCI_CMD + ' -vmm').read().split('\n\n'):
keir@17954 234 device_name = None
keir@17954 235 device_info = {}
keir@17954 236 for line in paragraph.split('\n'):
keir@17954 237 try:
keir@17954 238 (opt, value) = line.split(':\t')
keir@17954 239 if opt == 'Slot':
keir@18216 240 device_name = PCI_DEV_FORMAT_STR % parse_pci_name(value)
keir@17954 241 else:
keir@17954 242 device_info[opt] = value
keir@17954 243 except:
keir@17954 244 pass
keir@17954 245 if device_name is not None:
keir@17954 246 lspci_info[device_name] = device_info
keir@17954 247
keir@19363 248 def create_lspci_info():
keir@19363 249 global lspci_info_lock
keir@19363 250 lspci_info_lock.acquire()
keir@19363 251 try:
keir@19363 252 _create_lspci_info()
keir@19363 253 finally:
keir@19363 254 lspci_info_lock.release()
keir@19363 255
keir@18049 256 def save_pci_conf_space(devs_string):
keir@18049 257 pci_list = []
keir@18049 258 cfg_list = []
keir@18049 259 sysfs_mnt = find_sysfs_mnt()
keir@18049 260 for pci_str in devs_string:
keir@18049 261 pci_path = sysfs_mnt + SYSFS_PCI_DEVS_PATH + '/' + pci_str + \
keir@18049 262 SYSFS_PCI_DEV_CONFIG_PATH
keir@18049 263 fd = os.open(pci_path, os.O_RDONLY)
keir@18049 264 configs = []
keir@18049 265 for i in range(0, 256, 4):
keir@18049 266 configs = configs + [os.read(fd,4)]
keir@18049 267 os.close(fd)
keir@18049 268 pci_list = pci_list + [pci_path]
keir@18049 269 cfg_list = cfg_list + [configs]
keir@18049 270 return (pci_list, cfg_list)
keir@18049 271
keir@18049 272 def restore_pci_conf_space(pci_cfg_list):
keir@18049 273 pci_list = pci_cfg_list[0]
keir@18049 274 cfg_list = pci_cfg_list[1]
keir@18049 275 for i in range(0, len(pci_list)):
keir@18049 276 pci_path = pci_list[i]
keir@18049 277 configs = cfg_list[i]
keir@18049 278 fd = os.open(pci_path, os.O_WRONLY)
keir@18049 279 for dw in configs:
keir@18049 280 os.write(fd, dw)
keir@18049 281 os.close(fd)
keir@18049 282
keir@18050 283 def find_all_devices_owned_by_pciback():
keir@18050 284 sysfs_mnt = find_sysfs_mnt()
keir@18050 285 pciback_path = sysfs_mnt + SYSFS_PCIBACK_PATH
keir@18050 286 pci_names = os.popen('ls ' + pciback_path).read()
keir@19726 287 pci_list = extract_the_exact_pci_names(pci_names)
keir@18050 288 dev_list = []
keir@18050 289 for pci in pci_list:
keir@18050 290 (dom, b, d, f) = parse_pci_name(pci)
keir@18050 291 dev = PciDevice(dom, b, d, f)
keir@18050 292 dev_list = dev_list + [dev]
keir@18050 293 return dev_list
keir@18050 294
keir@18050 295 def transform_list(target, src):
keir@19247 296 ''' src: its element is pci string (Format: xxxx:xx:xx.x).
keir@18050 297 target: its element is pci string, or a list of pci string.
keir@18050 298
keir@18050 299 If all the elements in src are in target, we remove them from target
keir@18050 300 and add src into target; otherwise, we remove from target all the
keir@18050 301 elements that also appear in src.
keir@18050 302 '''
keir@18050 303 result = []
keir@18050 304 target_contains_src = True
keir@18050 305 for e in src:
keir@18050 306 if not e in target:
keir@18050 307 target_contains_src = False
keir@18050 308 break
keir@18050 309
keir@18050 310 if target_contains_src:
keir@18050 311 result = result + [src]
keir@18050 312 for e in target:
keir@18050 313 if not e in src:
keir@18050 314 result = result + [e]
keir@18050 315 return result
keir@18050 316
keir@18050 317 def check_FLR_capability(dev_list):
keir@18175 318 if len(dev_list) == 0:
keir@18050 319 return []
keir@18050 320
keir@18050 321 pci_list = []
keir@18050 322 pci_dev_dict = {}
keir@18050 323 for dev in dev_list:
keir@18050 324 pci_list = pci_list + [dev.name]
keir@18050 325 pci_dev_dict[dev.name] = dev
keir@18050 326
keir@18050 327 while True:
keir@18050 328 need_transform = False
keir@18050 329 for pci in pci_list:
keir@18050 330 if isinstance(pci, types.StringTypes):
keir@18050 331 dev = pci_dev_dict[pci]
keir@18175 332 if dev.bus == 0:
keir@18175 333 continue
keir@18050 334 if dev.dev_type == DEV_TYPE_PCIe_ENDPOINT and not dev.pcie_flr:
keir@18050 335 coassigned_pci_list = dev.find_all_the_multi_functions()
keir@18050 336 need_transform = True
keir@18050 337 elif dev.dev_type == DEV_TYPE_PCI and not dev.pci_af_flr:
keir@18982 338 coassigned_pci_list = dev.find_coassigned_pci_devices(True)
keir@18050 339 del coassigned_pci_list[0]
keir@18050 340 need_transform = True
keir@18050 341
keir@18050 342 if need_transform:
keir@18050 343 pci_list = transform_list(pci_list, coassigned_pci_list)
keir@18050 344 if not need_transform:
keir@18050 345 break
keir@18050 346
keir@18050 347 if len(pci_list) == 0:
keir@18050 348 return []
keir@18050 349
keir@18050 350 for i in range(0, len(pci_list)):
keir@18050 351 if isinstance(pci_list[i], types.StringTypes):
keir@18050 352 pci_list[i] = [pci_list[i]]
keir@18050 353
keir@18050 354 # Now every element in pci_list is a list of pci string.
keir@18050 355
keir@18050 356 result = []
keir@18050 357 for pci_names in pci_list:
keir@18050 358 devs = []
keir@18050 359 for pci in pci_names:
keir@18050 360 devs = devs + [pci_dev_dict[pci]]
keir@18050 361 result = result + [devs]
keir@18050 362 return result
keir@18050 363
keir@18050 364 def check_mmio_bar(devs_list):
keir@18050 365 result = []
keir@18050 366
keir@18050 367 for dev_list in devs_list:
keir@18050 368 non_aligned_bar_found = False
keir@18050 369 for dev in dev_list:
keir@18050 370 if dev.has_non_page_aligned_bar:
keir@18050 371 non_aligned_bar_found = True
keir@18050 372 break
keir@18050 373 if not non_aligned_bar_found:
keir@18050 374 result = result + [dev_list]
keir@18050 375
keir@18050 376 return result
keir@18050 377
kaf24@8880 378 class PciDeviceNotFoundError(Exception):
kaf24@8880 379 def __init__(self,domain,bus,slot,func):
kaf24@8880 380 self.domain = domain
kaf24@8880 381 self.bus = bus
kaf24@8880 382 self.slot = slot
kaf24@8880 383 self.func = func
keir@18049 384 self.name = PCI_DEV_FORMAT_STR %(domain, bus, slot, func)
kaf24@8880 385
kaf24@8880 386 def __str__(self):
kaf24@8880 387 return ('PCI Device %s Not Found' % (self.name))
kaf24@8880 388
kaf24@8880 389 class PciDeviceParseError(Exception):
kaf24@8880 390 def __init__(self,msg):
kaf24@8880 391 self.message = msg
kaf24@8880 392 def __str__(self):
kaf24@8880 393 return 'Error Parsing PCI Device Info: '+self.message
kaf24@8880 394
keir@18049 395 class PciDeviceAssignmentError(Exception):
keir@18049 396 def __init__(self,msg):
keir@18049 397 self.message = msg
keir@18049 398 def __str__(self):
keir@19698 399 return 'pci: improper device assignment specified: ' + \
keir@18049 400 self.message
keir@18049 401
keir@19642 402 class PciDeviceVslotMissing(Exception):
keir@19642 403 def __init__(self,msg):
keir@19642 404 self.message = msg
keir@19642 405 def __str__(self):
keir@19704 406 return 'pci: no vslot: ' + self.message
keir@19642 407
kaf24@8880 408 class PciDevice:
kaf24@8880 409 def __init__(self, domain, bus, slot, func):
kaf24@8880 410 self.domain = domain
kaf24@8880 411 self.bus = bus
kaf24@8880 412 self.slot = slot
kaf24@8880 413 self.func = func
keir@18049 414 self.name = PCI_DEV_FORMAT_STR % (domain, bus, slot, func)
keir@18049 415 self.cfg_space_path = find_sysfs_mnt()+SYSFS_PCI_DEVS_PATH+'/'+ \
keir@18049 416 self.name + SYSFS_PCI_DEV_CONFIG_PATH
kaf24@8880 417 self.irq = 0
kaf24@8880 418 self.iomem = []
kaf24@8880 419 self.ioports = []
kaf24@8880 420 self.driver = None
kfraser@10844 421 self.vendor = None
kfraser@10844 422 self.device = None
kfraser@10844 423 self.subvendor = None
kfraser@10844 424 self.subdevice = None
keir@17543 425 self.msix = 0
keir@17543 426 self.msix_iomem = []
keir@17954 427 self.revision = 0
keir@17954 428 self.classcode = None
keir@17954 429 self.vendorname = ""
keir@17954 430 self.devicename = ""
keir@17954 431 self.classname = ""
keir@17954 432 self.subvendorname = ""
keir@17954 433 self.subdevicename = ""
keir@18049 434 self.dev_type = None
keir@18049 435 self.has_non_page_aligned_bar = False
keir@18049 436 self.pcie_flr = False
keir@18049 437 self.pci_af_flr = False
keir@18049 438 self.detect_dev_info()
kfraser@10844 439 self.get_info_from_sysfs()
keir@17954 440 self.get_info_from_lspci()
kaf24@8880 441
keir@18049 442 def find_parent(self):
keir@18049 443 # i.e., /sys/bus/pci/devices/0000:00:19.0 or
keir@18049 444 # /sys/bus/pci/devices/0000:03:04.0
keir@18049 445 path = find_sysfs_mnt()+SYSFS_PCI_DEVS_PATH+'/'+ self.name
keir@18049 446 # i.e., ../../../devices/pci0000:00/0000:00:19.0
keir@18049 447 # ../../../devices/pci0000:00/0000:00:02.0/0000:01:00.2/0000:03:04.0
keir@18049 448 try:
keir@18049 449 target = os.readlink(path)
keir@18049 450 lst = target.split('/')
keir@18049 451 parent = lst[len(lst)-2]
keir@18049 452 if parent[0:3] == 'pci':
keir@18609 453 # We have reached the upmost one.
keir@18609 454 return None
keir@18049 455 else:
keir@18049 456 lst = parent.split(':')
keir@18049 457 dom = int(lst[0], 16)
keir@18049 458 bus = int(lst[1], 16)
keir@18049 459 lst = lst[2]
keir@18049 460 lst = lst.split('.')
keir@18049 461 dev = int(lst[0], 16)
keir@18049 462 func = int(lst[1], 16)
keir@18049 463 return (dom, bus, dev, func)
keir@18049 464 except OSError, (errno, strerr):
keir@18049 465 raise PciDeviceParseError('Can not locate the parent of %s',
keir@18049 466 self.name)
keir@18049 467
keir@18049 468 def find_the_uppermost_pci_bridge(self):
keir@18049 469 # Find the uppermost PCI/PCI-X bridge
keir@19450 470 dev = self.find_parent()
keir@19450 471 if dev is None:
keir@19450 472 return None
keir@19450 473 (dom, b, d, f) = dev
keir@18049 474 dev = dev_parent = PciDevice(dom, b, d, f)
keir@18049 475 while dev_parent.dev_type != DEV_TYPE_PCIe_BRIDGE:
keir@18609 476 parent = dev_parent.find_parent()
keir@18609 477 if parent is None:
keir@18609 478 break
keir@18609 479 (dom, b, d, f) = parent
keir@18049 480 dev = dev_parent
keir@18049 481 dev_parent = PciDevice(dom, b, d, f)
keir@18049 482 return dev
keir@18049 483
keir@18049 484 def find_all_devices_behind_the_bridge(self, ignore_bridge):
keir@18049 485 sysfs_mnt = find_sysfs_mnt()
keir@18049 486 self_path = sysfs_mnt + SYSFS_PCI_DEVS_PATH + '/' + self.name
keir@18049 487 pci_names = os.popen('ls ' + self_path).read()
keir@19726 488 dev_list = extract_the_exact_pci_names(pci_names)
keir@18049 489
keir@18049 490 list = [self.name]
keir@18049 491 for pci_str in dev_list:
keir@18049 492 (dom, b, d, f) = parse_pci_name(pci_str)
keir@18049 493 dev = PciDevice(dom, b, d, f)
keir@18049 494 if dev.dev_type == DEV_TYPE_PCI_BRIDGE or \
keir@18049 495 dev.dev_type == DEV_TYPE_PCIe_BRIDGE:
keir@18049 496 sub_list_including_self = \
keir@18049 497 dev.find_all_devices_behind_the_bridge(ignore_bridge)
keir@18049 498 if ignore_bridge:
keir@18049 499 del sub_list_including_self[0]
keir@18049 500 list = list + [sub_list_including_self]
keir@18049 501 else:
keir@18049 502 list = list + [dev.name]
keir@18049 503 return list
keir@18049 504
keir@18982 505 def find_coassigned_pci_devices(self, ignore_bridge = True):
keir@18049 506 ''' Here'self' is a PCI device, we need find the uppermost PCI/PCI-X
keir@18049 507 bridge, and all devices behind it must be co-assigned to the same
keir@18049 508 guest.
keir@18049 509
keir@18049 510 Parameter:
keir@18049 511 [ignore_bridge]: if set, the returned result doesn't include
keir@18049 512 any bridge behind the uppermost PCI/PCI-X bridge.
keir@18049 513
keir@18049 514 Note: The first element of the return value is the uppermost
keir@18049 515 PCI/PCI-X bridge. If the caller doesn't need the first
keir@18049 516 element, the caller itself can remove it explicitly.
keir@18049 517 '''
keir@18049 518 dev = self.find_the_uppermost_pci_bridge()
keir@19450 519
keir@19450 520 # The 'self' device is on bus0.
keir@19450 521 if dev is None:
keir@19450 522 return [self.name]
keir@19450 523
keir@18049 524 dev_list = dev.find_all_devices_behind_the_bridge(ignore_bridge)
keir@19739 525 dev_list = extract_the_exact_pci_names(dev_list)
keir@18049 526 return dev_list
keir@18049 527
keir@18049 528 def do_secondary_bus_reset(self, target_bus, devs):
keir@18049 529 # Save the config spaces of all the devices behind the bus.
keir@18049 530 (pci_list, cfg_list) = save_pci_conf_space(devs)
keir@18049 531
keir@18049 532 #Do the Secondary Bus Reset
keir@18049 533 sysfs_mnt = find_sysfs_mnt()
keir@18049 534 parent_path = sysfs_mnt + SYSFS_PCI_DEVS_PATH + '/' + \
keir@18049 535 target_bus + SYSFS_PCI_DEV_CONFIG_PATH
keir@18614 536 fd = os.open(parent_path, os.O_RDWR)
keir@18614 537 os.lseek(fd, PCI_CB_BRIDGE_CONTROL, 0)
keir@18614 538 br_cntl = (struct.unpack('H', os.read(fd, 2)))[0]
keir@18049 539 # Assert Secondary Bus Reset
keir@18049 540 os.lseek(fd, PCI_CB_BRIDGE_CONTROL, 0)
keir@18618 541 br_cntl |= PCI_BRIDGE_CTL_BUS_RESET
keir@18618 542 os.write(fd, struct.pack('H', br_cntl))
keir@19247 543 time.sleep(0.100)
keir@18049 544 # De-assert Secondary Bus Reset
keir@18614 545 os.lseek(fd, PCI_CB_BRIDGE_CONTROL, 0)
keir@18618 546 br_cntl &= ~PCI_BRIDGE_CTL_BUS_RESET
keir@18614 547 os.write(fd, struct.pack('H', br_cntl))
keir@19247 548 time.sleep(0.100)
keir@18049 549 os.close(fd)
keir@18049 550
keir@18049 551 # Restore the config spaces
keir@18049 552 restore_pci_conf_space((pci_list, cfg_list))
keir@18049 553
keir@18175 554 def do_Dstate_transition(self):
keir@18175 555 pos = self.find_cap_offset(PCI_CAP_ID_PM)
keir@18175 556 if pos == 0:
keir@18374 557 return False
keir@18175 558
keir@19247 559 # No_Soft_Reset - When set 1, this bit indicates that
keir@19247 560 # devices transitioning from D3hot to D0 because of
keir@19247 561 # PowerState commands do not perform an internal reset.
keir@19247 562 pm_ctl = self.pci_conf_read32(pos + PCI_PM_CTRL)
keir@19247 563 if (pm_ctl & PCI_PM_CTRL_NO_SOFT_RESET) == 1:
keir@19247 564 return False
keir@19247 565
keir@18175 566 (pci_list, cfg_list) = save_pci_conf_space([self.name])
keir@18175 567
keir@19247 568 # Enter D3hot
keir@18175 569 pm_ctl &= ~PCI_PM_CTRL_STATE_MASK
keir@18175 570 pm_ctl |= PCI_D3hot
keir@18175 571 self.pci_conf_write32(pos + PCI_PM_CTRL, pm_ctl)
keir@18175 572 time.sleep(0.010)
keir@18175 573
keir@18175 574 # From D3hot to D0
keir@19247 575 pm_ctl &= ~PCI_PM_CTRL_STATE_MASK
keir@19247 576 pm_ctl |= PCI_D0hot
keir@19247 577 self.pci_conf_write32(pos + PCI_PM_CTRL, pm_ctl)
keir@18175 578 time.sleep(0.010)
keir@18175 579
keir@18175 580 restore_pci_conf_space((pci_list, cfg_list))
keir@18374 581 return True
keir@18374 582
keir@18374 583 def do_vendor_specific_FLR_method(self):
keir@18374 584 pos = self.find_cap_offset(PCI_CAP_ID_VENDOR_SPECIFIC_CAP)
keir@18374 585 if pos == 0:
keir@18374 586 return
keir@18374 587
keir@18374 588 vendor_id = self.pci_conf_read16(PCI_VENDOR_ID)
keir@18374 589 if vendor_id != VENDOR_INTEL:
keir@18374 590 return
keir@18374 591
keir@18374 592 class_id = self.pci_conf_read16(PCI_CLASS_DEVICE)
keir@18374 593 if class_id != PCI_CLASS_ID_USB:
keir@18374 594 return
keir@18374 595
keir@18374 596 (pci_list, cfg_list) = save_pci_conf_space([self.name])
keir@18374 597
keir@18374 598 self.pci_conf_write8(pos + PCI_USB_FLRCTRL, 1)
keir@19247 599 time.sleep(0.100)
keir@18374 600
keir@18374 601 restore_pci_conf_space((pci_list, cfg_list))
keir@18374 602
keir@18374 603 def do_FLR_for_integrated_device(self):
keir@18374 604 if not self.do_Dstate_transition():
keir@18374 605 self.do_vendor_specific_FLR_method()
keir@18175 606
keir@18049 607 def find_all_the_multi_functions(self):
keir@18049 608 sysfs_mnt = find_sysfs_mnt()
keir@19698 609 parent = PCI_DEV_FORMAT_STR % self.find_parent()
keir@19698 610 pci_names = os.popen('ls ' + sysfs_mnt + SYSFS_PCI_DEVS_PATH + '/' + \
keir@19698 611 parent + '/').read()
keir@19726 612 funcs = extract_the_exact_pci_names(pci_names)
keir@18049 613 return funcs
keir@18049 614
keir@18982 615 def find_coassigned_devices(self):
keir@18982 616 if self.dev_type == DEV_TYPE_PCIe_ENDPOINT and not self.pcie_flr:
keir@18982 617 return self.find_all_the_multi_functions()
keir@18982 618 elif self.dev_type == DEV_TYPE_PCI and not self.pci_af_flr:
keir@18982 619 coassigned_pci_list = self.find_coassigned_pci_devices(True)
keir@19450 620 if len(coassigned_pci_list) > 1:
keir@19450 621 del coassigned_pci_list[0]
keir@18982 622 return coassigned_pci_list
keir@18982 623 else:
keir@18982 624 return [self.name]
keir@18982 625
keir@18049 626 def find_cap_offset(self, cap):
keir@18049 627 path = find_sysfs_mnt()+SYSFS_PCI_DEVS_PATH+'/'+ \
keir@18049 628 self.name+SYSFS_PCI_DEV_CONFIG_PATH
keir@18049 629
keir@18049 630 pos = PCI_CAPABILITY_LIST
keir@18049 631
keir@18049 632 try:
keir@18049 633 fd = os.open(path, os.O_RDONLY)
keir@18049 634 os.lseek(fd, PCI_STATUS, 0)
keir@18049 635 status = struct.unpack('H', os.read(fd, 2))[0]
keir@18049 636 if (status & 0x10) == 0:
keir@18049 637 # The device doesn't support PCI_STATUS_CAP_LIST
keir@18049 638 return 0
keir@18049 639
keir@18049 640 max_cap = 48
keir@18049 641 while max_cap > 0:
keir@18049 642 os.lseek(fd, pos, 0)
keir@18049 643 pos = ord(os.read(fd, 1))
keir@18049 644 if pos < 0x40:
keir@18049 645 pos = 0
keir@18049 646 break;
keir@18049 647 os.lseek(fd, pos + 0, 0)
keir@18049 648 id = ord(os.read(fd, 1))
keir@18049 649 if id == 0xff:
keir@18049 650 pos = 0
keir@18049 651 break;
keir@18049 652
keir@18049 653 # Found the capability
keir@18049 654 if id == cap:
keir@18049 655 break;
keir@18049 656
keir@18049 657 # Test the next one
keir@18049 658 pos = pos + 1
keir@18049 659 max_cap = max_cap - 1;
keir@18049 660
keir@18049 661 os.close(fd)
keir@18049 662 except OSError, (errno, strerr):
keir@18049 663 raise PciDeviceParseError(('Error when accessing sysfs: %s (%d)' %
keir@18049 664 (strerr, errno)))
keir@18049 665 return pos
keir@18049 666
keir@18049 667 def pci_conf_read8(self, pos):
keir@18049 668 fd = os.open(self.cfg_space_path, os.O_RDONLY)
keir@18049 669 os.lseek(fd, pos, 0)
keir@18049 670 str = os.read(fd, 1)
keir@18049 671 os.close(fd)
keir@18049 672 val = struct.unpack('B', str)[0]
keir@18049 673 return val
keir@18049 674
keir@18049 675 def pci_conf_read16(self, pos):
keir@18049 676 fd = os.open(self.cfg_space_path, os.O_RDONLY)
keir@18049 677 os.lseek(fd, pos, 0)
keir@18049 678 str = os.read(fd, 2)
keir@18049 679 os.close(fd)
keir@18049 680 val = struct.unpack('H', str)[0]
keir@18049 681 return val
keir@18049 682
keir@18049 683 def pci_conf_read32(self, pos):
keir@18049 684 fd = os.open(self.cfg_space_path, os.O_RDONLY)
keir@18049 685 os.lseek(fd, pos, 0)
keir@18049 686 str = os.read(fd, 4)
keir@18049 687 os.close(fd)
keir@18049 688 val = struct.unpack('I', str)[0]
keir@18049 689 return val
keir@18049 690
keir@18049 691 def pci_conf_write8(self, pos, val):
keir@18049 692 str = struct.pack('B', val)
keir@18049 693 fd = os.open(self.cfg_space_path, os.O_WRONLY)
keir@18049 694 os.lseek(fd, pos, 0)
keir@18049 695 os.write(fd, str)
keir@18049 696 os.close(fd)
keir@18049 697
keir@18049 698 def pci_conf_write16(self, pos, val):
keir@18049 699 str = struct.pack('H', val)
keir@18049 700 fd = os.open(self.cfg_space_path, os.O_WRONLY)
keir@18049 701 os.lseek(fd, pos, 0)
keir@18049 702 os.write(fd, str)
keir@18049 703 os.close(fd)
keir@18049 704
keir@18049 705 def pci_conf_write32(self, pos, val):
keir@18049 706 str = struct.pack('I', val)
keir@18049 707 fd = os.open(self.cfg_space_path, os.O_WRONLY)
keir@18049 708 os.lseek(fd, pos, 0)
keir@18049 709 os.write(fd, str)
keir@18049 710 os.close(fd)
keir@18049 711
keir@18049 712 def detect_dev_info(self):
keir@18049 713 class_dev = self.pci_conf_read16(PCI_CLASS_DEVICE)
keir@18049 714 pos = self.find_cap_offset(PCI_CAP_ID_EXP)
keir@18049 715 if class_dev == PCI_CLASS_BRIDGE_PCI:
keir@18049 716 if pos == 0:
keir@18049 717 self.dev_type = DEV_TYPE_PCI_BRIDGE
keir@18049 718 else:
keir@18049 719 creg = self.pci_conf_read16(pos + PCI_EXP_FLAGS)
keir@19247 720 if ((creg & PCI_EXP_FLAGS_TYPE) >> 4) == \
keir@18049 721 PCI_EXP_TYPE_PCI_BRIDGE:
keir@18049 722 self.dev_type = DEV_TYPE_PCI_BRIDGE
keir@18049 723 else:
keir@18049 724 self.dev_type = DEV_TYPE_PCIe_BRIDGE
keir@18049 725 else:
keir@18049 726 if pos != 0:
keir@18049 727 self.dev_type = DEV_TYPE_PCIe_ENDPOINT
keir@18049 728 else:
keir@18049 729 self.dev_type = DEV_TYPE_PCI
keir@18049 730
keir@18049 731 # Force 0000:00:00.0 to be DEV_TYPE_PCIe_BRIDGE
keir@18049 732 if self.name == '0000:00:00.0':
keir@18049 733 self.dev_type = DEV_TYPE_PCIe_BRIDGE
keir@18049 734
keir@18049 735 if (self.dev_type == DEV_TYPE_PCI_BRIDGE) or \
keir@18049 736 (self.dev_type == DEV_TYPE_PCIe_BRIDGE):
keir@18049 737 return
keir@18049 738
keir@18049 739 # Try to findthe PCIe FLR capability
keir@18049 740 if self.dev_type == DEV_TYPE_PCIe_ENDPOINT:
keir@18049 741 dev_cap = self.pci_conf_read32(pos + PCI_EXP_DEVCAP)
keir@18049 742 if dev_cap & PCI_EXP_DEVCAP_FLR:
keir@18049 743 self.pcie_flr = True
keir@18049 744 elif self.dev_type == DEV_TYPE_PCI:
keir@18049 745 # Try to find the "PCI Advanced Capabilities"
keir@18049 746 pos = self.find_cap_offset(PCI_CAP_ID_AF)
keir@18049 747 if pos != 0:
keir@18049 748 af_cap = self.pci_conf_read8(pos + PCI_AF_CAPs)
keir@18049 749 if (af_cap & PCI_AF_CAPs_TP_FLR) == PCI_AF_CAPs_TP_FLR:
keir@18049 750 self.pci_af_flr = True
keir@18049 751
keir@18049 752 bar_addr = PCI_BAR_0
keir@18049 753 while bar_addr <= PCI_BAR_5:
keir@18049 754 bar = self.pci_conf_read32(bar_addr)
keir@18049 755 if (bar & PCI_BAR_SPACE) == PCI_BAR_MEM:
keir@18049 756 bar = bar & PCI_BAR_MEM_MASK
keir@18049 757 bar = bar & ~PAGE_MASK
keir@18049 758 if bar != 0:
keir@18049 759 self.has_non_page_aligned_bar = True
keir@18049 760 break
keir@18049 761 bar_addr = bar_addr + 4
keir@18049 762
keir@18049 763 def devs_check_driver(self, devs):
keir@18049 764 if len(devs) == 0:
keir@18049 765 return
keir@18049 766 for pci_dev in devs:
keir@18049 767 (dom, b, d, f) = parse_pci_name(pci_dev)
keir@18049 768 dev = PciDevice(dom, b, d, f)
keir@18049 769 if dev.driver == 'pciback':
keir@18049 770 continue
keir@18049 771 err_msg = 'pci: %s must be co-assigned to the same guest with %s' + \
keir@18049 772 ', but it is not owned by pciback.'
keir@18049 773 raise PciDeviceAssignmentError(err_msg % (pci_dev, self.name))
keir@18049 774
keir@18049 775 def do_FLR(self):
keir@18049 776 """ Perform FLR (Functional Level Reset) for the device.
keir@18049 777 """
keir@18049 778 if self.dev_type == DEV_TYPE_PCIe_ENDPOINT:
keir@18049 779 # If PCIe device supports FLR, we use it.
keir@18049 780 if self.pcie_flr:
keir@18049 781 (pci_list, cfg_list) = save_pci_conf_space([self.name])
keir@18049 782 pos = self.find_cap_offset(PCI_CAP_ID_EXP)
keir@18049 783 self.pci_conf_write32(pos + PCI_EXP_DEVCTL, PCI_EXP_DEVCTL_FLR)
keir@18049 784 # We must sleep at least 100ms for the completion of FLR
keir@19247 785 time.sleep(0.100)
keir@18049 786 restore_pci_conf_space((pci_list, cfg_list))
keir@18049 787 else:
keir@18175 788 if self.bus == 0:
keir@18374 789 self.do_FLR_for_integrated_device()
keir@18175 790 else:
keir@18175 791 funcs = self.find_all_the_multi_functions()
keir@18175 792 self.devs_check_driver(funcs)
keir@18049 793
keir@18175 794 parent = '%04x:%02x:%02x.%01x' % self.find_parent()
keir@18049 795
keir@18175 796 # Do Secondary Bus Reset.
keir@18175 797 self.do_secondary_bus_reset(parent, funcs)
keir@18049 798 # PCI devices
keir@18049 799 else:
keir@18049 800 # For PCI device on host bus, we test "PCI Advanced Capabilities".
keir@18049 801 if self.bus == 0 and self.pci_af_flr:
keir@18049 802 (pci_list, cfg_list) = save_pci_conf_space([self.name])
keir@18049 803 # We use Advanced Capability to do FLR.
keir@18049 804 pos = self.find_cap_offset(PCI_CAP_ID_AF)
keir@18049 805 self.pci_conf_write8(pos + PCI_AF_CTL, PCI_AF_CTL_FLR)
keir@19247 806 time.sleep(0.100)
keir@18049 807 restore_pci_conf_space((pci_list, cfg_list))
keir@18049 808 else:
keir@18049 809 if self.bus == 0:
keir@18374 810 self.do_FLR_for_integrated_device()
keir@18049 811 else:
keir@18982 812 devs = self.find_coassigned_pci_devices(False)
keir@18049 813 # Remove the element 0 which is a bridge
keir@18049 814 target_bus = devs[0]
keir@18049 815 del devs[0]
keir@18049 816 self.devs_check_driver(devs)
keir@18049 817
keir@18049 818 # Do Secondary Bus Reset.
keir@18049 819 self.do_secondary_bus_reset(target_bus, devs)
keir@18049 820
keir@17543 821 def find_capability(self, type):
keir@18047 822 sysfs_mnt = find_sysfs_mnt()
keir@17543 823 if sysfs_mnt == None:
keir@17543 824 return False
keir@17543 825 path = sysfs_mnt+SYSFS_PCI_DEVS_PATH+'/'+ \
keir@17543 826 self.name+SYSFS_PCI_DEV_CONFIG_PATH
keir@17543 827 try:
keir@17543 828 conf_file = open(path, 'rb')
keir@18242 829 conf_file.seek(PCI_HEADER_TYPE)
keir@18242 830 header_type = ord(conf_file.read(1)) & PCI_HEADER_TYPE_MASK
keir@18242 831 if header_type == PCI_HEADER_TYPE_CARDBUS:
keir@18242 832 return
keir@17543 833 conf_file.seek(PCI_STATUS_OFFSET)
keir@17543 834 status = ord(conf_file.read(1))
keir@17543 835 if status&PCI_STATUS_CAP_MASK:
keir@17543 836 conf_file.seek(PCI_CAP_OFFSET)
keir@17543 837 capa_pointer = ord(conf_file.read(1))
keir@18242 838 capa_count = 0
keir@17543 839 while capa_pointer:
keir@18242 840 if capa_pointer < 0x40:
keir@18242 841 raise PciDeviceParseError(
keir@18242 842 ('Broken capability chain: %s' % self.name))
keir@18242 843 capa_count += 1
keir@18242 844 if capa_count > 96:
keir@18242 845 raise PciDeviceParseError(
keir@18242 846 ('Looped capability chain: %s' % self.name))
keir@17543 847 conf_file.seek(capa_pointer)
keir@17543 848 capa_id = ord(conf_file.read(1))
keir@17543 849 capa_pointer = ord(conf_file.read(1))
keir@17543 850 if capa_id == type:
keir@17543 851 # get the type
keir@17543 852 message_cont_lo = ord(conf_file.read(1))
keir@17543 853 message_cont_hi = ord(conf_file.read(1))
keir@17543 854 self.msix=1
keir@17574 855 self.msix_entries = (message_cont_lo + \
keir@17590 856 (message_cont_hi << 8)) \
keir@17574 857 & MSIX_SIZE_MASK
keir@17543 858 t_off=conf_file.read(4)
keir@17543 859 p_off=conf_file.read(4)
keir@17543 860 self.table_offset=ord(t_off[0]) | (ord(t_off[1])<<8) | \
keir@17543 861 (ord(t_off[2])<<16)| \
keir@17543 862 (ord(t_off[3])<<24)
keir@17543 863 self.pba_offset=ord(p_off[0]) | (ord(p_off[1]) << 8)| \
keir@17543 864 (ord(p_off[2])<<16) | \
keir@17543 865 (ord(p_off[3])<<24)
keir@17543 866 self.table_index = self.table_offset & MSIX_BIR_MASK
keir@17543 867 self.table_offset = self.table_offset & ~MSIX_BIR_MASK
keir@17543 868 self.pba_index = self.pba_offset & MSIX_BIR_MASK
keir@17543 869 self.pba_offset = self.pba_offset & ~MSIX_BIR_MASK
keir@17543 870 break
keir@17543 871 except IOError, (errno, strerr):
keir@18047 872 raise PciDeviceParseError(('Failed to locate sysfs mount: %s: %s (%d)' %
keir@17543 873 (PROC_PCI_PATH, strerr, errno)))
keir@17543 874
keir@17543 875 def remove_msix_iomem(self, index, start, size):
keir@17543 876 if (index == self.table_index):
keir@17543 877 table_start = start+self.table_offset
keir@17543 878 table_end = table_start + self.msix_entries * 16
keir@17543 879 table_start = table_start & PAGE_MASK
keir@17543 880 table_end = (table_end + PAGE_SIZE) & PAGE_MASK
keir@17543 881 self.msix_iomem.append((table_start, table_end-table_start))
keir@17543 882 if (index==self.pba_index):
keir@17543 883 pba_start = start + self.pba_offset
keir@17543 884 pba_end = pba_start + self.msix_entries/8
keir@17543 885 pba_start = pba_start & PAGE_MASK
keir@17543 886 pba_end = (pba_end + PAGE_SIZE) & PAGE_MASK
keir@17543 887 self.msix_iomem.append((pba_start, pba_end-pba_start))
keir@17543 888
kaf24@8880 889 def get_info_from_sysfs(self):
keir@17543 890 self.find_capability(0x11)
keir@18047 891 sysfs_mnt = find_sysfs_mnt()
kaf24@8880 892 if sysfs_mnt == None:
kaf24@8880 893 return False
kaf24@8880 894
kaf24@8880 895 path = sysfs_mnt+SYSFS_PCI_DEVS_PATH+'/'+ \
kaf24@8880 896 self.name+SYSFS_PCI_DEV_RESOURCE_PATH
kaf24@8880 897 try:
kaf24@8880 898 resource_file = open(path,'r')
kaf24@8880 899
kfraser@10844 900 for i in range(PROC_PCI_NUM_RESOURCES):
kaf24@8880 901 line = resource_file.readline()
kaf24@8880 902 sline = line.split()
kaf24@8880 903 if len(sline)<3:
kaf24@8880 904 continue
kaf24@8880 905
kaf24@8880 906 start = int(sline[0],16)
kaf24@8880 907 end = int(sline[1],16)
kaf24@8880 908 flags = int(sline[2],16)
kaf24@8880 909 size = end-start+1
kaf24@8880 910
kaf24@8880 911 if start!=0:
kaf24@8880 912 if flags&PCI_BAR_IO:
kaf24@8880 913 self.ioports.append( (start,size) )
kaf24@8880 914 else:
kaf24@8880 915 self.iomem.append( (start,size) )
keir@17543 916 if (self.msix):
keir@17543 917 self.remove_msix_iomem(i, start, size)
keir@17543 918
keir@17543 919
kaf24@8880 920
kaf24@8880 921 except IOError, (errno, strerr):
kaf24@8880 922 raise PciDeviceParseError(('Failed to open & read %s: %s (%d)' %
kaf24@8880 923 (path, strerr, errno)))
kaf24@8880 924
kaf24@8880 925 path = sysfs_mnt+SYSFS_PCI_DEVS_PATH+'/'+ \
kaf24@8880 926 self.name+SYSFS_PCI_DEV_IRQ_PATH
kaf24@8880 927 try:
kaf24@8880 928 self.irq = int(open(path,'r').readline())
kaf24@8880 929 except IOError, (errno, strerr):
kaf24@8880 930 raise PciDeviceParseError(('Failed to open & read %s: %s (%d)' %
kaf24@8880 931 (path, strerr, errno)))
kaf24@8880 932
kaf24@8880 933 path = sysfs_mnt+SYSFS_PCI_DEVS_PATH+'/'+ \
kaf24@8880 934 self.name+SYSFS_PCI_DEV_DRIVER_DIR_PATH
kaf24@8880 935 try:
kaf24@8880 936 self.driver = os.path.basename(os.readlink(path))
keir@17954 937 except OSError, (errno, strerr):
keir@17954 938 self.driver = ""
kaf24@8880 939
kfraser@10844 940 path = sysfs_mnt+SYSFS_PCI_DEVS_PATH+'/'+ \
kfraser@10844 941 self.name+SYSFS_PCI_DEV_VENDOR_PATH
kaf24@8880 942 try:
kfraser@10844 943 self.vendor = int(open(path,'r').readline(), 16)
kaf24@8880 944 except IOError, (errno, strerr):
kfraser@10844 945 raise PciDeviceParseError(('Failed to open & read %s: %s (%d)' %
kfraser@10844 946 (path, strerr, errno)))
kaf24@8880 947
kfraser@10844 948 path = sysfs_mnt+SYSFS_PCI_DEVS_PATH+'/'+ \
kfraser@10844 949 self.name+SYSFS_PCI_DEV_DEVICE_PATH
kfraser@10844 950 try:
kfraser@10844 951 self.device = int(open(path,'r').readline(), 16)
kfraser@10844 952 except IOError, (errno, strerr):
kfraser@10844 953 raise PciDeviceParseError(('Failed to open & read %s: %s (%d)' %
kfraser@10844 954 (path, strerr, errno)))
kaf24@8880 955
kfraser@10844 956 path = sysfs_mnt+SYSFS_PCI_DEVS_PATH+'/'+ \
kfraser@10844 957 self.name+SYSFS_PCI_DEV_SUBVENDOR_PATH
kfraser@10844 958 try:
kfraser@10844 959 self.subvendor = int(open(path,'r').readline(), 16)
kfraser@10844 960 except IOError, (errno, strerr):
kfraser@10844 961 raise PciDeviceParseError(('Failed to open & read %s: %s (%d)' %
kfraser@10844 962 (path, strerr, errno)))
kaf24@8880 963
kfraser@10844 964 path = sysfs_mnt+SYSFS_PCI_DEVS_PATH+'/'+ \
kfraser@10844 965 self.name+SYSFS_PCI_DEV_SUBDEVICE_PATH
kfraser@10844 966 try:
kfraser@10844 967 self.subdevice = int(open(path,'r').readline(), 16)
kfraser@10844 968 except IOError, (errno, strerr):
kfraser@10844 969 raise PciDeviceParseError(('Failed to open & read %s: %s (%d)' %
kfraser@10844 970 (path, strerr, errno)))
kfraser@10844 971
keir@17954 972 path = sysfs_mnt+SYSFS_PCI_DEVS_PATH+'/'+ \
keir@17954 973 self.name+SYSFS_PCI_DEV_CLASS_PATH
keir@17954 974 try:
keir@17954 975 self.classcode = int(open(path,'r').readline(), 16)
keir@17954 976 except IOError, (errno, strerr):
keir@17954 977 raise PciDeviceParseError(('Failed to open & read %s: %s (%d)' %
keir@17954 978 (path, strerr, errno)))
keir@17954 979
keir@17954 980 return True
keir@17954 981
keir@17954 982 def get_info_from_lspci(self):
keir@17954 983 """ Get information such as vendor name, device name, class name, etc.
keir@17954 984 Since we cannot obtain these data from sysfs, use 'lspci' command.
keir@17954 985 """
keir@17954 986 global lspci_info
keir@19363 987 global lspci_info_lock
keir@17954 988
keir@19363 989 lspci_info_lock.acquire()
keir@17954 990 try:
keir@19363 991 if lspci_info is None:
keir@19363 992 _create_lspci_info()
keir@17954 993
keir@19363 994 try:
keir@19363 995 device_info = lspci_info[self.name]
keir@19363 996 self.revision = int(device_info['Rev'], 16)
keir@19363 997 self.vendorname = device_info['Vendor']
keir@19363 998 self.devicename = device_info['Device']
keir@19363 999 self.classname = device_info['Class']
keir@19363 1000 self.subvendorname = device_info['SVendor']
keir@19363 1001 self.subdevicename = device_info['SDevice']
keir@19363 1002 except KeyError:
keir@19363 1003 pass
keir@19363 1004
keir@19363 1005 return True
keir@19363 1006 finally:
keir@19363 1007 lspci_info_lock.release()
kaf24@8880 1008
kaf24@8880 1009 def __str__(self):
kaf24@8880 1010 str = "PCI Device %s\n" % (self.name)
kaf24@8880 1011 for (start,size) in self.ioports:
kaf24@8880 1012 str = str + "IO Port 0x%02x [size=%d]\n"%(start,size)
kaf24@8880 1013 for (start,size) in self.iomem:
kaf24@8880 1014 str = str + "IO Mem 0x%02x [size=%d]\n"%(start,size)
kfraser@10844 1015 str = str + "IRQ %d\n"%(self.irq)
kfraser@10844 1016 str = str + "Vendor ID 0x%04x\n"%(self.vendor)
kfraser@10844 1017 str = str + "Device ID 0x%04x\n"%(self.device)
kfraser@10844 1018 str = str + "Sybsystem Vendor ID 0x%04x\n"%(self.subvendor)
kfraser@10844 1019 str = str + "Subsystem Device ID 0x%04x"%(self.subdevice)
kaf24@8880 1020 return str
kaf24@8880 1021
kaf24@8880 1022 def main():
kaf24@8880 1023 if len(sys.argv)<5:
keir@18049 1024 print "Usage: %s <domain> <bus> <slot> <func>\n" % sys.argv[0]
kaf24@8880 1025 sys.exit(2)
kaf24@8880 1026
kaf24@8880 1027 dev = PciDevice(int(sys.argv[1],16), int(sys.argv[2],16),
kaf24@8880 1028 int(sys.argv[3],16), int(sys.argv[4],16))
kaf24@8880 1029 print str(dev)
kaf24@8880 1030
kaf24@8880 1031 if __name__=='__main__':
kaf24@8880 1032 main()