182d2f21eSSasha Levin #include "kvm/virtio-balloon.h" 282d2f21eSSasha Levin 382d2f21eSSasha Levin #include "kvm/virtio-pci-dev.h" 482d2f21eSSasha Levin 582d2f21eSSasha Levin #include "kvm/disk-image.h" 682d2f21eSSasha Levin #include "kvm/virtio.h" 782d2f21eSSasha Levin #include "kvm/ioport.h" 882d2f21eSSasha Levin #include "kvm/util.h" 982d2f21eSSasha Levin #include "kvm/kvm.h" 1082d2f21eSSasha Levin #include "kvm/pci.h" 1182d2f21eSSasha Levin #include "kvm/threadpool.h" 1282d2f21eSSasha Levin #include "kvm/irq.h" 1382d2f21eSSasha Levin #include "kvm/ioeventfd.h" 14*4b2e0a7aSSasha Levin #include "kvm/guest_compat.h" 1582d2f21eSSasha Levin 1682d2f21eSSasha Levin #include <linux/virtio_ring.h> 1782d2f21eSSasha Levin #include <linux/virtio_balloon.h> 1882d2f21eSSasha Levin 1982d2f21eSSasha Levin #include <linux/list.h> 2082d2f21eSSasha Levin #include <fcntl.h> 2182d2f21eSSasha Levin #include <sys/types.h> 2282d2f21eSSasha Levin #include <sys/stat.h> 2382d2f21eSSasha Levin #include <pthread.h> 2482d2f21eSSasha Levin 25bc10d2c1SSasha Levin #define NUM_VIRT_QUEUES 3 2682d2f21eSSasha Levin #define VIRTIO_BLN_QUEUE_SIZE 128 2782d2f21eSSasha Levin #define VIRTIO_BLN_INFLATE 0 2882d2f21eSSasha Levin #define VIRTIO_BLN_DEFLATE 1 29bc10d2c1SSasha Levin #define VIRTIO_BLN_STATS 2 3082d2f21eSSasha Levin 3182d2f21eSSasha Levin struct bln_dev { 3282d2f21eSSasha Levin struct pci_device_header pci_hdr; 3382d2f21eSSasha Levin struct list_head list; 3482d2f21eSSasha Levin 3582d2f21eSSasha Levin u16 base_addr; 3682d2f21eSSasha Levin u8 status; 3782d2f21eSSasha Levin u8 isr; 3882d2f21eSSasha Levin u16 config_vector; 3982d2f21eSSasha Levin u32 host_features; 4082d2f21eSSasha Levin 4182d2f21eSSasha Levin /* virtio queue */ 4282d2f21eSSasha Levin u16 queue_selector; 4382d2f21eSSasha Levin struct virt_queue vqs[NUM_VIRT_QUEUES]; 445cac5d9cSSasha Levin struct thread_pool__job jobs[NUM_VIRT_QUEUES]; 4582d2f21eSSasha Levin 46bc10d2c1SSasha Levin struct virtio_balloon_stat stats[VIRTIO_BALLOON_S_NR]; 47bc10d2c1SSasha Levin struct virtio_balloon_stat *cur_stat; 48bc10d2c1SSasha Levin u32 cur_stat_head; 49bc10d2c1SSasha Levin u16 stat_count; 50bc10d2c1SSasha Levin int stat_waitfd; 51bc10d2c1SSasha Levin 52*4b2e0a7aSSasha Levin int compat_id; 5382d2f21eSSasha Levin struct virtio_balloon_config config; 5482d2f21eSSasha Levin }; 5582d2f21eSSasha Levin 5682d2f21eSSasha Levin static struct bln_dev bdev; 5782d2f21eSSasha Levin extern struct kvm *kvm; 5882d2f21eSSasha Levin 59c9f6a037SXiao Guangrong static bool virtio_bln_dev_in(void *data, unsigned long offset, int size) 6082d2f21eSSasha Levin { 6182d2f21eSSasha Levin u8 *config_space = (u8 *) &bdev.config; 6282d2f21eSSasha Levin 63c9f6a037SXiao Guangrong if (size != 1) 6482d2f21eSSasha Levin return false; 6582d2f21eSSasha Levin 6682d2f21eSSasha Levin ioport__write8(data, config_space[offset - VIRTIO_MSI_CONFIG_VECTOR]); 6782d2f21eSSasha Levin 6882d2f21eSSasha Levin return true; 6982d2f21eSSasha Levin } 7082d2f21eSSasha Levin 71c9f6a037SXiao Guangrong static bool virtio_bln_dev_out(void *data, unsigned long offset, int size) 7282d2f21eSSasha Levin { 7382d2f21eSSasha Levin u8 *config_space = (u8 *) &bdev.config; 7482d2f21eSSasha Levin 75c9f6a037SXiao Guangrong if (size != 1) 7682d2f21eSSasha Levin return false; 7782d2f21eSSasha Levin 7882d2f21eSSasha Levin config_space[offset - VIRTIO_MSI_CONFIG_VECTOR] = *(u8 *)data; 7982d2f21eSSasha Levin 8082d2f21eSSasha Levin return true; 8182d2f21eSSasha Levin } 8282d2f21eSSasha Levin 83c9f6a037SXiao Guangrong static bool virtio_bln_pci_io_in(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size) 8482d2f21eSSasha Levin { 8582d2f21eSSasha Levin unsigned long offset; 8682d2f21eSSasha Levin bool ret = true; 8782d2f21eSSasha Levin 8882d2f21eSSasha Levin offset = port - bdev.base_addr; 8982d2f21eSSasha Levin 9082d2f21eSSasha Levin switch (offset) { 9182d2f21eSSasha Levin case VIRTIO_PCI_HOST_FEATURES: 9282d2f21eSSasha Levin ioport__write32(data, bdev.host_features); 9382d2f21eSSasha Levin break; 9482d2f21eSSasha Levin case VIRTIO_PCI_GUEST_FEATURES: 9582d2f21eSSasha Levin case VIRTIO_PCI_QUEUE_SEL: 9682d2f21eSSasha Levin case VIRTIO_PCI_QUEUE_NOTIFY: 9782d2f21eSSasha Levin ret = false; 9882d2f21eSSasha Levin break; 9982d2f21eSSasha Levin case VIRTIO_PCI_QUEUE_PFN: 10082d2f21eSSasha Levin ioport__write32(data, bdev.vqs[bdev.queue_selector].pfn); 10182d2f21eSSasha Levin break; 10282d2f21eSSasha Levin case VIRTIO_PCI_QUEUE_NUM: 10382d2f21eSSasha Levin ioport__write16(data, VIRTIO_BLN_QUEUE_SIZE); 10482d2f21eSSasha Levin break; 10582d2f21eSSasha Levin case VIRTIO_PCI_STATUS: 10682d2f21eSSasha Levin ioport__write8(data, bdev.status); 10782d2f21eSSasha Levin break; 10882d2f21eSSasha Levin case VIRTIO_PCI_ISR: 10982d2f21eSSasha Levin ioport__write8(data, bdev.isr); 11082d2f21eSSasha Levin kvm__irq_line(kvm, bdev.pci_hdr.irq_line, VIRTIO_IRQ_LOW); 11182d2f21eSSasha Levin bdev.isr = VIRTIO_IRQ_LOW; 11282d2f21eSSasha Levin break; 11382d2f21eSSasha Levin default: 114c9f6a037SXiao Guangrong ret = virtio_bln_dev_in(data, offset, size); 11582d2f21eSSasha Levin break; 11682d2f21eSSasha Levin }; 11782d2f21eSSasha Levin 11882d2f21eSSasha Levin return ret; 11982d2f21eSSasha Levin } 12082d2f21eSSasha Levin 12182d2f21eSSasha Levin static bool virtio_bln_do_io_request(struct kvm *kvm, struct bln_dev *bdev, struct virt_queue *queue) 12282d2f21eSSasha Levin { 12382d2f21eSSasha Levin struct iovec iov[VIRTIO_BLN_QUEUE_SIZE]; 12482d2f21eSSasha Levin unsigned int len = 0; 12582d2f21eSSasha Levin u16 out, in, head; 12682d2f21eSSasha Levin u32 *ptrs, i; 12782d2f21eSSasha Levin 12882d2f21eSSasha Levin head = virt_queue__get_iov(queue, iov, &out, &in, kvm); 12982d2f21eSSasha Levin ptrs = iov[0].iov_base; 13082d2f21eSSasha Levin len = iov[0].iov_len / sizeof(u32); 13182d2f21eSSasha Levin 13282d2f21eSSasha Levin for (i = 0 ; i < len ; i++) { 13382d2f21eSSasha Levin void *guest_ptr; 13482d2f21eSSasha Levin 13582d2f21eSSasha Levin guest_ptr = guest_flat_to_host(kvm, ptrs[i] << VIRTIO_BALLOON_PFN_SHIFT); 13682d2f21eSSasha Levin if (queue == &bdev->vqs[VIRTIO_BLN_INFLATE]) { 13782d2f21eSSasha Levin madvise(guest_ptr, 1 << VIRTIO_BALLOON_PFN_SHIFT, MADV_DONTNEED); 13882d2f21eSSasha Levin bdev->config.actual++; 139bc10d2c1SSasha Levin } else if (queue == &bdev->vqs[VIRTIO_BLN_DEFLATE]) { 14082d2f21eSSasha Levin bdev->config.actual--; 14182d2f21eSSasha Levin } 14282d2f21eSSasha Levin } 14382d2f21eSSasha Levin 14482d2f21eSSasha Levin virt_queue__set_used_elem(queue, head, len); 14582d2f21eSSasha Levin 14682d2f21eSSasha Levin return true; 14782d2f21eSSasha Levin } 14882d2f21eSSasha Levin 149bc10d2c1SSasha Levin static bool virtio_bln_do_stat_request(struct kvm *kvm, struct bln_dev *bdev, struct virt_queue *queue) 150bc10d2c1SSasha Levin { 151bc10d2c1SSasha Levin struct iovec iov[VIRTIO_BLN_QUEUE_SIZE]; 152bc10d2c1SSasha Levin u16 out, in, head; 153bc10d2c1SSasha Levin struct virtio_balloon_stat *stat; 154bc10d2c1SSasha Levin u64 wait_val = 1; 155bc10d2c1SSasha Levin 156bc10d2c1SSasha Levin head = virt_queue__get_iov(queue, iov, &out, &in, kvm); 157bc10d2c1SSasha Levin stat = iov[0].iov_base; 158bc10d2c1SSasha Levin 159bc10d2c1SSasha Levin /* Initial empty stat buffer */ 160bc10d2c1SSasha Levin if (bdev->cur_stat == NULL) { 161bc10d2c1SSasha Levin bdev->cur_stat = stat; 162bc10d2c1SSasha Levin bdev->cur_stat_head = head; 163bc10d2c1SSasha Levin 164bc10d2c1SSasha Levin return true; 165bc10d2c1SSasha Levin } 166bc10d2c1SSasha Levin 167bc10d2c1SSasha Levin memcpy(bdev->stats, stat, iov[0].iov_len); 168bc10d2c1SSasha Levin 169bc10d2c1SSasha Levin bdev->stat_count = iov[0].iov_len / sizeof(struct virtio_balloon_stat); 170bc10d2c1SSasha Levin bdev->cur_stat = stat; 171bc10d2c1SSasha Levin bdev->cur_stat_head = head; 172bc10d2c1SSasha Levin 173bc10d2c1SSasha Levin if (write(bdev->stat_waitfd, &wait_val, sizeof(wait_val)) <= 0) 174bc10d2c1SSasha Levin return -EFAULT; 175bc10d2c1SSasha Levin 176bc10d2c1SSasha Levin return 1; 177bc10d2c1SSasha Levin } 178bc10d2c1SSasha Levin 17982d2f21eSSasha Levin static void virtio_bln_do_io(struct kvm *kvm, void *param) 18082d2f21eSSasha Levin { 18182d2f21eSSasha Levin struct virt_queue *vq = param; 18282d2f21eSSasha Levin 183bc10d2c1SSasha Levin if (vq == &bdev.vqs[VIRTIO_BLN_STATS]) { 184bc10d2c1SSasha Levin virtio_bln_do_stat_request(kvm, &bdev, vq); 185bc10d2c1SSasha Levin virt_queue__trigger_irq(vq, bdev.pci_hdr.irq_line, &bdev.isr, kvm); 186bc10d2c1SSasha Levin return; 187bc10d2c1SSasha Levin } 188bc10d2c1SSasha Levin 18982d2f21eSSasha Levin while (virt_queue__available(vq)) { 19082d2f21eSSasha Levin virtio_bln_do_io_request(kvm, &bdev, vq); 19182d2f21eSSasha Levin virt_queue__trigger_irq(vq, bdev.pci_hdr.irq_line, &bdev.isr, kvm); 19282d2f21eSSasha Levin } 19382d2f21eSSasha Levin } 19482d2f21eSSasha Levin 19582d2f21eSSasha Levin static void ioevent_callback(struct kvm *kvm, void *param) 19682d2f21eSSasha Levin { 19782d2f21eSSasha Levin thread_pool__do_job(param); 19882d2f21eSSasha Levin } 19982d2f21eSSasha Levin 200c9f6a037SXiao Guangrong static bool virtio_bln_pci_io_out(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size) 20182d2f21eSSasha Levin { 20282d2f21eSSasha Levin unsigned long offset; 20382d2f21eSSasha Levin bool ret = true; 20482d2f21eSSasha Levin struct ioevent ioevent; 20582d2f21eSSasha Levin 20682d2f21eSSasha Levin offset = port - bdev.base_addr; 20782d2f21eSSasha Levin 20882d2f21eSSasha Levin switch (offset) { 20982d2f21eSSasha Levin case VIRTIO_MSI_QUEUE_VECTOR: 21082d2f21eSSasha Levin case VIRTIO_PCI_GUEST_FEATURES: 21182d2f21eSSasha Levin break; 21282d2f21eSSasha Levin case VIRTIO_PCI_QUEUE_PFN: { 21382d2f21eSSasha Levin struct virt_queue *queue; 21482d2f21eSSasha Levin void *p; 21582d2f21eSSasha Levin 216*4b2e0a7aSSasha Levin compat__remove_message(bdev.compat_id); 217*4b2e0a7aSSasha Levin 21882d2f21eSSasha Levin queue = &bdev.vqs[bdev.queue_selector]; 21982d2f21eSSasha Levin queue->pfn = ioport__read32(data); 22082d2f21eSSasha Levin p = guest_pfn_to_host(kvm, queue->pfn); 22182d2f21eSSasha Levin 22282d2f21eSSasha Levin vring_init(&queue->vring, VIRTIO_BLN_QUEUE_SIZE, p, VIRTIO_PCI_VRING_ALIGN); 22382d2f21eSSasha Levin 2245cac5d9cSSasha Levin thread_pool__init_job(&bdev.jobs[bdev.queue_selector], kvm, virtio_bln_do_io, queue); 22582d2f21eSSasha Levin 22682d2f21eSSasha Levin ioevent = (struct ioevent) { 22782d2f21eSSasha Levin .io_addr = bdev.base_addr + VIRTIO_PCI_QUEUE_NOTIFY, 22882d2f21eSSasha Levin .io_len = sizeof(u16), 22982d2f21eSSasha Levin .fn = ioevent_callback, 2305cac5d9cSSasha Levin .fn_ptr = &bdev.jobs[bdev.queue_selector], 23182d2f21eSSasha Levin .datamatch = bdev.queue_selector, 23282d2f21eSSasha Levin .fn_kvm = kvm, 23382d2f21eSSasha Levin .fd = eventfd(0, 0), 23482d2f21eSSasha Levin }; 23582d2f21eSSasha Levin 23682d2f21eSSasha Levin ioeventfd__add_event(&ioevent); 23782d2f21eSSasha Levin 23882d2f21eSSasha Levin break; 23982d2f21eSSasha Levin } 24082d2f21eSSasha Levin case VIRTIO_PCI_QUEUE_SEL: 24182d2f21eSSasha Levin bdev.queue_selector = ioport__read16(data); 24282d2f21eSSasha Levin break; 24382d2f21eSSasha Levin case VIRTIO_PCI_QUEUE_NOTIFY: { 24482d2f21eSSasha Levin u16 queue_index; 24582d2f21eSSasha Levin queue_index = ioport__read16(data); 2465cac5d9cSSasha Levin thread_pool__do_job(&bdev.jobs[queue_index]); 24782d2f21eSSasha Levin break; 24882d2f21eSSasha Levin } 24982d2f21eSSasha Levin case VIRTIO_PCI_STATUS: 25082d2f21eSSasha Levin bdev.status = ioport__read8(data); 25182d2f21eSSasha Levin break; 25282d2f21eSSasha Levin case VIRTIO_MSI_CONFIG_VECTOR: 25382d2f21eSSasha Levin bdev.config_vector = VIRTIO_MSI_NO_VECTOR; 25482d2f21eSSasha Levin break; 25582d2f21eSSasha Levin default: 256c9f6a037SXiao Guangrong ret = virtio_bln_dev_out(data, offset, size); 25782d2f21eSSasha Levin break; 25882d2f21eSSasha Levin }; 25982d2f21eSSasha Levin 26082d2f21eSSasha Levin return ret; 26182d2f21eSSasha Levin } 26282d2f21eSSasha Levin 26382d2f21eSSasha Levin static struct ioport_operations virtio_bln_io_ops = { 26482d2f21eSSasha Levin .io_in = virtio_bln_pci_io_in, 26582d2f21eSSasha Levin .io_out = virtio_bln_pci_io_out, 26682d2f21eSSasha Levin }; 26782d2f21eSSasha Levin 268bc10d2c1SSasha Levin static int virtio_bln__collect_stats(void) 269bc10d2c1SSasha Levin { 270bc10d2c1SSasha Levin u64 tmp; 271bc10d2c1SSasha Levin 272bc10d2c1SSasha Levin virt_queue__set_used_elem(&bdev.vqs[VIRTIO_BLN_STATS], bdev.cur_stat_head, 273bc10d2c1SSasha Levin sizeof(struct virtio_balloon_stat)); 274bc10d2c1SSasha Levin virt_queue__trigger_irq(&bdev.vqs[VIRTIO_BLN_STATS], bdev.pci_hdr.irq_line, 275bc10d2c1SSasha Levin &bdev.isr, kvm); 276bc10d2c1SSasha Levin 277bc10d2c1SSasha Levin if (read(bdev.stat_waitfd, &tmp, sizeof(tmp)) <= 0) 278bc10d2c1SSasha Levin return -EFAULT; 279bc10d2c1SSasha Levin 280bc10d2c1SSasha Levin return 0; 281bc10d2c1SSasha Levin } 282bc10d2c1SSasha Levin 283bc10d2c1SSasha Levin static int virtio_bln__print_stats(void) 284bc10d2c1SSasha Levin { 285bc10d2c1SSasha Levin u16 i; 286bc10d2c1SSasha Levin 287bc10d2c1SSasha Levin if (virtio_bln__collect_stats() < 0) 288bc10d2c1SSasha Levin return -EFAULT; 289bc10d2c1SSasha Levin 290bc10d2c1SSasha Levin printf("\n\n\t*** Guest memory statistics ***\n\n"); 291bc10d2c1SSasha Levin for (i = 0; i < bdev.stat_count; i++) { 292bc10d2c1SSasha Levin switch (bdev.stats[i].tag) { 293bc10d2c1SSasha Levin case VIRTIO_BALLOON_S_SWAP_IN: 294bc10d2c1SSasha Levin printf("The amount of memory that has been swapped in (in bytes):"); 295bc10d2c1SSasha Levin break; 296bc10d2c1SSasha Levin case VIRTIO_BALLOON_S_SWAP_OUT: 297bc10d2c1SSasha Levin printf("The amount of memory that has been swapped out to disk (in bytes):"); 298bc10d2c1SSasha Levin break; 299bc10d2c1SSasha Levin case VIRTIO_BALLOON_S_MAJFLT: 300bc10d2c1SSasha Levin printf("The number of major page faults that have occurred:"); 301bc10d2c1SSasha Levin break; 302bc10d2c1SSasha Levin case VIRTIO_BALLOON_S_MINFLT: 303bc10d2c1SSasha Levin printf("The number of minor page faults that have occurred:"); 304bc10d2c1SSasha Levin break; 305bc10d2c1SSasha Levin case VIRTIO_BALLOON_S_MEMFREE: 306bc10d2c1SSasha Levin printf("The amount of memory not being used for any purpose (in bytes):"); 307bc10d2c1SSasha Levin break; 308bc10d2c1SSasha Levin case VIRTIO_BALLOON_S_MEMTOT: 309bc10d2c1SSasha Levin printf("The total amount of memory available (in bytes):"); 310bc10d2c1SSasha Levin break; 311bc10d2c1SSasha Levin } 312bc10d2c1SSasha Levin printf("%llu\n", bdev.stats[i].val); 313bc10d2c1SSasha Levin } 314bc10d2c1SSasha Levin printf("\n"); 315bc10d2c1SSasha Levin 316bc10d2c1SSasha Levin return 0; 317bc10d2c1SSasha Levin } 318bc10d2c1SSasha Levin 31982d2f21eSSasha Levin static void handle_sigmem(int sig) 32082d2f21eSSasha Levin { 32142bcd3eeSLiming Wang if (sig == SIGKVMADDMEM) { 32282d2f21eSSasha Levin bdev.config.num_pages += 256; 323bc10d2c1SSasha Levin } else if (sig == SIGKVMDELMEM) { 32442bcd3eeSLiming Wang if (bdev.config.num_pages < 256) 32542bcd3eeSLiming Wang return; 32642bcd3eeSLiming Wang 32782d2f21eSSasha Levin bdev.config.num_pages -= 256; 328bc10d2c1SSasha Levin } else if (sig == SIGKVMMEMSTAT) { 329bc10d2c1SSasha Levin virtio_bln__print_stats(); 330bc10d2c1SSasha Levin 331bc10d2c1SSasha Levin return; 33242bcd3eeSLiming Wang } 33382d2f21eSSasha Levin 33482d2f21eSSasha Levin /* Notify that the configuration space has changed */ 33582d2f21eSSasha Levin bdev.isr = VIRTIO_PCI_ISR_CONFIG; 33682d2f21eSSasha Levin kvm__irq_line(kvm, bdev.pci_hdr.irq_line, 1); 33782d2f21eSSasha Levin } 33882d2f21eSSasha Levin 33982d2f21eSSasha Levin void virtio_bln__init(struct kvm *kvm) 34082d2f21eSSasha Levin { 34182d2f21eSSasha Levin u8 pin, line, dev; 34282d2f21eSSasha Levin u16 bdev_base_addr; 34382d2f21eSSasha Levin 34482d2f21eSSasha Levin signal(SIGKVMADDMEM, handle_sigmem); 34582d2f21eSSasha Levin signal(SIGKVMDELMEM, handle_sigmem); 346bc10d2c1SSasha Levin signal(SIGKVMMEMSTAT, handle_sigmem); 34782d2f21eSSasha Levin 34882d2f21eSSasha Levin bdev_base_addr = ioport__register(IOPORT_EMPTY, &virtio_bln_io_ops, IOPORT_SIZE, &bdev); 34982d2f21eSSasha Levin 35082d2f21eSSasha Levin bdev.pci_hdr = (struct pci_device_header) { 35182d2f21eSSasha Levin .vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET, 35282d2f21eSSasha Levin .device_id = PCI_DEVICE_ID_VIRTIO_BLN, 35382d2f21eSSasha Levin .header_type = PCI_HEADER_TYPE_NORMAL, 35482d2f21eSSasha Levin .revision_id = 0, 35582d2f21eSSasha Levin .class = 0x010000, 35682d2f21eSSasha Levin .subsys_vendor_id = PCI_SUBSYSTEM_VENDOR_ID_REDHAT_QUMRANET, 35782d2f21eSSasha Levin .subsys_id = VIRTIO_ID_BALLOON, 35882d2f21eSSasha Levin .bar[0] = bdev_base_addr | PCI_BASE_ADDRESS_SPACE_IO, 35982d2f21eSSasha Levin }; 36082d2f21eSSasha Levin 36182d2f21eSSasha Levin bdev.base_addr = bdev_base_addr; 36282d2f21eSSasha Levin 36380c71af0SLiming Wang if (irq__register_device(VIRTIO_ID_BALLOON, &dev, &pin, &line) < 0) 36482d2f21eSSasha Levin return; 36582d2f21eSSasha Levin 36682d2f21eSSasha Levin bdev.pci_hdr.irq_pin = pin; 36782d2f21eSSasha Levin bdev.pci_hdr.irq_line = line; 368bc10d2c1SSasha Levin bdev.host_features = 1 << VIRTIO_BALLOON_F_STATS_VQ; 369bc10d2c1SSasha Levin bdev.stat_waitfd = eventfd(0, 0); 37082d2f21eSSasha Levin memset(&bdev.config, 0, sizeof(struct virtio_balloon_config)); 37182d2f21eSSasha Levin 37282d2f21eSSasha Levin pci__register(&bdev.pci_hdr, dev); 373*4b2e0a7aSSasha Levin 374*4b2e0a7aSSasha Levin bdev.compat_id = compat__add_message("virtio-balloon device was not detected", 375*4b2e0a7aSSasha Levin "While you have requested a virtio-balloon device, " 376*4b2e0a7aSSasha Levin "the guest kernel didn't seem to detect it.\n" 377*4b2e0a7aSSasha Levin "Please make sure that the kernel was compiled" 378*4b2e0a7aSSasha Levin "with CONFIG_VIRTIO_BALLOON."); 37982d2f21eSSasha Levin } 380