WARNING - OLD ARCHIVES

This is an archived copy of the Xen.org mailing list, which we have preserved to ensure that existing links to archives are not broken. The live archive, which contains the latest emails, can be found at http://lists.xen.org/
   
 
 
Xen 
 
Home Products Support Community News
 
   
 

xen-changelog

[Xen-changelog] [xen-unstable] tools: Add PV passthrough PCI device hotp

To: xen-changelog@xxxxxxxxxxxxxxxxxxx
Subject: [Xen-changelog] [xen-unstable] tools: Add PV passthrough PCI device hotplug support.
From: Xen patchbot-unstable <patchbot-unstable@xxxxxxxxxxxxxxxxxxx>
Date: Thu, 20 Mar 2008 05:40:37 -0700
Delivery-date: Thu, 20 Mar 2008 05:43:32 -0700
Envelope-to: www-data@xxxxxxxxxxxxxxxxxx
List-help: <mailto:xen-changelog-request@lists.xensource.com?subject=help>
List-id: BK change log <xen-changelog.lists.xensource.com>
List-post: <mailto:xen-changelog@lists.xensource.com>
List-subscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-changelog>, <mailto:xen-changelog-request@lists.xensource.com?subject=subscribe>
List-unsubscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-changelog>, <mailto:xen-changelog-request@lists.xensource.com?subject=unsubscribe>
Reply-to: xen-devel@xxxxxxxxxxxxxxxxxxx
Sender: xen-changelog-bounces@xxxxxxxxxxxxxxxxxxx
# HG changeset patch
# User Keir Fraser <keir.fraser@xxxxxxxxxx>
# Date 1205840361 0
# Node ID 3f407392da492ebaa30764406f69549bc11ae791
# Parent  e678b42c36c45bc301d365d4d234216301fb11cc
tools: Add PV passthrough PCI device hotplug support.
Signed-off-by: Yosuke Iwamatsu <y-iwamatsu@xxxxxxxxxxxxx>
---
 tools/python/xen/xend/XendConfig.py           |   17 +
 tools/python/xen/xend/XendDomainInfo.py       |  221 +++++++++++++++++--------
 tools/python/xen/xend/server/DevController.py |   50 +++++
 tools/python/xen/xend/server/pciif.py         |  229 ++++++++++++++++++++++----
 tools/python/xen/xm/main.py                   |   53 +++---
 5 files changed, 452 insertions(+), 118 deletions(-)

diff -r e678b42c36c4 -r 3f407392da49 tools/python/xen/xend/XendConfig.py
--- a/tools/python/xen/xend/XendConfig.py       Tue Mar 18 11:34:44 2008 +0000
+++ b/tools/python/xen/xend/XendConfig.py       Tue Mar 18 11:39:21 2008 +0000
@@ -1461,6 +1461,23 @@ class XendConfig(dict):
                 config = cfg_sxp
 
             dev_type, dev_info = self['devices'][dev_uuid]
+
+            if dev_type == 'pci': # Special case for pci
+                pci_devs = []
+                for pci_dev in sxp.children(config, 'dev'):
+                    pci_dev_info = {}
+                    for opt_val in pci_dev[1:]:
+                        try:
+                            opt, val = opt_val
+                            pci_dev_info[opt] = val
+                        except TypeError:
+                            pass
+                    pci_devs.append(pci_dev_info)
+                self['devices'][dev_uuid] = (dev_type,
+                                             {'devs': pci_devs,
+                                              'uuid': dev_uuid})
+                return True
+                
             for opt_val in config[1:]:
                 try:
                     opt, val = opt_val
diff -r e678b42c36c4 -r 3f407392da49 tools/python/xen/xend/XendDomainInfo.py
--- a/tools/python/xen/xend/XendDomainInfo.py   Tue Mar 18 11:34:44 2008 +0000
+++ b/tools/python/xen/xend/XendDomainInfo.py   Tue Mar 18 11:39:21 2008 +0000
@@ -558,18 +558,17 @@ class XendDomainInfo:
             count += 1
 
 
-    def pci_device_create(self, dev_config):
-        log.debug("XendDomainInfo.pci_device_create: %s" % 
scrub_password(dev_config))
+    def hvm_pci_device_create(self, dev_config):
+        log.debug("XendDomainInfo.hvm_pci_device_create: %s"
+                  % scrub_password(dev_config))
 
         if not self.info.is_hvm():
