Commit d6933561 authored by Amit Shah's avatar Amit Shah Committed by Rusty Russell

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: default avatarAmit Shah <amit.shah@redhat.com>
Signed-off-by: default avatarRusty Russell <rusty@rustcorp.com.au>
parent 22a29eac
...@@ -330,6 +330,7 @@ static void discard_port_data(struct port *port) ...@@ -330,6 +330,7 @@ static void discard_port_data(struct port *port)
struct port_buffer *buf; struct port_buffer *buf;
struct virtqueue *vq; struct virtqueue *vq;
unsigned int len; unsigned int len;
int ret;
vq = port->in_vq; vq = port->in_vq;
if (port->inbuf) if (port->inbuf)
...@@ -337,16 +338,18 @@ static void discard_port_data(struct port *port) ...@@ -337,16 +338,18 @@ static void discard_port_data(struct port *port)
else else
buf = vq->vq_ops->get_buf(vq, &len); buf = vq->vq_ops->get_buf(vq, &len);
if (!buf) ret = 0;
return; while (buf) {
if (add_inbuf(vq, buf) < 0) { if (add_inbuf(vq, buf) < 0) {
buf->len = buf->offset = 0; ret++;
dev_warn(port->dev, "Error adding buffer back to vq\n"); free_buf(buf);
return; }
buf = vq->vq_ops->get_buf(vq, &len);
} }
port->inbuf = NULL; 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) static bool port_has_data(struct port *port)
...@@ -354,12 +357,19 @@ static bool port_has_data(struct port *port) ...@@ -354,12 +357,19 @@ static bool port_has_data(struct port *port)
unsigned long flags; unsigned long flags;
bool ret; bool ret;
ret = false;
spin_lock_irqsave(&port->inbuf_lock, flags); spin_lock_irqsave(&port->inbuf_lock, flags);
if (port->inbuf) if (port->inbuf) {
ret = true; 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); spin_unlock_irqrestore(&port->inbuf_lock, flags);
return ret; return ret;
} }
...@@ -1011,6 +1021,7 @@ static void in_intr(struct virtqueue *vq) ...@@ -1011,6 +1021,7 @@ static void in_intr(struct virtqueue *vq)
return; return;
spin_lock_irqsave(&port->inbuf_lock, flags); spin_lock_irqsave(&port->inbuf_lock, flags);
if (!port->inbuf)
port->inbuf = get_inbuf(port); port->inbuf = get_inbuf(port);
/* /*
...@@ -1087,7 +1098,7 @@ static int add_port(struct ports_device *portdev, u32 id) ...@@ -1087,7 +1098,7 @@ static int add_port(struct ports_device *portdev, u32 id)
{ {
char debugfs_name[16]; char debugfs_name[16];
struct port *port; struct port *port;
struct port_buffer *inbuf; struct port_buffer *buf;
dev_t devt; dev_t devt;
int err; int err;
...@@ -1132,22 +1143,21 @@ static int add_port(struct ports_device *portdev, u32 id) ...@@ -1132,22 +1143,21 @@ static int add_port(struct ports_device *portdev, u32 id)
spin_lock_init(&port->inbuf_lock); spin_lock_init(&port->inbuf_lock);
init_waitqueue_head(&port->waitqueue); init_waitqueue_head(&port->waitqueue);
inbuf = alloc_buf(PAGE_SIZE); /* Fill the in_vq with buffers so the host can send us data. */
if (!inbuf) { err = fill_queue(port->in_vq, &port->inbuf_lock);
if (!err) {
dev_err(port->dev, "Error allocating inbufs\n");
err = -ENOMEM; err = -ENOMEM;
goto free_device; 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 we're not using multiport support, this has to be a console port
*/ */
if (!use_multiport(port->portdev)) { if (!use_multiport(port->portdev)) {
err = init_port_console(port); err = init_port_console(port);
if (err) if (err)
goto free_inbuf; goto free_inbufs;
} }
spin_lock_irq(&portdev->ports_lock); spin_lock_irq(&portdev->ports_lock);
...@@ -1175,8 +1185,9 @@ static int add_port(struct ports_device *portdev, u32 id) ...@@ -1175,8 +1185,9 @@ static int add_port(struct ports_device *portdev, u32 id)
} }
return 0; return 0;
free_inbuf: free_inbufs:
free_buf(inbuf); while ((buf = port->in_vq->vq_ops->detach_unused_buf(port->in_vq)))
free_buf(buf);
free_device: free_device:
device_destroy(pdrvdata.class, port->dev->devt); device_destroy(pdrvdata.class, port->dev->devt);
free_cdev: free_cdev:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment