ia64/xen-unstable

changeset 17954:e65fe28b5288

XenAPI: Add Physical PCI Device (PPCI) Support

Signed-off-by: Yosuke Iwamatsu <y-iwamatsu@ab.jp.nec.com>
author Keir Fraser <keir.fraser@citrix.com>
date Thu Jul 03 10:26:16 2008 +0100 (2008-07-03)
parents 3d5f28d6e777
children 52a388ec09f8
files tools/python/xen/util/pci.py tools/python/xen/xend/XendAPI.py tools/python/xen/xend/XendNode.py tools/python/xen/xend/XendPPCI.py
line diff
     1.1 --- a/tools/python/xen/util/pci.py	Wed Jul 02 17:28:27 2008 +0100
     1.2 +++ b/tools/python/xen/util/pci.py	Thu Jul 03 10:26:16 2008 +0100
     1.3 @@ -8,6 +8,8 @@
     1.4  import sys
     1.5  import os, os.path
     1.6  import resource
     1.7 +import re
     1.8 +import types
     1.9  
    1.10  PROC_MNT_PATH = '/proc/mounts'
    1.11  PROC_PCI_PATH = '/proc/bus/pci/devices'
    1.12 @@ -22,6 +24,9 @@ SYSFS_PCI_DEV_VENDOR_PATH = '/vendor'
    1.13  SYSFS_PCI_DEV_DEVICE_PATH = '/device'
    1.14  SYSFS_PCI_DEV_SUBVENDOR_PATH = '/subsystem_vendor'
    1.15  SYSFS_PCI_DEV_SUBDEVICE_PATH = '/subsystem_device'
    1.16 +SYSFS_PCI_DEV_CLASS_PATH = '/class'
    1.17 +
    1.18 +LSPCI_CMD = 'lspci'
    1.19  
    1.20  PCI_BAR_IO = 0x01
    1.21  PCI_BAR_IO_MASK = ~0x03
    1.22 @@ -32,6 +37,9 @@ PCI_CAP_OFFSET = 0x34
    1.23  MSIX_BIR_MASK = 0x7
    1.24  MSIX_SIZE_MASK = 0x7ff
    1.25  
    1.26 +# Global variable to store information from lspci
    1.27 +lspci_info = None
    1.28 +
    1.29  #Calculate PAGE_SHIFT: number of bits to shift an address to get the page number
    1.30  PAGE_SIZE = resource.getpagesize()
    1.31  PAGE_SHIFT = 0
    1.32 @@ -45,6 +53,15 @@ PAGE_MASK=~(PAGE_SIZE - 1)
    1.33  def PCI_DEVFN(slot, func):
    1.34      return ((((slot) & 0x1f) << 3) | ((func) & 0x07))
    1.35  
    1.36 +def parse_hex(val):
    1.37 +    try:
    1.38 +        if isinstance(val, types.StringTypes):
    1.39 +            return int(val, 16)
    1.40 +        else:
    1.41 +            return val
    1.42 +    except ValueError:
    1.43 +        return None
    1.44 +
    1.45  def find_sysfs_mnt():
    1.46      mounts_file = open(PROC_MNT_PATH,'r')
    1.47  
    1.48 @@ -58,6 +75,61 @@ def find_sysfs_mnt():
    1.49  
    1.50      return None
    1.51  
    1.52 +def get_all_pci_names():
    1.53 +    try:
    1.54 +        sysfs_mnt = find_sysfs_mnt()
    1.55 +    except IOError, (errno, strerr):
    1.56 +        raise PciDeviceParseError(('Failed to locate sysfs mount: %s (%d)' %
    1.57 +            (PROC_PCI_PATH, strerr, errno)))
    1.58 +
    1.59 +    pci_names = os.popen('ls ' + sysfs_mnt + SYSFS_PCI_DEVS_PATH).read().split()
    1.60 +
    1.61 +    return pci_names
    1.62 +
    1.63 +def get_all_pci_devices():
    1.64 +    pci_devs = []
    1.65 +    for pci_name in get_all_pci_names():
    1.66 +        pci_match = re.match(r"((?P<domain>[0-9a-fA-F]{1,4})[:,])?" + \
    1.67 +                r"(?P<bus>[0-9a-fA-F]{1,2})[:,]" + \
    1.68 +                r"(?P<slot>[0-9a-fA-F]{1,2})[.,]" + \
    1.69 +                r"(?P<func>[0-7])$", pci_name)
    1.70 +        if pci_match is None:
    1.71 +            raise PciDeviceParseError(('Failed to parse pci device name: %s' %
    1.72 +                pci_name))
    1.73 +        pci_dev_info = pci_match.groupdict('0')
    1.74 +        domain = parse_hex(pci_dev_info['domain'])
    1.75 +        bus = parse_hex(pci_dev_info['bus'])
    1.76 +        slot = parse_hex(pci_dev_info['slot'])
    1.77 +        func = parse_hex(pci_dev_info['func'])
    1.78 +        try:
    1.79 +            pci_dev = PciDevice(domain, bus, slot, func)
    1.80 +        except:
    1.81 +            continue
    1.82 +        pci_devs.append(pci_dev)
    1.83 +
    1.84 +    return pci_devs
    1.85 +
    1.86 +def create_lspci_info():
    1.87 +    global lspci_info
    1.88 +    lspci_info = {}
    1.89 +
    1.90 +    # Execute 'lspci' command and parse the result.
    1.91 +    # If the command does not exist, lspci_info will be kept blank ({}).
    1.92 +    for paragraph in os.popen(LSPCI_CMD + ' -vmmD').read().split('\n\n'):
    1.93 +        device_name = None
    1.94 +        device_info = {}
    1.95 +        for line in paragraph.split('\n'):
    1.96 +            try:
    1.97 +                (opt, value) = line.split(':\t')
    1.98 +                if opt == 'Slot':
    1.99 +                    device_name = value
   1.100 +                else:
   1.101 +                    device_info[opt] = value
   1.102 +            except:
   1.103 +                pass
   1.104 +        if device_name is not None:
   1.105 +            lspci_info[device_name] = device_info
   1.106 +
   1.107  class PciDeviceNotFoundError(Exception):
   1.108      def __init__(self,domain,bus,slot,func):
   1.109          self.domain = domain
   1.110 @@ -92,7 +164,15 @@ class PciDevice:
   1.111          self.subdevice = None
   1.112          self.msix = 0
   1.113          self.msix_iomem = []
   1.114 +        self.revision = 0
   1.115 +        self.classcode = None
   1.116 +        self.vendorname = ""
   1.117 +        self.devicename = ""
   1.118 +        self.classname = ""
   1.119 +        self.subvendorname = ""
   1.120 +        self.subdevicename = ""
   1.121          self.get_info_from_sysfs()
   1.122 +        self.get_info_from_lspci()
   1.123  
   1.124      def find_capability(self, type):
   1.125          try:
   1.126 @@ -208,9 +288,8 @@ class PciDevice:
   1.127                  self.name+SYSFS_PCI_DEV_DRIVER_DIR_PATH
   1.128          try:
   1.129              self.driver = os.path.basename(os.readlink(path))
   1.130 -        except IOError, (errno, strerr):
   1.131 -            raise PciDeviceParseError(('Failed to read %s: %s (%d)' %
   1.132 -                (path, strerr, errno)))
   1.133 +        except OSError, (errno, strerr):
   1.134 +            self.driver = ""
   1.135  
   1.136          path = sysfs_mnt+SYSFS_PCI_DEVS_PATH+'/'+ \
   1.137                  self.name+SYSFS_PCI_DEV_VENDOR_PATH
   1.138 @@ -244,6 +323,36 @@ class PciDevice:
   1.139              raise PciDeviceParseError(('Failed to open & read %s: %s (%d)' %
   1.140                  (path, strerr, errno)))
   1.141  
   1.142 +        path = sysfs_mnt+SYSFS_PCI_DEVS_PATH+'/'+ \
   1.143 +                self.name+SYSFS_PCI_DEV_CLASS_PATH
   1.144 +        try:
   1.145 +            self.classcode = int(open(path,'r').readline(), 16)
   1.146 +        except IOError, (errno, strerr):
   1.147 +            raise PciDeviceParseError(('Failed to open & read %s: %s (%d)' %
   1.148 +                (path, strerr, errno)))
   1.149 +
   1.150 +        return True
   1.151 +
   1.152 +    def get_info_from_lspci(self):
   1.153 +        """ Get information such as vendor name, device name, class name, etc.
   1.154 +        Since we cannot obtain these data from sysfs, use 'lspci' command.
   1.155 +        """
   1.156 +        global lspci_info
   1.157 +
   1.158 +        if lspci_info is None:
   1.159 +            create_lspci_info()
   1.160 +
   1.161 +        try:
   1.162 +            device_info = lspci_info[self.name]
   1.163 +            self.revision = int(device_info['Rev'], 16)
   1.164 +            self.vendorname = device_info['Vendor']
   1.165 +            self.devicename = device_info['Device']
   1.166 +            self.classname = device_info['Class']
   1.167 +            self.subvendorname = device_info['SVendor']
   1.168 +            self.subdevicename = device_info['SDevice']
   1.169 +        except KeyError:
   1.170 +            pass
   1.171 +
   1.172          return True
   1.173  
   1.174      def __str__(self):
     2.1 --- a/tools/python/xen/xend/XendAPI.py	Wed Jul 02 17:28:27 2008 +0100
     2.2 +++ b/tools/python/xen/xend/XendAPI.py	Thu Jul 03 10:26:16 2008 +0100
     2.3 @@ -40,6 +40,7 @@ from XendPIFMetrics import XendPIFMetric
     2.4  from XendVMMetrics import XendVMMetrics
     2.5  from XendPIF import XendPIF
     2.6  from XendPBD import XendPBD
     2.7 +from XendPPCI import XendPPCI
     2.8  from XendXSPolicy import XendXSPolicy, XendACMPolicy
     2.9  
    2.10  from XendAPIConstants import *
    2.11 @@ -476,7 +477,8 @@ classes = {
    2.12      'PIF'          : valid_object("PIF"),
    2.13      'VM_metrics'   : valid_object("VM_metrics"),
    2.14      'PBD'          : valid_object("PBD"),
    2.15 -    'PIF_metrics'  : valid_object("PIF_metrics")
    2.16 +    'PIF_metrics'  : valid_object("PIF_metrics"),
    2.17 +    'PPCI'         : valid_object("PPCI"),
    2.18  }
    2.19  
    2.20  autoplug_classes = {
    2.21 @@ -485,6 +487,7 @@ autoplug_classes = {
    2.22      'VM_metrics'  : XendVMMetrics,
    2.23      'PBD'         : XendPBD,
    2.24      'PIF_metrics' : XendPIFMetrics,
    2.25 +    'PPCI'        : XendPPCI,
    2.26      'XSPolicy'    : XendXSPolicy,
    2.27      'ACMPolicy'   : XendACMPolicy,
    2.28  }
    2.29 @@ -874,6 +877,7 @@ class XendAPI(object):
    2.30                      'resident_VMs',
    2.31                      'PBDs',
    2.32                      'PIFs',
    2.33 +                    'PPCIs',
    2.34                      'host_CPUs',
    2.35                      'cpu_configuration',
    2.36                      'metrics',
    2.37 @@ -952,6 +956,8 @@ class XendAPI(object):
    2.38          return xen_api_success(XendPBD.get_all())
    2.39      def host_get_PIFs(self, session, ref):
    2.40          return xen_api_success(XendNode.instance().get_PIF_refs())
    2.41 +    def host_get_PPCIs(self, session, ref):
    2.42 +        return xen_api_success(XendNode.instance().get_PPCI_refs())
    2.43      def host_get_host_CPUs(self, session, host_ref):
    2.44          return xen_api_success(XendNode.instance().get_host_cpu_refs())
    2.45      def host_get_metrics(self, _, ref):
    2.46 @@ -1027,7 +1033,8 @@ class XendAPI(object):
    2.47                    'sched_policy': node.get_vcpus_policy(),
    2.48                    'logging': {},
    2.49                    'PIFs': XendPIF.get_all(),
    2.50 -                  'PBDs': XendPBD.get_all()}
    2.51 +                  'PBDs': XendPBD.get_all(),
    2.52 +                  'PPCIs': XendPPCI.get_all()}
    2.53          return xen_api_success(record)
    2.54  
    2.55      # class methods
    2.56 @@ -1288,7 +1295,7 @@ class XendAPI(object):
    2.57      def VM_get_consoles(self, session, vm_ref):
    2.58          dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
    2.59          return xen_api_success(dom.get_consoles())
    2.60 -    
    2.61 +
    2.62      def VM_get_tools_version(self, session, vm_ref):
    2.63          dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
    2.64          return dom.get_tools_version()
     3.1 --- a/tools/python/xen/xend/XendNode.py	Wed Jul 02 17:28:27 2008 +0100
     3.2 +++ b/tools/python/xen/xend/XendNode.py	Thu Jul 03 10:26:16 2008 +0100
     3.3 @@ -21,6 +21,7 @@ import socket
     3.4  import xen.lowlevel.xc
     3.5  
     3.6  from xen.util import Brctl
     3.7 +from xen.util import pci as PciUtil
     3.8  from xen.xend import XendAPIStore
     3.9  
    3.10  import uuid, arch
    3.11 @@ -35,6 +36,7 @@ from XendPIFMetrics import XendPIFMetric
    3.12  from XendNetwork import *
    3.13  from XendStateStore import XendStateStore
    3.14  from XendMonitor import XendMonitor
    3.15 +from XendPPCI import XendPPCI
    3.16       
    3.17  class XendNode:
    3.18      """XendNode - Represents a Domain 0 Host."""
    3.19 @@ -49,6 +51,7 @@ class XendNode:
    3.20          * PIF_metrics
    3.21          * network
    3.22          * Storage Repository
    3.23 +        * PPCI
    3.24          """
    3.25          
    3.26          self.xc = xen.lowlevel.xc.xc()
    3.27 @@ -230,6 +233,41 @@ class XendNode:
    3.28                  except CreateUnspecifiedAttributeError:
    3.29                      log.warn("Error recreating PBD %s", pbd_uuid) 
    3.30  
    3.31 +
    3.32 +        # Initialise PPCIs
    3.33 +        saved_ppcis = self.state_store.load_state('ppci')
    3.34 +        saved_ppci_table = {}
    3.35 +        if saved_ppcis:
    3.36 +            for ppci_uuid, ppci_record in saved_ppcis.items():
    3.37 +                try:
    3.38 +                    saved_ppci_table[ppci_record['name']] = ppci_uuid
    3.39 +                except KeyError:
    3.40 +                    pass
    3.41 +
    3.42 +        for pci_dev in PciUtil.get_all_pci_devices():
    3.43 +            ppci_record = {
    3.44 +                'domain':                   pci_dev.domain,
    3.45 +                'bus':                      pci_dev.bus,
    3.46 +                'slot':                     pci_dev.slot,
    3.47 +                'func':                     pci_dev.func,
    3.48 +                'vendor_id':                pci_dev.vendor,
    3.49 +                'vendor_name':              pci_dev.vendorname,
    3.50 +                'device_id':                pci_dev.device,
    3.51 +                'device_name':              pci_dev.devicename,
    3.52 +                'revision_id':              pci_dev.revision,
    3.53 +                'class_code':               pci_dev.classcode,
    3.54 +                'class_name':               pci_dev.classname,
    3.55 +                'subsystem_vendor_id':      pci_dev.subvendor,
    3.56 +                'subsystem_vendor_name':    pci_dev.subvendorname,
    3.57 +                'subsystem_id':             pci_dev.subdevice,
    3.58 +                'subsystem_name':           pci_dev.subdevicename,
    3.59 +                'driver':                   pci_dev.driver
    3.60 +                }
    3.61 +            # If saved uuid exists, use it. Otherwise create one.
    3.62 +            ppci_uuid = saved_ppci_table.get(pci_dev.name, uuid.createString())
    3.63 +            XendPPCI(ppci_uuid, ppci_record)
    3.64 +
    3.65 +
    3.66  ##    def network_destroy(self, net_uuid):
    3.67   ##       del self.networks[net_uuid]
    3.68    ##      self.save_networks()
    3.69 @@ -272,6 +310,15 @@ class XendNode:
    3.70  ##         self.save_PIFs()
    3.71  
    3.72  
    3.73 +    def get_PPCI_refs(self):
    3.74 +        return XendPPCI.get_all()
    3.75 +
    3.76 +    def get_ppci_by_uuid(self, ppci_uuid):
    3.77 +        if ppci_uuid in self.get_PPCI_refs():
    3.78 +            return ppci_uuid
    3.79 +        return None
    3.80 +
    3.81 +
    3.82      def save(self):
    3.83          # save state
    3.84          host_record = {self.uuid: {'name_label':self.name,
    3.85 @@ -284,6 +331,7 @@ class XendNode:
    3.86          self.save_networks()
    3.87          self.save_PBDs()
    3.88          self.save_SRs()
    3.89 +        self.save_PPCIs()
    3.90  
    3.91      def save_PIFs(self):
    3.92          pif_records = dict([(pif_uuid, XendAPIStore.get(
    3.93 @@ -308,6 +356,12 @@ class XendNode:
    3.94                              for k, v in self.srs.items()])
    3.95          self.state_store.save_state('sr', sr_records)
    3.96  
    3.97 +    def save_PPCIs(self):
    3.98 +        ppci_records = dict([(ppci_uuid, XendAPIStore.get(
    3.99 +                                 ppci_uuid, "PPCI").get_record())
   3.100 +                            for ppci_uuid in XendPPCI.get_all()])
   3.101 +        self.state_store.save_state('ppci', ppci_records)
   3.102 +
   3.103      def shutdown(self):
   3.104          return 0
   3.105  
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/tools/python/xen/xend/XendPPCI.py	Thu Jul 03 10:26:16 2008 +0100
     4.3 @@ -0,0 +1,158 @@
     4.4 +#============================================================================
     4.5 +# This library is free software; you can redistribute it and/or
     4.6 +# modify it under the terms of version 2.1 of the GNU Lesser General Public
     4.7 +# License as published by the Free Software Foundation.
     4.8 +#
     4.9 +# This library is distributed in the hope that it will be useful,
    4.10 +# but WITHOUT ANY WARRANTY; without even the implied warranty of
    4.11 +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    4.12 +# Lesser General Public License for more details.
    4.13 +#
    4.14 +# You should have received a copy of the GNU Lesser General Public
    4.15 +# License along with this library; if not, write to the Free Software
    4.16 +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    4.17 +#============================================================================
    4.18 +# Copyright (c) 2008 NEC Corporation
    4.19 +#       Yosuke Iwamatsu <y-iwamatsu at ab jp nec com>
    4.20 +#============================================================================
    4.21 +
    4.22 +from xen.xend.XendBase import XendBase
    4.23 +from xen.xend.XendBase import XendAPIStore
    4.24 +from xen.xend import uuid as genuuid
    4.25 +
    4.26 +class XendPPCI(XendBase):
    4.27 +    """Representation of a physical PCI device."""
    4.28 +
    4.29 +    def getClass(self):
    4.30 +        return "PPCI"
    4.31 +
    4.32 +    def getAttrRO(self):
    4.33 +        attrRO = ['host',
    4.34 +                  'domain',
    4.35 +                  'bus',
    4.36 +                  'slot',
    4.37 +                  'func',
    4.38 +                  'name',
    4.39 +                  'vendor_id',
    4.40 +                  'vendor_name',
    4.41 +                  'device_id',
    4.42 +                  'device_name',
    4.43 +                  'revision_id',
    4.44 +                  'class_code',
    4.45 +                  'class_name',
    4.46 +                  'subsystem_vendor_id',
    4.47 +                  'subsystem_vendor_name',
    4.48 +                  'subsystem_id',
    4.49 +                  'subsystem_name',
    4.50 +                  'driver']
    4.51 +        return XendBase.getAttrRO() + attrRO
    4.52 +
    4.53 +    def getAttrRW(self):
    4.54 +        attrRW = []
    4.55 +        return XendBase.getAttrRW() + attrRW
    4.56 +
    4.57 +    def getAttrInst(self):
    4.58 +        attrInst = []
    4.59 +        return XendBase.getAttrInst() + attrInst
    4.60 +
    4.61 +    def getMethods(self):
    4.62 +        methods = []
    4.63 +        return XendBase.getMethods() + methods
    4.64 +
    4.65 +    def getFuncs(self):
    4.66 +        funcs = []
    4.67 +        return XendBase.getFuncs() + funcs
    4.68 +
    4.69 +    getClass    = classmethod(getClass)
    4.70 +    getAttrRO   = classmethod(getAttrRO)
    4.71 +    getAttrRW   = classmethod(getAttrRW)
    4.72 +    getAttrInst = classmethod(getAttrInst)
    4.73 +    getMethods  = classmethod(getMethods)
    4.74 +    getFuncs    = classmethod(getFuncs)
    4.75 + 
    4.76 +    def get_by_sbdf(self, domain, bus, slot, func):
    4.77 +        for ppci in XendAPIStore.get_all("PPCI"):
    4.78 +            if ppci.get_domain() == int(domain, 16) and \
    4.79 +               ppci.get_bus() == int(bus, 16) and \
    4.80 +               ppci.get_slot() == int(slot, 16) and \
    4.81 +               ppci.get_func() == int(func, 16):
    4.82 +                return ppci.get_uuid()
    4.83 +        return None
    4.84 +
    4.85 +    get_by_sbdf = classmethod(get_by_sbdf)
    4.86 +
    4.87 +    def __init__(self, uuid, record):
    4.88 +        self.domain = record['domain']
    4.89 +        self.bus = record['bus']
    4.90 +        self.slot = record['slot']
    4.91 +        self.func = record['func']
    4.92 +        self.vendor_id = record['vendor_id']
    4.93 +        self.vendor_name = record['vendor_name']
    4.94 +        self.device_id = record['device_id']
    4.95 +        self.device_name = record['device_name']
    4.96 +        self.revision_id = record['revision_id']
    4.97 +        self.class_code = record['class_code']
    4.98 +        self.class_name = record['class_name']
    4.99 +        self.subsystem_vendor_id = record['subsystem_vendor_id']
   4.100 +        self.subsystem_vendor_name = record['subsystem_vendor_name']
   4.101 +        self.subsystem_id = record['subsystem_id']
   4.102 +        self.subsystem_name = record['subsystem_name']
   4.103 +        self.driver = record['driver']
   4.104 +        XendBase.__init__(self, uuid, record)
   4.105 +
   4.106 +    def get_host(self):
   4.107 +        from xen.xend import XendNode
   4.108 +        return XendNode.instance().get_uuid()
   4.109 +
   4.110 +    def get_domain(self):
   4.111 +        return self.domain
   4.112 +
   4.113 +    def get_bus(self):
   4.114 +        return self.bus
   4.115 +
   4.116 +    def get_slot(self):
   4.117 +        return self.slot
   4.118 +
   4.119 +    def get_func(self):
   4.120 +        return self.func
   4.121 +
   4.122 +    def get_name(self):
   4.123 +        return "%04x:%02x:%02x.%01x" % (self.domain, self.bus, self.slot,
   4.124 +                                        self.func)
   4.125 +
   4.126 +    def get_vendor_id(self):
   4.127 +        return self.vendor_id
   4.128 +
   4.129 +    def get_vendor_name(self):
   4.130 +        return self.vendor_name
   4.131 +
   4.132 +    def get_device_id(self):
   4.133 +        return self.device_id
   4.134 +
   4.135 +    def get_device_name(self):
   4.136 +        return self.device_name
   4.137 +
   4.138 +    def get_class_code(self):
   4.139 +        return self.class_code
   4.140 +
   4.141 +    def get_class_name(self):
   4.142 +        return self.class_name
   4.143 +
   4.144 +    def get_revision_id(self):
   4.145 +        return self.revision_id
   4.146 +
   4.147 +    def get_subsystem_vendor_id(self):
   4.148 +        return self.subsystem_vendor_id
   4.149 +
   4.150 +    def get_subsystem_vendor_name(self):
   4.151 +        return self.subsystem_vendor_name
   4.152 +
   4.153 +    def get_subsystem_id(self):
   4.154 +        return self.subsystem_id
   4.155 +
   4.156 +    def get_subsystem_name(self):
   4.157 +        return self.subsystem_name
   4.158 +
   4.159 +    def get_driver(self):
   4.160 +        return self.driver
   4.161 +