diff options
author | Amit Shah <amit.shah@redhat.com> | 2011-12-22 06:28:28 -0500 |
---|---|---|
committer | Rusty Russell <rusty@rustcorp.com.au> | 2012-01-12 00:14:45 -0500 |
commit | 2b8f41d846990c3c1c8addbaed2cf53c3ef91d25 (patch) | |
tree | a3dbf456eb359650db0487d66d3594f1fa7be6c0 | |
parent | a0e2dbfc223028b72a1c193f94fcd3f67253ba4a (diff) |
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>
-rw-r--r-- | drivers/char/virtio_console.c | 58 |
1 files changed, 58 insertions, 0 deletions
diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index 9681ffd79904..614b84d38d7a 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c | |||
@@ -1844,6 +1844,60 @@ static unsigned int features[] = { | |||
1844 | VIRTIO_CONSOLE_F_MULTIPORT, | 1844 | VIRTIO_CONSOLE_F_MULTIPORT, |
1845 | }; | 1845 | }; |
1846 | 1846 | ||
1847 | #ifdef CONFIG_PM | ||
1848 | static int virtcons_freeze(struct virtio_device *vdev) | ||
1849 | { | ||
1850 | struct ports_device *portdev; | ||
1851 | struct port *port; | ||
1852 | |||
1853 | portdev = vdev->priv; | ||
1854 | |||
1855 | vdev->config->reset(vdev); | ||
1856 | |||
1857 | cancel_work_sync(&portdev->control_work); | ||
1858 | remove_controlq_data(portdev); | ||
1859 | |||
1860 | list_for_each_entry(port, &portdev->ports, list) { | ||
1861 | /* | ||
1862 | * We'll ask the host later if the new invocation has | ||
1863 | * the port opened or closed. | ||
1864 | */ | ||
1865 | port->host_connected = false; | ||
1866 | remove_port_data(port); | ||
1867 | } | ||
1868 | remove_vqs(portdev); | ||
1869 | |||
1870 | return 0; | ||
1871 | } | ||
1872 | |||
1873 | static int virtcons_restore(struct virtio_device *vdev) | ||
1874 | { | ||
1875 | struct ports_device *portdev; | ||
1876 | struct port *port; | ||
1877 | int ret; | ||
1878 | |||
1879 | portdev = vdev->priv; | ||
1880 | |||
1881 | ret = init_vqs(portdev); | ||
1882 | if (ret) | ||
1883 | return ret; | ||
1884 | |||
1885 | if (use_multiport(portdev)) | ||
1886 | fill_queue(portdev->c_ivq, &portdev->cvq_lock); | ||
1887 | |||
1888 | list_for_each_entry(port, &portdev->ports, list) { | ||
1889 | port->in_vq = portdev->in_vqs[port->id]; | ||
1890 | port->out_vq = portdev->out_vqs[port->id]; | ||
1891 | |||
1892 | fill_queue(port->in_vq, &port->inbuf_lock); | ||
1893 | |||
1894 | /* Get port open/close status on the host */ | ||
1895 | send_control_msg(port, VIRTIO_CONSOLE_PORT_READY, 1); | ||
1896 | } | ||
1897 | return 0; | ||
1898 | } | ||
1899 | #endif | ||
1900 | |||
1847 | static struct virtio_driver virtio_console = { | 1901 | static struct virtio_driver virtio_console = { |
1848 | .feature_table = features, | 1902 | .feature_table = features, |
1849 | .feature_table_size = ARRAY_SIZE(features), | 1903 | .feature_table_size = ARRAY_SIZE(features), |
@@ -1853,6 +1907,10 @@ static struct virtio_driver virtio_console = { | |||
1853 | .probe = virtcons_probe, | 1907 | .probe = virtcons_probe, |
1854 | .remove = virtcons_remove, | 1908 | .remove = virtcons_remove, |
1855 | .config_changed = config_intr, | 1909 | .config_changed = config_intr, |
1910 | #ifdef CONFIG_PM | ||
1911 | .freeze = virtcons_freeze, | ||
1912 | .restore = virtcons_restore, | ||
1913 | #endif | ||
1856 | }; | 1914 | }; |
1857 | 1915 | ||
1858 | static int __init init(void) | 1916 | static int __init init(void) |