ia64/xen-unstable

view tools/python/xen/util/pci.py @ 18216:8182a85460f7

xend: Fix portability issue of lspci option.

Signed-off-by: Yosuke Iwamatsu <y-iwamatsu@ab.jp.nec.com>
author Keir Fraser <keir.fraser@citrix.com>
date Thu Jul 31 12:39:56 2008 +0100 (2008-07-31)
parents 13690b68fd46
children 9113b3bacfac
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_STATUS = 0x6
44 PCI_CLASS_DEVICE = 0x0a
45 PCI_CLASS_BRIDGE_PCI = 0x0604
47 PCI_CAPABILITY_LIST = 0x34
48 PCI_CB_BRIDGE_CONTROL = 0x3e
49 PCI_BRIDGE_CTL_BUS_RESET= 0x40
51 PCI_CAP_ID_EXP = 0x10
52 PCI_EXP_FLAGS = 0x2
53 PCI_EXP_FLAGS_TYPE = 0x00f0
54 PCI_EXP_TYPE_PCI_BRIDGE = 0x7
55 PCI_EXP_DEVCAP = 0x4
56 PCI_EXP_DEVCAP_FLR = (0x1 << 28)
57 PCI_EXP_DEVCTL = 0x8
58 PCI_EXP_DEVCTL_FLR = (0x1 << 15)
60 PCI_CAP_ID_PM = 0x01
61 PCI_PM_CTRL = 4
62 PCI_PM_CTRL_NO_SOFT_RESET = 0x0004
63 PCI_PM_CTRL_STATE_MASK = 0x0003
64 PCI_D3hot = 3
66 PCI_CAP_ID_AF = 0x13
67 PCI_AF_CAPs = 0x3
68 PCI_AF_CAPs_TP_FLR = 0x3
69 PCI_AF_CTL = 0x4
70 PCI_AF_CTL_FLR = 0x1
72 PCI_BAR_0 = 0x10
73 PCI_BAR_5 = 0x24
74 PCI_BAR_SPACE = 0x01
75 PCI_BAR_IO = 0x01
76 PCI_BAR_IO_MASK = ~0x03
77 PCI_BAR_MEM = 0x00
78 PCI_BAR_MEM_MASK = ~0x0f
79 PCI_STATUS_CAP_MASK = 0x10
80 PCI_STATUS_OFFSET = 0x6
81 PCI_CAP_OFFSET = 0x34
82 MSIX_BIR_MASK = 0x7
83 MSIX_SIZE_MASK = 0x7ff
85 # Global variable to store information from lspci
86 lspci_info = None
88 # Global variable to store the sysfs mount point
89 sysfs_mnt_point = None
91 #Calculate PAGE_SHIFT: number of bits to shift an address to get the page number
92 PAGE_SIZE = resource.getpagesize()
93 PAGE_SHIFT = 0
94 t = PAGE_SIZE
95 while not (t&1):
96 t>>=1
97 PAGE_SHIFT+=1
99 PAGE_MASK=~(PAGE_SIZE - 1)
100 # Definitions from Linux: include/linux/pci.h
101 def PCI_DEVFN(slot, func):
102 return ((((slot) & 0x1f) << 3) | ((func) & 0x07))
104 def parse_hex(val):
105 try:
106 if isinstance(val, types.StringTypes):
107 return int(val, 16)
108 else:
109 return val
110 except ValueError:
111 return None
113 def parse_pci_name(pci_name_string):
114 pci_match = re.match(r"((?P<domain>[0-9a-fA-F]{1,4})[:,])?" + \
115 r"(?P<bus>[0-9a-fA-F]{1,2})[:,]" + \
116 r"(?P<slot>[0-9a-fA-F]{1,2})[.,]" + \
117 r"(?P<func>[0-7])$", pci_name_string)
118 if pci_match is None:
119 raise PciDeviceParseError(('Failed to parse pci device name: %s' %
120 pci_name_string))
121 pci_dev_info = pci_match.groupdict('0')
123 domain = parse_hex(pci_dev_info['domain'])
124 bus = parse_hex(pci_dev_info['bus'])
125 slot = parse_hex(pci_dev_info['slot'])
126 func = parse_hex(pci_dev_info['func'])
128 return (domain, bus, slot, func)
131 def find_sysfs_mnt():
132 global sysfs_mnt_point
133 if not sysfs_mnt_point is None:
134 return sysfs_mnt_point
136 try:
137 mounts_file = open(PROC_MNT_PATH,'r')
139 for line in mounts_file:
140 sline = line.split()
141 if len(sline)<3:
142 continue
143 if sline[2]=='sysfs':
144 sysfs_mnt_point= sline[1]
145 return sysfs_mnt_point
146 except IOError, (errno, strerr):
147 raise PciDeviceParseError(('Failed to locate sysfs mount: %s: %s (%d)'%
148 (PROC_PCI_PATH, strerr, errno)))
149 return None
151 def get_all_pci_names():
152 sysfs_mnt = find_sysfs_mnt()
153 pci_names = os.popen('ls ' + sysfs_mnt + SYSFS_PCI_DEVS_PATH).read().split()
154 return pci_names
156 def get_all_pci_devices():
157 pci_devs = []
158 for pci_name in get_all_pci_names():
159 pci_match = re.match(r"((?P<domain>[0-9a-fA-F]{1,4})[:,])?" + \
160 r"(?P<bus>[0-9a-fA-F]{1,2})[:,]" + \
161 r"(?P<slot>[0-9a-fA-F]{1,2})[.,]" + \
162 r"(?P<func>[0-7])$", pci_name)
163 if pci_match is None:
164 raise PciDeviceParseError(('Failed to parse pci device name: %s' %
165 pci_name))
166 pci_dev_info = pci_match.groupdict('0')
167 domain = parse_hex(pci_dev_info['domain'])
168 bus = parse_hex(pci_dev_info['bus'])
169 slot = parse_hex(pci_dev_info['slot'])
170 func = parse_hex(pci_dev_info['func'])
171 try:
172 pci_dev = PciDevice(domain, bus, slot, func)
173 except:
174 continue
175 pci_devs.append(pci_dev)
177 return pci_devs
179 def create_lspci_info():
180 global lspci_info
181 lspci_info = {}
183 # Execute 'lspci' command and parse the result.
184 # If the command does not exist, lspci_info will be kept blank ({}).
185 for paragraph in os.popen(LSPCI_CMD + ' -vmm').read().split('\n\n'):
186 device_name = None
187 device_info = {}
188 for line in paragraph.split('\n'):
189 try:
190 (opt, value) = line.split(':\t')
191 if opt == 'Slot':
192 device_name = PCI_DEV_FORMAT_STR % parse_pci_name(value)
193 else:
194 device_info[opt] = value
195 except:
196 pass
197 if device_name is not None:
198 lspci_info[device_name] = device_info
200 def save_pci_conf_space(devs_string):
201 pci_list = []
202 cfg_list = []
203 sysfs_mnt = find_sysfs_mnt()
204 for pci_str in devs_string:
205 pci_path = sysfs_mnt + SYSFS_PCI_DEVS_PATH + '/' + pci_str + \
206 SYSFS_PCI_DEV_CONFIG_PATH
207 fd = os.open(pci_path, os.O_RDONLY)
208 configs = []
209 for i in range(0, 256, 4):
210 configs = configs + [os.read(fd,4)]
211 os.close(fd)
212 pci_list = pci_list + [pci_path]
213 cfg_list = cfg_list + [configs]
214 return (pci_list, cfg_list)
216 def restore_pci_conf_space(pci_cfg_list):
217 pci_list = pci_cfg_list[0]
218 cfg_list = pci_cfg_list[1]
219 for i in range(0, len(pci_list)):
220 pci_path = pci_list[i]
221 configs = cfg_list[i]
222 fd = os.open(pci_path, os.O_WRONLY)
223 for dw in configs:
224 os.write(fd, dw)
225 os.close(fd)
227 def find_all_devices_owned_by_pciback():
228 sysfs_mnt = find_sysfs_mnt()
229 pciback_path = sysfs_mnt + SYSFS_PCIBACK_PATH
230 pci_names = os.popen('ls ' + pciback_path).read()
231 pci_list = re.findall(PCI_DEV_REG_EXPRESS_STR, pci_names)
232 dev_list = []
233 for pci in pci_list:
234 (dom, b, d, f) = parse_pci_name(pci)
235 dev = PciDevice(dom, b, d, f)
236 dev_list = dev_list + [dev]
237 return dev_list
239 def transform_list(target, src):
240 ''' src: its element is pci string (Format: xxxx:xx:xx:x).
241 target: its element is pci string, or a list of pci string.
243 If all the elements in src are in target, we remove them from target
244 and add src into target; otherwise, we remove from target all the
245 elements that also appear in src.
246 '''
247 result = []
248 target_contains_src = True
249 for e in src:
250 if not e in target:
251 target_contains_src = False
252 break
254 if target_contains_src:
255 result = result + [src]
256 for e in target:
257 if not e in src:
258 result = result + [e]
259 return result
261 def check_FLR_capability(dev_list):
262 if len(dev_list) == 0:
263 return []
265 pci_list = []
266 pci_dev_dict = {}
267 for dev in dev_list:
268 pci_list = pci_list + [dev.name]
269 pci_dev_dict[dev.name] = dev
271 while True:
272 need_transform = False
273 for pci in pci_list:
274 if isinstance(pci, types.StringTypes):
275 dev = pci_dev_dict[pci]
276 if dev.bus == 0:
277 continue
278 if dev.dev_type == DEV_TYPE_PCIe_ENDPOINT and not dev.pcie_flr:
279 coassigned_pci_list = dev.find_all_the_multi_functions()
280 need_transform = True
281 elif dev.dev_type == DEV_TYPE_PCI and not dev.pci_af_flr:
282 coassigned_pci_list = dev.find_coassigned_devices(True)
283 del coassigned_pci_list[0]
284 need_transform = True
286 if need_transform:
287 pci_list = transform_list(pci_list, coassigned_pci_list)
288 if not need_transform:
289 break
291 if len(pci_list) == 0:
292 return []
294 for i in range(0, len(pci_list)):
295 if isinstance(pci_list[i], types.StringTypes):
296 pci_list[i] = [pci_list[i]]
298 # Now every element in pci_list is a list of pci string.
300 result = []
301 for pci_names in pci_list:
302 devs = []
303 for pci in pci_names:
304 devs = devs + [pci_dev_dict[pci]]
305 result = result + [devs]
306 return result
308 def check_mmio_bar(devs_list):
309 result = []
311 for dev_list in devs_list:
312 non_aligned_bar_found = False
313 for dev in dev_list:
314 if dev.has_non_page_aligned_bar:
315 non_aligned_bar_found = True
316 break
317 if not non_aligned_bar_found:
318 result = result + [dev_list]
320 return result
322 class PciDeviceNotFoundError(Exception):
323 def __init__(self,domain,bus,slot,func):
324 self.domain = domain
325 self.bus = bus
326 self.slot = slot
327 self.func = func
328 self.name = PCI_DEV_FORMAT_STR %(domain, bus, slot, func)
330 def __str__(self):
331 return ('PCI Device %s Not Found' % (self.name))
333 class PciDeviceParseError(Exception):
334 def __init__(self,msg):
335 self.message = msg
336 def __str__(self):
337 return 'Error Parsing PCI Device Info: '+self.message
339 class PciDeviceAssignmentError(Exception):
340 def __init__(self,msg):
341 self.message = msg
342 def __str__(self):
343 return 'pci: impproper device assignment spcified: ' + \
344 self.message
346 class PciDevice:
347 def __init__(self, domain, bus, slot, func):
348 self.domain = domain
349 self.bus = bus
350 self.slot = slot
351 self.func = func
352 self.name = PCI_DEV_FORMAT_STR % (domain, bus, slot, func)
353 self.cfg_space_path = find_sysfs_mnt()+SYSFS_PCI_DEVS_PATH+'/'+ \
354 self.name + SYSFS_PCI_DEV_CONFIG_PATH
355 self.irq = 0
356 self.iomem = []
357 self.ioports = []
358 self.driver = None
359 self.vendor = None
360 self.device = None
361 self.subvendor = None
362 self.subdevice = None
363 self.msix = 0
364 self.msix_iomem = []
365 self.revision = 0
366 self.classcode = None
367 self.vendorname = ""
368 self.devicename = ""
369 self.classname = ""
370 self.subvendorname = ""
371 self.subdevicename = ""
372 self.dev_type = None
373 self.has_non_page_aligned_bar = False
374 self.pcie_flr = False
375 self.pci_af_flr = False
376 self.detect_dev_info()
377 self.get_info_from_sysfs()
378 self.get_info_from_lspci()
380 def find_parent(self):
381 # i.e., /sys/bus/pci/devices/0000:00:19.0 or
382 # /sys/bus/pci/devices/0000:03:04.0
383 path = find_sysfs_mnt()+SYSFS_PCI_DEVS_PATH+'/'+ self.name
384 # i.e., ../../../devices/pci0000:00/0000:00:19.0
385 # ../../../devices/pci0000:00/0000:00:02.0/0000:01:00.2/0000:03:04.0
386 try:
387 target = os.readlink(path)
388 lst = target.split('/')
389 parent = lst[len(lst)-2]
390 if parent[0:3] == 'pci':
391 parent = parent[3:]
392 lst = parent.split(':')
393 dom = int(lst[0], 16)
394 bus = int(lst[1], 16)
395 dev = 0
396 func = 0
397 else:
398 lst = parent.split(':')
399 dom = int(lst[0], 16)
400 bus = int(lst[1], 16)
401 lst = lst[2]
402 lst = lst.split('.')
403 dev = int(lst[0], 16)
404 func = int(lst[1], 16)
405 return (dom, bus, dev, func)
406 except OSError, (errno, strerr):
407 raise PciDeviceParseError('Can not locate the parent of %s',
408 self.name)
410 def find_the_uppermost_pci_bridge(self):
411 # Find the uppermost PCI/PCI-X bridge
412 (dom, b, d, f) = self.find_parent()
413 dev = dev_parent = PciDevice(dom, b, d, f)
414 while dev_parent.dev_type != DEV_TYPE_PCIe_BRIDGE:
415 (dom, b, d, f) = dev_parent.find_parent()
416 dev = dev_parent
417 dev_parent = PciDevice(dom, b, d, f)
418 return dev
420 def find_all_devices_behind_the_bridge(self, ignore_bridge):
421 sysfs_mnt = find_sysfs_mnt()
422 self_path = sysfs_mnt + SYSFS_PCI_DEVS_PATH + '/' + self.name
423 pci_names = os.popen('ls ' + self_path).read()
424 dev_list = re.findall(PCI_DEV_REG_EXPRESS_STR, pci_names)
426 list = [self.name]
427 for pci_str in dev_list:
428 (dom, b, d, f) = parse_pci_name(pci_str)
429 dev = PciDevice(dom, b, d, f)
430 if dev.dev_type == DEV_TYPE_PCI_BRIDGE or \
431 dev.dev_type == DEV_TYPE_PCIe_BRIDGE:
432 sub_list_including_self = \
433 dev.find_all_devices_behind_the_bridge(ignore_bridge)
434 if ignore_bridge:
435 del sub_list_including_self[0]
436 list = list + [sub_list_including_self]
437 else:
438 list = list + [dev.name]
439 return list
441 def find_coassigned_devices(self, ignore_bridge = True):
442 ''' Here'self' is a PCI device, we need find the uppermost PCI/PCI-X
443 bridge, and all devices behind it must be co-assigned to the same
444 guest.
446 Parameter:
447 [ignore_bridge]: if set, the returned result doesn't include
448 any bridge behind the uppermost PCI/PCI-X bridge.
450 Note: The first element of the return value is the uppermost
451 PCI/PCI-X bridge. If the caller doesn't need the first
452 element, the caller itself can remove it explicitly.
453 '''
454 dev = self.find_the_uppermost_pci_bridge()
455 dev_list = dev.find_all_devices_behind_the_bridge(ignore_bridge)
456 dev_list = re.findall(PCI_DEV_REG_EXPRESS_STR, '%s' % dev_list)
457 return dev_list
459 def do_secondary_bus_reset(self, target_bus, devs):
460 # Save the config spaces of all the devices behind the bus.
461 (pci_list, cfg_list) = save_pci_conf_space(devs)
463 #Do the Secondary Bus Reset
464 sysfs_mnt = find_sysfs_mnt()
465 parent_path = sysfs_mnt + SYSFS_PCI_DEVS_PATH + '/' + \
466 target_bus + SYSFS_PCI_DEV_CONFIG_PATH
467 fd = os.open(parent_path, os.O_WRONLY)
468 # Assert Secondary Bus Reset
469 os.lseek(fd, PCI_CB_BRIDGE_CONTROL, 0)
470 os.write(fd, struct.pack('I', PCI_BRIDGE_CTL_BUS_RESET))
471 time.sleep(0.200)
472 # De-assert Secondary Bus Reset
473 os.lseek(fd, 0x3e, 0)
474 os.write(fd, struct.pack('I', 0x00))
475 time.sleep(0.200)
476 os.close(fd)
478 # Restore the config spaces
479 restore_pci_conf_space((pci_list, cfg_list))
481 def do_Dstate_transition(self):
482 pos = self.find_cap_offset(PCI_CAP_ID_PM)
483 if pos == 0:
484 return
486 (pci_list, cfg_list) = save_pci_conf_space([self.name])
488 # Enter D3hot without soft reset
489 pm_ctl = self.pci_conf_read32(pos + PCI_PM_CTRL)
490 pm_ctl |= PCI_PM_CTRL_NO_SOFT_RESET
491 pm_ctl &= ~PCI_PM_CTRL_STATE_MASK
492 pm_ctl |= PCI_D3hot
493 self.pci_conf_write32(pos + PCI_PM_CTRL, pm_ctl)
494 time.sleep(0.010)
496 # From D3hot to D0
497 self.pci_conf_write32(pos + PCI_PM_CTRL, 0)
498 time.sleep(0.010)
500 restore_pci_conf_space((pci_list, cfg_list))
502 def find_all_the_multi_functions(self):
503 sysfs_mnt = find_sysfs_mnt()
504 pci_names = os.popen('ls ' + sysfs_mnt + SYSFS_PCI_DEVS_PATH).read()
505 p = self.name
506 p = p[0 : p.rfind('.')] + '.[0-7]'
507 funcs = re.findall(p, pci_names)
508 return funcs
510 def find_cap_offset(self, cap):
511 path = find_sysfs_mnt()+SYSFS_PCI_DEVS_PATH+'/'+ \
512 self.name+SYSFS_PCI_DEV_CONFIG_PATH
514 pos = PCI_CAPABILITY_LIST
516 try:
517 fd = os.open(path, os.O_RDONLY)
518 os.lseek(fd, PCI_STATUS, 0)
519 status = struct.unpack('H', os.read(fd, 2))[0]
520 if (status & 0x10) == 0:
521 # The device doesn't support PCI_STATUS_CAP_LIST
522 return 0
524 max_cap = 48
525 while max_cap > 0:
526 os.lseek(fd, pos, 0)
527 pos = ord(os.read(fd, 1))
528 if pos < 0x40:
529 pos = 0
530 break;
531 os.lseek(fd, pos + 0, 0)
532 id = ord(os.read(fd, 1))
533 if id == 0xff:
534 pos = 0
535 break;
537 # Found the capability
538 if id == cap:
539 break;
541 # Test the next one
542 pos = pos + 1
543 max_cap = max_cap - 1;
545 os.close(fd)
546 except OSError, (errno, strerr):
547 raise PciDeviceParseError(('Error when accessing sysfs: %s (%d)' %
548 (strerr, errno)))
549 return pos
551 def pci_conf_read8(self, pos):
552 fd = os.open(self.cfg_space_path, os.O_RDONLY)
553 os.lseek(fd, pos, 0)
554 str = os.read(fd, 1)
555 os.close(fd)
556 val = struct.unpack('B', str)[0]
557 return val
559 def pci_conf_read16(self, pos):
560 fd = os.open(self.cfg_space_path, os.O_RDONLY)
561 os.lseek(fd, pos, 0)
562 str = os.read(fd, 2)
563 os.close(fd)
564 val = struct.unpack('H', str)[0]
565 return val
567 def pci_conf_read32(self, pos):
568 fd = os.open(self.cfg_space_path, os.O_RDONLY)
569 os.lseek(fd, pos, 0)
570 str = os.read(fd, 4)
571 os.close(fd)
572 val = struct.unpack('I', str)[0]
573 return val
575 def pci_conf_write8(self, pos, val):
576 str = struct.pack('B', val)
577 fd = os.open(self.cfg_space_path, os.O_WRONLY)
578 os.lseek(fd, pos, 0)
579 os.write(fd, str)
580 os.close(fd)
582 def pci_conf_write16(self, pos, val):
583 str = struct.pack('H', val)
584 fd = os.open(self.cfg_space_path, os.O_WRONLY)
585 os.lseek(fd, pos, 0)
586 os.write(fd, str)
587 os.close(fd)
589 def pci_conf_write32(self, pos, val):
590 str = struct.pack('I', val)
591 fd = os.open(self.cfg_space_path, os.O_WRONLY)
592 os.lseek(fd, pos, 0)
593 os.write(fd, str)
594 os.close(fd)
596 def detect_dev_info(self):
597 class_dev = self.pci_conf_read16(PCI_CLASS_DEVICE)
598 pos = self.find_cap_offset(PCI_CAP_ID_EXP)
599 if class_dev == PCI_CLASS_BRIDGE_PCI:
600 if pos == 0:
601 self.dev_type = DEV_TYPE_PCI_BRIDGE
602 else:
603 creg = self.pci_conf_read16(pos + PCI_EXP_FLAGS)
604 if ((creg & PCI_EXP_TYPE_PCI_BRIDGE) >> 4) == \
605 PCI_EXP_TYPE_PCI_BRIDGE:
606 self.dev_type = DEV_TYPE_PCI_BRIDGE
607 else:
608 self.dev_type = DEV_TYPE_PCIe_BRIDGE
609 else:
610 if pos != 0:
611 self.dev_type = DEV_TYPE_PCIe_ENDPOINT
612 else:
613 self.dev_type = DEV_TYPE_PCI
615 # Force 0000:00:00.0 to be DEV_TYPE_PCIe_BRIDGE
616 if self.name == '0000:00:00.0':
617 self.dev_type = DEV_TYPE_PCIe_BRIDGE
619 if (self.dev_type == DEV_TYPE_PCI_BRIDGE) or \
620 (self.dev_type == DEV_TYPE_PCIe_BRIDGE):
621 return
623 # Try to findthe PCIe FLR capability
624 if self.dev_type == DEV_TYPE_PCIe_ENDPOINT:
625 dev_cap = self.pci_conf_read32(pos + PCI_EXP_DEVCAP)
626 if dev_cap & PCI_EXP_DEVCAP_FLR:
627 self.pcie_flr = True
628 elif self.dev_type == DEV_TYPE_PCI:
629 # Try to find the "PCI Advanced Capabilities"
630 pos = self.find_cap_offset(PCI_CAP_ID_AF)
631 if pos != 0:
632 af_cap = self.pci_conf_read8(pos + PCI_AF_CAPs)
633 if (af_cap & PCI_AF_CAPs_TP_FLR) == PCI_AF_CAPs_TP_FLR:
634 self.pci_af_flr = True
636 bar_addr = PCI_BAR_0
637 while bar_addr <= PCI_BAR_5:
638 bar = self.pci_conf_read32(bar_addr)
639 if (bar & PCI_BAR_SPACE) == PCI_BAR_MEM:
640 bar = bar & PCI_BAR_MEM_MASK
641 bar = bar & ~PAGE_MASK
642 if bar != 0:
643 self.has_non_page_aligned_bar = True
644 break
645 bar_addr = bar_addr + 4
647 def devs_check_driver(self, devs):
648 if len(devs) == 0:
649 return
650 for pci_dev in devs:
651 (dom, b, d, f) = parse_pci_name(pci_dev)
652 dev = PciDevice(dom, b, d, f)
653 if dev.driver == 'pciback':
654 continue
655 err_msg = 'pci: %s must be co-assigned to the same guest with %s' + \
656 ', but it is not owned by pciback.'
657 raise PciDeviceAssignmentError(err_msg % (pci_dev, self.name))
659 def do_FLR(self):
660 """ Perform FLR (Functional Level Reset) for the device.
661 """
662 if self.dev_type == DEV_TYPE_PCIe_ENDPOINT:
663 # If PCIe device supports FLR, we use it.
664 if self.pcie_flr:
665 (pci_list, cfg_list) = save_pci_conf_space([self.name])
666 pos = self.find_cap_offset(PCI_CAP_ID_EXP)
667 self.pci_conf_write32(pos + PCI_EXP_DEVCTL, PCI_EXP_DEVCTL_FLR)
668 # We must sleep at least 100ms for the completion of FLR
669 time.sleep(0.200)
670 restore_pci_conf_space((pci_list, cfg_list))
671 else:
672 if self.bus == 0:
673 self.do_Dstate_transition()
674 else:
675 funcs = self.find_all_the_multi_functions()
676 self.devs_check_driver(funcs)
678 parent = '%04x:%02x:%02x.%01x' % self.find_parent()
680 # Do Secondary Bus Reset.
681 self.do_secondary_bus_reset(parent, funcs)
682 # PCI devices
683 else:
684 # For PCI device on host bus, we test "PCI Advanced Capabilities".
685 if self.bus == 0 and self.pci_af_flr:
686 (pci_list, cfg_list) = save_pci_conf_space([self.name])
687 # We use Advanced Capability to do FLR.
688 pos = self.find_cap_offset(PCI_CAP_ID_AF)
689 self.pci_conf_write8(pos + PCI_AF_CTL, PCI_AF_CTL_FLR)
690 time.sleep(0.200)
691 restore_pci_conf_space((pci_list, cfg_list))
692 else:
693 if self.bus == 0:
694 self.do_Dstate_transition()
695 else:
696 devs = self.find_coassigned_devices(False)
697 # Remove the element 0 which is a bridge
698 target_bus = devs[0]
699 del devs[0]
700 self.devs_check_driver(devs)
702 # Do Secondary Bus Reset.
703 self.do_secondary_bus_reset(target_bus, devs)
705 def find_capability(self, type):
706 sysfs_mnt = find_sysfs_mnt()
707 if sysfs_mnt == None:
708 return False
709 path = sysfs_mnt+SYSFS_PCI_DEVS_PATH+'/'+ \
710 self.name+SYSFS_PCI_DEV_CONFIG_PATH
711 try:
712 conf_file = open(path, 'rb')
713 conf_file.seek(PCI_STATUS_OFFSET)
714 status = ord(conf_file.read(1))
715 if status&PCI_STATUS_CAP_MASK:
716 conf_file.seek(PCI_CAP_OFFSET)
717 capa_pointer = ord(conf_file.read(1))
718 while capa_pointer:
719 conf_file.seek(capa_pointer)
720 capa_id = ord(conf_file.read(1))
721 capa_pointer = ord(conf_file.read(1))
722 if capa_id == type:
723 # get the type
724 message_cont_lo = ord(conf_file.read(1))
725 message_cont_hi = ord(conf_file.read(1))
726 self.msix=1
727 self.msix_entries = (message_cont_lo + \
728 (message_cont_hi << 8)) \
729 & MSIX_SIZE_MASK
730 t_off=conf_file.read(4)
731 p_off=conf_file.read(4)
732 self.table_offset=ord(t_off[0]) | (ord(t_off[1])<<8) | \
733 (ord(t_off[2])<<16)| \
734 (ord(t_off[3])<<24)
735 self.pba_offset=ord(p_off[0]) | (ord(p_off[1]) << 8)| \
736 (ord(p_off[2])<<16) | \
737 (ord(p_off[3])<<24)
738 self.table_index = self.table_offset & MSIX_BIR_MASK
739 self.table_offset = self.table_offset & ~MSIX_BIR_MASK
740 self.pba_index = self.pba_offset & MSIX_BIR_MASK
741 self.pba_offset = self.pba_offset & ~MSIX_BIR_MASK
742 break
743 except IOError, (errno, strerr):
744 raise PciDeviceParseError(('Failed to locate sysfs mount: %s: %s (%d)' %
745 (PROC_PCI_PATH, strerr, errno)))
747 def remove_msix_iomem(self, index, start, size):
748 if (index == self.table_index):
749 table_start = start+self.table_offset
750 table_end = table_start + self.msix_entries * 16
751 table_start = table_start & PAGE_MASK
752 table_end = (table_end + PAGE_SIZE) & PAGE_MASK
753 self.msix_iomem.append((table_start, table_end-table_start))
754 if (index==self.pba_index):
755 pba_start = start + self.pba_offset
756 pba_end = pba_start + self.msix_entries/8
757 pba_start = pba_start & PAGE_MASK
758 pba_end = (pba_end + PAGE_SIZE) & PAGE_MASK
759 self.msix_iomem.append((pba_start, pba_end-pba_start))
761 def get_info_from_sysfs(self):
762 self.find_capability(0x11)
763 sysfs_mnt = find_sysfs_mnt()
764 if sysfs_mnt == None:
765 return False
767 path = sysfs_mnt+SYSFS_PCI_DEVS_PATH+'/'+ \
768 self.name+SYSFS_PCI_DEV_RESOURCE_PATH
769 try:
770 resource_file = open(path,'r')
772 for i in range(PROC_PCI_NUM_RESOURCES):
773 line = resource_file.readline()
774 sline = line.split()
775 if len(sline)<3:
776 continue
778 start = int(sline[0],16)
779 end = int(sline[1],16)
780 flags = int(sline[2],16)
781 size = end-start+1
783 if start!=0:
784 if flags&PCI_BAR_IO:
785 self.ioports.append( (start,size) )
786 else:
787 self.iomem.append( (start,size) )
788 if (self.msix):
789 self.remove_msix_iomem(i, start, size)
793 except IOError, (errno, strerr):
794 raise PciDeviceParseError(('Failed to open & read %s: %s (%d)' %
795 (path, strerr, errno)))
797 path = sysfs_mnt+SYSFS_PCI_DEVS_PATH+'/'+ \
798 self.name+SYSFS_PCI_DEV_IRQ_PATH
799 try:
800 self.irq = int(open(path,'r').readline())
801 except IOError, (errno, strerr):
802 raise PciDeviceParseError(('Failed to open & read %s: %s (%d)' %
803 (path, strerr, errno)))
805 path = sysfs_mnt+SYSFS_PCI_DEVS_PATH+'/'+ \
806 self.name+SYSFS_PCI_DEV_DRIVER_DIR_PATH
807 try:
808 self.driver = os.path.basename(os.readlink(path))
809 except OSError, (errno, strerr):
810 self.driver = ""
812 path = sysfs_mnt+SYSFS_PCI_DEVS_PATH+'/'+ \
813 self.name+SYSFS_PCI_DEV_VENDOR_PATH
814 try:
815 self.vendor = int(open(path,'r').readline(), 16)
816 except IOError, (errno, strerr):
817 raise PciDeviceParseError(('Failed to open & read %s: %s (%d)' %
818 (path, strerr, errno)))
820 path = sysfs_mnt+SYSFS_PCI_DEVS_PATH+'/'+ \
821 self.name+SYSFS_PCI_DEV_DEVICE_PATH
822 try:
823 self.device = int(open(path,'r').readline(), 16)
824 except IOError, (errno, strerr):
825 raise PciDeviceParseError(('Failed to open & read %s: %s (%d)' %
826 (path, strerr, errno)))
828 path = sysfs_mnt+SYSFS_PCI_DEVS_PATH+'/'+ \
829 self.name+SYSFS_PCI_DEV_SUBVENDOR_PATH
830 try:
831 self.subvendor = int(open(path,'r').readline(), 16)
832 except IOError, (errno, strerr):
833 raise PciDeviceParseError(('Failed to open & read %s: %s (%d)' %
834 (path, strerr, errno)))
836 path = sysfs_mnt+SYSFS_PCI_DEVS_PATH+'/'+ \
837 self.name+SYSFS_PCI_DEV_SUBDEVICE_PATH
838 try:
839 self.subdevice = int(open(path,'r').readline(), 16)
840 except IOError, (errno, strerr):
841 raise PciDeviceParseError(('Failed to open & read %s: %s (%d)' %
842 (path, strerr, errno)))
844 path = sysfs_mnt+SYSFS_PCI_DEVS_PATH+'/'+ \
845 self.name+SYSFS_PCI_DEV_CLASS_PATH
846 try:
847 self.classcode = int(open(path,'r').readline(), 16)
848 except IOError, (errno, strerr):
849 raise PciDeviceParseError(('Failed to open & read %s: %s (%d)' %
850 (path, strerr, errno)))
852 return True
854 def get_info_from_lspci(self):
855 """ Get information such as vendor name, device name, class name, etc.
856 Since we cannot obtain these data from sysfs, use 'lspci' command.
857 """
858 global lspci_info
860 if lspci_info is None:
861 create_lspci_info()
863 try:
864 device_info = lspci_info[self.name]
865 self.revision = int(device_info['Rev'], 16)
866 self.vendorname = device_info['Vendor']
867 self.devicename = device_info['Device']
868 self.classname = device_info['Class']
869 self.subvendorname = device_info['SVendor']
870 self.subdevicename = device_info['SDevice']
871 except KeyError:
872 pass
874 return True
876 def __str__(self):
877 str = "PCI Device %s\n" % (self.name)
878 for (start,size) in self.ioports:
879 str = str + "IO Port 0x%02x [size=%d]\n"%(start,size)
880 for (start,size) in self.iomem:
881 str = str + "IO Mem 0x%02x [size=%d]\n"%(start,size)
882 str = str + "IRQ %d\n"%(self.irq)
883 str = str + "Vendor ID 0x%04x\n"%(self.vendor)
884 str = str + "Device ID 0x%04x\n"%(self.device)
885 str = str + "Sybsystem Vendor ID 0x%04x\n"%(self.subvendor)
886 str = str + "Subsystem Device ID 0x%04x"%(self.subdevice)
887 return str
889 def main():
890 if len(sys.argv)<5:
891 print "Usage: %s <domain> <bus> <slot> <func>\n" % sys.argv[0]
892 sys.exit(2)
894 dev = PciDevice(int(sys.argv[1],16), int(sys.argv[2],16),
895 int(sys.argv[3],16), int(sys.argv[4],16))
896 print str(dev)
898 if __name__=='__main__':
899 main()