diff options
Diffstat (limited to 'drivers/char/virtio_console.c')
-rw-r--r-- | drivers/char/virtio_console.c | 77 |
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 = { | |||
1347 | static int __devinit virtcons_probe(struct virtio_device *vdev) | 1345 | static 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 | ||
1438 | free_vqs: | 1427 | free_vqs: |