xref: /haiku/src/add-ons/kernel/busses/virtio/virtio_pci/virtio_pci.cpp (revision dd2a1e350b303b855a50fd64e6cb55618be1ae6a)
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 	uint32 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 	uint32 msixCount = bus->pci->get_msix_count(bus->device);
464 	if (msixCount >= 2) {
465 		uint32 vectorCount = queueCount + 1;
466 		if (msixCount >= vectorCount) {
467 			uint32 vector;
468 			bus->cookies = new(std::nothrow)
469 				virtio_pci_queue_cookie[queueCount];
470 			if (bus->cookies != NULL
471 				&& bus->pci->configure_msix(bus->device, vectorCount,
472 					&vector) == B_OK
473 				&& bus->pci->enable_msix(bus->device) == B_OK) {
474 				TRACE_ALWAYS("using MSI-X count %" B_PRIu32 " starting at %" B_PRIu32 "\n",
475 					vectorCount, vector);
476 				bus->irq = vector;
477 				bus->irq_type = VIRTIO_IRQ_MSI_X;
478 			} else {
479 				ERROR("couldn't use MSI-X\n");
480 			}
481 		} else {
482 			uint32 vector;
483 			if (bus->pci->configure_msix(bus->device, 2, &vector) == B_OK
484 				&& bus->pci->enable_msix(bus->device) == B_OK) {
485 				TRACE_ALWAYS("using MSI-X vector shared %" B_PRIu32 "\n", vector);
486 				bus->irq = vector;
487 				bus->irq_type = VIRTIO_IRQ_MSI_X_SHARED;
488 			} else {
489 				ERROR("couldn't use MSI-X SHARED\n");
490 			}
491 		}
492 	}
493 
494 	if (bus->irq_type == VIRTIO_IRQ_LEGACY) {
495 		bus->irq = pciInfo->u.h0.interrupt_line;
496 		if (bus->irq == 0xff)
497 			bus->irq = 0;
498 		TRACE_ALWAYS("using legacy interrupt %" B_PRIu32 "\n", bus->irq);
499 	}
500 	if (bus->irq == 0) {
501 		ERROR("PCI IRQ not assigned\n");
502 		delete bus;
503 		return B_ERROR;
504 	}
505 
506 	if (bus->irq_type != VIRTIO_IRQ_LEGACY) {
507 		status_t status = install_io_interrupt_handler(bus->irq,
508 			virtio_pci_config_interrupt, bus, 0);
509 		if (status != B_OK) {
510 			ERROR("can't install interrupt handler\n");
511 			return status;
512 		}
513 		int32 irq = bus->irq + 1;
514 		if (bus->irq_type == VIRTIO_IRQ_MSI_X) {
515 			for (int32 queue = 0; queue < queueCount; queue++, irq++) {
516 				bus->cookies[queue].sim = bus->sim;
517 				bus->cookies[queue].queue = queue;
518 				status_t status = install_io_interrupt_handler(irq,
519 					virtio_pci_queue_interrupt, &bus->cookies[queue], 0);
520 				if (status != B_OK) {
521 					ERROR("can't install interrupt handler\n");
522 					return status;
523 				}
524 			}
525 		} else {
526 			status_t status = install_io_interrupt_handler(irq,
527 				virtio_pci_queues_interrupt, bus, 0);
528 			if (status != B_OK) {
529 				ERROR("can't install interrupt handler\n");
530 				return status;
531 			}
532 		}
533 		TRACE("setup_interrupt() installed MSI-X interrupt handlers\n");
534 		virtio_pci_setup_msix_interrupts(bus);
535 	} else {
536 		// setup interrupt handler
537 		status_t status = install_io_interrupt_handler(bus->irq,
538 			virtio_pci_interrupt, bus, 0);
539 		if (status != B_OK) {
540 			ERROR("can't install interrupt handler\n");
541 			return status;
542 		}
543 		TRACE("setup_interrupt() installed legacy interrupt handler\n");
544 	}
545 
546 	return B_OK;
547 }
548 
549 
550 static status_t
551 free_interrupt(void* cookie)
552 {
553 	CALLED();
554 	virtio_pci_sim_info* bus = (virtio_pci_sim_info*)cookie;
555 
556 	if (bus->irq_type != VIRTIO_IRQ_LEGACY) {
557 		remove_io_interrupt_handler(bus->irq, virtio_pci_config_interrupt, bus);
558 		int32 irq = bus->irq + 1;
559 		if (bus->irq_type == VIRTIO_IRQ_MSI_X) {
560 			for (int32 queue = 0; queue < bus->queue_count; queue++, irq++)
561 				remove_io_interrupt_handler(irq, virtio_pci_queue_interrupt, &bus->cookies[queue]);
562 			delete[] bus->cookies;
563 			bus->cookies = NULL;
564 		} else {
565 			remove_io_interrupt_handler(irq, virtio_pci_queues_interrupt, bus);
566 		}
567 		bus->pci->disable_msi(bus->device);
568 		bus->pci->unconfigure_msi(bus->device);
569 	} else
570 		remove_io_interrupt_handler(bus->irq, virtio_pci_interrupt, bus);
571 
572 	return B_OK;
573 }
574 
575 
576 static void
577 notify_queue(void* cookie, uint16 queue)
578 {
579 	CALLED();
580 	virtio_pci_sim_info* bus = (virtio_pci_sim_info*)cookie;
581 	if (queue >= bus->queue_count)
582 		return;
583 	if (bus->virtio1) {
584 		volatile uint16* notifyAddr = (volatile uint16*)(bus->notifyAddr + bus->notifyOffsets[queue]);
585 		*notifyAddr = queue;
586 	} else {
587 		bus->pci->write_io_16(bus->device, bus->base_addr
588 			+ VIRTIO_PCI_QUEUE_NOTIFY, queue);
589 	}
590 }
591 
592 
593 //	#pragma mark -
594 
595 
596 static status_t
597 init_bus(device_node* node, void** bus_cookie)
598 {
599 	CALLED();
600 	status_t status = B_OK;
601 
602 	virtio_pci_sim_info* bus = new(std::nothrow) virtio_pci_sim_info;
603 	if (bus == NULL) {
604 		return B_NO_MEMORY;
605 	}
606 
607 	pci_device_module_info* pci;
608 	pci_device* device;
609 	{
610 		device_node* parent = gDeviceManager->get_parent_node(node);
611 		device_node* pciParent = gDeviceManager->get_parent_node(parent);
612 		gDeviceManager->get_driver(pciParent, (driver_module_info**)&pci,
613 			(void**)&device);
614 		gDeviceManager->put_node(pciParent);
615 		gDeviceManager->put_node(parent);
616 	}
617 
618 	bus->node = node;
619 	bus->pci = pci;
620 	bus->device = device;
621 	bus->cookies = NULL;
622 	bus->irq_type = VIRTIO_IRQ_LEGACY;
623 
624 	pci_info *pciInfo = &bus->info;
625 	pci->get_pci_info(device, pciInfo);
626 
627 	bus->virtio1 = pciInfo->revision == 1;
628 
629 	if (bus->virtio1) {
630 		struct virtio_pci_cap common, isr, deviceCap;
631 		struct virtio_pci_notify_cap notify;
632 		bool deviceCfgFound = false;
633 		if (virtio_pci_find_capability(bus, VIRTIO_PCI_CAP_COMMON_CFG, &common,
634 			sizeof(common)) != B_OK) {
635 			return B_DEVICE_NOT_FOUND;
636 		}
637 		if (virtio_pci_find_capability(bus, VIRTIO_PCI_CAP_ISR_CFG, &isr,
638 			sizeof(isr)) != B_OK) {
639 			return B_DEVICE_NOT_FOUND;
640 		}
641 		if (virtio_pci_find_capability(bus, VIRTIO_PCI_CAP_DEVICE_CFG, &deviceCap,
642 			sizeof(deviceCap)) != B_OK) {
643 			memset(&deviceCap, 0, sizeof(deviceCap));
644 		} else {
645 			deviceCfgFound = true;
646 		}
647 		if (virtio_pci_find_capability(bus, VIRTIO_PCI_CAP_NOTIFY_CFG, &notify,
648 			sizeof(notify)) != B_OK) {
649 			return B_DEVICE_NOT_FOUND;
650 		}
651 
652 		size_t bars[6] = {0};
653 		if (common.length > 0)
654 			bars[common.bar] = common.offset + common.length;
655 		if (isr.length > 0)
656 			bars[isr.bar] = max_c(bars[isr.bar], isr.offset + isr.length);
657 		if (notify.cap.length > 0) {
658 			bars[notify.cap.bar] = max_c(bars[notify.cap.bar], notify.cap.offset
659 				+ notify.cap.length);
660 		}
661 		if (deviceCfgFound && deviceCap.length > 0)
662 			bars[deviceCap.bar] = max_c(bars[deviceCap.bar], deviceCap.offset + deviceCap.length);
663 
664 		int index = 0;
665 		addr_t registers[6] = {0};
666 		for (int i = 0; i < 6; i++) {
667 			if (bars[i] == 0)
668 				continue;
669 			phys_addr_t barAddr = pciInfo->u.h0.base_registers[i];
670 			size_t barSize = pciInfo->u.h0.base_register_sizes[i];
671 			if ((pciInfo->u.h0.base_register_flags[i] & PCI_address_type) == PCI_address_type_64) {
672 				barAddr |= (uint64)pciInfo->u.h0.base_registers[i + 1] << 32;
673 				barSize |= (uint64)pciInfo->u.h0.base_register_sizes[i + 1] << 32;
674 			}
675 
676 			bus->registersArea[i] = map_physical_memory("Virtio PCI memory mapped registers",
677 				barAddr, barSize, B_ANY_KERNEL_ADDRESS, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA,
678 				(void **)&registers[i]);
679 			index++;
680 		}
681 
682 		bus->commonCfgAddr = registers[common.bar] + common.offset;
683 		bus->isrAddr = registers[isr.bar] + isr.offset;
684 		bus->notifyAddr = registers[notify.cap.bar] + notify.cap.offset;
685 		bus->notifyOffsetMultiplier = notify.notify_off_multiplier;
686 		if (deviceCfgFound)
687 			bus->base_addr = registers[deviceCap.bar] + deviceCap.offset;
688 
689 		// enable bus master and memory
690 		uint16 pcicmd = pci->read_pci_config(device, PCI_command, 2);
691 		pcicmd &= ~(PCI_command_int_disable | PCI_command_io);
692 		pci->write_pci_config(device, PCI_command, 2,
693 			pcicmd | PCI_command_master | PCI_command_memory);
694 
695 		volatile uint16 *queueCount = (uint16*)(bus->commonCfgAddr
696 			+ offsetof(struct virtio_pci_common_cfg, num_queues));
697 		bus->notifyOffsets = new addr_t[*queueCount];
698 
699 	} else {
700 		// legacy interrupt
701 		bus->base_addr = pciInfo->u.h0.base_registers[0];
702 
703 		// enable bus master and io
704 		uint16 pcicmd = pci->read_pci_config(device, PCI_command, 2);
705 		pcicmd &= ~(PCI_command_memory | PCI_command_int_disable);
706 		pcicmd |= PCI_command_master | PCI_command_io;
707 		pci->write_pci_config(device, PCI_command, 2, pcicmd);
708 	}
709 
710 
711 	set_status(bus, VIRTIO_CONFIG_STATUS_RESET);
712 	set_status(bus, VIRTIO_CONFIG_STATUS_ACK);
713 
714 	TRACE("init_bus() %p node %p pci %p device %p\n", bus, node,
715 		bus->pci, bus->device);
716 
717 	*bus_cookie = bus;
718 	return status;
719 }
720 
721 
722 static void
723 uninit_bus(void* bus_cookie)
724 {
725 	virtio_pci_sim_info* bus = (virtio_pci_sim_info*)bus_cookie;
726 	if (bus->irq_type != VIRTIO_IRQ_LEGACY) {
727 		int32 irq = bus->irq + 1;
728 		if (bus->irq_type == VIRTIO_IRQ_MSI_X) {
729 			for (int32 queue = 0; queue < bus->queue_count; queue++, irq++)
730 				remove_io_interrupt_handler(irq, virtio_pci_queue_interrupt, &bus->cookies[queue]);
731 			delete[] bus->cookies;
732 		} else {
733 			remove_io_interrupt_handler(irq, virtio_pci_queues_interrupt, bus);
734 		}
735 		remove_io_interrupt_handler(bus->irq, virtio_pci_config_interrupt,
736 				bus);
737 
738 		bus->pci->disable_msi(bus->device);
739 		bus->pci->unconfigure_msi(bus->device);
740 	} else
741 		remove_io_interrupt_handler(bus->irq, virtio_pci_interrupt, bus);
742 
743 	if (bus->virtio1) {
744 		for (int i = 0; i < 6; i++) {
745 			if (bus->registersArea[i] >= 0)
746 				delete_area(bus->registersArea[i]);
747 			else
748 				break;
749 		}
750 		delete[] bus->notifyOffsets;
751 	}
752 
753 	delete bus;
754 }
755 
756 
757 static void
758 bus_removed(void* bus_cookie)
759 {
760 	return;
761 }
762 
763 
764 //	#pragma mark -
765 
766 
767 static status_t
768 register_child_devices(void* cookie)
769 {
770 	CALLED();
771 	device_node* node = (device_node*)cookie;
772 	device_node* parent = gDeviceManager->get_parent_node(node);
773 	pci_device_module_info* pci;
774 	pci_device* device;
775 	gDeviceManager->get_driver(parent, (driver_module_info**)&pci,
776 		(void**)&device);
777 
778 	uint16 pciSubDeviceId = pci->read_pci_config(device, PCI_subsystem_id, 2);
779 	uint8 pciRevision = pci->read_pci_config(device, PCI_revision, 1);
780 	uint16 pciDeviceId = pci->read_pci_config(device, PCI_device_id, 2);
781 
782 	uint16 virtioDeviceId = pciSubDeviceId;
783 	if (pciDeviceId >= VIRTIO_PCI_DEVICEID_MODERN_MIN)
784 		virtioDeviceId = pciDeviceId - VIRTIO_PCI_DEVICEID_MODERN_MIN;
785 
786 	char prettyName[25];
787 	sprintf(prettyName, "Virtio Device %" B_PRIu16, virtioDeviceId);
788 
789 	device_attr attrs[] = {
790 		// properties of this controller for virtio bus manager
791 		{ B_DEVICE_PRETTY_NAME, B_STRING_TYPE,
792 			{ .string = prettyName }},
793 		{ B_DEVICE_FIXED_CHILD, B_STRING_TYPE,
794 			{ .string = VIRTIO_FOR_CONTROLLER_MODULE_NAME }},
795 
796 		// private data to identify the device
797 		{ VIRTIO_DEVICE_TYPE_ITEM, B_UINT16_TYPE,
798 			{ .ui16 = virtioDeviceId }},
799 		{ VIRTIO_VRING_ALIGNMENT_ITEM, B_UINT16_TYPE,
800 			{ .ui16 = VIRTIO_PCI_VRING_ALIGN }},
801 		{ VIRTIO_VERSION_ITEM, B_UINT8_TYPE,
802 			{ .ui8 = pciRevision }},
803 		{ NULL }
804 	};
805 
806 	return gDeviceManager->register_node(node, VIRTIO_PCI_SIM_MODULE_NAME,
807 		attrs, NULL, &node);
808 }
809 
810 
811 static status_t
812 init_device(device_node* node, void** device_cookie)
813 {
814 	CALLED();
815 	*device_cookie = node;
816 	return B_OK;
817 }
818 
819 
820 static status_t
821 register_device(device_node* parent)
822 {
823 	device_attr attrs[] = {
824 		{B_DEVICE_PRETTY_NAME, B_STRING_TYPE, {.string = "Virtio PCI"}},
825 		{}
826 	};
827 
828 	return gDeviceManager->register_node(parent, VIRTIO_PCI_DEVICE_MODULE_NAME,
829 		attrs, NULL, NULL);
830 }
831 
832 
833 static float
834 supports_device(device_node* parent)
835 {
836 	CALLED();
837 	const char* bus;
838 	uint16 vendorID, deviceID;
839 
840 	// make sure parent is a PCI Virtio device node
841 	if (gDeviceManager->get_attr_string(parent, B_DEVICE_BUS, &bus, false) != B_OK
842 		|| gDeviceManager->get_attr_uint16(parent, B_DEVICE_VENDOR_ID,
843 				&vendorID, false) < B_OK
844 		|| gDeviceManager->get_attr_uint16(parent, B_DEVICE_ID, &deviceID,
845 				false) < B_OK) {
846 		return -1;
847 	}
848 
849 	if (strcmp(bus, "pci") != 0)
850 		return 0.0f;
851 
852 	if (vendorID == VIRTIO_PCI_VENDORID) {
853 		if (deviceID < VIRTIO_PCI_DEVICEID_MIN
854 			|| deviceID > VIRTIO_PCI_DEVICEID_MODERN_MAX) {
855 			return 0.0f;
856 		}
857 
858 		pci_device_module_info* pci;
859 		pci_device* device;
860 		gDeviceManager->get_driver(parent, (driver_module_info**)&pci,
861 			(void**)&device);
862 		uint8 pciRevision = pci->read_pci_config(device, PCI_revision,
863 			1);
864 		if (deviceID >= VIRTIO_PCI_DEVICEID_MIN
865 			&& deviceID <= VIRTIO_PCI_DEVICEID_LEGACY_MAX
866 			&& pciRevision != 0) {
867 			return 0.0f;
868 		}
869 		if (deviceID >= VIRTIO_PCI_DEVICEID_MODERN_MIN
870 			&& deviceID <= VIRTIO_PCI_DEVICEID_MODERN_MAX
871 			&& pciRevision != 1)
872 			return 0.0f;
873 
874 		TRACE("Virtio device found! vendor 0x%04x, device 0x%04x\n", vendorID,
875 			deviceID);
876 		return 0.8f;
877 	}
878 
879 	return 0.0f;
880 }
881 
882 
883 //	#pragma mark -
884 
885 
886 module_dependency module_dependencies[] = {
887 	{ VIRTIO_FOR_CONTROLLER_MODULE_NAME, (module_info**)&gVirtio },
888 	{ B_DEVICE_MANAGER_MODULE_NAME, (module_info**)&gDeviceManager },
889 	{}
890 };
891 
892 
893 static virtio_sim_interface gVirtioPCIDeviceModule = {
894 	{
895 		{
896 			VIRTIO_PCI_SIM_MODULE_NAME,
897 			0,
898 			NULL
899 		},
900 
901 		NULL,	// supports device
902 		NULL,	// register device
903 		init_bus,
904 		uninit_bus,
905 		NULL,	// register child devices
906 		NULL,	// rescan
907 		bus_removed,
908 	},
909 
910 	set_sim,
911 	read_host_features,
912 	write_guest_features,
913 	get_status,
914 	set_status,
915 	read_device_config,
916 	write_device_config,
917 	get_queue_ring_size,
918 	setup_queue,
919 	setup_interrupt,
920 	free_interrupt,
921 	notify_queue
922 };
923 
924 
925 static driver_module_info sVirtioDevice = {
926 	{
927 		VIRTIO_PCI_DEVICE_MODULE_NAME,
928 		0,
929 		NULL
930 	},
931 
932 	supports_device,
933 	register_device,
934 	init_device,
935 	NULL,	// uninit
936 	register_child_devices,
937 	NULL,	// rescan
938 	NULL,	// device removed
939 };
940 
941 module_info* modules[] = {
942 	(module_info* )&sVirtioDevice,
943 	(module_info* )&gVirtioPCIDeviceModule,
944 	NULL
945 };
946