-            raise VmError("only HVM guest support pci attach")
+            raise VmError("hvm_pci_device_create called on non-HVM guest")
 
         #all the PCI devs share one conf node
         devid = '0'
 
-        dev_type = sxp.name(dev_config)
-        new_devs = sxp.child_value(dev_config, 'devs')
-        new_dev = new_devs[0]
+        new_dev = dev_config['devs'][0]
         dev_info = self._getDeviceInfo_pci(devid)#from self.info['devices']
 
         #check conflict before trigger hotplug event
@@ -611,35 +610,6 @@ class XendDomainInfo:
                 new_dev['vslt'])
         self.image.signalDeviceModel('pci-ins', 'pci-inserted', bdf_str)
 
-        # update the virtual pci slot
-        vslt = xstransact.Read("/local/domain/0/device-model/%i/parameter"
-                          % self.getDomid())
-        new_dev['vslt'] = vslt
-
-        if dev_info is None:
-            # create a new one from scrach
-            dev_cfg_sxp = [dev_type,
-                ['dev',
-                  ['domain', new_dev['domain']],
-                  ['bus',    new_dev['bus']],
-                  ['slot',   new_dev['slot']],
-                  ['func',   new_dev['func']],
-                  ['vslt',   new_dev['vslt']]
-                ]]
-            dev_uuid = self.info.device_add(dev_type, cfg_sxp = dev_cfg_sxp)
-            dev_config_dict = self.info['devices'][dev_uuid][1]
-            try:
-                dev_config_dict['devid'] = devid = \
-                    self._createDevice(dev_type, dev_config_dict)
-                self._waitForDevice(dev_type, devid)
-            except VmError, ex:
-                raise ex
-        else:
-            # update the pci config to add the new dev
-            pci_devs.extend(new_devs)
-            self._reconfigureDevice('pci', devid, pci_conf)
-
-        return self.getDeviceController('pci').sxpr(devid)
 
     def device_create(self, dev_config):
         """Create a new device.
@@ -649,11 +619,6 @@ class XendDomainInfo:
         """
         log.debug("XendDomainInfo.device_create: %s" % 
scrub_password(dev_config))
         dev_type = sxp.name(dev_config)
-
-        if dev_type == 'pci':
-            rc = self.pci_device_create(dev_config)
-            return rc
-
         dev_uuid = self.info.device_add(dev_type, cfg_sxp = dev_config)
         dev_config_dict = self.info['devices'][dev_uuid][1]
         log.debug("XendDomainInfo.device_create: %s" % 
scrub_password(dev_config_dict))
@@ -676,6 +641,151 @@ class XendDomainInfo:
         xen.xend.XendDomain.instance().managed_config_save(self)
         return self.getDeviceController(dev_type).sxpr(devid)
 
