1*82d2f21eSSasha Levin #include "kvm/virtio-balloon.h" 2*82d2f21eSSasha Levin 3*82d2f21eSSasha Levin #include "kvm/virtio-pci-dev.h" 4*82d2f21eSSasha Levin 5*82d2f21eSSasha Levin #include "kvm/disk-image.h" 6*82d2f21eSSasha Levin #include "kvm/virtio.h" 7*82d2f21eSSasha Levin #include "kvm/ioport.h" 8*82d2f21eSSasha Levin #include "kvm/util.h" 9*82d2f21eSSasha Levin #include "kvm/kvm.h" 10*82d2f21eSSasha Levin #include "kvm/pci.h" 11*82d2f21eSSasha Levin #include "kvm/threadpool.h" 12*82d2f21eSSasha Levin #include "kvm/irq.h" 13*82d2f21eSSasha Levin #include "kvm/ioeventfd.h" 14*82d2f21eSSasha Levin 15*82d2f21eSSasha Levin #include <linux/virtio_ring.h> 16*82d2f21eSSasha Levin #include <linux/virtio_balloon.h> 17*82d2f21eSSasha Levin 18*82d2f21eSSasha Levin #include <linux/list.h> 19*82d2f21eSSasha Levin #include <fcntl.h> 20*82d2f21eSSasha Levin #include <sys/types.h> 21*82d2f21eSSasha Levin #include <sys/stat.h> 22*82d2f21eSSasha Levin #include <pthread.h> 23*82d2f21eSSasha Levin 24*82d2f21eSSasha Levin #define NUM_VIRT_QUEUES 2 25*82d2f21eSSasha Levin #define VIRTIO_BLN_QUEUE_SIZE 128 26*82d2f21eSSasha Levin #define VIRTIO_BLN_INFLATE 0 27*82d2f21eSSasha Levin #define VIRTIO_BLN_DEFLATE 1 28*82d2f21eSSasha Levin 29*82d2f21eSSasha Levin struct bln_dev { 30*82d2f21eSSasha Levin struct pci_device_header pci_hdr; 31*82d2f21eSSasha Levin struct list_head list; 32*82d2f21eSSasha Levin 33*82d2f21eSSasha Levin u16 base_addr; 34*82d2f21eSSasha Levin u8 status; 35*82d2f21eSSasha Levin u8 isr; 36*82d2f21eSSasha Levin u16 config_vector; 37*82d2f21eSSasha Levin u32 host_features; 38*82d2f21eSSasha Levin 39*82d2f21eSSasha Levin /* virtio queue */ 40*82d2f21eSSasha Levin u16 queue_selector; 41*82d2f21eSSasha Levin struct virt_queue vqs[NUM_VIRT_QUEUES]; 42*82d2f21eSSasha Levin void *jobs[NUM_VIRT_QUEUES]; 43*82d2f21eSSasha Levin 44*82d2f21eSSasha Levin struct virtio_balloon_config config; 45*82d2f21eSSasha Levin }; 46*82d2f21eSSasha Levin 47*82d2f21eSSasha Levin static struct bln_dev bdev; 48*82d2f21eSSasha Levin extern struct kvm *kvm; 49*82d2f21eSSasha Levin 50*82d2f21eSSasha Levin static bool virtio_bln_dev_in(void *data, unsigned long offset, int size, u32 count) 51*82d2f21eSSasha Levin { 52*82d2f21eSSasha Levin u8 *config_space = (u8 *) &bdev.config; 53*82d2f21eSSasha Levin 54*82d2f21eSSasha Levin if (size != 1 || count != 1) 55*82d2f21eSSasha Levin return false; 56*82d2f21eSSasha Levin 57*82d2f21eSSasha Levin ioport__write8(data, config_space[offset - VIRTIO_MSI_CONFIG_VECTOR]); 58*82d2f21eSSasha Levin 59*82d2f21eSSasha Levin return true; 60*82d2f21eSSasha Levin } 61*82d2f21eSSasha Levin 62*82d2f21eSSasha Levin static bool virtio_bln_dev_out(void *data, unsigned long offset, int size, u32 count) 63*82d2f21eSSasha Levin { 64*82d2f21eSSasha Levin u8 *config_space = (u8 *) &bdev.config; 65*82d2f21eSSasha Levin 66*82d2f21eSSasha Levin if (size != 1 || count != 1) 67*82d2f21eSSasha Levin return false; 68*82d2f21eSSasha Levin 69*82d2f21eSSasha Levin config_space[offset - VIRTIO_MSI_CONFIG_VECTOR] = *(u8 *)data; 70*82d2f21eSSasha Levin 71*82d2f21eSSasha Levin return true; 72*82d2f21eSSasha Levin } 73*82d2f21eSSasha Levin 74*82d2f21eSSasha Levin static bool virtio_bln_pci_io_in(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size, u32 count) 75*82d2f21eSSasha Levin { 76*82d2f21eSSasha Levin unsigned long offset; 77*82d2f21eSSasha Levin bool ret = true; 78*82d2f21eSSasha Levin 79*82d2f21eSSasha Levin offset = port - bdev.base_addr; 80*82d2f21eSSasha Levin 81*82d2f21eSSasha Levin switch (offset) { 82*82d2f21eSSasha Levin case VIRTIO_PCI_HOST_FEATURES: 83*82d2f21eSSasha Levin ioport__write32(data, bdev.host_features); 84*82d2f21eSSasha Levin break; 85*82d2f21eSSasha Levin case VIRTIO_PCI_GUEST_FEATURES: 86*82d2f21eSSasha Levin case VIRTIO_PCI_QUEUE_SEL: 87*82d2f21eSSasha Levin case VIRTIO_PCI_QUEUE_NOTIFY: 88*82d2f21eSSasha Levin ret = false; 89*82d2f21eSSasha Levin break; 90*82d2f21eSSasha Levin case VIRTIO_PCI_QUEUE_PFN: 91*82d2f21eSSasha Levin ioport__write32(data, bdev.vqs[bdev.queue_selector].pfn); 92*82d2f21eSSasha Levin break; 93*82d2f21eSSasha Levin case VIRTIO_PCI_QUEUE_NUM: 94*82d2f21eSSasha Levin ioport__write16(data, VIRTIO_BLN_QUEUE_SIZE); 95*82d2f21eSSasha Levin break; 96*82d2f21eSSasha Levin case VIRTIO_PCI_STATUS: 97*82d2f21eSSasha Levin ioport__write8(data, bdev.status); 98*82d2f21eSSasha Levin break; 99*82d2f21eSSasha Levin case VIRTIO_PCI_ISR: 100*82d2f21eSSasha Levin ioport__write8(data, bdev.isr); 101*82d2f21eSSasha Levin kvm__irq_line(kvm, bdev.pci_hdr.irq_line, VIRTIO_IRQ_LOW); 102*82d2f21eSSasha Levin bdev.isr = VIRTIO_IRQ_LOW; 103*82d2f21eSSasha Levin break; 104*82d2f21eSSasha Levin default: 105*82d2f21eSSasha Levin ret = virtio_bln_dev_in(data, offset, size, count); 106*82d2f21eSSasha Levin break; 107*82d2f21eSSasha Levin }; 108*82d2f21eSSasha Levin 109*82d2f21eSSasha Levin return ret; 110*82d2f21eSSasha Levin } 111*82d2f21eSSasha Levin 112*82d2f21eSSasha Levin static bool virtio_bln_do_io_request(struct kvm *kvm, struct bln_dev *bdev, struct virt_queue *queue) 113*82d2f21eSSasha Levin { 114*82d2f21eSSasha Levin struct iovec iov[VIRTIO_BLN_QUEUE_SIZE]; 115*82d2f21eSSasha Levin unsigned int len = 0; 116*82d2f21eSSasha Levin u16 out, in, head; 117*82d2f21eSSasha Levin u32 *ptrs, i; 118*82d2f21eSSasha Levin 119*82d2f21eSSasha Levin head = virt_queue__get_iov(queue, iov, &out, &in, kvm); 120*82d2f21eSSasha Levin ptrs = iov[0].iov_base; 121*82d2f21eSSasha Levin len = iov[0].iov_len / sizeof(u32); 122*82d2f21eSSasha Levin 123*82d2f21eSSasha Levin for (i = 0 ; i < len ; i++) { 124*82d2f21eSSasha Levin void *guest_ptr; 125*82d2f21eSSasha Levin 126*82d2f21eSSasha Levin guest_ptr = guest_flat_to_host(kvm, ptrs[i] << VIRTIO_BALLOON_PFN_SHIFT); 127*82d2f21eSSasha Levin if (queue == &bdev->vqs[VIRTIO_BLN_INFLATE]) { 128*82d2f21eSSasha Levin madvise(guest_ptr, 1 << VIRTIO_BALLOON_PFN_SHIFT, MADV_DONTNEED); 129*82d2f21eSSasha Levin bdev->config.actual++; 130*82d2f21eSSasha Levin } else { 131*82d2f21eSSasha Levin bdev->config.actual--; 132*82d2f21eSSasha Levin } 133*82d2f21eSSasha Levin } 134*82d2f21eSSasha Levin 135*82d2f21eSSasha Levin virt_queue__set_used_elem(queue, head, len); 136*82d2f21eSSasha Levin 137*82d2f21eSSasha Levin return true; 138*82d2f21eSSasha Levin } 139*82d2f21eSSasha Levin 140*82d2f21eSSasha Levin static void virtio_bln_do_io(struct kvm *kvm, void *param) 141*82d2f21eSSasha Levin { 142*82d2f21eSSasha Levin struct virt_queue *vq = param; 143*82d2f21eSSasha Levin 144*82d2f21eSSasha Levin while (virt_queue__available(vq)) { 145*82d2f21eSSasha Levin virtio_bln_do_io_request(kvm, &bdev, vq); 146*82d2f21eSSasha Levin virt_queue__trigger_irq(vq, bdev.pci_hdr.irq_line, &bdev.isr, kvm); 147*82d2f21eSSasha Levin } 148*82d2f21eSSasha Levin } 149*82d2f21eSSasha Levin 150*82d2f21eSSasha Levin static void ioevent_callback(struct kvm *kvm, void *param) 151*82d2f21eSSasha Levin { 152*82d2f21eSSasha Levin thread_pool__do_job(param); 153*82d2f21eSSasha Levin } 154*82d2f21eSSasha Levin 155*82d2f21eSSasha Levin static bool virtio_bln_pci_io_out(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size, u32 count) 156*82d2f21eSSasha Levin { 157*82d2f21eSSasha Levin unsigned long offset; 158*82d2f21eSSasha Levin bool ret = true; 159*82d2f21eSSasha Levin struct ioevent ioevent; 160*82d2f21eSSasha Levin 161*82d2f21eSSasha Levin offset = port - bdev.base_addr; 162*82d2f21eSSasha Levin 163*82d2f21eSSasha Levin switch (offset) { 164*82d2f21eSSasha Levin case VIRTIO_MSI_QUEUE_VECTOR: 165*82d2f21eSSasha Levin case VIRTIO_PCI_GUEST_FEATURES: 166*82d2f21eSSasha Levin break; 167*82d2f21eSSasha Levin case VIRTIO_PCI_QUEUE_PFN: { 168*82d2f21eSSasha Levin struct virt_queue *queue; 169*82d2f21eSSasha Levin void *p; 170*82d2f21eSSasha Levin 171*82d2f21eSSasha Levin queue = &bdev.vqs[bdev.queue_selector]; 172*82d2f21eSSasha Levin queue->pfn = ioport__read32(data); 173*82d2f21eSSasha Levin p = guest_pfn_to_host(kvm, queue->pfn); 174*82d2f21eSSasha Levin 175*82d2f21eSSasha Levin vring_init(&queue->vring, VIRTIO_BLN_QUEUE_SIZE, p, VIRTIO_PCI_VRING_ALIGN); 176*82d2f21eSSasha Levin 177*82d2f21eSSasha Levin bdev.jobs[bdev.queue_selector] = thread_pool__add_job(kvm, virtio_bln_do_io, queue); 178*82d2f21eSSasha Levin 179*82d2f21eSSasha Levin ioevent = (struct ioevent) { 180*82d2f21eSSasha Levin .io_addr = bdev.base_addr + VIRTIO_PCI_QUEUE_NOTIFY, 181*82d2f21eSSasha Levin .io_len = sizeof(u16), 182*82d2f21eSSasha Levin .fn = ioevent_callback, 183*82d2f21eSSasha Levin .fn_ptr = bdev.jobs[bdev.queue_selector], 184*82d2f21eSSasha Levin .datamatch = bdev.queue_selector, 185*82d2f21eSSasha Levin .fn_kvm = kvm, 186*82d2f21eSSasha Levin .fd = eventfd(0, 0), 187*82d2f21eSSasha Levin }; 188*82d2f21eSSasha Levin 189*82d2f21eSSasha Levin ioeventfd__add_event(&ioevent); 190*82d2f21eSSasha Levin 191*82d2f21eSSasha Levin break; 192*82d2f21eSSasha Levin } 193*82d2f21eSSasha Levin case VIRTIO_PCI_QUEUE_SEL: 194*82d2f21eSSasha Levin bdev.queue_selector = ioport__read16(data); 195*82d2f21eSSasha Levin break; 196*82d2f21eSSasha Levin case VIRTIO_PCI_QUEUE_NOTIFY: { 197*82d2f21eSSasha Levin u16 queue_index; 198*82d2f21eSSasha Levin queue_index = ioport__read16(data); 199*82d2f21eSSasha Levin thread_pool__do_job(bdev.jobs[queue_index]); 200*82d2f21eSSasha Levin break; 201*82d2f21eSSasha Levin } 202*82d2f21eSSasha Levin case VIRTIO_PCI_STATUS: 203*82d2f21eSSasha Levin bdev.status = ioport__read8(data); 204*82d2f21eSSasha Levin break; 205*82d2f21eSSasha Levin case VIRTIO_MSI_CONFIG_VECTOR: 206*82d2f21eSSasha Levin bdev.config_vector = VIRTIO_MSI_NO_VECTOR; 207*82d2f21eSSasha Levin break; 208*82d2f21eSSasha Levin default: 209*82d2f21eSSasha Levin ret = virtio_bln_dev_out(data, offset, size, count); 210*82d2f21eSSasha Levin break; 211*82d2f21eSSasha Levin }; 212*82d2f21eSSasha Levin 213*82d2f21eSSasha Levin return ret; 214*82d2f21eSSasha Levin } 215*82d2f21eSSasha Levin 216*82d2f21eSSasha Levin static struct ioport_operations virtio_bln_io_ops = { 217*82d2f21eSSasha Levin .io_in = virtio_bln_pci_io_in, 218*82d2f21eSSasha Levin .io_out = virtio_bln_pci_io_out, 219*82d2f21eSSasha Levin }; 220*82d2f21eSSasha Levin 221*82d2f21eSSasha Levin static void handle_sigmem(int sig) 222*82d2f21eSSasha Levin { 223*82d2f21eSSasha Levin if (sig == SIGKVMADDMEM) 224*82d2f21eSSasha Levin bdev.config.num_pages += 256; 225*82d2f21eSSasha Levin else 226*82d2f21eSSasha Levin bdev.config.num_pages -= 256; 227*82d2f21eSSasha Levin 228*82d2f21eSSasha Levin /* Notify that the configuration space has changed */ 229*82d2f21eSSasha Levin bdev.isr = VIRTIO_PCI_ISR_CONFIG; 230*82d2f21eSSasha Levin kvm__irq_line(kvm, bdev.pci_hdr.irq_line, 1); 231*82d2f21eSSasha Levin } 232*82d2f21eSSasha Levin 233*82d2f21eSSasha Levin void virtio_bln__init(struct kvm *kvm) 234*82d2f21eSSasha Levin { 235*82d2f21eSSasha Levin u8 pin, line, dev; 236*82d2f21eSSasha Levin u16 bdev_base_addr; 237*82d2f21eSSasha Levin 238*82d2f21eSSasha Levin signal(SIGKVMADDMEM, handle_sigmem); 239*82d2f21eSSasha Levin signal(SIGKVMDELMEM, handle_sigmem); 240*82d2f21eSSasha Levin 241*82d2f21eSSasha Levin bdev_base_addr = ioport__register(IOPORT_EMPTY, &virtio_bln_io_ops, IOPORT_SIZE, &bdev); 242*82d2f21eSSasha Levin 243*82d2f21eSSasha Levin bdev.pci_hdr = (struct pci_device_header) { 244*82d2f21eSSasha Levin .vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET, 245*82d2f21eSSasha Levin .device_id = PCI_DEVICE_ID_VIRTIO_BLN, 246*82d2f21eSSasha Levin .header_type = PCI_HEADER_TYPE_NORMAL, 247*82d2f21eSSasha Levin .revision_id = 0, 248*82d2f21eSSasha Levin .class = 0x010000, 249*82d2f21eSSasha Levin .subsys_vendor_id = PCI_SUBSYSTEM_VENDOR_ID_REDHAT_QUMRANET, 250*82d2f21eSSasha Levin .subsys_id = VIRTIO_ID_BALLOON, 251*82d2f21eSSasha Levin .bar[0] = bdev_base_addr | PCI_BASE_ADDRESS_SPACE_IO, 252*82d2f21eSSasha Levin }; 253*82d2f21eSSasha Levin 254*82d2f21eSSasha Levin bdev.base_addr = bdev_base_addr; 255*82d2f21eSSasha Levin 256*82d2f21eSSasha Levin if (irq__register_device(VIRTIO_ID_RNG, &dev, &pin, &line) < 0) 257*82d2f21eSSasha Levin return; 258*82d2f21eSSasha Levin 259*82d2f21eSSasha Levin bdev.pci_hdr.irq_pin = pin; 260*82d2f21eSSasha Levin bdev.pci_hdr.irq_line = line; 261*82d2f21eSSasha Levin bdev.host_features = 0; 262*82d2f21eSSasha Levin memset(&bdev.config, 0, sizeof(struct virtio_balloon_config)); 263*82d2f21eSSasha Levin 264*82d2f21eSSasha Levin pci__register(&bdev.pci_hdr, dev); 265*82d2f21eSSasha Levin } 266