|
@@ -1844,6 +1844,60 @@ static unsigned int features[] = {
|
|
|
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 = {
|
|
|
.feature_table = features,
|
|
|
.feature_table_size = ARRAY_SIZE(features),
|
|
@@ -1853,6 +1907,10 @@ static struct virtio_driver virtio_console = {
|
|
|
.probe = virtcons_probe,
|
|
|
.remove = virtcons_remove,
|
|
|
.config_changed = config_intr,
|
|
|
+#ifdef CONFIG_PM
|
|
|
+ .freeze = virtcons_freeze,
|
|
|
+ .restore = virtcons_restore,
|
|
|
+#endif
|
|
|
};
|
|
|
|
|
|
static int __init init(void)
|