+    def pci_convert_sxp_to_dict(self, dev_sxp):
+        """Convert pci device sxp to dict
+        @param dev_sxp: device configuration
+        @type  dev_sxp: SXP object (parsed config)
+        @return: dev_config
+        @rtype: dictionary
+        """
+        # In reconfigure phase, config of PCI device looks like below:
+        #
+        # sxp:
+        # [device, [pci, [dev, [domain, '0x0'], [bus, '0x0'], [slot, '0x0'],
+        #                      [func, '0x0'], [vslt, '0x0']],
+        #                [state, 'Initialising']]]
+        #
+        # dict:
+        # {devs: [{domain: '0x0', bus: '0x0', slot: '0x0', func: '0x0',
+        #          vslt: '0x0'}],
+        #  states: ['Initialising']}
+        #
+        # state 'Initialising' means the device is being attached.
+        # state 'Closing' means the device is being detached.
+
+        dev_config = {}
+        pci_devs = []
+        for pci_dev in sxp.children(dev_sxp, 'dev'):
+            pci_dev_info = {}
+            for opt_val in pci_dev[1:]:
+                try:
+                    opt, val = opt_val
+                    pci_dev_info[opt] = val
+                except TypeError:
+                    pass
+            pci_devs.append(pci_dev_info)
+        dev_config['devs'] = pci_devs 
+        pci_states = []
+        for pci_state in sxp.children(dev_sxp, 'state'):
+            try:
+                pci_states.append(pci_state[1])
+            except IndexError:
+                raise XendError("Error reading state while parsing pci sxp")
+        dev_config['states'] = pci_states
+        
+        return dev_config
+ 
+    def pci_device_configure(self, dev_sxp, devid = 0):
+        """Configure an existing pci device.
+        
+        @param dev_sxp: device configuration
+        @type  dev_sxp: SXP object (parsed config)
+        @param devid:      device id
+        @type  devid:      int
+        @return: Returns True if successfully updated device
+        @rtype: boolean
+        """
+        log.debug("XendDomainInfo.pci_device_configure: %s"
+                  % scrub_password(dev_sxp))
+
+        dev_class = sxp.name(dev_sxp)
+
+        if dev_class != 'pci':
+            return False
+
+        pci_state = sxp.child_value(dev_sxp, 'state')
+        existing_dev_info = self._getDeviceInfo_pci(devid)
+
+        if existing_dev_info is None and pci_state != 'Initialising':
+            raise XendError("Cannot detach when pci platform does not exist")
+
+        pci_dev = sxp.children(dev_sxp, 'dev')[0]
+        dev_config = self.pci_convert_sxp_to_dict(dev_sxp)
+        dev = dev_config['devs'][0]
+                
+        # Do HVM specific processing
+        if self.info.is_hvm():
+            if pci_state == 'Initialising':
+                # HVM PCI device attachment
+                self.hvm_pci_device_create(dev_config)
+                # Update vslt
+                vslt = 
xstransact.Read("/local/domain/0/device-model/%i/parameter"
+                                       % self.getDomid())
+                dev['vslt'] = vslt
+                for n in sxp.children(pci_dev):
+                    if(n[0] == 'vslt'):
+                        n[1] = vslt
+            else:
+                # HVM PCI device detachment
+                existing_dev_uuid = sxp.child_value(existing_dev_info, 'uuid')
+                existing_pci_conf = self.info['devices'][existing_dev_uuid][1]
+                existing_pci_devs = existing_pci_conf['devs']
+                vslt = '0x0'
+                for x in existing_pci_devs:
+                    if ( int(x['domain'], 16) == int(dev['domain'], 16) and
+                         int(x['bus'], 16) == int(dev['bus'], 16) and
+                         int(x['slot'], 16) == int(dev['slot'], 16) and
+                         int(x['func'], 16) == int(dev['func'], 16) ):
+                        vslt = x['vslt']
+                        break
+                if vslt == '0x0':
+                    raise VmError("Device %04x:%02x:%02x.%02x is not connected"
+                                  % (int(dev['domain'],16), int(dev['bus'],16),
+                                     int(dev['slot'],16), int(dev['func'],16)))
+                self.hvm_destroyPCIDevice(int(vslt, 16))
+                # Update vslt
+                dev['vslt'] = vslt
+                for n in sxp.children(pci_dev):
+                    if(n[0] == 'vslt'):
+                        n[1] = vslt
+
+        # If pci platform does not exist, create and exit.
+        if existing_dev_info is None:
+            self.device_create(dev_sxp)
+            return True
+
+        # use DevController.reconfigureDevice to change device config
+        dev_control = self.getDeviceController(dev_class)
+        dev_uuid = dev_control.reconfigureDevice(devid, dev_config)
+        if not self.info.is_hvm():
+            # in PV case, wait until backend state becomes connected.
+            dev_control.waitForDevice_reconfigure(devid)
+        num_devs = dev_control.cleanupDevice(devid)
+
+        # update XendConfig with new device info
+        if dev_uuid:
+            new_dev_sxp = dev_control.configuration(devid)
+            self.info.device_update(dev_uuid, new_dev_sxp)
+
+        # If there is no device left, destroy pci and remove config.
+        if num_devs == 0:
+            if self.info.is_hvm():
+                self.destroyDevice('pci', devid, True)
+                del self.info['devices'][dev_uuid]
+                platform = self.info['platform']
+                orig_dev_num = len(platform['pci'])
+                # TODO: can use this to keep some info to ask high level
+                # management tools to hot insert a new passthrough dev
+                # after migration
+                if orig_dev_num != 0:
+                    #platform['pci'] = ["%dDEVs" % orig_dev_num]
+                    platform['pci'] = []
+            else:
+                self.destroyDevice('pci', devid)
+                del self.info['devices'][dev_uuid]
+
+        return True
+
     def device_configure(self, dev_sxp, devid = None):
         """Configure an existing device.
         
@@ -690,6 +800,10 @@ class XendDomainInfo:
         # convert device sxp to a dict
         dev_class = sxp.name(dev_sxp)
         dev_config = {}
+
+        if dev_class == 'pci':
+            return self.pci_device_configure(dev_sxp)
+
         for opt_val in dev_sxp[1:]:
             try:
                 dev_config[opt_val[0]] = opt_val[1]
@@ -714,11 +828,11 @@ class XendDomainInfo:
         for devclass in XendDevices.valid_devices():
             self.getDeviceController(devclass).waitForDevices()
 
-    def destroyPCIDevice(self, vslot):
-        log.debug("destroyPCIDevice called %s", vslot)
+    def hvm_destroyPCIDevice(self, vslot):
+        log.debug("hvm_destroyPCIDevice called %s", vslot)
 
         if not self.info.is_hvm():
-            raise VmError("only HVM guest support pci detach")
+            raise VmError("hvm_destroyPCIDevice called on non-HVM guest")
 
         #all the PCI devs share one conf node
         devid = '0'
@@ -744,34 +858,15 @@ class XendDomainInfo:
             raise VmError("Device @ vslot 0x%x do not support hotplug." % 
(vslot))
 
         bdf_str = "%s:%s:%s.%s" % (x['domain'], x['bus'], x['slot'], x['func'])
-        log.info("destroyPCIDevice:%s:%s!", x, bdf_str)
+        log.info("hvm_destroyPCIDevice:%s:%s!", x, bdf_str)
 
         self.image.signalDeviceModel('pci-rem', 'pci-removed', bdf_str)
-
-        if pci_len > 1:
-            del pci_conf['devs'][devnum]
-            self._reconfigureDevice('pci', devid, pci_conf)
-        else:
-            self.getDeviceController('pci').destroyDevice(devid, True)
-            del self.info['devices'][dev_uuid]
-            platform = self.info['platform']
-            orig_dev_num = len(platform['pci'])
-
-            #need remove the pci config
-            #TODO:can use this to keep some info to ask high level management 
tools to hot insert a new passthrough dev after migration
-            if orig_dev_num != 0:
-#                platform['pci'] = ["%dDEVs" % orig_dev_num]
-                platform['pci'] = []
 
         return 0
 
     def destroyDevice(self, deviceClass, devid, force = False, rm_cfg = False):
         log.debug("XendDomainInfo.destroyDevice: deviceClass = %s, device = 
%s",
                   deviceClass, devid)
-
-        if deviceClass == 'dpci':
-            rc = self.destroyPCIDevice(devid)
-            return rc
 
         if rm_cfg:
             # Convert devid to device number.  A device number is
diff -r e678b42c36c4 -r 3f407392da49 
tools/python/xen/xend/server/DevController.py
--- a/tools/python/xen/xend/server/DevController.py     Tue Mar 18 11:34:44 
2008 +0000
+++ b/tools/python/xen/xend/server/DevController.py     Tue Mar 18 11:39:21 
2008 +0000
@@ -51,6 +51,8 @@ xenbusState = {
     'Connected'    : 4,
     'Closing'      : 5,
     'Closed'       : 6,
+    'Reconfiguring': 7,
+    'Reconfigured' : 8,
     }
 
 xoptions = XendOptions.instance()
@@ -88,6 +90,8 @@ class DevController:
         (devid, back, front) = self.getDeviceDetails(config)
         if devid is None:
             return 0
+
+        self.setupDevice(config)
 
         (backpath, frontpath) = self.addStoreEntries(config, devid, back,
                                                      front)
@@ -198,6 +202,15 @@ class DevController:
 
         if status == Timeout:
             raise VmError("Device %s (%s) could not be disconnected. " %
+                          (devid, self.deviceClass))
+
+    def waitForDevice_reconfigure(self, devid):
+        log.debug("Waiting for %s - reconfigureDevice.", devid)
+
+        (status, err) = self.waitForBackend_reconfigure(devid)
+
+        if status == Timeout:
+            raise VmError("Device %s (%s) could not be reconfigured. " %
                           (devid, self.deviceClass))
 
 
@@ -325,6 +338,11 @@ class DevController:
         """
 
         raise NotImplementedError()
