The discovered bit in PGCCSR register indicates if the device has been
[linux-2.6/next.git] / tools / kvm / virtio / balloon.c
blob0f2453901fce66d529c98026a17779b9ed6abb97
1 #include "kvm/virtio-balloon.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/pci.h"
9 #include "kvm/threadpool.h"
10 #include "kvm/guest_compat.h"
11 #include "kvm/virtio-pci.h"
13 #include <linux/virtio_ring.h>
14 #include <linux/virtio_balloon.h>
16 #include <linux/kernel.h>
17 #include <linux/list.h>
18 #include <fcntl.h>
19 #include <sys/types.h>
20 #include <sys/stat.h>
21 #include <sys/mman.h>
22 #include <pthread.h>
23 #include <sys/eventfd.h>
25 #define NUM_VIRT_QUEUES 3
26 #define VIRTIO_BLN_QUEUE_SIZE 128
27 #define VIRTIO_BLN_INFLATE 0
28 #define VIRTIO_BLN_DEFLATE 1
29 #define VIRTIO_BLN_STATS 2
31 struct bln_dev {
32 struct list_head list;
33 struct virtio_pci vpci;
35 u32 features;
37 /* virtio queue */
38 struct virt_queue vqs[NUM_VIRT_QUEUES];
39 struct thread_pool__job jobs[NUM_VIRT_QUEUES];
41 struct virtio_balloon_stat stats[VIRTIO_BALLOON_S_NR];
42 struct virtio_balloon_stat *cur_stat;
43 u32 cur_stat_head;
44 u16 stat_count;
45 int stat_waitfd;
47 int compat_id;
48 struct virtio_balloon_config config;
51 static struct bln_dev bdev;
52 extern struct kvm *kvm;
54 static bool virtio_bln_do_io_request(struct kvm *kvm, struct bln_dev *bdev, struct virt_queue *queue)
56 struct iovec iov[VIRTIO_BLN_QUEUE_SIZE];
57 unsigned int len = 0;
58 u16 out, in, head;
59 u32 *ptrs, i;
61 head = virt_queue__get_iov(queue, iov, &out, &in, kvm);
62 ptrs = iov[0].iov_base;
63 len = iov[0].iov_len / sizeof(u32);
65 for (i = 0 ; i < len ; i++) {
66 void *guest_ptr;
68 guest_ptr = guest_flat_to_host(kvm, ptrs[i] << VIRTIO_BALLOON_PFN_SHIFT);
69 if (queue == &bdev->vqs[VIRTIO_BLN_INFLATE]) {
70 madvise(guest_ptr, 1 << VIRTIO_BALLOON_PFN_SHIFT, MADV_DONTNEED);
71 bdev->config.actual++;
72 } else if (queue == &bdev->vqs[VIRTIO_BLN_DEFLATE]) {
73 bdev->config.actual--;
77 virt_queue__set_used_elem(queue, head, len);
79 return true;
82 static bool virtio_bln_do_stat_request(struct kvm *kvm, struct bln_dev *bdev, struct virt_queue *queue)
84 struct iovec iov[VIRTIO_BLN_QUEUE_SIZE];
85 u16 out, in, head;
86 struct virtio_balloon_stat *stat;
87 u64 wait_val = 1;
89 head = virt_queue__get_iov(queue, iov, &out, &in, kvm);
90 stat = iov[0].iov_base;
92 /* Initial empty stat buffer */
93 if (bdev->cur_stat == NULL) {
94 bdev->cur_stat = stat;
95 bdev->cur_stat_head = head;
97 return true;
100 memcpy(bdev->stats, stat, iov[0].iov_len);
102 bdev->stat_count = iov[0].iov_len / sizeof(struct virtio_balloon_stat);
103 bdev->cur_stat = stat;
104 bdev->cur_stat_head = head;
106 if (write(bdev->stat_waitfd, &wait_val, sizeof(wait_val)) <= 0)
107 return -EFAULT;
109 return 1;
112 static void virtio_bln_do_io(struct kvm *kvm, void *param)
114 struct virt_queue *vq = param;
116 if (vq == &bdev.vqs[VIRTIO_BLN_STATS]) {
117 virtio_bln_do_stat_request(kvm, &bdev, vq);
118 virtio_pci__signal_vq(kvm, &bdev.vpci, VIRTIO_BLN_STATS);
119 return;
122 while (virt_queue__available(vq)) {
123 virtio_bln_do_io_request(kvm, &bdev, vq);
124 virtio_pci__signal_vq(kvm, &bdev.vpci, vq - bdev.vqs);
128 static int virtio_bln__collect_stats(void)
130 u64 tmp;
132 virt_queue__set_used_elem(&bdev.vqs[VIRTIO_BLN_STATS], bdev.cur_stat_head,
133 sizeof(struct virtio_balloon_stat));
134 virtio_pci__signal_vq(kvm, &bdev.vpci, VIRTIO_BLN_STATS);
136 if (read(bdev.stat_waitfd, &tmp, sizeof(tmp)) <= 0)
137 return -EFAULT;
139 return 0;
142 static int virtio_bln__print_stats(void)
144 u16 i;
146 if (virtio_bln__collect_stats() < 0)
147 return -EFAULT;
149 printf("\n\n\t*** Guest memory statistics ***\n\n");
150 for (i = 0; i < bdev.stat_count; i++) {
151 switch (bdev.stats[i].tag) {
152 case VIRTIO_BALLOON_S_SWAP_IN:
153 printf("The amount of memory that has been swapped in (in bytes):");
154 break;
155 case VIRTIO_BALLOON_S_SWAP_OUT:
156 printf("The amount of memory that has been swapped out to disk (in bytes):");
157 break;
158 case VIRTIO_BALLOON_S_MAJFLT:
159 printf("The number of major page faults that have occurred:");
160 break;
161 case VIRTIO_BALLOON_S_MINFLT:
162 printf("The number of minor page faults that have occurred:");
163 break;
164 case VIRTIO_BALLOON_S_MEMFREE:
165 printf("The amount of memory not being used for any purpose (in bytes):");
166 break;
167 case VIRTIO_BALLOON_S_MEMTOT:
168 printf("The total amount of memory available (in bytes):");
169 break;
171 printf("%llu\n", bdev.stats[i].val);
173 printf("\n");
175 return 0;
178 static void handle_sigmem(int sig)
180 if (sig == SIGKVMADDMEM) {
181 bdev.config.num_pages += 256;
182 } else if (sig == SIGKVMDELMEM) {
183 if (bdev.config.num_pages < 256)
184 return;
186 bdev.config.num_pages -= 256;
187 } else if (sig == SIGKVMMEMSTAT) {
188 virtio_bln__print_stats();
190 return;
193 /* Notify that the configuration space has changed */
194 virtio_pci__signal_config(kvm, &bdev.vpci);
197 static void set_config(struct kvm *kvm, void *dev, u8 data, u32 offset)
199 struct bln_dev *bdev = dev;
201 ((u8 *)(&bdev->config))[offset] = data;
204 static u8 get_config(struct kvm *kvm, void *dev, u32 offset)
206 struct bln_dev *bdev = dev;
208 return ((u8 *)(&bdev->config))[offset];
211 static u32 get_host_features(struct kvm *kvm, void *dev)
213 return 1 << VIRTIO_BALLOON_F_STATS_VQ;
216 static void set_guest_features(struct kvm *kvm, void *dev, u32 features)
218 struct bln_dev *bdev = dev;
220 bdev->features = features;
223 static int init_vq(struct kvm *kvm, void *dev, u32 vq, u32 pfn)
225 struct bln_dev *bdev = dev;
226 struct virt_queue *queue;
227 void *p;
229 compat__remove_message(bdev->compat_id);
231 queue = &bdev->vqs[vq];
232 queue->pfn = pfn;
233 p = guest_pfn_to_host(kvm, queue->pfn);
235 thread_pool__init_job(&bdev->jobs[vq], kvm, virtio_bln_do_io, queue);
236 vring_init(&queue->vring, VIRTIO_BLN_QUEUE_SIZE, p, VIRTIO_PCI_VRING_ALIGN);
238 return 0;
241 static int notify_vq(struct kvm *kvm, void *dev, u32 vq)
243 struct bln_dev *bdev = dev;
245 thread_pool__do_job(&bdev->jobs[vq]);
247 return 0;
250 static int get_pfn_vq(struct kvm *kvm, void *dev, u32 vq)
252 struct bln_dev *bdev = dev;
254 return bdev->vqs[vq].pfn;
257 static int get_size_vq(struct kvm *kvm, void *dev, u32 vq)
259 return VIRTIO_BLN_QUEUE_SIZE;
262 void virtio_bln__init(struct kvm *kvm)
264 signal(SIGKVMADDMEM, handle_sigmem);
265 signal(SIGKVMDELMEM, handle_sigmem);
266 signal(SIGKVMMEMSTAT, handle_sigmem);
268 bdev.stat_waitfd = eventfd(0, 0);
269 memset(&bdev.config, 0, sizeof(struct virtio_balloon_config));
271 virtio_pci__init(kvm, &bdev.vpci, &bdev, PCI_DEVICE_ID_VIRTIO_BLN, VIRTIO_ID_BALLOON);
272 bdev.vpci.ops = (struct virtio_pci_ops) {
273 .set_config = set_config,
274 .get_config = get_config,
275 .get_host_features = get_host_features,
276 .set_guest_features = set_guest_features,
277 .init_vq = init_vq,
278 .notify_vq = notify_vq,
279 .get_pfn_vq = get_pfn_vq,
280 .get_size_vq = get_size_vq,
283 bdev.compat_id = compat__add_message("virtio-balloon device was not detected",
284 "While you have requested a virtio-balloon device, "
285 "the guest kernel didn't seem to detect it.\n"
286 "Please make sure that the kernel was compiled"
287 "with CONFIG_VIRTIO_BALLOON.");