ia64/xen-unstable

changeset 9418:05daa762a8e2

Support late binding of PCI devices to the PCI backend driver in
dom0. This allows you to bind devices to the backend driver *after*
dom0 has booted. You are no longer required to specify the devices to
hide on the kernel command-line. Using the bind/unbind driver
attributes (see /sys/bus/pci/drivers/pciback), you can specify which
devices that the PCI backend will seize. There are three new driver
attributes in that directory:

slots - lists all of the PCI slots that
the PCI backend will try to seize
new_slot - write the name of a slot here
(in 0000:00:00.0 format) to have the PCI
Backend seize the device in this slot
remove_slot - write the name of a slot here to have
the PCI Backend no longer try to seize a
device in this slot

Note that writing to new_slot/remove_slot does not actually change
whether the PCI Backend is actually bound to the device in that slot or
not. Instead, it tells the PCI backend which slots it should be
interested in. The sysfs attributes "bind" and "unbind" (which are
common to all drivers, not just the PCI Backend) must be used to
actually add or remove a device from the PCI backend driver. Note that
the syntax for specifying a device to bind and unbind is very strict (do
not append a newline).

For Example:

# Add a new slot to the PCI Backend's list
echo -n 0000:01:04.d > /sys/bus/pci/drivers/pciback/new_slot
# Now that the backend is watching for the slot, bind to it
echo -n 0000:01:04.d > /sys/bus/pci/drivers/pciback/bind

# Unbind a PCI network card from its network driver
echo -n 0000:05:02.0 > /sys/bus/pci/drivers/3c905/unbind
# And now bind it to the PCI Backend
echo -n 0000:05:02.0 > /sys/bus/pci/drivers/pciback/new_slot
echo -n 0000:05:02.0 > /sys/bus/pci/drivers/pciback/bind


Unfortunately, Linux makes it possible to remove (unbind) a PCI device
from the PCI backend while that device is attached to a driver domain.
It is also possible to unload the PCI Backend module while a PCI
Frontend is attached. DON'T DO EITHER OF THESE ACTIONS. This patch will
output warnings if you do try and do these. Be aware that while access
to the configuration space of the device has been revoked, the driver
domain can still access the I/O resources of the device as they have not
been revoked (although I *hope* to explore adding support for this
soon). Before unloading the module or unbinding a device, shutdown your
driver domain.

These patches also convert a few function and variable declarations to
static (no sense in polluting the global namespace with local function
names) and rename a few structures in drivers/xen/pciback/pci_stub.c.

