xref: /kvmtool/virtio/mmio.c (revision 5fe5eb04de80b8bc68f4d57443596d0b935907ef)
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