Add linux-next specific files for 20110831
[linux-2.6/next.git] / tools / kvm / virtio / console.c
blob035554cefc877000bf344c1a403a4d35bf48d083
1 #include "kvm/virtio-console.h"
2 #include "kvm/virtio-pci-dev.h"
3 #include "kvm/disk-image.h"
4 #include "kvm/virtio.h"
5 #include "kvm/ioport.h"
6 #include "kvm/util.h"
7 #include "kvm/term.h"
8 #include "kvm/mutex.h"
9 #include "kvm/kvm.h"
10 #include "kvm/pci.h"
11 #include "kvm/threadpool.h"
12 #include "kvm/irq.h"
13 #include "kvm/guest_compat.h"
14 #include "kvm/virtio-pci.h"
16 #include <linux/virtio_console.h>
17 #include <linux/virtio_ring.h>
18 #include <linux/virtio_blk.h>
20 #include <sys/uio.h>
21 #include <sys/types.h>
22 #include <sys/stat.h>
23 #include <termios.h>
24 #include <assert.h>
25 #include <unistd.h>
26 #include <fcntl.h>
28 #define VIRTIO_CONSOLE_QUEUE_SIZE 128
29 #define VIRTIO_CONSOLE_NUM_QUEUES 2
30 #define VIRTIO_CONSOLE_RX_QUEUE 0
31 #define VIRTIO_CONSOLE_TX_QUEUE 1
33 struct con_dev {
34 pthread_mutex_t mutex;
36 struct virtio_pci vpci;
37 struct virt_queue vqs[VIRTIO_CONSOLE_NUM_QUEUES];
38 struct virtio_console_config config;
39 u32 features;
40 int compat_id;
42 struct thread_pool__job jobs[VIRTIO_CONSOLE_NUM_QUEUES];
45 static struct con_dev cdev = {
46 .mutex = PTHREAD_MUTEX_INITIALIZER,
48 .config = {
49 .cols = 80,
50 .rows = 24,
51 .max_nr_ports = 1,
56 * Interrupts are injected for hvc0 only.
58 static void virtio_console__inject_interrupt_callback(struct kvm *kvm, void *param)
60 struct iovec iov[VIRTIO_CONSOLE_QUEUE_SIZE];
61 struct virt_queue *vq;
62 u16 out, in;
63 u16 head;
64 int len;
66 mutex_lock(&cdev.mutex);
68 vq = param;
70 if (term_readable(CONSOLE_VIRTIO) && virt_queue__available(vq)) {
71 head = virt_queue__get_iov(vq, iov, &out, &in, kvm);
72 len = term_getc_iov(CONSOLE_VIRTIO, iov, in);
73 virt_queue__set_used_elem(vq, head, len);
74 virtio_pci__signal_vq(kvm, &cdev.vpci, vq - cdev.vqs);
77 mutex_unlock(&cdev.mutex);
80 void virtio_console__inject_interrupt(struct kvm *kvm)
82 thread_pool__do_job(&cdev.jobs[VIRTIO_CONSOLE_RX_QUEUE]);
85 static void virtio_console_handle_callback(struct kvm *kvm, void *param)
87 struct iovec iov[VIRTIO_CONSOLE_QUEUE_SIZE];
88 struct virt_queue *vq;
89 u16 out, in;
90 u16 head;
91 u32 len;
93 vq = param;
96 * The current Linux implementation polls for the buffer
97 * to be used, rather than waiting for an interrupt.
98 * So there is no need to inject an interrupt for the tx path.
101 while (virt_queue__available(vq)) {
102 head = virt_queue__get_iov(vq, iov, &out, &in, kvm);
103 len = term_putc_iov(CONSOLE_VIRTIO, iov, out);
104 virt_queue__set_used_elem(vq, head, len);
109 static void set_config(struct kvm *kvm, void *dev, u8 data, u32 offset)
111 struct con_dev *cdev = dev;
113 ((u8 *)(&cdev->config))[offset] = data;
116 static u8 get_config(struct kvm *kvm, void *dev, u32 offset)
118 struct con_dev *cdev = dev;
120 return ((u8 *)(&cdev->config))[offset];
123 static u32 get_host_features(struct kvm *kvm, void *dev)
125 return 0;
128 static void set_guest_features(struct kvm *kvm, void *dev, u32 features)
130 /* Unused */
133 static int init_vq(struct kvm *kvm, void *dev, u32 vq, u32 pfn)
135 struct virt_queue *queue;
136 void *p;
138 assert(vq < VIRTIO_CONSOLE_NUM_QUEUES);
140 compat__remove_message(cdev.compat_id);
142 queue = &cdev.vqs[vq];
143 queue->pfn = pfn;
144 p = guest_pfn_to_host(kvm, queue->pfn);
146 vring_init(&queue->vring, VIRTIO_CONSOLE_QUEUE_SIZE, p, VIRTIO_PCI_VRING_ALIGN);
148 if (vq == VIRTIO_CONSOLE_TX_QUEUE)
149 thread_pool__init_job(&cdev.jobs[vq], kvm, virtio_console_handle_callback, queue);
150 else if (vq == VIRTIO_CONSOLE_RX_QUEUE)
151 thread_pool__init_job(&cdev.jobs[vq], kvm, virtio_console__inject_interrupt_callback, queue);
153 return 0;
156 static int notify_vq(struct kvm *kvm, void *dev, u32 vq)
158 struct con_dev *cdev = dev;
160 thread_pool__do_job(&cdev->jobs[vq]);
162 return 0;
165 static int get_pfn_vq(struct kvm *kvm, void *dev, u32 vq)
167 struct con_dev *cdev = dev;
169 return cdev->vqs[vq].pfn;
172 static int get_size_vq(struct kvm *kvm, void *dev, u32 vq)
174 return VIRTIO_CONSOLE_QUEUE_SIZE;
177 void virtio_console__init(struct kvm *kvm)
179 virtio_pci__init(kvm, &cdev.vpci, &cdev, PCI_DEVICE_ID_VIRTIO_CONSOLE, VIRTIO_ID_CONSOLE);
180 cdev.vpci.ops = (struct virtio_pci_ops) {
181 .set_config = set_config,
182 .get_config = get_config,
183 .get_host_features = get_host_features,
184 .set_guest_features = set_guest_features,
185 .init_vq = init_vq,
186 .notify_vq = notify_vq,
187 .get_pfn_vq = get_pfn_vq,
188 .get_size_vq = get_size_vq,
191 cdev.compat_id = compat__add_message("virtio-console device was not detected",
192 "While you have requested a virtio-console device, "
193 "the guest kernel didn't seem to detect it.\n"
194 "Please make sure that the kernel was compiled"
195 "with CONFIG_VIRTIO_CONSOLE.");