Signed-off-by: Sasha Levin <levinsasha928@xxxxxxxxx> --- tools/kvm/virtio/balloon.c | 267 ++++++++++++++++---------------------------- 1 files changed, 97 insertions(+), 170 deletions(-) diff --git a/tools/kvm/virtio/balloon.c b/tools/kvm/virtio/balloon.c index 7f3fe65..6b93121 100644 --- a/tools/kvm/virtio/balloon.c +++ b/tools/kvm/virtio/balloon.c @@ -2,24 +2,24 @@ #include "kvm/virtio-pci-dev.h" -#include "kvm/disk-image.h" #include "kvm/virtio.h" -#include "kvm/ioport.h" #include "kvm/util.h" #include "kvm/kvm.h" #include "kvm/pci.h" #include "kvm/threadpool.h" -#include "kvm/irq.h" #include "kvm/ioeventfd.h" #include "kvm/guest_compat.h" +#include "kvm/virtio-pci.h" #include <linux/virtio_ring.h> #include <linux/virtio_balloon.h> +#include <linux/kernel.h> #include <linux/list.h> #include <fcntl.h> #include <sys/types.h> #include <sys/stat.h> +#include <sys/mman.h> #include <pthread.h> #define NUM_VIRT_QUEUES 3 @@ -29,17 +29,12 @@ #define VIRTIO_BLN_STATS 2 struct bln_dev { - struct pci_device_header pci_hdr; struct list_head list; + struct virtio_pci vpci; - u16 base_addr; - u8 status; - u8 isr; - u16 config_vector; - u32 host_features; + u32 features; /* virtio queue */ - u16 queue_selector; struct virt_queue vqs[NUM_VIRT_QUEUES]; struct thread_pool__job jobs[NUM_VIRT_QUEUES]; @@ -56,68 +51,6 @@ struct bln_dev { static struct bln_dev bdev; extern struct kvm *kvm; -static bool virtio_bln_dev_in(void *data, unsigned long offset, int size) -{ - u8 *config_space = (u8 *) &bdev.config; - - if (size != 1) - return false; - - ioport__write8(data, config_space[offset - VIRTIO_MSI_CONFIG_VECTOR]); - - return true; -} - -static bool virtio_bln_dev_out(void *data, unsigned long offset, int size) -{ - u8 *config_space = (u8 *) &bdev.config; - - if (size != 1) - return false; - - config_space[offset - VIRTIO_MSI_CONFIG_VECTOR] = *(u8 *)data; - - return true; -} - -static bool virtio_bln_pci_io_in(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size) -{ - unsigned long offset; - bool ret = true; - - offset = port - bdev.base_addr; - - switch (offset) { - case VIRTIO_PCI_HOST_FEATURES: - ioport__write32(data, bdev.host_features); - break; - case VIRTIO_PCI_GUEST_FEATURES: - case VIRTIO_PCI_QUEUE_SEL: - case VIRTIO_PCI_QUEUE_NOTIFY: - ret = false; - break; - case VIRTIO_PCI_QUEUE_PFN: - ioport__write32(data, bdev.vqs[bdev.queue_selector].pfn); - break; - case VIRTIO_PCI_QUEUE_NUM: - ioport__write16(data, VIRTIO_BLN_QUEUE_SIZE); - break; - case VIRTIO_PCI_STATUS: - ioport__write8(data, bdev.status); - break; - case VIRTIO_PCI_ISR: - ioport__write8(data, bdev.isr); - kvm__irq_line(kvm, bdev.pci_hdr.irq_line, VIRTIO_IRQ_LOW); - bdev.isr = VIRTIO_IRQ_LOW; - break; - default: - ret = virtio_bln_dev_in(data, offset, size); - break; - }; - - return ret; -} - static bool virtio_bln_do_io_request(struct kvm *kvm, struct bln_dev *bdev, struct virt_queue *queue) { struct iovec iov[VIRTIO_BLN_QUEUE_SIZE]; @@ -182,13 +115,13 @@ static void virtio_bln_do_io(struct kvm *kvm, void *param) if (vq == &bdev.vqs[VIRTIO_BLN_STATS]) { virtio_bln_do_stat_request(kvm, &bdev, vq); - virt_queue__trigger_irq(vq, bdev.pci_hdr.irq_line, &bdev.isr, kvm); + virtio_pci__signal_vq(kvm, &bdev.vpci, VIRTIO_BLN_STATS); return; } while (virt_queue__available(vq)) { virtio_bln_do_io_request(kvm, &bdev, vq); - virt_queue__trigger_irq(vq, bdev.pci_hdr.irq_line, &bdev.isr, kvm); + virtio_pci__signal_vq(kvm, &bdev.vpci, vq - bdev.vqs); } } @@ -197,82 +130,13 @@ static void ioevent_callback(struct kvm *kvm, void *param) thread_pool__do_job(param); } -static bool virtio_bln_pci_io_out(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size) -{ - unsigned long offset; - bool ret = true; - struct ioevent ioevent; - - offset = port - bdev.base_addr; - - switch (offset) { - case VIRTIO_MSI_QUEUE_VECTOR: - case VIRTIO_PCI_GUEST_FEATURES: - break; - case VIRTIO_PCI_QUEUE_PFN: { - struct virt_queue *queue; - void *p; - - compat__remove_message(bdev.compat_id); - - queue = &bdev.vqs[bdev.queue_selector]; - queue->pfn = ioport__read32(data); - p = guest_pfn_to_host(kvm, queue->pfn); - - vring_init(&queue->vring, VIRTIO_BLN_QUEUE_SIZE, p, VIRTIO_PCI_VRING_ALIGN); - - thread_pool__init_job(&bdev.jobs[bdev.queue_selector], kvm, virtio_bln_do_io, queue); - - ioevent = (struct ioevent) { - .io_addr = bdev.base_addr + VIRTIO_PCI_QUEUE_NOTIFY, - .io_len = sizeof(u16), - .fn = ioevent_callback, - .fn_ptr = &bdev.jobs[bdev.queue_selector], - .datamatch = bdev.queue_selector, - .fn_kvm = kvm, - .fd = eventfd(0, 0), - }; - - ioeventfd__add_event(&ioevent); - - break; - } - case VIRTIO_PCI_QUEUE_SEL: - bdev.queue_selector = ioport__read16(data); - break; - case VIRTIO_PCI_QUEUE_NOTIFY: { - u16 queue_index; - queue_index = ioport__read16(data); - thread_pool__do_job(&bdev.jobs[queue_index]); - break; - } - case VIRTIO_PCI_STATUS: - bdev.status = ioport__read8(data); - break; - case VIRTIO_MSI_CONFIG_VECTOR: - bdev.config_vector = VIRTIO_MSI_NO_VECTOR; - break; - default: - ret = virtio_bln_dev_out(data, offset, size); - break; - }; - - return ret; -} - -static struct ioport_operations virtio_bln_io_ops = { - .io_in = virtio_bln_pci_io_in, - .io_out = virtio_bln_pci_io_out, -}; - static int virtio_bln__collect_stats(void) { u64 tmp; virt_queue__set_used_elem(&bdev.vqs[VIRTIO_BLN_STATS], bdev.cur_stat_head, sizeof(struct virtio_balloon_stat)); - virt_queue__trigger_irq(&bdev.vqs[VIRTIO_BLN_STATS], bdev.pci_hdr.irq_line, - &bdev.isr, kvm); + virtio_pci__signal_vq(kvm, &bdev.vpci, VIRTIO_BLN_STATS); if (read(bdev.stat_waitfd, &tmp, sizeof(tmp)) <= 0) return -EFAULT; @@ -332,44 +196,107 @@ static void handle_sigmem(int sig) } /* Notify that the configuration space has changed */ - bdev.isr = VIRTIO_PCI_ISR_CONFIG; - kvm__irq_line(kvm, bdev.pci_hdr.irq_line, 1); + virtio_pci__signal_config(kvm, &bdev.vpci); } -void virtio_bln__init(struct kvm *kvm) +static void set_config(struct kvm *kvm, void *dev, u8 data, u32 offset) { - u8 pin, line, dev; - u16 bdev_base_addr; + struct bln_dev *bdev = dev; - signal(SIGKVMADDMEM, handle_sigmem); - signal(SIGKVMDELMEM, handle_sigmem); - signal(SIGKVMMEMSTAT, handle_sigmem); + ((u8 *)(&bdev->config))[offset] = data; +} + +static u8 get_config(struct kvm *kvm, void *dev, u32 offset) +{ + struct bln_dev *bdev = dev; - bdev_base_addr = ioport__register(IOPORT_EMPTY, &virtio_bln_io_ops, IOPORT_SIZE, &bdev); - - bdev.pci_hdr = (struct pci_device_header) { - .vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET, - .device_id = PCI_DEVICE_ID_VIRTIO_BLN, - .header_type = PCI_HEADER_TYPE_NORMAL, - .revision_id = 0, - .class = 0x010000, - .subsys_vendor_id = PCI_SUBSYSTEM_VENDOR_ID_REDHAT_QUMRANET, - .subsys_id = VIRTIO_ID_BALLOON, - .bar[0] = bdev_base_addr | PCI_BASE_ADDRESS_SPACE_IO, + return ((u8 *)(&bdev->config))[offset]; +} + +static u32 get_host_features(struct kvm *kvm, void *dev) +{ + return 1 << VIRTIO_BALLOON_F_STATS_VQ; +} + +static void set_guest_features(struct kvm *kvm, void *dev, u32 features) +{ + struct bln_dev *bdev = dev; + + bdev->features = features; +} + +static int init_vq(struct kvm *kvm, void *dev, u32 vq, u32 pfn) +{ + struct bln_dev *bdev = dev; + struct virt_queue *queue; + void *p; + struct ioevent ioevent; + + compat__remove_message(bdev->compat_id); + + queue = &bdev->vqs[vq]; + queue->pfn = pfn; + p = guest_pfn_to_host(kvm, queue->pfn); + + thread_pool__init_job(&bdev->jobs[vq], kvm, virtio_bln_do_io, queue); + vring_init(&queue->vring, VIRTIO_BLN_QUEUE_SIZE, p, VIRTIO_PCI_VRING_ALIGN); + + ioevent = (struct ioevent) { + .io_addr = bdev->vpci.base_addr + VIRTIO_PCI_QUEUE_NOTIFY, + .io_len = sizeof(u16), + .fn = ioevent_callback, + .fn_ptr = &bdev->jobs[vq], + .datamatch = vq, + .fn_kvm = kvm, + .fd = eventfd(0, 0), }; - bdev.base_addr = bdev_base_addr; + ioeventfd__add_event(&ioevent); - if (irq__register_device(VIRTIO_ID_BALLOON, &dev, &pin, &line) < 0) - return; + return 0; +} + +static int notify_vq(struct kvm *kvm, void *dev, u32 vq) +{ + struct bln_dev *bdev = dev; + + thread_pool__do_job(&bdev->jobs[vq]); + + return 0; +} + +static int get_pfn_vq(struct kvm *kvm, void *dev, u32 vq) +{ + struct bln_dev *bdev = dev; + + return bdev->vqs[vq].pfn; +} + +static int get_size_vq(struct kvm *kvm, void *dev, u32 vq) +{ + return VIRTIO_BLN_QUEUE_SIZE; +} + +void virtio_bln__init(struct kvm *kvm) +{ + signal(SIGKVMADDMEM, handle_sigmem); + signal(SIGKVMDELMEM, handle_sigmem); + signal(SIGKVMMEMSTAT, handle_sigmem); - bdev.pci_hdr.irq_pin = pin; - bdev.pci_hdr.irq_line = line; - bdev.host_features = 1 << VIRTIO_BALLOON_F_STATS_VQ; bdev.stat_waitfd = eventfd(0, 0); memset(&bdev.config, 0, sizeof(struct virtio_balloon_config)); - pci__register(&bdev.pci_hdr, dev); + virtio_pci__init(kvm, &bdev.vpci, &bdev, PCI_DEVICE_ID_VIRTIO_BLN, VIRTIO_ID_BALLOON); + bdev.vpci.ops = (struct virtio_pci_ops) { + .set_config = set_config, + .get_config = get_config, + .get_host_features = get_host_features, + .set_guest_features = set_guest_features, + .init_vq = init_vq, + .notify_vq = notify_vq, + .get_pfn_vq = get_pfn_vq, + .get_size_vq = get_size_vq, + }; bdev.compat_id = compat__add_message("virtio-balloon device was not detected", "While you have requested a virtio-balloon device, " -- 1.7.6 -- To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html