xref: /haiku/src/add-ons/kernel/busses/virtio/virtio_pci/virtio_pci.cpp (revision f967e2c0c73efb25581afdc95a838f7633e8c03b)
1 /*
2  * Copyright 2013, 2018, Jérôme Duval, jerome.duval@gmail.com.
3  * Distributed under the terms of the MIT License.
4  */
5 
6 
7 #include <new>
8 #include <stdio.h>
9 #include <string.h>
10 
11 #include <bus/PCI.h>
12 #include <virtio.h>
13 
14 #include "virtio_pci.h"
15 
16 
17 //#define TRACE_VIRTIO
18 #ifdef TRACE_VIRTIO
19 #	define TRACE(x...) dprintf("\33[33mvirtio_pci:\33[0m " x)
20 #else
21 #	define TRACE(x...) ;
22 #endif
23 #define TRACE_ALWAYS(x...)	dprintf("\33[33mvirtio_pci:\33[0m " x)
24 #define ERROR(x...)			dprintf("\33[33mvirtio_pci:\33[0m " x)
25 #define CALLED(x...)		TRACE("CALLED %s\n", __PRETTY_FUNCTION__)
26 
27 
28 #define VIRTIO_PCI_DEVICE_MODULE_NAME "busses/virtio/virtio_pci/driver_v1"
29 #define VIRTIO_PCI_SIM_MODULE_NAME "busses/virtio/virtio_pci/device/v1"
30 
31 #define VIRTIO_PCI_CONTROLLER_TYPE_NAME "virtio pci controller"
32 
33 typedef enum {
34 	VIRTIO_IRQ_LEGACY,
35 	VIRTIO_IRQ_MSI,
36 	VIRTIO_IRQ_MSI_X_SHARED,
37 	VIRTIO_IRQ_MSI_X,
38 } virtio_irq_type;
39 
40 typedef struct {
41 	virtio_sim sim;
42 	uint16 queue;
43 } virtio_pci_queue_cookie;
44 
45 typedef struct {
46 	pci_device_module_info* pci;
47 	pci_device* device;
48 	addr_t base_addr;
49 	uint8 irq;
50 	virtio_irq_type irq_type;
51 	virtio_sim sim;
52 	uint16 queue_count;
53 
54 	device_node* node;
55 	pci_info info;
56 
57 	virtio_pci_queue_cookie *cookies;
58 } virtio_pci_sim_info;
59 
60 
61 device_manager_info* gDeviceManager;
62 virtio_for_controller_interface* gVirtio;
63 
64 
65 int32
66 virtio_pci_interrupt(void *data)
67 {
68 	virtio_pci_sim_info* bus = (virtio_pci_sim_info*)data;
69 	uint8 isr = bus->pci->read_io_8(bus->device,
70 		bus->base_addr + VIRTIO_PCI_ISR);
71 	if (isr == 0)
72 		return B_UNHANDLED_INTERRUPT;
73 
74 	if (isr & VIRTIO_PCI_ISR_CONFIG)
75 		gVirtio->config_interrupt_handler(bus->sim);
76 
77 	if (isr & VIRTIO_PCI_ISR_INTR)
78 		gVirtio->queue_interrupt_handler(bus->sim, INT16_MAX);
79 
80 	return B_HANDLED_INTERRUPT;
81 }
82 
83 
84 int32
85 virtio_pci_config_interrupt(void *data)
86 {
87 	virtio_pci_sim_info* bus = (virtio_pci_sim_info*)data;
88 	gVirtio->config_interrupt_handler(bus->sim);
89 
90 	return B_HANDLED_INTERRUPT;
91 }
92 
93 
94 int32
95 virtio_pci_queue_interrupt(void *data)
96 {
97 	virtio_pci_queue_cookie* cookie = (virtio_pci_queue_cookie*)data;
98 	gVirtio->queue_interrupt_handler(cookie->sim, cookie->queue);
99 
100 	return B_HANDLED_INTERRUPT;
101 }
102 
103 
104 status_t
105 virtio_pci_setup_msix_interrupts(virtio_pci_sim_info* bus)
106 {
107 	CALLED();
108 	uint8 irq = 0; // first irq slot
109 	bus->pci->write_io_16(bus->device, bus->base_addr
110 		+ VIRTIO_MSI_CONFIG_VECTOR, irq);
111 	if (bus->pci->read_io_16(bus->device, bus->base_addr
112 		+ VIRTIO_MSI_CONFIG_VECTOR) == VIRTIO_MSI_NO_VECTOR) {
113 		ERROR("msix config vector incorrect\n");
114 		return B_BAD_VALUE;
115 	}
116 	if (bus->irq_type == VIRTIO_IRQ_MSI_X)
117 		irq++;
118 
119 	for (uint16 queue = 0; queue < bus->queue_count; queue++) {
120 		bus->pci->write_io_16(bus->device, bus->base_addr
121 			+ VIRTIO_PCI_QUEUE_SEL, queue);
122 		bus->pci->write_io_16(bus->device, bus->base_addr
123 			+ VIRTIO_MSI_QUEUE_VECTOR, irq);
124 
125 		if (bus->pci->read_io_16(bus->device, bus->base_addr
126 			+ VIRTIO_MSI_QUEUE_VECTOR) == VIRTIO_MSI_NO_VECTOR) {
127 			ERROR("msix queue vector incorrect\n");
128 			return B_BAD_VALUE;
129 		}
130 
131 		if (bus->irq_type == VIRTIO_IRQ_MSI_X)
132 			irq++;
133 	}
134 
135 	return B_OK;
136 }
137 
138 
139 static void
140 set_sim(void* cookie, virtio_sim sim)
141 {
142 	CALLED();
143 	virtio_pci_sim_info* bus = (virtio_pci_sim_info*)cookie;
144 	bus->sim = sim;
145 }
146 
147 
148 static status_t
149 read_host_features(void* cookie, uint32 *features)
150 {
151 	CALLED();
152 	virtio_pci_sim_info* bus = (virtio_pci_sim_info*)cookie;
153 
154 	TRACE("read_host_features() %p node %p pci %p device %p\n", bus,
155 		bus->node, bus->pci, bus->device);
156 
157 	*features = bus->pci->read_io_32(bus->device,
158 		bus->base_addr + VIRTIO_PCI_HOST_FEATURES);
159 	return B_OK;
160 }
161 
162 
163 static status_t
164 write_guest_features(void* cookie, uint32 features)
165 {
166 	CALLED();
167 	virtio_pci_sim_info* bus = (virtio_pci_sim_info*)cookie;
168 	bus->pci->write_io_32(bus->device, bus->base_addr
169 		+ VIRTIO_PCI_GUEST_FEATURES, features);
170 	return B_OK;
171 }
172 
173 
174 uint8
175 get_status(void* cookie)
176 {
177 	CALLED();
178 	virtio_pci_sim_info* bus = (virtio_pci_sim_info*)cookie;
179 	return bus->pci->read_io_8(bus->device, bus->base_addr
180 		+ VIRTIO_PCI_STATUS);
181 }
182 
183 
184 void
185 set_status(void* cookie, uint8 status)
186 {
187 	CALLED();
188 	virtio_pci_sim_info* bus = (virtio_pci_sim_info*)cookie;
189 	bus->pci->write_io_8(bus->device, bus->base_addr + VIRTIO_PCI_STATUS,
190 		status);
191 }
192 
193 
194 status_t
195 read_device_config(void* cookie, uint8 _offset, void* _buffer,
196 	size_t bufferSize)
197 {
198 	CALLED();
199 	virtio_pci_sim_info* bus = (virtio_pci_sim_info*)cookie;
200 
201 	addr_t offset = bus->base_addr + VIRTIO_PCI_CONFIG(bus) + _offset;
202 	uint8* buffer = (uint8*)_buffer;
203 	while (bufferSize > 0) {
204 		uint8 size = 4;
205 		if (bufferSize == 1) {
206 			size = 1;
207 			*buffer = bus->pci->read_io_8(bus->device,
208 			offset);
209 		} else if (bufferSize <= 3) {
210 			size = 2;
211 			*(uint16*)buffer = bus->pci->read_io_16(bus->device,
212 			offset);
213 		} else {
214 			*(uint32*)buffer = bus->pci->read_io_32(bus->device,
215 				offset);
216 		}
217 		buffer += size;
218 		bufferSize -= size;
219 		offset += size;
220 	}
221 
222 	return B_OK;
223 }
224 
225 
226 status_t
227 write_device_config(void* cookie, uint8 _offset, const void* _buffer,
228 	size_t bufferSize)
229 {
230 	CALLED();
231 	virtio_pci_sim_info* bus = (virtio_pci_sim_info*)cookie;
232 
233 	addr_t offset = bus->base_addr + VIRTIO_PCI_CONFIG(bus) + _offset;
234 	const uint8* buffer = (const uint8*)_buffer;
235 	while (bufferSize > 0) {
236 		uint8 size = 4;
237 		if (bufferSize == 1) {
238 			size = 1;
239 			bus->pci->write_io_8(bus->device,
240 				offset, *buffer);
241 		} else if (bufferSize <= 3) {
242 			size = 2;
243 			bus->pci->write_io_16(bus->device,
244 				offset, *(const uint16*)buffer);
245 		} else {
246 			bus->pci->write_io_32(bus->device,
247 				offset, *(const uint32*)buffer);
248 		}
249 		buffer += size;
250 		bufferSize -= size;
251 		offset += size;
252 	}
253 	return B_OK;
254 }
255 
256 
257 uint16
258 get_queue_ring_size(void* cookie, uint16 queue)
259 {
260 	CALLED();
261 	virtio_pci_sim_info* bus = (virtio_pci_sim_info*)cookie;
262 	bus->pci->write_io_16(bus->device, bus->base_addr + VIRTIO_PCI_QUEUE_SEL,
263 		queue);
264 	return bus->pci->read_io_16(bus->device, bus->base_addr
265 		+ VIRTIO_PCI_QUEUE_NUM);
266 }
267 
268 
269 status_t
270 setup_queue(void* cookie, uint16 queue, phys_addr_t phy)
271 {
272 	CALLED();
273 	virtio_pci_sim_info* bus = (virtio_pci_sim_info*)cookie;
274 	bus->pci->write_io_16(bus->device, bus->base_addr + VIRTIO_PCI_QUEUE_SEL,
275 		queue);
276 	bus->pci->write_io_32(bus->device, bus->base_addr + VIRTIO_PCI_QUEUE_PFN,
277 		(uint32)phy >> VIRTIO_PCI_QUEUE_ADDR_SHIFT);
278 	return B_OK;
279 }
280 
281 
282 status_t
283 setup_interrupt(void* cookie, uint16 queueCount)
284 {
285 	CALLED();
286 	virtio_pci_sim_info* bus = (virtio_pci_sim_info*)cookie;
287 	pci_info *pciInfo = &bus->info;
288 
289 	bus->queue_count = queueCount;
290 
291 	// try MSI-X
292 	uint8 msixCount = bus->pci->get_msix_count(bus->device);
293 	if (msixCount >= 1) {
294 		if (msixCount >= (queueCount + 1)) {
295 			uint8 vector;
296 			bus->cookies = new(std::nothrow)
297 				virtio_pci_queue_cookie[queueCount];
298 			if (bus->cookies != NULL
299 				&& bus->pci->configure_msix(bus->device, queueCount + 1,
300 					&vector) == B_OK
301 				&& bus->pci->enable_msix(bus->device) == B_OK) {
302 				TRACE_ALWAYS("using MSI-X count %u starting at %d\n",
303 					queueCount + 1, vector);
304 				bus->irq = vector;
305 				bus->irq_type = VIRTIO_IRQ_MSI_X;
306 			} else {
307 				ERROR("couldn't use MSI-X\n");
308 			}
309 		} else {
310 			uint8 vector;
311 			if (bus->pci->configure_msix(bus->device, queueCount + 1, &vector) == B_OK
312 				&& bus->pci->enable_msix(bus->device) == B_OK) {
313 				TRACE_ALWAYS("using MSI-X vector shared %u\n", 1);
314 				bus->irq = vector;
315 				bus->irq_type = VIRTIO_IRQ_MSI_X_SHARED;
316 			} else {
317 				ERROR("couldn't use MSI-X SHARED\n");
318 			}
319 		}
320 	} else if (bus->pci->get_msi_count(bus->device) >= 1) {
321 		// try MSI
322 		uint8 vector;
323 		if (bus->pci->configure_msi(bus->device, 1, &vector) == B_OK
324 			&& bus->pci->enable_msi(bus->device) == B_OK) {
325 			TRACE_ALWAYS("using MSI vector %u\n", vector);
326 			bus->irq = vector;
327 			bus->irq_type = VIRTIO_IRQ_MSI;
328 		} else {
329 			ERROR("couldn't use MSI\n");
330 		}
331 	}
332 
333 	if (bus->irq_type == VIRTIO_IRQ_LEGACY) {
334 		bus->irq = pciInfo->u.h0.interrupt_line;
335 		TRACE_ALWAYS("using legacy interrupt %u\n", bus->irq);
336 	}
337 	if (bus->irq == 0 || bus->irq == 0xff) {
338 		ERROR("PCI IRQ not assigned\n");
339 		delete bus;
340 		return B_ERROR;
341 	}
342 
343 	if (bus->irq_type == VIRTIO_IRQ_MSI_X) {
344 		status_t status = install_io_interrupt_handler(bus->irq,
345 			virtio_pci_config_interrupt, bus, 0);
346 		if (status != B_OK) {
347 			ERROR("can't install interrupt handler\n");
348 			return status;
349 		}
350 		int32 irq = bus->irq + 1;
351 		for (int32 queue = 0; queue < queueCount; queue++, irq++) {
352 			bus->cookies[queue].sim = bus->sim;
353 			bus->cookies[queue].queue = queue;
354 			status_t status = install_io_interrupt_handler(irq,
355 				virtio_pci_queue_interrupt, &bus->cookies[queue], 0);
356 			if (status != B_OK) {
357 				ERROR("can't install interrupt handler\n");
358 				return status;
359 			}
360 		}
361 		TRACE("setup_interrupt() installed MSI-X interrupt handlers\n");
362 		virtio_pci_setup_msix_interrupts(bus);
363 	} else {
364 		// setup interrupt handler
365 		status_t status = install_io_interrupt_handler(bus->irq,
366 			virtio_pci_interrupt, bus, 0);
367 		if (status != B_OK) {
368 			ERROR("can't install interrupt handler\n");
369 			return status;
370 		}
371 		TRACE("setup_interrupt() installed legacy interrupt handler\n");
372 	}
373 
374 	return B_OK;
375 }
376 
377 
378 status_t
379 free_interrupt(void* cookie)
380 {
381 	CALLED();
382 	virtio_pci_sim_info* bus = (virtio_pci_sim_info*)cookie;
383 
384 	if (bus->irq_type == VIRTIO_IRQ_MSI_X) {
385 		remove_io_interrupt_handler(bus->irq, virtio_pci_config_interrupt,
386 			bus);
387 		int32 irq = bus->irq + 1;
388 		for (int32 queue = 0; queue < bus->queue_count; queue++, irq++) {
389 			remove_io_interrupt_handler(irq, virtio_pci_queue_interrupt,
390 				&bus->cookies[queue]);
391 		}
392 		delete[] bus->cookies;
393 
394 	} else
395 		remove_io_interrupt_handler(bus->irq, virtio_pci_interrupt, bus);
396 
397 	if (bus->irq_type != VIRTIO_IRQ_LEGACY) {
398 		bus->pci->disable_msi(bus->device);
399 		bus->pci->unconfigure_msi(bus->device);
400 	}
401 	return B_OK;
402 }
403 
404 
405 void
406 notify_queue(void* cookie, uint16 queue)
407 {
408 	CALLED();
409 	virtio_pci_sim_info* bus = (virtio_pci_sim_info*)cookie;
410 	bus->pci->write_io_16(bus->device, bus->base_addr
411 		+ VIRTIO_PCI_QUEUE_NOTIFY, queue);
412 }
413 
414 
415 //	#pragma mark -
416 
417 
418 static status_t
419 init_bus(device_node* node, void** bus_cookie)
420 {
421 	CALLED();
422 	status_t status = B_OK;
423 
424 	virtio_pci_sim_info* bus = new(std::nothrow) virtio_pci_sim_info;
425 	if (bus == NULL) {
426 		return B_NO_MEMORY;
427 	}
428 
429 	pci_device_module_info* pci;
430 	pci_device* device;
431 	{
432 		device_node* parent = gDeviceManager->get_parent_node(node);
433 		device_node* pciParent = gDeviceManager->get_parent_node(parent);
434 		gDeviceManager->get_driver(pciParent, (driver_module_info**)&pci,
435 			(void**)&device);
436 		gDeviceManager->put_node(pciParent);
437 		gDeviceManager->put_node(parent);
438 	}
439 
440 	bus->node = node;
441 	bus->pci = pci;
442 	bus->device = device;
443 	bus->cookies = NULL;
444 	bus->irq_type = VIRTIO_IRQ_LEGACY;
445 
446 	pci_info *pciInfo = &bus->info;
447 	pci->get_pci_info(device, pciInfo);
448 
449 	// legacy interrupt
450 	bus->base_addr = pciInfo->u.h0.base_registers[0];
451 
452 	// enable bus master and io
453 	uint16 pcicmd = pci->read_pci_config(device, PCI_command, 2);
454 	pcicmd &= ~(PCI_command_memory | PCI_command_int_disable);
455 	pcicmd |= PCI_command_master | PCI_command_io;
456 	pci->write_pci_config(device, PCI_command, 2, pcicmd);
457 
458 	set_status(bus, VIRTIO_CONFIG_STATUS_RESET);
459 	set_status(bus, VIRTIO_CONFIG_STATUS_ACK);
460 
461 	TRACE("init_bus() %p node %p pci %p device %p\n", bus, node,
462 		bus->pci, bus->device);
463 
464 	*bus_cookie = bus;
465 	return status;
466 }
467 
468 
469 static void
470 uninit_bus(void* bus_cookie)
471 {
472 	virtio_pci_sim_info* bus = (virtio_pci_sim_info*)bus_cookie;
473 	if (bus->irq_type != VIRTIO_IRQ_LEGACY) {
474 		if (bus->irq_type == VIRTIO_IRQ_MSI) {
475 			remove_io_interrupt_handler(bus->irq, virtio_pci_interrupt, bus);
476 		} else {
477 			int32 irq = bus->irq + 1;
478 			for (uint16 queue = 0; queue < bus->queue_count; queue++, irq++) {
479 				remove_io_interrupt_handler(irq, virtio_pci_queue_interrupt,
480 					&bus->cookies[queue]);
481 			}
482 			remove_io_interrupt_handler(bus->irq, virtio_pci_config_interrupt,
483 					bus);
484 		}
485 
486 		bus->pci->disable_msi(bus->device);
487 		bus->pci->unconfigure_msi(bus->device);
488 	} else
489 		remove_io_interrupt_handler(bus->irq, virtio_pci_interrupt, bus);
490 
491 	delete[] bus->cookies;
492 	delete bus;
493 }
494 
495 
496 static void
497 bus_removed(void* bus_cookie)
498 {
499 	return;
500 }
501 
502 
503 //	#pragma mark -
504 
505 
506 static status_t
507 register_child_devices(void* cookie)
508 {
509 	CALLED();
510 	device_node* node = (device_node*)cookie;
511 	device_node* parent = gDeviceManager->get_parent_node(node);
512 	pci_device_module_info* pci;
513 	pci_device* device;
514 	gDeviceManager->get_driver(parent, (driver_module_info**)&pci,
515 		(void**)&device);
516 
517 	uint16 pciSubDeviceId = pci->read_pci_config(device, PCI_subsystem_id,
518 		2);
519 
520 	char prettyName[25];
521 	sprintf(prettyName, "Virtio Device %" B_PRIu16, pciSubDeviceId);
522 
523 	device_attr attrs[] = {
524 		// properties of this controller for virtio bus manager
525 		{ B_DEVICE_PRETTY_NAME, B_STRING_TYPE,
526 			{ .string = prettyName }},
527 		{ B_DEVICE_FIXED_CHILD, B_STRING_TYPE,
528 			{ .string = VIRTIO_FOR_CONTROLLER_MODULE_NAME }},
529 
530 		// private data to identify the device
531 		{ VIRTIO_DEVICE_TYPE_ITEM, B_UINT16_TYPE,
532 			{ .ui16 = pciSubDeviceId }},
533 		{ VIRTIO_VRING_ALIGNMENT_ITEM, B_UINT16_TYPE,
534 			{ .ui16 = VIRTIO_PCI_VRING_ALIGN }},
535 		{ NULL }
536 	};
537 
538 	return gDeviceManager->register_node(node, VIRTIO_PCI_SIM_MODULE_NAME,
539 		attrs, NULL, &node);
540 }
541 
542 
543 static status_t
544 init_device(device_node* node, void** device_cookie)
545 {
546 	CALLED();
547 	*device_cookie = node;
548 	return B_OK;
549 }
550 
551 
552 static status_t
553 register_device(device_node* parent)
554 {
555 	device_attr attrs[] = {
556 		{B_DEVICE_PRETTY_NAME, B_STRING_TYPE, {.string = "Virtio PCI"}},
557 		{}
558 	};
559 
560 	return gDeviceManager->register_node(parent, VIRTIO_PCI_DEVICE_MODULE_NAME,
561 		attrs, NULL, NULL);
562 }
563 
564 
565 static float
566 supports_device(device_node* parent)
567 {
568 	CALLED();
569 	const char* bus;
570 	uint16 vendorID, deviceID;
571 
572 	// make sure parent is a PCI Virtio device node
573 	if (gDeviceManager->get_attr_string(parent, B_DEVICE_BUS, &bus, false) != B_OK
574 		|| gDeviceManager->get_attr_uint16(parent, B_DEVICE_VENDOR_ID,
575 				&vendorID, false) < B_OK
576 		|| gDeviceManager->get_attr_uint16(parent, B_DEVICE_ID, &deviceID,
577 				false) < B_OK) {
578 		return -1;
579 	}
580 
581 	if (strcmp(bus, "pci") != 0)
582 		return 0.0f;
583 
584 	if (vendorID == VIRTIO_PCI_VENDORID) {
585 		if (deviceID < VIRTIO_PCI_DEVICEID_MIN
586 			|| deviceID > VIRTIO_PCI_DEVICEID_MAX) {
587 			return 0.0f;
588 		}
589 
590 		pci_device_module_info* pci;
591 		pci_device* device;
592 		gDeviceManager->get_driver(parent, (driver_module_info**)&pci,
593 			(void**)&device);
594 		uint8 pciSubDeviceId = pci->read_pci_config(device, PCI_revision,
595 			1);
596 		if (pciSubDeviceId != VIRTIO_PCI_ABI_VERSION)
597 			return 0.0f;
598 
599 		TRACE("Virtio device found! vendor 0x%04x, device 0x%04x\n", vendorID,
600 			deviceID);
601 		return 0.8f;
602 	}
603 
604 	return 0.0f;
605 }
606 
607 
608 //	#pragma mark -
609 
610 
611 module_dependency module_dependencies[] = {
612 	{ VIRTIO_FOR_CONTROLLER_MODULE_NAME, (module_info**)&gVirtio },
613 	{ B_DEVICE_MANAGER_MODULE_NAME, (module_info**)&gDeviceManager },
614 	{}
615 };
616 
617 
618 static virtio_sim_interface gVirtioPCIDeviceModule = {
619 	{
620 		{
621 			VIRTIO_PCI_SIM_MODULE_NAME,
622 			0,
623 			NULL
624 		},
625 
626 		NULL,	// supports device
627 		NULL,	// register device
628 		init_bus,
629 		uninit_bus,
630 		NULL,	// register child devices
631 		NULL,	// rescan
632 		bus_removed,
633 	},
634 
635 	set_sim,
636 	read_host_features,
637 	write_guest_features,
638 	get_status,
639 	set_status,
640 	read_device_config,
641 	write_device_config,
642 	get_queue_ring_size,
643 	setup_queue,
644 	setup_interrupt,
645 	free_interrupt,
646 	notify_queue
647 };
648 
649 
650 static driver_module_info sVirtioDevice = {
651 	{
652 		VIRTIO_PCI_DEVICE_MODULE_NAME,
653 		0,
654 		NULL
655 	},
656 
657 	supports_device,
658 	register_device,
659 	init_device,
660 	NULL,	// uninit
661 	register_child_devices,
662 	NULL,	// rescan
663 	NULL,	// device removed
664 };
665 
666 module_info* modules[] = {
667 	(module_info* )&sVirtioDevice,
668 	(module_info* )&gVirtioPCIDeviceModule,
669 	NULL
670 };
671