Signed-off-by: Ryan Wilson <hap9@epoch.ncsc.mil>
author kaf24@firebug.cl.cam.ac.uk
date Thu Mar 23 10:57:48 2006 +0100 (2006-03-23)
parents 799957f5092c
children 2c77d26871f7
files linux-2.6-xen-sparse/drivers/xen/pciback/passthrough.c linux-2.6-xen-sparse/drivers/xen/pciback/pci_stub.c linux-2.6-xen-sparse/drivers/xen/pciback/pciback.h linux-2.6-xen-sparse/drivers/xen/pciback/pciback_ops.c linux-2.6-xen-sparse/drivers/xen/pciback/vpci.c linux-2.6-xen-sparse/drivers/xen/pciback/xenbus.c tools/python/xen/xend/server/pciif.py
line diff
     1.1 --- a/linux-2.6-xen-sparse/drivers/xen/pciback/passthrough.c	Thu Mar 23 10:53:55 2006 +0100
     1.2 +++ b/linux-2.6-xen-sparse/drivers/xen/pciback/passthrough.c	Thu Mar 23 10:57:48 2006 +0100
     1.3 @@ -7,10 +7,13 @@
     1.4  
     1.5  #include <linux/list.h>
     1.6  #include <linux/pci.h>
     1.7 +#include <linux/spinlock.h>
     1.8  #include "pciback.h"
     1.9  
    1.10  struct passthrough_dev_data {
    1.11 +	/* Access to dev_list must be protected by lock */
    1.12  	struct list_head dev_list;
    1.13 +	spinlock_t lock;
    1.14  };
    1.15  
    1.16  struct pci_dev *pciback_get_pci_dev(struct pciback_device *pdev,
    1.17 @@ -19,33 +22,66 @@ struct pci_dev *pciback_get_pci_dev(stru
    1.18  {
    1.19  	struct passthrough_dev_data *dev_data = pdev->pci_dev_data;
    1.20  	struct pci_dev_entry *dev_entry;
    1.21 +	struct pci_dev *dev = NULL;
    1.22 +	unsigned long flags;
    1.23 +
    1.24 +	spin_lock_irqsave(&dev_data->lock, flags);
    1.25  
    1.26  	list_for_each_entry(dev_entry, &dev_data->dev_list, list) {
    1.27  		if (domain == (unsigned int)pci_domain_nr(dev_entry->dev->bus)
    1.28  		    && bus == (unsigned int)dev_entry->dev->bus->number
    1.29 -		    && devfn == dev_entry->dev->devfn)
    1.30 -			return dev_entry->dev;
    1.31 +		    && devfn == dev_entry->dev->devfn) {
    1.32 +			dev = dev_entry->dev;
    1.33 +			break;
    1.34 +		}
    1.35  	}
    1.36  
    1.37 -	return NULL;
    1.38 +	spin_unlock_irqrestore(&dev_data->lock, flags);
    1.39 +
    1.40 +	return dev;
    1.41  }
    1.42  
    1.43 -/* Must hold pciback_device->dev_lock when calling this */
    1.44  int pciback_add_pci_dev(struct pciback_device *pdev, struct pci_dev *dev)
    1.45  {
    1.46  	struct passthrough_dev_data *dev_data = pdev->pci_dev_data;
    1.47  	struct pci_dev_entry *dev_entry;
    1.48 +	unsigned long flags;
    1.49  
    1.50  	dev_entry = kmalloc(sizeof(*dev_entry), GFP_KERNEL);
    1.51  	if (!dev_entry)
    1.52  		return -ENOMEM;
    1.53  	dev_entry->dev = dev;
    1.54  
    1.55 +	spin_lock_irqsave(&dev_data->lock, flags);
    1.56  	list_add_tail(&dev_entry->list, &dev_data->dev_list);
    1.57 +	spin_unlock_irqrestore(&dev_data->lock, flags);
    1.58  
    1.59  	return 0;
    1.60  }
    1.61  
    1.62 +void pciback_release_pci_dev(struct pciback_device *pdev, struct pci_dev *dev)
    1.63 +{
    1.64 +	struct passthrough_dev_data *dev_data = pdev->pci_dev_data;
    1.65 +	struct pci_dev_entry *dev_entry, *t;
    1.66 +	struct pci_dev *found_dev = NULL;
    1.67 +	unsigned long flags;
    1.68 +
    1.69 +	spin_lock_irqsave(&dev_data->lock, flags);
    1.70 +
    1.71 +	list_for_each_entry_safe(dev_entry, t, &dev_data->dev_list, list) {
    1.72 +		if (dev_entry->dev == dev) {
    1.73 +			list_del(&dev_entry->list);
    1.74 +			found_dev = dev_entry->dev;
    1.75 +			kfree(dev_entry);
    1.76 +		}
    1.77 +	}
    1.78 +
    1.79 +	spin_unlock_irqrestore(&dev_data->lock, flags);
    1.80 +
    1.81 +	if (found_dev)
    1.82 +		pcistub_put_pci_dev(found_dev);
    1.83 +}
    1.84 +
    1.85  int pciback_init_devices(struct pciback_device *pdev)
    1.86  {
    1.87  	struct passthrough_dev_data *dev_data;
    1.88 @@ -54,6 +90,8 @@ int pciback_init_devices(struct pciback_
    1.89  	if (!dev_data)
    1.90  		return -ENOMEM;
    1.91  
    1.92 +	spin_lock_init(&dev_data->lock);
    1.93 +
    1.94  	INIT_LIST_HEAD(&dev_data->dev_list);
    1.95  
    1.96  	pdev->pci_dev_data = dev_data;
    1.97 @@ -71,6 +109,8 @@ int pciback_publish_pci_roots(struct pci
    1.98  	int found;
    1.99  	unsigned int domain, bus;
   1.100  
   1.101 +	spin_lock(&dev_data->lock);
   1.102 +
   1.103  	list_for_each_entry(dev_entry, &dev_data->dev_list, list) {
   1.104  		/* Only publish this device as a root if none of its
   1.105  		 * parent bridges are exported
   1.106 @@ -96,10 +136,11 @@ int pciback_publish_pci_roots(struct pci
   1.107  		}
   1.108  	}
   1.109  
   1.110 +	spin_unlock(&dev_data->lock);
   1.111 +
   1.112  	return err;
   1.113  }
   1.114  
   1.115 -/* Must hold pciback_device->dev_lock when calling this */
   1.116  void pciback_release_devices(struct pciback_device *pdev)
   1.117  {
   1.118  	struct passthrough_dev_data *dev_data = pdev->pci_dev_data;
     2.1 --- a/linux-2.6-xen-sparse/drivers/xen/pciback/pci_stub.c	Thu Mar 23 10:53:55 2006 +0100
     2.2 +++ b/linux-2.6-xen-sparse/drivers/xen/pciback/pci_stub.c	Thu Mar 23 10:57:48 2006 +0100
     2.3 @@ -7,110 +7,190 @@
     2.4  #include <linux/init.h>
     2.5  #include <linux/list.h>
     2.6  #include <linux/spinlock.h>
     2.7 +#include <linux/kref.h>
     2.8  #include <asm/atomic.h>
     2.9  #include "pciback.h"
    2.10  
    2.11  static char *pci_devs_to_hide = NULL;
    2.12  module_param_named(hide, pci_devs_to_hide, charp, 0444);
    2.13  
    2.14 -struct pci_stub_device_id {
    2.15 +struct pcistub_device_id {
    2.16  	struct list_head slot_list;
    2.17  	int domain;
    2.18  	unsigned char bus;
    2.19  	unsigned int devfn;
    2.20  };
    2.21 -LIST_HEAD(pci_stub_device_ids);
    2.22 +static LIST_HEAD(pcistub_device_ids);
    2.23 +static DEFINE_SPINLOCK(device_ids_lock);
    2.24  
    2.25 -struct pci_stub_device {
    2.26 +struct pcistub_device {
    2.27 +	struct kref kref;
    2.28  	struct list_head dev_list;
    2.29 +	spinlock_t lock;
    2.30 +
    2.31  	struct pci_dev *dev;
    2.32 -	atomic_t in_use;
    2.33 +	struct pciback_device *pdev;	/* non-NULL if struct pci_dev is in use */
    2.34  };
    2.35 -/* Access to pci_stub_devices & seized_devices lists and the initialize_devices
    2.36 - * flag must be locked with pci_stub_devices_lock
    2.37 +/* Access to pcistub_devices & seized_devices lists and the initialize_devices
    2.38 + * flag must be locked with pcistub_devices_lock
    2.39   */
    2.40 -DEFINE_SPINLOCK(pci_stub_devices_lock);
    2.41 -LIST_HEAD(pci_stub_devices);
    2.42 +static DEFINE_SPINLOCK(pcistub_devices_lock);
    2.43 +static LIST_HEAD(pcistub_devices);
    2.44  
    2.45  /* wait for device_initcall before initializing our devices
    2.46   * (see pcistub_init_devices_late)
    2.47   */
    2.48  static int initialize_devices = 0;
    2.49 -LIST_HEAD(seized_devices);
    2.50 +static LIST_HEAD(seized_devices);
    2.51  
    2.52 -static inline struct pci_dev *get_pci_dev(struct pci_stub_device *psdev)
    2.53 +static struct pcistub_device *pcistub_device_alloc(struct pci_dev *dev)
    2.54  {
    2.55 -	if (atomic_dec_and_test(&psdev->in_use))
    2.56 -		return psdev->dev;
    2.57 -	else {
    2.58 -		atomic_inc(&psdev->in_use);
    2.59 +	struct pcistub_device *psdev;
    2.60 +
    2.61 +	dev_dbg(&dev->dev, "pcistub_device_alloc\n");
    2.62 +
    2.63 +	psdev = kzalloc(sizeof(*psdev), GFP_ATOMIC);
    2.64 +	if (!psdev)
    2.65 +		return NULL;
    2.66 +
    2.67 +	psdev->dev = pci_dev_get(dev);
    2.68 +	if (!psdev->dev) {
    2.69 +		kfree(psdev);
    2.70  		return NULL;
    2.71  	}
    2.72 +
    2.73 +	kref_init(&psdev->kref);
    2.74 +	spin_lock_init(&psdev->lock);
    2.75 +
    2.76 +	return psdev;
    2.77  }
    2.78  
    2.79 -struct pci_dev *pcistub_get_pci_dev_by_slot(int domain, int bus,
    2.80 +/* Don't call this directly as it's called by pcistub_device_put */
    2.81 +static void pcistub_device_release(struct kref *kref)
    2.82 +{
    2.83 +	struct pcistub_device *psdev;
    2.84 +
    2.85 +	psdev = container_of(kref, struct pcistub_device, kref);
    2.86 +
    2.87 +	dev_dbg(&psdev->dev->dev, "pcistub_device_release\n");
    2.88 +
    2.89 +	/* Clean-up the device */
    2.90 +	pciback_reset_device(psdev->dev);
    2.91 +	pciback_config_free(psdev->dev);
    2.92 +	kfree(pci_get_drvdata(psdev->dev));
    2.93 +	pci_set_drvdata(psdev->dev, NULL);
    2.94 +
    2.95 +	pci_dev_put(psdev->dev);
    2.96 +
    2.97 +	kfree(psdev);
    2.98 +}
    2.99 +
   2.100 +static inline void pcistub_device_get(struct pcistub_device *psdev)
   2.101 +{
   2.102 +	kref_get(&psdev->kref);
   2.103 +}
   2.104 +
   2.105 +static inline void pcistub_device_put(struct pcistub_device *psdev)
   2.106 +{
   2.107 +	kref_put(&psdev->kref, pcistub_device_release);
   2.108 +}
   2.109 +
   2.110 +static struct pci_dev *pcistub_device_get_pci_dev(struct pciback_device *pdev,
   2.111 +						  struct pcistub_device *psdev)
   2.112 +{
   2.113 +	struct pci_dev *pci_dev = NULL;
   2.114 +	unsigned long flags;
   2.115 +
   2.116 +	pcistub_device_get(psdev);
   2.117 +
   2.118 +	spin_lock_irqsave(&psdev->lock, flags);
   2.119 +	if (!psdev->pdev) {
   2.120 +		psdev->pdev = pdev;
   2.121 +		pci_dev = psdev->dev;
   2.122 +	}
   2.123 +	spin_unlock_irqrestore(&psdev->lock, flags);
   2.124 +
   2.125 +	if (!pci_dev)
   2.126 +		pcistub_device_put(psdev);
   2.127 +
   2.128 +	return pci_dev;
   2.129 +}
   2.130 +
   2.131 +struct pci_dev *pcistub_get_pci_dev_by_slot(struct pciback_device *pdev,
   2.132 +					    int domain, int bus,
   2.133  					    int slot, int func)
   2.134  {
   2.135 -	struct pci_stub_device *psdev;
   2.136 +	struct pcistub_device *psdev;
   2.137  	struct pci_dev *found_dev = NULL;
   2.138 +	unsigned long flags;
   2.139  
   2.140 -	spin_lock(&pci_stub_devices_lock);
   2.141 +	spin_lock_irqsave(&pcistub_devices_lock, flags);
   2.142  
   2.143 -	list_for_each_entry(psdev, &pci_stub_devices, dev_list) {
   2.144 +	list_for_each_entry(psdev, &pcistub_devices, dev_list) {
   2.145  		if (psdev->dev != NULL
   2.146  		    && domain == pci_domain_nr(psdev->dev->bus)
   2.147  		    && bus == psdev->dev->bus->number
   2.148  		    && PCI_DEVFN(slot, func) == psdev->dev->devfn) {
   2.149 -			found_dev = get_pci_dev(psdev);
   2.150 +			found_dev = pcistub_device_get_pci_dev(pdev, psdev);
   2.151  			break;
   2.152  		}
   2.153  	}
   2.154  
   2.155 -	spin_unlock(&pci_stub_devices_lock);
   2.156 +	spin_unlock_irqrestore(&pcistub_devices_lock, flags);
   2.157  	return found_dev;
   2.158  }
   2.159  
   2.160 -struct pci_dev *pcistub_get_pci_dev(struct pci_dev *dev)
   2.161 +struct pci_dev *pcistub_get_pci_dev(struct pciback_device *pdev,
   2.162 +				    struct pci_dev *dev)
   2.163  {
   2.164 -	struct pci_stub_device *psdev;
   2.165 +	struct pcistub_device *psdev;
   2.166  	struct pci_dev *found_dev = NULL;
   2.167 +	unsigned long flags;
   2.168  
   2.169 -	spin_lock(&pci_stub_devices_lock);
   2.170 +	spin_lock_irqsave(&pcistub_devices_lock, flags);
   2.171  
   2.172 -	list_for_each_entry(psdev, &pci_stub_devices, dev_list) {
   2.173 +	list_for_each_entry(psdev, &pcistub_devices, dev_list) {
   2.174  		if (psdev->dev == dev) {
   2.175 -			found_dev = get_pci_dev(psdev);
   2.176 +			found_dev = pcistub_device_get_pci_dev(pdev, psdev);
   2.177  			break;
   2.178  		}
   2.179  	}
   2.180  
   2.181 -	spin_unlock(&pci_stub_devices_lock);
   2.182 +	spin_unlock_irqrestore(&pcistub_devices_lock, flags);
   2.183  	return found_dev;
   2.184  }
   2.185  
   2.186  void pcistub_put_pci_dev(struct pci_dev *dev)
   2.187  {
   2.188 -	struct pci_stub_device *psdev;
   2.189 +	struct pcistub_device *psdev, *found_psdev = NULL;
   2.190 +	unsigned long flags;
   2.191  
   2.192 -	spin_lock(&pci_stub_devices_lock);
   2.193 +	spin_lock_irqsave(&pcistub_devices_lock, flags);
   2.194  
   2.195 -	list_for_each_entry(psdev, &pci_stub_devices, dev_list) {
   2.196 +	list_for_each_entry(psdev, &pcistub_devices, dev_list) {
   2.197  		if (psdev->dev == dev) {
   2.198 -			/* Cleanup our device
   2.199 -			 * (so it's ready for the next domain)
   2.200 -			 */
   2.201 -			pciback_reset_device(psdev->dev);
   2.202 -
   2.203 -			atomic_inc(&psdev->in_use);
   2.204 +			found_psdev = psdev;
   2.205  			break;
   2.206  		}
   2.207  	}
   2.208  
   2.209 -	spin_unlock(&pci_stub_devices_lock);
   2.210 +	spin_unlock_irqrestore(&pcistub_devices_lock, flags);
   2.211 +
   2.212 +	/* Cleanup our device
   2.213 +	 * (so it's ready for the next domain)
   2.214 +	 */
   2.215 +	pciback_reset_device(found_psdev->dev);
   2.216 +	pciback_config_reset(found_psdev->dev);
   2.217 +
   2.218 +	spin_lock_irqsave(&found_psdev->lock, flags);
   2.219 +	found_psdev->pdev = NULL;
   2.220 +	spin_unlock_irqrestore(&found_psdev->lock, flags);
   2.221 +
   2.222 +	pcistub_device_put(found_psdev);
   2.223  }
   2.224  
   2.225 -static int __devinit pcistub_match(struct pci_dev *dev,
   2.226 -				   struct pci_stub_device_id *pdev_id)
   2.227 +static int __devinit pcistub_match_one(struct pci_dev *dev,
   2.228 +				       struct pcistub_device_id *pdev_id)
   2.229  {
   2.230  	/* Match the specified device by domain, bus, slot, func and also if
   2.231  	 * any of the device's parent bridges match.
   2.232 @@ -125,23 +205,44 @@ static int __devinit pcistub_match(struc
   2.233  	return 0;
   2.234  }
   2.235  
   2.236 +static int __devinit pcistub_match(struct pci_dev *dev)
   2.237 +{
   2.238 +	struct pcistub_device_id *pdev_id;
   2.239 +	unsigned long flags;
   2.240 +	int found = 0;
   2.241 +
   2.242 +	spin_lock_irqsave(&device_ids_lock, flags);
   2.243 +	list_for_each_entry(pdev_id, &pcistub_device_ids, slot_list) {
   2.244 +		if (pcistub_match_one(dev, pdev_id)) {
   2.245 +			found = 1;
   2.246 +			break;
   2.247 +		}
   2.248 +	}
   2.249 +	spin_unlock_irqrestore(&device_ids_lock, flags);
   2.250 +
   2.251 +	return found;
   2.252 +}
   2.253 +
   2.254  static int __devinit pcistub_init_device(struct pci_dev *dev)
   2.255  {
   2.256  	struct pciback_dev_data *dev_data;
   2.257  	int err = 0;
   2.258  
   2.259 +	dev_dbg(&dev->dev, "initializing...\n");
   2.260 +
   2.261  	/* The PCI backend is not intended to be a module (or to work with
   2.262  	 * removable PCI devices (yet). If it were, pciback_config_free()
   2.263  	 * would need to be called somewhere to free the memory allocated
   2.264  	 * here and then to call kfree(pci_get_drvdata(psdev->dev)).
   2.265  	 */
   2.266 -	dev_data = kmalloc(sizeof(*dev_data), GFP_KERNEL);
   2.267 +	dev_data = kmalloc(sizeof(*dev_data), GFP_ATOMIC);
   2.268  	if (!dev_data) {
   2.269  		err = -ENOMEM;
   2.270  		goto out;
   2.271  	}
   2.272  	pci_set_drvdata(dev, dev_data);
   2.273  
   2.274 +	dev_dbg(&dev->dev, "initializing config\n");
   2.275  	err = pciback_config_init(dev);
   2.276  	if (err)
   2.277  		goto out;
   2.278 @@ -153,14 +254,15 @@ static int __devinit pcistub_init_device
   2.279  	 * This makes the assumption that the device's resources won't
   2.280  	 * change after this point (otherwise this code may break!)
   2.281  	 */
   2.282 +	dev_dbg(&dev->dev, "enabling device\n");
   2.283  	err = pci_enable_device(dev);
   2.284  	if (err)
   2.285  		goto config_release;
   2.286  
   2.287  	/* Now disable the device (this also ensures some private device
   2.288  	 * data is setup before we export)
   2.289 -	 * This calls pciback_config_reset(dev)
   2.290  	 */
   2.291 +	dev_dbg(&dev->dev, "reset device\n");
   2.292  	pciback_reset_device(dev);
   2.293  
   2.294  	return 0;
   2.295 @@ -182,60 +284,82 @@ static int __devinit pcistub_init_device
   2.296   */
   2.297  static int __init pcistub_init_devices_late(void)
   2.298  {
   2.299 -	struct pci_stub_device *psdev, *t;
   2.300 +	struct pcistub_device *psdev;
   2.301 +	unsigned long flags;
   2.302  	int err = 0;
   2.303  
   2.304 -	spin_lock(&pci_stub_devices_lock);
   2.305 +	pr_debug("pciback: pcistub_init_devices_late\n");
   2.306  
   2.307 -	list_for_each_entry_safe(psdev, t, &seized_devices, dev_list) {
   2.308 +	spin_lock_irqsave(&pcistub_devices_lock, flags);
   2.309 +
   2.310 +	while (!list_empty(&seized_devices)) {
   2.311 +		psdev = container_of(seized_devices.next,
   2.312 +				     struct pcistub_device, dev_list);
   2.313  		list_del(&psdev->dev_list);
   2.314 +
   2.315 +		spin_unlock_irqrestore(&pcistub_devices_lock, flags);
   2.316 +
   2.317  		err = pcistub_init_device(psdev->dev);
   2.318  		if (err) {
   2.319 -			printk(KERN_ERR
   2.320 -			       "pciback: %s error %d initializing device\n",
   2.321 -			       pci_name(psdev->dev), err);
   2.322 +			dev_err(&psdev->dev->dev,
   2.323 +				"error %d initializing device\n", err);
   2.324  			kfree(psdev);
   2.325 -			continue;
   2.326 +			psdev = NULL;
   2.327  		}
   2.328  
   2.329 -		list_add_tail(&psdev->dev_list, &pci_stub_devices);
   2.330 +		spin_lock_irqsave(&pcistub_devices_lock, flags);
   2.331 +
   2.332 +		if (psdev)
   2.333 +			list_add_tail(&psdev->dev_list, &pcistub_devices);
   2.334  	}
   2.335  
   2.336  	initialize_devices = 1;
   2.337  
   2.338 -	spin_unlock(&pci_stub_devices_lock);
   2.339 +	spin_unlock_irqrestore(&pcistub_devices_lock, flags);
   2.340  
   2.341  	return 0;
   2.342  }
   2.343  
   2.344  static int __devinit pcistub_seize(struct pci_dev *dev)
   2.345  {
   2.346 -	struct pci_stub_device *psdev;
   2.347 +	struct pcistub_device *psdev;
   2.348 +	unsigned long flags;
   2.349 +	int initialize_devices_copy;
   2.350  	int err = 0;
   2.351  
   2.352 -	psdev = kmalloc(sizeof(*psdev), GFP_KERNEL);
   2.353 +	psdev = pcistub_device_alloc(dev);
   2.354  	if (!psdev)
   2.355  		return -ENOMEM;
   2.356  
   2.357 -	psdev->dev = dev;
   2.358 -	atomic_set(&psdev->in_use, 1);
   2.359 +	/* initialize_devices has to be accessed under a spin lock. But since
   2.360 +	 * it can only change from 0 -> 1, if it's already 1, we don't have to
   2.361 +	 * worry about it changing. That's why we can take a *copy* of
   2.362 +	 * initialize_devices and wait till we're outside of the lock to
   2.363 +	 * check if it's 1 (don't ever check if it's 0 outside of the lock)
   2.364 +	 */
   2.365 +	spin_lock_irqsave(&pcistub_devices_lock, flags);
   2.366  
   2.367 -	spin_lock(&pci_stub_devices_lock);
   2.368 +	initialize_devices_copy = initialize_devices;
   2.369  
   2.370 -	if (initialize_devices) {
   2.371 +	if (!initialize_devices_copy) {
   2.372 +		dev_dbg(&dev->dev, "deferring initialization\n");
   2.373 +		list_add(&psdev->dev_list, &seized_devices);
   2.374 +	}
   2.375 +
   2.376 +	spin_unlock_irqrestore(&pcistub_devices_lock, flags);
   2.377 +
   2.378 +	if (initialize_devices_copy) {
   2.379 +		/* don't want irqs disabled when calling pcistub_init_device */
   2.380  		err = pcistub_init_device(psdev->dev);
   2.381  		if (err)
   2.382  			goto out;
   2.383  
   2.384 -		list_add(&psdev->dev_list, &pci_stub_devices);
   2.385 -	} else
   2.386 -		list_add(&psdev->dev_list, &seized_devices);
   2.387 +		list_add(&psdev->dev_list, &pcistub_devices);
   2.388 +	}
   2.389  
   2.390        out:
   2.391 -	spin_unlock(&pci_stub_devices_lock);
   2.392 -
   2.393  	if (err)
   2.394 -		kfree(psdev);
   2.395 +		pcistub_device_put(psdev);
   2.396  
   2.397  	return err;
   2.398  }
   2.399 @@ -243,47 +367,78 @@ static int __devinit pcistub_seize(struc
   2.400  static int __devinit pcistub_probe(struct pci_dev *dev,
   2.401  				   const struct pci_device_id *id)
   2.402  {
   2.403 -	struct pci_stub_device_id *pdev_id;
   2.404 -	struct pci_dev *seized_dev;
   2.405  	int err = 0;
   2.406  
   2.407 -	list_for_each_entry(pdev_id, &pci_stub_device_ids, slot_list) {
   2.408 +	dev_dbg(&dev->dev, "probing...\n");
   2.409  
   2.410 -		if (!pcistub_match(dev, pdev_id))
   2.411 -			continue;
   2.412 +	if (pcistub_match(dev)) {
   2.413  
   2.414  		if (dev->hdr_type != PCI_HEADER_TYPE_NORMAL
   2.415  		    && dev->hdr_type != PCI_HEADER_TYPE_BRIDGE) {
   2.416 -			printk(KERN_ERR
   2.417 -			       "pciback: %s: can't export pci devices that "
   2.418 -			       "don't have a normal (0) or bridge (1) "
   2.419 -			       "header type!\n", pci_name(dev));
   2.420 -			break;
   2.421 +			dev_err(&dev->dev, "can't export pci devices that "
   2.422 +				"don't have a normal (0) or bridge (1) "
   2.423 +				"header type!\n");
   2.424 +			err = -ENODEV;
   2.425 +			goto out;
   2.426  		}
   2.427  
   2.428 -		pr_info("pciback: seizing PCI device %s\n", pci_name(dev));
   2.429 -		seized_dev = pci_dev_get(dev);
   2.430 -
   2.431 -		if (seized_dev) {
   2.432 -			err = pcistub_seize(seized_dev);
   2.433 -			if (err) {
   2.434 -				pci_dev_put(dev);
   2.435 -				goto out;
   2.436 -			}
   2.437 -
   2.438 -			/* Success! */
   2.439 -			goto out;
   2.440 -		}
   2.441 -	}
   2.442 -
   2.443 -	/* Didn't find the device */
   2.444 -	err = -ENODEV;
   2.445 +		dev_info(&dev->dev, "seizing device\n");
   2.446 +		err = pcistub_seize(dev);
   2.447 +	} else
   2.448 +		/* Didn't find the device */
   2.449 +		err = -ENODEV;
   2.450  
   2.451        out:
   2.452  	return err;
   2.453  }
   2.454  
   2.455 -struct pci_device_id pcistub_ids[] = {
   2.456 +static void pcistub_remove(struct pci_dev *dev)
   2.457 +{
   2.458 +	struct pcistub_device *psdev, *found_psdev = NULL;
   2.459 +	unsigned long flags;
   2.460 +
   2.461 +	dev_dbg(&dev->dev, "removing\n");
   2.462 +
   2.463 +	spin_lock_irqsave(&pcistub_devices_lock, flags);
   2.464 +
   2.465 +	list_for_each_entry(psdev, &pcistub_devices, dev_list) {
   2.466 +		if (psdev->dev == dev) {
   2.467 +			found_psdev = psdev;
   2.468 +			break;
   2.469 +		}
   2.470 +	}
   2.471 +
   2.472 +	spin_unlock_irqrestore(&pcistub_devices_lock, flags);
   2.473 +
   2.474 +	if (found_psdev) {
   2.475 +		dev_dbg(&dev->dev, "found device to remove - in use? %p\n",
   2.476 +			found_psdev->pdev);
   2.477 +
   2.478 +		if (found_psdev->pdev) {
   2.479 +			printk(KERN_WARNING "pciback: ****** removing device "
   2.480 +			       "%s while still in-use! ******\n",
   2.481 +			       pci_name(found_psdev->dev));
   2.482 +			printk(KERN_WARNING "pciback: ****** driver domain may "
   2.483 +			       "still access this device's i/o resources!\n");
   2.484 +			printk(KERN_WARNING "pciback: ****** shutdown driver "
   2.485 +			       "domain before binding device\n");
   2.486 +			printk(KERN_WARNING "pciback: ****** to other drivers "
   2.487 +			       "or domains\n");
   2.488 +
   2.489 +			pciback_release_pci_dev(found_psdev->pdev,
   2.490 +						found_psdev->dev);
   2.491 +		}
   2.492 +
   2.493 +		spin_lock_irqsave(&pcistub_devices_lock, flags);
   2.494 +		list_del(&found_psdev->dev_list);
   2.495 +		spin_unlock_irqrestore(&pcistub_devices_lock, flags);
   2.496 +
   2.497 +		/* the final put for releasing from the list */
   2.498 +		pcistub_device_put(found_psdev);
   2.499 +	}
   2.500 +}
   2.501 +
   2.502 +static struct pci_device_id pcistub_ids[] = {
   2.503  	{
   2.504  	 .vendor = PCI_ANY_ID,
   2.505  	 .device = PCI_ANY_ID,
   2.506 @@ -298,16 +453,152 @@ struct pci_device_id pcistub_ids[] = {
   2.507   * for a normal device. I don't want it to be loaded automatically.
   2.508   */
   2.509  
   2.510 -struct pci_driver pciback_pci_driver = {
   2.511 +static struct pci_driver pciback_pci_driver = {
   2.512  	.name = "pciback",
   2.513  	.id_table = pcistub_ids,
   2.514  	.probe = pcistub_probe,
   2.515 +	.remove = pcistub_remove,
   2.516  };
   2.517  
   2.518 +static inline int str_to_slot(const char *buf, int *domain, int *bus,
   2.519 +			      int *slot, int *func)
   2.520 +{
   2.521 +	int err;
   2.522 +
   2.523 +	err = sscanf(buf, " %x:%x:%x.%x", domain, bus, slot, func);
   2.524 +	if (err == 4)
   2.525 +		return 0;
   2.526 +	else if (err < 0)
   2.527 +		return -EINVAL;
   2.528 +
   2.529 +	/* try again without domain */
   2.530 +	*domain = 0;
   2.531 +	err = sscanf(buf, " %x:%x.%x", bus, slot, func);
   2.532 +	if (err == 3)
   2.533 +		return 0;
   2.534 +
   2.535 +	return -EINVAL;
   2.536 +}
   2.537 +
   2.538 +static int pcistub_device_id_add(int domain, int bus, int slot, int func)
   2.539 +{
   2.540 +	struct pcistub_device_id *pci_dev_id;
   2.541 +	unsigned long flags;
   2.542 +
   2.543 +	pci_dev_id = kmalloc(sizeof(*pci_dev_id), GFP_KERNEL);
   2.544 +	if (!pci_dev_id)
   2.545 +		return -ENOMEM;
   2.546 +
   2.547 +	pci_dev_id->domain = domain;
   2.548 +	pci_dev_id->bus = bus;
   2.549 +	pci_dev_id->devfn = PCI_DEVFN(slot, func);
   2.550 +
   2.551 +	pr_debug("pciback: wants to seize %04x:%02x:%02x.%01x\n",
   2.552 +		 domain, bus, slot, func);
   2.553 +
   2.554 +	spin_lock_irqsave(&device_ids_lock, flags);
   2.555 +	list_add_tail(&pci_dev_id->slot_list, &pcistub_device_ids);
   2.556 +	spin_unlock_irqrestore(&device_ids_lock, flags);
   2.557 +
   2.558 +	return 0;
   2.559 +}
   2.560 +
   2.561 +static int pcistub_device_id_remove(int domain, int bus, int slot, int func)
   2.562 +{
   2.563 +	struct pcistub_device_id *pci_dev_id, *t;
   2.564 +	int devfn = PCI_DEVFN(slot, func);
   2.565 +	int err = -ENOENT;
   2.566 +	unsigned long flags;
   2.567 +
   2.568 +	spin_lock_irqsave(&device_ids_lock, flags);
   2.569 +	list_for_each_entry_safe(pci_dev_id, t, &pcistub_device_ids, slot_list) {
   2.570 +
   2.571 +		if (pci_dev_id->domain == domain
   2.572 +		    && pci_dev_id->bus == bus && pci_dev_id->devfn == devfn) {
   2.573 +			/* Don't break; here because it's possible the same
   2.574 +			 * slot could be in the list more than once
   2.575 +			 */
   2.576 +			list_del(&pci_dev_id->slot_list);
   2.577 +			kfree(pci_dev_id);
   2.578 +
   2.579 +			err = 0;
   2.580 +
   2.581 +			pr_debug("pciback: removed %04x:%02x:%02x.%01x from "
   2.582 +				 "seize list\n", domain, bus, slot, func);
   2.583 +		}
   2.584 +	}
   2.585 +	spin_unlock_irqrestore(&device_ids_lock, flags);
   2.586 +
   2.587 +	return err;
   2.588 +}
   2.589 +
   2.590 +static ssize_t pcistub_slot_add(struct device_driver *drv, const char *buf,
   2.591 +				size_t count)
   2.592 +{
   2.593 +	int domain, bus, slot, func;
   2.594 +	int err;
   2.595 +
   2.596 +	err = str_to_slot(buf, &domain, &bus, &slot, &func);
   2.597 +	if (err)
   2.598 +		goto out;
   2.599 +
   2.600 +	err = pcistub_device_id_add(domain, bus, slot, func);
   2.601 +
   2.602 +      out:
   2.603 +	if (!err)
   2.604 +		err = count;
   2.605 +	return err;
   2.606 +}
   2.607 +
   2.608 +DRIVER_ATTR(new_slot, S_IWUSR, NULL, pcistub_slot_add);
   2.609 +
   2.610 +static ssize_t pcistub_slot_remove(struct device_driver *drv, const char *buf,
   2.611 +				   size_t count)
   2.612 +{
   2.613 +	int domain, bus, slot, func;
   2.614 +	int err;
   2.615 +
   2.616 +	err = str_to_slot(buf, &domain, &bus, &slot, &func);
   2.617 +	if (err)
   2.618 +		goto out;
   2.619 +
   2.620 +	err = pcistub_device_id_remove(domain, bus, slot, func);
   2.621 +
   2.622 +      out:
   2.623 +	if (!err)
   2.624 +		err = count;
   2.625 +	return err;
   2.626 +}
   2.627 +
   2.628 +DRIVER_ATTR(remove_slot, S_IWUSR, NULL, pcistub_slot_remove);
   2.629 +
   2.630 +static ssize_t pcistub_slot_show(struct device_driver *drv, char *buf)
   2.631 +{
   2.632 +	struct pcistub_device_id *pci_dev_id;
   2.633 +	size_t count = 0;
   2.634 +	unsigned long flags;
   2.635 +
   2.636 +	spin_lock_irqsave(&device_ids_lock, flags);
   2.637 +	list_for_each_entry(pci_dev_id, &pcistub_device_ids, slot_list) {
   2.638 +		if (count >= PAGE_SIZE)
   2.639 +			break;
   2.640 +
   2.641 +		count += scnprintf(buf + count, PAGE_SIZE - count,
   2.642 +				   "%04x:%02x:%02x.%01x\n",
   2.643 +				   pci_dev_id->domain, pci_dev_id->bus,
   2.644 +				   PCI_SLOT(pci_dev_id->devfn),
   2.645 +				   PCI_FUNC(pci_dev_id->devfn));
   2.646 +	}
   2.647 +	spin_unlock_irqrestore(&device_ids_lock, flags);
   2.648 +
   2.649 +	return count;
   2.650 +}
   2.651 +
   2.652 +DRIVER_ATTR(slots, S_IRUSR, pcistub_slot_show, NULL);
   2.653 +
   2.654  static int __init pcistub_init(void)
   2.655  {
   2.656  	int pos = 0;
   2.657 -	struct pci_stub_device_id *pci_dev_id;
   2.658  	int err = 0;
   2.659  	int domain, bus, slot, func;
   2.660  	int parsed;
   2.661 @@ -328,33 +619,27 @@ static int __init pcistub_init(void)
   2.662  					goto parse_error;
   2.663  			}
   2.664  
   2.665 -			pci_dev_id = kmalloc(sizeof(*pci_dev_id), GFP_KERNEL);
   2.666 -			if (!pci_dev_id) {
   2.667 -				err = -ENOMEM;
   2.668 +			err = pcistub_device_id_add(domain, bus, slot, func);
   2.669 +			if (err)
   2.670  				goto out;
   2.671 -			}
   2.672 -
   2.673 -			pci_dev_id->domain = domain;
   2.674 -			pci_dev_id->bus = bus;
   2.675 -			pci_dev_id->devfn = PCI_DEVFN(slot, func);
   2.676 -
   2.677 -			pr_debug
   2.678 -			    ("pciback: wants to seize %04x:%02x:%02x.%01x\n",
   2.679 -			     domain, bus, slot, func);
   2.680 -
   2.681 -			list_add_tail(&pci_dev_id->slot_list,
   2.682 -				      &pci_stub_device_ids);
   2.683  
   2.684  			/* if parsed<=0, we've reached the end of the string */
   2.685  			pos += parsed;
   2.686  		} while (parsed > 0 && pci_devs_to_hide[pos]);
   2.687 +	}
   2.688  
   2.689 -		/* If we're the first PCI Device Driver to register, we're the
   2.690 -		 * first one to get offered PCI devices as they become
   2.691 -		 * available (and thus we can be the first to grab them)
   2.692 -		 */
   2.693 -		pci_register_driver(&pciback_pci_driver);
   2.694 -	}
   2.695 +	/* If we're the first PCI Device Driver to register, we're the
   2.696 +	 * first one to get offered PCI devices as they become
   2.697 +	 * available (and thus we can be the first to grab them)
   2.698 +	 */
   2.699 +	err = pci_register_driver(&pciback_pci_driver);
   2.700 +	if (err < 0)
   2.701 +		goto out;
   2.702 +
   2.703 +	driver_create_file(&pciback_pci_driver.driver, &driver_attr_new_slot);
   2.704 +	driver_create_file(&pciback_pci_driver.driver,
   2.705 +			   &driver_attr_remove_slot);
   2.706 +	driver_create_file(&pciback_pci_driver.driver, &driver_attr_slots);
   2.707  
   2.708        out:
   2.709  	return err;
   2.710 @@ -386,19 +671,22 @@ static int __init pciback_init(void)
   2.711  		return err;
   2.712  #endif
   2.713  
   2.714 -	if (list_empty(&pci_stub_device_ids))
   2.715 -		return -ENODEV;
   2.716  	pcistub_init_devices_late();
   2.717  	pciback_xenbus_register();
   2.718  
   2.719 -	__unsafe(THIS_MODULE);
   2.720 -
   2.721  	return 0;
   2.722  }
   2.723  
   2.724 -static void pciback_cleanup(void)
   2.725 +static void __exit pciback_cleanup(void)
   2.726  {
   2.727 -	BUG();
   2.728 +	pciback_xenbus_unregister();
   2.729 +
   2.730 +	driver_remove_file(&pciback_pci_driver.driver, &driver_attr_new_slot);
   2.731 +	driver_remove_file(&pciback_pci_driver.driver,
   2.732 +			   &driver_attr_remove_slot);
   2.733 +	driver_remove_file(&pciback_pci_driver.driver, &driver_attr_slots);
   2.734 +
   2.735 +	pci_unregister_driver(&pciback_pci_driver);
   2.736  }
   2.737  
   2.738  module_init(pciback_init);
     3.1 --- a/linux-2.6-xen-sparse/drivers/xen/pciback/pciback.h	Thu Mar 23 10:53:55 2006 +0100
     3.2 +++ b/linux-2.6-xen-sparse/drivers/xen/pciback/pciback.h	Thu Mar 23 10:57:48 2006 +0100
     3.3 @@ -37,9 +37,11 @@ struct pciback_dev_data {
     3.4  };
     3.5  
     3.6  /* Get/Put PCI Devices that are hidden from the PCI Backend Domain */
     3.7 -struct pci_dev *pcistub_get_pci_dev_by_slot(int domain, int bus,
     3.8 +struct pci_dev *pcistub_get_pci_dev_by_slot(struct pciback_device *pdev,
     3.9 +					    int domain, int bus,
    3.10  					    int slot, int func);
    3.11 -struct pci_dev *pcistub_get_pci_dev(struct pci_dev *dev);
    3.12 +struct pci_dev *pcistub_get_pci_dev(struct pciback_device *pdev,
    3.13 +				    struct pci_dev *dev);
    3.14  void pcistub_put_pci_dev(struct pci_dev *dev);
    3.15  
    3.16  /* Ensure a device is turned off or reset */
    3.17 @@ -57,6 +59,7 @@ int pciback_config_write(struct pci_dev 
    3.18  typedef int (*publish_pci_root_cb) (struct pciback_device * pdev,
    3.19  				    unsigned int domain, unsigned int bus);
    3.20  int pciback_add_pci_dev(struct pciback_device *pdev, struct pci_dev *dev);
    3.21 +void pciback_release_pci_dev(struct pciback_device *pdev, struct pci_dev *dev);
    3.22  struct pci_dev *pciback_get_pci_dev(struct pciback_device *pdev,
    3.23  				    unsigned int domain, unsigned int bus,
    3.24  				    unsigned int devfn);
    3.25 @@ -69,6 +72,7 @@ void pciback_release_devices(struct pcib
    3.26  irqreturn_t pciback_handle_event(int irq, void *dev_id, struct pt_regs *regs);
    3.27  
    3.28  int pciback_xenbus_register(void);
    3.29 +void pciback_xenbus_unregister(void);
    3.30  
    3.31  extern int verbose_request;
    3.32  #endif
     4.1 --- a/linux-2.6-xen-sparse/drivers/xen/pciback/pciback_ops.c	Thu Mar 23 10:53:55 2006 +0100
     4.2 +++ b/linux-2.6-xen-sparse/drivers/xen/pciback/pciback_ops.c	Thu Mar 23 10:57:48 2006 +0100
     4.3 @@ -12,9 +12,8 @@ int verbose_request = 0;
     4.4  module_param(verbose_request, int, 0644);
     4.5  
     4.6  /* Ensure a device is "turned off" and ready to be exported.
     4.7 - * This also sets up the device's private data to keep track of what should
     4.8 - * be in the base address registers (BARs) so that we can keep the
     4.9 - * client from manipulating them directly.
    4.10 + * (Also see pciback_config_reset to ensure virtual configuration space is
    4.11 + * ready to be re-exported)
    4.12   */
    4.13  void pciback_reset_device(struct pci_dev *dev)
    4.14  {
     5.1 --- a/linux-2.6-xen-sparse/drivers/xen/pciback/vpci.c	Thu Mar 23 10:53:55 2006 +0100
     5.2 +++ b/linux-2.6-xen-sparse/drivers/xen/pciback/vpci.c	Thu Mar 23 10:57:48 2006 +0100
     5.3 @@ -8,12 +8,15 @@
     5.4  #include <linux/list.h>
     5.5  #include <linux/slab.h>
     5.6  #include <linux/pci.h>
     5.7 +#include <linux/spinlock.h>
     5.8  #include "pciback.h"
     5.9  
    5.10  #define PCI_SLOT_MAX 32
    5.11  
    5.12  struct vpci_dev_data {
    5.13 +	/* Access to dev_list must be protected by lock */
    5.14  	struct list_head dev_list[PCI_SLOT_MAX];
    5.15 +	spinlock_t lock;
    5.16  };
    5.17  
    5.18  static inline struct list_head *list_first(struct list_head *head)
    5.19 @@ -25,25 +28,29 @@ struct pci_dev *pciback_get_pci_dev(stru
    5.20  				    unsigned int domain, unsigned int bus,
    5.21  				    unsigned int devfn)
    5.22  {
    5.23 -	struct pci_dev_entry *dev_entry;
    5.24 +	struct pci_dev_entry *entry;
    5.25 +	struct pci_dev *dev = NULL;
    5.26  	struct vpci_dev_data *vpci_dev = pdev->pci_dev_data;
    5.27 +	unsigned long flags;
    5.28  
    5.29  	if (domain != 0 || bus != 0)
    5.30  		return NULL;
    5.31  
    5.32  	if (PCI_SLOT(devfn) < PCI_SLOT_MAX) {
    5.33 -		/* we don't need to lock the list here because once the backend
    5.34 -		 * is in operation, it won't have any more devices addeded
    5.35 -		 * (or removed).
    5.36 -		 */
    5.37 -		list_for_each_entry(dev_entry,
    5.38 +		spin_lock_irqsave(&vpci_dev->lock, flags);
    5.39 +
    5.40 +		list_for_each_entry(entry,
    5.41  				    &vpci_dev->dev_list[PCI_SLOT(devfn)],
    5.42  				    list) {
    5.43 -			if (PCI_FUNC(dev_entry->dev->devfn) == PCI_FUNC(devfn))
    5.44 -				return dev_entry->dev;
    5.45 +			if (PCI_FUNC(entry->dev->devfn) == PCI_FUNC(devfn)) {
    5.46 +				dev = entry->dev;
    5.47 +				break;
    5.48 +			}
    5.49  		}
    5.50 +
    5.51 +		spin_unlock_irqrestore(&vpci_dev->lock, flags);
    5.52  	}
    5.53 -	return NULL;
    5.54 +	return dev;
    5.55  }
    5.56  
    5.57  static inline int match_slot(struct pci_dev *l, struct pci_dev *r)
    5.58 @@ -55,12 +62,12 @@ static inline int match_slot(struct pci_
    5.59  	return 0;
    5.60  }
    5.61  
    5.62 -/* Must hold pciback_device->dev_lock when calling this */
    5.63  int pciback_add_pci_dev(struct pciback_device *pdev, struct pci_dev *dev)
    5.64  {
    5.65  	int err = 0, slot;
    5.66  	struct pci_dev_entry *t, *dev_entry;
    5.67  	struct vpci_dev_data *vpci_dev = pdev->pci_dev_data;
    5.68 +	unsigned long flags;
    5.69  
    5.70  	if ((dev->class >> 24) == PCI_BASE_CLASS_BRIDGE) {
    5.71  		err = -EFAULT;
    5.72 @@ -79,6 +86,8 @@ int pciback_add_pci_dev(struct pciback_d
    5.73  
    5.74  	dev_entry->dev = dev;
    5.75  
    5.76 +	spin_lock_irqsave(&vpci_dev->lock, flags);
    5.77 +
    5.78  	/* Keep multi-function devices together on the virtual PCI bus */
    5.79  	for (slot = 0; slot < PCI_SLOT_MAX; slot++) {
    5.80  		if (!list_empty(&vpci_dev->dev_list[slot])) {
    5.81 @@ -92,7 +101,7 @@ int pciback_add_pci_dev(struct pciback_d
    5.82  					PCI_FUNC(dev->devfn));
    5.83  				list_add_tail(&dev_entry->list,
    5.84  					      &vpci_dev->dev_list[slot]);
    5.85 -				goto out;
    5.86 +				goto unlock;
    5.87  			}
    5.88  		}
    5.89  	}
    5.90 @@ -105,7 +114,7 @@ int pciback_add_pci_dev(struct pciback_d
    5.91  			       pci_name(dev), slot);
    5.92  			list_add_tail(&dev_entry->list,
    5.93  				      &vpci_dev->dev_list[slot]);
    5.94 -			goto out;
    5.95 +			goto unlock;
    5.96  		}
    5.97  	}
    5.98  
    5.99 @@ -113,10 +122,41 @@ int pciback_add_pci_dev(struct pciback_d
   5.100  	xenbus_dev_fatal(pdev->xdev, err,
   5.101  			 "No more space on root virtual PCI bus");
   5.102  
   5.103 +      unlock:
   5.104 +	spin_unlock_irqrestore(&vpci_dev->lock, flags);
   5.105        out:
   5.106  	return err;
   5.107  }
   5.108  
   5.109 +void pciback_release_pci_dev(struct pciback_device *pdev, struct pci_dev *dev)
   5.110 +{
   5.111 +	int slot;
   5.112 +	struct vpci_dev_data *vpci_dev = pdev->pci_dev_data;
   5.113 +	struct pci_dev *found_dev = NULL;
   5.114 +	unsigned long flags;
   5.115 +
   5.116 +	spin_lock_irqsave(&vpci_dev->lock, flags);
   5.117 +
   5.118 +	for (slot = 0; slot < PCI_SLOT_MAX; slot++) {
   5.119 +		struct pci_dev_entry *e, *tmp;
   5.120 +		list_for_each_entry_safe(e, tmp, &vpci_dev->dev_list[slot],
   5.121 +					 list) {
   5.122 +			if (e->dev == dev) {
   5.123 +				list_del(&e->list);
   5.124 +				found_dev = e->dev;
   5.125 +				kfree(e);
   5.126 +				goto out;
   5.127 +			}
   5.128 +		}
   5.129 +	}
   5.130 +
   5.131 +      out:
   5.132 +	spin_unlock_irqrestore(&vpci_dev->lock, flags);
   5.133 +
   5.134 +	if (found_dev)
   5.135 +		pcistub_put_pci_dev(found_dev);
   5.136 +}
   5.137 +
   5.138  int pciback_init_devices(struct pciback_device *pdev)
   5.139  {
   5.140  	int slot;
   5.141 @@ -126,6 +166,8 @@ int pciback_init_devices(struct pciback_
   5.142  	if (!vpci_dev)
   5.143  		return -ENOMEM;
   5.144  
   5.145 +	spin_lock_init(&vpci_dev->lock);
   5.146 +
   5.147  	for (slot = 0; slot < PCI_SLOT_MAX; slot++) {
   5.148  		INIT_LIST_HEAD(&vpci_dev->dev_list[slot]);
   5.149  	}
   5.150 @@ -142,7 +184,6 @@ int pciback_publish_pci_roots(struct pci
   5.151  	return publish_cb(pdev, 0, 0);
   5.152  }
   5.153  
   5.154 -/* Must hold pciback_device->dev_lock when calling this */
   5.155  void pciback_release_devices(struct pciback_device *pdev)
   5.156  {
   5.157  	int slot;
     6.1 --- a/linux-2.6-xen-sparse/drivers/xen/pciback/xenbus.c	Thu Mar 23 10:53:55 2006 +0100
     6.2 +++ b/linux-2.6-xen-sparse/drivers/xen/pciback/xenbus.c	Thu Mar 23 10:57:48 2006 +0100
     6.3 @@ -12,7 +12,7 @@
     6.4  
     6.5  #define INVALID_EVTCHN_IRQ  (-1)
     6.6  
     6.7 -struct pciback_device *alloc_pdev(struct xenbus_device *xdev)
     6.8 +static struct pciback_device *alloc_pdev(struct xenbus_device *xdev)
     6.9  {
    6.10  	struct pciback_device *pdev;
    6.11  
    6.12 @@ -38,7 +38,7 @@ struct pciback_device *alloc_pdev(struct
    6.13  	return pdev;
    6.14  }
    6.15  
    6.16 -void free_pdev(struct pciback_device *pdev)
    6.17 +static void free_pdev(struct pciback_device *pdev)
    6.18  {
    6.19  	if (pdev->be_watching)
    6.20  		unregister_xenbus_watch(&pdev->be_watch);
    6.21 @@ -247,7 +247,7 @@ static int pciback_export_device(struct 
    6.22  	dev_dbg(&pdev->xdev->dev, "exporting dom %x bus %x slot %x func %x\n",
    6.23  		domain, bus, slot, func);
    6.24  
    6.25 -	dev = pcistub_get_pci_dev_by_slot(domain, bus, slot, func);
    6.26 +	dev = pcistub_get_pci_dev_by_slot(pdev, domain, bus, slot, func);
    6.27  	if (!dev) {
    6.28  		err = -EINVAL;
    6.29  		xenbus_dev_fatal(pdev->xdev, err,
    6.30 @@ -434,3 +434,8 @@ int __init pciback_xenbus_register(void)
    6.31  {
    6.32  	return xenbus_register_backend(&xenbus_pciback_driver);
    6.33  }
    6.34 +
    6.35 +void __exit pciback_xenbus_unregister(void)
    6.36 +{
    6.37 +	xenbus_unregister_driver(&xenbus_pciback_driver);
    6.38 +}
     7.1 --- a/tools/python/xen/xend/server/pciif.py	Thu Mar 23 10:53:55 2006 +0100
     7.2 +++ b/tools/python/xen/xend/server/pciif.py	Thu Mar 23 10:57:48 2006 +0100
     7.3 @@ -118,10 +118,12 @@ class PciController(DevController):
     7.4                      "parse it's resources - %s"+str(e))
     7.5  
     7.6          if dev.driver!='pciback':
     7.7 -            raise VmError(("pci: PCI Backend does not own device "+
     7.8 -                    "%s\n"+
     7.9 -                    "See the pciback.hide kernel "+
    7.10 -                    "command-line parameter")%(dev.name))
    7.11 +            raise VmError(("pci: PCI Backend does not own device "+ \
    7.12 +                    "%s\n"+ \
    7.13 +                    "See the pciback.hide kernel "+ \
    7.14 +                    "command-line parameter or\n"+ \
    7.15 +                    "bind your slot/device to the PCI backend using sysfs" \
    7.16 +                    )%(dev.name))
    7.17  
    7.18          for (start, size) in dev.ioports:
    7.19              log.debug('pci: enabling ioport 0x%x/0x%x'%(start,size))