+
+    def setupDevice(self, config):
+        """ Setup device from config.
+        """
+        return
 
     def migrate(self, deviceConfig, network, dst, step, domName):
         """ Migration of a device. The 'network' parameter indicates
@@ -569,6 +587,22 @@ class DevController:
 
         return result['status']
 
+    def waitForBackend_reconfigure(self, devid):
+        frontpath = self.frontendPath(devid)
+        backpath = xstransact.Read(frontpath, "backend")
+        if backpath:
+            statusPath = backpath + '/' + "state"
+            ev = Event()
+            result = { 'status': Timeout }
+
+            xswatch(statusPath, xenbusStatusCallback, ev, result)
+
+            ev.wait(DEVICE_CREATE_TIMEOUT)
+
+            return (result['status'], None)
+        else:
+            return (Missing, None)
+
 
     def backendPath(self, backdom, devid):
         """Construct backend path given the backend domain and device id.
@@ -634,3 +668,19 @@ def deviceDestroyCallback(statusPath, ev
 
     ev.set()
     return 0
+
+
+def xenbusStatusCallback(statusPath, ev, result):
+    log.debug("xenbusStatusCallback %s.", statusPath)
+
+    status = xstransact.Read(statusPath)
+
+    if status == str(xenbusState['Connected']):
+        result['status'] = Connected
+    else:
+        return 1
+
+    log.debug("xenbusStatusCallback %d.", result['status'])
+
+    ev.set()
+    return 0
diff -r e678b42c36c4 -r 3f407392da49 tools/python/xen/xend/server/pciif.py
--- a/tools/python/xen/xend/server/pciif.py     Tue Mar 18 11:34:44 2008 +0000
+++ b/tools/python/xen/xend/server/pciif.py     Tue Mar 18 11:39:21 2008 +0000
@@ -24,7 +24,7 @@ from xen.xend.XendError import VmError
 from xen.xend.XendError import VmError
 from xen.xend.XendLogging import log
 
-from xen.xend.server.DevController import DevController
+from xen.xend.server.DevController import DevController, xenbusState
 
 import xen.lowlevel.xc
 
@@ -44,6 +44,15 @@ while not (t&1):
     t>>=1
     PAGE_SHIFT+=1
 
+def parse_hex(val):
+    try:
+        if isinstance(val, types.StringTypes):
+            return int(val, 16)
+        else:
+            return val
+    except ValueError:
+        return None
+
 class PciController(DevController):
 
     def __init__(self, vm):
@@ -52,15 +61,6 @@ class PciController(DevController):
 
     def getDeviceDetails(self, config):
         """@see DevController.getDeviceDetails"""
-        def parse_hex(val):
-            try:
-                if isinstance(val, types.StringTypes):
-                    return int(val, 16)
-                else:
-                    return val
-            except ValueError:
-                return None
-            
         back = {}
         pcidevid = 0
         vslots = ""
@@ -74,7 +74,6 @@ class PciController(DevController):
             if vslt is not None:
                 vslots = vslots + vslt + ";"
 
-            self.setupDevice(domain, bus, slot, func)
             back['dev-%i' % pcidevid] = "%04x:%02x:%02x.%02x" % \
                                         (domain, bus, slot, func)
             pcidevid += 1
@@ -86,27 +85,80 @@ class PciController(DevController):
         back['uuid'] = config.get('uuid','')
         return (0, back, {})
 
+
     def reconfigureDevice(self, _, config):
         """@see DevController.reconfigureDevice"""
-        #currently only support config changes by hot insert/remove 
pass-through dev
-        #delete all the devices in xenstore
-        (devid, new_back, new_front) = self.getDeviceDetails(config)
-        num_devs = self.readBackend(devid, 'num_devs')
-        for i in range(int(num_devs)):
-            self.removeBackend(devid, 'dev-%d' % i)
-        self.removeBackend(devid, 'num_devs')
-
-        #create new devices config
-        num_devs = new_back['num_devs']
-        for i in range(int(num_devs)):
-            dev_no = 'dev-%d' % i
-            self.writeBackend(devid, dev_no, new_back[dev_no])
-        self.writeBackend(devid, 'num_devs', num_devs)
-
-        if new_back['vslots'] is not None:
-            self.writeBackend(devid, 'vslots', new_back['vslots'])
-
-        return new_back.get('uuid')
+        (devid, back, front) = self.getDeviceDetails(config)
+        num_devs = int(back['num_devs'])
+        states = config.get('states', [])
+
+        old_vslots = self.readBackend(devid, 'vslots')
+        if old_vslots is None:
+            old_vslots = ''
+        num_olddevs = int(self.readBackend(devid, 'num_devs'))
+
+        for i in range(num_devs):
+            try:
+                dev = back['dev-%i' % i]
+                state = states[i]
+            except:
+                raise XendError('Error reading config')
+
+            if state == 'Initialising':
+                # PCI device attachment
+                for j in range(num_olddevs):
+                    if dev == self.readBackend(devid, 'dev-%i' % j):
+                        raise XendError('Device %s is already connected.' % 
dev)
+                log.debug('Attaching PCI device %s.' % dev)
+                (domain, bus, slotfunc) = dev.split(':')
+                (slot, func) = slotfunc.split('.')
+                domain = parse_hex(domain)
+                bus = parse_hex(bus)
+                slot = parse_hex(slot)
+                func = parse_hex(func)
+                self.setupOneDevice(domain, bus, slot, func)
+
+                self.writeBackend(devid, 'dev-%i' % (num_olddevs + i), dev)
+                self.writeBackend(devid, 'state-%i' % (num_olddevs + i),
+                                  str(xenbusState['Initialising']))
+                self.writeBackend(devid, 'num_devs', str(num_olddevs + i + 1))
+
+                # Update vslots
+                if back['vslots'] is not None:
+                    vslots = old_vslots + back['vslots']
+                    self.writeBackend(devid, 'vslots', vslots)
+
+            elif state == 'Closing':
+                # PCI device detachment
+                found = False
+                for j in range(num_olddevs):
+                    if dev == self.readBackend(devid, 'dev-%i' % j):
+                        found = True
+                        log.debug('Detaching device %s' % dev)
+                        self.writeBackend(devid, 'state-%i' % j,
+                                          str(xenbusState['Closing']))
+                if not found:
+                    raise XendError('Device %s is not connected' % dev)
+
+                # Update vslots
+                if back['vslots'] is not None:
+                    vslots = old_vslots
+                    for vslt in back['vslots'].split(';'):
+                        if vslt != '':
+                            vslots = vslots.replace(vslt + ';', '', 1)
+                    if vslots == '':
+                        self.removeBackend(devid, 'vslots')
+                    else:
+                        self.writeBackend(devid, 'vslots', vslots)
+
+            else:
+                raise XendError('Error configuring device %s: invalid state %s'
+                                % (dev,state))
+
+        self.writeBackend(devid, 'state', str(xenbusState['Reconfiguring']))
+
+        return self.readBackend(devid, 'uuid')
+
 
     def getDeviceConfiguration(self, devid, transaction = None):
         result = DevController.getDeviceConfiguration(self, devid, transaction)
@@ -136,7 +188,10 @@ class PciController(DevController):
 
                 #append vslot info
                 if vslots is not None:
-                    dev_dict['vslt'] = slot_list[i]
+                    try:
+                        dev_dict['vslt'] = slot_list[i]
+                    except IndexError:
+                        dev_dict['vslt'] = '0x0'
 
                 pci_devs.append(dev_dict)
 
@@ -171,7 +226,7 @@ class PciController(DevController):
 
         return sxpr    
 
-    def setupDevice(self, domain, bus, slot, func):
+    def setupOneDevice(self, domain, bus, slot, func):
         """ Attach I/O resources for device to frontend domain
         """
         fe_domid = self.getDomid()
@@ -225,6 +280,116 @@ class PciController(DevController):
                 raise VmError(('pci: failed to configure irq on device '+
                             '%s - errno=%d')%(dev.name,rc))
 
+    def setupDevice(self, config):
+        """Setup devices from config
+        """
+        for pci_config in config.get('devs', []):
+            domain = parse_hex(pci_config.get('domain', 0))
+            bus = parse_hex(pci_config.get('bus', 0))
+            slot = parse_hex(pci_config.get('slot', 0))
+            func = parse_hex(pci_config.get('func', 0))            
+            self.setupOneDevice(domain, bus, slot, func)
+
+        return
+
+    def cleanupOneDevice(self, domain, bus, slot, func):
+        """ Detach I/O resources for device from frontend domain
+        """
+        fe_domid = self.getDomid()
+
+        try:
+            dev = PciDevice(domain, bus, slot, func)
+        except Exception, e:
+            raise VmError("pci: failed to locate device and "+
+                    "parse it's resources - "+str(e))
+
+        if dev.driver!='pciback':
+            raise VmError(("pci: PCI Backend does not own device "+ \
+                    "%s\n"+ \
+                    "See the pciback.hide kernel "+ \
+                    "command-line parameter or\n"+ \
+                    "bind your slot/device to the PCI backend using sysfs" \
+                    )%(dev.name))
+
+        for (start, size) in dev.ioports:
+            log.debug('pci: disabling ioport 0x%x/0x%x'%(start,size))
+            rc = xc.domain_ioport_permission(domid = fe_domid, first_port = 
start,
+                    nr_ports = size, allow_access = False)
+            if rc<0:
+                raise VmError(('pci: failed to configure I/O ports on device '+
+                            '%s - errno=%d')%(dev.name,rc))
+
+        for (start, size) in dev.iomem:
+            # Convert start/size from bytes to page frame sizes
+            start_pfn = start>>PAGE_SHIFT
+            # Round number of pages up to nearest page boundary (if not on one)
+            nr_pfns = (size+(PAGE_SIZE-1))>>PAGE_SHIFT
+
+            log.debug('pci: disabling iomem 0x%x/0x%x pfn 0x%x/0x%x'% \
+                    (start,size,start_pfn,nr_pfns))
+            rc = xc.domain_iomem_permission(domid =  fe_domid,
+                    first_pfn = start_pfn,
+                    nr_pfns = nr_pfns,
+                    allow_access = False)
+            if rc<0:
+                raise VmError(('pci: failed to configure I/O memory on device 
'+
+                            '%s - errno=%d')%(dev.name,rc))
+
+        if dev.irq>0:
+            log.debug('pci: disabling irq %d'%dev.irq)
+            rc = xc.domain_irq_permission(domid =  fe_domid, pirq = dev.irq,
+                    allow_access = False)
+            if rc<0:
+                raise VmError(('pci: failed to configure irq on device '+
+                            '%s - errno=%d')%(dev.name,rc))
+
+    def cleanupDevice(self, devid):
+        """ Detach I/O resources for device and cleanup xenstore nodes
+        after reconfigure.
+
+        @param devid: The device ID
+        @type devid:  int
+        @return:      Return the number of devices connected
+        @rtype:       int
+        """
+        num_devs = int(self.readBackend(devid, 'num_devs'))
+        new_num_devs = 0
+        for i in range(num_devs):
+            state = int(self.readBackend(devid, 'state-%i' % i))
+            if state == xenbusState['Closing']:
+                # Detach I/O resources.
+                dev = self.readBackend(devid, 'dev-%i' % i)
+                (domain, bus, slotfunc) = dev.split(':')
+                (slot, func) = slotfunc.split('.')
+                domain = parse_hex(domain)
+                bus = parse_hex(bus)
+                slot = parse_hex(slot)
+                func = parse_hex(func)            
+                # In HVM case, I/O resources are disabled in ioemu.
+                self.cleanupOneDevice(domain, bus, slot, func)
+                # Remove xenstore nodes.
+                self.removeBackend(devid, 'dev-%i' % i)
+                self.removeBackend(devid, 'vdev-%i' % i)
+                self.removeBackend(devid, 'state-%i' % i)
+            else:
+                if new_num_devs != i:
+                    tmpdev = self.readBackend(devid, 'dev-%i' % i)
+                    self.writeBackend(devid, 'dev-%i' % new_num_devs, tmpdev)
+                    self.removeBackend(devid, 'dev-%i' % i)
+                    tmpvdev = self.readBackend(devid, 'vdev-%i' % i)
+                    if tmpvdev is not None:
+                        self.writeBackend(devid, 'vdev-%i' % new_num_devs,
+                                          tmpvdev)
+                    self.removeBackend(devid, 'vdev-%i' % i)
+                    tmpstate = self.readBackend(devid, 'state-%i' % i)
+                    self.writeBackend(devid, 'state-%i' % new_num_devs, 
tmpstate)
+                    self.removeBackend(devid, 'state-%i' % i)
+                new_num_devs = new_num_devs + 1
+
+        self.writeBackend(devid, 'num_devs', str(new_num_devs))
+
+        return new_num_devs
+
     def waitForBackend(self,devid):
         return (0, "ok - no hotplug")
 
diff -r e678b42c36c4 -r 3f407392da49 tools/python/xen/xm/main.py
--- a/tools/python/xen/xm/main.py       Tue Mar 18 11:34:44 2008 +0000
+++ b/tools/python/xen/xm/main.py       Tue Mar 18 11:39:21 2008 +0000
@@ -175,11 +175,11 @@ SUBCOMMAND_HELP = {
     'vnet-delete'   :  ('<VnetId>', 'Delete a Vnet.'),
     'vnet-list'     :  ('[-l|--long]', 'List Vnets.'),
     'vtpm-list'     :  ('<Domain> [--long]', 'List virtual TPM devices.'),
-    'pci-attach '   :  ('<Domain> <dom> <bus> <slot> <func> [virtual slot]',
+    'pci-attach'    :  ('<Domain> <domain:bus:slot.func> [virtual slot]',
                         'Insert a new pass-through pci device.'),
-    'pci-detach '   :  ('<Domain> <virtual slot>',
+    'pci-detach'    :  ('<Domain> <domain:bus:slot.func>',
                         'Remove a domain\'s pass-through pci device.'),
-    'pci-list'     :  ('<Domain>',
+    'pci-list'      :  ('<Domain>',
                         'List pass-through pci devices for a domain.'),
 
     # security
@@ -2232,29 +2232,37 @@ def xm_network_attach(args):
             vif.append(vif_param)
         server.xend.domain.device_create(dom, vif)
 
-def parse_pci_configuration(args):
+def parse_pci_configuration(args, state):
     dom = args[0]
-
-    if len(args) == 6:
-        vslt = args[5]
+    pci_dev_str = args[1]
+    if len(args) == 3:
+        vslt = args[2]
     else:
         vslt = '0x0' #chose a free virtual PCI slot
-
-    pci = ['pci',
-          ['devs',
-            [{'domain': "0x%x" % int(args[1], 16),
-              'bus':    "0x%x" % int(args[2], 16),
-              'slot':   "0x%x" % int(args[3], 16),
-              'func':   "0x%x" % int(args[4], 16),
-              'vslt':   "0x%x" % int(vslt,    16)}]
-          ]]
+    pci=['pci']
+    pci_match = re.match(r"((?P<domain>[0-9a-fA-F]{1,4})[:,])?" + \
+            r"(?P<bus>[0-9a-fA-F]{1,2})[:,]" + \
+            r"(?P<slot>[0-9a-fA-F]{1,2})[.,]" + \
+            r"(?P<func>[0-7])$", pci_dev_str)
+    if pci_match == None:
+        raise OptionError("Invalid argument: %s %s" % (pci_dev_str,vslt))
+    pci_dev_info = pci_match.groupdict('0')
+    try:
+        pci.append(['dev', ['domain', '0x'+ pci_dev_info['domain']], \
+                ['bus', '0x'+ pci_dev_info['bus']],
+                ['slot', '0x'+ pci_dev_info['slot']],
+                ['func', '0x'+ pci_dev_info['func']],
+                ['vslt', '0x%x' % int(vslt, 16)]])
+    except:
+        raise OptionError("Invalid argument: %s %s" % (pci_dev_str,vslt))
+    pci.append(['state', state])
 
     return (dom, pci)
 
 def xm_pci_attach(args):
-    arg_check(args, 'pci-attach', 5, 6)
-    (dom, pci) = parse_pci_configuration(args)
-    server.xend.domain.device_create(dom, pci)
+    arg_check(args, 'pci-attach', 2, 3)
+    (dom, pci) = parse_pci_configuration(args, 'Initialising')
+    server.xend.domain.device_configure(dom, pci)
 
 def detach(args, deviceClass):
     rm_cfg = True
@@ -2319,12 +2327,11 @@ def xm_network_detach(args):
         arg_check(args, 'network-detach', 2, 3)
         detach(args, 'vif')
 
-
 def xm_pci_detach(args):
     arg_check(args, 'pci-detach', 2)
-    dom = args[0]
-    dev = args[1]
-    server.xend.domain.destroyDevice(dom, 'dpci', dev)
+    (dom, pci) = parse_pci_configuration(args, 'Closing')
+    server.xend.domain.device_configure(dom, pci)
+
 
 def xm_vnet_list(args):
     xenapi_unsupported()

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog

<Prev in Thread] Current Thread [Next in Thread>
  • [Xen-changelog] [xen-unstable] tools: Add PV passthrough PCI device hotplug support., Xen patchbot-unstable <=