diff options
Diffstat (limited to 'drivers/char/virtio_console.c')
-rw-r--r-- | drivers/char/virtio_console.c | 44 |
1 files changed, 30 insertions, 14 deletions
diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index e905d5f53051..ce5f3fc25d6d 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c | |||
@@ -149,7 +149,8 @@ struct ports_device { | |||
149 | spinlock_t ports_lock; | 149 | spinlock_t ports_lock; |
150 | 150 | ||
151 | /* To protect the vq operations for the control channel */ | 151 | /* To protect the vq operations for the control channel */ |
152 | spinlock_t cvq_lock; | 152 | spinlock_t c_ivq_lock; |
153 | spinlock_t c_ovq_lock; | ||
153 | 154 | ||
154 | /* The current config space is stored here */ | 155 | /* The current config space is stored here */ |
155 | struct virtio_console_config config; | 156 | struct virtio_console_config config; |
@@ -569,11 +570,14 @@ static ssize_t __send_control_msg(struct ports_device *portdev, u32 port_id, | |||
569 | vq = portdev->c_ovq; | 570 | vq = portdev->c_ovq; |
570 | 571 | ||
571 | sg_init_one(sg, &cpkt, sizeof(cpkt)); | 572 | sg_init_one(sg, &cpkt, sizeof(cpkt)); |
573 | |||
574 | spin_lock(&portdev->c_ovq_lock); | ||
572 | if (virtqueue_add_buf(vq, sg, 1, 0, &cpkt, GFP_ATOMIC) == 0) { | 575 | if (virtqueue_add_buf(vq, sg, 1, 0, &cpkt, GFP_ATOMIC) == 0) { |
573 | virtqueue_kick(vq); | 576 | virtqueue_kick(vq); |
574 | while (!virtqueue_get_buf(vq, &len)) | 577 | while (!virtqueue_get_buf(vq, &len)) |
575 | cpu_relax(); | 578 | cpu_relax(); |
576 | } | 579 | } |
580 | spin_unlock(&portdev->c_ovq_lock); | ||
577 | return 0; | 581 | return 0; |
578 | } | 582 | } |
579 | 583 | ||
@@ -1436,7 +1440,7 @@ static int add_port(struct ports_device *portdev, u32 id) | |||
1436 | * rproc_serial does not want the console port, only | 1440 | * rproc_serial does not want the console port, only |
1437 | * the generic port implementation. | 1441 | * the generic port implementation. |
1438 | */ | 1442 | */ |
1439 | port->host_connected = port->guest_connected = true; | 1443 | port->host_connected = true; |
1440 | else if (!use_multiport(port->portdev)) { | 1444 | else if (!use_multiport(port->portdev)) { |
1441 | /* | 1445 | /* |
1442 | * If we're not using multiport support, | 1446 | * If we're not using multiport support, |
@@ -1709,23 +1713,23 @@ static void control_work_handler(struct work_struct *work) | |||
1709 | portdev = container_of(work, struct ports_device, control_work); | 1713 | portdev = container_of(work, struct ports_device, control_work); |
1710 | vq = portdev->c_ivq; | 1714 | vq = portdev->c_ivq; |
1711 | 1715 | ||
1712 | spin_lock(&portdev->cvq_lock); | 1716 | spin_lock(&portdev->c_ivq_lock); |
1713 | while ((buf = virtqueue_get_buf(vq, &len))) { | 1717 | while ((buf = virtqueue_get_buf(vq, &len))) { |
1714 | spin_unlock(&portdev->cvq_lock); | 1718 | spin_unlock(&portdev->c_ivq_lock); |
1715 | 1719 | ||
1716 | buf->len = len; | 1720 | buf->len = len; |
1717 | buf->offset = 0; | 1721 | buf->offset = 0; |
1718 | 1722 | ||
1719 | handle_control_message(portdev, buf); | 1723 | handle_control_message(portdev, buf); |
1720 | 1724 | ||
1721 | spin_lock(&portdev->cvq_lock); | 1725 | spin_lock(&portdev->c_ivq_lock); |
1722 | if (add_inbuf(portdev->c_ivq, buf) < 0) { | 1726 | if (add_inbuf(portdev->c_ivq, buf) < 0) { |
1723 | dev_warn(&portdev->vdev->dev, | 1727 | dev_warn(&portdev->vdev->dev, |
1724 | "Error adding buffer to queue\n"); | 1728 | "Error adding buffer to queue\n"); |
1725 | free_buf(buf, false); | 1729 | free_buf(buf, false); |
1726 | } | 1730 | } |
1727 | } | 1731 | } |
1728 | spin_unlock(&portdev->cvq_lock); | 1732 | spin_unlock(&portdev->c_ivq_lock); |
1729 | } | 1733 | } |
1730 | 1734 | ||
1731 | static void out_intr(struct virtqueue *vq) | 1735 | static void out_intr(struct virtqueue *vq) |
@@ -1752,13 +1756,23 @@ static void in_intr(struct virtqueue *vq) | |||
1752 | port->inbuf = get_inbuf(port); | 1756 | port->inbuf = get_inbuf(port); |
1753 | 1757 | ||
1754 | /* | 1758 | /* |
1755 | * Don't queue up data when port is closed. This condition | 1759 | * Normally the port should not accept data when the port is |
1760 | * closed. For generic serial ports, the host won't (shouldn't) | ||
1761 | * send data till the guest is connected. But this condition | ||
1756 | * can be reached when a console port is not yet connected (no | 1762 | * can be reached when a console port is not yet connected (no |
1757 | * tty is spawned) and the host sends out data to console | 1763 | * tty is spawned) and the other side sends out data over the |
1758 | * ports. For generic serial ports, the host won't | 1764 | * vring, or when a remote devices start sending data before |
1759 | * (shouldn't) send data till the guest is connected. | 1765 | * the ports are opened. |
1766 | * | ||
1767 | * A generic serial port will discard data if not connected, | ||
1768 | * while console ports and rproc-serial ports accepts data at | ||
1769 | * any time. rproc-serial is initiated with guest_connected to | ||
1770 | * false because port_fops_open expects this. Console ports are | ||
1771 | * hooked up with an HVC console and is initialized with | ||
1772 | * guest_connected to true. | ||
1760 | */ | 1773 | */ |
1761 | if (!port->guest_connected) | 1774 | |
1775 | if (!port->guest_connected && !is_rproc_serial(port->portdev->vdev)) | ||
1762 | discard_port_data(port); | 1776 | discard_port_data(port); |
1763 | 1777 | ||
1764 | spin_unlock_irqrestore(&port->inbuf_lock, flags); | 1778 | spin_unlock_irqrestore(&port->inbuf_lock, flags); |
@@ -1986,10 +2000,12 @@ static int virtcons_probe(struct virtio_device *vdev) | |||
1986 | if (multiport) { | 2000 | if (multiport) { |
1987 | unsigned int nr_added_bufs; | 2001 | unsigned int nr_added_bufs; |
1988 | 2002 | ||
1989 | spin_lock_init(&portdev->cvq_lock); | 2003 | spin_lock_init(&portdev->c_ivq_lock); |
2004 | spin_lock_init(&portdev->c_ovq_lock); | ||
1990 | INIT_WORK(&portdev->control_work, &control_work_handler); | 2005 | INIT_WORK(&portdev->control_work, &control_work_handler); |
1991 | 2006 | ||
1992 | nr_added_bufs = fill_queue(portdev->c_ivq, &portdev->cvq_lock); | 2007 | nr_added_bufs = fill_queue(portdev->c_ivq, |
2008 | &portdev->c_ivq_lock); | ||
1993 | if (!nr_added_bufs) { | 2009 | if (!nr_added_bufs) { |
1994 | dev_err(&vdev->dev, | 2010 | dev_err(&vdev->dev, |
1995 | "Error allocating buffers for control queue\n"); | 2011 | "Error allocating buffers for control queue\n"); |
@@ -2140,7 +2156,7 @@ static int virtcons_restore(struct virtio_device *vdev) | |||
2140 | return ret; | 2156 | return ret; |
2141 | 2157 | ||
2142 | if (use_multiport(portdev)) | 2158 | if (use_multiport(portdev)) |
2143 | fill_queue(portdev->c_ivq, &portdev->cvq_lock); | 2159 | fill_queue(portdev->c_ivq, &portdev->c_ivq_lock); |
2144 | 2160 | ||
2145 | list_for_each_entry(port, &portdev->ports, list) { | 2161 | list_for_each_entry(port, &portdev->ports, list) { |
2146 | port->in_vq = portdev->in_vqs[port->id]; | 2162 | port->in_vq = portdev->in_vqs[port->id]; |