mirror of
https://github.com/xen-project/xen.git
synced 2026-10-29 18:50:05 +01:00
[PCI] xend parses the user-space PCI backend policy files and sends
the corresponding fields to the PCI bus manager via sysfs nodes: /sys/bus/pci/drivers/pciback/quirks /sys/bus/pci/drivers/pciback/permissive xend reads the policy file every time it creates a new domain that was assigned a PCI device. Signed-off-by: Chris Bookholt <hap10@tycho.ncsc.mil>
This commit is contained in:
1 parent
4c975eb710
commit
2b9c0e336c
3 files changed
+193
-46
No files matched your search
@@ -16,6 +16,10 @@ SYSFS_PCI_DEVS_PATH = '/bus/pci/devices'
|
||||
SYSFS_PCI_DEV_RESOURCE_PATH = '/resource'
|
||||
SYSFS_PCI_DEV_IRQ_PATH = '/irq'
|
||||
SYSFS_PCI_DEV_DRIVER_DIR_PATH = '/driver'
|
||||
SYSFS_PCI_DEV_VENDOR_PATH = '/vendor'
|
||||
SYSFS_PCI_DEV_DEVICE_PATH = '/device'
|
||||
SYSFS_PCI_DEV_SUBVENDOR_PATH = '/subsystem_vendor'
|
||||
SYSFS_PCI_DEV_SUBDEVICE_PATH = '/subsystem_device'
|
||||
|
||||
PCI_BAR_IO = 0x01
|
||||
PCI_BAR_IO_MASK = ~0x03
|
||||
@@ -66,9 +70,12 @@ class PciDevice:
|
||||
self.iomem = []
|
||||
self.ioports = []
|
||||
self.driver = None
|
||||
self.vendor = None
|
||||
self.device = None
|
||||
self.subvendor = None
|
||||
self.subdevice = None
|
||||
|
||||
if not self.get_info_from_sysfs():
|
||||
self.get_info_from_proc()
|
||||
self.get_info_from_sysfs()
|
||||
|
||||
def get_info_from_sysfs(self):
|
||||
try:
|
||||
@@ -85,7 +92,7 @@ class PciDevice:
|
||||
try:
|
||||
resource_file = open(path,'r')
|
||||
|
||||
for i in range(7):
|
||||
for i in range(PROC_PCI_NUM_RESOURCES):
|
||||
line = resource_file.readline()
|
||||
sline = line.split()
|
||||
if len(sline)<3:
|
||||
@@ -122,53 +129,39 @@ class PciDevice:
|
||||
raise PciDeviceParseError(('Failed to read %s: %s (%d)' %
|
||||
(path, strerr, errno)))
|
||||
|
||||
return True
|
||||
|
||||
def get_info_from_proc(self):
|
||||
bus_devfn = '%02x%02x' % (self.bus,PCI_DEVFN(self.slot,self.func))
|
||||
|
||||
# /proc/bus/pci/devices doesn't expose domains
|
||||
if self.domain!=0:
|
||||
raise PciDeviceParseError("Can't yet detect resource usage by "+
|
||||
"devices in other domains through proc!")
|
||||
|
||||
path = sysfs_mnt+SYSFS_PCI_DEVS_PATH+'/'+ \
|
||||
self.name+SYSFS_PCI_DEV_VENDOR_PATH
|
||||
try:
|
||||
proc_pci_file = open(PROC_PCI_PATH,'r')
|
||||
self.vendor = int(open(path,'r').readline(), 16)
|
||||
except IOError, (errno, strerr):
|
||||
raise PciDeviceParseError(('Failed to open %s: %s (%d)' %
|
||||
(PROC_PCI_PATH, strerr, errno)))
|
||||
raise PciDeviceParseError(('Failed to open & read %s: %s (%d)' %
|
||||
(path, strerr, errno)))
|
||||
|
||||
for line in proc_pci_file:
|
||||
sline = line.split()
|
||||
if len(sline)<(PROC_PCI_NUM_RESOURCES*2+3):
|
||||
continue
|
||||
path = sysfs_mnt+SYSFS_PCI_DEVS_PATH+'/'+ \
|
||||
self.name+SYSFS_PCI_DEV_DEVICE_PATH
|
||||
try:
|
||||
self.device = int(open(path,'r').readline(), 16)
|
||||
except IOError, (errno, strerr):
|
||||
raise PciDeviceParseError(('Failed to open & read %s: %s (%d)' %
|
||||
(path, strerr, errno)))
|
||||
|
||||
if sline[0]==bus_devfn:
|
||||
self.dissect_proc_pci_line(sline)
|
||||
break
|
||||
else:
|
||||
raise PciDeviceNotFoundError(self.domain, self.bus,
|
||||
self.slot, self.func)
|
||||
path = sysfs_mnt+SYSFS_PCI_DEVS_PATH+'/'+ \
|
||||
self.name+SYSFS_PCI_DEV_SUBVENDOR_PATH
|
||||
try:
|
||||
self.subvendor = int(open(path,'r').readline(), 16)
|
||||
except IOError, (errno, strerr):
|
||||
raise PciDeviceParseError(('Failed to open & read %s: %s (%d)' %
|
||||
(path, strerr, errno)))
|
||||
|
||||
def dissect_proc_pci_line(self, sline):
|
||||
self.irq = int(sline[2],16)
|
||||
start_idx = 3
|
||||
for i in range(PROC_PCI_NUM_RESOURCES):
|
||||
flags = int(sline[start_idx+i],16)
|
||||
size = int(sline[start_idx+i+PROC_PCI_NUM_RESOURCES],16)
|
||||
if flags&PCI_BAR_IO:
|
||||
start = flags&PCI_BAR_IO_MASK
|
||||
if start!=0:
|
||||
self.ioports.append( (start,size) )
|
||||
else:
|
||||
start = flags&PCI_BAR_MEM_MASK
|
||||
if start!=0:
|
||||
self.iomem.append( (start,size) )
|
||||
path = sysfs_mnt+SYSFS_PCI_DEVS_PATH+'/'+ \
|
||||
self.name+SYSFS_PCI_DEV_SUBDEVICE_PATH
|
||||
try:
|
||||
self.subdevice = int(open(path,'r').readline(), 16)
|
||||
except IOError, (errno, strerr):
|
||||
raise PciDeviceParseError(('Failed to open & read %s: %s (%d)' %
|
||||
(path, strerr, errno)))
|
||||
|
||||
# detect driver module name
|
||||
driver_idx = PROC_PCI_NUM_RESOURCES*2+3
|
||||
if len(sline)>driver_idx:
|
||||
self.driver = sline[driver_idx]
|
||||
return True
|
||||
|
||||
def __str__(self):
|
||||
str = "PCI Device %s\n" % (self.name)
|
||||
@@ -176,7 +169,11 @@ class PciDevice:
|
||||
str = str + "IO Port 0x%02x [size=%d]\n"%(start,size)
|
||||
for (start,size) in self.iomem:
|
||||
str = str + "IO Mem 0x%02x [size=%d]\n"%(start,size)
|
||||
str = str + "IRQ %d"%(self.irq)
|
||||
str = str + "IRQ %d\n"%(self.irq)
|
||||
str = str + "Vendor ID 0x%04x\n"%(self.vendor)
|
||||
str = str + "Device ID 0x%04x\n"%(self.device)
|
||||
str = str + "Sybsystem Vendor ID 0x%04x\n"%(self.subvendor)
|
||||
str = str + "Subsystem Device ID 0x%04x"%(self.subdevice)
|
||||
return str
|
||||
|
||||
def main():
|
||||
|
||||
@@ -33,6 +33,8 @@ from xen.util.pci import PciDevice
|
||||
import resource
|
||||
import re
|
||||
|
||||
from xen.xend.server.pciquirk import *
|
||||
|
||||
xc = xen.lowlevel.xc.xc()
|
||||
|
||||
#Calculate PAGE_SHIFT: number of bits to shift an address to get the page number
|
||||
@@ -150,7 +152,10 @@ class PciController(DevController):
|
||||
"bind your slot/device to the PCI backend using sysfs" \
|
||||
)%(dev.name))
|
||||
|
||||
for (start, size) in dev.ioports:
|
||||
PCIQuirk(dev.vendor, dev.device, dev.subvendor, dev.subdevice, domain,
|
||||
bus, slot, func)
|
||||
|
||||
for (start, size) in dev.ioports:
|
||||
log.debug('pci: enabling ioport 0x%x/0x%x'%(start,size))
|
||||
rc = xc.domain_ioport_permission(dom = fe_domid, first_port = start,
|
||||
nr_ports = size, allow_access = True)
|
||||
|
||||
@@ -0,0 +1,145 @@
|
||||
from xen.xend.XendLogging import log
|
||||
from xen.xend.XendError import XendError
|
||||
import sys
|
||||
import os.path
|
||||
from xen.xend.sxp import *
|
||||
|
||||
QUIRK_SYSFS_NODE = "/sys/bus/pci/drivers/pciback/quirks"
|
||||
QUIRK_CONFIG_FILE = "/etc/xen/xend-pci-quirks.sxp"
|
||||
PERMISSIVE_CONFIG_FILE = "/etc/xen/xend-pci-permissive.sxp"
|
||||
PERMISSIVE_SYSFS_NODE = "/sys/bus/pci/drivers/pciback/permissive"
|
||||
|
||||
class PCIQuirk:
|
||||
def __init__( self, vendor, device, subvendor, subdevice, domain, bus, slot, func):
|
||||
self.vendor = vendor
|
||||
self.device = device
|
||||
self.subvendor = subvendor
|
||||
self.subdevice = subdevice
|
||||
self.domain = domain
|
||||
self.bus = bus
|
||||
self.slot = slot
|
||||
self.func = func
|
||||
|
||||
self.devid = "%04x:%04x:%04x:%04x" % (vendor, device, subvendor, subdevice)
|
||||
self.pciid = "%04x:%02x:%02x.%01x" % (domain, bus, slot, func)
|
||||
|
||||
self.quirks = self.__getQuirksByID( )
|
||||
|
||||
self.__sendQuirks( )
|
||||
self.__sendPermDevs( )
|
||||
|
||||
def __matchPCIdev( self, list ):
|
||||
ret = False
|
||||
if list == None:
|
||||
return False
|
||||
for id in list:
|
||||
if id.startswith( self.devid[:9] ): # id's vendor and device ID match
|
||||
skey = id.split(':')
|
||||
size = len(skey)
|
||||
if (size == 2): # subvendor/subdevice not suplied
|
||||
ret = True
|
||||
break
|
||||
elif (size == 4): # check subvendor/subdevice
|
||||
# check subvendor
|
||||
subven = '%04x' % self.subvendor
|
||||
if ((skey[2] != 'FFFF') and
|
||||
(skey[2] != 'ffff') and
|
||||
(skey[2] != subven)):
|
||||
continue
|
||||
# check subdevice
|
||||
subdev = '%04x' % self.subdevice
|
||||
if ((skey[3] != 'FFFF') and
|
||||
(skey[3] != 'ffff') and
|
||||
(skey[3] != subdev)):
|
||||
continue
|
||||
ret = True
|
||||
break
|
||||
else:
|
||||
log.debug("WARNING: invalid configuration entry: %s" % id)
|
||||
ret = False
|
||||
break
|
||||
return ret
|
||||
|
||||
def __getQuirksByID( self ):
|
||||
if os.path.exists(QUIRK_CONFIG_FILE):
|
||||
try:
|
||||
fin = file(QUIRK_CONFIG_FILE, 'rb')
|
||||
try:
|
||||
pci_quirks_config = parse(fin)
|
||||
finally:
|
||||
fin.close()
|
||||
if pci_quirks_config is None:
|
||||
pci_quirks_config = ['xend-pci-quirks']
|
||||
else:
|
||||
pci_quirks_config.insert(0, 'xend-pci-quirks')
|
||||
self.pci_quirks_config = pci_quirks_config
|
||||
except Exception, ex:
|
||||
raise XendError("Reading config file %s: %s" %
|
||||
(QUIRK_CONFIG_FILE, str(ex)))
|
||||
else:
|
||||
log.info("Config file does not exist: %s" % QUIRK_CONFIG_FILE)
|
||||
self.pci_quirks_config = ['xend-pci-quirks']
|
||||
|
||||
devices = children(self.pci_quirks_config)
|
||||
for dev in devices:
|
||||
ids = child_at(child(dev,'pci_ids'),0)
|
||||
fields = child_at(child(dev,'pci_config_space_fields'),0)
|
||||
if self.__matchPCIdev( ids ):
|
||||
log.info("Quirks found for PCI device [%s]" % self.devid)
|
||||
return fields
|
||||
|
||||
log.info("NO quirks found for PCI device [%s]" % self.devid)
|
||||
return []
|
||||
|
||||
def __sendQuirks(self):
|
||||
for quirk in self.quirks:
|
||||
log.debug("Quirk Info: %04x:%02x:%02x.%1x-%s" % (self.domain,
|
||||
self.bus, self.slot, self.func, quirk))
|
||||
try:
|
||||
f = file(QUIRK_SYSFS_NODE ,"w")
|
||||
f.write( "%04x:%02x:%02x.%1x-%s" % (self.domain, self.bus,
|
||||
self.slot, self.func, quirk) )
|
||||
f.close()
|
||||
except Exception, e:
|
||||
raise VmError("pci: failed to open/write/close quirks sysfs " + \
|
||||
"node - " + str(e))
|
||||
|
||||
def __devIsUnconstrained( self ):
|
||||
if os.path.exists(PERMISSIVE_CONFIG_FILE):
|
||||
try:
|
||||
fin = file(PERMISSIVE_CONFIG_FILE, 'rb')
|
||||
try:
|
||||
pci_perm_dev_config = parse(fin)
|
||||
finally:
|
||||
fin.close()
|
||||
if pci_perm_dev_config is None:
|
||||
pci_perm_dev_config = ['']
|
||||
else:
|
||||
pci_perm_dev_config.insert(0, '')
|
||||
self.pci_perm_dev_config = pci_perm_dev_config
|
||||
except Exception, ex:
|
||||
raise XendError("Reading config file %s: %s" %
|
||||
(PERMISSIVE_CONFIG_FILE,str(ex)))
|
||||
else:
|
||||
log.info("Config file does not exist: %s" % PERMISSIVE_CONFIG_FILE)
|
||||
self.pci_perm_dev_config = ['xend-pci-perm-devs']
|
||||
|
||||
devices = child_at(child(pci_perm_dev_config, 'unconstrained_dev_ids'),0)
|
||||
if self.__matchPCIdev( devices ):
|
||||
log.debug("Permissive mode enabled for PCI device [%s]" % self.devid)
|
||||
return True
|
||||
log.debug("Permissive mode NOT enabled for PCI device [%s]" % self.devid)
|
||||
return False
|
||||
|
||||
def __sendPermDevs(self):
|
||||
if self.__devIsUnconstrained( ):
|
||||
log.debug("Unconstrained device: %04x:%02x:%02x.%1x" % (self.domain,
|
||||
self.bus, self.slot, self.func))
|
||||
try:
|
||||
f = file(PERMISSIVE_SYSFS_NODE ,"w")
|
||||
f.write( "%04x:%02x:%02x.%1x" % (self.domain, self.bus,
|
||||
self.slot, self.func) )
|
||||
f.close()
|
||||
except Exception, e:
|
||||
raise VmError("pci: failed to open/write/close permissive " + \
|
||||
"sysfs node: " + str(e))
|
||||