aboutsummaryrefslogtreecommitdiff
path: root/drivers/char
diff options
context:
space:
mode:
authorAmit Shah <amit.shah@redhat.com>2010-02-12 10:32:18 +0530
committerRusty Russell <rusty@rustcorp.com.au>2010-02-24 14:23:06 +1030
commitd6933561924d8022f5d986ce7c511a2646eeadce (patch)
tree8e0a0c86a079400df7919f80194289258b7f5144 /drivers/char
parent22a29eacd2a17f22c8260a8106a4e36bae7fb6ea (diff)
virtio: console: Fill ports' entire in_vq with buffers
Instead of allocating just one buffer for a port's in_vq, fill the entire in_vq with buffers so the host need not stall while an application consumes the data and makes the buffer available again for the host. Signed-off-by: Amit Shah <amit.shah@redhat.com> Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Diffstat (limited to 'drivers/char')
-rw-r--r--drivers/char/virtio_console.c53
1 files changed, 32 insertions, 21 deletions
diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c
index c40703759e2..213373b5f17 100644
--- a/drivers/char/virtio_console.c
+++ b/drivers/char/virtio_console.c
@@ -330,6 +330,7 @@ static void discard_port_data(struct port *port)
struct port_buffer *buf;
struct virtqueue *vq;
unsigned int len;
+ int ret;
vq = port->in_vq;
if (port->inbuf)
@@ -337,16 +338,18 @@ static void discard_port_data(struct port *port)
else
buf = vq->vq_ops->get_buf(vq, &len);
- if (!buf)
- return;
-
- if (add_inbuf(vq, buf) < 0) {
- buf->len = buf->offset = 0;
- dev_warn(port->dev, "Error adding buffer back to vq\n");
- return;
+ ret = 0;
+ while (buf) {
+ if (add_inbuf(vq, buf) < 0) {
+ ret++;
+ free_buf(buf);
+ }
+ buf = vq->vq_ops->get_buf(vq, &len);
}
-
port->inbuf = NULL;
+ if (ret)
+ dev_warn(port->dev, "Errors adding %d buffers back to vq\n",
+ ret);
}
static bool port_has_data(struct port *port)
@@ -354,12 +357,19 @@ static bool port_has_data(struct port *port)
unsigned long flags;
bool ret;
- ret = false;
spin_lock_irqsave(&port->inbuf_lock, flags);
- if (port->inbuf)
+ if (port->inbuf) {
ret = true;
+ goto out;
+ }
+ port->inbuf = get_inbuf(port);
+ if (port->inbuf) {
+ ret = true;
+ goto out;
+ }
+ ret = false;
+out:
spin_unlock_irqrestore(&port->inbuf_lock, flags);
-
return ret;
}
@@ -1011,7 +1021,8 @@ static void in_intr(struct virtqueue *vq)
return;
spin_lock_irqsave(&port->inbuf_lock, flags);
- port->inbuf = get_inbuf(port);
+ if (!port->inbuf)
+ port->inbuf = get_inbuf(port);
/*
* Don't queue up data when port is closed. This condition
@@ -1087,7 +1098,7 @@ static int add_port(struct ports_device *portdev, u32 id)
{
char debugfs_name[16];
struct port *port;
- struct port_buffer *inbuf;
+ struct port_buffer *buf;
dev_t devt;
int err;
@@ -1132,22 +1143,21 @@ static int add_port(struct ports_device *portdev, u32 id)
spin_lock_init(&port->inbuf_lock);
init_waitqueue_head(&port->waitqueue);
- inbuf = alloc_buf(PAGE_SIZE);
- if (!inbuf) {
+ /* Fill the in_vq with buffers so the host can send us data. */
+ err = fill_queue(port->in_vq, &port->inbuf_lock);
+ if (!err) {
+ dev_err(port->dev, "Error allocating inbufs\n");
err = -ENOMEM;
goto free_device;
}
- /* Register the input buffer the first time. */
- add_inbuf(port->in_vq, inbuf);
-
/*
* If we're not using multiport support, this has to be a console port
*/
if (!use_multiport(port->portdev)) {
err = init_port_console(port);
if (err)
- goto free_inbuf;
+ goto free_inbufs;
}
spin_lock_irq(&portdev->ports_lock);
@@ -1175,8 +1185,9 @@ static int add_port(struct ports_device *portdev, u32 id)
}
return 0;
-free_inbuf:
- free_buf(inbuf);
+free_inbufs:
+ while ((buf = port->in_vq->vq_ops->detach_unused_buf(port->in_vq)))
+ free_buf(buf);
free_device:
device_destroy(pdrvdata.class, port->dev->devt);
free_cdev: