Commit 1f7aa42d166cd104b0700d61efe2064178a3f6da

Authored by Amit Shah
Committed by Rusty Russell
1 parent 7f5d810dac

virtio: console: Add ability to hot-unplug ports

Remove port data; deregister from the hvc core if it's a console port.

Signed-off-by: Amit Shah <amit.shah@redhat.com>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>

Showing 2 changed files with 64 additions and 2 deletions Side-by-side Diff

drivers/char/virtio_console.c
... ... @@ -783,6 +783,36 @@
783 783 .attrs = port_sysfs_entries,
784 784 };
785 785  
  786 +/* Remove all port-specific data. */
  787 +static int remove_port(struct port *port)
  788 +{
  789 + spin_lock_irq(&port->portdev->ports_lock);
  790 + list_del(&port->list);
  791 + spin_unlock_irq(&port->portdev->ports_lock);
  792 +
  793 + if (is_console_port(port)) {
  794 + spin_lock_irq(&pdrvdata_lock);
  795 + list_del(&port->cons.list);
  796 + spin_unlock_irq(&pdrvdata_lock);
  797 + hvc_remove(port->cons.hvc);
  798 + }
  799 + if (port->guest_connected)
  800 + send_control_msg(port, VIRTIO_CONSOLE_PORT_OPEN, 0);
  801 +
  802 + while (port->in_vq->vq_ops->detach_unused_buf(port->in_vq))
  803 + ;
  804 +
  805 + sysfs_remove_group(&port->dev->kobj, &port_attribute_group);
  806 + device_destroy(pdrvdata.class, port->dev->devt);
  807 + cdev_del(&port->cdev);
  808 +
  809 + discard_port_data(port);
  810 + kfree(port->name);
  811 +
  812 + kfree(port);
  813 + return 0;
  814 +}
  815 +
786 816 /* Any private messages that the Host and Guest want to share */
787 817 static void handle_control_message(struct ports_device *portdev,
788 818 struct port_buffer *buf)
... ... @@ -854,6 +884,32 @@
854 884 err);
855 885  
856 886 break;
  887 + case VIRTIO_CONSOLE_PORT_REMOVE:
  888 + /*
  889 + * Hot unplug the port. We don't decrement nr_ports
  890 + * since we don't want to deal with extra complexities
  891 + * of using the lowest-available port id: We can just
  892 + * pick up the nr_ports number as the id and not have
  893 + * userspace send it to us. This helps us in two
  894 + * ways:
  895 + *
  896 + * - We don't need to have a 'port_id' field in the
  897 + * config space when a port is hot-added. This is a
  898 + * good thing as we might queue up multiple hotplug
  899 + * requests issued in our workqueue.
  900 + *
  901 + * - Another way to deal with this would have been to
  902 + * use a bitmap of the active ports and select the
  903 + * lowest non-active port from that map. That
  904 + * bloats the already tight config space and we
  905 + * would end up artificially limiting the
  906 + * max. number of ports to sizeof(bitmap). Right
  907 + * now we can support 2^32 ports (as the port id is
  908 + * stored in a u32 type).
  909 + *
  910 + */
  911 + remove_port(port);
  912 + break;
857 913 }
858 914 }
859 915  
860 916  
... ... @@ -1078,12 +1134,17 @@
1078 1134 /*
1079 1135 * Port 0 got hot-added. Since we already did all the
1080 1136 * other initialisation for it, just tell the Host
1081   - * that the port is ready.
  1137 + * that the port is ready if we find the port. In
  1138 + * case the port was hot-removed earlier, we call
  1139 + * add_port to add the port.
1082 1140 */
1083 1141 struct port *port;
1084 1142  
1085 1143 port = find_port_by_id(portdev, 0);
1086   - send_control_msg(port, VIRTIO_CONSOLE_PORT_READY, 1);
  1144 + if (!port)
  1145 + add_port(portdev, 0);
  1146 + else
  1147 + send_control_msg(port, VIRTIO_CONSOLE_PORT_READY, 1);
1087 1148 return;
1088 1149 }
1089 1150 if (virtconconf.nr_ports > portdev->config.max_nr_ports) {
include/linux/virtio_console.h
... ... @@ -41,6 +41,7 @@
41 41 #define VIRTIO_CONSOLE_RESIZE 2
42 42 #define VIRTIO_CONSOLE_PORT_OPEN 3
43 43 #define VIRTIO_CONSOLE_PORT_NAME 4
  44 +#define VIRTIO_CONSOLE_PORT_REMOVE 5
44 45  
45 46 #ifdef __KERNEL__
46 47 int __init virtio_cons_early_init(int (*put_chars)(u32, const char *, int));