]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - drivers/char/virtio_console.c
Merge remote-tracking branch 'hexagon/linux-next'
[karo-tx-linux.git] / drivers / char / virtio_console.c
index ee4dbeafb377c5a7786e97372962db2a05904427..ce5f3fc25d6dbf1f7c45ff4cad6d2349da202d1a 100644 (file)
@@ -61,9 +61,6 @@ struct ports_driver_data {
        /* List of all the devices we're handling */
        struct list_head portdevs;
 
-       /* Number of devices this driver is handling */
-       unsigned int index;
-
        /*
         * This is used to keep track of the number of hvc consoles
         * spawned by this driver.  This number is given as the first
@@ -152,7 +149,8 @@ struct ports_device {
        spinlock_t ports_lock;
 
        /* To protect the vq operations for the control channel */
-       spinlock_t cvq_lock;
+       spinlock_t c_ivq_lock;
+       spinlock_t c_ovq_lock;
 
        /* The current config space is stored here */
        struct virtio_console_config config;
@@ -169,9 +167,6 @@ struct ports_device {
        /* Array of per-port IO virtqueues */
        struct virtqueue **in_vqs, **out_vqs;
 
-       /* Used for numbering devices for sysfs and debugfs */
-       unsigned int drv_index;
-
        /* Major number for this device.  Ports will be created as minors. */
        int chr_major;
 };
@@ -575,11 +570,14 @@ static ssize_t __send_control_msg(struct ports_device *portdev, u32 port_id,
        vq = portdev->c_ovq;
 
        sg_init_one(sg, &cpkt, sizeof(cpkt));
+
+       spin_lock(&portdev->c_ovq_lock);
        if (virtqueue_add_buf(vq, sg, 1, 0, &cpkt, GFP_ATOMIC) == 0) {
                virtqueue_kick(vq);
                while (!virtqueue_get_buf(vq, &len))
                        cpu_relax();
        }
+       spin_unlock(&portdev->c_ovq_lock);
        return 0;
 }
 
@@ -1415,7 +1413,7 @@ static int add_port(struct ports_device *portdev, u32 id)
        }
        port->dev = device_create(pdrvdata.class, &port->portdev->vdev->dev,
                                  devt, port, "vport%up%u",
-                                 port->portdev->drv_index, id);
+                                 port->portdev->vdev->index, id);
        if (IS_ERR(port->dev)) {
                err = PTR_ERR(port->dev);
                dev_err(&port->portdev->vdev->dev,
@@ -1470,7 +1468,7 @@ static int add_port(struct ports_device *portdev, u32 id)
                 * inspect a port's state at any time
                 */
                sprintf(debugfs_name, "vport%up%u",
-                       port->portdev->drv_index, id);
+                       port->portdev->vdev->index, id);
                port->debugfs_file = debugfs_create_file(debugfs_name, 0444,
                                                         pdrvdata.debugfs_dir,
                                                         port,
@@ -1715,23 +1713,23 @@ static void control_work_handler(struct work_struct *work)
        portdev = container_of(work, struct ports_device, control_work);
        vq = portdev->c_ivq;
 
-       spin_lock(&portdev->cvq_lock);
+       spin_lock(&portdev->c_ivq_lock);
        while ((buf = virtqueue_get_buf(vq, &len))) {
-               spin_unlock(&portdev->cvq_lock);
+               spin_unlock(&portdev->c_ivq_lock);
 
                buf->len = len;
                buf->offset = 0;
 
                handle_control_message(portdev, buf);
 
-               spin_lock(&portdev->cvq_lock);
+               spin_lock(&portdev->c_ivq_lock);
                if (add_inbuf(portdev->c_ivq, buf) < 0) {
                        dev_warn(&portdev->vdev->dev,
                                 "Error adding buffer to queue\n");
                        free_buf(buf, false);
                }
        }
-       spin_unlock(&portdev->cvq_lock);
+       spin_unlock(&portdev->c_ivq_lock);
 }
 
 static void out_intr(struct virtqueue *vq)
@@ -1758,13 +1756,23 @@ static void in_intr(struct virtqueue *vq)
        port->inbuf = get_inbuf(port);
 
        /*
-        * Don't queue up data when port is closed.  This condition
+        * Normally the port should not accept data when the port is
+        * closed. For generic serial ports, the host won't (shouldn't)
+        * send data till the guest is connected. But this condition
         * can be reached when a console port is not yet connected (no
-        * tty is spawned) and the host sends out data to console
-        * ports.  For generic serial ports, the host won't
-        * (shouldn't) send data till the guest is connected.
+        * tty is spawned) and the other side sends out data over the
+        * vring, or when a remote devices start sending data before
+        * the ports are opened.
+        *
+        * A generic serial port will discard data if not connected,
+        * while console ports and rproc-serial ports accepts data at
+        * any time. rproc-serial is initiated with guest_connected to
+        * false because port_fops_open expects this. Console ports are
+        * hooked up with an HVC console and is initialized with
+        * guest_connected to true.
         */
-       if (!port->guest_connected)
+
+       if (!port->guest_connected && !is_rproc_serial(port->portdev->vdev))
                discard_port_data(port);
 
        spin_unlock_irqrestore(&port->inbuf_lock, flags);
@@ -1958,16 +1966,12 @@ static int virtcons_probe(struct virtio_device *vdev)
        portdev->vdev = vdev;
        vdev->priv = portdev;
 
-       spin_lock_irq(&pdrvdata_lock);
-       portdev->drv_index = pdrvdata.index++;
-       spin_unlock_irq(&pdrvdata_lock);
-
        portdev->chr_major = register_chrdev(0, "virtio-portsdev",
                                             &portdev_fops);
        if (portdev->chr_major < 0) {
                dev_err(&vdev->dev,
                        "Error %d registering chrdev for device %u\n",
-                       portdev->chr_major, portdev->drv_index);
+                       portdev->chr_major, vdev->index);
                err = portdev->chr_major;
                goto free;
        }
@@ -1996,10 +2000,12 @@ static int virtcons_probe(struct virtio_device *vdev)
        if (multiport) {
                unsigned int nr_added_bufs;
 
-               spin_lock_init(&portdev->cvq_lock);
+               spin_lock_init(&portdev->c_ivq_lock);
+               spin_lock_init(&portdev->c_ovq_lock);
                INIT_WORK(&portdev->control_work, &control_work_handler);
 
-               nr_added_bufs = fill_queue(portdev->c_ivq, &portdev->cvq_lock);
+               nr_added_bufs = fill_queue(portdev->c_ivq,
+                                          &portdev->c_ivq_lock);
                if (!nr_added_bufs) {
                        dev_err(&vdev->dev,
                                "Error allocating buffers for control queue\n");
@@ -2150,7 +2156,7 @@ static int virtcons_restore(struct virtio_device *vdev)
                return ret;
 
        if (use_multiport(portdev))
-               fill_queue(portdev->c_ivq, &portdev->cvq_lock);
+               fill_queue(portdev->c_ivq, &portdev->c_ivq_lock);
 
        list_for_each_entry(port, &portdev->ports, list) {
                port->in_vq = portdev->in_vqs[port->id];