xref: /kvmtool/virtio/pci.c (revision 1c47ce695a0c853fcca0dccf558c7f2d62d23715)
1 #include "kvm/virtio-pci.h"
2 
3 #include "kvm/ioport.h"
4 #include "kvm/kvm.h"
5 #include "kvm/virtio-pci-dev.h"
6 #include "kvm/irq.h"
7 #include "kvm/virtio.h"
8 #include "kvm/ioeventfd.h"
9 #include "kvm/virtio-trans.h"
10 
11 #include <linux/virtio_pci.h>
12 #include <string.h>
13 
14 struct virtio_trans_ops *virtio_pci__get_trans_ops(void)
15 {
16 	static struct virtio_trans_ops virtio_pci_trans = (struct virtio_trans_ops) {
17 		.signal_vq	= virtio_pci__signal_vq,
18 		.signal_config	= virtio_pci__signal_config,
19 		.init		= virtio_pci__init,
20 	};
21 	return &virtio_pci_trans;
22 };
23 
24 static void virtio_pci__ioevent_callback(struct kvm *kvm, void *param)
25 {
26 	struct virtio_pci_ioevent_param *ioeventfd = param;
27 	struct virtio_pci *vpci = ioeventfd->vtrans->virtio;
28 
29 	ioeventfd->vtrans->virtio_ops->notify_vq(kvm, vpci->dev, ioeventfd->vq);
30 }
31 
32 static int virtio_pci__init_ioeventfd(struct kvm *kvm, struct virtio_trans *vtrans, u32 vq)
33 {
34 	struct ioevent ioevent;
35 	struct virtio_pci *vpci = vtrans->virtio;
36 
37 	vpci->ioeventfds[vq] = (struct virtio_pci_ioevent_param) {
38 		.vtrans		= vtrans,
39 		.vq		= vq,
40 	};
41 
42 	ioevent = (struct ioevent) {
43 		.io_addr	= vpci->base_addr + VIRTIO_PCI_QUEUE_NOTIFY,
44 		.io_len		= sizeof(u16),
45 		.fn		= virtio_pci__ioevent_callback,
46 		.fn_ptr		= &vpci->ioeventfds[vq],
47 		.datamatch	= vq,
48 		.fn_kvm		= kvm,
49 		.fd		= eventfd(0, 0),
50 	};
51 
52 	ioeventfd__add_event(&ioevent);
53 
54 	return 0;
55 }
56 
57 static inline bool virtio_pci__msix_enabled(struct virtio_pci *vpci)
58 {
59 	return vpci->pci_hdr.msix.ctrl & PCI_MSIX_FLAGS_ENABLE;
60 }
61 
62 static bool virtio_pci__specific_io_in(struct kvm *kvm, struct virtio_trans *vtrans, u16 port,
63 					void *data, int size, int offset)
64 {
65 	u32 config_offset;
66 	struct virtio_pci *vpci = vtrans->virtio;
67 	int type = virtio__get_dev_specific_field(offset - 20,
68 							virtio_pci__msix_enabled(vpci),
69 							0, &config_offset);
70 	if (type == VIRTIO_PCI_O_MSIX) {
71 		switch (offset) {
72 		case VIRTIO_MSI_CONFIG_VECTOR:
73 			ioport__write16(data, vpci->config_vector);
74 			break;
75 		case VIRTIO_MSI_QUEUE_VECTOR:
76 			ioport__write16(data, vpci->vq_vector[vpci->queue_selector]);
77 			break;
78 		};
79 
80 		return true;
81 	} else if (type == VIRTIO_PCI_O_CONFIG) {
82 		u8 cfg;
83 
84 		cfg = vtrans->virtio_ops->get_config(kvm, vpci->dev, config_offset);
85 		ioport__write8(data, cfg);
86 		return true;
87 	}
88 
89 	return false;
90 }
91 
92 static bool virtio_pci__io_in(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size)
93 {
94 	unsigned long offset;
95 	bool ret = true;
96 	struct virtio_trans *vtrans;
97 	struct virtio_pci *vpci;
98 	u32 val;
99 
100 	vtrans = ioport->priv;
101 	vpci = vtrans->virtio;
102 	offset = port - vpci->base_addr;
103 
104 	switch (offset) {
105 	case VIRTIO_PCI_HOST_FEATURES:
106 		val = vtrans->virtio_ops->get_host_features(kvm, vpci->dev);
107 		ioport__write32(data, val);
108 		break;
109 	case VIRTIO_PCI_QUEUE_PFN:
110 		val = vtrans->virtio_ops->get_pfn_vq(kvm, vpci->dev, vpci->queue_selector);
111 		ioport__write32(data, val);
112 		break;
113 	case VIRTIO_PCI_QUEUE_NUM:
114 		val = vtrans->virtio_ops->get_size_vq(kvm, vpci->dev, vpci->queue_selector);
115 		ioport__write32(data, val);
116 		break;
117 		break;
118 	case VIRTIO_PCI_STATUS:
119 		ioport__write8(data, vpci->status);
120 		break;
121 	case VIRTIO_PCI_ISR:
122 		ioport__write8(data, vpci->isr);
123 		kvm__irq_line(kvm, vpci->pci_hdr.irq_line, VIRTIO_IRQ_LOW);
124 		vpci->isr = VIRTIO_IRQ_LOW;
125 		break;
126 	default:
127 		ret = virtio_pci__specific_io_in(kvm, vtrans, port, data, size, offset);
128 		break;
129 	};
130 
131 	return ret;
132 }
133 
134 static bool virtio_pci__specific_io_out(struct kvm *kvm, struct virtio_trans *vtrans, u16 port,
135 					void *data, int size, int offset)
136 {
137 	struct virtio_pci *vpci = vtrans->virtio;
138 	u32 config_offset, gsi, vec;
139 	int type = virtio__get_dev_specific_field(offset - 20, virtio_pci__msix_enabled(vpci),
140 							0, &config_offset);
141 	if (type == VIRTIO_PCI_O_MSIX) {
142 		switch (offset) {
143 		case VIRTIO_MSI_CONFIG_VECTOR:
144 			vec = vpci->config_vector = ioport__read16(data);
145 
146 			gsi = irq__add_msix_route(kvm, &vpci->msix_table[vec].msg);
147 
148 			vpci->config_gsi = gsi;
149 			break;
150 		case VIRTIO_MSI_QUEUE_VECTOR: {
151 			vec = vpci->vq_vector[vpci->queue_selector] = ioport__read16(data);
152 
153 			gsi = irq__add_msix_route(kvm, &vpci->msix_table[vec].msg);
154 			vpci->gsis[vpci->queue_selector] = gsi;
155 			break;
156 		}
157 		};
158 
159 		return true;
160 	} else if (type == VIRTIO_PCI_O_CONFIG) {
161 		vtrans->virtio_ops->set_config(kvm, vpci->dev, *(u8 *)data, config_offset);
162 
163 		return true;
164 	}
165 
166 	return false;
167 }
168 
169 static bool virtio_pci__io_out(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size)
170 {
171 	unsigned long offset;
172 	bool ret = true;
173 	struct virtio_trans *vtrans;
174 	struct virtio_pci *vpci;
175 	u32 val;
176 
177 	vtrans = ioport->priv;
178 	vpci = vtrans->virtio;
179 	offset = port - vpci->base_addr;
180 
181 	switch (offset) {
182 	case VIRTIO_PCI_GUEST_FEATURES:
183 		val = ioport__read32(data);
184 		vtrans->virtio_ops->set_guest_features(kvm, vpci, val);
185 		break;
186 	case VIRTIO_PCI_QUEUE_PFN:
187 		val = ioport__read32(data);
188 		virtio_pci__init_ioeventfd(kvm, vtrans, vpci->queue_selector);
189 		vtrans->virtio_ops->init_vq(kvm, vpci->dev, vpci->queue_selector, val);
190 		break;
191 	case VIRTIO_PCI_QUEUE_SEL:
192 		vpci->queue_selector	= ioport__read16(data);
193 		break;
194 	case VIRTIO_PCI_QUEUE_NOTIFY:
195 		val			= ioport__read16(data);
196 		vtrans->virtio_ops->notify_vq(kvm, vpci->dev, val);
197 		break;
198 	case VIRTIO_PCI_STATUS:
199 		vpci->status		= ioport__read8(data);
200 		break;
201 	default:
202 		ret = virtio_pci__specific_io_out(kvm, vtrans, port, data, size, offset);
203 		break;
204 	};
205 
206 	return ret;
207 }
208 
209 static struct ioport_operations virtio_pci__io_ops = {
210 	.io_in	= virtio_pci__io_in,
211 	.io_out	= virtio_pci__io_out,
212 };
213 
214 static void callback_mmio_table(u64 addr, u8 *data, u32 len, u8 is_write, void *ptr)
215 {
216 	struct virtio_pci *vpci = ptr;
217 	void *table = &vpci->msix_table;
218 
219 	if (is_write)
220 		memcpy(table + addr - vpci->msix_io_block, data, len);
221 	else
222 		memcpy(data, table + addr - vpci->msix_io_block, len);
223 }
224 
225 static void callback_mmio_pba(u64 addr, u8 *data, u32 len, u8 is_write, void *ptr)
226 {
227 	struct virtio_pci *vpci = ptr;
228 	void *pba = &vpci->msix_pba;
229 
230 	if (is_write)
231 		memcpy(pba + addr - vpci->msix_pba_block, data, len);
232 	else
233 		memcpy(data, pba + addr - vpci->msix_pba_block, len);
234 }
235 
236 int virtio_pci__signal_vq(struct kvm *kvm, struct virtio_trans *vtrans, u32 vq)
237 {
238 	struct virtio_pci *vpci = vtrans->virtio;
239 	int tbl = vpci->vq_vector[vq];
240 
241 	if (virtio_pci__msix_enabled(vpci)) {
242 		if (vpci->pci_hdr.msix.ctrl & PCI_MSIX_FLAGS_MASKALL ||
243 			vpci->msix_table[tbl].ctrl & PCI_MSIX_ENTRY_CTRL_MASKBIT) {
244 
245 			vpci->msix_pba |= 1 << tbl;
246 			return 0;
247 		}
248 
249 		kvm__irq_trigger(kvm, vpci->gsis[vq]);
250 	} else {
251 		vpci->isr = VIRTIO_IRQ_HIGH;
252 		kvm__irq_trigger(kvm, vpci->pci_hdr.irq_line);
253 	}
254 	return 0;
255 }
256 
257 int virtio_pci__signal_config(struct kvm *kvm, struct virtio_trans *vtrans)
258 {
259 	struct virtio_pci *vpci = vtrans->virtio;
260 	int tbl = vpci->config_vector;
261 
262 	if (virtio_pci__msix_enabled(vpci)) {
263 		if (vpci->pci_hdr.msix.ctrl & PCI_MSIX_FLAGS_MASKALL ||
264 			vpci->msix_table[tbl].ctrl & PCI_MSIX_ENTRY_CTRL_MASKBIT) {
265 
266 			vpci->msix_pba |= 1 << tbl;
267 			return 0;
268 		}
269 
270 		kvm__irq_trigger(kvm, vpci->config_gsi);
271 	} else {
272 		vpci->isr = VIRTIO_PCI_ISR_CONFIG;
273 		kvm__irq_trigger(kvm, vpci->pci_hdr.irq_line);
274 	}
275 
276 	return 0;
277 }
278 
279 int virtio_pci__init(struct kvm *kvm, struct virtio_trans *vtrans, void *dev,
280 			int device_id, int subsys_id, int class)
281 {
282 	struct virtio_pci *vpci = vtrans->virtio;
283 	u8 pin, line, ndev;
284 
285 	vpci->dev = dev;
286 	vpci->msix_io_block = pci_get_io_space_block(PCI_IO_SIZE);
287 	vpci->msix_pba_block = pci_get_io_space_block(PCI_IO_SIZE);
288 
289 	vpci->base_addr = ioport__register(IOPORT_EMPTY, &virtio_pci__io_ops, IOPORT_SIZE, vtrans);
290 	kvm__register_mmio(kvm, vpci->msix_io_block, 0x100, callback_mmio_table, vpci);
291 	kvm__register_mmio(kvm, vpci->msix_pba_block, 0x100, callback_mmio_pba, vpci);
292 
293 	vpci->pci_hdr = (struct pci_device_header) {
294 		.vendor_id		= PCI_VENDOR_ID_REDHAT_QUMRANET,
295 		.device_id		= device_id,
296 		.header_type		= PCI_HEADER_TYPE_NORMAL,
297 		.revision_id		= 0,
298 		.class			= class,
299 		.subsys_vendor_id	= PCI_SUBSYSTEM_VENDOR_ID_REDHAT_QUMRANET,
300 		.subsys_id		= subsys_id,
301 		.bar[0]			= vpci->base_addr | PCI_BASE_ADDRESS_SPACE_IO,
302 		.bar[1]			= vpci->msix_io_block | PCI_BASE_ADDRESS_SPACE_MEMORY
303 					| PCI_BASE_ADDRESS_MEM_TYPE_64,
304 		.bar[3]			= vpci->msix_pba_block | PCI_BASE_ADDRESS_SPACE_MEMORY
305 					| PCI_BASE_ADDRESS_MEM_TYPE_64,
306 		.status			= PCI_STATUS_CAP_LIST,
307 		.capabilities		= (void *)&vpci->pci_hdr.msix - (void *)&vpci->pci_hdr,
308 	};
309 
310 	vpci->pci_hdr.msix.cap = PCI_CAP_ID_MSIX;
311 	vpci->pci_hdr.msix.next = 0;
312 	/*
313 	 * We at most have VIRTIO_PCI_MAX_VQ entries for virt queue,
314 	 * VIRTIO_PCI_MAX_CONFIG entries for config.
315 	 *
316 	 * To quote the PCI spec:
317 	 *
318 	 * System software reads this field to determine the
319 	 * MSI-X Table Size N, which is encoded as N-1.
320 	 * For example, a returned value of "00000000011"
321 	 * indicates a table size of 4.
322 	 */
323 	vpci->pci_hdr.msix.ctrl = (VIRTIO_PCI_MAX_VQ + VIRTIO_PCI_MAX_CONFIG - 1);
324 
325 	/*
326 	 * Both table and PBA could be mapped on the same BAR, but for now
327 	 * we're not in short of BARs
328 	 */
329 	vpci->pci_hdr.msix.table_offset = 1; /* Use BAR 1 */
330 	vpci->pci_hdr.msix.pba_offset = 3; /* Use BAR 3 */
331 	vpci->config_vector = 0;
332 
333 	if (irq__register_device(subsys_id, &ndev, &pin, &line) < 0)
334 		return -1;
335 
336 	vpci->pci_hdr.irq_pin	= pin;
337 	vpci->pci_hdr.irq_line	= line;
338 	pci__register(&vpci->pci_hdr, ndev);
339 
340 	return 0;
341 }
342