aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char/virtio_console.c
diff options
context:
space:
mode:
authorAmit Shah <amit.shah@redhat.com>2009-12-21 11:52:08 -0500
committerRusty Russell <rusty@rustcorp.com.au>2010-02-23 22:52:58 -0500
commit7f5d810dac70214d00b2440787535b6c7a73b6b7 (patch)
treecef6d7fcdd30978a552200586d4a5fc4afb82843 /drivers/char/virtio_console.c
parent88f251ac58b2460ed16ff619a020ad3ef365e607 (diff)
virtio: console: Handle port hot-plug
If the 'nr_ports' variable in the config space is updated to a higher value, that means new ports have been hotplugged. Introduce a new workqueue to handle such updates and create new ports. Signed-off-by: Amit Shah <amit.shah@redhat.com> Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Diffstat (limited to 'drivers/char/virtio_console.c')
-rw-r--r--drivers/char/virtio_console.c78
1 files changed, 72 insertions, 6 deletions
diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c
index 5506ff8bdf03..7c53f58c87ba 100644
--- a/drivers/char/virtio_console.c
+++ b/drivers/char/virtio_console.c
@@ -105,6 +105,7 @@ struct ports_device {
105 * notification 105 * notification
106 */ 106 */
107 struct work_struct control_work; 107 struct work_struct control_work;
108 struct work_struct config_work;
108 109
109 struct list_head ports; 110 struct list_head ports;
110 111
@@ -675,11 +676,6 @@ static void resize_console(struct port *port)
675 } 676 }
676} 677}
677 678
678static void virtcons_apply_config(struct virtio_device *vdev)
679{
680 resize_console(find_port_by_vtermno(0));
681}
682
683/* We set the configuration at this point, since we now have a tty */ 679/* We set the configuration at this point, since we now have a tty */
684static int notifier_add_vio(struct hvc_struct *hp, int data) 680static int notifier_add_vio(struct hvc_struct *hp, int data)
685{ 681{
@@ -928,6 +924,24 @@ static void control_intr(struct virtqueue *vq)
928 schedule_work(&portdev->control_work); 924 schedule_work(&portdev->control_work);
929} 925}
930 926
927static void config_intr(struct virtio_device *vdev)
928{
929 struct ports_device *portdev;
930
931 portdev = vdev->priv;
932 if (use_multiport(portdev)) {
933 /* Handle port hot-add */
934 schedule_work(&portdev->config_work);
935 }
936 /*
937 * We'll use this way of resizing only for legacy support.
938 * For newer userspace (VIRTIO_CONSOLE_F_MULTPORT+), use
939 * control messages to indicate console size changes so that
940 * it can be done per-port
941 */
942 resize_console(find_port_by_id(portdev, 0));
943}
944
931static void fill_queue(struct virtqueue *vq, spinlock_t *lock) 945static void fill_queue(struct virtqueue *vq, spinlock_t *lock)
932{ 946{
933 struct port_buffer *buf; 947 struct port_buffer *buf;
@@ -1040,6 +1054,57 @@ fail:
1040 return err; 1054 return err;
1041} 1055}
1042 1056
1057/*
1058 * The workhandler for config-space updates.
1059 *
1060 * This is called when ports are hot-added.
1061 */
1062static void config_work_handler(struct work_struct *work)
1063{
1064 struct virtio_console_config virtconconf;
1065 struct ports_device *portdev;
1066 struct virtio_device *vdev;
1067 int err;
1068
1069 portdev = container_of(work, struct ports_device, config_work);
1070
1071 vdev = portdev->vdev;
1072 vdev->config->get(vdev,
1073 offsetof(struct virtio_console_config, nr_ports),
1074 &virtconconf.nr_ports,
1075 sizeof(virtconconf.nr_ports));
1076
1077 if (portdev->config.nr_ports == virtconconf.nr_ports) {
1078 /*
1079 * Port 0 got hot-added. Since we already did all the
1080 * other initialisation for it, just tell the Host
1081 * that the port is ready.
1082 */
1083 struct port *port;
1084
1085 port = find_port_by_id(portdev, 0);
1086 send_control_msg(port, VIRTIO_CONSOLE_PORT_READY, 1);
1087 return;
1088 }
1089 if (virtconconf.nr_ports > portdev->config.max_nr_ports) {
1090 dev_warn(&vdev->dev,
1091 "More ports specified (%u) than allowed (%u)",
1092 portdev->config.nr_ports + 1,
1093 portdev->config.max_nr_ports);
1094 return;
1095 }
1096 if (virtconconf.nr_ports < portdev->config.nr_ports)
1097 return;
1098
1099 /* Hot-add ports */
1100 while (virtconconf.nr_ports - portdev->config.nr_ports) {
1101 err = add_port(portdev, portdev->config.nr_ports);
1102 if (err)
1103 break;
1104 portdev->config.nr_ports++;
1105 }
1106}
1107
1043static int init_vqs(struct ports_device *portdev) 1108static int init_vqs(struct ports_device *portdev)
1044{ 1109{
1045 vq_callback_t **io_callbacks; 1110 vq_callback_t **io_callbacks;
@@ -1230,6 +1295,7 @@ static int __devinit virtcons_probe(struct virtio_device *vdev)
1230 if (multiport) { 1295 if (multiport) {
1231 spin_lock_init(&portdev->cvq_lock); 1296 spin_lock_init(&portdev->cvq_lock);
1232 INIT_WORK(&portdev->control_work, &control_work_handler); 1297 INIT_WORK(&portdev->control_work, &control_work_handler);
1298 INIT_WORK(&portdev->config_work, &config_work_handler);
1233 1299
1234 fill_queue(portdev->c_ivq, &portdev->cvq_lock); 1300 fill_queue(portdev->c_ivq, &portdev->cvq_lock);
1235 } 1301 }
@@ -1266,7 +1332,7 @@ static struct virtio_driver virtio_console = {
1266 .driver.owner = THIS_MODULE, 1332 .driver.owner = THIS_MODULE,
1267 .id_table = id_table, 1333 .id_table = id_table,
1268 .probe = virtcons_probe, 1334 .probe = virtcons_probe,
1269 .config_changed = virtcons_apply_config, 1335 .config_changed = config_intr,
1270}; 1336};
1271 1337
1272static int __init init(void) 1338static int __init init(void)