kvm tools: MSI-X fixes
[linux-2.6/next.git] / tools / kvm / virtio / rng.c
blobdc97729dafae5d7069ce240774c62632523bc3ff
1 #include "kvm/virtio-rng.h"
3 #include "kvm/virtio-pci-dev.h"
5 #include "kvm/virtio.h"
6 #include "kvm/util.h"
7 #include "kvm/kvm.h"
8 #include "kvm/threadpool.h"
9 #include "kvm/guest_compat.h"
10 #include "kvm/virtio-pci.h"
12 #include <linux/virtio_ring.h>
13 #include <linux/virtio_rng.h>
15 #include <linux/list.h>
16 #include <fcntl.h>
17 #include <sys/types.h>
18 #include <sys/stat.h>
19 #include <pthread.h>
20 #include <linux/kernel.h>
22 #define NUM_VIRT_QUEUES 1
23 #define VIRTIO_RNG_QUEUE_SIZE 128
25 struct rng_dev_job {
26 struct virt_queue *vq;
27 struct rng_dev *rdev;
28 struct thread_pool__job job_id;
31 struct rng_dev {
32 struct list_head list;
33 struct virtio_pci vpci;
35 int fd;
36 int compat_id;
38 /* virtio queue */
39 struct virt_queue vqs[NUM_VIRT_QUEUES];
40 struct rng_dev_job jobs[NUM_VIRT_QUEUES];
43 static LIST_HEAD(rdevs);
45 static void set_config(struct kvm *kvm, void *dev, u8 data, u32 offset)
47 /* Unused */
50 static u8 get_config(struct kvm *kvm, void *dev, u32 offset)
52 /* Unused */
53 return 0;
56 static u32 get_host_features(struct kvm *kvm, void *dev)
58 /* Unused */
59 return 0;
62 static void set_guest_features(struct kvm *kvm, void *dev, u32 features)
64 /* Unused */
67 static bool virtio_rng_do_io_request(struct kvm *kvm, struct rng_dev *rdev, struct virt_queue *queue)
69 struct iovec iov[VIRTIO_RNG_QUEUE_SIZE];
70 unsigned int len = 0;
71 u16 out, in, head;
73 head = virt_queue__get_iov(queue, iov, &out, &in, kvm);
74 len = readv(rdev->fd, iov, in);
76 virt_queue__set_used_elem(queue, head, len);
78 return true;
81 static void virtio_rng_do_io(struct kvm *kvm, void *param)
83 struct rng_dev_job *job = param;
84 struct virt_queue *vq = job->vq;
85 struct rng_dev *rdev = job->rdev;
87 while (virt_queue__available(vq))
88 virtio_rng_do_io_request(kvm, rdev, vq);
90 virtio_pci__signal_vq(kvm, &rdev->vpci, vq - rdev->vqs);
93 static int init_vq(struct kvm *kvm, void *dev, u32 vq, u32 pfn)
95 struct rng_dev *rdev = dev;
96 struct virt_queue *queue;
97 struct rng_dev_job *job;
98 void *p;
100 compat__remove_message(rdev->compat_id);
102 queue = &rdev->vqs[vq];
103 queue->pfn = pfn;
104 p = guest_pfn_to_host(kvm, queue->pfn);
106 job = &rdev->jobs[vq];
108 vring_init(&queue->vring, VIRTIO_RNG_QUEUE_SIZE, p, VIRTIO_PCI_VRING_ALIGN);
110 *job = (struct rng_dev_job) {
111 .vq = queue,
112 .rdev = rdev,
115 thread_pool__init_job(&job->job_id, kvm, virtio_rng_do_io, job);
117 return 0;
120 static int notify_vq(struct kvm *kvm, void *dev, u32 vq)
122 struct rng_dev *rdev = dev;
124 thread_pool__do_job(&rdev->jobs[vq].job_id);
126 return 0;
129 static int get_pfn_vq(struct kvm *kvm, void *dev, u32 vq)
131 struct rng_dev *rdev = dev;
133 return rdev->vqs[vq].pfn;
136 static int get_size_vq(struct kvm *kvm, void *dev, u32 vq)
138 return VIRTIO_RNG_QUEUE_SIZE;
141 void virtio_rng__init(struct kvm *kvm)
143 struct rng_dev *rdev;
145 rdev = malloc(sizeof(*rdev));
146 if (rdev == NULL)
147 return;
149 rdev->fd = open("/dev/urandom", O_RDONLY);
150 if (rdev->fd < 0)
151 die("Failed initializing RNG");
153 virtio_pci__init(kvm, &rdev->vpci, rdev, PCI_DEVICE_ID_VIRTIO_RNG, VIRTIO_ID_RNG);
154 rdev->vpci.ops = (struct virtio_pci_ops) {
155 .set_config = set_config,
156 .get_config = get_config,
157 .get_host_features = get_host_features,
158 .set_guest_features = set_guest_features,
159 .init_vq = init_vq,
160 .notify_vq = notify_vq,
161 .get_pfn_vq = get_pfn_vq,
162 .get_size_vq = get_size_vq,
165 list_add_tail(&rdev->list, &rdevs);
167 rdev->compat_id = compat__add_message("virtio-rng device was not detected",
168 "While you have requested a virtio-rng device, "
169 "the guest kernel didn't seem to detect it.\n"
170 "Please make sure that the kernel was compiled"
171 "with CONFIG_HW_RANDOM_VIRTIO.");
174 void virtio_rng__delete_all(struct kvm *kvm)
176 while (!list_empty(&rdevs)) {
177 struct rng_dev *rdev;
179 rdev = list_first_entry(&rdevs, struct rng_dev, list);
180 list_del(&rdev->list);
181 free(rdev);