Skip to content

Commit

Permalink
virtio-pci: move freeze/restore to virtio core
Browse files Browse the repository at this point in the history
This is in preparation to extending config changed event handling
in core.
Wrapping these in an API also seems to make for a cleaner code.

Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Reviewed-by: Cornelia Huck <cornelia.huck@de.ibm.com>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
  • Loading branch information
Michael S. Tsirkin authored and Rusty Russell committed Oct 14, 2014
1 parent 016c98c commit c6716ba
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 52 deletions.
54 changes: 54 additions & 0 deletions drivers/virtio/virtio.c
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,60 @@ void virtio_config_changed(struct virtio_device *dev)
}
EXPORT_SYMBOL_GPL(virtio_config_changed);

#ifdef CONFIG_PM_SLEEP
int virtio_device_freeze(struct virtio_device *dev)
{
struct virtio_driver *drv = drv_to_virtio(dev->dev.driver);

dev->failed = dev->config->get_status(dev) & VIRTIO_CONFIG_S_FAILED;

if (drv && drv->freeze)
return drv->freeze(dev);

return 0;
}
EXPORT_SYMBOL_GPL(virtio_device_freeze);

int virtio_device_restore(struct virtio_device *dev)
{
struct virtio_driver *drv = drv_to_virtio(dev->dev.driver);

/* We always start by resetting the device, in case a previous
* driver messed it up. */
dev->config->reset(dev);

/* Acknowledge that we've seen the device. */
add_status(dev, VIRTIO_CONFIG_S_ACKNOWLEDGE);

/* Maybe driver failed before freeze.
* Restore the failed status, for debugging. */
if (dev->failed)
add_status(dev, VIRTIO_CONFIG_S_FAILED);

if (!drv)
return 0;

/* We have a driver! */
add_status(dev, VIRTIO_CONFIG_S_DRIVER);

dev->config->finalize_features(dev);

if (drv->restore) {
int ret = drv->restore(dev);
if (ret) {
add_status(dev, VIRTIO_CONFIG_S_FAILED);
return ret;
}
}

/* Finally, tell the device we're all set */
add_status(dev, VIRTIO_CONFIG_S_DRIVER_OK);

return 0;
}
EXPORT_SYMBOL_GPL(virtio_device_restore);
#endif

static int virtio_init(void)
{
if (bus_register(&virtio_bus) != 0)
Expand Down
54 changes: 2 additions & 52 deletions drivers/virtio/virtio_pci.c
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,6 @@ struct virtio_pci_device
/* 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 @@ -764,16 +761,9 @@ 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);
ret = virtio_device_freeze(&vp_dev->vdev);

if (!ret)
pci_disable_device(pci_dev);
Expand All @@ -784,54 +774,14 @@ 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;
unsigned status = 0;
int ret;

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

ret = pci_enable_device(pci_dev);
if (ret)
return ret;

pci_set_master(pci_dev);
/* We always start by resetting the device, in case a previous
* driver messed it up. */
vp_reset(&vp_dev->vdev);

/* Acknowledge that we've seen the device. */
status |= VIRTIO_CONFIG_S_ACKNOWLEDGE;
vp_set_status(&vp_dev->vdev, status);

/* Maybe driver failed before freeze.
* Restore the failed status, for debugging. */
status |= vp_dev->saved_status & VIRTIO_CONFIG_S_FAILED;
vp_set_status(&vp_dev->vdev, status);

if (!drv)
return 0;

/* We have a driver! */
status |= VIRTIO_CONFIG_S_DRIVER;
vp_set_status(&vp_dev->vdev, status);

vp_finalize_features(&vp_dev->vdev);

if (drv->restore) {
ret = drv->restore(&vp_dev->vdev);
if (ret) {
status |= VIRTIO_CONFIG_S_FAILED;
vp_set_status(&vp_dev->vdev, status);
return ret;
}
}

/* Finally, tell the device we're all set */
status |= VIRTIO_CONFIG_S_DRIVER_OK;
vp_set_status(&vp_dev->vdev, status);

return ret;
return virtio_device_restore(&vp_dev->vdev);
}

static const struct dev_pm_ops virtio_pci_pm_ops = {
Expand Down
6 changes: 6 additions & 0 deletions include/linux/virtio.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ bool virtqueue_is_broken(struct virtqueue *vq);
/**
* virtio_device - representation of a device using virtio
* @index: unique position on the virtio bus
* @failed: saved value for CONFIG_S_FAILED bit (for restore)
* @dev: underlying device.
* @id: the device type identification (used to match it with a driver).
* @config: the configuration ops for this device.
Expand All @@ -88,6 +89,7 @@ bool virtqueue_is_broken(struct virtqueue *vq);
*/
struct virtio_device {
int index;
bool failed;
struct device dev;
struct virtio_device_id id;
const struct virtio_config_ops *config;
Expand All @@ -109,6 +111,10 @@ void unregister_virtio_device(struct virtio_device *dev);
void virtio_break_device(struct virtio_device *dev);

void virtio_config_changed(struct virtio_device *dev);
#ifdef CONFIG_PM_SLEEP
int virtio_device_freeze(struct virtio_device *dev);
int virtio_device_restore(struct virtio_device *dev);
#endif

/**
* virtio_driver - operations for a virtio I/O driver
Expand Down

0 comments on commit c6716ba

Please sign in to comment.