121ff329dSWill Deacon #include "kvm/devices.h"
260273720SAsias He #include "kvm/virtio-mmio.h"
360273720SAsias He #include "kvm/ioeventfd.h"
460273720SAsias He #include "kvm/virtio.h"
560273720SAsias He #include "kvm/kvm.h"
660273720SAsias He #include "kvm/irq.h"
72454c7dcSWill Deacon #include "kvm/fdt.h"
860273720SAsias He
960273720SAsias He #include <linux/virtio_mmio.h>
1060273720SAsias He #include <string.h>
1160273720SAsias He
1260273720SAsias He static u32 virtio_mmio_io_space_blocks = KVM_VIRTIO_MMIO_AREA;
1360273720SAsias He
virtio_mmio_get_io_space_block(u32 size)1460273720SAsias He static u32 virtio_mmio_get_io_space_block(u32 size)
1560273720SAsias He {
1660273720SAsias He u32 block = virtio_mmio_io_space_blocks;
1760273720SAsias He virtio_mmio_io_space_blocks += size;
1860273720SAsias He
1960273720SAsias He return block;
2060273720SAsias He }
2160273720SAsias He
virtio_mmio_ioevent_callback(struct kvm * kvm,void * param)2260273720SAsias He static void virtio_mmio_ioevent_callback(struct kvm *kvm, void *param)
2360273720SAsias He {
2460273720SAsias He struct virtio_mmio_ioevent_param *ioeventfd = param;
2560273720SAsias He struct virtio_mmio *vmmio = ioeventfd->vdev->virtio;
2660273720SAsias He
2760273720SAsias He ioeventfd->vdev->ops->notify_vq(kvm, vmmio->dev, ioeventfd->vq);
2860273720SAsias He }
2960273720SAsias He
virtio_mmio_init_ioeventfd(struct kvm * kvm,struct virtio_device * vdev,u32 vq)3022a08236SJean-Philippe Brucker int virtio_mmio_init_ioeventfd(struct kvm *kvm, struct virtio_device *vdev,
3122a08236SJean-Philippe Brucker u32 vq)
3260273720SAsias He {
3360273720SAsias He struct virtio_mmio *vmmio = vdev->virtio;
3460273720SAsias He struct ioevent ioevent;
3560273720SAsias He int err;
3660273720SAsias He
3760273720SAsias He vmmio->ioeventfds[vq] = (struct virtio_mmio_ioevent_param) {
3860273720SAsias He .vdev = vdev,
3960273720SAsias He .vq = vq,
4060273720SAsias He };
4160273720SAsias He
4260273720SAsias He ioevent = (struct ioevent) {
4360273720SAsias He .io_addr = vmmio->addr + VIRTIO_MMIO_QUEUE_NOTIFY,
4460273720SAsias He .io_len = sizeof(u32),
4560273720SAsias He .fn = virtio_mmio_ioevent_callback,
4660273720SAsias He .fn_ptr = &vmmio->ioeventfds[vq],
4760273720SAsias He .datamatch = vq,
4860273720SAsias He .fn_kvm = kvm,
4960273720SAsias He .fd = eventfd(0, 0),
5060273720SAsias He };
5160273720SAsias He
52627d6874SAsias He if (vdev->use_vhost)
53627d6874SAsias He /*
54627d6874SAsias He * Vhost will poll the eventfd in host kernel side,
55627d6874SAsias He * no need to poll in userspace.
56627d6874SAsias He */
5727347f76SWill Deacon err = ioeventfd__add_event(&ioevent, 0);
58627d6874SAsias He else
59627d6874SAsias He /* Need to poll in userspace. */
6027347f76SWill Deacon err = ioeventfd__add_event(&ioevent, IOEVENTFD_FLAG_USER_POLL);
6160273720SAsias He if (err)
6260273720SAsias He return err;
6360273720SAsias He
6460273720SAsias He if (vdev->ops->notify_vq_eventfd)
6560273720SAsias He vdev->ops->notify_vq_eventfd(kvm, vmmio->dev, vq, ioevent.fd);
6660273720SAsias He
6760273720SAsias He return 0;
6860273720SAsias He }
6960273720SAsias He
virtio_mmio_signal_vq(struct kvm * kvm,struct virtio_device * vdev,u32 vq)7060273720SAsias He int virtio_mmio_signal_vq(struct kvm *kvm, struct virtio_device *vdev, u32 vq)
7160273720SAsias He {
7260273720SAsias He struct virtio_mmio *vmmio = vdev->virtio;
7360273720SAsias He
7460273720SAsias He vmmio->hdr.interrupt_state |= VIRTIO_MMIO_INT_VRING;
7560273720SAsias He kvm__irq_trigger(vmmio->kvm, vmmio->irq);
7660273720SAsias He
7760273720SAsias He return 0;
7860273720SAsias He }
7960273720SAsias He
virtio_mmio_init_vq(struct kvm * kvm,struct virtio_device * vdev,int vq)8022a08236SJean-Philippe Brucker int virtio_mmio_init_vq(struct kvm *kvm, struct virtio_device *vdev, int vq)
81d0607293SJean-Philippe Brucker {
82d0607293SJean-Philippe Brucker int ret;
83d0607293SJean-Philippe Brucker struct virtio_mmio *vmmio = vdev->virtio;
84d0607293SJean-Philippe Brucker
85d0607293SJean-Philippe Brucker ret = virtio_mmio_init_ioeventfd(vmmio->kvm, vdev, vq);
86d0607293SJean-Philippe Brucker if (ret) {
87d0607293SJean-Philippe Brucker pr_err("couldn't add ioeventfd for vq %d: %d", vq, ret);
88d0607293SJean-Philippe Brucker return ret;
89d0607293SJean-Philippe Brucker }
90d0607293SJean-Philippe Brucker return vdev->ops->init_vq(vmmio->kvm, vmmio->dev, vq);
91d0607293SJean-Philippe Brucker }
92d0607293SJean-Philippe Brucker
virtio_mmio_exit_vq(struct kvm * kvm,struct virtio_device * vdev,int vq)9322a08236SJean-Philippe Brucker void virtio_mmio_exit_vq(struct kvm *kvm, struct virtio_device *vdev, int vq)
94ad346c2eSJean-Philippe Brucker {
95ad346c2eSJean-Philippe Brucker struct virtio_mmio *vmmio = vdev->virtio;
96ad346c2eSJean-Philippe Brucker
97ad346c2eSJean-Philippe Brucker ioeventfd__del_event(vmmio->addr + VIRTIO_MMIO_QUEUE_NOTIFY, vq);
98ad346c2eSJean-Philippe Brucker virtio_exit_vq(kvm, vdev, vmmio->dev, vq);
99ad346c2eSJean-Philippe Brucker }
100ad346c2eSJean-Philippe Brucker
virtio_mmio_signal_config(struct kvm * kvm,struct virtio_device * vdev)10160273720SAsias He int virtio_mmio_signal_config(struct kvm *kvm, struct virtio_device *vdev)
10260273720SAsias He {
10360273720SAsias He struct virtio_mmio *vmmio = vdev->virtio;
10460273720SAsias He
10560273720SAsias He vmmio->hdr.interrupt_state |= VIRTIO_MMIO_INT_CONFIG;
10660273720SAsias He kvm__irq_trigger(vmmio->kvm, vmmio->irq);
10760273720SAsias He
10860273720SAsias He return 0;
10960273720SAsias He }
11060273720SAsias He
1112454c7dcSWill Deacon #ifdef CONFIG_HAS_LIBFDT
1122454c7dcSWill Deacon #define DEVICE_NAME_MAX_LEN 32
1132bfd9ac3SAndre Przywara static
generate_virtio_mmio_fdt_node(void * fdt,struct device_header * dev_hdr,void (* generate_irq_prop)(void * fdt,u8 irq,enum irq_type))1142bfd9ac3SAndre Przywara void generate_virtio_mmio_fdt_node(void *fdt,
1152454c7dcSWill Deacon struct device_header *dev_hdr,
1162454c7dcSWill Deacon void (*generate_irq_prop)(void *fdt,
1172bfd9ac3SAndre Przywara u8 irq,
1182bfd9ac3SAndre Przywara enum irq_type))
1192454c7dcSWill Deacon {
1202454c7dcSWill Deacon char dev_name[DEVICE_NAME_MAX_LEN];
1212454c7dcSWill Deacon struct virtio_mmio *vmmio = container_of(dev_hdr,
1222454c7dcSWill Deacon struct virtio_mmio,
1232454c7dcSWill Deacon dev_hdr);
1242454c7dcSWill Deacon u64 addr = vmmio->addr;
1252454c7dcSWill Deacon u64 reg_prop[] = {
1262454c7dcSWill Deacon cpu_to_fdt64(addr),
1272454c7dcSWill Deacon cpu_to_fdt64(VIRTIO_MMIO_IO_SIZE),
1282454c7dcSWill Deacon };
1292454c7dcSWill Deacon
1302454c7dcSWill Deacon snprintf(dev_name, DEVICE_NAME_MAX_LEN, "virtio@%llx", addr);
1312454c7dcSWill Deacon
1322454c7dcSWill Deacon _FDT(fdt_begin_node(fdt, dev_name));
1332454c7dcSWill Deacon _FDT(fdt_property_string(fdt, "compatible", "virtio,mmio"));
1342454c7dcSWill Deacon _FDT(fdt_property(fdt, "reg", reg_prop, sizeof(reg_prop)));
1359a8af7e3SRobin Murphy _FDT(fdt_property(fdt, "dma-coherent", NULL, 0));
1362bfd9ac3SAndre Przywara generate_irq_prop(fdt, vmmio->irq, IRQ_TYPE_EDGE_RISING);
1372454c7dcSWill Deacon _FDT(fdt_end_node(fdt));
1382454c7dcSWill Deacon }
1392454c7dcSWill Deacon #else
generate_virtio_mmio_fdt_node(void * fdt,struct device_header * dev_hdr,void (* generate_irq_prop)(void * fdt,u8 irq))1402454c7dcSWill Deacon static void generate_virtio_mmio_fdt_node(void *fdt,
1412454c7dcSWill Deacon struct device_header *dev_hdr,
1422454c7dcSWill Deacon void (*generate_irq_prop)(void *fdt,
1432454c7dcSWill Deacon u8 irq))
1442454c7dcSWill Deacon {
1452454c7dcSWill Deacon die("Unable to generate device tree nodes without libfdt\n");
1462454c7dcSWill Deacon }
1472454c7dcSWill Deacon #endif
1482454c7dcSWill Deacon
virtio_mmio_init(struct kvm * kvm,void * dev,struct virtio_device * vdev,int device_id,int subsys_id,int class)14960273720SAsias He int virtio_mmio_init(struct kvm *kvm, void *dev, struct virtio_device *vdev,
15060273720SAsias He int device_id, int subsys_id, int class)
15160273720SAsias He {
152*5fe5eb04SJean-Philippe Brucker bool legacy = vdev->legacy;
15360273720SAsias He struct virtio_mmio *vmmio = vdev->virtio;
1548f160708SAlexandru Elisei int r;
15560273720SAsias He
15660273720SAsias He vmmio->addr = virtio_mmio_get_io_space_block(VIRTIO_MMIO_IO_SIZE);
15760273720SAsias He vmmio->kvm = kvm;
15860273720SAsias He vmmio->dev = dev;
15960273720SAsias He
160*5fe5eb04SJean-Philippe Brucker if (!legacy)
161*5fe5eb04SJean-Philippe Brucker vdev->endian = VIRTIO_ENDIAN_LE;
162*5fe5eb04SJean-Philippe Brucker
163*5fe5eb04SJean-Philippe Brucker r = kvm__register_mmio(kvm, vmmio->addr, VIRTIO_MMIO_IO_SIZE, false,
164*5fe5eb04SJean-Philippe Brucker legacy ? virtio_mmio_legacy_callback :
165*5fe5eb04SJean-Philippe Brucker virtio_mmio_modern_callback,
166*5fe5eb04SJean-Philippe Brucker vdev);
1678f160708SAlexandru Elisei if (r < 0)
1688f160708SAlexandru Elisei return r;
16960273720SAsias He
17060273720SAsias He vmmio->hdr = (struct virtio_mmio_hdr) {
17160273720SAsias He .magic = {'v', 'i', 'r', 't'},
172*5fe5eb04SJean-Philippe Brucker .version = legacy ? 1 : 2,
173449d5eb3SWill Deacon .device_id = subsys_id,
17460273720SAsias He .vendor_id = 0x4d564b4c , /* 'LKVM' */
17560273720SAsias He .queue_num_max = 256,
17660273720SAsias He };
17760273720SAsias He
17821ff329dSWill Deacon vmmio->dev_hdr = (struct device_header) {
17921ff329dSWill Deacon .bus_type = DEVICE_BUS_MMIO,
1802454c7dcSWill Deacon .data = generate_virtio_mmio_fdt_node,
18121ff329dSWill Deacon };
18221ff329dSWill Deacon
183af731be3SAndre Przywara vmmio->irq = irq__alloc_line();
184af731be3SAndre Przywara
1858f160708SAlexandru Elisei r = device__register(&vmmio->dev_hdr);
1868f160708SAlexandru Elisei if (r < 0) {
1878f160708SAlexandru Elisei kvm__deregister_mmio(kvm, vmmio->addr);
1888f160708SAlexandru Elisei return r;
1898f160708SAlexandru Elisei }
19060273720SAsias He
19160273720SAsias He /*
19260273720SAsias He * Instantiate guest virtio-mmio devices using kernel command line
19360273720SAsias He * (or module) parameter, e.g
19460273720SAsias He *
19560273720SAsias He * virtio_mmio.devices=0x200@0xd2000000:5,0x200@0xd2000200:6
19660273720SAsias He */
197e1c7c62aSAndre Przywara pr_debug("virtio-mmio.devices=0x%x@0x%x:%d", VIRTIO_MMIO_IO_SIZE,
198e1c7c62aSAndre Przywara vmmio->addr, vmmio->irq);
19960273720SAsias He
20060273720SAsias He return 0;
20160273720SAsias He }
20260273720SAsias He
virtio_mmio_reset(struct kvm * kvm,struct virtio_device * vdev)203eb34a8c2SJean-Philippe Brucker int virtio_mmio_reset(struct kvm *kvm, struct virtio_device *vdev)
204eb34a8c2SJean-Philippe Brucker {
20531e0eaccSMartin Radev unsigned int vq;
206eb34a8c2SJean-Philippe Brucker struct virtio_mmio *vmmio = vdev->virtio;
207eb34a8c2SJean-Philippe Brucker
208eb34a8c2SJean-Philippe Brucker for (vq = 0; vq < vdev->ops->get_vq_count(kvm, vmmio->dev); vq++)
209eb34a8c2SJean-Philippe Brucker virtio_mmio_exit_vq(kvm, vdev, vq);
210eb34a8c2SJean-Philippe Brucker
211eb34a8c2SJean-Philippe Brucker return 0;
212eb34a8c2SJean-Philippe Brucker }
213eb34a8c2SJean-Philippe Brucker
virtio_mmio_exit(struct kvm * kvm,struct virtio_device * vdev)21460273720SAsias He int virtio_mmio_exit(struct kvm *kvm, struct virtio_device *vdev)
21560273720SAsias He {
21660273720SAsias He struct virtio_mmio *vmmio = vdev->virtio;
21760273720SAsias He
218eb34a8c2SJean-Philippe Brucker virtio_mmio_reset(kvm, vdev);
21960273720SAsias He kvm__deregister_mmio(kvm, vmmio->addr);
22060273720SAsias He
22160273720SAsias He return 0;
22260273720SAsias He }
223