121ff329dSWill Deacon #include "kvm/devices.h" 260273720SAsias He #include "kvm/virtio-mmio.h" 360273720SAsias He #include "kvm/ioeventfd.h" 460273720SAsias He #include "kvm/ioport.h" 560273720SAsias He #include "kvm/virtio.h" 660273720SAsias He #include "kvm/kvm.h" 719d98215SMarc Zyngier #include "kvm/kvm-cpu.h" 860273720SAsias He #include "kvm/irq.h" 92454c7dcSWill Deacon #include "kvm/fdt.h" 1060273720SAsias He 1160273720SAsias He #include <linux/virtio_mmio.h> 1260273720SAsias He #include <string.h> 1360273720SAsias He 1460273720SAsias He static u32 virtio_mmio_io_space_blocks = KVM_VIRTIO_MMIO_AREA; 1560273720SAsias He 1660273720SAsias He static u32 virtio_mmio_get_io_space_block(u32 size) 1760273720SAsias He { 1860273720SAsias He u32 block = virtio_mmio_io_space_blocks; 1960273720SAsias He virtio_mmio_io_space_blocks += size; 2060273720SAsias He 2160273720SAsias He return block; 2260273720SAsias He } 2360273720SAsias He 2460273720SAsias He static void virtio_mmio_ioevent_callback(struct kvm *kvm, void *param) 2560273720SAsias He { 2660273720SAsias He struct virtio_mmio_ioevent_param *ioeventfd = param; 2760273720SAsias He struct virtio_mmio *vmmio = ioeventfd->vdev->virtio; 2860273720SAsias He 2960273720SAsias He ioeventfd->vdev->ops->notify_vq(kvm, vmmio->dev, ioeventfd->vq); 3060273720SAsias He } 3160273720SAsias He 3260273720SAsias He static int virtio_mmio_init_ioeventfd(struct kvm *kvm, 3360273720SAsias He struct virtio_device *vdev, u32 vq) 3460273720SAsias He { 3560273720SAsias He struct virtio_mmio *vmmio = vdev->virtio; 3660273720SAsias He struct ioevent ioevent; 3760273720SAsias He int err; 3860273720SAsias He 3960273720SAsias He vmmio->ioeventfds[vq] = (struct virtio_mmio_ioevent_param) { 4060273720SAsias He .vdev = vdev, 4160273720SAsias He .vq = vq, 4260273720SAsias He }; 4360273720SAsias He 4460273720SAsias He ioevent = (struct ioevent) { 4560273720SAsias He .io_addr = vmmio->addr + VIRTIO_MMIO_QUEUE_NOTIFY, 4660273720SAsias He .io_len = sizeof(u32), 4760273720SAsias He .fn = virtio_mmio_ioevent_callback, 4860273720SAsias He .fn_ptr = &vmmio->ioeventfds[vq], 4960273720SAsias He .datamatch = vq, 5060273720SAsias He .fn_kvm = kvm, 5160273720SAsias He .fd = eventfd(0, 0), 5260273720SAsias He }; 5360273720SAsias He 54627d6874SAsias He if (vdev->use_vhost) 55627d6874SAsias He /* 56627d6874SAsias He * Vhost will poll the eventfd in host kernel side, 57627d6874SAsias He * no need to poll in userspace. 58627d6874SAsias He */ 5927347f76SWill Deacon err = ioeventfd__add_event(&ioevent, 0); 60627d6874SAsias He else 61627d6874SAsias He /* Need to poll in userspace. */ 6227347f76SWill Deacon err = ioeventfd__add_event(&ioevent, IOEVENTFD_FLAG_USER_POLL); 6360273720SAsias He if (err) 6460273720SAsias He return err; 6560273720SAsias He 6660273720SAsias He if (vdev->ops->notify_vq_eventfd) 6760273720SAsias He vdev->ops->notify_vq_eventfd(kvm, vmmio->dev, vq, ioevent.fd); 6860273720SAsias He 6960273720SAsias He return 0; 7060273720SAsias He } 7160273720SAsias He 7260273720SAsias He int virtio_mmio_signal_vq(struct kvm *kvm, struct virtio_device *vdev, u32 vq) 7360273720SAsias He { 7460273720SAsias He struct virtio_mmio *vmmio = vdev->virtio; 7560273720SAsias He 7660273720SAsias He vmmio->hdr.interrupt_state |= VIRTIO_MMIO_INT_VRING; 7760273720SAsias He kvm__irq_trigger(vmmio->kvm, vmmio->irq); 7860273720SAsias He 7960273720SAsias He return 0; 8060273720SAsias He } 8160273720SAsias He 82ad346c2eSJean-Philippe Brucker static void virtio_mmio_exit_vq(struct kvm *kvm, struct virtio_device *vdev, 83ad346c2eSJean-Philippe Brucker int vq) 84ad346c2eSJean-Philippe Brucker { 85ad346c2eSJean-Philippe Brucker struct virtio_mmio *vmmio = vdev->virtio; 86ad346c2eSJean-Philippe Brucker 87ad346c2eSJean-Philippe Brucker ioeventfd__del_event(vmmio->addr + VIRTIO_MMIO_QUEUE_NOTIFY, vq); 88ad346c2eSJean-Philippe Brucker virtio_exit_vq(kvm, vdev, vmmio->dev, vq); 89ad346c2eSJean-Philippe Brucker } 90ad346c2eSJean-Philippe Brucker 9160273720SAsias He int virtio_mmio_signal_config(struct kvm *kvm, struct virtio_device *vdev) 9260273720SAsias He { 9360273720SAsias He struct virtio_mmio *vmmio = vdev->virtio; 9460273720SAsias He 9560273720SAsias He vmmio->hdr.interrupt_state |= VIRTIO_MMIO_INT_CONFIG; 9660273720SAsias He kvm__irq_trigger(vmmio->kvm, vmmio->irq); 9760273720SAsias He 9860273720SAsias He return 0; 9960273720SAsias He } 10060273720SAsias He 1019b735910SMarc Zyngier static void virtio_mmio_device_specific(struct kvm_cpu *vcpu, 1029b735910SMarc Zyngier u64 addr, u8 *data, u32 len, 10360273720SAsias He u8 is_write, struct virtio_device *vdev) 10460273720SAsias He { 10560273720SAsias He struct virtio_mmio *vmmio = vdev->virtio; 106e4730284SMartin Radev u8 *config; 107e4730284SMartin Radev size_t config_size; 10860273720SAsias He u32 i; 10960273720SAsias He 110e4730284SMartin Radev config = vdev->ops->get_config(vmmio->kvm, vmmio->dev); 111e4730284SMartin Radev config_size = vdev->ops->get_config_size(vmmio->kvm, vmmio->dev); 112e4730284SMartin Radev 113e4730284SMartin Radev /* Prevent invalid accesses which go beyond the config */ 114e4730284SMartin Radev if (config_size < addr + len) { 115e4730284SMartin Radev WARN_ONCE(1, "Offset (%llu) Length (%u) goes beyond config size (%zu).\n", 116e4730284SMartin Radev addr, len, config_size); 117e4730284SMartin Radev return; 118e4730284SMartin Radev } 119e4730284SMartin Radev 12060273720SAsias He for (i = 0; i < len; i++) { 12160273720SAsias He if (is_write) 122e4730284SMartin Radev config[addr + i] = *(u8 *)data + i; 12360273720SAsias He else 124e4730284SMartin Radev data[i] = config[addr + i]; 12560273720SAsias He } 12660273720SAsias He } 12760273720SAsias He 1289b735910SMarc Zyngier static void virtio_mmio_config_in(struct kvm_cpu *vcpu, 1299b735910SMarc Zyngier u64 addr, void *data, u32 len, 13060273720SAsias He struct virtio_device *vdev) 13160273720SAsias He { 13260273720SAsias He struct virtio_mmio *vmmio = vdev->virtio; 13353fbb17bSJean-Philippe Brucker struct virt_queue *vq; 13460273720SAsias He u32 val = 0; 13560273720SAsias He 13660273720SAsias He switch (addr) { 13760273720SAsias He case VIRTIO_MMIO_MAGIC_VALUE: 13860273720SAsias He case VIRTIO_MMIO_VERSION: 13960273720SAsias He case VIRTIO_MMIO_DEVICE_ID: 14060273720SAsias He case VIRTIO_MMIO_VENDOR_ID: 14160273720SAsias He case VIRTIO_MMIO_STATUS: 14260273720SAsias He case VIRTIO_MMIO_INTERRUPT_STATUS: 14360273720SAsias He ioport__write32(data, *(u32 *)(((void *)&vmmio->hdr) + addr)); 14460273720SAsias He break; 14560273720SAsias He case VIRTIO_MMIO_HOST_FEATURES: 14660273720SAsias He if (vmmio->hdr.host_features_sel == 0) 14760273720SAsias He val = vdev->ops->get_host_features(vmmio->kvm, 14860273720SAsias He vmmio->dev); 14960273720SAsias He ioport__write32(data, val); 15060273720SAsias He break; 15160273720SAsias He case VIRTIO_MMIO_QUEUE_PFN: 15253fbb17bSJean-Philippe Brucker vq = vdev->ops->get_vq(vmmio->kvm, vmmio->dev, 15360273720SAsias He vmmio->hdr.queue_sel); 15453fbb17bSJean-Philippe Brucker ioport__write32(data, vq->pfn); 15560273720SAsias He break; 15660273720SAsias He case VIRTIO_MMIO_QUEUE_NUM_MAX: 15760273720SAsias He val = vdev->ops->get_size_vq(vmmio->kvm, vmmio->dev, 15860273720SAsias He vmmio->hdr.queue_sel); 15960273720SAsias He ioport__write32(data, val); 16060273720SAsias He break; 16160273720SAsias He default: 16260273720SAsias He break; 16360273720SAsias He } 16460273720SAsias He } 16560273720SAsias He 1669b735910SMarc Zyngier static void virtio_mmio_config_out(struct kvm_cpu *vcpu, 1679b735910SMarc Zyngier u64 addr, void *data, u32 len, 16860273720SAsias He struct virtio_device *vdev) 16960273720SAsias He { 17060273720SAsias He struct virtio_mmio *vmmio = vdev->virtio; 171e2b98125SMarc Zyngier struct kvm *kvm = vmmio->kvm; 172*31e0eaccSMartin Radev unsigned int vq_count = vdev->ops->get_vq_count(kvm, vmmio->dev); 17360273720SAsias He u32 val = 0; 17460273720SAsias He 17560273720SAsias He switch (addr) { 17660273720SAsias He case VIRTIO_MMIO_HOST_FEATURES_SEL: 17760273720SAsias He case VIRTIO_MMIO_GUEST_FEATURES_SEL: 178*31e0eaccSMartin Radev val = ioport__read32(data); 179*31e0eaccSMartin Radev *(u32 *)(((void *)&vmmio->hdr) + addr) = val; 180*31e0eaccSMartin Radev break; 18160273720SAsias He case VIRTIO_MMIO_QUEUE_SEL: 18260273720SAsias He val = ioport__read32(data); 183*31e0eaccSMartin Radev if (val >= vq_count) { 184*31e0eaccSMartin Radev WARN_ONCE(1, "QUEUE_SEL value (%u) is larger than VQ count (%u)\n", 185*31e0eaccSMartin Radev val, vq_count); 186*31e0eaccSMartin Radev break; 187*31e0eaccSMartin Radev } 18860273720SAsias He *(u32 *)(((void *)&vmmio->hdr) + addr) = val; 18960273720SAsias He break; 190e2b98125SMarc Zyngier case VIRTIO_MMIO_STATUS: 191e2b98125SMarc Zyngier vmmio->hdr.status = ioport__read32(data); 19219d98215SMarc Zyngier if (!vmmio->hdr.status) /* Sample endianness on reset */ 19319d98215SMarc Zyngier vdev->endian = kvm_cpu__get_endianness(vcpu); 19495242e44SJean-Philippe Brucker virtio_notify_status(kvm, vdev, vmmio->dev, vmmio->hdr.status); 195e2b98125SMarc Zyngier break; 19660273720SAsias He case VIRTIO_MMIO_GUEST_FEATURES: 19760273720SAsias He if (vmmio->hdr.guest_features_sel == 0) { 19860273720SAsias He val = ioport__read32(data); 19956a16c90SJean-Philippe Brucker virtio_set_guest_features(vmmio->kvm, vdev, 20060273720SAsias He vmmio->dev, val); 20160273720SAsias He } 20260273720SAsias He break; 20360273720SAsias He case VIRTIO_MMIO_GUEST_PAGE_SIZE: 20460273720SAsias He val = ioport__read32(data); 20560273720SAsias He vmmio->hdr.guest_page_size = val; 20660273720SAsias He break; 20760273720SAsias He case VIRTIO_MMIO_QUEUE_NUM: 20860273720SAsias He val = ioport__read32(data); 20960273720SAsias He vmmio->hdr.queue_num = val; 21060273720SAsias He vdev->ops->set_size_vq(vmmio->kvm, vmmio->dev, 21160273720SAsias He vmmio->hdr.queue_sel, val); 21260273720SAsias He break; 21360273720SAsias He case VIRTIO_MMIO_QUEUE_ALIGN: 21460273720SAsias He val = ioport__read32(data); 21560273720SAsias He vmmio->hdr.queue_align = val; 21660273720SAsias He break; 21760273720SAsias He case VIRTIO_MMIO_QUEUE_PFN: 21860273720SAsias He val = ioport__read32(data); 219ad346c2eSJean-Philippe Brucker if (val) { 220ad346c2eSJean-Philippe Brucker virtio_mmio_init_ioeventfd(vmmio->kvm, vdev, 221ad346c2eSJean-Philippe Brucker vmmio->hdr.queue_sel); 22260273720SAsias He vdev->ops->init_vq(vmmio->kvm, vmmio->dev, 223c59ba304SWill Deacon vmmio->hdr.queue_sel, 224c59ba304SWill Deacon vmmio->hdr.guest_page_size, 225c59ba304SWill Deacon vmmio->hdr.queue_align, 226c59ba304SWill Deacon val); 227ad346c2eSJean-Philippe Brucker } else { 228ad346c2eSJean-Philippe Brucker virtio_mmio_exit_vq(kvm, vdev, vmmio->hdr.queue_sel); 229ad346c2eSJean-Philippe Brucker } 23060273720SAsias He break; 23160273720SAsias He case VIRTIO_MMIO_QUEUE_NOTIFY: 23260273720SAsias He val = ioport__read32(data); 233*31e0eaccSMartin Radev if (val >= vq_count) { 234*31e0eaccSMartin Radev WARN_ONCE(1, "QUEUE_NOTIFY value (%u) is larger than VQ count (%u)\n", 235*31e0eaccSMartin Radev val, vq_count); 236*31e0eaccSMartin Radev break; 237*31e0eaccSMartin Radev } 23860273720SAsias He vdev->ops->notify_vq(vmmio->kvm, vmmio->dev, val); 23960273720SAsias He break; 24060273720SAsias He case VIRTIO_MMIO_INTERRUPT_ACK: 24160273720SAsias He val = ioport__read32(data); 24260273720SAsias He vmmio->hdr.interrupt_state &= ~val; 24360273720SAsias He break; 24460273720SAsias He default: 24560273720SAsias He break; 24660273720SAsias He }; 24760273720SAsias He } 24860273720SAsias He 2499b735910SMarc Zyngier static void virtio_mmio_mmio_callback(struct kvm_cpu *vcpu, 2509b735910SMarc Zyngier u64 addr, u8 *data, u32 len, 25160273720SAsias He u8 is_write, void *ptr) 25260273720SAsias He { 25360273720SAsias He struct virtio_device *vdev = ptr; 25460273720SAsias He struct virtio_mmio *vmmio = vdev->virtio; 25560273720SAsias He u32 offset = addr - vmmio->addr; 25660273720SAsias He 25760273720SAsias He if (offset >= VIRTIO_MMIO_CONFIG) { 25860273720SAsias He offset -= VIRTIO_MMIO_CONFIG; 2599b735910SMarc Zyngier virtio_mmio_device_specific(vcpu, offset, data, len, is_write, ptr); 26060273720SAsias He return; 26160273720SAsias He } 26260273720SAsias He 26360273720SAsias He if (is_write) 2649b735910SMarc Zyngier virtio_mmio_config_out(vcpu, offset, data, len, ptr); 26560273720SAsias He else 2669b735910SMarc Zyngier virtio_mmio_config_in(vcpu, offset, data, len, ptr); 26760273720SAsias He } 26860273720SAsias He 2692454c7dcSWill Deacon #ifdef CONFIG_HAS_LIBFDT 2702454c7dcSWill Deacon #define DEVICE_NAME_MAX_LEN 32 2712bfd9ac3SAndre Przywara static 2722bfd9ac3SAndre Przywara void generate_virtio_mmio_fdt_node(void *fdt, 2732454c7dcSWill Deacon struct device_header *dev_hdr, 2742454c7dcSWill Deacon void (*generate_irq_prop)(void *fdt, 2752bfd9ac3SAndre Przywara u8 irq, 2762bfd9ac3SAndre Przywara enum irq_type)) 2772454c7dcSWill Deacon { 2782454c7dcSWill Deacon char dev_name[DEVICE_NAME_MAX_LEN]; 2792454c7dcSWill Deacon struct virtio_mmio *vmmio = container_of(dev_hdr, 2802454c7dcSWill Deacon struct virtio_mmio, 2812454c7dcSWill Deacon dev_hdr); 2822454c7dcSWill Deacon u64 addr = vmmio->addr; 2832454c7dcSWill Deacon u64 reg_prop[] = { 2842454c7dcSWill Deacon cpu_to_fdt64(addr), 2852454c7dcSWill Deacon cpu_to_fdt64(VIRTIO_MMIO_IO_SIZE), 2862454c7dcSWill Deacon }; 2872454c7dcSWill Deacon 2882454c7dcSWill Deacon snprintf(dev_name, DEVICE_NAME_MAX_LEN, "virtio@%llx", addr); 2892454c7dcSWill Deacon 2902454c7dcSWill Deacon _FDT(fdt_begin_node(fdt, dev_name)); 2912454c7dcSWill Deacon _FDT(fdt_property_string(fdt, "compatible", "virtio,mmio")); 2922454c7dcSWill Deacon _FDT(fdt_property(fdt, "reg", reg_prop, sizeof(reg_prop))); 2939a8af7e3SRobin Murphy _FDT(fdt_property(fdt, "dma-coherent", NULL, 0)); 2942bfd9ac3SAndre Przywara generate_irq_prop(fdt, vmmio->irq, IRQ_TYPE_EDGE_RISING); 2952454c7dcSWill Deacon _FDT(fdt_end_node(fdt)); 2962454c7dcSWill Deacon } 2972454c7dcSWill Deacon #else 2982454c7dcSWill Deacon static void generate_virtio_mmio_fdt_node(void *fdt, 2992454c7dcSWill Deacon struct device_header *dev_hdr, 3002454c7dcSWill Deacon void (*generate_irq_prop)(void *fdt, 3012454c7dcSWill Deacon u8 irq)) 3022454c7dcSWill Deacon { 3032454c7dcSWill Deacon die("Unable to generate device tree nodes without libfdt\n"); 3042454c7dcSWill Deacon } 3052454c7dcSWill Deacon #endif 3062454c7dcSWill Deacon 30760273720SAsias He int virtio_mmio_init(struct kvm *kvm, void *dev, struct virtio_device *vdev, 30860273720SAsias He int device_id, int subsys_id, int class) 30960273720SAsias He { 31060273720SAsias He struct virtio_mmio *vmmio = vdev->virtio; 3118f160708SAlexandru Elisei int r; 31260273720SAsias He 31360273720SAsias He vmmio->addr = virtio_mmio_get_io_space_block(VIRTIO_MMIO_IO_SIZE); 31460273720SAsias He vmmio->kvm = kvm; 31560273720SAsias He vmmio->dev = dev; 31660273720SAsias He 3178f160708SAlexandru Elisei r = kvm__register_mmio(kvm, vmmio->addr, VIRTIO_MMIO_IO_SIZE, 31860273720SAsias He false, virtio_mmio_mmio_callback, vdev); 3198f160708SAlexandru Elisei if (r < 0) 3208f160708SAlexandru Elisei return r; 32160273720SAsias He 32260273720SAsias He vmmio->hdr = (struct virtio_mmio_hdr) { 32360273720SAsias He .magic = {'v', 'i', 'r', 't'}, 32460273720SAsias He .version = 1, 325449d5eb3SWill Deacon .device_id = subsys_id, 32660273720SAsias He .vendor_id = 0x4d564b4c , /* 'LKVM' */ 32760273720SAsias He .queue_num_max = 256, 32860273720SAsias He }; 32960273720SAsias He 33021ff329dSWill Deacon vmmio->dev_hdr = (struct device_header) { 33121ff329dSWill Deacon .bus_type = DEVICE_BUS_MMIO, 3322454c7dcSWill Deacon .data = generate_virtio_mmio_fdt_node, 33321ff329dSWill Deacon }; 33421ff329dSWill Deacon 335af731be3SAndre Przywara vmmio->irq = irq__alloc_line(); 336af731be3SAndre Przywara 3378f160708SAlexandru Elisei r = device__register(&vmmio->dev_hdr); 3388f160708SAlexandru Elisei if (r < 0) { 3398f160708SAlexandru Elisei kvm__deregister_mmio(kvm, vmmio->addr); 3408f160708SAlexandru Elisei return r; 3418f160708SAlexandru Elisei } 34260273720SAsias He 34360273720SAsias He /* 34460273720SAsias He * Instantiate guest virtio-mmio devices using kernel command line 34560273720SAsias He * (or module) parameter, e.g 34660273720SAsias He * 34760273720SAsias He * virtio_mmio.devices=0x200@0xd2000000:5,0x200@0xd2000200:6 34860273720SAsias He */ 349e1c7c62aSAndre Przywara pr_debug("virtio-mmio.devices=0x%x@0x%x:%d", VIRTIO_MMIO_IO_SIZE, 350e1c7c62aSAndre Przywara vmmio->addr, vmmio->irq); 35160273720SAsias He 35260273720SAsias He return 0; 35360273720SAsias He } 35460273720SAsias He 355eb34a8c2SJean-Philippe Brucker int virtio_mmio_reset(struct kvm *kvm, struct virtio_device *vdev) 356eb34a8c2SJean-Philippe Brucker { 357*31e0eaccSMartin Radev unsigned int vq; 358eb34a8c2SJean-Philippe Brucker struct virtio_mmio *vmmio = vdev->virtio; 359eb34a8c2SJean-Philippe Brucker 360eb34a8c2SJean-Philippe Brucker for (vq = 0; vq < vdev->ops->get_vq_count(kvm, vmmio->dev); vq++) 361eb34a8c2SJean-Philippe Brucker virtio_mmio_exit_vq(kvm, vdev, vq); 362eb34a8c2SJean-Philippe Brucker 363eb34a8c2SJean-Philippe Brucker return 0; 364eb34a8c2SJean-Philippe Brucker } 365eb34a8c2SJean-Philippe Brucker 36660273720SAsias He int virtio_mmio_exit(struct kvm *kvm, struct virtio_device *vdev) 36760273720SAsias He { 36860273720SAsias He struct virtio_mmio *vmmio = vdev->virtio; 36960273720SAsias He 370eb34a8c2SJean-Philippe Brucker virtio_mmio_reset(kvm, vdev); 37160273720SAsias He kvm__deregister_mmio(kvm, vmmio->addr); 37260273720SAsias He 37360273720SAsias He return 0; 37460273720SAsias He } 375