aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char/virtio_console.c
diff options
context:
space:
mode:
authorAmit Shah <amit.shah@redhat.com>2010-05-20 00:15:48 -0400
committerRusty Russell <rusty@rustcorp.com.au>2010-05-19 08:45:49 -0400
commitf909f850d666e3dbac1ee7c9d5d83416bd02f84e (patch)
treea434032b27519ae0a92ab3a2d211fb240681f50c /drivers/char/virtio_console.c
parentc446f8fcc9fba3369bffb894b31756cf7a09f783 (diff)
virtio: console: Use a control message to add ports
Instead of the host and guest independently enumerating ports, switch to a control message to add ports where the host supplies the port number so there's no ambiguity or a possibility of a race between the host and the guest port numbers. We now no longer need the 'nr_ports' config value. Since no kernel has been released with the MULTIPORT changes yet, we have a chance to fiddle with the config space without adding compatibility features. This is beneficial for management software, which would now be able to instantiate ports at known locations and avoid problems that arise with implicit numbering in the host and the guest. This removes the 'guessing game' part of it, and management software can now actually indicate which id to spawn a particular port on. 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.c77
1 files changed, 33 insertions, 44 deletions
diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c
index 237eee26fbc3..7671914be172 100644
--- a/drivers/char/virtio_console.c
+++ b/drivers/char/virtio_console.c
@@ -1048,7 +1048,7 @@ static void handle_control_message(struct ports_device *portdev,
1048 cpkt = (struct virtio_console_control *)(buf->buf + buf->offset); 1048 cpkt = (struct virtio_console_control *)(buf->buf + buf->offset);
1049 1049
1050 port = find_port_by_id(portdev, cpkt->id); 1050 port = find_port_by_id(portdev, cpkt->id);
1051 if (!port) { 1051 if (!port && cpkt->event != VIRTIO_CONSOLE_PORT_ADD) {
1052 /* No valid header at start of buffer. Drop it. */ 1052 /* No valid header at start of buffer. Drop it. */
1053 dev_dbg(&portdev->vdev->dev, 1053 dev_dbg(&portdev->vdev->dev,
1054 "Invalid index %u in control packet\n", cpkt->id); 1054 "Invalid index %u in control packet\n", cpkt->id);
@@ -1056,6 +1056,30 @@ static void handle_control_message(struct ports_device *portdev,
1056 } 1056 }
1057 1057
1058 switch (cpkt->event) { 1058 switch (cpkt->event) {
1059 case VIRTIO_CONSOLE_PORT_ADD:
1060 if (port) {
1061 /*
1062 * This can happen for port 0: we have to
1063 * create a console port during probe() as was
1064 * the behaviour before the MULTIPORT feature.
1065 * On a newer host, when the host tells us
1066 * that a port 0 is available, we should just
1067 * say we have the port all set up.
1068 */
1069 send_control_msg(port, VIRTIO_CONSOLE_PORT_READY, 1);
1070 break;
1071 }
1072 if (cpkt->id >= portdev->config.max_nr_ports) {
1073 dev_warn(&portdev->vdev->dev,
1074 "Request for adding port with out-of-bound id %u, max. supported id: %u\n",
1075 cpkt->id, portdev->config.max_nr_ports - 1);
1076 break;
1077 }
1078 add_port(portdev, cpkt->id);
1079 break;
1080 case VIRTIO_CONSOLE_PORT_REMOVE:
1081 remove_port(port);
1082 break;
1059 case VIRTIO_CONSOLE_CONSOLE_PORT: 1083 case VIRTIO_CONSOLE_CONSOLE_PORT:
1060 if (!cpkt->value) 1084 if (!cpkt->value)
1061 break; 1085 break;
@@ -1114,32 +1138,6 @@ static void handle_control_message(struct ports_device *portdev,
1114 kobject_uevent(&port->dev->kobj, KOBJ_CHANGE); 1138 kobject_uevent(&port->dev->kobj, KOBJ_CHANGE);
1115 } 1139 }
1116 break; 1140 break;
1117 case VIRTIO_CONSOLE_PORT_REMOVE:
1118 /*
1119 * Hot unplug the port. We don't decrement nr_ports
1120 * since we don't want to deal with extra complexities
1121 * of using the lowest-available port id: We can just
1122 * pick up the nr_ports number as the id and not have
1123 * userspace send it to us. This helps us in two
1124 * ways:
1125 *
1126 * - We don't need to have a 'port_id' field in the
1127 * config space when a port is hot-added. This is a
1128 * good thing as we might queue up multiple hotplug
1129 * requests issued in our workqueue.
1130 *
1131 * - Another way to deal with this would have been to
1132 * use a bitmap of the active ports and select the
1133 * lowest non-active port from that map. That
1134 * bloats the already tight config space and we
1135 * would end up artificially limiting the
1136 * max. number of ports to sizeof(bitmap). Right
1137 * now we can support 2^32 ports (as the port id is
1138 * stored in a u32 type).
1139 *
1140 */
1141 remove_port(port);
1142 break;
1143 } 1141 }
1144} 1142}
1145 1143
@@ -1347,7 +1345,6 @@ static const struct file_operations portdev_fops = {
1347static int __devinit virtcons_probe(struct virtio_device *vdev) 1345static int __devinit virtcons_probe(struct virtio_device *vdev)
1348{ 1346{
1349 struct ports_device *portdev; 1347 struct ports_device *portdev;
1350 u32 i;
1351 int err; 1348 int err;
1352 bool multiport; 1349 bool multiport;
1353 1350
@@ -1376,29 +1373,15 @@ static int __devinit virtcons_probe(struct virtio_device *vdev)
1376 } 1373 }
1377 1374
1378 multiport = false; 1375 multiport = false;
1379 portdev->config.nr_ports = 1;
1380 portdev->config.max_nr_ports = 1; 1376 portdev->config.max_nr_ports = 1;
1381 if (virtio_has_feature(vdev, VIRTIO_CONSOLE_F_MULTIPORT)) { 1377 if (virtio_has_feature(vdev, VIRTIO_CONSOLE_F_MULTIPORT)) {
1382 multiport = true; 1378 multiport = true;
1383 vdev->features[0] |= 1 << VIRTIO_CONSOLE_F_MULTIPORT; 1379 vdev->features[0] |= 1 << VIRTIO_CONSOLE_F_MULTIPORT;
1384 1380
1385 vdev->config->get(vdev, offsetof(struct virtio_console_config, 1381 vdev->config->get(vdev, offsetof(struct virtio_console_config,
1386 nr_ports),
1387 &portdev->config.nr_ports,
1388 sizeof(portdev->config.nr_ports));
1389 vdev->config->get(vdev, offsetof(struct virtio_console_config,
1390 max_nr_ports), 1382 max_nr_ports),
1391 &portdev->config.max_nr_ports, 1383 &portdev->config.max_nr_ports,
1392 sizeof(portdev->config.max_nr_ports)); 1384 sizeof(portdev->config.max_nr_ports));
1393 if (portdev->config.nr_ports > portdev->config.max_nr_ports) {
1394 dev_warn(&vdev->dev,
1395 "More ports (%u) specified than allowed (%u). Will init %u ports.",
1396 portdev->config.nr_ports,
1397 portdev->config.max_nr_ports,
1398 portdev->config.max_nr_ports);
1399
1400 portdev->config.nr_ports = portdev->config.max_nr_ports;
1401 }
1402 } 1385 }
1403 1386
1404 /* Let the Host know we support multiple ports.*/ 1387 /* Let the Host know we support multiple ports.*/
@@ -1428,11 +1411,17 @@ static int __devinit virtcons_probe(struct virtio_device *vdev)
1428 } 1411 }
1429 } 1412 }
1430 1413
1431 for (i = 0; i < portdev->config.nr_ports; i++) 1414 /*
1432 add_port(portdev, i); 1415 * For backward compatibility: if we're running on an older
1416 * host, we always want to create a console port.
1417 */
1418 add_port(portdev, 0);
1433 1419
1434 /* Start using the new console output. */ 1420 /* Start using the new console output. */
1435 early_put_chars = NULL; 1421 early_put_chars = NULL;
1422
1423 __send_control_msg(portdev, VIRTIO_CONSOLE_BAD_ID,
1424 VIRTIO_CONSOLE_DEVICE_READY, 1);
1436 return 0; 1425 return 0;
1437 1426
1438free_vqs: 1427free_vqs: