diff options
author | Michael S. Tsirkin <mst@redhat.com> | 2015-01-13 10:23:32 +0100 |
---|---|---|
committer | Rusty Russell <rusty@rustcorp.com.au> | 2015-01-21 06:58:51 +0100 |
commit | ff31d2e28549c84d53252b3c36b6f0ba18b78697 (patch) | |
tree | c9fa6b04df782a19b50d923c8f1cdd4fbe29888c /drivers/virtio/virtio_pci_common.c | |
parent | virtio_pci: drop useless del_vqs call (diff) | |
download | linux-ff31d2e28549c84d53252b3c36b6f0ba18b78697.tar.xz linux-ff31d2e28549c84d53252b3c36b6f0ba18b78697.zip |
virtio_pci: move probe/remove code to common
Most of initialization is device-independent.
Let's move it to common.
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Diffstat (limited to 'drivers/virtio/virtio_pci_common.c')
-rw-r--r-- | drivers/virtio/virtio_pci_common.c | 69 |
1 files changed, 67 insertions, 2 deletions
diff --git a/drivers/virtio/virtio_pci_common.c b/drivers/virtio/virtio_pci_common.c index 9756f21b809e..457cbe29c8c4 100644 --- a/drivers/virtio/virtio_pci_common.c +++ b/drivers/virtio/virtio_pci_common.c @@ -464,15 +464,80 @@ static const struct pci_device_id virtio_pci_id_table[] = { MODULE_DEVICE_TABLE(pci, virtio_pci_id_table); +static void virtio_pci_release_dev(struct device *_d) +{ + struct virtio_device *vdev = dev_to_virtio(_d); + struct virtio_pci_device *vp_dev = to_vp_device(vdev); + + /* As struct device is a kobject, it's not safe to + * free the memory (including the reference counter itself) + * until it's release callback. */ + kfree(vp_dev); +} + static int virtio_pci_probe(struct pci_dev *pci_dev, const struct pci_device_id *id) { - return virtio_pci_legacy_probe(pci_dev, id); + struct virtio_pci_device *vp_dev; + int rc; + + /* allocate our structure and fill it out */ + vp_dev = kzalloc(sizeof(struct virtio_pci_device), GFP_KERNEL); + if (!vp_dev) + return -ENOMEM; + + pci_set_drvdata(pci_dev, vp_dev); + vp_dev->vdev.dev.parent = &pci_dev->dev; + vp_dev->vdev.dev.release = virtio_pci_release_dev; + vp_dev->pci_dev = pci_dev; + INIT_LIST_HEAD(&vp_dev->virtqueues); + spin_lock_init(&vp_dev->lock); + + /* Disable MSI/MSIX to bring device to a known good state. */ + pci_msi_off(pci_dev); + + /* enable the device */ + rc = pci_enable_device(pci_dev); + if (rc) + goto err_enable_device; + + rc = pci_request_regions(pci_dev, "virtio-pci"); + if (rc) + goto err_request_regions; + + rc = virtio_pci_legacy_probe(vp_dev); + if (rc) + goto err_probe; + + pci_set_master(pci_dev); + + rc = register_virtio_device(&vp_dev->vdev); + if (rc) + goto err_register; + + return 0; + +err_register: + virtio_pci_legacy_remove(vp_dev); +err_probe: + pci_release_regions(pci_dev); +err_request_regions: + pci_disable_device(pci_dev); +err_enable_device: + kfree(vp_dev); + return rc; } static void virtio_pci_remove(struct pci_dev *pci_dev) { - virtio_pci_legacy_remove(pci_dev); + struct virtio_pci_device *vp_dev = pci_get_drvdata(pci_dev); + + unregister_virtio_device(&vp_dev->vdev); + + virtio_pci_legacy_remove(pci_dev); + + pci_release_regions(pci_dev); + pci_disable_device(pci_dev); } static struct pci_driver virtio_pci_driver = { |