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
36typedef enum {
37	VIRTIO_IRQ_LEGACY,
38	VIRTIO_IRQ_MSI_X_SHARED,
39	VIRTIO_IRQ_MSI_X,
40} virtio_irq_type;
41
42typedef struct {
43	virtio_sim sim;
44	uint16 queue;
45} virtio_pci_queue_cookie;
46
47typedef 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
70device_manager_info* gDeviceManager;
71virtio_for_controller_interface* gVirtio;
72
73
74static status_t
75virtio_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
109static int32
110virtio_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
134static int32
135virtio_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
144static int32
145virtio_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
154static int32
155virtio_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
164static status_t
165virtio_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
213static void
214set_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
222static status_t
223read_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
249static status_t
250write_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
271static uint8
272get_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
286static void
287set_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
307static status_t
308read_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
351static status_t
352write_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
393static uint16
394get_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
414static status_t
415setup_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
453static status_t
454setup_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
550static status_t
551free_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
576static void
577notify_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
596static status_t
597init_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
722static void
723uninit_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
757static void
758bus_removed(void* bus_cookie)
759{
760	return;
761}
762
763
764//	#pragma mark -
765
766
767static status_t
768register_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
811static status_t
812init_device(device_node* node, void** device_cookie)
813{
814	CALLED();
815	*device_cookie = node;
816	return B_OK;
817}
818
819
820static status_t
821register_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
833static float
834supports_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
886module_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
893static 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
925static 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
941module_info* modules[] = {
942	(module_info* )&sVirtioDevice,
943	(module_info* )&gVirtioPCIDeviceModule,
944	NULL
945};
946