1029cd2bbSJean-Philippe Brucker #include "kvm/irq.h" 2745221e5SJean-Philippe Brucker #include "kvm/virtio.h" 3*46aaf3b8SJean-Philippe Brucker #include "kvm/epoll.h" 4745221e5SJean-Philippe Brucker 5f84ab9ebSJean-Philippe Brucker #include <linux/kvm.h> 6f84ab9ebSJean-Philippe Brucker #include <linux/vhost.h> 7f84ab9ebSJean-Philippe Brucker #include <linux/list.h> 8f84ab9ebSJean-Philippe Brucker 9029cd2bbSJean-Philippe Brucker #include <sys/eventfd.h> 10029cd2bbSJean-Philippe Brucker 11*46aaf3b8SJean-Philippe Brucker static struct kvm__epoll epoll; 12*46aaf3b8SJean-Philippe Brucker 13*46aaf3b8SJean-Philippe Brucker static void virtio_vhost_signal_vq(struct kvm *kvm, struct epoll_event *ev) 14*46aaf3b8SJean-Philippe Brucker { 15*46aaf3b8SJean-Philippe Brucker int r; 16*46aaf3b8SJean-Philippe Brucker u64 tmp; 17*46aaf3b8SJean-Philippe Brucker struct virt_queue *queue = ev->data.ptr; 18*46aaf3b8SJean-Philippe Brucker 19*46aaf3b8SJean-Philippe Brucker if (read(queue->irqfd, &tmp, sizeof(tmp)) < 0) 20*46aaf3b8SJean-Philippe Brucker pr_warning("%s: failed to read eventfd", __func__); 21*46aaf3b8SJean-Philippe Brucker 22*46aaf3b8SJean-Philippe Brucker r = queue->vdev->ops->signal_vq(kvm, queue->vdev, queue->index); 23*46aaf3b8SJean-Philippe Brucker if (r) 24*46aaf3b8SJean-Philippe Brucker pr_warning("%s failed to signal virtqueue", __func__); 25*46aaf3b8SJean-Philippe Brucker } 26*46aaf3b8SJean-Philippe Brucker 27*46aaf3b8SJean-Philippe Brucker static int virtio_vhost_start_poll(struct kvm *kvm) 28*46aaf3b8SJean-Philippe Brucker { 29*46aaf3b8SJean-Philippe Brucker if (epoll.fd) 30*46aaf3b8SJean-Philippe Brucker return 0; 31*46aaf3b8SJean-Philippe Brucker 32*46aaf3b8SJean-Philippe Brucker if (epoll__init(kvm, &epoll, "vhost-irq-worker", 33*46aaf3b8SJean-Philippe Brucker virtio_vhost_signal_vq)) 34*46aaf3b8SJean-Philippe Brucker return -1; 35*46aaf3b8SJean-Philippe Brucker 36*46aaf3b8SJean-Philippe Brucker return 0; 37*46aaf3b8SJean-Philippe Brucker } 38*46aaf3b8SJean-Philippe Brucker 39*46aaf3b8SJean-Philippe Brucker static int virtio_vhost_stop_poll(struct kvm *kvm) 40*46aaf3b8SJean-Philippe Brucker { 41*46aaf3b8SJean-Philippe Brucker if (epoll.fd) 42*46aaf3b8SJean-Philippe Brucker epoll__exit(&epoll); 43*46aaf3b8SJean-Philippe Brucker return 0; 44*46aaf3b8SJean-Philippe Brucker } 45*46aaf3b8SJean-Philippe Brucker base_exit(virtio_vhost_stop_poll); 46*46aaf3b8SJean-Philippe Brucker 47f84ab9ebSJean-Philippe Brucker void virtio_vhost_init(struct kvm *kvm, int vhost_fd) 48f84ab9ebSJean-Philippe Brucker { 49f84ab9ebSJean-Philippe Brucker struct kvm_mem_bank *bank; 50f84ab9ebSJean-Philippe Brucker struct vhost_memory *mem; 51f84ab9ebSJean-Philippe Brucker int i = 0, r; 52f84ab9ebSJean-Philippe Brucker 53*46aaf3b8SJean-Philippe Brucker r = virtio_vhost_start_poll(kvm); 54*46aaf3b8SJean-Philippe Brucker if (r) 55*46aaf3b8SJean-Philippe Brucker die("Unable to start vhost polling thread\n"); 56*46aaf3b8SJean-Philippe Brucker 57f84ab9ebSJean-Philippe Brucker mem = calloc(1, sizeof(*mem) + 58f84ab9ebSJean-Philippe Brucker kvm->mem_slots * sizeof(struct vhost_memory_region)); 59f84ab9ebSJean-Philippe Brucker if (mem == NULL) 60f84ab9ebSJean-Philippe Brucker die("Failed allocating memory for vhost memory map"); 61f84ab9ebSJean-Philippe Brucker 62f84ab9ebSJean-Philippe Brucker list_for_each_entry(bank, &kvm->mem_banks, list) { 63f84ab9ebSJean-Philippe Brucker mem->regions[i] = (struct vhost_memory_region) { 64f84ab9ebSJean-Philippe Brucker .guest_phys_addr = bank->guest_phys_addr, 65f84ab9ebSJean-Philippe Brucker .memory_size = bank->size, 66f84ab9ebSJean-Philippe Brucker .userspace_addr = (unsigned long)bank->host_addr, 67f84ab9ebSJean-Philippe Brucker }; 68f84ab9ebSJean-Philippe Brucker i++; 69f84ab9ebSJean-Philippe Brucker } 70f84ab9ebSJean-Philippe Brucker mem->nregions = i; 71f84ab9ebSJean-Philippe Brucker 72f84ab9ebSJean-Philippe Brucker r = ioctl(vhost_fd, VHOST_SET_OWNER); 73f84ab9ebSJean-Philippe Brucker if (r != 0) 74f84ab9ebSJean-Philippe Brucker die_perror("VHOST_SET_OWNER failed"); 75f84ab9ebSJean-Philippe Brucker 76f84ab9ebSJean-Philippe Brucker r = ioctl(vhost_fd, VHOST_SET_MEM_TABLE, mem); 77f84ab9ebSJean-Philippe Brucker if (r != 0) 78f84ab9ebSJean-Philippe Brucker die_perror("VHOST_SET_MEM_TABLE failed"); 79f84ab9ebSJean-Philippe Brucker 80f84ab9ebSJean-Philippe Brucker free(mem); 81f84ab9ebSJean-Philippe Brucker } 82745221e5SJean-Philippe Brucker 83*46aaf3b8SJean-Philippe Brucker static int virtio_vhost_get_irqfd(struct virt_queue *queue) 84*46aaf3b8SJean-Philippe Brucker { 85*46aaf3b8SJean-Philippe Brucker if (!queue->irqfd) { 86*46aaf3b8SJean-Philippe Brucker queue->irqfd = eventfd(0, 0); 87*46aaf3b8SJean-Philippe Brucker if (queue->irqfd < 0) 88*46aaf3b8SJean-Philippe Brucker die_perror("eventfd()"); 89*46aaf3b8SJean-Philippe Brucker } 90*46aaf3b8SJean-Philippe Brucker return queue->irqfd; 91*46aaf3b8SJean-Philippe Brucker } 92*46aaf3b8SJean-Philippe Brucker 93745221e5SJean-Philippe Brucker void virtio_vhost_set_vring(struct kvm *kvm, int vhost_fd, u32 index, 94745221e5SJean-Philippe Brucker struct virt_queue *queue) 95745221e5SJean-Philippe Brucker { 96745221e5SJean-Philippe Brucker int r; 97745221e5SJean-Philippe Brucker struct vhost_vring_addr addr = { 98745221e5SJean-Philippe Brucker .index = index, 99745221e5SJean-Philippe Brucker .desc_user_addr = (u64)(unsigned long)queue->vring.desc, 100745221e5SJean-Philippe Brucker .avail_user_addr = (u64)(unsigned long)queue->vring.avail, 101745221e5SJean-Philippe Brucker .used_user_addr = (u64)(unsigned long)queue->vring.used, 102745221e5SJean-Philippe Brucker }; 103745221e5SJean-Philippe Brucker struct vhost_vring_state state = { .index = index }; 104*46aaf3b8SJean-Philippe Brucker struct vhost_vring_file file = { 105*46aaf3b8SJean-Philippe Brucker .index = index, 106*46aaf3b8SJean-Philippe Brucker .fd = virtio_vhost_get_irqfd(queue), 107*46aaf3b8SJean-Philippe Brucker }; 108*46aaf3b8SJean-Philippe Brucker struct epoll_event event = { 109*46aaf3b8SJean-Philippe Brucker .events = EPOLLIN, 110*46aaf3b8SJean-Philippe Brucker .data.ptr = queue, 111*46aaf3b8SJean-Philippe Brucker }; 112*46aaf3b8SJean-Philippe Brucker 113*46aaf3b8SJean-Philippe Brucker queue->index = index; 114745221e5SJean-Philippe Brucker 115745221e5SJean-Philippe Brucker if (queue->endian != VIRTIO_ENDIAN_HOST) 116745221e5SJean-Philippe Brucker die("VHOST requires the same endianness in guest and host"); 117745221e5SJean-Philippe Brucker 118745221e5SJean-Philippe Brucker state.num = queue->vring.num; 119745221e5SJean-Philippe Brucker r = ioctl(vhost_fd, VHOST_SET_VRING_NUM, &state); 120745221e5SJean-Philippe Brucker if (r < 0) 121745221e5SJean-Philippe Brucker die_perror("VHOST_SET_VRING_NUM failed"); 122745221e5SJean-Philippe Brucker 123745221e5SJean-Philippe Brucker state.num = 0; 124745221e5SJean-Philippe Brucker r = ioctl(vhost_fd, VHOST_SET_VRING_BASE, &state); 125745221e5SJean-Philippe Brucker if (r < 0) 126745221e5SJean-Philippe Brucker die_perror("VHOST_SET_VRING_BASE failed"); 127745221e5SJean-Philippe Brucker 128745221e5SJean-Philippe Brucker r = ioctl(vhost_fd, VHOST_SET_VRING_ADDR, &addr); 129745221e5SJean-Philippe Brucker if (r < 0) 130745221e5SJean-Philippe Brucker die_perror("VHOST_SET_VRING_ADDR failed"); 131*46aaf3b8SJean-Philippe Brucker 132*46aaf3b8SJean-Philippe Brucker r = ioctl(vhost_fd, VHOST_SET_VRING_CALL, &file); 133*46aaf3b8SJean-Philippe Brucker if (r < 0) 134*46aaf3b8SJean-Philippe Brucker die_perror("VHOST_SET_VRING_CALL failed"); 135*46aaf3b8SJean-Philippe Brucker 136*46aaf3b8SJean-Philippe Brucker r = epoll_ctl(epoll.fd, EPOLL_CTL_ADD, file.fd, &event); 137*46aaf3b8SJean-Philippe Brucker if (r < 0) 138*46aaf3b8SJean-Philippe Brucker die_perror("EPOLL_CTL_ADD vhost call fd"); 139745221e5SJean-Philippe Brucker } 140676c0c8aSJean-Philippe Brucker 141676c0c8aSJean-Philippe Brucker void virtio_vhost_set_vring_kick(struct kvm *kvm, int vhost_fd, 142676c0c8aSJean-Philippe Brucker u32 index, int event_fd) 143676c0c8aSJean-Philippe Brucker { 144676c0c8aSJean-Philippe Brucker int r; 145676c0c8aSJean-Philippe Brucker struct vhost_vring_file file = { 146676c0c8aSJean-Philippe Brucker .index = index, 147676c0c8aSJean-Philippe Brucker .fd = event_fd, 148676c0c8aSJean-Philippe Brucker }; 149676c0c8aSJean-Philippe Brucker 150676c0c8aSJean-Philippe Brucker r = ioctl(vhost_fd, VHOST_SET_VRING_KICK, &file); 151676c0c8aSJean-Philippe Brucker if (r < 0) 152676c0c8aSJean-Philippe Brucker die_perror("VHOST_SET_VRING_KICK failed"); 153676c0c8aSJean-Philippe Brucker } 154029cd2bbSJean-Philippe Brucker 155*46aaf3b8SJean-Philippe Brucker void virtio_vhost_set_vring_irqfd(struct kvm *kvm, u32 gsi, 156*46aaf3b8SJean-Philippe Brucker struct virt_queue *queue) 157029cd2bbSJean-Philippe Brucker { 158029cd2bbSJean-Philippe Brucker int r; 159*46aaf3b8SJean-Philippe Brucker int fd = virtio_vhost_get_irqfd(queue); 160029cd2bbSJean-Philippe Brucker 161*46aaf3b8SJean-Philippe Brucker if (queue->gsi) 162*46aaf3b8SJean-Philippe Brucker irq__del_irqfd(kvm, queue->gsi, fd); 163*46aaf3b8SJean-Philippe Brucker else 164*46aaf3b8SJean-Philippe Brucker /* Disconnect user polling thread */ 165*46aaf3b8SJean-Philippe Brucker epoll_ctl(epoll.fd, EPOLL_CTL_DEL, fd, NULL); 166*46aaf3b8SJean-Philippe Brucker 167*46aaf3b8SJean-Philippe Brucker /* Connect the direct IRQFD route */ 168*46aaf3b8SJean-Philippe Brucker r = irq__add_irqfd(kvm, gsi, fd, -1); 169029cd2bbSJean-Philippe Brucker if (r < 0) 170029cd2bbSJean-Philippe Brucker die_perror("KVM_IRQFD failed"); 171029cd2bbSJean-Philippe Brucker 172029cd2bbSJean-Philippe Brucker queue->gsi = gsi; 173029cd2bbSJean-Philippe Brucker } 174029cd2bbSJean-Philippe Brucker 175029cd2bbSJean-Philippe Brucker void virtio_vhost_reset_vring(struct kvm *kvm, int vhost_fd, u32 index, 176029cd2bbSJean-Philippe Brucker struct virt_queue *queue) 177029cd2bbSJean-Philippe Brucker 178029cd2bbSJean-Philippe Brucker { 179*46aaf3b8SJean-Philippe Brucker struct vhost_vring_file file = { 180*46aaf3b8SJean-Philippe Brucker .index = index, 181*46aaf3b8SJean-Philippe Brucker .fd = -1, 182*46aaf3b8SJean-Philippe Brucker }; 183*46aaf3b8SJean-Philippe Brucker 184*46aaf3b8SJean-Philippe Brucker if (!queue->irqfd) 185*46aaf3b8SJean-Philippe Brucker return; 186*46aaf3b8SJean-Philippe Brucker 187029cd2bbSJean-Philippe Brucker if (queue->gsi) { 188029cd2bbSJean-Philippe Brucker irq__del_irqfd(kvm, queue->gsi, queue->irqfd); 189*46aaf3b8SJean-Philippe Brucker queue->gsi = 0; 190029cd2bbSJean-Philippe Brucker } 191*46aaf3b8SJean-Philippe Brucker 192*46aaf3b8SJean-Philippe Brucker epoll_ctl(epoll.fd, EPOLL_CTL_DEL, queue->irqfd, NULL); 193*46aaf3b8SJean-Philippe Brucker 194*46aaf3b8SJean-Philippe Brucker if (ioctl(vhost_fd, VHOST_SET_VRING_CALL, &file)) 195*46aaf3b8SJean-Philippe Brucker perror("SET_VRING_CALL"); 196*46aaf3b8SJean-Philippe Brucker close(queue->irqfd); 197*46aaf3b8SJean-Philippe Brucker queue->irqfd = 0; 198029cd2bbSJean-Philippe Brucker } 199