diff options
Diffstat (limited to 'drivers/virtio/virtio_pci.c')
-rw-r--r-- | drivers/virtio/virtio_pci.c | 110 |
1 files changed, 104 insertions, 6 deletions
diff --git a/drivers/virtio/virtio_pci.c b/drivers/virtio/virtio_pci.c index baabb7937ec2..635e1efb3792 100644 --- a/drivers/virtio/virtio_pci.c +++ b/drivers/virtio/virtio_pci.c | |||
@@ -55,6 +55,10 @@ struct virtio_pci_device | |||
55 | unsigned msix_vectors; | 55 | unsigned msix_vectors; |
56 | /* Vectors allocated, excluding per-vq vectors if any */ | 56 | /* Vectors allocated, excluding per-vq vectors if any */ |
57 | unsigned msix_used_vectors; | 57 | unsigned msix_used_vectors; |
58 | |||
59 | /* Status saved during hibernate/restore */ | ||
60 | u8 saved_status; | ||
61 | |||
58 | /* Whether we have vector per vq */ | 62 | /* Whether we have vector per vq */ |
59 | bool per_vq_vectors; | 63 | bool per_vq_vectors; |
60 | }; | 64 | }; |
@@ -414,8 +418,8 @@ static struct virtqueue *setup_vq(struct virtio_device *vdev, unsigned index, | |||
414 | vp_dev->ioaddr + VIRTIO_PCI_QUEUE_PFN); | 418 | vp_dev->ioaddr + VIRTIO_PCI_QUEUE_PFN); |
415 | 419 | ||
416 | /* create the vring */ | 420 | /* create the vring */ |
417 | vq = vring_new_virtqueue(info->num, VIRTIO_PCI_VRING_ALIGN, | 421 | vq = vring_new_virtqueue(info->num, VIRTIO_PCI_VRING_ALIGN, vdev, |
418 | vdev, info->queue, vp_notify, callback, name); | 422 | true, info->queue, vp_notify, callback, name); |
419 | if (!vq) { | 423 | if (!vq) { |
420 | err = -ENOMEM; | 424 | err = -ENOMEM; |
421 | goto out_activate_queue; | 425 | goto out_activate_queue; |
@@ -716,19 +720,114 @@ static void __devexit virtio_pci_remove(struct pci_dev *pci_dev) | |||
716 | } | 720 | } |
717 | 721 | ||
718 | #ifdef CONFIG_PM | 722 | #ifdef CONFIG_PM |
719 | static int virtio_pci_suspend(struct pci_dev *pci_dev, pm_message_t state) | 723 | static int virtio_pci_suspend(struct device *dev) |
720 | { | 724 | { |
725 | struct pci_dev *pci_dev = to_pci_dev(dev); | ||
726 | |||
721 | pci_save_state(pci_dev); | 727 | pci_save_state(pci_dev); |
722 | pci_set_power_state(pci_dev, PCI_D3hot); | 728 | pci_set_power_state(pci_dev, PCI_D3hot); |
723 | return 0; | 729 | return 0; |
724 | } | 730 | } |
725 | 731 | ||
726 | static int virtio_pci_resume(struct pci_dev *pci_dev) | 732 | static int virtio_pci_resume(struct device *dev) |
727 | { | 733 | { |
734 | struct pci_dev *pci_dev = to_pci_dev(dev); | ||
735 | |||
728 | pci_restore_state(pci_dev); | 736 | pci_restore_state(pci_dev); |
729 | pci_set_power_state(pci_dev, PCI_D0); | 737 | pci_set_power_state(pci_dev, PCI_D0); |
730 | return 0; | 738 | return 0; |
731 | } | 739 | } |
740 | |||
741 | static int virtio_pci_freeze(struct device *dev) | ||
742 | { | ||
743 | struct pci_dev *pci_dev = to_pci_dev(dev); | ||
744 | struct virtio_pci_device *vp_dev = pci_get_drvdata(pci_dev); | ||
745 | struct virtio_driver *drv; | ||
746 | int ret; | ||
747 | |||
748 | drv = container_of(vp_dev->vdev.dev.driver, | ||
749 | struct virtio_driver, driver); | ||
750 | |||
751 | ret = 0; | ||
752 | vp_dev->saved_status = vp_get_status(&vp_dev->vdev); | ||
753 | if (drv && drv->freeze) | ||
754 | ret = drv->freeze(&vp_dev->vdev); | ||
755 | |||
756 | if (!ret) | ||
757 | pci_disable_device(pci_dev); | ||
758 | return ret; | ||
759 | } | ||
760 | |||
761 | static int restore_common(struct device *dev) | ||
762 | { | ||
763 | struct pci_dev *pci_dev = to_pci_dev(dev); | ||
764 | struct virtio_pci_device *vp_dev = pci_get_drvdata(pci_dev); | ||
765 | int ret; | ||
766 | |||
767 | ret = pci_enable_device(pci_dev); | ||
768 | if (ret) | ||
769 | return ret; | ||
770 | pci_set_master(pci_dev); | ||
771 | vp_finalize_features(&vp_dev->vdev); | ||
772 | |||
773 | return ret; | ||
774 | } | ||
775 | |||
776 | static int virtio_pci_thaw(struct device *dev) | ||
777 | { | ||
778 | struct pci_dev *pci_dev = to_pci_dev(dev); | ||
779 | struct virtio_pci_device *vp_dev = pci_get_drvdata(pci_dev); | ||
780 | struct virtio_driver *drv; | ||
781 | int ret; | ||
782 | |||
783 | ret = restore_common(dev); | ||
784 | if (ret) | ||
785 | return ret; | ||
786 | |||
787 | drv = container_of(vp_dev->vdev.dev.driver, | ||
788 | struct virtio_driver, driver); | ||
789 | |||
790 | if (drv && drv->thaw) | ||
791 | ret = drv->thaw(&vp_dev->vdev); | ||
792 | else if (drv && drv->restore) | ||
793 | ret = drv->restore(&vp_dev->vdev); | ||
794 | |||
795 | /* Finally, tell the device we're all set */ | ||
796 | if (!ret) | ||
797 | vp_set_status(&vp_dev->vdev, vp_dev->saved_status); | ||
798 | |||
799 | return ret; | ||
800 | } | ||
801 | |||
802 | static int virtio_pci_restore(struct device *dev) | ||
803 | { | ||
804 | struct pci_dev *pci_dev = to_pci_dev(dev); | ||
805 | struct virtio_pci_device *vp_dev = pci_get_drvdata(pci_dev); | ||
806 | struct virtio_driver *drv; | ||
807 | int ret; | ||
808 | |||
809 | drv = container_of(vp_dev->vdev.dev.driver, | ||
810 | struct virtio_driver, driver); | ||
811 | |||
812 | ret = restore_common(dev); | ||
813 | if (!ret && drv && drv->restore) | ||
814 | ret = drv->restore(&vp_dev->vdev); | ||
815 | |||
816 | /* Finally, tell the device we're all set */ | ||
817 | if (!ret) | ||
818 | vp_set_status(&vp_dev->vdev, vp_dev->saved_status); | ||
819 | |||
820 | return ret; | ||
821 | } | ||
822 | |||
823 | static const struct dev_pm_ops virtio_pci_pm_ops = { | ||
824 | .suspend = virtio_pci_suspend, | ||
825 | .resume = virtio_pci_resume, | ||
826 | .freeze = virtio_pci_freeze, | ||
827 | .thaw = virtio_pci_thaw, | ||
828 | .restore = virtio_pci_restore, | ||
829 | .poweroff = virtio_pci_suspend, | ||
830 | }; | ||
732 | #endif | 831 | #endif |
733 | 832 | ||
734 | static struct pci_driver virtio_pci_driver = { | 833 | static struct pci_driver virtio_pci_driver = { |
@@ -737,8 +836,7 @@ static struct pci_driver virtio_pci_driver = { | |||
737 | .probe = virtio_pci_probe, | 836 | .probe = virtio_pci_probe, |
738 | .remove = __devexit_p(virtio_pci_remove), | 837 | .remove = __devexit_p(virtio_pci_remove), |
739 | #ifdef CONFIG_PM | 838 | #ifdef CONFIG_PM |
740 | .suspend = virtio_pci_suspend, | 839 | .driver.pm = &virtio_pci_pm_ops, |
741 | .resume = virtio_pci_resume, | ||
742 | #endif | 840 | #endif |
743 | }; | 841 | }; |
744 | 842 | ||