diff options
Diffstat (limited to 'drivers/pci/xen-pcifront.c')
| -rw-r--r-- | drivers/pci/xen-pcifront.c | 38 |
1 files changed, 26 insertions, 12 deletions
diff --git a/drivers/pci/xen-pcifront.c b/drivers/pci/xen-pcifront.c index 0aab85a5155..53df39a22c8 100644 --- a/drivers/pci/xen-pcifront.c +++ b/drivers/pci/xen-pcifront.c @@ -20,6 +20,7 @@ #include <linux/workqueue.h> #include <linux/bitops.h> #include <linux/time.h> +#include <xen/platform_pci.h> #include <asm/xen/swiotlb-xen.h> #define INVALID_GRANT_REF (0) @@ -412,7 +413,7 @@ static int pcifront_claim_resource(struct pci_dev *dev, void *data) return 0; } -static int __devinit pcifront_scan_bus(struct pcifront_device *pdev, +static int pcifront_scan_bus(struct pcifront_device *pdev, unsigned int domain, unsigned int bus, struct pci_bus *b) { @@ -441,7 +442,7 @@ static int __devinit pcifront_scan_bus(struct pcifront_device *pdev, return 0; } -static int __devinit pcifront_scan_root(struct pcifront_device *pdev, +static int pcifront_scan_root(struct pcifront_device *pdev, unsigned int domain, unsigned int bus) { struct pci_bus *b; @@ -471,12 +472,15 @@ static int __devinit pcifront_scan_root(struct pcifront_device *pdev, } pcifront_init_sd(sd, domain, bus, pdev); + pci_lock_rescan_remove(); + b = pci_scan_bus_parented(&pdev->xdev->dev, bus, &pcifront_bus_ops, sd); if (!b) { dev_err(&pdev->xdev->dev, "Error creating PCI Frontend Bus!\n"); err = -ENOMEM; + pci_unlock_rescan_remove(); goto err_out; } @@ -494,6 +498,7 @@ static int __devinit pcifront_scan_root(struct pcifront_device *pdev, /* Create SysFS and notify udev of the devices. Aka: "going live" */ pci_bus_add_devices(b); + pci_unlock_rescan_remove(); return err; err_out: @@ -503,7 +508,7 @@ err_out: return err; } -static int __devinit pcifront_rescan_root(struct pcifront_device *pdev, +static int pcifront_rescan_root(struct pcifront_device *pdev, unsigned int domain, unsigned int bus) { int err; @@ -556,6 +561,7 @@ static void pcifront_free_roots(struct pcifront_device *pdev) dev_dbg(&pdev->xdev->dev, "cleaning up root buses\n"); + pci_lock_rescan_remove(); list_for_each_entry_safe(bus_entry, t, &pdev->root_buses, list) { list_del(&bus_entry->list); @@ -568,6 +574,7 @@ static void pcifront_free_roots(struct pcifront_device *pdev) kfree(bus_entry); } + pci_unlock_rescan_remove(); } static pci_ers_result_t pcifront_common_process(int cmd, @@ -655,9 +662,9 @@ static void pcifront_do_aer(struct work_struct *data) notify_remote_via_evtchn(pdev->evtchn); /*in case of we lost an aer request in four lines time_window*/ - smp_mb__before_clear_bit(); + smp_mb__before_atomic(); clear_bit(_PDEVB_op_active, &pdev->flags); - smp_mb__after_clear_bit(); + smp_mb__after_atomic(); schedule_pcifront_aer_op(pdev); @@ -678,10 +685,9 @@ static int pcifront_connect_and_init_dma(struct pcifront_device *pdev) if (!pcifront_dev) { dev_info(&pdev->xdev->dev, "Installing PCI frontend\n"); pcifront_dev = pdev; - } else { - dev_err(&pdev->xdev->dev, "PCI frontend already installed!\n"); + } else err = -EEXIST; - } + spin_unlock(&pcifront_dev_lock); if (!err && !swiotlb_nr_tbl()) { @@ -834,7 +840,7 @@ out: return err; } -static int __devinit pcifront_try_connect(struct pcifront_device *pdev) +static int pcifront_try_connect(struct pcifront_device *pdev) { int err = -EFAULT; int i, num_roots, len; @@ -848,7 +854,7 @@ static int __devinit pcifront_try_connect(struct pcifront_device *pdev) goto out; err = pcifront_connect_and_init_dma(pdev); - if (err) { + if (err && err != -EEXIST) { xenbus_dev_fatal(pdev->xdev, err, "Error setting up PCI Frontend"); goto out; @@ -924,7 +930,7 @@ out: return err; } -static int __devinit pcifront_attach_devices(struct pcifront_device *pdev) +static int pcifront_attach_devices(struct pcifront_device *pdev) { int err = -EFAULT; int i, num_roots, len; @@ -1044,8 +1050,10 @@ static int pcifront_detach_devices(struct pcifront_device *pdev) domain, bus, slot, func); continue; } + pci_lock_rescan_remove(); pci_stop_and_remove_bus_device(pci_dev); pci_dev_put(pci_dev); + pci_unlock_rescan_remove(); dev_dbg(&pdev->xdev->dev, "PCI device %04x:%02x:%02x.%d removed.\n", @@ -1068,13 +1076,16 @@ static void __init_refok pcifront_backend_changed(struct xenbus_device *xdev, case XenbusStateInitialising: case XenbusStateInitWait: case XenbusStateInitialised: - case XenbusStateClosed: break; case XenbusStateConnected: pcifront_try_connect(pdev); break; + case XenbusStateClosed: + if (xdev->state == XenbusStateClosed) + break; + /* Missed the backend's CLOSING state -- fallthrough */ case XenbusStateClosing: dev_warn(&xdev->dev, "backend going away!\n"); pcifront_try_disconnect(pdev); @@ -1136,6 +1147,9 @@ static int __init pcifront_init(void) if (!xen_pv_domain() || xen_initial_domain()) return -ENODEV; + if (!xen_has_pv_devices()) + return -ENODEV; + pci_frontend_registrar(1 /* enable */); return xenbus_register_frontend(&xenpci_driver); |
