ia64/xen-unstable

annotate tools/python/xen/util/pci.py @ 19755:08de8ec655c2

xend: pass-through: fix typo: spx -> sxp

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