aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/char/virtio_console.c65
-rw-r--r--include/linux/virtio_console.h1
2 files changed, 64 insertions, 2 deletions
diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c
index 7c53f58c87ba..9f20fda9c56f 100644
--- a/drivers/char/virtio_console.c
+++ b/drivers/char/virtio_console.c
@@ -783,6 +783,36 @@ static struct attribute_group port_attribute_group = {
783 .attrs = port_sysfs_entries, 783 .attrs = port_sysfs_entries,
784}; 784};
785 785
786/* Remove all port-specific data. */
787static 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/* Any private messages that the Host and Guest want to share */ 816/* Any private messages that the Host and Guest want to share */
787static void handle_control_message(struct ports_device *portdev, 817static void handle_control_message(struct ports_device *portdev,
788 struct port_buffer *buf) 818 struct port_buffer *buf)
@@ -854,6 +884,32 @@ static void handle_control_message(struct ports_device *portdev,
854 err); 884 err);
855 885
856 break; 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
@@ -1078,12 +1134,17 @@ static void config_work_handler(struct work_struct *work)
1078 /* 1134 /*
1079 * Port 0 got hot-added. Since we already did all the 1135 * Port 0 got hot-added. Since we already did all the
1080 * other initialisation for it, just tell the Host 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 struct port *port; 1141 struct port *port;
1084 1142
1085 port = find_port_by_id(portdev, 0); 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 return; 1148 return;
1088 } 1149 }
1089 if (virtconconf.nr_ports > portdev->config.max_nr_ports) { 1150 if (virtconconf.nr_ports > portdev->config.max_nr_ports) {
diff --git a/include/linux/virtio_console.h b/include/linux/virtio_console.h
index 1ebf007812a8..ae4f039515b4 100644
--- a/include/linux/virtio_console.h
+++ b/include/linux/virtio_console.h
@@ -41,6 +41,7 @@ struct virtio_console_control {
41#define VIRTIO_CONSOLE_RESIZE 2 41#define VIRTIO_CONSOLE_RESIZE 2
42#define VIRTIO_CONSOLE_PORT_OPEN 3 42#define VIRTIO_CONSOLE_PORT_OPEN 3
43#define VIRTIO_CONSOLE_PORT_NAME 4 43#define VIRTIO_CONSOLE_PORT_NAME 4
44#define VIRTIO_CONSOLE_PORT_REMOVE 5
44 45
45#ifdef __KERNEL__ 46#ifdef __KERNEL__
46int __init virtio_cons_early_init(int (*put_chars)(u32, const char *, int)); 47int __init virtio_cons_early_init(int (*put_chars)(u32, const char *, int));