debuggers.hg

view tools/python/xen/util/pci.py @ 20941:729b32b17440

VT-d, tools: Intel IGD passthrough 1/2: vendor-specific FLR

Due to FLR capability of IGD is not exposed on some platforms, this
patch uses vendor specific FLR to reset those IGDs.

Signed-off-by: Weidong Han <weidong.han@intel.com>
author Keir Fraser <keir.fraser@citrix.com>
date Thu Feb 04 09:08:05 2010 +0000 (2010-02-04)
parents cec57fd4565e
children dbe65678b6f8
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 errno
11 import resource
12 import re
13 import types
14 import struct
15 import time
16 import threading
17 from xen.util import utils
18 from xen.xend import uuid
19 from xen.xend import sxp
20 from xen.xend.XendConstants import AUTO_PHP_SLOT
21 from xen.xend.XendSXPDev import dev_dict_to_sxp
22 from xen.xend.XendLogging import log
24 # for 2.3 compatibility
25 try:
26 set()
27 except NameError:
28 from sets import Set as set
30 PROC_PCI_PATH = '/proc/bus/pci/devices'
31 PROC_PCI_NUM_RESOURCES = 7
33 SYSFS_PCI_DEVS_PATH = '/bus/pci/devices'
34 SYSFS_PCI_DEV_RESOURCE_PATH = '/resource'
35 SYSFS_PCI_DEV_CONFIG_PATH = '/config'
36 SYSFS_PCI_DEV_IRQ_PATH = '/irq'
37 SYSFS_PCI_DEV_DRIVER_DIR_PATH = '/driver'
38 SYSFS_PCI_DEV_VENDOR_PATH = '/vendor'
39 SYSFS_PCI_DEV_DEVICE_PATH = '/device'
40 SYSFS_PCI_DEV_SUBVENDOR_PATH = '/subsystem_vendor'
41 SYSFS_PCI_DEV_SUBDEVICE_PATH = '/subsystem_device'
42 SYSFS_PCI_DEV_CLASS_PATH = '/class'
43 SYSFS_PCIBACK_PATH = '/bus/pci/drivers/pciback/'
44 SYSFS_PCISTUB_PATH = '/bus/pci/drivers/pci-stub/'
46 LSPCI_CMD = 'lspci'
48 PCI_DEV_REG_EXPRESS_STR = r"[0-9a-fA-F]{4}:[0-9a-fA-F]{2}:[0-9a-fA-F]{2}."+ \
49 r"[0-9a-fA-F]{1}"
51 DEV_TYPE_PCIe_ENDPOINT = 0
52 DEV_TYPE_PCIe_BRIDGE = 1
53 DEV_TYPE_PCI_BRIDGE = 2
54 DEV_TYPE_PCI = 3
56 PCI_VENDOR_ID = 0x0
57 PCI_STATUS = 0x6
58 PCI_CLASS_DEVICE = 0x0a
59 PCI_CLASS_BRIDGE_PCI = 0x0604
61 PCI_HEADER_TYPE = 0x0e
62 PCI_HEADER_TYPE_MASK = 0x7f
63 PCI_HEADER_TYPE_NORMAL = 0
64 PCI_HEADER_TYPE_BRIDGE = 1
65 PCI_HEADER_TYPE_CARDBUS = 2
67 PCI_CAPABILITY_LIST = 0x34
68 PCI_CB_BRIDGE_CONTROL = 0x3e
69 PCI_BRIDGE_CTL_BUS_RESET= 0x40
71 PCI_CAP_ID_EXP = 0x10
72 PCI_EXP_FLAGS = 0x2
73 PCI_EXP_FLAGS_TYPE = 0x00f0
74 PCI_EXP_TYPE_DOWNSTREAM = 0x6
75 PCI_EXP_TYPE_PCI_BRIDGE = 0x7
76 PCI_EXP_DEVCAP = 0x4
77 PCI_EXP_DEVCAP_FLR = (0x1 << 28)
78 PCI_EXP_DEVCTL = 0x8
79 PCI_EXP_DEVCTL_FLR = (0x1 << 15)
81 PCI_EXT_CAP_ID_ACS = 0x000d
82 PCI_EXT_CAP_ACS_ENABLED = 0x1d # The bits V, R, C, U.
83 PCI_EXT_ACS_CTRL = 0x06
86 PCI_CAP_ID_PM = 0x01
87 PCI_PM_CTRL = 4
88 PCI_PM_CTRL_NO_SOFT_RESET = 0x0008
89 PCI_PM_CTRL_STATE_MASK = 0x0003
90 PCI_D3hot = 3
91 PCI_D0hot = 0
93 VENDOR_INTEL = 0x8086
94 PCI_CAP_ID_VENDOR_SPECIFIC_CAP = 0x09
95 PCI_CLASS_ID_USB = 0x0c03
96 PCI_USB_FLRCTRL = 0x4
98 PCI_DEVICE_ID = 0x02
99 PCI_COMMAND = 0x04
100 PCI_CLASS_ID_VGA = 0x0300
102 PCI_DEVICE_ID_IGFX_GM45 = 0x2a42
103 PCI_DEVICE_ID_IGFX_EAGLELAKE = 0x2e02
104 PCI_DEVICE_ID_IGFX_Q45 = 0x2e12
105 PCI_DEVICE_ID_IGFX_G45 = 0x2e22
106 PCI_DEVICE_ID_IGFX_G41 = 0x2e32
108 PCI_CAP_IGFX_CAP09_OFFSET = 0xa4
109 PCI_CAP_IGFX_CAP13_OFFSET = 0xa4
110 PCI_CAP_IGFX_GDRST = 0X0d
111 PCI_CAP_IGFX_GDRST_OFFSET = 0xc0
113 # The VF of Intel 82599 10GbE Controller
114 # See http://download.intel.com/design/network/datashts/82599_datasheet.pdf
115 # For 'VF PCIe Configuration Space', see its Table 9.7.
116 DEVICE_ID_82599 = 0x10ed
118 PCI_CAP_ID_AF = 0x13
119 PCI_AF_CAPs = 0x3
120 PCI_AF_CAPs_TP_FLR = 0x3
121 PCI_AF_CTL = 0x4
122 PCI_AF_CTL_FLR = 0x1
124 PCI_BAR_0 = 0x10
125 PCI_BAR_5 = 0x24
126 PCI_BAR_SPACE = 0x01
127 PCI_BAR_IO = 0x01
128 PCI_BAR_IO_MASK = ~0x03
129 PCI_BAR_MEM = 0x00
130 PCI_BAR_MEM_MASK = ~0x0f
131 PCI_STATUS_CAP_MASK = 0x10
132 PCI_STATUS_OFFSET = 0x6
133 PCI_CAP_OFFSET = 0x34
134 MSIX_BIR_MASK = 0x7
135 MSIX_SIZE_MASK = 0x7ff
137 # Global variable to store information from lspci
138 lspci_info = None
139 lspci_info_lock = threading.RLock()
141 #Calculate PAGE_SHIFT: number of bits to shift an address to get the page number
142 PAGE_SIZE = resource.getpagesize()
143 PAGE_SHIFT = 0
144 t = PAGE_SIZE
145 while not (t&1):
146 t>>=1
147 PAGE_SHIFT+=1
149 PAGE_MASK=~(PAGE_SIZE - 1)
150 # Definitions from Linux: include/linux/pci.h
151 def PCI_DEVFN(slot, func):
152 return ((((slot) & 0x1f) << 3) | ((func) & 0x07))
153 def PCI_SLOT(devfn):
154 return (devfn >> 3) & 0x1f
155 def PCI_FUNC(devfn):
156 return devfn & 0x7
158 def PCI_BDF(domain, bus, slot, func):
159 return (((domain & 0xffff) << 16) | ((bus & 0xff) << 8) |
160 PCI_DEVFN(slot, func))
162 def check_pci_opts(opts):
163 def f((k, v)):
164 if k not in ['msitranslate', 'power_mgmt'] or \
165 not v.lower() in ['0', '1', 'yes', 'no']:
166 raise PciDeviceParseError('Invalid pci option %s=%s: ' % (k, v))
168 map(f, opts)
170 def serialise_pci_opts(opts):
171 return ','.join(map(lambda x: '='.join(x), opts))
173 def split_pci_opts(opts):
174 return map(lambda x: x.split('='),
175 filter(lambda x: x != '', opts.split(',')))
177 def append_default_pci_opts(opts, defopts):
178 optsdict = dict(opts)
179 return opts + filter(lambda (k, v): not optsdict.has_key(k), defopts)
181 def pci_opts_list_to_sxp(list):
182 return dev_dict_to_sxp({'opts': list})
184 def pci_opts_list_from_sxp(dev):
185 return map(lambda x: sxp.children(x)[0], sxp.children(dev, 'opts'))
187 def pci_convert_dict_to_sxp(dev, state, sub_state = None):
188 pci_sxp = ['pci', dev_dict_to_sxp(dev), ['state', state]]
189 if sub_state != None:
190 pci_sxp.append(['sub_state', sub_state])
191 return pci_sxp
193 def pci_convert_sxp_to_dict(dev_sxp):
194 """Convert pci device sxp to dict
195 @param dev_sxp: device configuration
196 @type dev_sxp: SXP object (parsed config)
197 @return: dev_config
198 @rtype: dictionary
199 """
200 # Parsing the device SXP's. In most cases, the SXP looks
201 # like this:
202 #
203 # [device, [vif, [mac, xx:xx:xx:xx:xx:xx], [ip 1.3.4.5]]]
204 #
205 # However, for PCI devices it looks like this:
206 #
207 # [device, [pci, [dev, [domain, 0], [bus, 0], [slot, 1], [func, 2]]]
208 #
209 # It seems the reasoning for this difference is because
210 # pciif.py needs all the PCI device configurations at
211 # the same time when creating the devices.
212 #
213 # To further complicate matters, Xen 2.0 configuration format
214 # uses the following for pci device configuration:
215 #
216 # [device, [pci, [domain, 0], [bus, 0], [dev, 1], [func, 2]]]
218 # For PCI device hotplug support, the SXP of PCI devices is
219 # extendend like this:
220 #
221 # [device, [pci, [dev, [domain, 0], [bus, 0], [slot, 1], [func, 2],
222 # [vdevfn, 0]],
223 # [state, 'Initialising']]]
224 #
225 # 'vdevfn' shows the virtual hotplug slot number which the PCI device
226 # is inserted in. This is only effective for HVM domains.
227 #
228 # state 'Initialising' indicates that the device is being attached,
229 # while state 'Closing' indicates that the device is being detached.
230 #
231 # The Dict looks like this:
232 #
233 # { devs: [{domain: 0, bus: 0, slot: 1, func: 2, vdevfn: 0}],
234 # states: ['Initialising'] }
236 dev_config = {}
238 pci_devs = []
239 for pci_dev in sxp.children(dev_sxp, 'dev'):
240 pci_dev_info = dict(pci_dev[1:])
241 if 'opts' in pci_dev_info:
242 pci_dev_info['opts'] = pci_opts_list_from_sxp(pci_dev)
243 # append uuid to each pci device that does't already have one.
244 if not pci_dev_info.has_key('uuid'):
245 dpci_uuid = pci_dev_info.get('uuid', uuid.createString())
246 pci_dev_info['uuid'] = dpci_uuid
247 pci_devs.append(pci_dev_info)
248 dev_config['devs'] = pci_devs
250 pci_states = []
251 for pci_state in sxp.children(dev_sxp, 'state'):
252 try:
253 pci_states.append(pci_state[1])
254 except IndexError:
255 raise XendError("Error reading state while parsing pci sxp")
256 dev_config['states'] = pci_states
258 return dev_config
260 def parse_hex(val):
261 try:
262 if isinstance(val, types.StringTypes):
263 return int(val, 16)
264 else:
265 return val
266 except ValueError:
267 return None
269 AUTO_PHP_FUNC = 1
270 MANUAL_PHP_FUNC = 2
272 def parse_pci_pfunc_vfunc(func_str):
273 list = func_str.split('=')
274 l = len(list)
275 if l == 0 or l > 2:
276 raise PciDeviceParseError('Invalid function: ' + func_str)
277 p = int(list[0], 16)
278 if p < 0 or p > 7:
279 raise PciDeviceParseError('Invalid physical function in: ' + func_str)
280 if l == 1:
281 # This defaults to linear mapping of physical to virtual functions
282 return (p, p, AUTO_PHP_FUNC)
283 else:
284 v = int(list[1], 16)
285 if v < 0 or v > 7:
286 raise PciDeviceParseError('Invalid virtual function in: ' +
287 func_str)
288 return (p, v, MANUAL_PHP_FUNC)
290 def pci_func_range(start, end):
291 if end < start:
292 x = pci_func_range(end, start)
293 x.reverse()
294 return x
295 return range(start, end + 1)
297 def pci_pfunc_vfunc_range(orig, a, b):
298 phys = pci_func_range(a[0], b[0])
299 virt = pci_func_range(a[1], b[1])
300 if len(phys) != len(virt):
301 raise PciDeviceParseError('Invalid range in: ' + orig)
302 return map(lambda x: x + (MANUAL_PHP_FUNC,), zip(phys, virt))
304 def pci_func_list_map_fn(key, func_str):
305 if func_str == "*":
306 return map(lambda x: parse_pci_pfunc_vfunc(x['func']),
307 filter(lambda x:
308 pci_dict_cmp(x, key, ['domain', 'bus', 'slot']),
309 get_all_pci_dict()))
310 l = map(parse_pci_pfunc_vfunc, func_str.split("-"))
311 if len(l) == 1:
312 return l
313 if len(l) == 2:
314 return pci_pfunc_vfunc_range(func_str, l[0], l[1])
315 return []
317 def pci_func_list_process(pci_dev_str, template, func_str):
318 l = reduce(lambda x, y: x + y,
319 (map(lambda x: pci_func_list_map_fn(template, x),
320 func_str.split(","))))
322 phys = map(lambda x: x[0], l)
323 virt = map(lambda x: x[1], l)
324 if len(phys) != len(set(phys)) or len(virt) != len(set(virt)):
325 raise PciDeviceParseError("Duplicate functions: %s" % pci_dev_str)
327 return l
329 def parse_pci_name_extended(pci_dev_str):
330 pci_match = re.match(r"((?P<domain>[0-9a-fA-F]{1,4})[:,])?" +
331 r"(?P<bus>[0-9a-fA-F]{1,2})[:,]" +
332 r"(?P<slot>[0-9a-fA-F]{1,2})[.,]" +
333 r"(?P<func>(\*|[0-7]([,-=][0-7])*))" +
334 r"(@(?P<vdevfn>[01]?[0-9a-fA-F]))?" +
335 r"(,(?P<opts>.*))?$", pci_dev_str)
337 if pci_match == None:
338 raise PciDeviceParseError("Failed to parse pci device: %s" %
339 pci_dev_str)
341 pci_dev_info = pci_match.groupdict('')
343 template = {}
344 if pci_dev_info['domain'] != '':
345 domain = int(pci_dev_info['domain'], 16)
346 else:
347 domain = 0
348 template['domain'] = "0x%04x" % domain
349 template['bus'] = "0x%02x" % int(pci_dev_info['bus'], 16)
350 template['slot'] = "0x%02x" % int(pci_dev_info['slot'], 16)
351 template['key'] = pci_dev_str.split(',')[0]
352 if pci_dev_info['opts'] != '':
353 template['opts'] = split_pci_opts(pci_dev_info['opts'])
354 check_pci_opts(template['opts'])
356 # This is where virtual function assignment takes place
357 func_list = pci_func_list_process(pci_dev_str, template,
358 pci_dev_info['func'])
359 if len(func_list) == 0:
360 return []
362 # Set the virtual function of the numerically lowest physical function
363 # to zero if it has not been manually set
364 if not filter(lambda x: x[1] == 0, func_list):
365 auto = filter(lambda x: x[2] == AUTO_PHP_FUNC, func_list)
366 manual = filter(lambda x: x[2] == MANUAL_PHP_FUNC, func_list)
367 if not auto:
368 raise PciDeviceParseError('Virtual device does not include '
369 'virtual function 0: ' + pci_dev_str)
370 auto.sort(lambda x,y: cmp(x[1], y[1]))
371 auto[0] = (auto[0][0], 0, AUTO_PHP_FUNC)
372 func_list = auto + manual
374 # For pci attachment and detachment is it important that virtual
375 # function 0 is done last. This is because is virtual function 0 that
376 # is used to singnal changes to the guest using ACPI
377 func_list.sort(lambda x,y: cmp(PCI_FUNC(y[1]), PCI_FUNC(x[1])))
379 # Virtual slot assignment takes place here if specified in the bdf,
380 # else it is done inside qemu-xen, as it knows which slots are free
381 pci = []
382 for (pfunc, vfunc, auto) in func_list:
383 pci_dev = template.copy()
384 pci_dev['func'] = "0x%x" % pfunc
386 if pci_dev_info['vdevfn'] == '':
387 vdevfn = AUTO_PHP_SLOT | vfunc
388 else:
389 vdevfn = PCI_DEVFN(int(pci_dev_info['vdevfn'], 16), vfunc)
390 pci_dev['vdevfn'] = "0x%02x" % vdevfn
392 pci.append(pci_dev)
394 return pci
396 def parse_pci_name(pci_name_string):
397 dev = parse_pci_name_extended(pci_name_string)
399 if len(dev) != 1:
400 raise PciDeviceParseError(("Failed to parse pci device: %s: "
401 "multiple functions specified prohibited") %
402 pci_name_string)
404 pci = dev[0]
405 if not int(pci['vdevfn'], 16) & AUTO_PHP_SLOT:
406 raise PciDeviceParseError(("Failed to parse pci device: %s: " +
407 "vdevfn provided where prohibited: 0x%02x") %
408 (pci_name_string,
409 PCI_SLOT(int(pci['vdevfn'], 16))))
410 if 'opts' in pci:
411 raise PciDeviceParseError(("Failed to parse pci device: %s: " +
412 "options provided where prohibited: %s") %
413 (pci_name_string, pci['opts']))
415 return pci
417 def __pci_dict_to_fmt_str(fmt, dev):
418 return fmt % (int(dev['domain'], 16), int(dev['bus'], 16),
419 int(dev['slot'], 16), int(dev['func'], 16))
421 def pci_dict_to_bdf_str(dev):
422 return __pci_dict_to_fmt_str('%04x:%02x:%02x.%01x', dev)
424 def pci_dict_to_xc_str(dev):
425 return __pci_dict_to_fmt_str('0x%x, 0x%x, 0x%x, 0x%x', dev)
427 def pci_dict_cmp(a, b, keys=['domain', 'bus', 'slot', 'func']):
428 return reduce(lambda x, y: x and y,
429 map(lambda k: int(a[k], 16) == int(b[k], 16), keys))
431 def extract_the_exact_pci_names(pci_names):
432 result = []
434 if isinstance(pci_names, types.StringTypes):
435 pci_names = pci_names.split()
436 elif isinstance(pci_names, types.ListType):
437 pci_names = re.findall(PCI_DEV_REG_EXPRESS_STR, '%s' % pci_names)
438 else:
439 raise PciDeviceParseError('Invalid argument: %s' % pci_names)
441 for pci in pci_names:
442 # The length of DDDD:bb:dd.f is 12.
443 if len(pci) != 12:
444 continue
445 if re.match(PCI_DEV_REG_EXPRESS_STR, pci) is None:
446 continue
447 result = result + [pci]
448 return result
450 def find_sysfs_mnt():
451 try:
452 return utils.find_sysfs_mount()
453 except IOError, (errno, strerr):
454 raise PciDeviceParseError(('Failed to locate sysfs mount: %s: %s (%d)'%
455 (PROC_PCI_PATH, strerr, errno)))
456 return None
458 def get_all_pci_names():
459 sysfs_mnt = find_sysfs_mnt()
460 if sysfs_mnt is None:
461 return None
462 pci_names = os.popen('ls ' + sysfs_mnt + SYSFS_PCI_DEVS_PATH).read().split()
463 return pci_names
465 def get_all_pci_dict():
466 return map(parse_pci_name, get_all_pci_names())
468 def get_all_pci_devices():
469 return map(PciDevice, get_all_pci_dict())
471 def _create_lspci_info():
472 """Execute 'lspci' command and parse the result.
473 If the command does not exist, lspci_info will be kept blank ({}).
475 Expects to be protected by lspci_info_lock.
476 """
477 global lspci_info
479 lspci_info = {}
481 for paragraph in os.popen(LSPCI_CMD + ' -vmm').read().split('\n\n'):
482 device_name = None
483 device_info = {}
484 # FIXME: workaround for pciutils without the -mm option.
485 # see: git://git.kernel.org/pub/scm/utils/pciutils/pciutils.git
486 # commit: 3fd6b4d2e2fda814047664ffc67448ac782a8089
487 first_device = True
488 for line in paragraph.split('\n'):
489 try:
490 (opt, value) = line.split(':\t')
491 if opt == 'Slot' or (opt == 'Device' and first_device):
492 device_name = pci_dict_to_bdf_str(parse_pci_name(value))
493 first_device = False
494 else:
495 device_info[opt] = value
496 except:
497 pass
498 if device_name is not None:
499 lspci_info[device_name] = device_info
501 def create_lspci_info():
502 global lspci_info_lock
503 lspci_info_lock.acquire()
504 try:
505 _create_lspci_info()
506 finally:
507 lspci_info_lock.release()
509 def save_pci_conf_space(devs_string):
510 pci_list = []
511 cfg_list = []
512 sysfs_mnt = find_sysfs_mnt()
513 for pci_str in devs_string:
514 pci_path = sysfs_mnt + SYSFS_PCI_DEVS_PATH + '/' + pci_str + \
515 SYSFS_PCI_DEV_CONFIG_PATH
516 fd = os.open(pci_path, os.O_RDONLY)
517 configs = []
518 for i in range(0, 256, 4):
519 configs = configs + [os.read(fd,4)]
520 os.close(fd)
521 pci_list = pci_list + [pci_path]
522 cfg_list = cfg_list + [configs]
523 return (pci_list, cfg_list)
525 def restore_pci_conf_space(pci_cfg_list):
526 pci_list = pci_cfg_list[0]
527 cfg_list = pci_cfg_list[1]
528 for i in range(0, len(pci_list)):
529 pci_path = pci_list[i]
530 configs = cfg_list[i]
531 fd = os.open(pci_path, os.O_WRONLY)
532 for dw in configs:
533 os.write(fd, dw)
534 os.close(fd)
536 def find_all_assignable_devices():
537 ''' devices owned by pcibak or pci-stub can be directly assigned to
538 guest with IOMMU (VT-d or AMD IOMMU), find all these devices.
539 '''
540 sysfs_mnt = find_sysfs_mnt()
541 pciback_path = sysfs_mnt + SYSFS_PCIBACK_PATH
542 pcistub_path = sysfs_mnt + SYSFS_PCISTUB_PATH
543 pci_names1 = os.popen('ls %s 2>/dev/null' % pciback_path).read()
544 pci_names2 = os.popen('ls %s 2>/dev/null' % pcistub_path).read()
545 if len(pci_names1) + len(pci_names2) == 0 :
546 return None
547 pci_list = extract_the_exact_pci_names(pci_names1)
548 pci_list = pci_list + extract_the_exact_pci_names(pci_names2)
549 dev_list = []
550 for pci in pci_list:
551 dev = PciDevice(parse_pci_name(pci))
552 dev_list = dev_list + [dev]
553 return dev_list
555 def transform_list(target, src):
556 ''' src: its element is pci string (Format: xxxx:xx:xx.x).
557 target: its element is pci string, or a list of pci string.
559 If all the elements in src are in target, we remove them from target
560 and add src into target; otherwise, we remove from target all the
561 elements that also appear in src.
562 '''
563 result = []
564 target_contains_src = True
565 for e in src:
566 if not e in target:
567 target_contains_src = False
568 break
570 if target_contains_src:
571 result = result + [src]
572 for e in target:
573 if not e in src:
574 result = result + [e]
575 return result
577 def check_FLR_capability(dev_list):
578 if len(dev_list) == 0:
579 return []
581 pci_list = []
582 pci_dev_dict = {}
583 for dev in dev_list:
584 pci_list = pci_list + [dev.name]
585 pci_dev_dict[dev.name] = dev
587 while True:
588 need_transform = False
589 for pci in pci_list:
590 if isinstance(pci, types.StringTypes):
591 dev = pci_dev_dict[pci]
592 if dev.bus == 0:
593 continue
594 if dev.dev_type == DEV_TYPE_PCIe_ENDPOINT and not dev.pcie_flr:
595 coassigned_pci_list = dev.find_all_the_multi_functions()
596 need_transform = True
597 elif dev.dev_type == DEV_TYPE_PCI and not dev.pci_af_flr:
598 coassigned_pci_list = dev.find_coassigned_pci_devices(True)
599 del coassigned_pci_list[0]
600 need_transform = True
602 if need_transform:
603 pci_list = transform_list(pci_list, coassigned_pci_list)
604 if not need_transform:
605 break
607 if len(pci_list) == 0:
608 return []
610 for i in range(0, len(pci_list)):
611 if isinstance(pci_list[i], types.StringTypes):
612 pci_list[i] = [pci_list[i]]
614 # Now every element in pci_list is a list of pci string.
616 result = []
617 for pci_names in pci_list:
618 devs = []
619 for pci in pci_names:
620 devs = devs + [pci_dev_dict[pci]]
621 result = result + [devs]
622 return result
624 def check_mmio_bar(devs_list):
625 result = []
627 for dev_list in devs_list:
628 non_aligned_bar_found = False
629 for dev in dev_list:
630 if dev.has_non_page_aligned_bar:
631 non_aligned_bar_found = True
632 break
633 if not non_aligned_bar_found:
634 result = result + [dev_list]
636 return result
638 class PciDeviceParseError(Exception):
639 def __init__(self,msg):
640 self.message = msg
641 def __str__(self):
642 return self.message
644 class PciDeviceAssignmentError(Exception):
645 def __init__(self,msg):
646 self.message = msg
647 def __str__(self):
648 return 'pci: improper device assignment specified: ' + \
649 self.message
651 class PciDeviceVslotMissing(Exception):
652 def __init__(self,msg):
653 self.message = msg
654 def __str__(self):
655 return 'pci: no vslot: ' + self.message
657 class PciDevice:
658 def __init__(self, dev):
659 self.domain = int(dev['domain'], 16)
660 self.bus = int(dev['bus'], 16)
661 self.slot = int(dev['slot'], 16)
662 self.func = int(dev['func'], 16)
663 self.name = pci_dict_to_bdf_str(dev)
664 self.cfg_space_path = find_sysfs_mnt()+SYSFS_PCI_DEVS_PATH+'/'+ \
665 self.name + SYSFS_PCI_DEV_CONFIG_PATH
666 self.irq = 0
667 self.iomem = []
668 self.ioports = []
669 self.driver = None
670 self.vendor = None
671 self.device = None
672 self.subvendor = None
673 self.subdevice = None
674 self.msix = 0
675 self.msix_iomem = []
676 self.revision = 0
677 self.classcode = None
678 self.vendorname = ""
679 self.devicename = ""
680 self.classname = ""
681 self.subvendorname = ""
682 self.subdevicename = ""
683 self.dev_type = None
684 self.is_downstream_port = False
685 self.acs_enabled = False
686 self.has_non_page_aligned_bar = False
687 self.pcie_flr = False
688 self.pci_af_flr = False
689 self.detect_dev_info()
690 if (self.dev_type == DEV_TYPE_PCI_BRIDGE) or \
691 (self.dev_type == DEV_TYPE_PCIe_BRIDGE):
692 return
693 self.get_info_from_sysfs()
694 self.get_info_from_lspci()
696 def find_parent(self):
697 # i.e., /sys/bus/pci/devices/0000:00:19.0 or
698 # /sys/bus/pci/devices/0000:03:04.0
699 path = find_sysfs_mnt()+SYSFS_PCI_DEVS_PATH+'/'+ self.name
700 # i.e., ../../../devices/pci0000:00/0000:00:19.0
701 # ../../../devices/pci0000:00/0000:00:02.0/0000:01:00.2/0000:03:04.0
702 try:
703 target = os.readlink(path)
704 lst = target.split('/')
705 parent = lst[len(lst)-2]
706 if parent[0:3] == 'pci':
707 # We have reached the upmost one.
708 return None
709 return parse_pci_name(parent)
710 except OSError, (errno, strerr):
711 raise PciDeviceParseError('Can not locate the parent of %s',
712 self.name)
714 def find_the_uppermost_pci_bridge(self):
715 # Find the uppermost PCI/PCI-X bridge
716 dev = self.find_parent()
717 if dev is None:
718 return None
719 dev = dev_parent = PciDevice(dev)
720 while dev_parent.dev_type != DEV_TYPE_PCIe_BRIDGE:
721 parent = dev_parent.find_parent()
722 if parent is None:
723 break
724 dev = dev_parent
725 dev_parent = PciDevice(parent)
726 return dev
728 def find_all_devices_behind_the_bridge(self, ignore_bridge):
729 sysfs_mnt = find_sysfs_mnt()
730 self_path = sysfs_mnt + SYSFS_PCI_DEVS_PATH + '/' + self.name
731 pci_names = os.popen('ls ' + self_path).read()
732 dev_list = extract_the_exact_pci_names(pci_names)
734 list = [self.name]
735 for pci_str in dev_list:
736 dev = PciDevice(parse_pci_name(pci_str))
737 if dev.dev_type == DEV_TYPE_PCI_BRIDGE or \
738 dev.dev_type == DEV_TYPE_PCIe_BRIDGE:
739 sub_list_including_self = \
740 dev.find_all_devices_behind_the_bridge(ignore_bridge)
741 if ignore_bridge:
742 del sub_list_including_self[0]
743 list = list + [sub_list_including_self]
744 else:
745 list = list + [dev.name]
746 return list
748 def find_coassigned_pci_devices(self, ignore_bridge = True):
749 ''' Here'self' is a PCI device, we need find the uppermost PCI/PCI-X
750 bridge, and all devices behind it must be co-assigned to the same
751 guest.
753 Parameter:
754 [ignore_bridge]: if set, the returned result doesn't include
755 any bridge behind the uppermost PCI/PCI-X bridge.
757 Note: The first element of the return value is the uppermost
758 PCI/PCI-X bridge. If the caller doesn't need the first
759 element, the caller itself can remove it explicitly.
760 '''
761 dev = self.find_the_uppermost_pci_bridge()
763 # The 'self' device is on bus0.
764 if dev is None:
765 return [self.name]
767 dev_list = dev.find_all_devices_behind_the_bridge(ignore_bridge)
768 dev_list = extract_the_exact_pci_names(dev_list)
769 return dev_list
771 def do_secondary_bus_reset(self, target_bus, devs):
772 # Save the config spaces of all the devices behind the bus.
773 (pci_list, cfg_list) = save_pci_conf_space(devs)
775 #Do the Secondary Bus Reset
776 sysfs_mnt = find_sysfs_mnt()
777 parent_path = sysfs_mnt + SYSFS_PCI_DEVS_PATH + '/' + \
778 target_bus + SYSFS_PCI_DEV_CONFIG_PATH
779 fd = os.open(parent_path, os.O_RDWR)
780 os.lseek(fd, PCI_CB_BRIDGE_CONTROL, 0)
781 br_cntl = (struct.unpack('H', os.read(fd, 2)))[0]
782 # Assert Secondary Bus Reset
783 os.lseek(fd, PCI_CB_BRIDGE_CONTROL, 0)
784 br_cntl |= PCI_BRIDGE_CTL_BUS_RESET
785 os.write(fd, struct.pack('H', br_cntl))
786 time.sleep(0.100)
787 # De-assert Secondary Bus Reset
788 os.lseek(fd, PCI_CB_BRIDGE_CONTROL, 0)
789 br_cntl &= ~PCI_BRIDGE_CTL_BUS_RESET
790 os.write(fd, struct.pack('H', br_cntl))
791 time.sleep(0.100)
792 os.close(fd)
794 # Restore the config spaces
795 restore_pci_conf_space((pci_list, cfg_list))
797 def do_Dstate_transition(self):
798 pos = self.find_cap_offset(PCI_CAP_ID_PM)
799 if pos == 0:
800 return False
802 # No_Soft_Reset - When set 1, this bit indicates that
803 # devices transitioning from D3hot to D0 because of
804 # PowerState commands do not perform an internal reset.
805 pm_ctl = self.pci_conf_read32(pos + PCI_PM_CTRL)
806 if (pm_ctl & PCI_PM_CTRL_NO_SOFT_RESET) == PCI_PM_CTRL_NO_SOFT_RESET:
807 return False
809 (pci_list, cfg_list) = save_pci_conf_space([self.name])
811 # Enter D3hot
812 pm_ctl &= ~PCI_PM_CTRL_STATE_MASK
813 pm_ctl |= PCI_D3hot
814 self.pci_conf_write32(pos + PCI_PM_CTRL, pm_ctl)
815 time.sleep(0.010)
817 # From D3hot to D0
818 pm_ctl &= ~PCI_PM_CTRL_STATE_MASK
819 pm_ctl |= PCI_D0hot
820 self.pci_conf_write32(pos + PCI_PM_CTRL, pm_ctl)
821 time.sleep(0.010)
823 restore_pci_conf_space((pci_list, cfg_list))
824 return True
826 def do_vendor_specific_FLR_method(self):
827 pos = self.find_cap_offset(PCI_CAP_ID_VENDOR_SPECIFIC_CAP)
828 if pos == 0:
829 return
831 vendor_id = self.pci_conf_read16(PCI_VENDOR_ID)
832 if vendor_id != VENDOR_INTEL:
833 return
835 class_id = self.pci_conf_read16(PCI_CLASS_DEVICE)
836 if class_id != PCI_CLASS_ID_USB:
837 return
839 (pci_list, cfg_list) = save_pci_conf_space([self.name])
841 self.pci_conf_write8(pos + PCI_USB_FLRCTRL, 1)
842 time.sleep(0.100)
844 restore_pci_conf_space((pci_list, cfg_list))
846 def do_FLR_for_integrated_device(self):
847 if not self.do_Dstate_transition():
848 self.do_vendor_specific_FLR_method()
850 def do_AF_FLR(self, af_pos):
851 ''' use PCI Advanced Capability to do FLR
852 '''
853 (pci_list, cfg_list) = save_pci_conf_space([self.name])
854 self.pci_conf_write8(af_pos + PCI_AF_CTL, PCI_AF_CTL_FLR)
855 time.sleep(0.100)
856 restore_pci_conf_space((pci_list, cfg_list))
858 def do_FLR_for_intel_4Series_iGFX(self):
859 af_pos = PCI_CAP_IGFX_CAP13_OFFSET
860 self.do_AF_FLR(af_pos)
861 log.debug("Intel 4 Series iGFX FLR done")
863 def do_FLR_for_GM45_iGFX(self):
864 reg32 = self.pci_conf_read32(PCI_CAP_IGFX_CAP09_OFFSET)
865 if ((reg32 >> 16) & 0x000000FF) != 0x06 or \
866 ((reg32 >> 24) & 0x000000F0) != 0x20:
867 return
869 self.pci_conf_write8(PCI_CAP_IGFX_GDRST_OFFSET, PCI_CAP_IGFX_GDRST)
870 for i in range(0, 10):
871 time.sleep(0.100)
872 reg8 = self.pci_conf_read8(PCI_CAP_IGFX_GDRST_OFFSET)
873 if (reg8 & 0x01) == 0:
874 break
875 if i == 10:
876 log.debug("Intel iGFX FLR fail on GM45")
877 return
879 # This specific reset will hang if the command register does not have
880 # memory space access enabled
881 cmd = self.pci_conf_read16(PCI_COMMAND)
882 self.pci_conf_write16(PCI_COMMAND, (cmd | 0x02))
883 af_pos = PCI_CAP_IGFX_CAP09_OFFSET
884 self.do_AF_FLR(af_pos)
885 self.pci_conf_write16(PCI_COMMAND, cmd)
887 log.debug("Intel iGFX FLR on GM45 done")
889 def find_all_the_multi_functions(self):
890 sysfs_mnt = find_sysfs_mnt()
891 parentdict = self.find_parent()
892 if parentdict is None :
893 return [ self.name ]
894 parent = pci_dict_to_bdf_str(parentdict)
895 pci_names = os.popen('ls ' + sysfs_mnt + SYSFS_PCI_DEVS_PATH + '/' + \
896 parent + '/').read()
897 funcs = extract_the_exact_pci_names(pci_names)
898 return funcs
900 def find_coassigned_devices(self):
901 if self.dev_type == DEV_TYPE_PCIe_ENDPOINT and not self.pcie_flr:
902 return self.find_all_the_multi_functions()
903 elif self.dev_type == DEV_TYPE_PCI and not self.pci_af_flr:
904 coassigned_pci_list = self.find_coassigned_pci_devices(True)
905 if len(coassigned_pci_list) > 1:
906 del coassigned_pci_list[0]
907 return coassigned_pci_list
908 else:
909 return [self.name]
911 def find_cap_offset(self, cap):
912 path = find_sysfs_mnt()+SYSFS_PCI_DEVS_PATH+'/'+ \
913 self.name+SYSFS_PCI_DEV_CONFIG_PATH
915 pos = PCI_CAPABILITY_LIST
917 try:
918 fd = os.open(path, os.O_RDONLY)
919 os.lseek(fd, PCI_STATUS, 0)
920 status = struct.unpack('H', os.read(fd, 2))[0]
921 if (status & 0x10) == 0:
922 # The device doesn't support PCI_STATUS_CAP_LIST
923 return 0
925 max_cap = 48
926 while max_cap > 0:
927 os.lseek(fd, pos, 0)
928 pos = ord(os.read(fd, 1))
929 if pos < 0x40:
930 pos = 0
931 break;
932 os.lseek(fd, pos + 0, 0)
933 id = ord(os.read(fd, 1))
934 if id == 0xff:
935 pos = 0
936 break;
938 # Found the capability
939 if id == cap:
940 break;
942 # Test the next one
943 pos = pos + 1
944 max_cap = max_cap - 1;
946 os.close(fd)
947 except OSError, (errno, strerr):
948 raise PciDeviceParseError(('Error when accessing sysfs: %s (%d)' %
949 (strerr, errno)))
950 return pos
952 def find_ext_cap(self, cap):
953 path = find_sysfs_mnt()+SYSFS_PCI_DEVS_PATH+'/'+ \
954 self.name+SYSFS_PCI_DEV_CONFIG_PATH
956 ttl = 480; # 3840 bytes, minimum 8 bytes per capability
957 pos = 0x100
959 try:
960 fd = os.open(path, os.O_RDONLY)
961 os.lseek(fd, pos, 0)
962 h = os.read(fd, 4)
963 if len(h) == 0: # MMCONF is not enabled?
964 return 0
965 header = struct.unpack('I', h)[0]
966 if header == 0 or header == -1:
967 return 0
969 while ttl > 0:
970 if (header & 0x0000ffff) == cap:
971 return pos
972 pos = (header >> 20) & 0xffc
973 if pos < 0x100:
974 break
975 os.lseek(fd, pos, 0)
976 header = struct.unpack('I', os.read(fd, 4))[0]
977 ttl = ttl - 1
978 os.close(fd)
979 except OSError, (errno, strerr):
980 raise PciDeviceParseError(('Error when accessing sysfs: %s (%d)' %
981 (strerr, errno)))
982 return 0
984 def is_behind_switch_lacking_acs(self):
985 # If there is intermediate PCIe switch, which doesn't support ACS or
986 # doesn't enable ACS, between Root Complex and the function, we return
987 # True, meaning the function is not allowed to be assigned to guest due
988 # to potential security issue.
989 parent = self.find_parent()
990 while parent is not None:
991 dev_parent = PciDevice(parent)
992 if dev_parent.is_downstream_port and not dev_parent.acs_enabled:
993 return True
994 parent = dev_parent.find_parent()
995 return False
997 def pci_conf_read8(self, pos):
998 fd = os.open(self.cfg_space_path, os.O_RDONLY)
999 os.lseek(fd, pos, 0)
1000 str = os.read(fd, 1)
1001 os.close(fd)
1002 val = struct.unpack('B', str)[0]
1003 return val
1005 def pci_conf_read16(self, pos):
1006 fd = os.open(self.cfg_space_path, os.O_RDONLY)
1007 os.lseek(fd, pos, 0)
1008 str = os.read(fd, 2)
1009 os.close(fd)
1010 val = struct.unpack('H', str)[0]
1011 return val
1013 def pci_conf_read32(self, pos):
1014 fd = os.open(self.cfg_space_path, os.O_RDONLY)
1015 os.lseek(fd, pos, 0)
1016 str = os.read(fd, 4)
1017 os.close(fd)
1018 val = struct.unpack('I', str)[0]
1019 return val
1021 def pci_conf_write8(self, pos, val):
1022 str = struct.pack('B', val)
1023 fd = os.open(self.cfg_space_path, os.O_WRONLY)
1024 os.lseek(fd, pos, 0)
1025 os.write(fd, str)
1026 os.close(fd)
1028 def pci_conf_write16(self, pos, val):
1029 str = struct.pack('H', val)
1030 fd = os.open(self.cfg_space_path, os.O_WRONLY)
1031 os.lseek(fd, pos, 0)
1032 os.write(fd, str)
1033 os.close(fd)
1035 def pci_conf_write32(self, pos, val):
1036 str = struct.pack('I', val)
1037 fd = os.open(self.cfg_space_path, os.O_WRONLY)
1038 os.lseek(fd, pos, 0)
1039 os.write(fd, str)
1040 os.close(fd)
1042 def detect_dev_info(self):
1043 try:
1044 class_dev = self.pci_conf_read16(PCI_CLASS_DEVICE)
1045 except OSError, (err, strerr):
1046 if err == errno.ENOENT:
1047 strerr = "the device doesn't exist?"
1048 raise PciDeviceParseError('%s: %s' %\
1049 (self.name, strerr))
1050 pos = self.find_cap_offset(PCI_CAP_ID_EXP)
1051 if class_dev == PCI_CLASS_BRIDGE_PCI:
1052 if pos == 0:
1053 self.dev_type = DEV_TYPE_PCI_BRIDGE
1054 else:
1055 creg = self.pci_conf_read16(pos + PCI_EXP_FLAGS)
1056 type = (creg & PCI_EXP_FLAGS_TYPE) >> 4
1057 if type == PCI_EXP_TYPE_PCI_BRIDGE:
1058 self.dev_type = DEV_TYPE_PCI_BRIDGE
1059 else:
1060 self.dev_type = DEV_TYPE_PCIe_BRIDGE
1061 if type == PCI_EXP_TYPE_DOWNSTREAM:
1062 self.is_downstream_port = True
1063 pos = self.find_ext_cap(PCI_EXT_CAP_ID_ACS)
1064 if pos != 0:
1065 ctrl = self.pci_conf_read16(pos + PCI_EXT_ACS_CTRL)
1066 if (ctrl & PCI_EXT_CAP_ACS_ENABLED) == \
1067 (PCI_EXT_CAP_ACS_ENABLED):
1068 self.acs_enabled = True
1069 else:
1070 if pos != 0:
1071 self.dev_type = DEV_TYPE_PCIe_ENDPOINT
1072 else:
1073 self.dev_type = DEV_TYPE_PCI
1075 # Force 0000:00:00.0 to be DEV_TYPE_PCIe_BRIDGE
1076 if self.name == '0000:00:00.0':
1077 self.dev_type = DEV_TYPE_PCIe_BRIDGE
1079 if (self.dev_type == DEV_TYPE_PCI_BRIDGE) or \
1080 (self.dev_type == DEV_TYPE_PCIe_BRIDGE):
1081 return
1083 # Try to findthe PCIe FLR capability
1084 if self.dev_type == DEV_TYPE_PCIe_ENDPOINT:
1085 dev_cap = self.pci_conf_read32(pos + PCI_EXP_DEVCAP)
1086 if dev_cap & PCI_EXP_DEVCAP_FLR:
1087 self.pcie_flr = True
1088 else:
1089 # Quirk for the VF of Intel 82599 10GbE Controller.
1090 # We know it does have PCIe FLR capability even if it doesn't
1091 # report that (dev_cap.PCI_EXP_DEVCAP_FLR is 0).
1092 # See the 82599 datasheet.
1093 dev_path = find_sysfs_mnt()+SYSFS_PCI_DEVS_PATH+'/'+self.name
1094 vendor_id = parse_hex(os.popen('cat %s/vendor' % dev_path).read())
1095 device_id = parse_hex(os.popen('cat %s/device' % dev_path).read())
1096 if (vendor_id == VENDOR_INTEL) and \
1097 (device_id == DEVICE_ID_82599):
1098 self.pcie_flr = True
1099 elif self.dev_type == DEV_TYPE_PCI:
1100 # Try to find the "PCI Advanced Capabilities"
1101 pos = self.find_cap_offset(PCI_CAP_ID_AF)
1102 if pos != 0:
1103 af_cap = self.pci_conf_read8(pos + PCI_AF_CAPs)
1104 if (af_cap & PCI_AF_CAPs_TP_FLR) == PCI_AF_CAPs_TP_FLR:
1105 self.pci_af_flr = True
1107 bar_addr = PCI_BAR_0
1108 while bar_addr <= PCI_BAR_5:
1109 bar = self.pci_conf_read32(bar_addr)
1110 if (bar & PCI_BAR_SPACE) == PCI_BAR_MEM:
1111 bar = bar & PCI_BAR_MEM_MASK
1112 bar = bar & ~PAGE_MASK
1113 if bar != 0:
1114 self.has_non_page_aligned_bar = True
1115 break
1116 bar_addr = bar_addr + 4
1118 def devs_check_driver(self, devs):
1119 if len(devs) == 0:
1120 return
1121 for pci_dev in devs:
1122 dev = PciDevice(parse_pci_name(pci_dev))
1123 if dev.driver == 'pciback' or dev.driver == 'pci-stub':
1124 continue
1125 err_msg = 'pci: %s must be co-assigned to the same guest with %s' + \
1126 ', but it is not owned by pciback or pci-stub.'
1127 raise PciDeviceAssignmentError(err_msg % (pci_dev, self.name))
1129 def do_FLR(self, is_hvm, strict_check):
1130 """ Perform FLR (Functional Level Reset) for the device.
1131 """
1132 if self.dev_type == DEV_TYPE_PCIe_ENDPOINT:
1133 # If PCIe device supports FLR, we use it.
1134 if self.pcie_flr:
1135 (pci_list, cfg_list) = save_pci_conf_space([self.name])
1136 pos = self.find_cap_offset(PCI_CAP_ID_EXP)
1137 self.pci_conf_write32(pos + PCI_EXP_DEVCTL, PCI_EXP_DEVCTL_FLR)
1138 # We must sleep at least 100ms for the completion of FLR
1139 time.sleep(0.100)
1140 restore_pci_conf_space((pci_list, cfg_list))
1141 else:
1142 if self.bus == 0:
1143 self.do_FLR_for_integrated_device()
1144 else:
1145 funcs = self.find_all_the_multi_functions()
1147 if not is_hvm and (len(funcs) > 1):
1148 return
1149 if is_hvm and not strict_check:
1150 return
1152 self.devs_check_driver(funcs)
1154 parent = pci_dict_to_bdf_str(self.find_parent())
1156 # Do Secondary Bus Reset.
1157 self.do_secondary_bus_reset(parent, funcs)
1158 # PCI devices
1159 else:
1160 # For PCI device on host bus, we test "PCI Advanced Capabilities".
1161 if self.bus == 0 and self.pci_af_flr:
1162 af_pos = self.find_cap_offset(PCI_CAP_ID_AF)
1163 self.do_AF_FLR(af_pos)
1164 else:
1165 if self.bus == 0:
1166 if self.slot == 0x02 and self.func == 0x0:
1167 vendor_id = self.pci_conf_read16(PCI_VENDOR_ID)
1168 if vendor_id != VENDOR_INTEL:
1169 return
1170 class_id = self.pci_conf_read16(PCI_CLASS_DEVICE)
1171 if class_id != PCI_CLASS_ID_VGA:
1172 return
1173 device_id = self.pci_conf_read16(PCI_DEVICE_ID)
1174 if device_id == PCI_DEVICE_ID_IGFX_GM45:
1175 self.do_FLR_for_GM45_iGFX()
1176 elif device_id == PCI_DEVICE_ID_IGFX_EAGLELAKE or \
1177 device_id == PCI_DEVICE_ID_IGFX_Q45 or \
1178 device_id == PCI_DEVICE_ID_IGFX_G45 or \
1179 device_id == PCI_DEVICE_ID_IGFX_G41:
1180 self.do_FLR_for_intel_4Series_iGFX()
1181 else:
1182 log.debug("Unknown iGFX device_id:%x", device_id)
1183 else:
1184 self.do_FLR_for_integrated_device()
1185 else:
1186 devs = self.find_coassigned_pci_devices(False)
1187 # Remove the element 0 which is a bridge
1188 target_bus = devs[0]
1189 del devs[0]
1191 if not is_hvm and (len(devs) > 1):
1192 return
1193 if is_hvm and not strict_check:
1194 return
1196 self.devs_check_driver(devs)
1198 # Do Secondary Bus Reset.
1199 self.do_secondary_bus_reset(target_bus, devs)
1201 def find_capability(self, type):
1202 sysfs_mnt = find_sysfs_mnt()
1203 if sysfs_mnt == None:
1204 return False
1205 path = sysfs_mnt+SYSFS_PCI_DEVS_PATH+'/'+ \
1206 self.name+SYSFS_PCI_DEV_CONFIG_PATH
1207 try:
1208 conf_file = open(path, 'rb')
1209 conf_file.seek(PCI_HEADER_TYPE)
1210 header_type = ord(conf_file.read(1)) & PCI_HEADER_TYPE_MASK
1211 if header_type == PCI_HEADER_TYPE_CARDBUS:
1212 return
1213 conf_file.seek(PCI_STATUS_OFFSET)
1214 status = ord(conf_file.read(1))
1215 if status&PCI_STATUS_CAP_MASK:
1216 conf_file.seek(PCI_CAP_OFFSET)
1217 capa_pointer = ord(conf_file.read(1))
1218 capa_count = 0
1219 while capa_pointer:
1220 if capa_pointer < 0x40:
1221 raise PciDeviceParseError(
1222 ('Broken capability chain: %s' % self.name))
1223 capa_count += 1
1224 if capa_count > 96:
1225 raise PciDeviceParseError(
1226 ('Looped capability chain: %s' % self.name))
1227 conf_file.seek(capa_pointer)
1228 capa_id = ord(conf_file.read(1))
1229 capa_pointer = ord(conf_file.read(1))
1230 if capa_id == type:
1231 # get the type
1232 message_cont_lo = ord(conf_file.read(1))
1233 message_cont_hi = ord(conf_file.read(1))
1234 self.msix=1
1235 self.msix_entries = (message_cont_lo + \
1236 (message_cont_hi << 8)) \
1237 & MSIX_SIZE_MASK
1238 t_off=conf_file.read(4)
1239 p_off=conf_file.read(4)
1240 self.table_offset=ord(t_off[0]) | (ord(t_off[1])<<8) | \
1241 (ord(t_off[2])<<16)| \
1242 (ord(t_off[3])<<24)
1243 self.pba_offset=ord(p_off[0]) | (ord(p_off[1]) << 8)| \
1244 (ord(p_off[2])<<16) | \
1245 (ord(p_off[3])<<24)
1246 self.table_index = self.table_offset & MSIX_BIR_MASK
1247 self.table_offset = self.table_offset & ~MSIX_BIR_MASK
1248 self.pba_index = self.pba_offset & MSIX_BIR_MASK
1249 self.pba_offset = self.pba_offset & ~MSIX_BIR_MASK
1250 break
1251 except IOError, (errno, strerr):
1252 raise PciDeviceParseError(('Failed to locate sysfs mount: %s: %s (%d)' %
1253 (PROC_PCI_PATH, strerr, errno)))
1255 def get_info_from_sysfs(self):
1256 self.find_capability(0x11)
1257 sysfs_mnt = find_sysfs_mnt()
1258 if sysfs_mnt == None:
1259 return False
1261 path = sysfs_mnt+SYSFS_PCI_DEVS_PATH+'/'+ \
1262 self.name+SYSFS_PCI_DEV_RESOURCE_PATH
1263 try:
1264 resource_file = open(path,'r')
1266 for i in range(PROC_PCI_NUM_RESOURCES):
1267 line = resource_file.readline()
1268 sline = line.split()
1269 if len(sline)<3:
1270 continue
1272 start = int(sline[0],16)
1273 end = int(sline[1],16)
1274 flags = int(sline[2],16)
1275 size = end-start+1
1277 if start!=0:
1278 if flags&PCI_BAR_IO:
1279 self.ioports.append( (start,size) )
1280 else:
1281 self.iomem.append( (start,size) )
1283 except IOError, (errno, strerr):
1284 raise PciDeviceParseError(('Failed to open & read %s: %s (%d)' %
1285 (path, strerr, errno)))
1287 path = sysfs_mnt+SYSFS_PCI_DEVS_PATH+'/'+ \
1288 self.name+SYSFS_PCI_DEV_IRQ_PATH
1289 try:
1290 self.irq = int(open(path,'r').readline())
1291 except IOError, (errno, strerr):
1292 raise PciDeviceParseError(('Failed to open & read %s: %s (%d)' %
1293 (path, strerr, errno)))
1295 path = sysfs_mnt+SYSFS_PCI_DEVS_PATH+'/'+ \
1296 self.name+SYSFS_PCI_DEV_DRIVER_DIR_PATH
1297 try:
1298 self.driver = os.path.basename(os.readlink(path))
1299 except OSError, (errno, strerr):
1300 self.driver = ""
1302 path = sysfs_mnt+SYSFS_PCI_DEVS_PATH+'/'+ \
1303 self.name+SYSFS_PCI_DEV_VENDOR_PATH
1304 try:
1305 self.vendor = int(open(path,'r').readline(), 16)
1306 except IOError, (errno, strerr):
1307 raise PciDeviceParseError(('Failed to open & read %s: %s (%d)' %
1308 (path, strerr, errno)))
1310 path = sysfs_mnt+SYSFS_PCI_DEVS_PATH+'/'+ \
1311 self.name+SYSFS_PCI_DEV_DEVICE_PATH
1312 try:
1313 self.device = int(open(path,'r').readline(), 16)
1314 except IOError, (errno, strerr):
1315 raise PciDeviceParseError(('Failed to open & read %s: %s (%d)' %
1316 (path, strerr, errno)))
1318 path = sysfs_mnt+SYSFS_PCI_DEVS_PATH+'/'+ \
1319 self.name+SYSFS_PCI_DEV_SUBVENDOR_PATH
1320 try:
1321 self.subvendor = int(open(path,'r').readline(), 16)
1322 except IOError, (errno, strerr):
1323 raise PciDeviceParseError(('Failed to open & read %s: %s (%d)' %
1324 (path, strerr, errno)))
1326 path = sysfs_mnt+SYSFS_PCI_DEVS_PATH+'/'+ \
1327 self.name+SYSFS_PCI_DEV_SUBDEVICE_PATH
1328 try:
1329 self.subdevice = int(open(path,'r').readline(), 16)
1330 except IOError, (errno, strerr):
1331 raise PciDeviceParseError(('Failed to open & read %s: %s (%d)' %
1332 (path, strerr, errno)))
1334 path = sysfs_mnt+SYSFS_PCI_DEVS_PATH+'/'+ \
1335 self.name+SYSFS_PCI_DEV_CLASS_PATH
1336 try:
1337 self.classcode = int(open(path,'r').readline(), 16)
1338 except IOError, (errno, strerr):
1339 raise PciDeviceParseError(('Failed to open & read %s: %s (%d)' %
1340 (path, strerr, errno)))
1342 return True
1344 def get_info_from_lspci(self):
1345 """ Get information such as vendor name, device name, class name, etc.
1346 Since we cannot obtain these data from sysfs, use 'lspci' command.
1347 """
1348 global lspci_info
1349 global lspci_info_lock
1351 lspci_info_lock.acquire()
1352 try:
1353 if lspci_info is None:
1354 _create_lspci_info()
1356 device_info = lspci_info.get(self.name)
1357 if device_info:
1358 try:
1359 self.revision = int(device_info.get('Rev', '0'), 16)
1360 except ValueError:
1361 pass
1362 self.vendorname = device_info.get('Vendor', '')
1363 self.devicename = device_info.get('Device', '')
1364 self.classname = device_info.get('Class', '')
1365 self.subvendorname = device_info.get('SVendor', '')
1366 self.subdevicename = device_info.get('SDevice', '')
1367 return True
1368 finally:
1369 lspci_info_lock.release()
1371 def __str__(self):
1372 str = "PCI Device %s\n" % (self.name)
1373 for (start,size) in self.ioports:
1374 str = str + "IO Port 0x%02x [size=%d]\n"%(start,size)
1375 for (start,size) in self.iomem:
1376 str = str + "IO Mem 0x%02x [size=%d]\n"%(start,size)
1377 str = str + "IRQ %d\n"%(self.irq)
1378 str = str + "Vendor ID 0x%04x\n"%(self.vendor)
1379 str = str + "Device ID 0x%04x\n"%(self.device)
1380 str = str + "Sybsystem Vendor ID 0x%04x\n"%(self.subvendor)
1381 str = str + "Subsystem Device ID 0x%04x"%(self.subdevice)
1382 return str
1384 def main():
1385 if len(sys.argv)<5:
1386 print "Usage: %s <domain> <bus> <slot> <func>\n" % sys.argv[0]
1387 sys.exit(2)
1389 dev = PciDevice(int(sys.argv[1],16), int(sys.argv[2],16),
1390 int(sys.argv[3],16), int(sys.argv[4],16))
1391 print str(dev)
1393 if __name__=='__main__':
1394 main()