ia64/xen-unstable

view tools/python/xen/util/pci.py @ 18609:a9be7b357b0b

xend: Fix the detection of the upmost bridge in the python function find_parent().

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