xref: /haiku/src/add-ons/kernel/bus_managers/pci/pci.cpp (revision 445d4fd926c569e7b9ae28017da86280aaecbae2)
1 /*
2  * Copyright 2003-2008, Marcus Overhagen. All rights reserved.
3  * Copyright 2005-2008, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
4  *
5  * Distributed under the terms of the MIT License.
6  */
7 
8 
9 #include <string.h>
10 #include <KernelExport.h>
11 #define __HAIKU_PCI_BUS_MANAGER_TESTING 1
12 #include <PCI.h>
13 #include <arch/generic/msi.h>
14 #if defined(__i386__) || defined(__x86_64__)
15 #include <arch/x86/msi.h>
16 #endif
17 
18 #include "util/kernel_cpp.h"
19 #include "pci_fixup.h"
20 #include "pci_info.h"
21 #include "pci_private.h"
22 #include "pci.h"
23 
24 
25 #define TRACE_CAP(x...) dprintf(x)
26 #define FLOW(x...)
27 //#define FLOW(x...) dprintf(x)
28 
29 
30 PCI *gPCI;
31 
32 
33 // #pragma mark bus manager exports
34 
35 
36 long
37 pci_get_nth_pci_info(long index, pci_info *outInfo)
38 {
39 	return gPCI->GetNthInfo(index, outInfo);
40 }
41 
42 
43 uint32
44 pci_read_config(uint8 virtualBus, uint8 device, uint8 function, uint16 offset,
45 	uint8 size)
46 {
47 	uint8 bus;
48 	uint8 domain;
49 	uint32 value;
50 
51 	if (gPCI->ResolveVirtualBus(virtualBus, &domain, &bus) != B_OK)
52 		return 0xffffffff;
53 
54 	if (gPCI->ReadConfig(domain, bus, device, function, offset, size,
55 			&value) != B_OK)
56 		return 0xffffffff;
57 
58 	return value;
59 }
60 
61 
62 void
63 pci_write_config(uint8 virtualBus, uint8 device, uint8 function, uint16 offset,
64 	uint8 size, uint32 value)
65 {
66 	uint8 bus;
67 	uint8 domain;
68 	if (gPCI->ResolveVirtualBus(virtualBus, &domain, &bus) != B_OK)
69 		return;
70 
71 	gPCI->WriteConfig(domain, bus, device, function, offset, size, value);
72 }
73 
74 
75 phys_addr_t
76 pci_ram_address(phys_addr_t childAdr)
77 {
78 	phys_addr_t hostAdr = 0;
79 #if defined(__i386__) || defined(__x86_64__)
80 	hostAdr = childAdr;
81 #else
82 	uint8 domain;
83 	pci_resource_range range;
84 	if (gPCI->LookupRange(kPciRangeMmio, childAdr, domain, range) >= B_OK)
85 		hostAdr = childAdr - range.pci_addr + range.host_addr;
86 #endif
87 	//dprintf("pci_ram_address(%#" B_PRIx64 ") -> %#" B_PRIx64 "\n", childAdr, hostAdr);
88 	return hostAdr;
89 }
90 
91 
92 status_t
93 pci_find_capability(uint8 virtualBus, uint8 device, uint8 function,
94 	uint8 capID, uint8 *offset)
95 {
96 	uint8 bus;
97 	uint8 domain;
98 	if (gPCI->ResolveVirtualBus(virtualBus, &domain, &bus) != B_OK)
99 		return B_ERROR;
100 
101 	return gPCI->FindCapability(domain, bus, device, function, capID, offset);
102 }
103 
104 
105 status_t
106 pci_find_extended_capability(uint8 virtualBus, uint8 device, uint8 function,
107 	uint16 capID, uint16 *offset)
108 {
109 	uint8 bus;
110 	uint8 domain;
111 	if (gPCI->ResolveVirtualBus(virtualBus, &domain, &bus) != B_OK)
112 		return B_ERROR;
113 
114 	return gPCI->FindExtendedCapability(domain, bus, device, function, capID,
115 		offset);
116 }
117 
118 
119 status_t
120 pci_reserve_device(uchar virtualBus, uchar device, uchar function,
121 	const char *driverName, void *nodeCookie)
122 {
123 	status_t status;
124 	uint8 bus;
125 	uint8 domain;
126 	TRACE(("pci_reserve_device(%d, %d, %d, %s)\n", virtualBus, device, function,
127 		driverName));
128 
129 	/*
130 	 * we add 2 nodes to the PCI devices, one with constant attributes,
131 	 * so adding for another driver fails, and a subnode with the
132 	 * driver-provided informations.
133 	 */
134 
135 	if (gPCI->ResolveVirtualBus(virtualBus, &domain, &bus) != B_OK)
136 		return B_ERROR;
137 
138 	//TRACE(("%s(%d [%d:%d], %d, %d, %s, %p)\n", __FUNCTION__, virtualBus,
139 	//	domain, bus, device, function, driverName, nodeCookie));
140 
141 	device_attr matchThis[] = {
142 		// info about device
143 		{B_DEVICE_BUS, B_STRING_TYPE, {.string = "pci"}},
144 
145 		// location on PCI bus
146 		{B_PCI_DEVICE_DOMAIN, B_UINT8_TYPE, {.ui8 = domain}},
147 		{B_PCI_DEVICE_BUS, B_UINT8_TYPE, {.ui8 = bus}},
148 		{B_PCI_DEVICE_DEVICE, B_UINT8_TYPE, {.ui8 = device}},
149 		{B_PCI_DEVICE_FUNCTION, B_UINT8_TYPE, {.ui8 = function}},
150 		{NULL}
151 	};
152 	device_attr legacyAttrs[] = {
153 		// info about device
154 		{B_DEVICE_BUS, B_STRING_TYPE, {.string = "legacy_driver"}},
155 		{B_DEVICE_PRETTY_NAME, B_STRING_TYPE, {.string = "Legacy Driver Reservation"}},
156 		{NULL}
157 	};
158 	device_attr drvAttrs[] = {
159 		// info about device
160 		{B_DEVICE_BUS, B_STRING_TYPE, {.string = "legacy_driver"}},
161 		{B_DEVICE_PRETTY_NAME, B_STRING_TYPE, {.string = driverName}},
162 		{"legacy_driver", B_STRING_TYPE, {.string = driverName}},
163 		{"legacy_driver_cookie", B_UINT64_TYPE, {.ui64 = (uint64)nodeCookie}},
164 		{NULL}
165 	};
166 	device_node *node, *legacy;
167 
168 	status = B_DEVICE_NOT_FOUND;
169 	device_node *root_pci_node = gPCI->_GetDomainData(domain)->root_node;
170 
171 	node = NULL;
172 	if (gDeviceManager->get_next_child_node(root_pci_node,
173 		matchThis, &node) < B_OK) {
174 		goto err1;
175 	}
176 
177 	// common API for all legacy modules ?
178 	//status = legacy_driver_register(node, driverName, nodeCookie, PCI_LEGACY_DRIVER_MODULE_NAME);
179 
180 	status = gDeviceManager->register_node(node, PCI_LEGACY_DRIVER_MODULE_NAME,
181 		legacyAttrs, NULL, &legacy);
182 	if (status < B_OK)
183 		goto err2;
184 
185 	status = gDeviceManager->register_node(legacy, PCI_LEGACY_DRIVER_MODULE_NAME,
186 		drvAttrs, NULL, NULL);
187 	if (status < B_OK)
188 		goto err3;
189 
190 	gDeviceManager->put_node(node);
191 
192 	return B_OK;
193 
194 err3:
195 	gDeviceManager->unregister_node(legacy);
196 err2:
197 	gDeviceManager->put_node(node);
198 err1:
199 	TRACE(("pci_reserve_device for driver %s failed: %s\n", driverName,
200 		strerror(status)));
201 	return status;
202 }
203 
204 
205 status_t
206 pci_unreserve_device(uchar virtualBus, uchar device, uchar function,
207 	const char *driverName, void *nodeCookie)
208 {
209 	status_t status;
210 	uint8 bus;
211 	uint8 domain;
212 	TRACE(("pci_unreserve_device(%d, %d, %d, %s)\n", virtualBus, device,
213 		function, driverName));
214 
215 	if (gPCI->ResolveVirtualBus(virtualBus, &domain, &bus) != B_OK)
216 		return B_ERROR;
217 
218 	//TRACE(("%s(%d [%d:%d], %d, %d, %s, %p)\n", __FUNCTION__, virtualBus,
219 	//	domain, bus, device, function, driverName, nodeCookie));
220 
221 	device_attr matchThis[] = {
222 		// info about device
223 		{B_DEVICE_BUS, B_STRING_TYPE, {.string = "pci"}},
224 
225 		// location on PCI bus
226 		{B_PCI_DEVICE_DOMAIN, B_UINT8_TYPE, {.ui8 = domain}},
227 		{B_PCI_DEVICE_BUS, B_UINT8_TYPE, {.ui8 = bus}},
228 		{B_PCI_DEVICE_DEVICE, B_UINT8_TYPE, {.ui8 = device}},
229 		{B_PCI_DEVICE_FUNCTION, B_UINT8_TYPE, {.ui8 = function}},
230 		{NULL}
231 	};
232 	device_attr legacyAttrs[] = {
233 		// info about device
234 		{B_DEVICE_BUS, B_STRING_TYPE, {.string = "legacy_driver"}},
235 		{B_DEVICE_PRETTY_NAME, B_STRING_TYPE, {.string = "Legacy Driver Reservation"}},
236 		{NULL}
237 	};
238 	device_attr drvAttrs[] = {
239 		// info about device
240 		{B_DEVICE_BUS, B_STRING_TYPE, {.string = "legacy_driver"}},
241 		{"legacy_driver", B_STRING_TYPE, {.string = driverName}},
242 		{"legacy_driver_cookie", B_UINT64_TYPE, {.ui64 = (uint64)nodeCookie}},
243 		{NULL}
244 	};
245 	device_node *pci, *node, *legacy, *drv;
246 
247 	status = B_DEVICE_NOT_FOUND;
248 
249 	pci = gPCI->_GetDomainData(domain)->root_node;
250 
251 	node = NULL;
252 	if (gDeviceManager->get_next_child_node(pci, matchThis, &node) < B_OK)
253 		goto err1;
254 
255 	// common API for all legacy modules ?
256 	//status = legacy_driver_unregister(node, driverName, nodeCookie);
257 
258 	legacy = NULL;
259 	if (gDeviceManager->get_next_child_node(node, legacyAttrs, &legacy) < B_OK)
260 		goto err2;
261 
262 	drv = NULL;
263 	if (gDeviceManager->get_next_child_node(legacy, drvAttrs, &drv) < B_OK)
264 		goto err3;
265 
266 	gDeviceManager->put_node(drv);
267 	status = gDeviceManager->unregister_node(drv);
268 	//dprintf("unreg:drv:%s\n", strerror(status));
269 
270 	gDeviceManager->put_node(legacy);
271 	status = gDeviceManager->unregister_node(legacy);
272 	//dprintf("unreg:legacy:%s\n", strerror(status));
273 	// we'll get EBUSY here anyway...
274 
275 	gDeviceManager->put_node(node);
276 	return B_OK;
277 
278 err3:
279 	gDeviceManager->put_node(legacy);
280 err2:
281 	gDeviceManager->put_node(node);
282 err1:
283 	TRACE(("pci_unreserve_device for driver %s failed: %s\n", driverName,
284 		strerror(status)));
285 	return status;
286 }
287 
288 
289 status_t
290 pci_update_interrupt_line(uchar virtualBus, uchar device, uchar function,
291 	uchar newInterruptLineValue)
292 {
293 	uint8 bus;
294 	uint8 domain;
295 	if (gPCI->ResolveVirtualBus(virtualBus, &domain, &bus) != B_OK)
296 		return B_ERROR;
297 
298 	return gPCI->UpdateInterruptLine(domain, bus, device, function,
299 		newInterruptLineValue);
300 }
301 
302 
303 status_t
304 pci_get_powerstate(uchar virtualBus, uint8 device, uint8 function, uint8* state)
305 {
306 	uint8 bus;
307 	uint8 domain;
308 	if (gPCI->ResolveVirtualBus(virtualBus, &domain, &bus) != B_OK)
309 		return B_ERROR;
310 
311 	return gPCI->GetPowerstate(domain, bus, device, function, state);
312 }
313 
314 
315 status_t
316 pci_set_powerstate(uchar virtualBus, uint8 device, uint8 function, uint8 newState)
317 {
318 	uint8 bus;
319 	uint8 domain;
320 	if (gPCI->ResolveVirtualBus(virtualBus, &domain, &bus) != B_OK)
321 		return B_ERROR;
322 
323 	return gPCI->SetPowerstate(domain, bus, device, function, newState);
324 }
325 
326 
327 // used by pci_info.cpp print_info_basic()
328 void
329 __pci_resolve_virtual_bus(uint8 virtualBus, uint8 *domain, uint8 *bus)
330 {
331 	if (gPCI->ResolveVirtualBus(virtualBus, domain, bus) < B_OK)
332 		panic("ResolveVirtualBus failed");
333 }
334 
335 
336 // #pragma mark kernel debugger commands
337 
338 
339 static int
340 display_io(int argc, char **argv)
341 {
342 	int32 displayWidth;
343 	int32 itemSize;
344 	int32 num = 1;
345 	int address;
346 	int i = 1, j;
347 
348 	switch (argc) {
349 	case 3:
350 		num = atoi(argv[2]);
351 	case 2:
352 		address = strtoul(argv[1], NULL, 0);
353 		break;
354 	default:
355 		kprintf("usage: %s <address> [num]\n", argv[0]);
356 		return 0;
357 	}
358 
359 	// build the format string
360 	if (strcmp(argv[0], "inb") == 0 || strcmp(argv[0], "in8") == 0) {
361 		itemSize = 1;
362 		displayWidth = 16;
363 	} else if (strcmp(argv[0], "ins") == 0 || strcmp(argv[0], "in16") == 0) {
364 		itemSize = 2;
365 		displayWidth = 8;
366 	} else if (strcmp(argv[0], "inw") == 0 || strcmp(argv[0], "in32") == 0) {
367 		itemSize = 4;
368 		displayWidth = 4;
369 	} else {
370 		kprintf("display_io called in an invalid way!\n");
371 		return 0;
372 	}
373 
374 	for (i = 0; i < num; i++) {
375 		if ((i % displayWidth) == 0) {
376 			int32 displayed = min_c(displayWidth, (num-i)) * itemSize;
377 			if (i != 0)
378 				kprintf("\n");
379 
380 			kprintf("[0x%" B_PRIx32 "]  ", address + i * itemSize);
381 
382 			if (num > displayWidth) {
383 				// make sure the spacing in the last line is correct
384 				for (j = displayed; j < displayWidth * itemSize; j++)
385 					kprintf(" ");
386 			}
387 			kprintf("  ");
388 		}
389 
390 		switch (itemSize) {
391 			case 1:
392 				kprintf(" %02" B_PRIx8, pci_read_io_8(address + i * itemSize));
393 				break;
394 			case 2:
395 				kprintf(" %04" B_PRIx16, pci_read_io_16(address + i * itemSize));
396 				break;
397 			case 4:
398 				kprintf(" %08" B_PRIx32, pci_read_io_32(address + i * itemSize));
399 				break;
400 		}
401 	}
402 
403 	kprintf("\n");
404 	return 0;
405 }
406 
407 
408 static int
409 write_io(int argc, char **argv)
410 {
411 	int32 itemSize;
412 	uint32 value;
413 	int address;
414 	int i = 1;
415 
416 	if (argc < 3) {
417 		kprintf("usage: %s <address> <value> [value [...]]\n", argv[0]);
418 		return 0;
419 	}
420 
421 	address = strtoul(argv[1], NULL, 0);
422 
423 	if (strcmp(argv[0], "outb") == 0 || strcmp(argv[0], "out8") == 0) {
424 		itemSize = 1;
425 	} else if (strcmp(argv[0], "outs") == 0 || strcmp(argv[0], "out16") == 0) {
426 		itemSize = 2;
427 	} else if (strcmp(argv[0], "outw") == 0 || strcmp(argv[0], "out32") == 0) {
428 		itemSize = 4;
429 	} else {
430 		kprintf("write_io called in an invalid way!\n");
431 		return 0;
432 	}
433 
434 	// skip cmd name and address
435 	argv += 2;
436 	argc -= 2;
437 
438 	for (i = 0; i < argc; i++) {
439 		value = strtoul(argv[i], NULL, 0);
440 		switch (itemSize) {
441 			case 1:
442 				pci_write_io_8(address + i * itemSize, value);
443 				break;
444 			case 2:
445 				pci_write_io_16(address + i * itemSize, value);
446 				break;
447 			case 4:
448 				pci_write_io_32(address + i * itemSize, value);
449 				break;
450 		}
451 	}
452 
453 	return 0;
454 }
455 
456 
457 static int
458 pcistatus(int argc, char **argv)
459 {
460 	gPCI->ClearDeviceStatus(NULL, true);
461 	return 0;
462 }
463 
464 
465 static int
466 pcirefresh(int argc, char **argv)
467 {
468 	gPCI->RefreshDeviceInfo();
469 	pci_print_info();
470 	return 0;
471 }
472 
473 
474 // #pragma mark bus manager init/uninit
475 
476 static bool sInitDone;
477 
478 
479 status_t
480 pci_init_deferred(void)
481 {
482 	dprintf("pci_init_deferred()\n");
483 
484 	if (sInitDone)
485 		return B_OK;
486 
487 	add_debugger_command("inw", &display_io, "dump io words (32-bit)");
488 	add_debugger_command("in32", &display_io, "dump io words (32-bit)");
489 	add_debugger_command("ins", &display_io, "dump io shorts (16-bit)");
490 	add_debugger_command("in16", &display_io, "dump io shorts (16-bit)");
491 	add_debugger_command("inb", &display_io, "dump io bytes (8-bit)");
492 	add_debugger_command("in8", &display_io, "dump io bytes (8-bit)");
493 
494 	add_debugger_command("outw", &write_io, "write io words (32-bit)");
495 	add_debugger_command("out32", &write_io, "write io words (32-bit)");
496 	add_debugger_command("outs", &write_io, "write io shorts (16-bit)");
497 	add_debugger_command("out16", &write_io, "write io shorts (16-bit)");
498 	add_debugger_command("outb", &write_io, "write io bytes (8-bit)");
499 	add_debugger_command("out8", &write_io, "write io bytes (8-bit)");
500 
501 	gPCI->InitDomainData();
502 	gPCI->InitBus();
503 
504 	add_debugger_command("pcistatus", &pcistatus, "dump and clear pci device status registers");
505 	add_debugger_command("pcirefresh", &pcirefresh, "refresh and print all pci_info");
506 
507 	if (gPCI->Finalize() != B_OK) {
508 		TRACE(("PCI: pci_controller_finalize failed\n"));
509 		return B_ERROR;
510 	}
511 
512 	pci_print_info();
513 
514 	sInitDone = true;
515 	return B_OK;
516 }
517 
518 
519 status_t
520 pci_init(void)
521 {
522 	gPCI = new PCI;
523 	return B_OK;
524 }
525 
526 
527 void
528 pci_uninit(void)
529 {
530 	delete gPCI;
531 
532 	if (!sInitDone)
533 		return;
534 
535 	sInitDone = false;
536 
537 	remove_debugger_command("outw", &write_io);
538 	remove_debugger_command("out32", &write_io);
539 	remove_debugger_command("outs", &write_io);
540 	remove_debugger_command("out16", &write_io);
541 	remove_debugger_command("outb", &write_io);
542 	remove_debugger_command("out8", &write_io);
543 
544 	remove_debugger_command("inw", &display_io);
545 	remove_debugger_command("in32", &display_io);
546 	remove_debugger_command("ins", &display_io);
547 	remove_debugger_command("in16", &display_io);
548 	remove_debugger_command("inb", &display_io);
549 	remove_debugger_command("in8", &display_io);
550 
551 	remove_debugger_command("pcistatus", &pcistatus);
552 	remove_debugger_command("pcirefresh", &pcirefresh);
553 }
554 
555 
556 // #pragma mark PCI class
557 
558 
559 PCI::PCI()
560 	:
561 	fRootBus(0),
562 	fDomainCount(0),
563 	fBusEnumeration(false),
564 	fVirtualBusMap(),
565 	fNextVirtualBus(0)
566 {
567 	#if defined(__POWERPC__) || defined(__M68K__)
568 		fBusEnumeration = true;
569 	#endif
570 }
571 
572 
573 void
574 PCI::InitBus()
575 {
576 	PCIBus **nextBus = &fRootBus;
577 	for (uint8 i = 0; i < fDomainCount; i++) {
578 		PCIBus *bus = new PCIBus;
579 		bus->next = NULL;
580 		bus->parent = NULL;
581 		bus->child = NULL;
582 		bus->domain = i;
583 		bus->bus = 0;
584 		*nextBus = bus;
585 		nextBus = &bus->next;
586 	}
587 
588 	if (fBusEnumeration) {
589 		for (uint8 i = 0; i < fDomainCount; i++) {
590 			_EnumerateBus(i, 0);
591 		}
592 	}
593 
594 	if (1) {
595 		for (uint8 i = 0; i < fDomainCount; i++) {
596 			_FixupDevices(i, 0);
597 		}
598 	}
599 
600 	if (fRootBus) {
601 		_DiscoverBus(fRootBus);
602 		_ConfigureBridges(fRootBus);
603 		ClearDeviceStatus(fRootBus, false);
604 		_RefreshDeviceInfo(fRootBus);
605 	}
606 }
607 
608 
609 status_t
610 PCI::Finalize()
611 {
612 	// TODO: Properly handle multiple domains. Currently finalize fill be called twice for first
613 	// domain is second domain is added, but should be called only once.
614 
615 	for (uint8 i = 0; i < fDomainCount; i++) {
616 		pci_controller_module_info* controller = fDomainData[i].controller;
617 		if (controller->finalize != NULL) {
618 			status_t res = controller->finalize(fDomainData[i].controller_cookie);
619 			if (res < B_OK)
620 				return res;
621 		}
622 	}
623 
624 	return B_OK;
625 }
626 
627 
628 PCI::~PCI()
629 {
630 }
631 
632 
633 status_t
634 PCI::_CreateVirtualBus(uint8 domain, uint8 bus, uint8 *virtualBus)
635 {
636 #if defined(__i386__) || defined(__x86_64__)
637 
638 	// IA32 doesn't use domains
639 	if (domain)
640 		panic("PCI::CreateVirtualBus domain != 0");
641 	*virtualBus = bus;
642 	return B_OK;
643 
644 #else
645 
646 	if (fNextVirtualBus > 0xff)
647 		panic("PCI::CreateVirtualBus: virtual bus number space exhausted");
648 
649 	uint16 value = domain << 8 | bus;
650 
651 	for (VirtualBusMap::Iterator it = fVirtualBusMap.Begin();
652 		it != fVirtualBusMap.End(); ++it) {
653 		if (it->Value() == value) {
654 			*virtualBus = it->Key();
655 			FLOW("PCI::CreateVirtualBus: domain %d, bus %d already in map => "
656 				"virtualBus %d\n", domain, bus, *virtualBus);
657 			return B_OK;
658 		}
659 	}
660 
661 	*virtualBus = fNextVirtualBus++;
662 
663 	FLOW("PCI::CreateVirtualBus: domain %d, bus %d => virtualBus %d\n", domain,
664 		bus, *virtualBus);
665 
666 	return fVirtualBusMap.Insert(*virtualBus, value);
667 
668 #endif
669 }
670 
671 
672 status_t
673 PCI::ResolveVirtualBus(uint8 virtualBus, uint8 *domain, uint8 *bus)
674 {
675 #if defined(__i386__) || defined(__x86_64__)
676 
677 	// IA32 doesn't use domains
678 	*bus = virtualBus;
679 	*domain = 0;
680 	return B_OK;
681 
682 #else
683 
684 	if (virtualBus >= fNextVirtualBus)
685 		return B_ERROR;
686 
687 	uint16 value = fVirtualBusMap.Get(virtualBus);
688 	*domain = value >> 8;
689 	*bus = value & 0xff;
690 	return B_OK;
691 
692 #endif
693 }
694 
695 
696 status_t
697 PCI::AddController(pci_controller_module_info *controller, void *controller_cookie,
698 	device_node *root_node)
699 {
700 	if (fDomainCount == MAX_PCI_DOMAINS)
701 		return B_ERROR;
702 
703 	fDomainData[fDomainCount].controller = controller;
704 	fDomainData[fDomainCount].controller_cookie = controller_cookie;
705 	fDomainData[fDomainCount].root_node = root_node;
706 
707 	// initialized later to avoid call back into controller at this point
708 	fDomainData[fDomainCount].max_bus_devices = -1;
709 
710 	fDomainCount++;
711 	return B_OK;
712 }
713 
714 
715 status_t
716 PCI::LookupRange(uint32 type, phys_addr_t pciAddr,
717 	uint8 &domain, pci_resource_range &range, uint8 **mappedAdr)
718 {
719 	if (type >= kPciRangeEnd)
720 		return B_BAD_VALUE;
721 
722 	for (uint8 curDomain = 0; curDomain < fDomainCount; curDomain++) {
723 		pci_resource_range const *const &ranges = fDomainData[curDomain].ranges;
724 
725 		uint32 typeBeg, typeEnd;
726 		if (type == kPciRangeMmio) {
727 			typeBeg = kPciRangeMmio;
728 			typeEnd = kPciRangeMmioEnd;
729 		} else {
730 			typeBeg = type;
731 			typeEnd = type + 1;
732 		}
733 		for (uint32 curType = typeBeg; curType < typeEnd; curType++) {
734 			const pci_resource_range curRange = ranges[curType];
735 			if (pciAddr >= curRange.pci_addr && pciAddr < curRange.pci_addr + curRange.size) {
736 				domain = curDomain;
737 				range = curRange;
738 #if !(defined(__i386__) || defined(__x86_64__))
739 				if (type == kPciRangeIoPort && mappedAdr != NULL)
740 					*mappedAdr = fDomainData[curDomain].io_port_adr;
741 #endif
742 				return B_OK;
743 			}
744 		}
745 	}
746 	return B_ENTRY_NOT_FOUND;
747 }
748 
749 
750 void
751 PCI::InitDomainData()
752 {
753 	for (uint8 i = 0; i < fDomainCount; i++) {
754 		int32 count;
755 		status_t status;
756 
757 		pci_controller_module_info *ctrlModule = fDomainData[i].controller;
758 		void *ctrl = fDomainData[i].controller_cookie;
759 
760 		status = ctrlModule->get_max_bus_devices(ctrl, &count);
761 		fDomainData[i].max_bus_devices = (status == B_OK) ? count : 0;
762 
763 		memset(fDomainData[i].ranges, 0, sizeof(fDomainData[i].ranges));
764 		pci_resource_range range;
765 		for (uint32 j = 0; ctrlModule->get_range(ctrl, j, &range) >= B_OK; j++) {
766 			if (range.type < kPciRangeEnd && range.size > 0)
767 				fDomainData[i].ranges[range.type] = range;
768 		}
769 
770 #if !(defined(__i386__) || defined(__x86_64__))
771 		// TODO: free resources when domain is detached
772 		pci_resource_range &ioPortRange = fDomainData[i].ranges[kPciRangeIoPort];
773 		if (ioPortRange.size > 0) {
774 			fDomainData[i].io_port_area = map_physical_memory("PCI IO Ports",
775 				ioPortRange.host_addr, ioPortRange.size, B_ANY_KERNEL_ADDRESS,
776 				B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA, (void **)&fDomainData[i].io_port_adr);
777 
778 			if (fDomainData[i].io_port_area < B_OK)
779 				fDomainData[i].io_port_adr = NULL;
780 		}
781 #endif
782 	}
783 }
784 
785 
786 domain_data *
787 PCI::_GetDomainData(uint8 domain)
788 {
789 	if (domain >= fDomainCount)
790 		return NULL;
791 
792 	return &fDomainData[domain];
793 }
794 
795 
796 inline int
797 PCI::_NumFunctions(uint8 domain, uint8 bus, uint8 device)
798 {
799 	uint8 type = ReadConfig(domain, bus, device,
800 		0, PCI_header_type, 1);
801 	return (type & PCI_multifunction) != 0 ? 8 : 1;
802 }
803 
804 
805 status_t
806 PCI::GetNthInfo(long index, pci_info *outInfo)
807 {
808 	long currentIndex = 0;
809 	if (!fRootBus)
810 		return B_ERROR;
811 
812 	return _GetNthInfo(fRootBus, &currentIndex, index, outInfo);
813 }
814 
815 
816 status_t
817 PCI::_GetNthInfo(PCIBus *bus, long *currentIndex, long wantIndex,
818 	pci_info *outInfo)
819 {
820 	// maps tree structure to linear indexed view
821 	PCIDev *dev = bus->child;
822 	while (dev) {
823 		if (*currentIndex == wantIndex) {
824 			*outInfo = dev->info;
825 			return B_OK;
826 		}
827 		*currentIndex += 1;
828 		if (dev->child && B_OK == _GetNthInfo(dev->child, currentIndex,
829 				wantIndex, outInfo))
830 			return B_OK;
831 		dev = dev->next;
832 	}
833 
834 	if (bus->next)
835 		return _GetNthInfo(bus->next, currentIndex, wantIndex, outInfo);
836 
837 	return B_ERROR;
838 }
839 
840 
841 void
842 PCI::_EnumerateBus(uint8 domain, uint8 bus, uint8 *subordinateBus)
843 {
844 	TRACE(("PCI: EnumerateBus: domain %u, bus %u\n", domain, bus));
845 
846 	int maxBusDevices = _GetDomainData(domain)->max_bus_devices;
847 
848 	// step 1: disable all bridges on this bus
849 	for (int dev = 0; dev < maxBusDevices; dev++) {
850 		uint16 vendor_id = ReadConfig(domain, bus, dev, 0, PCI_vendor_id, 2);
851 		if (vendor_id == 0xffff)
852 			continue;
853 
854 		int numFunctions = _NumFunctions(domain, bus, dev);
855 		for (int function = 0; function < numFunctions; function++) {
856 			uint16 device_id = ReadConfig(domain, bus, dev, function,
857 				PCI_device_id, 2);
858 			if (device_id == 0xffff)
859 				continue;
860 
861 			uint8 baseClass = ReadConfig(domain, bus, dev, function,
862 				PCI_class_base, 1);
863 			uint8 subClass = ReadConfig(domain, bus, dev, function,
864 				PCI_class_sub, 1);
865 			if (baseClass != PCI_bridge || subClass != PCI_pci)
866 				continue;
867 
868 			// skip incorrectly configured devices
869 			uint8 headerType = ReadConfig(domain, bus, dev, function,
870 				PCI_header_type, 1) & PCI_header_type_mask;
871 			if (headerType != PCI_header_type_PCI_to_PCI_bridge)
872 				continue;
873 
874 			TRACE(("PCI: found PCI-PCI bridge: domain %u, bus %u, dev %u, func %u\n",
875 				domain, bus, dev, function));
876 			TRACE(("PCI: original settings: pcicmd %04" B_PRIx32 ", primary-bus "
877 				"%" B_PRIu32 ", secondary-bus %" B_PRIu32 ", subordinate-bus "
878 				"%" B_PRIu32 "\n",
879 				ReadConfig(domain, bus, dev, function, PCI_command, 2),
880 				ReadConfig(domain, bus, dev, function, PCI_primary_bus, 1),
881 				ReadConfig(domain, bus, dev, function, PCI_secondary_bus, 1),
882 				ReadConfig(domain, bus, dev, function, PCI_subordinate_bus, 1)));
883 
884 			// disable decoding
885 			uint16 pcicmd;
886 			pcicmd = ReadConfig(domain, bus, dev, function, PCI_command, 2);
887 			pcicmd &= ~(PCI_command_io | PCI_command_memory
888 				| PCI_command_master);
889 			WriteConfig(domain, bus, dev, function, PCI_command, 2, pcicmd);
890 
891 			// disable busses
892 			WriteConfig(domain, bus, dev, function, PCI_primary_bus, 1, 0);
893 			WriteConfig(domain, bus, dev, function, PCI_secondary_bus, 1, 0);
894 			WriteConfig(domain, bus, dev, function, PCI_subordinate_bus, 1, 0);
895 
896 			TRACE(("PCI: disabled settings: pcicmd %04" B_PRIx32 ", primary-bus "
897 				"%" B_PRIu32 ", secondary-bus %" B_PRIu32 ", subordinate-bus "
898 				"%" B_PRIu32 "\n",
899 				ReadConfig(domain, bus, dev, function, PCI_command, 2),
900 				ReadConfig(domain, bus, dev, function, PCI_primary_bus, 1),
901 				ReadConfig(domain, bus, dev, function, PCI_secondary_bus, 1),
902 				ReadConfig(domain, bus, dev, function, PCI_subordinate_bus, 1)));
903 		}
904 	}
905 
906 	uint8 lastUsedBusNumber = bus;
907 
908 	// step 2: assign busses to all bridges, and enable them again
909 	for (int dev = 0; dev < maxBusDevices; dev++) {
910 		uint16 vendor_id = ReadConfig(domain, bus, dev, 0, PCI_vendor_id, 2);
911 		if (vendor_id == 0xffff)
912 			continue;
913 
914 		int numFunctions = _NumFunctions(domain, bus, dev);
915 		for (int function = 0; function < numFunctions; function++) {
916 			uint16 deviceID = ReadConfig(domain, bus, dev, function,
917 				PCI_device_id, 2);
918 			if (deviceID == 0xffff)
919 				continue;
920 
921 			uint8 baseClass = ReadConfig(domain, bus, dev, function,
922 				PCI_class_base, 1);
923 			uint8 subClass = ReadConfig(domain, bus, dev, function,
924 				PCI_class_sub, 1);
925 			if (baseClass != PCI_bridge || subClass != PCI_pci)
926 				continue;
927 
928 			// skip incorrectly configured devices
929 			uint8 headerType = ReadConfig(domain, bus, dev, function,
930 				PCI_header_type, 1) & PCI_header_type_mask;
931 			if (headerType != PCI_header_type_PCI_to_PCI_bridge)
932 				continue;
933 
934 			TRACE(("PCI: configuring PCI-PCI bridge: domain %u, bus %u, dev %u, func %u\n",
935 				domain, bus, dev, function));
936 
937 			// open Scheunentor for enumerating the bus behind the bridge
938 			WriteConfig(domain, bus, dev, function, PCI_primary_bus, 1, bus);
939 			WriteConfig(domain, bus, dev, function, PCI_secondary_bus, 1,
940 				lastUsedBusNumber + 1);
941 			WriteConfig(domain, bus, dev, function, PCI_subordinate_bus, 1, 255);
942 
943 			// enable decoding (too early here?)
944 			uint16 pcicmd;
945 			pcicmd = ReadConfig(domain, bus, dev, function, PCI_command, 2);
946 			pcicmd |= PCI_command_io | PCI_command_memory | PCI_command_master;
947 			WriteConfig(domain, bus, dev, function, PCI_command, 2, pcicmd);
948 
949 			TRACE(("PCI: probing settings: pcicmd %04" B_PRIx32 ", primary-bus "
950 				"%" B_PRIu32 ", secondary-bus %" B_PRIu32 ", subordinate-bus "
951 				"%" B_PRIu32 "\n",
952 				ReadConfig(domain, bus, dev, function, PCI_command, 2),
953 				ReadConfig(domain, bus, dev, function, PCI_primary_bus, 1),
954 				ReadConfig(domain, bus, dev, function, PCI_secondary_bus, 1),
955 				ReadConfig(domain, bus, dev, function, PCI_subordinate_bus, 1)));
956 
957 			// enumerate bus
958 			_EnumerateBus(domain, lastUsedBusNumber + 1, &lastUsedBusNumber);
959 
960 			// close Scheunentor
961 			WriteConfig(domain, bus, dev, function, PCI_subordinate_bus, 1, lastUsedBusNumber);
962 
963 			TRACE(("PCI: configured settings: pcicmd %04" B_PRIx32 ", primary-bus "
964 				"%" B_PRIu32 ", secondary-bus %" B_PRIu32 ", subordinate-bus "
965 				"%" B_PRIu32 "\n",
966 				ReadConfig(domain, bus, dev, function, PCI_command, 2),
967 				ReadConfig(domain, bus, dev, function, PCI_primary_bus, 1),
968 				ReadConfig(domain, bus, dev, function, PCI_secondary_bus, 1),
969 				ReadConfig(domain, bus, dev, function, PCI_subordinate_bus, 1)));
970 			}
971 	}
972 	if (subordinateBus)
973 		*subordinateBus = lastUsedBusNumber;
974 
975 	TRACE(("PCI: EnumerateBus done: domain %u, bus %u, last used bus number %u\n", domain, bus, lastUsedBusNumber));
976 }
977 
978 
979 void
980 PCI::_FixupDevices(uint8 domain, uint8 bus)
981 {
982 	FLOW("PCI: FixupDevices domain %u, bus %u\n", domain, bus);
983 
984 	int maxBusDevices = _GetDomainData(domain)->max_bus_devices;
985 	static int recursed = 0;
986 
987 	if (recursed++ > 10) {
988 		// guard against buggy chipsets
989 		// XXX: is there any official limit ?
990 		dprintf("PCI: FixupDevices: too many recursions (buggy chipset?)\n");
991 		recursed--;
992 		return;
993 	}
994 
995 	for (int dev = 0; dev < maxBusDevices; dev++) {
996 		uint16 vendorId = ReadConfig(domain, bus, dev, 0, PCI_vendor_id, 2);
997 		if (vendorId == 0xffff)
998 			continue;
999 
1000 		int numFunctions = _NumFunctions(domain, bus, dev);
1001 		for (int function = 0; function < numFunctions; function++) {
1002 			uint16 deviceId = ReadConfig(domain, bus, dev, function,
1003 				PCI_device_id, 2);
1004 			if (deviceId == 0xffff)
1005 				continue;
1006 
1007 			pci_fixup_device(this, domain, bus, dev, function);
1008 
1009 			uint8 baseClass = ReadConfig(domain, bus, dev, function,
1010 				PCI_class_base, 1);
1011 			if (baseClass != PCI_bridge)
1012 				continue;
1013 			uint8 subClass = ReadConfig(domain, bus, dev, function,
1014 				PCI_class_sub, 1);
1015 			if (subClass != PCI_pci)
1016 				continue;
1017 
1018 			// some FIC motherboards have a buggy BIOS...
1019 			// make sure the header type is correct for a bridge,
1020 			uint8 headerType = ReadConfig(domain, bus, dev, function,
1021 				PCI_header_type, 1) & PCI_header_type_mask;
1022 			if (headerType != PCI_header_type_PCI_to_PCI_bridge) {
1023 				dprintf("PCI: dom %u, bus %u, dev %2u, func %u, PCI bridge"
1024 					" class but wrong header type 0x%02x, ignoring.\n",
1025 					domain, bus, dev, function, headerType);
1026 				continue;
1027 			}
1028 
1029 
1030 			int busBehindBridge = ReadConfig(domain, bus, dev, function,
1031 				PCI_secondary_bus, 1);
1032 
1033 			TRACE(("PCI: FixupDevices: checking bus %d behind %04x:%04x\n",
1034 				busBehindBridge, vendorId, deviceId));
1035 			_FixupDevices(domain, busBehindBridge);
1036 		}
1037 	}
1038 	recursed--;
1039 }
1040 
1041 
1042 void
1043 PCI::_ConfigureBridges(PCIBus *bus)
1044 {
1045 	for (PCIDev *dev = bus->child; dev; dev = dev->next) {
1046 		if (dev->info.class_base == PCI_bridge
1047 			&& dev->info.class_sub == PCI_pci
1048 			&& (dev->info.header_type & PCI_header_type_mask)
1049 			== PCI_header_type_PCI_to_PCI_bridge) {
1050 			uint16 bridgeControlOld = ReadConfig(dev->domain, dev->bus,
1051 				dev->device, dev->function, PCI_bridge_control, 2);
1052 			uint16 bridgeControlNew = bridgeControlOld;
1053 			// Enable: Parity Error Response, SERR, Master Abort Mode, Discard
1054 			// Timer SERR
1055 			// Clear: Discard Timer Status
1056 			bridgeControlNew |= PCI_bridge_parity_error_response
1057 				| PCI_bridge_serr | PCI_bridge_master_abort
1058 				| PCI_bridge_discard_timer_status
1059 				| PCI_bridge_discard_timer_serr;
1060 			// Set discard timer to 2^15 PCI clocks
1061 			bridgeControlNew &= ~(PCI_bridge_primary_discard_timeout
1062 				| PCI_bridge_secondary_discard_timeout);
1063 			WriteConfig(dev->domain, dev->bus, dev->device, dev->function,
1064 				PCI_bridge_control, 2, bridgeControlNew);
1065 			bridgeControlNew = ReadConfig(dev->domain, dev->bus, dev->device,
1066 				dev->function, PCI_bridge_control, 2);
1067 			dprintf("PCI: dom %u, bus %u, dev %2u, func %u, changed PCI bridge"
1068 				" control from 0x%04x to 0x%04x\n", dev->domain, dev->bus,
1069 				dev->device, dev->function, bridgeControlOld,
1070 				bridgeControlNew);
1071 		}
1072 
1073 		if (dev->child)
1074 			_ConfigureBridges(dev->child);
1075 	}
1076 
1077 	if (bus->next)
1078 		_ConfigureBridges(bus->next);
1079 }
1080 
1081 
1082 void
1083 PCI::ClearDeviceStatus(PCIBus *bus, bool dumpStatus)
1084 {
1085 	if (!bus) {
1086 		if (!fRootBus)
1087 			return;
1088 		bus = fRootBus;
1089 	}
1090 
1091 	for (PCIDev *dev = bus->child; dev; dev = dev->next) {
1092 		// Clear and dump PCI device status
1093 		uint16 status = ReadConfig(dev->domain, dev->bus, dev->device,
1094 			dev->function, PCI_status, 2);
1095 		WriteConfig(dev->domain, dev->bus, dev->device, dev->function,
1096 			PCI_status, 2, status);
1097 		if (dumpStatus) {
1098 			kprintf("domain %u, bus %u, dev %2u, func %u, PCI device status "
1099 				"0x%04x\n", dev->domain, dev->bus, dev->device, dev->function,
1100 				status);
1101 			if (status & PCI_status_parity_error_detected)
1102 				kprintf("  Detected Parity Error\n");
1103 			if (status & PCI_status_serr_signalled)
1104 				kprintf("  Signalled System Error\n");
1105 			if (status & PCI_status_master_abort_received)
1106 				kprintf("  Received Master-Abort\n");
1107 			if (status & PCI_status_target_abort_received)
1108 				kprintf("  Received Target-Abort\n");
1109 			if (status & PCI_status_target_abort_signalled)
1110 				kprintf("  Signalled Target-Abort\n");
1111 			if (status & PCI_status_parity_signalled)
1112 				kprintf("  Master Data Parity Error\n");
1113 		}
1114 
1115 		if (dev->info.class_base == PCI_bridge
1116 			&& dev->info.class_sub == PCI_pci) {
1117 			// Clear and dump PCI bridge secondary status
1118 			uint16 secondaryStatus = ReadConfig(dev->domain, dev->bus,
1119 				dev->device, dev->function, PCI_secondary_status, 2);
1120 			WriteConfig(dev->domain, dev->bus, dev->device, dev->function,
1121 				PCI_secondary_status, 2, secondaryStatus);
1122 			if (dumpStatus) {
1123 				kprintf("domain %u, bus %u, dev %2u, func %u, PCI bridge "
1124 					"secondary status 0x%04x\n", dev->domain, dev->bus,
1125 					dev->device, dev->function, secondaryStatus);
1126 				if (secondaryStatus & PCI_status_parity_error_detected)
1127 					kprintf("  Detected Parity Error\n");
1128 				if (secondaryStatus & PCI_status_serr_signalled)
1129 					kprintf("  Received System Error\n");
1130 				if (secondaryStatus & PCI_status_master_abort_received)
1131 					kprintf("  Received Master-Abort\n");
1132 				if (secondaryStatus & PCI_status_target_abort_received)
1133 					kprintf("  Received Target-Abort\n");
1134 				if (secondaryStatus & PCI_status_target_abort_signalled)
1135 					kprintf("  Signalled Target-Abort\n");
1136 				if (secondaryStatus & PCI_status_parity_signalled)
1137 					kprintf("  Data Parity Reported\n");
1138 			}
1139 
1140 			// Clear and dump the discard-timer error bit located in bridge-control register
1141 			uint16 bridgeControl = ReadConfig(dev->domain, dev->bus,
1142 				dev->device, dev->function, PCI_bridge_control, 2);
1143 			WriteConfig(dev->domain, dev->bus, dev->device, dev->function,
1144 				PCI_bridge_control, 2, bridgeControl);
1145 			if (dumpStatus) {
1146 				kprintf("domain %u, bus %u, dev %2u, func %u, PCI bridge "
1147 					"control 0x%04x\n", dev->domain, dev->bus, dev->device,
1148 					dev->function, bridgeControl);
1149 				if (bridgeControl & PCI_bridge_discard_timer_status) {
1150 					kprintf("  bridge-control: Discard Timer Error\n");
1151 				}
1152 			}
1153 		}
1154 
1155 		if (dev->child)
1156 			ClearDeviceStatus(dev->child, dumpStatus);
1157 	}
1158 
1159 	if (bus->next)
1160 		ClearDeviceStatus(bus->next, dumpStatus);
1161 }
1162 
1163 
1164 void
1165 PCI::_DiscoverBus(PCIBus *bus)
1166 {
1167 	FLOW("PCI: DiscoverBus, domain %u, bus %u\n", bus->domain, bus->bus);
1168 
1169 	int maxBusDevices = _GetDomainData(bus->domain)->max_bus_devices;
1170 	static int recursed = 0;
1171 
1172 	if (recursed++ > 10) {
1173 		// guard against buggy chipsets
1174 		// XXX: is there any official limit ?
1175 		dprintf("PCI: DiscoverBus: too many recursions (buggy chipset?)\n");
1176 		recursed--;
1177 		return;
1178 	}
1179 
1180 	for (int dev = 0; dev < maxBusDevices; dev++) {
1181 		uint16 vendorID = ReadConfig(bus->domain, bus->bus, dev, 0,
1182 			PCI_vendor_id, 2);
1183 		if (vendorID == 0xffff)
1184 			continue;
1185 
1186 		int numFunctions = _NumFunctions(bus->domain, bus->bus, dev);
1187 		for (int function = 0; function < numFunctions; function++)
1188 			_DiscoverDevice(bus, dev, function);
1189 	}
1190 
1191 	if (bus->next)
1192 		_DiscoverBus(bus->next);
1193 	recursed--;
1194 }
1195 
1196 
1197 void
1198 PCI::_DiscoverDevice(PCIBus *bus, uint8 dev, uint8 function)
1199 {
1200 	FLOW("PCI: DiscoverDevice, domain %u, bus %u, dev %u, func %u\n", bus->domain, bus->bus, dev, function);
1201 
1202 	uint16 deviceID = ReadConfig(bus->domain, bus->bus, dev, function,
1203 		PCI_device_id, 2);
1204 	if (deviceID == 0xffff)
1205 		return;
1206 
1207 	PCIDev *newDev = _CreateDevice(bus, dev, function);
1208 
1209 	uint8 baseClass = ReadConfig(bus->domain, bus->bus, dev, function,
1210 		PCI_class_base, 1);
1211 	uint8 subClass = ReadConfig(bus->domain, bus->bus, dev, function,
1212 		PCI_class_sub, 1);
1213 	uint8 headerType = ReadConfig(bus->domain, bus->bus, dev, function,
1214 		PCI_header_type, 1) & PCI_header_type_mask;
1215 	if (baseClass == PCI_bridge && subClass == PCI_pci
1216 		&& headerType == PCI_header_type_PCI_to_PCI_bridge) {
1217 		uint8 secondaryBus = ReadConfig(bus->domain, bus->bus, dev, function,
1218 			PCI_secondary_bus, 1);
1219 		PCIBus *newBus = _CreateBus(newDev, bus->domain, secondaryBus);
1220 		_DiscoverBus(newBus);
1221 	}
1222 }
1223 
1224 
1225 PCIBus *
1226 PCI::_CreateBus(PCIDev *parent, uint8 domain, uint8 bus)
1227 {
1228 	PCIBus *newBus = new(std::nothrow) PCIBus;
1229 	if (newBus == NULL)
1230 		return NULL;
1231 
1232 	newBus->next = NULL;
1233 	newBus->parent = parent;
1234 	newBus->child = NULL;
1235 	newBus->domain = domain;
1236 	newBus->bus = bus;
1237 
1238 	// append
1239 	parent->child = newBus;
1240 
1241 	return newBus;
1242 }
1243 
1244 
1245 PCIDev *
1246 PCI::_CreateDevice(PCIBus *parent, uint8 device, uint8 function)
1247 {
1248 	FLOW("PCI: CreateDevice, domain %u, bus %u, dev %u, func %u:\n", parent->domain,
1249 		parent->bus, device, function);
1250 
1251 	PCIDev *newDev = new(std::nothrow) PCIDev;
1252 	if (newDev == NULL)
1253 		return NULL;
1254 
1255 	newDev->next = NULL;
1256 	newDev->parent = parent;
1257 	newDev->child = NULL;
1258 	newDev->domain = parent->domain;
1259 	newDev->bus = parent->bus;
1260 	newDev->device = device;
1261 	newDev->function = function;
1262 	memset(&newDev->info, 0, sizeof(newDev->info));
1263 
1264 	_ReadBasicInfo(newDev);
1265 
1266 	FLOW("PCI: CreateDevice, vendor 0x%04x, device 0x%04x, class_base 0x%02x, "
1267 		"class_sub 0x%02x\n", newDev->info.vendor_id, newDev->info.device_id,
1268 		newDev->info.class_base, newDev->info.class_sub);
1269 
1270 	// append
1271 	if (parent->child == NULL) {
1272 		parent->child = newDev;
1273 	} else {
1274 		PCIDev *sub = parent->child;
1275 		while (sub->next)
1276 			sub = sub->next;
1277 		sub->next = newDev;
1278 	}
1279 
1280 	return newDev;
1281 }
1282 
1283 
1284 uint64
1285 PCI::_BarSize(uint64 bits)
1286 {
1287 	if (!bits)
1288 		return 0;
1289 
1290 	uint64 size = 1;
1291 	while ((bits & size) == 0)
1292 		size <<= 1;
1293 
1294 	return size;
1295 }
1296 
1297 
1298 size_t
1299 PCI::_GetBarInfo(PCIDev *dev, uint8 offset, uint32 &_ramAddress,
1300 	uint32 &_pciAddress, uint32 &_size, uint8 &flags, uint32 *_highRAMAddress,
1301 	uint32 *_highPCIAddress, uint32 *_highSize)
1302 {
1303 	uint64 pciAddress = ReadConfig(dev->domain, dev->bus, dev->device,
1304 		dev->function, offset, 4);
1305 	WriteConfig(dev->domain, dev->bus, dev->device, dev->function, offset, 4,
1306 		0xffffffff);
1307 	uint64 size = ReadConfig(dev->domain, dev->bus, dev->device, dev->function,
1308 		offset, 4);
1309 	WriteConfig(dev->domain, dev->bus, dev->device, dev->function, offset, 4,
1310 		pciAddress);
1311 
1312 	uint32 mask = PCI_address_memory_32_mask;
1313 	bool is64bit = false;
1314 	if ((pciAddress & PCI_address_space) != 0)
1315 		mask = PCI_address_io_mask;
1316 	else {
1317 		is64bit = (pciAddress & PCI_address_type) == PCI_address_type_64;
1318 
1319 		if (is64bit && _highRAMAddress != NULL) {
1320 			uint64 highPCIAddress = ReadConfig(dev->domain, dev->bus,
1321 				dev->device, dev->function, offset + 4, 4);
1322 			WriteConfig(dev->domain, dev->bus, dev->device, dev->function,
1323 				offset + 4, 4, 0xffffffff);
1324 			uint64 highSize = ReadConfig(dev->domain, dev->bus, dev->device,
1325 				dev->function, offset + 4, 4);
1326 			WriteConfig(dev->domain, dev->bus, dev->device, dev->function,
1327 				offset + 4, 4, highPCIAddress);
1328 
1329 			pciAddress |= highPCIAddress << 32;
1330 			size |= highSize << 32;
1331 		}
1332 	}
1333 
1334 	flags = (uint32)pciAddress & ~mask;
1335 	pciAddress &= ((uint64)0xffffffff << 32) | mask;
1336 	size &= ((uint64)0xffffffff << 32) | mask;
1337 
1338 	size = _BarSize(size);
1339 	uint64 ramAddress = pci_ram_address(pciAddress);
1340 
1341 	_ramAddress = ramAddress;
1342 	_pciAddress = pciAddress;
1343 	_size = size;
1344 	if (!is64bit)
1345 		return 1;
1346 
1347 	if (_highRAMAddress == NULL || _highPCIAddress == NULL || _highSize == NULL)
1348 		panic("64 bit PCI BAR but no space to store high values\n");
1349 	else {
1350 		*_highRAMAddress = ramAddress >> 32;
1351 		*_highPCIAddress = pciAddress >> 32;
1352 		*_highSize = size >> 32;
1353 	}
1354 
1355 	return 2;
1356 }
1357 
1358 
1359 void
1360 PCI::_GetRomBarInfo(PCIDev *dev, uint8 offset, uint32 &_address, uint32 *_size,
1361 	uint8 *_flags)
1362 {
1363 	uint32 oldValue = ReadConfig(dev->domain, dev->bus, dev->device, dev->function,
1364 		offset, 4);
1365 	WriteConfig(dev->domain, dev->bus, dev->device, dev->function, offset, 4,
1366 		0xfffffffe); // LSB must be 0
1367 	uint32 newValue = ReadConfig(dev->domain, dev->bus, dev->device, dev->function,
1368 		offset, 4);
1369 	WriteConfig(dev->domain, dev->bus, dev->device, dev->function, offset, 4,
1370 		oldValue);
1371 
1372 	_address = oldValue & PCI_rom_address_mask;
1373 	if (_size != NULL)
1374 		*_size = _BarSize(newValue & PCI_rom_address_mask);
1375 	if (_flags != NULL)
1376 		*_flags = newValue & 0xf;
1377 }
1378 
1379 
1380 void
1381 PCI::_ReadBasicInfo(PCIDev *dev)
1382 {
1383 	uint8 virtualBus;
1384 
1385 	if (_CreateVirtualBus(dev->domain, dev->bus, &virtualBus) != B_OK) {
1386 		dprintf("PCI: CreateVirtualBus failed, domain %u, bus %u\n", dev->domain, dev->bus);
1387 		return;
1388 	}
1389 
1390 	dev->info.vendor_id = ReadConfig(dev->domain, dev->bus, dev->device,
1391 		dev->function, PCI_vendor_id, 2);
1392 	dev->info.device_id = ReadConfig(dev->domain, dev->bus, dev->device,
1393 		dev->function, PCI_device_id, 2);
1394 	dev->info.bus = virtualBus;
1395 	dev->info.device = dev->device;
1396 	dev->info.function = dev->function;
1397 	dev->info.revision = ReadConfig(dev->domain, dev->bus, dev->device,
1398 		dev->function, PCI_revision, 1);
1399 	dev->info.class_api = ReadConfig(dev->domain, dev->bus, dev->device,
1400 		dev->function, PCI_class_api, 1);
1401 	dev->info.class_sub = ReadConfig(dev->domain, dev->bus, dev->device,
1402 		dev->function, PCI_class_sub, 1);
1403 	dev->info.class_base = ReadConfig(dev->domain, dev->bus, dev->device,
1404 		dev->function, PCI_class_base, 1);
1405 	dev->info.line_size = ReadConfig(dev->domain, dev->bus, dev->device,
1406 		dev->function, PCI_line_size, 1);
1407 	dev->info.latency = ReadConfig(dev->domain, dev->bus, dev->device,
1408 		dev->function, PCI_latency, 1);
1409 	// BeOS does not mask off the multifunction bit, developer must use
1410 	// (header_type & PCI_header_type_mask)
1411 	dev->info.header_type = ReadConfig(dev->domain, dev->bus, dev->device,
1412 		dev->function, PCI_header_type, 1);
1413 	dev->info.bist = ReadConfig(dev->domain, dev->bus, dev->device,
1414 		dev->function, PCI_bist, 1);
1415 	dev->info.reserved = 0;
1416 }
1417 
1418 
1419 void
1420 PCI::_ReadHeaderInfo(PCIDev *dev)
1421 {
1422 	switch (dev->info.header_type & PCI_header_type_mask) {
1423 		case PCI_header_type_generic:
1424 		{
1425 			// disable PCI device address decoding (io and memory) while BARs
1426 			// are modified
1427 			uint16 pcicmd = ReadConfig(dev->domain, dev->bus, dev->device,
1428 				dev->function, PCI_command, 2);
1429 			WriteConfig(dev->domain, dev->bus, dev->device, dev->function,
1430 				PCI_command, 2,
1431 				pcicmd & ~(PCI_command_io | PCI_command_memory));
1432 
1433 			// get BAR size infos
1434 			_GetRomBarInfo(dev, PCI_rom_base, dev->info.u.h0.rom_base_pci,
1435 				&dev->info.u.h0.rom_size);
1436 			for (int i = 0; i < 6;) {
1437 				i += _GetBarInfo(dev, PCI_base_registers + 4 * i,
1438 					dev->info.u.h0.base_registers[i],
1439 					dev->info.u.h0.base_registers_pci[i],
1440 					dev->info.u.h0.base_register_sizes[i],
1441 					dev->info.u.h0.base_register_flags[i],
1442 					i < 5 ? &dev->info.u.h0.base_registers[i + 1] : NULL,
1443 					i < 5 ? &dev->info.u.h0.base_registers_pci[i + 1] : NULL,
1444 					i < 5 ? &dev->info.u.h0.base_register_sizes[i + 1] : NULL);
1445 			}
1446 
1447 			// restore PCI device address decoding
1448 			WriteConfig(dev->domain, dev->bus, dev->device, dev->function,
1449 				PCI_command, 2, pcicmd);
1450 
1451 			dev->info.u.h0.rom_base = (uint32)pci_ram_address(
1452 				dev->info.u.h0.rom_base_pci);
1453 
1454 			dev->info.u.h0.cardbus_cis = ReadConfig(dev->domain, dev->bus,
1455 				dev->device, dev->function, PCI_cardbus_cis, 4);
1456 			dev->info.u.h0.subsystem_id = ReadConfig(dev->domain, dev->bus,
1457 				dev->device, dev->function, PCI_subsystem_id, 2);
1458 			dev->info.u.h0.subsystem_vendor_id = ReadConfig(dev->domain,
1459 				dev->bus, dev->device, dev->function, PCI_subsystem_vendor_id,
1460 				2);
1461 			dev->info.u.h0.interrupt_line = ReadConfig(dev->domain, dev->bus,
1462 				dev->device, dev->function, PCI_interrupt_line, 1);
1463 			dev->info.u.h0.interrupt_pin = ReadConfig(dev->domain, dev->bus,
1464 				dev->device, dev->function, PCI_interrupt_pin, 1);
1465 			dev->info.u.h0.min_grant = ReadConfig(dev->domain, dev->bus,
1466 				dev->device, dev->function, PCI_min_grant, 1);
1467 			dev->info.u.h0.max_latency = ReadConfig(dev->domain, dev->bus,
1468 				dev->device, dev->function, PCI_max_latency, 1);
1469 			break;
1470 		}
1471 
1472 		case PCI_header_type_PCI_to_PCI_bridge:
1473 		{
1474 			// disable PCI device address decoding (io and memory) while BARs
1475 			// are modified
1476 			uint16 pcicmd = ReadConfig(dev->domain, dev->bus, dev->device,
1477 				dev->function, PCI_command, 2);
1478 			WriteConfig(dev->domain, dev->bus, dev->device, dev->function,
1479 				PCI_command, 2,
1480 				pcicmd & ~(PCI_command_io | PCI_command_memory));
1481 
1482 			_GetRomBarInfo(dev, PCI_bridge_rom_base,
1483 				dev->info.u.h1.rom_base_pci);
1484 			for (int i = 0; i < 2;) {
1485 				i += _GetBarInfo(dev, PCI_base_registers + 4 * i,
1486 					dev->info.u.h1.base_registers[i],
1487 					dev->info.u.h1.base_registers_pci[i],
1488 					dev->info.u.h1.base_register_sizes[i],
1489 					dev->info.u.h1.base_register_flags[i],
1490 					i < 1 ? &dev->info.u.h1.base_registers[i + 1] : NULL,
1491 					i < 1 ? &dev->info.u.h1.base_registers_pci[i + 1] : NULL,
1492 					i < 1 ? &dev->info.u.h1.base_register_sizes[i + 1] : NULL);
1493 			}
1494 
1495 			// restore PCI device address decoding
1496 			WriteConfig(dev->domain, dev->bus, dev->device, dev->function,
1497 				PCI_command, 2, pcicmd);
1498 
1499 			dev->info.u.h1.rom_base = (uint32)pci_ram_address(
1500 				dev->info.u.h1.rom_base_pci);
1501 
1502 			dev->info.u.h1.primary_bus = ReadConfig(dev->domain, dev->bus,
1503 				dev->device, dev->function, PCI_primary_bus, 1);
1504 			dev->info.u.h1.secondary_bus = ReadConfig(dev->domain, dev->bus,
1505 				dev->device, dev->function, PCI_secondary_bus, 1);
1506 			dev->info.u.h1.subordinate_bus = ReadConfig(dev->domain,
1507 				dev->bus, dev->device, dev->function, PCI_subordinate_bus, 1);
1508 			dev->info.u.h1.secondary_latency = ReadConfig(dev->domain,
1509 				dev->bus, dev->device, dev->function, PCI_secondary_latency, 1);
1510 			dev->info.u.h1.io_base = ReadConfig(dev->domain, dev->bus,
1511 				dev->device, dev->function, PCI_io_base, 1);
1512 			dev->info.u.h1.io_limit = ReadConfig(dev->domain, dev->bus,
1513 				dev->device, dev->function, PCI_io_limit, 1);
1514 			dev->info.u.h1.secondary_status = ReadConfig(dev->domain,
1515 				dev->bus, dev->device, dev->function, PCI_secondary_status, 2);
1516 			dev->info.u.h1.memory_base = ReadConfig(dev->domain, dev->bus,
1517 				dev->device, dev->function, PCI_memory_base, 2);
1518 			dev->info.u.h1.memory_limit = ReadConfig(dev->domain, dev->bus,
1519 				dev->device, dev->function, PCI_memory_limit, 2);
1520 			dev->info.u.h1.prefetchable_memory_base = ReadConfig(dev->domain,
1521 				dev->bus, dev->device, dev->function,
1522 				PCI_prefetchable_memory_base, 2);
1523 			dev->info.u.h1.prefetchable_memory_limit = ReadConfig(
1524 				dev->domain, dev->bus, dev->device, dev->function,
1525 				PCI_prefetchable_memory_limit, 2);
1526 			dev->info.u.h1.prefetchable_memory_base_upper32 = ReadConfig(
1527 				dev->domain, dev->bus, dev->device, dev->function,
1528 				PCI_prefetchable_memory_base_upper32, 4);
1529 			dev->info.u.h1.prefetchable_memory_limit_upper32 = ReadConfig(
1530 				dev->domain, dev->bus, dev->device, dev->function,
1531 				PCI_prefetchable_memory_limit_upper32, 4);
1532 			dev->info.u.h1.io_base_upper16 = ReadConfig(dev->domain,
1533 				dev->bus, dev->device, dev->function, PCI_io_base_upper16, 2);
1534 			dev->info.u.h1.io_limit_upper16 = ReadConfig(dev->domain,
1535 				dev->bus, dev->device, dev->function, PCI_io_limit_upper16, 2);
1536 			dev->info.u.h1.interrupt_line = ReadConfig(dev->domain, dev->bus,
1537 				dev->device, dev->function, PCI_interrupt_line, 1);
1538 			dev->info.u.h1.interrupt_pin = ReadConfig(dev->domain, dev->bus,
1539 				dev->device, dev->function, PCI_interrupt_pin, 1);
1540 			dev->info.u.h1.bridge_control = ReadConfig(dev->domain, dev->bus,
1541 				dev->device, dev->function, PCI_bridge_control, 2);
1542 			dev->info.u.h1.subsystem_id = ReadConfig(dev->domain, dev->bus,
1543 				dev->device, dev->function, PCI_sub_device_id_1, 2);
1544 			dev->info.u.h1.subsystem_vendor_id = ReadConfig(dev->domain,
1545 				dev->bus, dev->device, dev->function, PCI_sub_vendor_id_1, 2);
1546 			break;
1547 		}
1548 
1549 		case PCI_header_type_cardbus:
1550 		{
1551 			// for testing only, not final:
1552 			dev->info.u.h2.subsystem_id = ReadConfig(dev->domain, dev->bus,
1553 				dev->device, dev->function, PCI_sub_device_id_2, 2);
1554 			dev->info.u.h2.subsystem_vendor_id = ReadConfig(dev->domain,
1555 				dev->bus, dev->device, dev->function, PCI_sub_vendor_id_2, 2);
1556 			dev->info.u.h2.primary_bus = ReadConfig(dev->domain, dev->bus,
1557 				dev->device, dev->function, PCI_primary_bus_2, 1);
1558 			dev->info.u.h2.secondary_bus = ReadConfig(dev->domain, dev->bus,
1559 				dev->device, dev->function, PCI_secondary_bus_2, 1);
1560 			dev->info.u.h2.subordinate_bus = ReadConfig(dev->domain,
1561 				dev->bus, dev->device, dev->function, PCI_subordinate_bus_2, 1);
1562 			dev->info.u.h2.secondary_latency = ReadConfig(dev->domain,
1563 				dev->bus, dev->device, dev->function, PCI_secondary_latency_2, 1);
1564 			dev->info.u.h2.reserved = 0;
1565 			dev->info.u.h2.memory_base = ReadConfig(dev->domain, dev->bus,
1566 				dev->device, dev->function, PCI_memory_base0_2, 4);
1567 			dev->info.u.h2.memory_limit = ReadConfig(dev->domain, dev->bus,
1568 				dev->device, dev->function, PCI_memory_limit0_2, 4);
1569 			dev->info.u.h2.memory_base_upper32 = ReadConfig(dev->domain,
1570 				dev->bus, dev->device, dev->function, PCI_memory_base1_2, 4);
1571 			dev->info.u.h2.memory_limit_upper32 = ReadConfig(dev->domain,
1572 				dev->bus, dev->device, dev->function, PCI_memory_limit1_2, 4);
1573 			dev->info.u.h2.io_base = ReadConfig(dev->domain, dev->bus,
1574 				dev->device, dev->function, PCI_io_base0_2, 4);
1575 			dev->info.u.h2.io_limit = ReadConfig(dev->domain, dev->bus,
1576 				dev->device, dev->function, PCI_io_limit0_2, 4);
1577 			dev->info.u.h2.io_base_upper32 = ReadConfig(dev->domain,
1578 				dev->bus, dev->device, dev->function, PCI_io_base1_2, 4);
1579 			dev->info.u.h2.io_limit_upper32 = ReadConfig(dev->domain,
1580 				dev->bus, dev->device, dev->function, PCI_io_limit1_2, 4);
1581 			dev->info.u.h2.secondary_status = ReadConfig(dev->domain,
1582 				dev->bus, dev->device, dev->function, PCI_secondary_status_2, 2);
1583 			dev->info.u.h2.bridge_control = ReadConfig(dev->domain,
1584 				dev->bus, dev->device, dev->function, PCI_bridge_control_2, 2);
1585 			break;
1586 		}
1587 
1588 		default:
1589 			TRACE(("PCI: Header type unknown (0x%02x)\n", dev->info.header_type));
1590 			break;
1591 	}
1592 }
1593 
1594 
1595 void
1596 PCI::RefreshDeviceInfo()
1597 {
1598 	if (fRootBus == NULL)
1599 		return;
1600 
1601 	_RefreshDeviceInfo(fRootBus);
1602 }
1603 
1604 
1605 void
1606 PCI::_RefreshDeviceInfo(PCIBus *bus)
1607 {
1608 	for (PCIDev *dev = bus->child; dev; dev = dev->next) {
1609 		_ReadBasicInfo(dev);
1610 		_ReadHeaderInfo(dev);
1611 		_ReadMSIInfo(dev);
1612 		_ReadMSIXInfo(dev);
1613 		_ReadHtMappingInfo(dev);
1614 		if (dev->child)
1615 			_RefreshDeviceInfo(dev->child);
1616 	}
1617 
1618 	if (bus->next)
1619 		_RefreshDeviceInfo(bus->next);
1620 }
1621 
1622 
1623 status_t
1624 PCI::ReadConfig(uint8 domain, uint8 bus, uint8 device, uint8 function,
1625 	uint16 offset, uint8 size, uint32 *value)
1626 {
1627 	domain_data *info = _GetDomainData(domain);
1628 	if (!info)
1629 		return B_ERROR;
1630 
1631 	if (device > (info->max_bus_devices - 1)
1632 		|| function > 7
1633 		|| (size != 1 && size != 2 && size != 4)
1634 		|| (size == 2 && (offset & 3) == 3)
1635 		|| (size == 4 && (offset & 3) != 0)) {
1636 		dprintf("PCI: can't read config for domain %d, bus %u, device %u, function %u, offset %u, size %u\n",
1637 			 domain, bus, device, function, offset, size);
1638 		return B_ERROR;
1639 	}
1640 
1641 	return (*info->controller->read_pci_config)(info->controller_cookie, bus,
1642 		device, function, offset, size, value);
1643 }
1644 
1645 
1646 uint32
1647 PCI::ReadConfig(uint8 domain, uint8 bus, uint8 device, uint8 function,
1648 	uint16 offset, uint8 size)
1649 {
1650 	uint32 value;
1651 	if (ReadConfig(domain, bus, device, function, offset, size, &value)
1652 			!= B_OK)
1653 		return 0xffffffff;
1654 
1655 	return value;
1656 }
1657 
1658 
1659 uint32
1660 PCI::ReadConfig(PCIDev *device, uint16 offset, uint8 size)
1661 {
1662 	uint32 value;
1663 	if (ReadConfig(device->domain, device->bus, device->device,
1664 			device->function, offset, size, &value) != B_OK)
1665 		return 0xffffffff;
1666 
1667 	return value;
1668 }
1669 
1670 
1671 status_t
1672 PCI::WriteConfig(uint8 domain, uint8 bus, uint8 device, uint8 function,
1673 	uint16 offset, uint8 size, uint32 value)
1674 {
1675 	domain_data *info = _GetDomainData(domain);
1676 	if (!info)
1677 		return B_ERROR;
1678 
1679 	if (device > (info->max_bus_devices - 1)
1680 		|| function > 7
1681 		|| (size != 1 && size != 2 && size != 4)
1682 		|| (size == 2 && (offset & 3) == 3)
1683 		|| (size == 4 && (offset & 3) != 0)) {
1684 		dprintf("PCI: can't write config for domain %d, bus %u, device %u, function %u, offset %u, size %u\n",
1685 			 domain, bus, device, function, offset, size);
1686 		return B_ERROR;
1687 	}
1688 
1689 	return (*info->controller->write_pci_config)(info->controller_cookie, bus,
1690 		device, function, offset, size, value);
1691 }
1692 
1693 
1694 status_t
1695 PCI::WriteConfig(PCIDev *device, uint16 offset, uint8 size, uint32 value)
1696 {
1697 	return WriteConfig(device->domain, device->bus, device->device,
1698 		device->function, offset, size, value);
1699 }
1700 
1701 
1702 status_t
1703 PCI::FindCapability(uint8 domain, uint8 bus, uint8 device, uint8 function,
1704 	uint8 capID, uint8 *offset)
1705 {
1706 	uint16 status = ReadConfig(domain, bus, device, function, PCI_status, 2);
1707 	if (!(status & PCI_status_capabilities)) {
1708 		FLOW("PCI: find_pci_capability ERROR %u:%u:%u capability %#02x "
1709 			"not supported\n", bus, device, function, capID);
1710 		return B_ERROR;
1711 	}
1712 
1713 	uint8 headerType = ReadConfig(domain, bus, device, function,
1714 		PCI_header_type, 1);
1715 	uint8 capPointer;
1716 
1717 	switch (headerType & PCI_header_type_mask) {
1718 		case PCI_header_type_generic:
1719 		case PCI_header_type_PCI_to_PCI_bridge:
1720 			capPointer = PCI_capabilities_ptr;
1721 			break;
1722 		case PCI_header_type_cardbus:
1723 			capPointer = PCI_capabilities_ptr_2;
1724 			break;
1725 		default:
1726 			TRACE_CAP("PCI: find_pci_capability ERROR %u:%u:%u capability "
1727 				"%#02x unknown header type\n", bus, device, function, capID);
1728 			return B_ERROR;
1729 	}
1730 
1731 	capPointer = ReadConfig(domain, bus, device, function, capPointer, 1);
1732 	capPointer &= ~3;
1733 	if (capPointer == 0) {
1734 		TRACE_CAP("PCI: find_pci_capability ERROR %u:%u:%u capability %#02x "
1735 			"empty list\n", bus, device, function, capID);
1736 		return B_NAME_NOT_FOUND;
1737 	}
1738 
1739 	for (int i = 0; i < 48; i++) {
1740 		if (ReadConfig(domain, bus, device, function, capPointer, 1) == capID) {
1741 			if (offset != NULL)
1742 				*offset = capPointer;
1743 			return B_OK;
1744 		}
1745 
1746 		capPointer = ReadConfig(domain, bus, device, function, capPointer + 1,
1747 			1);
1748 		capPointer &= ~3;
1749 
1750 		if (capPointer == 0)
1751 			return B_NAME_NOT_FOUND;
1752 	}
1753 
1754 	TRACE_CAP("PCI: find_pci_capability ERROR %u:%u:%u capability %#02x circular list\n", bus, device, function, capID);
1755 	return B_ERROR;
1756 }
1757 
1758 
1759 status_t
1760 PCI::FindCapability(PCIDev *device, uint8 capID, uint8 *offset)
1761 {
1762 	return FindCapability(device->domain, device->bus, device->device,
1763 		device->function, capID, offset);
1764 }
1765 
1766 
1767 status_t
1768 PCI::FindExtendedCapability(uint8 domain, uint8 bus, uint8 device,
1769 	uint8 function, uint16 capID, uint16 *offset)
1770 {
1771 	if (FindCapability(domain, bus, device, function, PCI_cap_id_pcie)
1772 		!= B_OK) {
1773 		FLOW("PCI:FindExtendedCapability ERROR %u:%u:%u capability %#02x "
1774 			"not supported\n", bus, device, function, capID);
1775 		return B_ERROR;
1776 	}
1777 	uint16 capPointer = PCI_extended_capability;
1778 	uint32 capability = ReadConfig(domain, bus, device, function,
1779 		capPointer, 4);
1780 
1781 	if (capability == 0 || capability == 0xffffffff)
1782 			return B_NAME_NOT_FOUND;
1783 
1784 	for (int i = 0; i < 48; i++) {
1785 		if (PCI_extcap_id(capability) == capID) {
1786 			if (offset != NULL)
1787 				*offset = capPointer;
1788 			return B_OK;
1789 		}
1790 
1791 		capPointer = PCI_extcap_next_ptr(capability) & ~3;
1792 		if (capPointer < PCI_extended_capability)
1793 			return B_NAME_NOT_FOUND;
1794 		capability = ReadConfig(domain, bus, device, function,
1795 			capPointer, 4);
1796 	}
1797 
1798 	TRACE_CAP("PCI:FindExtendedCapability ERROR %u:%u:%u capability %#04x "
1799 		"circular list\n", bus, device, function, capID);
1800 	return B_ERROR;
1801 }
1802 
1803 
1804 status_t
1805 PCI::FindExtendedCapability(PCIDev *device, uint16 capID, uint16 *offset)
1806 {
1807 	return FindExtendedCapability(device->domain, device->bus, device->device,
1808 		device->function, capID, offset);
1809 }
1810 
1811 
1812 status_t
1813 PCI::FindHTCapability(uint8 domain, uint8 bus, uint8 device,
1814 	uint8 function, uint16 capID, uint8 *offset)
1815 {
1816 	uint8 capPointer;
1817 	// consider the passed offset as the current ht capability block pointer
1818 	// when it's non zero
1819 	if (offset != NULL && *offset != 0) {
1820 		capPointer = ReadConfig(domain, bus, device, function, *offset + 1,
1821 			1);
1822 	} else if (FindCapability(domain, bus, device, function, PCI_cap_id_ht,
1823 		&capPointer) != B_OK) {
1824 		FLOW("PCI:FindHTCapability ERROR %u:%u:%u capability %#02x "
1825 			"not supported\n", bus, device, function, capID);
1826 		return B_NAME_NOT_FOUND;
1827 	}
1828 
1829 	uint16 mask = PCI_ht_command_cap_mask_5_bits;
1830 	if (capID == PCI_ht_command_cap_slave || capID == PCI_ht_command_cap_host)
1831 		mask = PCI_ht_command_cap_mask_3_bits;
1832 	for (int i = 0; i < 48; i++) {
1833 		capPointer &= ~3;
1834 		if (capPointer == 0)
1835 			return B_NAME_NOT_FOUND;
1836 
1837 		uint8 capability = ReadConfig(domain, bus, device, function,
1838 			capPointer, 1);
1839 		if (capability == PCI_cap_id_ht) {
1840 			if ((ReadConfig(domain, bus, device, function,
1841 					capPointer + PCI_ht_command, 2) & mask) == capID) {
1842 				if (offset != NULL)
1843 					*offset = capPointer;
1844 				return B_OK;
1845 			}
1846 		}
1847 
1848 		capPointer = ReadConfig(domain, bus, device, function, capPointer + 1,
1849 			1);
1850 	}
1851 
1852 	TRACE_CAP("PCI:FindHTCapability ERROR %u:%u:%u capability %#04x "
1853 		"circular list\n", bus, device, function, capID);
1854 	return B_ERROR;
1855 }
1856 
1857 
1858 status_t
1859 PCI::FindHTCapability(PCIDev *device, uint16 capID, uint8 *offset)
1860 {
1861 	return FindHTCapability(device->domain, device->bus, device->device,
1862 		device->function, capID, offset);
1863 }
1864 
1865 
1866 PCIDev *
1867 PCI::FindDevice(uint8 domain, uint8 bus, uint8 device, uint8 function)
1868 {
1869 	return _FindDevice(fRootBus, domain, bus, device, function);
1870 }
1871 
1872 
1873 PCIDev *
1874 PCI::_FindDevice(PCIBus *current, uint8 domain, uint8 bus, uint8 device,
1875 	uint8 function)
1876 {
1877 	if (current->domain == domain) {
1878 		// search device on this bus
1879 
1880 		for (PCIDev *child = current->child; child != NULL;
1881 				child = child->next) {
1882 			if (child->bus == bus && child->device == device
1883 				&& child->function == function)
1884 				return child;
1885 
1886 			if (child->child != NULL) {
1887 				// search child busses
1888 				PCIDev *found = _FindDevice(child->child, domain, bus, device,
1889 					function);
1890 				if (found != NULL)
1891 					return found;
1892 			}
1893 		}
1894 	}
1895 
1896 	// search other busses
1897 	if (current->next != NULL)
1898 		return _FindDevice(current->next, domain, bus, device, function);
1899 
1900 	return NULL;
1901 }
1902 
1903 
1904 status_t
1905 PCI::UpdateInterruptLine(uint8 domain, uint8 bus, uint8 _device, uint8 function,
1906 	uint8 newInterruptLineValue)
1907 {
1908 	PCIDev *device = FindDevice(domain, bus, _device, function);
1909 	if (device == NULL)
1910 		return B_ERROR;
1911 
1912 	pci_info &info = device->info;
1913 	switch (info.header_type & PCI_header_type_mask) {
1914 		case PCI_header_type_generic:
1915 			info.u.h0.interrupt_line = newInterruptLineValue;
1916 			break;
1917 
1918 		case PCI_header_type_PCI_to_PCI_bridge:
1919 			info.u.h1.interrupt_line = newInterruptLineValue;
1920 			break;
1921 
1922 		default:
1923 			return B_ERROR;
1924 	}
1925 
1926 	return WriteConfig(device, PCI_interrupt_line, 1, newInterruptLineValue);
1927 }
1928 
1929 
1930 uint8
1931 PCI::GetPowerstate(PCIDev *device)
1932 {
1933 	uint8 capabilityOffset;
1934 	status_t res = FindCapability(device, PCI_cap_id_pm, &capabilityOffset);
1935 	if (res == B_OK) {
1936 		uint32 state = ReadConfig(device, capabilityOffset + PCI_pm_status, 2);
1937 		return (state & PCI_pm_mask);
1938 	}
1939 	return PCI_pm_state_d0;
1940 }
1941 
1942 
1943 void
1944 PCI::SetPowerstate(PCIDev *device, uint8 newState)
1945 {
1946 	uint8 capabilityOffset;
1947 	status_t res = FindCapability(device, PCI_cap_id_pm, &capabilityOffset);
1948 	if (res == B_OK) {
1949 		uint32 state = ReadConfig(device, capabilityOffset + PCI_pm_status, 2);
1950 		if ((state & PCI_pm_mask) != newState) {
1951 			WriteConfig(device, capabilityOffset + PCI_pm_status, 2,
1952 				(state & ~PCI_pm_mask) | newState);
1953 			if ((state & PCI_pm_mask) == PCI_pm_state_d3)
1954 				snooze(10);
1955 		}
1956 	}
1957 }
1958 
1959 
1960 status_t
1961 PCI::GetPowerstate(uint8 domain, uint8 bus, uint8 _device, uint8 function,
1962 	uint8* state)
1963 {
1964 	PCIDev *device = FindDevice(domain, bus, _device, function);
1965 	if (device == NULL)
1966 		return B_ERROR;
1967 
1968 	*state = GetPowerstate(device);
1969 	return B_OK;
1970 }
1971 
1972 
1973 status_t
1974 PCI::SetPowerstate(uint8 domain, uint8 bus, uint8 _device, uint8 function,
1975 	uint8 newState)
1976 {
1977 	PCIDev *device = FindDevice(domain, bus, _device, function);
1978 	if (device == NULL)
1979 		return B_ERROR;
1980 
1981 	SetPowerstate(device, newState);
1982 	return B_OK;
1983 }
1984 
1985 
1986 //#pragma mark - MSI
1987 
1988 uint8
1989 PCI::GetMSICount(PCIDev *device)
1990 {
1991 	if (!msi_supported())
1992 		return 0;
1993 
1994 	msi_info *info = &device->msi;
1995 	if (!info->msi_capable)
1996 		return 0;
1997 
1998 	return info->message_count;
1999 }
2000 
2001 
2002 status_t
2003 PCI::ConfigureMSI(PCIDev *device, uint8 count, uint8 *startVector)
2004 {
2005 	if (!msi_supported())
2006 		return B_UNSUPPORTED;
2007 
2008 	if (count == 0 || startVector == NULL)
2009 		return B_BAD_VALUE;
2010 
2011 	msi_info *info = &device->msi;
2012 	if (!info->msi_capable)
2013 		return B_UNSUPPORTED;
2014 
2015 	if (count > 32 || count > info->message_count
2016 		|| ((count - 1) & count) != 0 /* needs to be a power of 2 */) {
2017 		return B_BAD_VALUE;
2018 	}
2019 
2020 	if (info->configured_count != 0)
2021 		return B_BUSY;
2022 
2023 	status_t result = msi_allocate_vectors(count, &info->start_vector,
2024 		&info->address_value, &info->data_value);
2025 	if (result != B_OK)
2026 		return result;
2027 
2028 	uint8 offset = info->capability_offset;
2029 	WriteConfig(device, offset + PCI_msi_address, 4,
2030 		info->address_value & 0xffffffff);
2031 	if (info->control_value & PCI_msi_control_64bit) {
2032 		WriteConfig(device, offset + PCI_msi_address_high, 4,
2033 			info->address_value >> 32);
2034 		WriteConfig(device, offset + PCI_msi_data_64bit, 2,
2035 			info->data_value);
2036 	} else
2037 		WriteConfig(device, offset + PCI_msi_data, 2, info->data_value);
2038 
2039 	info->control_value &= ~PCI_msi_control_mme_mask;
2040 	info->control_value |= (ffs(count) - 1) << 4;
2041 	WriteConfig(device, offset + PCI_msi_control, 2, info->control_value);
2042 
2043 	info->configured_count = count;
2044 	*startVector = info->start_vector;
2045 	return B_OK;
2046 }
2047 
2048 
2049 status_t
2050 PCI::UnconfigureMSI(PCIDev *device)
2051 {
2052 	if (!msi_supported())
2053 		return B_UNSUPPORTED;
2054 
2055 	// try MSI-X
2056 	status_t result = _UnconfigureMSIX(device);
2057 	if (result != B_UNSUPPORTED && result != B_NO_INIT)
2058 		return result;
2059 
2060 	msi_info *info =  &device->msi;
2061 	if (!info->msi_capable)
2062 		return B_UNSUPPORTED;
2063 
2064 	if (info->configured_count == 0)
2065 		return B_NO_INIT;
2066 
2067 	msi_free_vectors(info->configured_count, info->start_vector);
2068 
2069 	info->control_value &= ~PCI_msi_control_mme_mask;
2070 	WriteConfig(device, info->capability_offset + PCI_msi_control, 2,
2071 		info->control_value);
2072 
2073 	info->configured_count = 0;
2074 	info->address_value = 0;
2075 	info->data_value = 0;
2076 	return B_OK;
2077 }
2078 
2079 
2080 status_t
2081 PCI::EnableMSI(PCIDev *device)
2082 {
2083 	if (!msi_supported())
2084 		return B_UNSUPPORTED;
2085 
2086 	msi_info *info =  &device->msi;
2087 	if (!info->msi_capable)
2088 		return B_UNSUPPORTED;
2089 
2090 	if (info->configured_count == 0)
2091 		return B_NO_INIT;
2092 
2093 	// ensure the pinned interrupt is disabled
2094 	WriteConfig(device, PCI_command, 2,
2095 		ReadConfig(device, PCI_command, 2) | PCI_command_int_disable);
2096 
2097 	// enable msi generation
2098 	info->control_value |= PCI_msi_control_enable;
2099 	WriteConfig(device, info->capability_offset + PCI_msi_control, 2,
2100 		info->control_value);
2101 
2102 	// enable HT msi mapping (if applicable)
2103 	_HtMSIMap(device, info->address_value);
2104 
2105 	dprintf("msi enabled: 0x%04" B_PRIx32 "\n",
2106 		ReadConfig(device, info->capability_offset + PCI_msi_control, 2));
2107 	return B_OK;
2108 }
2109 
2110 
2111 status_t
2112 PCI::DisableMSI(PCIDev *device)
2113 {
2114 	if (!msi_supported())
2115 		return B_UNSUPPORTED;
2116 
2117 	// try MSI-X
2118 	status_t result = _DisableMSIX(device);
2119 	if (result != B_UNSUPPORTED && result != B_NO_INIT)
2120 		return result;
2121 
2122 	msi_info *info =  &device->msi;
2123 	if (!info->msi_capable)
2124 		return B_UNSUPPORTED;
2125 
2126 	if (info->configured_count == 0)
2127 		return B_NO_INIT;
2128 
2129 	// disable HT msi mapping (if applicable)
2130 	_HtMSIMap(device, 0);
2131 
2132 	// disable msi generation
2133 	info->control_value &= ~PCI_msi_control_enable;
2134 	WriteConfig(device, info->capability_offset + PCI_msi_control, 2,
2135 		info->control_value);
2136 
2137 	return B_OK;
2138 }
2139 
2140 
2141 uint8
2142 PCI::GetMSIXCount(PCIDev *device)
2143 {
2144 	if (!msi_supported())
2145 		return 0;
2146 
2147 	msix_info *info = &device->msix;
2148 	if (!info->msix_capable)
2149 		return 0;
2150 
2151 	return info->message_count;
2152 }
2153 
2154 
2155 status_t
2156 PCI::ConfigureMSIX(PCIDev *device, uint8 count, uint8 *startVector)
2157 {
2158 	if (!msi_supported())
2159 		return B_UNSUPPORTED;
2160 
2161 	if (count == 0 || startVector == NULL)
2162 		return B_BAD_VALUE;
2163 
2164 	msix_info *info = &device->msix;
2165 	if (!info->msix_capable)
2166 		return B_UNSUPPORTED;
2167 
2168 	if (count > 32 || count > info->message_count) {
2169 		return B_BAD_VALUE;
2170 	}
2171 
2172 	if (info->configured_count != 0)
2173 		return B_BUSY;
2174 
2175 	// map the table bar
2176 	size_t tableSize = info->message_count * 16;
2177 	addr_t address;
2178 	phys_addr_t barAddr = device->info.u.h0.base_registers[info->table_bar];
2179 	uchar flags = device->info.u.h0.base_register_flags[info->table_bar];
2180 	if ((flags & PCI_address_type) == PCI_address_type_64) {
2181 		barAddr |= (uint64)device->info.u.h0.base_registers[
2182 			info->table_bar + 1] << 32;
2183 	}
2184 	area_id area = map_physical_memory("msi table map",
2185 		barAddr, tableSize + info->table_offset,
2186 		B_ANY_KERNEL_ADDRESS, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA,
2187 		(void**)&address);
2188 	if (area < 0)
2189 		return area;
2190 	info->table_area_id = area;
2191 	info->table_address = address + info->table_offset;
2192 
2193 	// and the pba bar if necessary
2194 	if (info->table_bar != info->pba_bar) {
2195 		barAddr = device->info.u.h0.base_registers[info->pba_bar];
2196 		flags = device->info.u.h0.base_register_flags[info->pba_bar];
2197 		if ((flags & PCI_address_type) == PCI_address_type_64) {
2198 			barAddr |= (uint64)device->info.u.h0.base_registers[
2199 				info->pba_bar + 1] << 32;
2200 		}
2201 		area = map_physical_memory("msi pba map",
2202 			barAddr, tableSize + info->pba_offset,
2203 			B_ANY_KERNEL_ADDRESS, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA,
2204 			(void**)&address);
2205 		if (area < 0) {
2206 			delete_area(info->table_area_id);
2207 			info->table_area_id = -1;
2208 			return area;
2209 		}
2210 		info->pba_area_id = area;
2211 	} else
2212 		info->pba_area_id = -1;
2213 	info->pba_address = address + info->pba_offset;
2214 
2215 	status_t result = msi_allocate_vectors(count, &info->start_vector,
2216 		&info->address_value, &info->data_value);
2217 	if (result != B_OK) {
2218 		delete_area(info->pba_area_id);
2219 		delete_area(info->table_area_id);
2220 		info->pba_area_id = -1;
2221 		info->table_area_id = -1;
2222 		return result;
2223 	}
2224 
2225 	// ensure the memory i/o is enabled
2226 	WriteConfig(device, PCI_command, 2,
2227 		ReadConfig(device, PCI_command, 2) | PCI_command_memory);
2228 
2229 	uint32 data_value = info->data_value;
2230 	for (uint32 index = 0; index < count; index++) {
2231 		volatile uint32 *entry = (uint32*)(info->table_address + 16 * index);
2232 		*(entry + 3) |= PCI_msix_vctrl_mask;
2233 		*entry++ = info->address_value & 0xffffffff;
2234 		*entry++ = info->address_value >> 32;
2235 		*entry++ = data_value++;
2236 		*entry &= ~PCI_msix_vctrl_mask;
2237 	}
2238 
2239 	info->configured_count = count;
2240 	*startVector = info->start_vector;
2241 	dprintf("msix configured for %d vectors\n", count);
2242 	return B_OK;
2243 }
2244 
2245 
2246 status_t
2247 PCI::EnableMSIX(PCIDev *device)
2248 {
2249 	if (!msi_supported())
2250 		return B_UNSUPPORTED;
2251 
2252 	msix_info *info = &device->msix;
2253 	if (!info->msix_capable)
2254 		return B_UNSUPPORTED;
2255 
2256 	if (info->configured_count == 0)
2257 		return B_NO_INIT;
2258 
2259 	// ensure the pinned interrupt is disabled
2260 	WriteConfig(device, PCI_command, 2,
2261 		ReadConfig(device, PCI_command, 2) | PCI_command_int_disable);
2262 
2263 	// enable msi-x generation
2264 	info->control_value |= PCI_msix_control_enable;
2265 	WriteConfig(device, info->capability_offset + PCI_msix_control, 2,
2266 		info->control_value);
2267 
2268 	// enable HT msi mapping (if applicable)
2269 	_HtMSIMap(device, info->address_value);
2270 
2271 	dprintf("msi-x enabled: 0x%04" B_PRIx32 "\n",
2272 		ReadConfig(device, info->capability_offset + PCI_msix_control, 2));
2273 	return B_OK;
2274 }
2275 
2276 
2277 void
2278 PCI::_HtMSIMap(PCIDev *device, uint64 address)
2279 {
2280 	ht_mapping_info *info = &device->ht_mapping;
2281 	if (!info->ht_mapping_capable)
2282 		return;
2283 
2284 	bool enabled = (info->control_value & PCI_ht_command_msi_enable) != 0;
2285 	if ((address != 0) != enabled) {
2286 		if (enabled) {
2287 			info->control_value &= ~PCI_ht_command_msi_enable;
2288 		} else {
2289 			if ((address >> 20) != (info->address_value >> 20))
2290 				return;
2291 			dprintf("ht msi mapping enabled\n");
2292 			info->control_value |= PCI_ht_command_msi_enable;
2293 		}
2294 		WriteConfig(device, info->capability_offset + PCI_ht_command, 2,
2295 			info->control_value);
2296 	}
2297 }
2298 
2299 
2300 void
2301 PCI::_ReadMSIInfo(PCIDev *device)
2302 {
2303 	if (!msi_supported())
2304 		return;
2305 
2306 	msi_info *info = &device->msi;
2307 	info->msi_capable = false;
2308 	status_t result = FindCapability(device->domain, device->bus,
2309 		device->device, device->function, PCI_cap_id_msi,
2310 		&info->capability_offset);
2311 	if (result != B_OK)
2312 		return;
2313 
2314 	info->msi_capable = true;
2315 	info->control_value = ReadConfig(device->domain, device->bus,
2316 		device->device, device->function,
2317 		info->capability_offset + PCI_msi_control, 2);
2318 	info->message_count
2319 		= 1 << ((info->control_value & PCI_msi_control_mmc_mask) >> 1);
2320 	info->configured_count = 0;
2321 	info->data_value = 0;
2322 	info->address_value = 0;
2323 }
2324 
2325 
2326 void
2327 PCI::_ReadMSIXInfo(PCIDev *device)
2328 {
2329 	if (!msi_supported())
2330 		return;
2331 
2332 	msix_info *info = &device->msix;
2333 	info->msix_capable = false;
2334 	status_t result = FindCapability(device->domain, device->bus,
2335 		device->device, device->function, PCI_cap_id_msix,
2336 		&info->capability_offset);
2337 	if (result != B_OK)
2338 		return;
2339 
2340 	info->msix_capable = true;
2341 	info->control_value = ReadConfig(device->domain, device->bus,
2342 		device->device, device->function,
2343 		info->capability_offset + PCI_msix_control, 2);
2344 	info->message_count
2345 		= (info->control_value & PCI_msix_control_table_size) + 1;
2346 	info->configured_count = 0;
2347 	info->data_value = 0;
2348 	info->address_value = 0;
2349 	info->table_area_id = -1;
2350 	info->pba_area_id = -1;
2351 	uint32 table_value = ReadConfig(device->domain, device->bus,
2352 		device->device, device->function,
2353 		info->capability_offset + PCI_msix_table, 4);
2354 	uint32 pba_value = ReadConfig(device->domain, device->bus,
2355 		device->device, device->function,
2356 		info->capability_offset + PCI_msix_pba, 4);
2357 
2358 	info->table_bar = table_value & PCI_msix_bir_mask;
2359 	info->table_offset = table_value & PCI_msix_offset_mask;
2360 	info->pba_bar = pba_value & PCI_msix_bir_mask;
2361 	info->pba_offset = pba_value & PCI_msix_offset_mask;
2362 }
2363 
2364 
2365 void
2366 PCI::_ReadHtMappingInfo(PCIDev *device)
2367 {
2368 	if (!msi_supported())
2369 		return;
2370 
2371 	ht_mapping_info *info = &device->ht_mapping;
2372 	info->ht_mapping_capable = false;
2373 
2374 	uint8 offset = 0;
2375 	if (FindHTCapability(device, PCI_ht_command_cap_msi_mapping,
2376 		&offset) == B_OK) {
2377 		info->control_value = ReadConfig(device, offset + PCI_ht_command,
2378 			2);
2379 		info->capability_offset = offset;
2380 		info->ht_mapping_capable = true;
2381 		if ((info->control_value & PCI_ht_command_msi_fixed) != 0) {
2382 #if defined(__i386__) || defined(__x86_64__)
2383 			info->address_value = MSI_ADDRESS_BASE;
2384 #else
2385 			// TODO: investigate what should be set here for non-x86
2386 			dprintf("PCI_ht_command_msi_fixed flag unimplemented\n");
2387 			info->address_value = 0;
2388 #endif
2389 		} else {
2390 			info->address_value = ReadConfig(device, offset
2391 				+ PCI_ht_msi_address_high, 4);
2392 			info->address_value <<= 32;
2393 			info->address_value |= ReadConfig(device, offset
2394 				+ PCI_ht_msi_address_low, 4);
2395 		}
2396 		dprintf("found an ht msi mapping at %#" B_PRIx64 "\n",
2397 			info->address_value);
2398 	}
2399 }
2400 
2401 
2402 status_t
2403 PCI::_UnconfigureMSIX(PCIDev *device)
2404 {
2405 	msix_info *info =  &device->msix;
2406 	if (!info->msix_capable)
2407 		return B_UNSUPPORTED;
2408 
2409 	if (info->configured_count == 0)
2410 		return B_NO_INIT;
2411 
2412 	// disable msi-x generation
2413 	info->control_value &= ~PCI_msix_control_enable;
2414 	WriteConfig(device, info->capability_offset + PCI_msix_control, 2,
2415 		info->control_value);
2416 
2417 	msi_free_vectors(info->configured_count, info->start_vector);
2418 	for (uint8 index = 0; index < info->configured_count; index++) {
2419 		volatile uint32 *entry = (uint32*)(info->table_address + 16 * index);
2420 		if ((*(entry + 3) & PCI_msix_vctrl_mask) == 0)
2421 			*(entry + 3) |= PCI_msix_vctrl_mask;
2422 	}
2423 
2424 	if (info->pba_area_id != -1)
2425 		delete_area(info->pba_area_id);
2426 	if (info->table_area_id != -1)
2427 		delete_area(info->table_area_id);
2428 	info->pba_area_id= -1;
2429 	info->table_area_id = -1;
2430 
2431 	info->configured_count = 0;
2432 	info->address_value = 0;
2433 	info->data_value = 0;
2434 	return B_OK;
2435 }
2436 
2437 
2438 status_t
2439 PCI::_DisableMSIX(PCIDev *device)
2440 {
2441 	msix_info *info =  &device->msix;
2442 	if (!info->msix_capable)
2443 		return B_UNSUPPORTED;
2444 
2445 	if (info->configured_count == 0)
2446 		return B_NO_INIT;
2447 
2448 	// disable HT msi mapping (if applicable)
2449 	_HtMSIMap(device, 0);
2450 
2451 	// disable msi-x generation
2452 	info->control_value &= ~PCI_msix_control_enable;
2453 	gPCI->WriteConfig(device, info->capability_offset + PCI_msix_control, 2,
2454 		info->control_value);
2455 
2456 	return B_OK;
2457 }
2458