xref: /kvmtool/virtio/mmio.c (revision 5fe5eb04de80b8bc68f4d57443596d0b935907ef)
1 #include "kvm/devices.h"
2 #include "kvm/virtio-mmio.h"
3 #include "kvm/ioeventfd.h"
4 #include "kvm/virtio.h"
5 #include "kvm/kvm.h"
6 #include "kvm/irq.h"
7 #include "kvm/fdt.h"
8 
9 #include <linux/virtio_mmio.h>
10 #include <string.h>
11 
12 static u32 virtio_mmio_io_space_blocks = KVM_VIRTIO_MMIO_AREA;
13 
virtio_mmio_get_io_space_block(u32 size)14 static u32 virtio_mmio_get_io_space_block(u32 size)
15 {
16 	u32 block = virtio_mmio_io_space_blocks;
17 	virtio_mmio_io_space_blocks += size;
18 
19 	return block;
20 }
21 
virtio_mmio_ioevent_callback(struct kvm * kvm,void * param)22 static void virtio_mmio_ioevent_callback(struct kvm *kvm, void *param)
23 {
24 	struct virtio_mmio_ioevent_param *ioeventfd = param;
25 	struct virtio_mmio *vmmio = ioeventfd->vdev->virtio;
26 
27 	ioeventfd->vdev->ops->notify_vq(kvm, vmmio->dev, ioeventfd->vq);
28 }
29 
virtio_mmio_init_ioeventfd(struct kvm * kvm,struct virtio_device * vdev,u32 vq)30 int virtio_mmio_init_ioeventfd(struct kvm *kvm, struct virtio_device *vdev,
31 			       u32 vq)
32 {
33 	struct virtio_mmio *vmmio = vdev->virtio;
34 	struct ioevent ioevent;
35 	int err;
36 
37 	vmmio->ioeventfds[vq] = (struct virtio_mmio_ioevent_param) {
38 		.vdev		= vdev,
39 		.vq		= vq,
40 	};
41 
42 	ioevent = (struct ioevent) {
43 		.io_addr	= vmmio->addr + VIRTIO_MMIO_QUEUE_NOTIFY,
44 		.io_len		= sizeof(u32),
45 		.fn		= virtio_mmio_ioevent_callback,
46 		.fn_ptr		= &vmmio->ioeventfds[vq],
47 		.datamatch	= vq,
48 		.fn_kvm		= kvm,
49 		.fd		= eventfd(0, 0),
50 	};
51 
52 	if (vdev->use_vhost)
53 		/*
54 		 * Vhost will poll the eventfd in host kernel side,
55 		 * no need to poll in userspace.
56 		 */
57 		err = ioeventfd__add_event(&ioevent, 0);
58 	else
59 		/* Need to poll in userspace. */
60 		err = ioeventfd__add_event(&ioevent, IOEVENTFD_FLAG_USER_POLL);
61 	if (err)
62 		return err;
63 
64 	if (vdev->ops->notify_vq_eventfd)
65 		vdev->ops->notify_vq_eventfd(kvm, vmmio->dev, vq, ioevent.fd);
66 
67 	return 0;
68 }
69 
virtio_mmio_signal_vq(struct kvm * kvm,struct virtio_device * vdev,u32 vq)70 int virtio_mmio_signal_vq(struct kvm *kvm, struct virtio_device *vdev, u32 vq)
71 {
72 	struct virtio_mmio *vmmio = vdev->virtio;
73 
74 	vmmio->hdr.interrupt_state |= VIRTIO_MMIO_INT_VRING;
75 	kvm__irq_trigger(vmmio->kvm, vmmio->irq);
76 
77 	return 0;
78 }
79 
virtio_mmio_init_vq(struct kvm * kvm,struct virtio_device * vdev,int vq)80 int virtio_mmio_init_vq(struct kvm *kvm, struct virtio_device *vdev, int vq)
81 {
82 	int ret;
83 	struct virtio_mmio *vmmio = vdev->virtio;
84 
85 	ret = virtio_mmio_init_ioeventfd(vmmio->kvm, vdev, vq);
86 	if (ret) {
87 		pr_err("couldn't add ioeventfd for vq %d: %d", vq, ret);
88 		return ret;
89 	}
90 	return vdev->ops->init_vq(vmmio->kvm, vmmio->dev, vq);
91 }
92 
virtio_mmio_exit_vq(struct kvm * kvm,struct virtio_device * vdev,int vq)93 void virtio_mmio_exit_vq(struct kvm *kvm, struct virtio_device *vdev, int vq)
94 {
95 	struct virtio_mmio *vmmio = vdev->virtio;
96 
97 	ioeventfd__del_event(vmmio->addr + VIRTIO_MMIO_QUEUE_NOTIFY, vq);
98 	virtio_exit_vq(kvm, vdev, vmmio->dev, vq);
99 }
100 
virtio_mmio_signal_config(struct kvm * kvm,struct virtio_device * vdev)101 int virtio_mmio_signal_config(struct kvm *kvm, struct virtio_device *vdev)
102 {
103 	struct virtio_mmio *vmmio = vdev->virtio;
104 
105 	vmmio->hdr.interrupt_state |= VIRTIO_MMIO_INT_CONFIG;
106 	kvm__irq_trigger(vmmio->kvm, vmmio->irq);
107 
108 	return 0;
109 }
110 
111 #ifdef CONFIG_HAS_LIBFDT
112 #define DEVICE_NAME_MAX_LEN 32
113 static
generate_virtio_mmio_fdt_node(void * fdt,struct device_header * dev_hdr,void (* generate_irq_prop)(void * fdt,u8 irq,enum irq_type))114 void generate_virtio_mmio_fdt_node(void *fdt,
115 				   struct device_header *dev_hdr,
116 				   void (*generate_irq_prop)(void *fdt,
117 							     u8 irq,
118 							     enum irq_type))
119 {
120 	char dev_name[DEVICE_NAME_MAX_LEN];
121 	struct virtio_mmio *vmmio = container_of(dev_hdr,
122 						 struct virtio_mmio,
123 						 dev_hdr);
124 	u64 addr = vmmio->addr;
125 	u64 reg_prop[] = {
126 		cpu_to_fdt64(addr),
127 		cpu_to_fdt64(VIRTIO_MMIO_IO_SIZE),
128 	};
129 
130 	snprintf(dev_name, DEVICE_NAME_MAX_LEN, "virtio@%llx", addr);
131 
132 	_FDT(fdt_begin_node(fdt, dev_name));
133 	_FDT(fdt_property_string(fdt, "compatible", "virtio,mmio"));
134 	_FDT(fdt_property(fdt, "reg", reg_prop, sizeof(reg_prop)));
135 	_FDT(fdt_property(fdt, "dma-coherent", NULL, 0));
136 	generate_irq_prop(fdt, vmmio->irq, IRQ_TYPE_EDGE_RISING);
137 	_FDT(fdt_end_node(fdt));
138 }
139 #else
generate_virtio_mmio_fdt_node(void * fdt,struct device_header * dev_hdr,void (* generate_irq_prop)(void * fdt,u8 irq))140 static void generate_virtio_mmio_fdt_node(void *fdt,
141 					  struct device_header *dev_hdr,
142 					  void (*generate_irq_prop)(void *fdt,
143 								    u8 irq))
144 {
145 	die("Unable to generate device tree nodes without libfdt\n");
146 }
147 #endif
148 
virtio_mmio_init(struct kvm * kvm,void * dev,struct virtio_device * vdev,int device_id,int subsys_id,int class)149 int virtio_mmio_init(struct kvm *kvm, void *dev, struct virtio_device *vdev,
150 		     int device_id, int subsys_id, int class)
151 {
152 	bool legacy = vdev->legacy;
153 	struct virtio_mmio *vmmio = vdev->virtio;
154 	int r;
155 
156 	vmmio->addr	= virtio_mmio_get_io_space_block(VIRTIO_MMIO_IO_SIZE);
157 	vmmio->kvm	= kvm;
158 	vmmio->dev	= dev;
159 
160 	if (!legacy)
161 		vdev->endian = VIRTIO_ENDIAN_LE;
162 
163 	r = kvm__register_mmio(kvm, vmmio->addr, VIRTIO_MMIO_IO_SIZE, false,
164 			       legacy ? virtio_mmio_legacy_callback :
165 					virtio_mmio_modern_callback,
166 			       vdev);
167 	if (r < 0)
168 		return r;
169 
170 	vmmio->hdr = (struct virtio_mmio_hdr) {
171 		.magic		= {'v', 'i', 'r', 't'},
172 		.version	= legacy ? 1 : 2,
173 		.device_id	= subsys_id,
174 		.vendor_id	= 0x4d564b4c , /* 'LKVM' */
175 		.queue_num_max	= 256,
176 	};
177 
178 	vmmio->dev_hdr = (struct device_header) {
179 		.bus_type	= DEVICE_BUS_MMIO,
180 		.data		= generate_virtio_mmio_fdt_node,
181 	};
182 
183 	vmmio->irq = irq__alloc_line();
184 
185 	r = device__register(&vmmio->dev_hdr);
186 	if (r < 0) {
187 		kvm__deregister_mmio(kvm, vmmio->addr);
188 		return r;
189 	}
190 
191 	/*
192 	 * Instantiate guest virtio-mmio devices using kernel command line
193 	 * (or module) parameter, e.g
194 	 *
195 	 * virtio_mmio.devices=0x200@0xd2000000:5,0x200@0xd2000200:6
196 	 */
197 	pr_debug("virtio-mmio.devices=0x%x@0x%x:%d", VIRTIO_MMIO_IO_SIZE,
198 		 vmmio->addr, vmmio->irq);
199 
200 	return 0;
201 }
202 
virtio_mmio_reset(struct kvm * kvm,struct virtio_device * vdev)203 int virtio_mmio_reset(struct kvm *kvm, struct virtio_device *vdev)
204 {
205 	unsigned int vq;
206 	struct virtio_mmio *vmmio = vdev->virtio;
207 
208 	for (vq = 0; vq < vdev->ops->get_vq_count(kvm, vmmio->dev); vq++)
209 		virtio_mmio_exit_vq(kvm, vdev, vq);
210 
211 	return 0;
212 }
213 
virtio_mmio_exit(struct kvm * kvm,struct virtio_device * vdev)214 int virtio_mmio_exit(struct kvm *kvm, struct virtio_device *vdev)
215 {
216 	struct virtio_mmio *vmmio = vdev->virtio;
217 
218 	virtio_mmio_reset(kvm, vdev);
219 	kvm__deregister_mmio(kvm, vmmio->addr);
220 
221 	return 0;
222 }
223