virtio: console: Add freeze and restore handlers to support S4
Remove all vqs and associated buffers in the freeze callback which prepares us to go into hibernation state. On restore, re-create all the vqs and populate the input vqs with buffers to get to the pre-hibernate state. Note: Any outstanding unconsumed buffers are discarded; which means there's a possibility of data loss in case the host or the guest didn't consume any data already present in the vqs. This can be addressed in a later patch series, perhaps in virtio common code. Signed-off-by: Amit Shah <amit.shah@redhat.com> Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
parent
a0e2dbfc22
commit
2b8f41d846
|
@ -1844,6 +1844,60 @@ static unsigned int features[] = {
|
||||||
VIRTIO_CONSOLE_F_MULTIPORT,
|
VIRTIO_CONSOLE_F_MULTIPORT,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#ifdef CONFIG_PM
|
||||||
|
static int virtcons_freeze(struct virtio_device *vdev)
|
||||||
|
{
|
||||||
|
struct ports_device *portdev;
|
||||||
|
struct port *port;
|
||||||
|
|
||||||
|
portdev = vdev->priv;
|
||||||
|
|
||||||
|
vdev->config->reset(vdev);
|
||||||
|
|
||||||
|
cancel_work_sync(&portdev->control_work);
|
||||||
|
remove_controlq_data(portdev);
|
||||||
|
|
||||||
|
list_for_each_entry(port, &portdev->ports, list) {
|
||||||
|
/*
|
||||||
|
* We'll ask the host later if the new invocation has
|
||||||
|
* the port opened or closed.
|
||||||
|
*/
|
||||||
|
port->host_connected = false;
|
||||||
|
remove_port_data(port);
|
||||||
|
}
|
||||||
|
remove_vqs(portdev);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int virtcons_restore(struct virtio_device *vdev)
|
||||||
|
{
|
||||||
|
struct ports_device *portdev;
|
||||||
|
struct port *port;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
portdev = vdev->priv;
|
||||||
|
|
||||||
|
ret = init_vqs(portdev);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
if (use_multiport(portdev))
|
||||||
|
fill_queue(portdev->c_ivq, &portdev->cvq_lock);
|
||||||
|
|
||||||
|
list_for_each_entry(port, &portdev->ports, list) {
|
||||||
|
port->in_vq = portdev->in_vqs[port->id];
|
||||||
|
port->out_vq = portdev->out_vqs[port->id];
|
||||||
|
|
||||||
|
fill_queue(port->in_vq, &port->inbuf_lock);
|
||||||
|
|
||||||
|
/* Get port open/close status on the host */
|
||||||
|
send_control_msg(port, VIRTIO_CONSOLE_PORT_READY, 1);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static struct virtio_driver virtio_console = {
|
static struct virtio_driver virtio_console = {
|
||||||
.feature_table = features,
|
.feature_table = features,
|
||||||
.feature_table_size = ARRAY_SIZE(features),
|
.feature_table_size = ARRAY_SIZE(features),
|
||||||
|
@ -1853,6 +1907,10 @@ static struct virtio_driver virtio_console = {
|
||||||
.probe = virtcons_probe,
|
.probe = virtcons_probe,
|
||||||
.remove = virtcons_remove,
|
.remove = virtcons_remove,
|
||||||
.config_changed = config_intr,
|
.config_changed = config_intr,
|
||||||
|
#ifdef CONFIG_PM
|
||||||
|
.freeze = virtcons_freeze,
|
||||||
|
.restore = virtcons_restore,
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
static int __init init(void)
|
static int __init init(void)
|
||||||
|
|
Loading…
Reference in New Issue