aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/char/virtio_console.c392
-rw-r--r--include/linux/virtio_console.h21
2 files changed, 357 insertions, 56 deletions
diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c
index d01051060be3..a70f2b3a9e64 100644
--- a/drivers/char/virtio_console.c
+++ b/drivers/char/virtio_console.c
@@ -1,5 +1,6 @@
1/* 1/*
2 * Copyright (C) 2006, 2007, 2009 Rusty Russell, IBM Corporation 2 * Copyright (C) 2006, 2007, 2009 Rusty Russell, IBM Corporation
3 * Copyright (C) 2009, 2010 Red Hat, Inc.
3 * 4 *
4 * This program is free software; you can redistribute it and/or modify 5 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by 6 * it under the terms of the GNU General Public License as published by
@@ -21,6 +22,7 @@
21#include <linux/spinlock.h> 22#include <linux/spinlock.h>
22#include <linux/virtio.h> 23#include <linux/virtio.h>
23#include <linux/virtio_console.h> 24#include <linux/virtio_console.h>
25#include <linux/workqueue.h>
24#include "hvc_console.h" 26#include "hvc_console.h"
25 27
26/* 28/*
@@ -69,17 +71,6 @@ struct console {
69 u32 vtermno; 71 u32 vtermno;
70}; 72};
71 73
72/*
73 * This is a per-device struct that stores data common to all the
74 * ports for that device (vdev->priv).
75 */
76struct ports_device {
77 /* Array of per-port IO virtqueues */
78 struct virtqueue **in_vqs, **out_vqs;
79
80 struct virtio_device *vdev;
81};
82
83struct port_buffer { 74struct port_buffer {
84 char *buf; 75 char *buf;
85 76
@@ -92,8 +83,46 @@ struct port_buffer {
92 size_t offset; 83 size_t offset;
93}; 84};
94 85
86/*
87 * This is a per-device struct that stores data common to all the
88 * ports for that device (vdev->priv).
89 */
90struct ports_device {
91 /*
92 * Workqueue handlers where we process deferred work after
93 * notification
94 */
95 struct work_struct control_work;
96
97 struct list_head ports;
98
99 /* To protect the list of ports */
100 spinlock_t ports_lock;
101
102 /* To protect the vq operations for the control channel */
103 spinlock_t cvq_lock;
104
105 /* The current config space is stored here */
106 struct virtio_console_config config;
107
108 /* The virtio device we're associated with */
109 struct virtio_device *vdev;
110
111 /*
112 * A couple of virtqueues for the control channel: one for
113 * guest->host transfers, one for host->guest transfers
114 */
115 struct virtqueue *c_ivq, *c_ovq;
116
117 /* Array of per-port IO virtqueues */
118 struct virtqueue **in_vqs, **out_vqs;
119};
120
95/* This struct holds the per-port data */ 121/* This struct holds the per-port data */
96struct port { 122struct port {
123 /* Next port in the list, head is in the ports_device */
124 struct list_head list;
125
97 /* Pointer to the parent virtio_console device */ 126 /* Pointer to the parent virtio_console device */
98 struct ports_device *portdev; 127 struct ports_device *portdev;
99 128
@@ -115,6 +144,9 @@ struct port {
115 * hooked up to an hvc console 144 * hooked up to an hvc console
116 */ 145 */
117 struct console cons; 146 struct console cons;
147
148 /* The 'id' to identify the port with the Host */
149 u32 id;
118}; 150};
119 151
120/* This is the very early arch-specified put chars function. */ 152/* This is the very early arch-specified put chars function. */
@@ -139,25 +171,56 @@ out:
139 return port; 171 return port;
140} 172}
141 173
174static struct port *find_port_by_id(struct ports_device *portdev, u32 id)
175{
176 struct port *port;
177 unsigned long flags;
178
179 spin_lock_irqsave(&portdev->ports_lock, flags);
180 list_for_each_entry(port, &portdev->ports, list)
181 if (port->id == id)
182 goto out;
183 port = NULL;
184out:
185 spin_unlock_irqrestore(&portdev->ports_lock, flags);
186
187 return port;
188}
189
142static struct port *find_port_by_vq(struct ports_device *portdev, 190static struct port *find_port_by_vq(struct ports_device *portdev,
143 struct virtqueue *vq) 191 struct virtqueue *vq)
144{ 192{
145 struct port *port; 193 struct port *port;
146 struct console *cons;
147 unsigned long flags; 194 unsigned long flags;
148 195
149 spin_lock_irqsave(&pdrvdata_lock, flags); 196 spin_lock_irqsave(&portdev->ports_lock, flags);
150 list_for_each_entry(cons, &pdrvdata.consoles, list) { 197 list_for_each_entry(port, &portdev->ports, list)
151 port = container_of(cons, struct port, cons);
152 if (port->in_vq == vq || port->out_vq == vq) 198 if (port->in_vq == vq || port->out_vq == vq)
153 goto out; 199 goto out;
154 }
155 port = NULL; 200 port = NULL;
156out: 201out:
157 spin_unlock_irqrestore(&pdrvdata_lock, flags); 202 spin_unlock_irqrestore(&portdev->ports_lock, flags);
158 return port; 203 return port;
159} 204}
160 205
206static bool is_console_port(struct port *port)
207{
208 if (port->cons.hvc)
209 return true;
210 return false;
211}
212
213static inline bool use_multiport(struct ports_device *portdev)
214{
215 /*
216 * This condition can be true when put_chars is called from
217 * early_init
218 */
219 if (!portdev->vdev)
220 return 0;
221 return portdev->vdev->features[0] & (1 << VIRTIO_CONSOLE_F_MULTIPORT);
222}
223
161static void free_buf(struct port_buffer *buf) 224static void free_buf(struct port_buffer *buf)
162{ 225{
163 kfree(buf->buf); 226 kfree(buf->buf);
@@ -233,6 +296,32 @@ static bool port_has_data(struct port *port)
233 return ret; 296 return ret;
234} 297}
235 298
299static ssize_t send_control_msg(struct port *port, unsigned int event,
300 unsigned int value)
301{
302 struct scatterlist sg[1];
303 struct virtio_console_control cpkt;
304 struct virtqueue *vq;
305 int len;
306
307 if (!use_multiport(port->portdev))
308 return 0;
309
310 cpkt.id = port->id;
311 cpkt.event = event;
312 cpkt.value = value;
313
314 vq = port->portdev->c_ovq;
315
316 sg_init_one(sg, &cpkt, sizeof(cpkt));
317 if (vq->vq_ops->add_buf(vq, sg, 1, 0, &cpkt) >= 0) {
318 vq->vq_ops->kick(vq);
319 while (!vq->vq_ops->get_buf(vq, &len))
320 cpu_relax();
321 }
322 return 0;
323}
324
236static ssize_t send_buf(struct port *port, void *in_buf, size_t in_count) 325static ssize_t send_buf(struct port *port, void *in_buf, size_t in_count)
237{ 326{
238 struct scatterlist sg[1]; 327 struct scatterlist sg[1];
@@ -387,24 +476,7 @@ static void notifier_del_vio(struct hvc_struct *hp, int data)
387 hp->irq_requested = 0; 476 hp->irq_requested = 0;
388} 477}
389 478
390static void hvc_handle_input(struct virtqueue *vq) 479/* The operations for console ports. */
391{
392 struct port *port;
393 unsigned long flags;
394
395 port = find_port_by_vq(vq->vdev->priv, vq);
396 if (!port)
397 return;
398
399 spin_lock_irqsave(&port->inbuf_lock, flags);
400 port->inbuf = get_inbuf(port);
401 spin_unlock_irqrestore(&port->inbuf_lock, flags);
402
403 if (hvc_poll(port->cons.hvc))
404 hvc_kick();
405}
406
407/* The operations for the console. */
408static const struct hv_ops hv_ops = { 480static const struct hv_ops hv_ops = {
409 .get_chars = get_chars, 481 .get_chars = get_chars,
410 .put_chars = put_chars, 482 .put_chars = put_chars,
@@ -428,7 +500,7 @@ int __init virtio_cons_early_init(int (*put_chars)(u32, const char *, int))
428 return hvc_instantiate(0, 0, &hv_ops); 500 return hvc_instantiate(0, 0, &hv_ops);
429} 501}
430 502
431int __devinit init_port_console(struct port *port) 503int init_port_console(struct port *port)
432{ 504{
433 int ret; 505 int ret;
434 506
@@ -465,7 +537,122 @@ int __devinit init_port_console(struct port *port)
465 return 0; 537 return 0;
466} 538}
467 539
468static int __devinit add_port(struct ports_device *portdev) 540/* Any private messages that the Host and Guest want to share */
541static void handle_control_message(struct ports_device *portdev,
542 struct port_buffer *buf)
543{
544 struct virtio_console_control *cpkt;
545 struct port *port;
546
547 cpkt = (struct virtio_console_control *)(buf->buf + buf->offset);
548
549 port = find_port_by_id(portdev, cpkt->id);
550 if (!port) {
551 /* No valid header at start of buffer. Drop it. */
552 dev_dbg(&portdev->vdev->dev,
553 "Invalid index %u in control packet\n", cpkt->id);
554 return;
555 }
556
557 switch (cpkt->event) {
558 case VIRTIO_CONSOLE_CONSOLE_PORT:
559 if (!cpkt->value)
560 break;
561 if (is_console_port(port))
562 break;
563
564 init_port_console(port);
565 /*
566 * Could remove the port here in case init fails - but
567 * have to notify the host first.
568 */
569 break;
570 case VIRTIO_CONSOLE_RESIZE:
571 if (!is_console_port(port))
572 break;
573 port->cons.hvc->irq_requested = 1;
574 resize_console(port);
575 break;
576 }
577}
578
579static void control_work_handler(struct work_struct *work)
580{
581 struct ports_device *portdev;
582 struct virtqueue *vq;
583 struct port_buffer *buf;
584 unsigned int len;
585
586 portdev = container_of(work, struct ports_device, control_work);
587 vq = portdev->c_ivq;
588
589 spin_lock(&portdev->cvq_lock);
590 while ((buf = vq->vq_ops->get_buf(vq, &len))) {
591 spin_unlock(&portdev->cvq_lock);
592
593 buf->len = len;
594 buf->offset = 0;
595
596 handle_control_message(portdev, buf);
597
598 spin_lock(&portdev->cvq_lock);
599 if (add_inbuf(portdev->c_ivq, buf) < 0) {
600 dev_warn(&portdev->vdev->dev,
601 "Error adding buffer to queue\n");
602 free_buf(buf);
603 }
604 }
605 spin_unlock(&portdev->cvq_lock);
606}
607
608static void in_intr(struct virtqueue *vq)
609{
610 struct port *port;
611 unsigned long flags;
612
613 port = find_port_by_vq(vq->vdev->priv, vq);
614 if (!port)
615 return;
616
617 spin_lock_irqsave(&port->inbuf_lock, flags);
618 port->inbuf = get_inbuf(port);
619
620 spin_unlock_irqrestore(&port->inbuf_lock, flags);
621
622 if (is_console_port(port) && hvc_poll(port->cons.hvc))
623 hvc_kick();
624}
625
626static void control_intr(struct virtqueue *vq)
627{
628 struct ports_device *portdev;
629
630 portdev = vq->vdev->priv;
631 schedule_work(&portdev->control_work);
632}
633
634static void fill_queue(struct virtqueue *vq, spinlock_t *lock)
635{
636 struct port_buffer *buf;
637 int ret;
638
639 do {
640 buf = alloc_buf(PAGE_SIZE);
641 if (!buf)
642 break;
643
644 spin_lock_irq(lock);
645 ret = add_inbuf(vq, buf);
646 if (ret < 0) {
647 spin_unlock_irq(lock);
648 free_buf(buf);
649 break;
650 }
651 spin_unlock_irq(lock);
652 } while (ret > 0);
653}
654
655static int add_port(struct ports_device *portdev, u32 id)
469{ 656{
470 struct port *port; 657 struct port *port;
471 struct port_buffer *inbuf; 658 struct port_buffer *inbuf;
@@ -478,11 +665,13 @@ static int __devinit add_port(struct ports_device *portdev)
478 } 665 }
479 666
480 port->portdev = portdev; 667 port->portdev = portdev;
668 port->id = id;
481 669
482 port->inbuf = NULL; 670 port->inbuf = NULL;
671 port->cons.hvc = NULL;
483 672
484 port->in_vq = portdev->in_vqs[0]; 673 port->in_vq = portdev->in_vqs[port->id];
485 port->out_vq = portdev->out_vqs[0]; 674 port->out_vq = portdev->out_vqs[port->id];
486 675
487 spin_lock_init(&port->inbuf_lock); 676 spin_lock_init(&port->inbuf_lock);
488 677
@@ -495,9 +684,25 @@ static int __devinit add_port(struct ports_device *portdev)
495 /* Register the input buffer the first time. */ 684 /* Register the input buffer the first time. */
496 add_inbuf(port->in_vq, inbuf); 685 add_inbuf(port->in_vq, inbuf);
497 686
498 err = init_port_console(port); 687 /*
499 if (err) 688 * If we're not using multiport support, this has to be a console port
500 goto free_inbuf; 689 */
690 if (!use_multiport(port->portdev)) {
691 err = init_port_console(port);
692 if (err)
693 goto free_inbuf;
694 }
695
696 spin_lock_irq(&portdev->ports_lock);
697 list_add_tail(&port->list, &port->portdev->ports);
698 spin_unlock_irq(&portdev->ports_lock);
699
700 /*
701 * Tell the Host we're set so that it can send us various
702 * configuration parameters for this port (eg, port name,
703 * caching, whether this is a console port, etc.)
704 */
705 send_control_msg(port, VIRTIO_CONSOLE_PORT_READY, 1);
501 706
502 return 0; 707 return 0;
503 708
@@ -514,12 +719,11 @@ static int init_vqs(struct ports_device *portdev)
514 vq_callback_t **io_callbacks; 719 vq_callback_t **io_callbacks;
515 char **io_names; 720 char **io_names;
516 struct virtqueue **vqs; 721 struct virtqueue **vqs;
517 u32 nr_ports, nr_queues; 722 u32 i, j, nr_ports, nr_queues;
518 int err; 723 int err;
519 724
520 /* We currently only have one port and two queues for that port */ 725 nr_ports = portdev->config.max_nr_ports;
521 nr_ports = 1; 726 nr_queues = use_multiport(portdev) ? (nr_ports + 1) * 2 : 2;
522 nr_queues = 2;
523 727
524 vqs = kmalloc(nr_queues * sizeof(struct virtqueue *), GFP_KERNEL); 728 vqs = kmalloc(nr_queues * sizeof(struct virtqueue *), GFP_KERNEL);
525 if (!vqs) { 729 if (!vqs) {
@@ -549,11 +753,32 @@ static int init_vqs(struct ports_device *portdev)
549 goto free_invqs; 753 goto free_invqs;
550 } 754 }
551 755
552 io_callbacks[0] = hvc_handle_input; 756 /*
553 io_callbacks[1] = NULL; 757 * For backward compat (newer host but older guest), the host
554 io_names[0] = "input"; 758 * spawns a console port first and also inits the vqs for port
555 io_names[1] = "output"; 759 * 0 before others.
556 760 */
761 j = 0;
762 io_callbacks[j] = in_intr;
763 io_callbacks[j + 1] = NULL;
764 io_names[j] = "input";
765 io_names[j + 1] = "output";
766 j += 2;
767
768 if (use_multiport(portdev)) {
769 io_callbacks[j] = control_intr;
770 io_callbacks[j + 1] = NULL;
771 io_names[j] = "control-i";
772 io_names[j + 1] = "control-o";
773
774 for (i = 1; i < nr_ports; i++) {
775 j += 2;
776 io_callbacks[j] = in_intr;
777 io_callbacks[j + 1] = NULL;
778 io_names[j] = "input";
779 io_names[j + 1] = "output";
780 }
781 }
557 /* Find the queues. */ 782 /* Find the queues. */
558 err = portdev->vdev->config->find_vqs(portdev->vdev, nr_queues, vqs, 783 err = portdev->vdev->config->find_vqs(portdev->vdev, nr_queues, vqs,
559 io_callbacks, 784 io_callbacks,
@@ -561,9 +786,20 @@ static int init_vqs(struct ports_device *portdev)
561 if (err) 786 if (err)
562 goto free_outvqs; 787 goto free_outvqs;
563 788
789 j = 0;
564 portdev->in_vqs[0] = vqs[0]; 790 portdev->in_vqs[0] = vqs[0];
565 portdev->out_vqs[0] = vqs[1]; 791 portdev->out_vqs[0] = vqs[1];
566 792 j += 2;
793 if (use_multiport(portdev)) {
794 portdev->c_ivq = vqs[j];
795 portdev->c_ovq = vqs[j + 1];
796
797 for (i = 1; i < nr_ports; i++) {
798 j += 2;
799 portdev->in_vqs[i] = vqs[j];
800 portdev->out_vqs[i] = vqs[j + 1];
801 }
802 }
567 kfree(io_callbacks); 803 kfree(io_callbacks);
568 kfree(io_names); 804 kfree(io_names);
569 kfree(vqs); 805 kfree(vqs);
@@ -587,11 +823,17 @@ fail:
587/* 823/*
588 * Once we're further in boot, we get probed like any other virtio 824 * Once we're further in boot, we get probed like any other virtio
589 * device. 825 * device.
826 *
827 * If the host also supports multiple console ports, we check the
828 * config space to see how many ports the host has spawned. We
829 * initialize each port found.
590 */ 830 */
591static int __devinit virtcons_probe(struct virtio_device *vdev) 831static int __devinit virtcons_probe(struct virtio_device *vdev)
592{ 832{
593 struct ports_device *portdev; 833 struct ports_device *portdev;
834 u32 i;
594 int err; 835 int err;
836 bool multiport;
595 837
596 portdev = kmalloc(sizeof(*portdev), GFP_KERNEL); 838 portdev = kmalloc(sizeof(*portdev), GFP_KERNEL);
597 if (!portdev) { 839 if (!portdev) {
@@ -603,16 +845,53 @@ static int __devinit virtcons_probe(struct virtio_device *vdev)
603 portdev->vdev = vdev; 845 portdev->vdev = vdev;
604 vdev->priv = portdev; 846 vdev->priv = portdev;
605 847
848 multiport = false;
849 portdev->config.nr_ports = 1;
850 portdev->config.max_nr_ports = 1;
851 if (virtio_has_feature(vdev, VIRTIO_CONSOLE_F_MULTIPORT)) {
852 multiport = true;
853 vdev->features[0] |= 1 << VIRTIO_CONSOLE_F_MULTIPORT;
854
855 vdev->config->get(vdev, offsetof(struct virtio_console_config,
856 nr_ports),
857 &portdev->config.nr_ports,
858 sizeof(portdev->config.nr_ports));
859 vdev->config->get(vdev, offsetof(struct virtio_console_config,
860 max_nr_ports),
861 &portdev->config.max_nr_ports,
862 sizeof(portdev->config.max_nr_ports));
863 if (portdev->config.nr_ports > portdev->config.max_nr_ports) {
864 dev_warn(&vdev->dev,
865 "More ports (%u) specified than allowed (%u). Will init %u ports.",
866 portdev->config.nr_ports,
867 portdev->config.max_nr_ports,
868 portdev->config.max_nr_ports);
869
870 portdev->config.nr_ports = portdev->config.max_nr_ports;
871 }
872 }
873
874 /* Let the Host know we support multiple ports.*/
875 vdev->config->finalize_features(vdev);
876
606 err = init_vqs(portdev); 877 err = init_vqs(portdev);
607 if (err < 0) { 878 if (err < 0) {
608 dev_err(&vdev->dev, "Error %d initializing vqs\n", err); 879 dev_err(&vdev->dev, "Error %d initializing vqs\n", err);
609 goto free; 880 goto free;
610 } 881 }
611 882
612 /* We only have one port. */ 883 spin_lock_init(&portdev->ports_lock);
613 err = add_port(portdev); 884 INIT_LIST_HEAD(&portdev->ports);
614 if (err) 885
615 goto free_vqs; 886 if (multiport) {
887 spin_lock_init(&portdev->cvq_lock);
888 INIT_WORK(&portdev->control_work, &control_work_handler);
889
890 fill_queue(portdev->c_ivq, &portdev->cvq_lock);
891 }
892
893 for (i = 0; i < portdev->config.nr_ports; i++)
894 add_port(portdev, i);
616 895
617 /* Start using the new console output. */ 896 /* Start using the new console output. */
618 early_put_chars = NULL; 897 early_put_chars = NULL;
@@ -635,6 +914,7 @@ static struct virtio_device_id id_table[] = {
635 914
636static unsigned int features[] = { 915static unsigned int features[] = {
637 VIRTIO_CONSOLE_F_SIZE, 916 VIRTIO_CONSOLE_F_SIZE,
917 VIRTIO_CONSOLE_F_MULTIPORT,
638}; 918};
639 919
640static struct virtio_driver virtio_console = { 920static struct virtio_driver virtio_console = {
diff --git a/include/linux/virtio_console.h b/include/linux/virtio_console.h
index 9e0da40beae0..f4d183b5b493 100644
--- a/include/linux/virtio_console.h
+++ b/include/linux/virtio_console.h
@@ -6,18 +6,39 @@
6/* 6/*
7 * This header, excluding the #ifdef __KERNEL__ part, is BSD licensed so 7 * This header, excluding the #ifdef __KERNEL__ part, is BSD licensed so
8 * anyone can use the definitions to implement compatible drivers/servers. 8 * anyone can use the definitions to implement compatible drivers/servers.
9 *
10 * Copyright (C) Red Hat, Inc., 2009, 2010
9 */ 11 */
10 12
11/* Feature bits */ 13/* Feature bits */
12#define VIRTIO_CONSOLE_F_SIZE 0 /* Does host provide console size? */ 14#define VIRTIO_CONSOLE_F_SIZE 0 /* Does host provide console size? */
15#define VIRTIO_CONSOLE_F_MULTIPORT 1 /* Does host provide multiple ports? */
13 16
14struct virtio_console_config { 17struct virtio_console_config {
15 /* colums of the screens */ 18 /* colums of the screens */
16 __u16 cols; 19 __u16 cols;
17 /* rows of the screens */ 20 /* rows of the screens */
18 __u16 rows; 21 __u16 rows;
22 /* max. number of ports this device can hold */
23 __u32 max_nr_ports;
24 /* number of ports added so far */
25 __u32 nr_ports;
19} __attribute__((packed)); 26} __attribute__((packed));
20 27
28/*
29 * A message that's passed between the Host and the Guest for a
30 * particular port.
31 */
32struct virtio_console_control {
33 __u32 id; /* Port number */
34 __u16 event; /* The kind of control event (see below) */
35 __u16 value; /* Extra information for the key */
36};
37
38/* Some events for control messages */
39#define VIRTIO_CONSOLE_PORT_READY 0
40#define VIRTIO_CONSOLE_CONSOLE_PORT 1
41#define VIRTIO_CONSOLE_RESIZE 2
21 42
22#ifdef __KERNEL__ 43#ifdef __KERNEL__
23int __init virtio_cons_early_init(int (*put_chars)(u32, const char *, int)); 44int __init virtio_cons_early_init(int (*put_chars)(u32, const char *, int));