Skip to content

Commit

Permalink
virtio: pci: add PM notification handlers for restore, freeze, thaw, …
Browse files Browse the repository at this point in the history
…poweroff

Handle thaw, restore and freeze notifications from the PM core.  Expose
these to individual virtio drivers that can quiesce and resume vq
operations.  For drivers not implementing the thaw() method, use the
restore method instead.

These functions also save device-specific data so that the device can be
put in pre-suspend state after resume, and disable and enable the PCI
device in the freeze and resume functions, respectively.

Signed-off-by: Amit Shah <[email protected]>
Signed-off-by: Rusty Russell <[email protected]>
  • Loading branch information
Amit Shah authored and rustyrussell committed Jan 12, 2012
1 parent d077536 commit f0fe6f1
Show file tree
Hide file tree
Showing 2 changed files with 97 additions and 2 deletions.
94 changes: 92 additions & 2 deletions drivers/virtio/virtio_pci.c
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,10 @@ struct virtio_pci_device
unsigned msix_vectors;
/* Vectors allocated, excluding per-vq vectors if any */
unsigned msix_used_vectors;

/* Status saved during hibernate/restore */
u8 saved_status;

/* Whether we have vector per vq */
bool per_vq_vectors;
};
Expand Down Expand Up @@ -734,9 +738,95 @@ static int virtio_pci_resume(struct device *dev)
return 0;
}

static int virtio_pci_freeze(struct device *dev)
{
struct pci_dev *pci_dev = to_pci_dev(dev);
struct virtio_pci_device *vp_dev = pci_get_drvdata(pci_dev);
struct virtio_driver *drv;
int ret;

drv = container_of(vp_dev->vdev.dev.driver,
struct virtio_driver, driver);

ret = 0;
vp_dev->saved_status = vp_get_status(&vp_dev->vdev);
if (drv && drv->freeze)
ret = drv->freeze(&vp_dev->vdev);

if (!ret)
pci_disable_device(pci_dev);
return ret;
}

static int restore_common(struct device *dev)
{
struct pci_dev *pci_dev = to_pci_dev(dev);
struct virtio_pci_device *vp_dev = pci_get_drvdata(pci_dev);
int ret;

ret = pci_enable_device(pci_dev);
if (ret)
return ret;
pci_set_master(pci_dev);
vp_finalize_features(&vp_dev->vdev);

return ret;
}

static int virtio_pci_thaw(struct device *dev)
{
struct pci_dev *pci_dev = to_pci_dev(dev);
struct virtio_pci_device *vp_dev = pci_get_drvdata(pci_dev);
struct virtio_driver *drv;
int ret;

ret = restore_common(dev);
if (ret)
return ret;

drv = container_of(vp_dev->vdev.dev.driver,
struct virtio_driver, driver);

if (drv && drv->thaw)
ret = drv->thaw(&vp_dev->vdev);
else if (drv && drv->restore)
ret = drv->restore(&vp_dev->vdev);

/* Finally, tell the device we're all set */
if (!ret)
vp_set_status(&vp_dev->vdev, vp_dev->saved_status);

return ret;
}

static int virtio_pci_restore(struct device *dev)
{
struct pci_dev *pci_dev = to_pci_dev(dev);
struct virtio_pci_device *vp_dev = pci_get_drvdata(pci_dev);
struct virtio_driver *drv;
int ret;

drv = container_of(vp_dev->vdev.dev.driver,
struct virtio_driver, driver);

ret = restore_common(dev);
if (!ret && drv && drv->restore)
ret = drv->restore(&vp_dev->vdev);

/* Finally, tell the device we're all set */
if (!ret)
vp_set_status(&vp_dev->vdev, vp_dev->saved_status);

return ret;
}

static const struct dev_pm_ops virtio_pci_pm_ops = {
.suspend = virtio_pci_suspend,
.resume = virtio_pci_resume,
.suspend = virtio_pci_suspend,
.resume = virtio_pci_resume,
.freeze = virtio_pci_freeze,
.thaw = virtio_pci_thaw,
.restore = virtio_pci_restore,
.poweroff = virtio_pci_suspend,
};
#endif

Expand Down
5 changes: 5 additions & 0 deletions include/linux/virtio.h
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,11 @@ struct virtio_driver {
int (*probe)(struct virtio_device *dev);
void (*remove)(struct virtio_device *dev);
void (*config_changed)(struct virtio_device *dev);
#ifdef CONFIG_PM
int (*freeze)(struct virtio_device *dev);
int (*thaw)(struct virtio_device *dev);
int (*restore)(struct virtio_device *dev);
#endif
};

int register_virtio_driver(struct virtio_driver *drv);
Expand Down

0 comments on commit f0fe6f1

Please sign in to comment.