diff options
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[] = { | |||
| 464 | 464 | ||
| 465 | MODULE_DEVICE_TABLE(pci, virtio_pci_id_table); | 465 | MODULE_DEVICE_TABLE(pci, virtio_pci_id_table); |
| 466 | 466 | ||
| 467 | static void virtio_pci_release_dev(struct device *_d) | ||
| 468 | { | ||
| 469 | struct virtio_device *vdev = dev_to_virtio(_d); | ||
| 470 | struct virtio_pci_device *vp_dev = to_vp_device(vdev); | ||
| 471 | |||
| 472 | /* As struct device is a kobject, it's not safe to | ||
| 473 | * free the memory (including the reference counter itself) | ||
| 474 | * until it's release callback. */ | ||
| 475 | kfree(vp_dev); | ||
| 476 | } | ||
| 477 | |||
| 467 | static int virtio_pci_probe(struct pci_dev *pci_dev, | 478 | static int virtio_pci_probe(struct pci_dev *pci_dev, |
| 468 | const struct pci_device_id *id) | 479 | const struct pci_device_id *id) |
| 469 | { | 480 | { |
| 470 | return virtio_pci_legacy_probe(pci_dev, id); | 481 | struct virtio_pci_device *vp_dev; |
| 482 | int rc; | ||
| 483 | |||
| 484 | /* allocate our structure and fill it out */ | ||
| 485 | vp_dev = kzalloc(sizeof(struct virtio_pci_device), GFP_KERNEL); | ||
| 486 | if (!vp_dev) | ||
| 487 | return -ENOMEM; | ||
| 488 | |||
| 489 | pci_set_drvdata(pci_dev, vp_dev); | ||
| 490 | vp_dev->vdev.dev.parent = &pci_dev->dev; | ||
| 491 | vp_dev->vdev.dev.release = virtio_pci_release_dev; | ||
| 492 | vp_dev->pci_dev = pci_dev; | ||
| 493 | INIT_LIST_HEAD(&vp_dev->virtqueues); | ||
| 494 | spin_lock_init(&vp_dev->lock); | ||
| 495 | |||
| 496 | /* Disable MSI/MSIX to bring device to a known good state. */ | ||
| 497 | pci_msi_off(pci_dev); | ||
| 498 | |||
| 499 | /* enable the device */ | ||
| 500 | rc = pci_enable_device(pci_dev); | ||
| 501 | if (rc) | ||
| 502 | goto err_enable_device; | ||
| 503 | |||
| 504 | rc = pci_request_regions(pci_dev, "virtio-pci"); | ||
| 505 | if (rc) | ||
| 506 | goto err_request_regions; | ||
| 507 | |||
| 508 | rc = virtio_pci_legacy_probe(vp_dev); | ||
| 509 | if (rc) | ||
| 510 | goto err_probe; | ||
| 511 | |||
| 512 | pci_set_master(pci_dev); | ||
| 513 | |||
| 514 | rc = register_virtio_device(&vp_dev->vdev); | ||
| 515 | if (rc) | ||
| 516 | goto err_register; | ||
| 517 | |||
| 518 | return 0; | ||
| 519 | |||
| 520 | err_register: | ||
| 521 | virtio_pci_legacy_remove(vp_dev); | ||
| 522 | err_probe: | ||
| 523 | pci_release_regions(pci_dev); | ||
| 524 | err_request_regions: | ||
| 525 | pci_disable_device(pci_dev); | ||
| 526 | err_enable_device: | ||
| 527 | kfree(vp_dev); | ||
| 528 | return rc; | ||
| 471 | } | 529 | } |
| 472 | 530 | ||
| 473 | static void virtio_pci_remove(struct pci_dev *pci_dev) | 531 | static void virtio_pci_remove(struct pci_dev *pci_dev) |
| 474 | { | 532 | { |
| 475 | virtio_pci_legacy_remove(pci_dev); | 533 | struct virtio_pci_device *vp_dev = pci_get_drvdata(pci_dev); |
| 534 | |||
| 535 | unregister_virtio_device(&vp_dev->vdev); | ||
| 536 | |||
| 537 | virtio_pci_legacy_remove(pci_dev); | ||
| 538 | |||
| 539 | pci_release_regions(pci_dev); | ||
| 540 | pci_disable_device(pci_dev); | ||
| 476 | } | 541 | } |
| 477 | 542 | ||
| 478 | static struct pci_driver virtio_pci_driver = { | 543 | static struct pci_driver virtio_pci_driver = { |
