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