[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-changelog] [xen-unstable] tools: Add PV passthrough PCI device hotplug support.



# 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


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.