xref: /haiku/src/add-ons/kernel/busses/virtio/virtio_pci/virtio_pci.cpp (revision 01dc1ea4cfb70a5499b7d90f91fede60e50c468f)
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 <SupportDefs.h>
13 
14 #include <kernel.h>
15 #include <virtio.h>
16 
17 #include "virtio_pci.h"
18 
19 
20 //#define TRACE_VIRTIO
21 #ifdef TRACE_VIRTIO
22 #	define TRACE(x...) dprintf("\33[33mvirtio_pci:\33[0m " x)
23 #else
24 #	define TRACE(x...) ;
25 #endif
26 #define TRACE_ALWAYS(x...)	dprintf("\33[33mvirtio_pci:\33[0m " x)
27 #define ERROR(x...)			dprintf("\33[33mvirtio_pci:\33[0m " x)
28 #define CALLED(x...)		TRACE("CALLED %s\n", __PRETTY_FUNCTION__)
29 
30 
31 #define VIRTIO_PCI_DEVICE_MODULE_NAME "busses/virtio/virtio_pci/driver_v1"
32 #define VIRTIO_PCI_SIM_MODULE_NAME "busses/virtio/virtio_pci/device/v1"
33 
34 #define VIRTIO_PCI_CONTROLLER_TYPE_NAME "virtio pci controller"
35 
36 typedef enum {
37 	VIRTIO_IRQ_LEGACY,
38 	VIRTIO_IRQ_MSI_X_SHARED,
39 	VIRTIO_IRQ_MSI_X,
40 } virtio_irq_type;
41 
42 typedef struct {
43 	virtio_sim sim;
44 	uint16 queue;
45 } virtio_pci_queue_cookie;
46 
47 typedef struct {
48 	pci_device_module_info* pci;
49 	pci_device* device;
50 	bool virtio1;
51 	addr_t base_addr;
52 	area_id registersArea[4];
53 	addr_t commonCfgAddr;
54 	addr_t isrAddr;
55 	addr_t notifyAddr;
56 	uint32 notifyOffsetMultiplier;
57 	uint8 irq;
58 	virtio_irq_type irq_type;
59 	virtio_sim sim;
60 	uint16 queue_count;
61 	addr_t* notifyOffsets;
62 
63 	device_node* node;
64 	pci_info info;
65 
66 	virtio_pci_queue_cookie *cookies;
67 } virtio_pci_sim_info;
68 
69 
70 device_manager_info* gDeviceManager;
71 virtio_for_controller_interface* gVirtio;
72 
73 
74 static status_t
75 virtio_pci_find_capability(virtio_pci_sim_info* bus, uint8 cfgType,
76 	void* buffer, size_t size)
77 {
78 	uint8 capabilityOffset;
79 	if (bus->pci->find_pci_capability(bus->device, PCI_cap_id_vendspec, &capabilityOffset) != B_OK)
80 		return B_ENTRY_NOT_FOUND;
81 
82 	if (size < sizeof(virtio_pci_cap))
83 		return B_RESULT_NOT_REPRESENTABLE;
84 	union regs {
85 		uint32 reg[8];
86 		struct virtio_pci_cap capability;
87 	} * v = (union regs*)buffer;
88 
89 	while (capabilityOffset != 0) {
90 		for (int i = 0; i < 4; i++) {
91 			v->reg[i] = bus->pci->read_pci_config(bus->device, capabilityOffset + i * 4, 4);
92 		}
93 		if (v->capability.cfg_type == cfgType)
94 			break;
95 		capabilityOffset = v->capability.cap_next;
96 	}
97 	if (capabilityOffset == 0)
98 		return B_ENTRY_NOT_FOUND;
99 
100 	if (v->capability.length > sizeof(virtio_pci_cap)) {
101 		size_t length = min_c(ROUNDUP(v->capability.length, sizeof(uint32)), size);
102 		for (size_t i = 4; i < length / sizeof(uint32); i++)
103 			v->reg[i] = bus->pci->read_pci_config(bus->device, capabilityOffset + i * 4, 4);
104 	}
105 	return B_OK;
106 }
107 
108 
109 static int32
110 virtio_pci_interrupt(void *data)
111 {
112 	virtio_pci_sim_info* bus = (virtio_pci_sim_info*)data;
113 	uint8 isr;
114 	if (bus->virtio1) {
115 		uint8* isrAddr = (uint8*)bus->isrAddr;
116 		isr = *isrAddr;
117 	} else {
118 		isr = bus->pci->read_io_8(bus->device,
119 			bus->base_addr + VIRTIO_PCI_ISR);
120 	}
121 	if (isr == 0)
122 		return B_UNHANDLED_INTERRUPT;
123 
124 	if (isr & VIRTIO_PCI_ISR_CONFIG)
125 		gVirtio->config_interrupt_handler(bus->sim);
126 
127 	if (isr & VIRTIO_PCI_ISR_INTR)
128 		gVirtio->queue_interrupt_handler(bus->sim, INT16_MAX);
129 
130 	return B_HANDLED_INTERRUPT;
131 }
132 
133 
134 static int32
135 virtio_pci_config_interrupt(void *data)
136 {
137 	virtio_pci_sim_info* bus = (virtio_pci_sim_info*)data;
138 	gVirtio->config_interrupt_handler(bus->sim);
139 
140 	return B_HANDLED_INTERRUPT;
141 }
142 
143 
144 static int32
145 virtio_pci_queue_interrupt(void *data)
146 {
147 	virtio_pci_queue_cookie* cookie = (virtio_pci_queue_cookie*)data;
148 	gVirtio->queue_interrupt_handler(cookie->sim, cookie->queue);
149 
150 	return B_HANDLED_INTERRUPT;
151 }
152 
153 
154 static int32
155 virtio_pci_queues_interrupt(void *data)
156 {
157 	virtio_pci_sim_info* bus = (virtio_pci_sim_info*)data;
158 	gVirtio->queue_interrupt_handler(bus->sim, INT16_MAX);
159 
160 	return B_HANDLED_INTERRUPT;
161 }
162 
163 
164 static status_t
165 virtio_pci_setup_msix_interrupts(virtio_pci_sim_info* bus)
166 {
167 	CALLED();
168 	uint8 irq = 0; // first irq slot
169 	if (bus->virtio1) {
170 		volatile uint16 *msixVector = (uint16*)(bus->commonCfgAddr
171 			+ offsetof(struct virtio_pci_common_cfg, config_msix_vector));
172 		*msixVector = irq;
173 	} else {
174 		bus->pci->write_io_16(bus->device, bus->base_addr
175 			+ VIRTIO_MSI_CONFIG_VECTOR, irq);
176 		if (bus->pci->read_io_16(bus->device, bus->base_addr
177 			+ VIRTIO_MSI_CONFIG_VECTOR) == VIRTIO_MSI_NO_VECTOR) {
178 			ERROR("msix config vector incorrect\n");
179 			return B_BAD_VALUE;
180 		}
181 	}
182 	if (bus->irq_type == VIRTIO_IRQ_MSI_X || bus->irq_type == VIRTIO_IRQ_MSI_X_SHARED)
183 		irq++;
184 
185 	for (uint16 queue = 0; queue < bus->queue_count; queue++) {
186 		if (bus->virtio1) {
187 			volatile uint16* queueSelect = (uint16*)(bus->commonCfgAddr
188 				+ offsetof(struct virtio_pci_common_cfg, queue_select));
189 			*queueSelect = queue;
190 			volatile uint16* msixVector = (uint16*)(bus->commonCfgAddr
191 				+ offsetof(struct virtio_pci_common_cfg, queue_msix_vector));
192 			*msixVector = irq;
193 		} else {
194 			bus->pci->write_io_16(bus->device, bus->base_addr
195 				+ VIRTIO_PCI_QUEUE_SEL, queue);
196 			bus->pci->write_io_16(bus->device, bus->base_addr
197 				+ VIRTIO_MSI_QUEUE_VECTOR, irq);
198 
199 			if (bus->pci->read_io_16(bus->device, bus->base_addr
200 				+ VIRTIO_MSI_QUEUE_VECTOR) == VIRTIO_MSI_NO_VECTOR) {
201 				ERROR("msix queue vector incorrect\n");
202 				return B_BAD_VALUE;
203 			}
204 		}
205 		if (bus->irq_type == VIRTIO_IRQ_MSI_X)
206 			irq++;
207 	}
208 
209 	return B_OK;
210 }
211 
212 
213 static void
214 set_sim(void* cookie, virtio_sim sim)
215 {
216 	CALLED();
217 	virtio_pci_sim_info* bus = (virtio_pci_sim_info*)cookie;
218 	bus->sim = sim;
219 }
220 
221 
222 static status_t
223 read_host_features(void* cookie, uint64 *features)
224 {
225 	CALLED();
226 	virtio_pci_sim_info* bus = (virtio_pci_sim_info*)cookie;
227 
228 	TRACE("read_host_features() %p node %p pci %p device %p\n", bus,
229 		bus->node, bus->pci, bus->device);
230 
231 	if (bus->virtio1) {
232 		volatile uint32 *select = (uint32*)(bus->commonCfgAddr
233 			+ offsetof(struct virtio_pci_common_cfg, device_feature_select));
234 		volatile uint32 *feature = (uint32*)(bus->commonCfgAddr
235 			+ offsetof(struct virtio_pci_common_cfg, device_feature));
236 		*select = 0;
237 		*features = *feature;
238 		*select = 1;
239 		*features |= ((uint64)*feature << 32) ;
240 		TRACE("read_host_features() %" B_PRIx64 "\n", *features);
241 	} else {
242 		*features = bus->pci->read_io_32(bus->device,
243 			bus->base_addr + VIRTIO_PCI_HOST_FEATURES);
244 	}
245 	return B_OK;
246 }
247 
248 
249 static status_t
250 write_guest_features(void* cookie, uint64 features)
251 {
252 	CALLED();
253 	virtio_pci_sim_info* bus = (virtio_pci_sim_info*)cookie;
254 	if (bus->virtio1) {
255 		volatile uint32 *select = (uint32*)(bus->commonCfgAddr
256 			+ offsetof(struct virtio_pci_common_cfg, device_feature_select));
257 		volatile uint32 *feature = (uint32*)(bus->commonCfgAddr
258 			+ offsetof(struct virtio_pci_common_cfg, device_feature));
259 		*select = 0;
260 		*feature = features & 0xffffffff;
261 		*select = 1;
262 		*feature = (features >> 32) ;
263 	} else {
264 		bus->pci->write_io_32(bus->device, bus->base_addr
265 			+ VIRTIO_PCI_GUEST_FEATURES, features);
266 	}
267 	return B_OK;
268 }
269 
270 
271 static uint8
272 get_status(void* cookie)
273 {
274 	CALLED();
275 	virtio_pci_sim_info* bus = (virtio_pci_sim_info*)cookie;
276 	if (bus->virtio1) {
277 		uint8 *addr = (uint8*)(bus->commonCfgAddr
278 			+ offsetof(struct virtio_pci_common_cfg, device_status));
279 		return *addr;
280 	} else {
281 		return bus->pci->read_io_8(bus->device, bus->base_addr + VIRTIO_PCI_STATUS);
282 	}
283 }
284 
285 
286 static void
287 set_status(void* cookie, uint8 status)
288 {
289 	CALLED();
290 	virtio_pci_sim_info* bus = (virtio_pci_sim_info*)cookie;
291 	if (bus->virtio1) {
292 		uint8 *addr = (uint8*)(bus->commonCfgAddr
293 			+ offsetof(struct virtio_pci_common_cfg, device_status));
294 		uint8 old = 0;
295 		if (status != 0)
296 			old = *addr;
297 		*addr = status | old;
298 	} else {
299 		uint8 old = 0;
300 		if (status != 0)
301 			old = bus->pci->read_io_8(bus->device, bus->base_addr + VIRTIO_PCI_STATUS);
302 		bus->pci->write_io_8(bus->device, bus->base_addr + VIRTIO_PCI_STATUS, status | old);
303 	}
304 }
305 
306 
307 static status_t
308 read_device_config(void* cookie, uint8 _offset, void* _buffer,
309 	size_t bufferSize)
310 {
311 	CALLED();
312 	virtio_pci_sim_info* bus = (virtio_pci_sim_info*)cookie;
313 
314 	addr_t offset = bus->base_addr + _offset;
315 	if (!bus->virtio1)
316 		offset += VIRTIO_PCI_CONFIG(bus);
317 	uint8* buffer = (uint8*)_buffer;
318 	while (bufferSize > 0) {
319 		uint8 size = 4;
320 		if (bufferSize == 1) {
321 			size = 1;
322 			if (bus->virtio1) {
323 				*buffer = *(uint8*)offset;
324 			} else {
325 				*buffer = bus->pci->read_io_8(bus->device, offset);
326 			}
327 		} else if (bufferSize <= 3) {
328 			size = 2;
329 			if (bus->virtio1) {
330 				*(uint16*)buffer = *(uint16*)offset;
331 			} else {
332 				*(uint16*)buffer = bus->pci->read_io_16(bus->device, offset);
333 			}
334 		} else {
335 			if (bus->virtio1) {
336 				*(uint32*)buffer = *(uint32*)offset;
337 			} else {
338 				*(uint32*)buffer = bus->pci->read_io_32(bus->device,
339 					offset);
340 			}
341 		}
342 		buffer += size;
343 		bufferSize -= size;
344 		offset += size;
345 	}
346 
347 	return B_OK;
348 }
349 
350 
351 static status_t
352 write_device_config(void* cookie, uint8 _offset, const void* _buffer,
353 	size_t bufferSize)
354 {
355 	CALLED();
356 	virtio_pci_sim_info* bus = (virtio_pci_sim_info*)cookie;
357 
358 	addr_t offset = bus->base_addr + _offset;
359 	if (!bus->virtio1)
360 		offset += VIRTIO_PCI_CONFIG(bus);
361 	const uint8* buffer = (const uint8*)_buffer;
362 	while (bufferSize > 0) {
363 		uint8 size = 4;
364 		if (bufferSize == 1) {
365 			size = 1;
366 			if (bus->virtio1) {
367 				*(uint8*)offset = *buffer;
368 			} else {
369 				bus->pci->write_io_8(bus->device, offset, *buffer);
370 			}
371 		} else if (bufferSize <= 3) {
372 			size = 2;
373 			if (bus->virtio1) {
374 				*(uint16*)offset = *(uint16*)buffer;
375 			} else {
376 				bus->pci->write_io_16(bus->device, offset, *(const uint16*)buffer);
377 			}
378 		} else {
379 			if (bus->virtio1) {
380 				*(uint32*)offset = *(uint32*)buffer;
381 			} else {
382 				bus->pci->write_io_32(bus->device, offset, *(const uint32*)buffer);
383 			}
384 		}
385 		buffer += size;
386 		bufferSize -= size;
387 		offset += size;
388 	}
389 	return B_OK;
390 }
391 
392 
393 static uint16
394 get_queue_ring_size(void* cookie, uint16 queue)
395 {
396 	CALLED();
397 	virtio_pci_sim_info* bus = (virtio_pci_sim_info*)cookie;
398 	if (bus->virtio1) {
399 		volatile uint16* queueSelect = (uint16*)(bus->commonCfgAddr
400 			+ offsetof(struct virtio_pci_common_cfg, queue_select));
401 		*queueSelect = queue;
402 		volatile uint16* ringSize = (volatile uint16*)(bus->commonCfgAddr
403 			+ offsetof(struct virtio_pci_common_cfg, queue_size));
404 		return *ringSize;
405 	} else {
406 		bus->pci->write_io_16(bus->device, bus->base_addr + VIRTIO_PCI_QUEUE_SEL,
407 			queue);
408 		return bus->pci->read_io_16(bus->device, bus->base_addr
409 			+ VIRTIO_PCI_QUEUE_NUM);
410 	}
411 }
412 
413 
414 static status_t
415 setup_queue(void* cookie, uint16 queue, phys_addr_t phy, phys_addr_t phyAvail,
416 	phys_addr_t phyUsed)
417 {
418 	CALLED();
419 	virtio_pci_sim_info* bus = (virtio_pci_sim_info*)cookie;
420 	if (queue >= bus->queue_count)
421 		return B_BAD_VALUE;
422 
423 	if (bus->virtio1) {
424 		volatile uint16* queueSelect = (uint16*)(bus->commonCfgAddr
425 			+ offsetof(struct virtio_pci_common_cfg, queue_select));
426 		*queueSelect = queue;
427 
428 		volatile uint64* queueDesc = (volatile uint64*)(bus->commonCfgAddr
429 			+ offsetof(struct virtio_pci_common_cfg, queue_desc));
430 		*queueDesc = phy;
431 		volatile uint64* queueAvail = (volatile uint64*)(bus->commonCfgAddr
432 			+ offsetof(struct virtio_pci_common_cfg, queue_avail));
433 		*queueAvail = phyAvail;
434 		volatile uint64* queueUsed = (volatile uint64*)(bus->commonCfgAddr
435 			+ offsetof(struct virtio_pci_common_cfg, queue_used));
436 		*queueUsed = phyUsed;
437 		volatile uint16* queueEnable = (volatile uint16*)(bus->commonCfgAddr
438 			+ offsetof(struct virtio_pci_common_cfg, queue_enable));
439 		*queueEnable = 1;
440 
441 		volatile uint16* queueNotifyOffset = (volatile uint16*)(bus->commonCfgAddr
442 			+ offsetof(struct virtio_pci_common_cfg, queue_notify_off));
443 		bus->notifyOffsets[queue] = *queueNotifyOffset * bus->notifyOffsetMultiplier;
444 	} else {
445 		bus->pci->write_io_16(bus->device, bus->base_addr + VIRTIO_PCI_QUEUE_SEL, queue);
446 		bus->pci->write_io_32(bus->device, bus->base_addr + VIRTIO_PCI_QUEUE_PFN,
447 			(uint32)phy >> VIRTIO_PCI_QUEUE_ADDR_SHIFT);
448 	}
449 	return B_OK;
450 }
451 
452 
453 static status_t
454 setup_interrupt(void* cookie, uint16 queueCount)
455 {
456 	CALLED();
457 	virtio_pci_sim_info* bus = (virtio_pci_sim_info*)cookie;
458 	pci_info *pciInfo = &bus->info;
459 
460 	bus->queue_count = queueCount;
461 
462 	// try MSI-X
463 	uint8 msixCount = bus->pci->get_msix_count(bus->device);
464 	if (msixCount >= 2) {
465 		if (msixCount >= (queueCount + 1)) {
466 			uint8 vector;
467 			bus->cookies = new(std::nothrow)
468 				virtio_pci_queue_cookie[queueCount];
469 			if (bus->cookies != NULL
470 				&& bus->pci->configure_msix(bus->device, queueCount + 1,
471 					&vector) == B_OK
472 				&& bus->pci->enable_msix(bus->device) == B_OK) {
473 				TRACE_ALWAYS("using MSI-X count %u starting at %d\n",
474 					queueCount + 1, vector);
475 				bus->irq = vector;
476 				bus->irq_type = VIRTIO_IRQ_MSI_X;
477 			} else {
478 				ERROR("couldn't use MSI-X\n");
479 			}
480 		} else {
481 			uint8 vector;
482 			if (bus->pci->configure_msix(bus->device, 2, &vector) == B_OK
483 				&& bus->pci->enable_msix(bus->device) == B_OK) {
484 				TRACE_ALWAYS("using MSI-X vector shared %u\n", vector);
485 				bus->irq = vector;
486 				bus->irq_type = VIRTIO_IRQ_MSI_X_SHARED;
487 			} else {
488 				ERROR("couldn't use MSI-X SHARED\n");
489 			}
490 		}
491 	}
492 
493 	if (bus->irq_type == VIRTIO_IRQ_LEGACY) {
494 		bus->irq = pciInfo->u.h0.interrupt_line;
495 		TRACE_ALWAYS("using legacy interrupt %u\n", bus->irq);
496 	}
497 	if (bus->irq == 0 || bus->irq == 0xff) {
498 		ERROR("PCI IRQ not assigned\n");
499 		delete bus;
500 		return B_ERROR;
501 	}
502 
503 	if (bus->irq_type != VIRTIO_IRQ_LEGACY) {
504 		status_t status = install_io_interrupt_handler(bus->irq,
505 			virtio_pci_config_interrupt, bus, 0);
506 		if (status != B_OK) {
507 			ERROR("can't install interrupt handler\n");
508 			return status;
509 		}
510 		int32 irq = bus->irq + 1;
511 		if (bus->irq_type == VIRTIO_IRQ_MSI_X) {
512 			for (int32 queue = 0; queue < queueCount; queue++, irq++) {
513 				bus->cookies[queue].sim = bus->sim;
514 				bus->cookies[queue].queue = queue;
515 				status_t status = install_io_interrupt_handler(irq,
516 					virtio_pci_queue_interrupt, &bus->cookies[queue], 0);
517 				if (status != B_OK) {
518 					ERROR("can't install interrupt handler\n");
519 					return status;
520 				}
521 			}
522 		} else {
523 			status_t status = install_io_interrupt_handler(irq,
524 				virtio_pci_queues_interrupt, bus, 0);
525 			if (status != B_OK) {
526 				ERROR("can't install interrupt handler\n");
527 				return status;
528 			}
529 		}
530 		TRACE("setup_interrupt() installed MSI-X interrupt handlers\n");
531 		virtio_pci_setup_msix_interrupts(bus);
532 	} else {
533 		// setup interrupt handler
534 		status_t status = install_io_interrupt_handler(bus->irq,
535 			virtio_pci_interrupt, bus, 0);
536 		if (status != B_OK) {
537 			ERROR("can't install interrupt handler\n");
538 			return status;
539 		}
540 		TRACE("setup_interrupt() installed legacy interrupt handler\n");
541 	}
542 
543 	return B_OK;
544 }
545 
546 
547 static status_t
548 free_interrupt(void* cookie)
549 {
550 	CALLED();
551 	virtio_pci_sim_info* bus = (virtio_pci_sim_info*)cookie;
552 
553 	if (bus->irq_type != VIRTIO_IRQ_LEGACY) {
554 		remove_io_interrupt_handler(bus->irq, virtio_pci_config_interrupt, bus);
555 		int32 irq = bus->irq + 1;
556 		if (bus->irq_type == VIRTIO_IRQ_MSI_X) {
557 			for (int32 queue = 0; queue < bus->queue_count; queue++, irq++)
558 				remove_io_interrupt_handler(irq, virtio_pci_queue_interrupt, &bus->cookies[queue]);
559 			delete[] bus->cookies;
560 			bus->cookies = NULL;
561 		} else {
562 			remove_io_interrupt_handler(irq, virtio_pci_queues_interrupt, bus);
563 		}
564 		bus->pci->disable_msi(bus->device);
565 		bus->pci->unconfigure_msi(bus->device);
566 	} else
567 		remove_io_interrupt_handler(bus->irq, virtio_pci_interrupt, bus);
568 
569 	return B_OK;
570 }
571 
572 
573 static void
574 notify_queue(void* cookie, uint16 queue)
575 {
576 	CALLED();
577 	virtio_pci_sim_info* bus = (virtio_pci_sim_info*)cookie;
578 	if (queue >= bus->queue_count)
579 		return;
580 	if (bus->virtio1) {
581 		volatile uint16* notifyAddr = (volatile uint16*)(bus->notifyAddr + bus->notifyOffsets[queue]);
582 		*notifyAddr = queue;
583 	} else {
584 		bus->pci->write_io_16(bus->device, bus->base_addr
585 			+ VIRTIO_PCI_QUEUE_NOTIFY, queue);
586 	}
587 }
588 
589 
590 //	#pragma mark -
591 
592 
593 static status_t
594 init_bus(device_node* node, void** bus_cookie)
595 {
596 	CALLED();
597 	status_t status = B_OK;
598 
599 	virtio_pci_sim_info* bus = new(std::nothrow) virtio_pci_sim_info;
600 	if (bus == NULL) {
601 		return B_NO_MEMORY;
602 	}
603 
604 	pci_device_module_info* pci;
605 	pci_device* device;
606 	{
607 		device_node* parent = gDeviceManager->get_parent_node(node);
608 		device_node* pciParent = gDeviceManager->get_parent_node(parent);
609 		gDeviceManager->get_driver(pciParent, (driver_module_info**)&pci,
610 			(void**)&device);
611 		gDeviceManager->put_node(pciParent);
612 		gDeviceManager->put_node(parent);
613 	}
614 
615 	bus->node = node;
616 	bus->pci = pci;
617 	bus->device = device;
618 	bus->cookies = NULL;
619 	bus->irq_type = VIRTIO_IRQ_LEGACY;
620 
621 	pci_info *pciInfo = &bus->info;
622 	pci->get_pci_info(device, pciInfo);
623 
624 	bus->virtio1 = pciInfo->revision == 1;
625 
626 	if (bus->virtio1) {
627 		struct virtio_pci_cap common, isr, deviceCap;
628 		struct virtio_pci_notify_cap notify;
629 		bool deviceCfgFound = false;
630 		if (virtio_pci_find_capability(bus, VIRTIO_PCI_CAP_COMMON_CFG, &common,
631 			sizeof(common)) != B_OK) {
632 			return B_DEVICE_NOT_FOUND;
633 		}
634 		if (virtio_pci_find_capability(bus, VIRTIO_PCI_CAP_ISR_CFG, &isr,
635 			sizeof(isr)) != B_OK) {
636 			return B_DEVICE_NOT_FOUND;
637 		}
638 		if (virtio_pci_find_capability(bus, VIRTIO_PCI_CAP_DEVICE_CFG, &deviceCap,
639 			sizeof(deviceCap)) != B_OK) {
640 			memset(&deviceCap, 0, sizeof(deviceCap));
641 		} else {
642 			deviceCfgFound = true;
643 		}
644 		if (virtio_pci_find_capability(bus, VIRTIO_PCI_CAP_NOTIFY_CFG, &notify,
645 			sizeof(notify)) != B_OK) {
646 			return B_DEVICE_NOT_FOUND;
647 		}
648 
649 		size_t bars[6] = {0};
650 		if (common.length > 0)
651 			bars[common.bar] = common.offset + common.length;
652 		if (isr.length > 0)
653 			bars[isr.bar] = max_c(bars[isr.bar], isr.offset + isr.length);
654 		if (notify.cap.length > 0) {
655 			bars[notify.cap.bar] = max_c(bars[notify.cap.bar], notify.cap.offset
656 				+ notify.cap.length);
657 		}
658 		if (deviceCfgFound && deviceCap.length > 0)
659 			bars[deviceCap.bar] = max_c(bars[deviceCap.bar], deviceCap.offset + deviceCap.length);
660 
661 		int index = 0;
662 		addr_t registers[6] = {0};
663 		for (int i = 0; i < 6; i++) {
664 			if (bars[i] == 0)
665 				continue;
666 			phys_addr_t barAddr = pciInfo->u.h0.base_registers[i];
667 			size_t barSize = pciInfo->u.h0.base_register_sizes[i];
668 			if ((pciInfo->u.h0.base_register_flags[i] & PCI_address_type) == PCI_address_type_64) {
669 				barAddr |= (uint64)pciInfo->u.h0.base_registers[i + 1] << 32;
670 				barSize |= (uint64)pciInfo->u.h0.base_register_sizes[i + 1] << 32;
671 			}
672 
673 			bus->registersArea[i] = map_physical_memory("Virtio PCI memory mapped registers",
674 				barAddr, barSize, B_ANY_KERNEL_ADDRESS, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA,
675 				(void **)&registers[i]);
676 			index++;
677 		}
678 
679 		bus->commonCfgAddr = registers[common.bar] + common.offset;
680 		bus->isrAddr = registers[isr.bar] + isr.offset;
681 		bus->notifyAddr = registers[notify.cap.bar] + notify.cap.offset;
682 		bus->notifyOffsetMultiplier = notify.notify_off_multiplier;
683 		if (deviceCfgFound)
684 			bus->base_addr = registers[deviceCap.bar] + deviceCap.offset;
685 
686 		// enable bus master and memory
687 		uint16 pcicmd = pci->read_pci_config(device, PCI_command, 2);
688 		pcicmd &= ~(PCI_command_int_disable | PCI_command_io);
689 		pci->write_pci_config(device, PCI_command, 2,
690 			pcicmd | PCI_command_master | PCI_command_memory);
691 
692 		volatile uint16 *queueCount = (uint16*)(bus->commonCfgAddr
693 			+ offsetof(struct virtio_pci_common_cfg, num_queues));
694 		bus->notifyOffsets = new addr_t[*queueCount];
695 
696 	} else {
697 		// legacy interrupt
698 		bus->base_addr = pciInfo->u.h0.base_registers[0];
699 
700 		// enable bus master and io
701 		uint16 pcicmd = pci->read_pci_config(device, PCI_command, 2);
702 		pcicmd &= ~(PCI_command_memory | PCI_command_int_disable);
703 		pcicmd |= PCI_command_master | PCI_command_io;
704 		pci->write_pci_config(device, PCI_command, 2, pcicmd);
705 	}
706 
707 
708 	set_status(bus, VIRTIO_CONFIG_STATUS_RESET);
709 	set_status(bus, VIRTIO_CONFIG_STATUS_ACK);
710 
711 	TRACE("init_bus() %p node %p pci %p device %p\n", bus, node,
712 		bus->pci, bus->device);
713 
714 	*bus_cookie = bus;
715 	return status;
716 }
717 
718 
719 static void
720 uninit_bus(void* bus_cookie)
721 {
722 	virtio_pci_sim_info* bus = (virtio_pci_sim_info*)bus_cookie;
723 	if (bus->irq_type != VIRTIO_IRQ_LEGACY) {
724 		int32 irq = bus->irq + 1;
725 		if (bus->irq_type == VIRTIO_IRQ_MSI_X) {
726 			for (int32 queue = 0; queue < bus->queue_count; queue++, irq++)
727 				remove_io_interrupt_handler(irq, virtio_pci_queue_interrupt, &bus->cookies[queue]);
728 			delete[] bus->cookies;
729 		} else {
730 			remove_io_interrupt_handler(irq, virtio_pci_queues_interrupt, bus);
731 		}
732 		remove_io_interrupt_handler(bus->irq, virtio_pci_config_interrupt,
733 				bus);
734 
735 		bus->pci->disable_msi(bus->device);
736 		bus->pci->unconfigure_msi(bus->device);
737 	} else
738 		remove_io_interrupt_handler(bus->irq, virtio_pci_interrupt, bus);
739 
740 	if (bus->virtio1) {
741 		for (int i = 0; i < 6; i++) {
742 			if (bus->registersArea[i] >= 0)
743 				delete_area(bus->registersArea[i]);
744 			else
745 				break;
746 		}
747 		delete[] bus->notifyOffsets;
748 	}
749 
750 	delete bus;
751 }
752 
753 
754 static void
755 bus_removed(void* bus_cookie)
756 {
757 	return;
758 }
759 
760 
761 //	#pragma mark -
762 
763 
764 static status_t
765 register_child_devices(void* cookie)
766 {
767 	CALLED();
768 	device_node* node = (device_node*)cookie;
769 	device_node* parent = gDeviceManager->get_parent_node(node);
770 	pci_device_module_info* pci;
771 	pci_device* device;
772 	gDeviceManager->get_driver(parent, (driver_module_info**)&pci,
773 		(void**)&device);
774 
775 	uint16 pciSubDeviceId = pci->read_pci_config(device, PCI_subsystem_id, 2);
776 	uint8 pciRevision = pci->read_pci_config(device, PCI_revision, 1);
777 	uint16 pciDeviceId = pci->read_pci_config(device, PCI_device_id, 2);
778 
779 	uint16 virtioDeviceId = pciSubDeviceId;
780 	if (pciDeviceId >= VIRTIO_PCI_DEVICEID_MODERN_MIN)
781 		virtioDeviceId = pciDeviceId - VIRTIO_PCI_DEVICEID_MODERN_MIN;
782 
783 	char prettyName[25];
784 	sprintf(prettyName, "Virtio Device %" B_PRIu16, virtioDeviceId);
785 
786 	device_attr attrs[] = {
787 		// properties of this controller for virtio bus manager
788 		{ B_DEVICE_PRETTY_NAME, B_STRING_TYPE,
789 			{ .string = prettyName }},
790 		{ B_DEVICE_FIXED_CHILD, B_STRING_TYPE,
791 			{ .string = VIRTIO_FOR_CONTROLLER_MODULE_NAME }},
792 
793 		// private data to identify the device
794 		{ VIRTIO_DEVICE_TYPE_ITEM, B_UINT16_TYPE,
795 			{ .ui16 = virtioDeviceId }},
796 		{ VIRTIO_VRING_ALIGNMENT_ITEM, B_UINT16_TYPE,
797 			{ .ui16 = VIRTIO_PCI_VRING_ALIGN }},
798 		{ VIRTIO_VERSION_ITEM, B_UINT8_TYPE,
799 			{ .ui8 = pciRevision }},
800 		{ NULL }
801 	};
802 
803 	return gDeviceManager->register_node(node, VIRTIO_PCI_SIM_MODULE_NAME,
804 		attrs, NULL, &node);
805 }
806 
807 
808 static status_t
809 init_device(device_node* node, void** device_cookie)
810 {
811 	CALLED();
812 	*device_cookie = node;
813 	return B_OK;
814 }
815 
816 
817 static status_t
818 register_device(device_node* parent)
819 {
820 	device_attr attrs[] = {
821 		{B_DEVICE_PRETTY_NAME, B_STRING_TYPE, {.string = "Virtio PCI"}},
822 		{}
823 	};
824 
825 	return gDeviceManager->register_node(parent, VIRTIO_PCI_DEVICE_MODULE_NAME,
826 		attrs, NULL, NULL);
827 }
828 
829 
830 static float
831 supports_device(device_node* parent)
832 {
833 	CALLED();
834 	const char* bus;
835 	uint16 vendorID, deviceID;
836 
837 	// make sure parent is a PCI Virtio device node
838 	if (gDeviceManager->get_attr_string(parent, B_DEVICE_BUS, &bus, false) != B_OK
839 		|| gDeviceManager->get_attr_uint16(parent, B_DEVICE_VENDOR_ID,
840 				&vendorID, false) < B_OK
841 		|| gDeviceManager->get_attr_uint16(parent, B_DEVICE_ID, &deviceID,
842 				false) < B_OK) {
843 		return -1;
844 	}
845 
846 	if (strcmp(bus, "pci") != 0)
847 		return 0.0f;
848 
849 	if (vendorID == VIRTIO_PCI_VENDORID) {
850 		if (deviceID < VIRTIO_PCI_DEVICEID_MIN
851 			|| deviceID > VIRTIO_PCI_DEVICEID_MODERN_MAX) {
852 			return 0.0f;
853 		}
854 
855 		pci_device_module_info* pci;
856 		pci_device* device;
857 		gDeviceManager->get_driver(parent, (driver_module_info**)&pci,
858 			(void**)&device);
859 		uint8 pciRevision = pci->read_pci_config(device, PCI_revision,
860 			1);
861 		if (deviceID >= VIRTIO_PCI_DEVICEID_MIN
862 			&& deviceID <= VIRTIO_PCI_DEVICEID_LEGACY_MAX
863 			&& pciRevision != 0) {
864 			return 0.0f;
865 		}
866 		if (deviceID >= VIRTIO_PCI_DEVICEID_MODERN_MIN
867 			&& deviceID <= VIRTIO_PCI_DEVICEID_MODERN_MAX
868 			&& pciRevision != 1)
869 			return 0.0f;
870 
871 		TRACE("Virtio device found! vendor 0x%04x, device 0x%04x\n", vendorID,
872 			deviceID);
873 		return 0.8f;
874 	}
875 
876 	return 0.0f;
877 }
878 
879 
880 //	#pragma mark -
881 
882 
883 module_dependency module_dependencies[] = {
884 	{ VIRTIO_FOR_CONTROLLER_MODULE_NAME, (module_info**)&gVirtio },
885 	{ B_DEVICE_MANAGER_MODULE_NAME, (module_info**)&gDeviceManager },
886 	{}
887 };
888 
889 
890 static virtio_sim_interface gVirtioPCIDeviceModule = {
891 	{
892 		{
893 			VIRTIO_PCI_SIM_MODULE_NAME,
894 			0,
895 			NULL
896 		},
897 
898 		NULL,	// supports device
899 		NULL,	// register device
900 		init_bus,
901 		uninit_bus,
902 		NULL,	// register child devices
903 		NULL,	// rescan
904 		bus_removed,
905 	},
906 
907 	set_sim,
908 	read_host_features,
909 	write_guest_features,
910 	get_status,
911 	set_status,
912 	read_device_config,
913 	write_device_config,
914 	get_queue_ring_size,
915 	setup_queue,
916 	setup_interrupt,
917 	free_interrupt,
918 	notify_queue
919 };
920 
921 
922 static driver_module_info sVirtioDevice = {
923 	{
924 		VIRTIO_PCI_DEVICE_MODULE_NAME,
925 		0,
926 		NULL
927 	},
928 
929 	supports_device,
930 	register_device,
931 	init_device,
932 	NULL,	// uninit
933 	register_child_devices,
934 	NULL,	// rescan
935 	NULL,	// device removed
936 };
937 
938 module_info* modules[] = {
939 	(module_info* )&sVirtioDevice,
940 	(module_info* )&gVirtioPCIDeviceModule,
941 	NULL
942 };
943