diff options
author | kaf24@firebug.cl.cam.ac.uk <kaf24@firebug.cl.cam.ac.uk> | 2006-03-23 10:53:55 +0100 |
---|---|---|
committer | kaf24@firebug.cl.cam.ac.uk <kaf24@firebug.cl.cam.ac.uk> | 2006-03-23 10:53:55 +0100 |
commit | 7a128eeb93369334d61ae5549491f2f10597f685 (patch) | |
tree | 1119c14261e0f166513b075a4f3d811e4f5848e6 | |
parent | 67f77e61bc5ad08da058d22c7fb7a1cee0a97c57 (diff) | |
download | xen-7a128eeb93369334d61ae5549491f2f10597f685.tar.gz xen-7a128eeb93369334d61ae5549491f2f10597f685.tar.bz2 xen-7a128eeb93369334d61ae5549491f2f10597f685.zip |
The PCI Frontend doesn't properly clean-up PCI buses and their devices
that are in-use if the PCI Backend goes away. This patch corrects that.
This patch also shortens the timeout in drivers/xen/pcifront/pci_op.c
(in an attempt to minimize the amount of time spent waiting with
interrupts disabled).
Signed-off-by: Ryan Wilson <hap9@epoch.ncsc.mil>
-rw-r--r-- | linux-2.6-xen-sparse/drivers/xen/pcifront/pci_op.c | 39 | ||||
-rw-r--r-- | linux-2.6-xen-sparse/drivers/xen/pcifront/xenbus.c | 2 |
2 files changed, 28 insertions, 13 deletions
diff --git a/linux-2.6-xen-sparse/drivers/xen/pcifront/pci_op.c b/linux-2.6-xen-sparse/drivers/xen/pcifront/pci_op.c index c7e6580f28..38906ade6e 100644 --- a/linux-2.6-xen-sparse/drivers/xen/pcifront/pci_op.c +++ b/linux-2.6-xen-sparse/drivers/xen/pcifront/pci_op.c @@ -56,19 +56,19 @@ static int do_pci_op(struct pcifront_device *pdev, struct xen_pci_op *op) notify_remote_via_evtchn(port); /* - * We set a poll timeout of 5 seconds but give up on return after - * 4 seconds. It is better to time out too late rather than too early + * We set a poll timeout of 3 seconds but give up on return after + * 2 seconds. It is better to time out too late rather than too early * (in the latter case we end up continually re-executing poll() with a * timeout in the past). 1s difference gives plenty of slack for error. */ do_gettimeofday(&tv); - ns_timeout = timeval_to_ns(&tv) + 4 * (nsec_t)NSEC_PER_SEC; + ns_timeout = timeval_to_ns(&tv) + 2 * (nsec_t)NSEC_PER_SEC; clear_evtchn(port); while (test_bit(_XEN_PCIF_active, (unsigned long *)&pdev->sh_info->flags)) { - if (HYPERVISOR_poll(&port, 1, jiffies + 5*HZ)) + if (HYPERVISOR_poll(&port, 1, jiffies + 3*HZ)) BUG(); clear_evtchn(port); do_gettimeofday(&tv); @@ -173,7 +173,7 @@ static void pcifront_claim_resource(struct pci_dev *dev, void *data) if (!r->parent && r->start && r->flags) { dev_dbg(&pdev->xdev->dev, "claiming resource %s/%d\n", - pci_name(dev), i); + pci_name(dev), i); pci_claim_resource(dev, i); } } @@ -234,25 +234,38 @@ int pcifront_scan_root(struct pcifront_device *pdev, return err; } +static void free_root_bus_devs(struct pci_bus *bus) +{ + struct pci_dev *dev; + + spin_lock(&pci_bus_lock); + while (!list_empty(&bus->devices)) { + dev = container_of(bus->devices.next, struct pci_dev, bus_list); + spin_unlock(&pci_bus_lock); + + dev_dbg(&dev->dev, "removing device\n"); + pci_remove_bus_device(dev); + + spin_lock(&pci_bus_lock); + } + spin_unlock(&pci_bus_lock); +} + void pcifront_free_roots(struct pcifront_device *pdev) { struct pci_bus_entry *bus_entry, *t; + dev_dbg(&pdev->xdev->dev, "cleaning up root buses\n"); + list_for_each_entry_safe(bus_entry, t, &pdev->root_buses, list) { - /* TODO: Removing a PCI Bus is untested (as it normally - * just goes away on domain shutdown) - */ list_del(&bus_entry->list); - spin_lock(&pci_bus_lock); - list_del(&bus_entry->bus->node); - spin_unlock(&pci_bus_lock); + free_root_bus_devs(bus_entry->bus); kfree(bus_entry->bus->sysdata); device_unregister(bus_entry->bus->bridge); - - /* Do we need to free() the bus itself? */ + pci_remove_bus(bus_entry->bus); kfree(bus_entry); } diff --git a/linux-2.6-xen-sparse/drivers/xen/pcifront/xenbus.c b/linux-2.6-xen-sparse/drivers/xen/pcifront/xenbus.c index c596ed4c7b..eed89eb5d3 100644 --- a/linux-2.6-xen-sparse/drivers/xen/pcifront/xenbus.c +++ b/linux-2.6-xen-sparse/drivers/xen/pcifront/xenbus.c @@ -50,6 +50,8 @@ static void free_pdev(struct pcifront_device *pdev) { dev_dbg(&pdev->xdev->dev, "freeing pdev @ 0x%p\n", pdev); + pcifront_free_roots(pdev); + if (pdev->evtchn != INVALID_EVTCHN) xenbus_free_evtchn(pdev->xdev, pdev->evtchn); |