aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2011-11-02 18:00:56 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2011-11-02 18:00:56 -0400
commit80c2861672bbf000f6af838656959ee937e4ee4d (patch)
tree78b361fd7278d461b1e664272f3b27660b64c642 /drivers/char
parentd211858837ff8d8e31942ca7d27e6e08b3b46f5e (diff)
parent5087a50e66bd51b6e72c60bce4757a42b93f6b2c (diff)
Merge git://github.com/rustyrussell/linux
* git://github.com/rustyrussell/linux: virtio-blk: use ida to allocate disk index virtio: Add platform bus driver for memory mapped virtio device virtio: Dont add "config" to list for !per_vq_vector virtio: console: wait for first console port for early console output virtio: console: add port stats for bytes received, sent and discarded virtio: console: make discard_port_data() use get_inbuf() virtio: console: rename variable virtio: console: make get_inbuf() return port->inbuf if present virtio: console: Fix return type for get_inbuf() virtio: console: Use wait_event_freezable instead of _interruptible virtio: console: Ignore port name update request if name already set virtio: console: Fix indentation virtio: modify vring_init and vring_size to take account of the layout containing *_event_idx virtio.h: correct comment for struct virtio_driver virtio-net: Use virtio_config_val() for retrieving config virtio_config: Add virtio_config_val_len() virtio-console: Use virtio_config_val() for retrieving config
Diffstat (limited to 'drivers/char')
-rw-r--r--drivers/char/virtio_console.c120
1 files changed, 79 insertions, 41 deletions
diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c
index fb68b1295373..4ca181f1378b 100644
--- a/drivers/char/virtio_console.c
+++ b/drivers/char/virtio_console.c
@@ -19,8 +19,10 @@
19 */ 19 */
20#include <linux/cdev.h> 20#include <linux/cdev.h>
21#include <linux/debugfs.h> 21#include <linux/debugfs.h>
22#include <linux/completion.h>
22#include <linux/device.h> 23#include <linux/device.h>
23#include <linux/err.h> 24#include <linux/err.h>
25#include <linux/freezer.h>
24#include <linux/fs.h> 26#include <linux/fs.h>
25#include <linux/init.h> 27#include <linux/init.h>
26#include <linux/list.h> 28#include <linux/list.h>
@@ -73,6 +75,7 @@ struct ports_driver_data {
73static struct ports_driver_data pdrvdata; 75static struct ports_driver_data pdrvdata;
74 76
75DEFINE_SPINLOCK(pdrvdata_lock); 77DEFINE_SPINLOCK(pdrvdata_lock);
78DECLARE_COMPLETION(early_console_added);
76 79
77/* This struct holds information that's relevant only for console ports */ 80/* This struct holds information that's relevant only for console ports */
78struct console { 81struct console {
@@ -151,6 +154,10 @@ struct ports_device {
151 int chr_major; 154 int chr_major;
152}; 155};
153 156
157struct port_stats {
158 unsigned long bytes_sent, bytes_received, bytes_discarded;
159};
160
154/* This struct holds the per-port data */ 161/* This struct holds the per-port data */
155struct port { 162struct port {
156 /* Next port in the list, head is in the ports_device */ 163 /* Next port in the list, head is in the ports_device */
@@ -179,6 +186,13 @@ struct port {
179 struct dentry *debugfs_file; 186 struct dentry *debugfs_file;
180 187
181 /* 188 /*
189 * Keep count of the bytes sent, received and discarded for
190 * this port for accounting and debugging purposes. These
191 * counts are not reset across port open / close events.
192 */
193 struct port_stats stats;
194
195 /*
182 * The entries in this struct will be valid if this port is 196 * The entries in this struct will be valid if this port is
183 * hooked up to an hvc console 197 * hooked up to an hvc console
184 */ 198 */
@@ -347,17 +361,19 @@ fail:
347} 361}
348 362
349/* Callers should take appropriate locks */ 363/* Callers should take appropriate locks */
350static void *get_inbuf(struct port *port) 364static struct port_buffer *get_inbuf(struct port *port)
351{ 365{
352 struct port_buffer *buf; 366 struct port_buffer *buf;
353 struct virtqueue *vq;
354 unsigned int len; 367 unsigned int len;
355 368
356 vq = port->in_vq; 369 if (port->inbuf)
357 buf = virtqueue_get_buf(vq, &len); 370 return port->inbuf;
371
372 buf = virtqueue_get_buf(port->in_vq, &len);
358 if (buf) { 373 if (buf) {
359 buf->len = len; 374 buf->len = len;
360 buf->offset = 0; 375 buf->offset = 0;
376 port->stats.bytes_received += len;
361 } 377 }
362 return buf; 378 return buf;
363} 379}
@@ -384,32 +400,27 @@ static int add_inbuf(struct virtqueue *vq, struct port_buffer *buf)
384static void discard_port_data(struct port *port) 400static void discard_port_data(struct port *port)
385{ 401{
386 struct port_buffer *buf; 402 struct port_buffer *buf;
387 struct virtqueue *vq; 403 unsigned int err;
388 unsigned int len;
389 int ret;
390 404
391 if (!port->portdev) { 405 if (!port->portdev) {
392 /* Device has been unplugged. vqs are already gone. */ 406 /* Device has been unplugged. vqs are already gone. */
393 return; 407 return;
394 } 408 }
395 vq = port->in_vq; 409 buf = get_inbuf(port);
396 if (port->inbuf)
397 buf = port->inbuf;
398 else
399 buf = virtqueue_get_buf(vq, &len);
400 410
401 ret = 0; 411 err = 0;
402 while (buf) { 412 while (buf) {
403 if (add_inbuf(vq, buf) < 0) { 413 port->stats.bytes_discarded += buf->len - buf->offset;
404 ret++; 414 if (add_inbuf(port->in_vq, buf) < 0) {
415 err++;
405 free_buf(buf); 416 free_buf(buf);
406 } 417 }
407 buf = virtqueue_get_buf(vq, &len); 418 port->inbuf = NULL;
419 buf = get_inbuf(port);
408 } 420 }
409 port->inbuf = NULL; 421 if (err)
410 if (ret)
411 dev_warn(port->dev, "Errors adding %d buffers back to vq\n", 422 dev_warn(port->dev, "Errors adding %d buffers back to vq\n",
412 ret); 423 err);
413} 424}
414 425
415static bool port_has_data(struct port *port) 426static bool port_has_data(struct port *port)
@@ -417,18 +428,12 @@ static bool port_has_data(struct port *port)
417 unsigned long flags; 428 unsigned long flags;
418 bool ret; 429 bool ret;
419 430
431 ret = false;
420 spin_lock_irqsave(&port->inbuf_lock, flags); 432 spin_lock_irqsave(&port->inbuf_lock, flags);
421 if (port->inbuf) {
422 ret = true;
423 goto out;
424 }
425 port->inbuf = get_inbuf(port); 433 port->inbuf = get_inbuf(port);
426 if (port->inbuf) { 434 if (port->inbuf)
427 ret = true; 435 ret = true;
428 goto out; 436
429 }
430 ret = false;
431out:
432 spin_unlock_irqrestore(&port->inbuf_lock, flags); 437 spin_unlock_irqrestore(&port->inbuf_lock, flags);
433 return ret; 438 return ret;
434} 439}
@@ -529,6 +534,8 @@ static ssize_t send_buf(struct port *port, void *in_buf, size_t in_count,
529 cpu_relax(); 534 cpu_relax();
530done: 535done:
531 spin_unlock_irqrestore(&port->outvq_lock, flags); 536 spin_unlock_irqrestore(&port->outvq_lock, flags);
537
538 port->stats.bytes_sent += in_count;
532 /* 539 /*
533 * We're expected to return the amount of data we wrote -- all 540 * We're expected to return the amount of data we wrote -- all
534 * of it 541 * of it
@@ -633,8 +640,8 @@ static ssize_t port_fops_read(struct file *filp, char __user *ubuf,
633 if (filp->f_flags & O_NONBLOCK) 640 if (filp->f_flags & O_NONBLOCK)
634 return -EAGAIN; 641 return -EAGAIN;
635 642
636 ret = wait_event_interruptible(port->waitqueue, 643 ret = wait_event_freezable(port->waitqueue,
637 !will_read_block(port)); 644 !will_read_block(port));
638 if (ret < 0) 645 if (ret < 0)
639 return ret; 646 return ret;
640 } 647 }
@@ -677,8 +684,8 @@ static ssize_t port_fops_write(struct file *filp, const char __user *ubuf,
677 if (nonblock) 684 if (nonblock)
678 return -EAGAIN; 685 return -EAGAIN;
679 686
680 ret = wait_event_interruptible(port->waitqueue, 687 ret = wait_event_freezable(port->waitqueue,
681 !will_write_block(port)); 688 !will_write_block(port));
682 if (ret < 0) 689 if (ret < 0)
683 return ret; 690 return ret;
684 } 691 }
@@ -1059,6 +1066,14 @@ static ssize_t debugfs_read(struct file *filp, char __user *ubuf,
1059 out_offset += snprintf(buf + out_offset, out_count - out_offset, 1066 out_offset += snprintf(buf + out_offset, out_count - out_offset,
1060 "outvq_full: %d\n", port->outvq_full); 1067 "outvq_full: %d\n", port->outvq_full);
1061 out_offset += snprintf(buf + out_offset, out_count - out_offset, 1068 out_offset += snprintf(buf + out_offset, out_count - out_offset,
1069 "bytes_sent: %lu\n", port->stats.bytes_sent);
1070 out_offset += snprintf(buf + out_offset, out_count - out_offset,
1071 "bytes_received: %lu\n",
1072 port->stats.bytes_received);
1073 out_offset += snprintf(buf + out_offset, out_count - out_offset,
1074 "bytes_discarded: %lu\n",
1075 port->stats.bytes_discarded);
1076 out_offset += snprintf(buf + out_offset, out_count - out_offset,
1062 "is_console: %s\n", 1077 "is_console: %s\n",
1063 is_console_port(port) ? "yes" : "no"); 1078 is_console_port(port) ? "yes" : "no");
1064 out_offset += snprintf(buf + out_offset, out_count - out_offset, 1079 out_offset += snprintf(buf + out_offset, out_count - out_offset,
@@ -1143,6 +1158,7 @@ static int add_port(struct ports_device *portdev, u32 id)
1143 port->cons.ws.ws_row = port->cons.ws.ws_col = 0; 1158 port->cons.ws.ws_row = port->cons.ws.ws_col = 0;
1144 1159
1145 port->host_connected = port->guest_connected = false; 1160 port->host_connected = port->guest_connected = false;
1161 port->stats = (struct port_stats) { 0 };
1146 1162
1147 port->outvq_full = false; 1163 port->outvq_full = false;
1148 1164
@@ -1352,6 +1368,7 @@ static void handle_control_message(struct ports_device *portdev,
1352 break; 1368 break;
1353 1369
1354 init_port_console(port); 1370 init_port_console(port);
1371 complete(&early_console_added);
1355 /* 1372 /*
1356 * Could remove the port here in case init fails - but 1373 * Could remove the port here in case init fails - but
1357 * have to notify the host first. 1374 * have to notify the host first.
@@ -1394,6 +1411,13 @@ static void handle_control_message(struct ports_device *portdev,
1394 break; 1411 break;
1395 case VIRTIO_CONSOLE_PORT_NAME: 1412 case VIRTIO_CONSOLE_PORT_NAME:
1396 /* 1413 /*
1414 * If we woke up after hibernation, we can get this
1415 * again. Skip it in that case.
1416 */
1417 if (port->name)
1418 break;
1419
1420 /*
1397 * Skip the size of the header and the cpkt to get the size 1421 * Skip the size of the header and the cpkt to get the size
1398 * of the name that was sent 1422 * of the name that was sent
1399 */ 1423 */
@@ -1481,8 +1505,7 @@ static void in_intr(struct virtqueue *vq)
1481 return; 1505 return;
1482 1506
1483 spin_lock_irqsave(&port->inbuf_lock, flags); 1507 spin_lock_irqsave(&port->inbuf_lock, flags);
1484 if (!port->inbuf) 1508 port->inbuf = get_inbuf(port);
1485 port->inbuf = get_inbuf(port);
1486 1509
1487 /* 1510 /*
1488 * Don't queue up data when port is closed. This condition 1511 * Don't queue up data when port is closed. This condition
@@ -1563,7 +1586,7 @@ static int init_vqs(struct ports_device *portdev)
1563 portdev->out_vqs = kmalloc(nr_ports * sizeof(struct virtqueue *), 1586 portdev->out_vqs = kmalloc(nr_ports * sizeof(struct virtqueue *),
1564 GFP_KERNEL); 1587 GFP_KERNEL);
1565 if (!vqs || !io_callbacks || !io_names || !portdev->in_vqs || 1588 if (!vqs || !io_callbacks || !io_names || !portdev->in_vqs ||
1566 !portdev->out_vqs) { 1589 !portdev->out_vqs) {
1567 err = -ENOMEM; 1590 err = -ENOMEM;
1568 goto free; 1591 goto free;
1569 } 1592 }
@@ -1648,6 +1671,10 @@ static int __devinit virtcons_probe(struct virtio_device *vdev)
1648 struct ports_device *portdev; 1671 struct ports_device *portdev;
1649 int err; 1672 int err;
1650 bool multiport; 1673 bool multiport;
1674 bool early = early_put_chars != NULL;
1675
1676 /* Ensure to read early_put_chars now */
1677 barrier();
1651 1678
1652 portdev = kmalloc(sizeof(*portdev), GFP_KERNEL); 1679 portdev = kmalloc(sizeof(*portdev), GFP_KERNEL);
1653 if (!portdev) { 1680 if (!portdev) {
@@ -1675,13 +1702,11 @@ static int __devinit virtcons_probe(struct virtio_device *vdev)
1675 1702
1676 multiport = false; 1703 multiport = false;
1677 portdev->config.max_nr_ports = 1; 1704 portdev->config.max_nr_ports = 1;
1678 if (virtio_has_feature(vdev, VIRTIO_CONSOLE_F_MULTIPORT)) { 1705 if (virtio_config_val(vdev, VIRTIO_CONSOLE_F_MULTIPORT,
1706 offsetof(struct virtio_console_config,
1707 max_nr_ports),
1708 &portdev->config.max_nr_ports) == 0)
1679 multiport = true; 1709 multiport = true;
1680 vdev->config->get(vdev, offsetof(struct virtio_console_config,
1681 max_nr_ports),
1682 &portdev->config.max_nr_ports,
1683 sizeof(portdev->config.max_nr_ports));
1684 }
1685 1710
1686 err = init_vqs(portdev); 1711 err = init_vqs(portdev);
1687 if (err < 0) { 1712 if (err < 0) {
@@ -1719,6 +1744,19 @@ static int __devinit virtcons_probe(struct virtio_device *vdev)
1719 1744
1720 __send_control_msg(portdev, VIRTIO_CONSOLE_BAD_ID, 1745 __send_control_msg(portdev, VIRTIO_CONSOLE_BAD_ID,
1721 VIRTIO_CONSOLE_DEVICE_READY, 1); 1746 VIRTIO_CONSOLE_DEVICE_READY, 1);
1747
1748 /*
1749 * If there was an early virtio console, assume that there are no
1750 * other consoles. We need to wait until the hvc_alloc matches the
1751 * hvc_instantiate, otherwise tty_open will complain, resulting in
1752 * a "Warning: unable to open an initial console" boot failure.
1753 * Without multiport this is done in add_port above. With multiport
1754 * this might take some host<->guest communication - thus we have to
1755 * wait.
1756 */
1757 if (multiport && early)
1758 wait_for_completion(&early_console_added);
1759
1722 return 0; 1760 return 0;
1723 1761
1724free_vqs: 1762free_vqs: