diff options
| author | Amit Shah <amit.shah@redhat.com> | 2009-12-21 11:57:31 -0500 |
|---|---|---|
| committer | Rusty Russell <rusty@rustcorp.com.au> | 2010-02-23 22:53:00 -0500 |
| commit | 1f7aa42d166cd104b0700d61efe2064178a3f6da (patch) | |
| tree | 2c6f749da860955f754e8f7e49cbe6bd4ec6216a | |
| parent | 7f5d810dac70214d00b2440787535b6c7a73b6b7 (diff) | |
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>
| -rw-r--r-- | drivers/char/virtio_console.c | 65 | ||||
| -rw-r--r-- | include/linux/virtio_console.h | 1 |
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. */ | ||
| 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 | /* Any private messages that the Host and Guest want to share */ | 816 | /* Any private messages that the Host and Guest want to share */ |
| 787 | static void handle_control_message(struct ports_device *portdev, | 817 | static 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__ |
| 46 | int __init virtio_cons_early_init(int (*put_chars)(u32, const char *, int)); | 47 | int __init virtio_cons_early_init(int (*put_chars)(u32, const char *, int)); |
