xref: /haiku/src/add-ons/kernel/bus_managers/pci/pci.cpp (revision 822e8462075a234cd2bd4fc82d353a584346692d)
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 
14 #include "util/kernel_cpp.h"
15 #include "pci_fixup.h"
16 #include "pci_info.h"
17 #include "pci_private.h"
18 #include "pci.h"
19 
20 #define TRACE_CAP(x...) dprintf(x)
21 #define FLOW(x...)
22 //#define FLOW(x...) dprintf(x)
23 
24 
25 PCI *gPCI;
26 
27 
28 // #pragma mark bus manager exports
29 
30 
31 status_t
32 pci_controller_add(pci_controller *controller, void *cookie)
33 {
34 	return gPCI->AddController(controller, cookie);
35 }
36 
37 
38 long
39 pci_get_nth_pci_info(long index, pci_info *outInfo)
40 {
41 	return gPCI->GetNthInfo(index, outInfo);
42 }
43 
44 
45 uint32
46 pci_read_config(uint8 virtualBus, uint8 device, uint8 function, uint8 offset,
47 	uint8 size)
48 {
49 	uint8 bus;
50 	int domain;
51 	uint32 value;
52 
53 	if (gPCI->ResolveVirtualBus(virtualBus, &domain, &bus) != B_OK)
54 		return 0xffffffff;
55 
56 	if (gPCI->ReadConfig(domain, bus, device, function, offset, size,
57 			&value) != B_OK)
58 		return 0xffffffff;
59 
60 	return value;
61 }
62 
63 
64 void
65 pci_write_config(uint8 virtualBus, uint8 device, uint8 function, uint8 offset,
66 	uint8 size, uint32 value)
67 {
68 	uint8 bus;
69 	int domain;
70 	if (gPCI->ResolveVirtualBus(virtualBus, &domain, &bus) != B_OK)
71 		return;
72 
73 	gPCI->WriteConfig(domain, bus, device, function, offset, size, value);
74 }
75 
76 
77 status_t
78 pci_find_capability(uchar virtualBus, uchar device, uchar function,
79 	uchar capID, uchar *offset)
80 {
81 	uint8 bus;
82 	int domain;
83 	if (gPCI->ResolveVirtualBus(virtualBus, &domain, &bus) != B_OK)
84 		return B_ERROR;
85 
86 	return gPCI->FindCapability(domain, bus, device, function, capID, offset);
87 }
88 
89 
90 status_t
91 pci_reserve_device(uchar virtualBus, uchar device, uchar function,
92 	const char *driverName, void *nodeCookie)
93 {
94 	status_t status;
95 	uint8 bus;
96 	int domain;
97 	TRACE(("pci_reserve_device(%d, %d, %d, %s)\n", virtualBus, device, function,
98 		driverName));
99 
100 	/*
101 	 * we add 2 nodes to the PCI devices, one with constant attributes,
102 	 * so adding for another driver fails, and a subnode with the
103 	 * driver-provided informations.
104 	 */
105 
106 	if (gPCI->ResolveVirtualBus(virtualBus, &domain, &bus) != B_OK)
107 		return B_ERROR;
108 
109 	//TRACE(("%s(%d [%d:%d], %d, %d, %s, %p)\n", __FUNCTION__, virtualBus,
110 	//	domain, bus, device, function, driverName, nodeCookie));
111 
112 	device_attr matchPCIRoot[] = {
113 		{B_DEVICE_PRETTY_NAME, B_STRING_TYPE, {string: "PCI"}},
114 		{NULL}
115 	};
116 	device_attr matchThis[] = {
117 		// info about device
118 		{B_DEVICE_BUS, B_STRING_TYPE, {string: "pci"}},
119 
120 		// location on PCI bus
121 		{B_PCI_DEVICE_DOMAIN, B_UINT32_TYPE, {ui32: domain}},
122 		{B_PCI_DEVICE_BUS, B_UINT8_TYPE, {ui8: bus}},
123 		{B_PCI_DEVICE_DEVICE, B_UINT8_TYPE, {ui8: device}},
124 		{B_PCI_DEVICE_FUNCTION, B_UINT8_TYPE, {ui8: function}},
125 		{NULL}
126 	};
127 	device_attr legacyAttrs[] = {
128 		// info about device
129 		{B_DEVICE_BUS, B_STRING_TYPE, {string: "legacy_driver"}},
130 		{B_DEVICE_PRETTY_NAME, B_STRING_TYPE, {string: "Legacy Driver Reservation"}},
131 		{NULL}
132 	};
133 	device_attr drvAttrs[] = {
134 		// info about device
135 		{B_DEVICE_BUS, B_STRING_TYPE, {string: "legacy_driver"}},
136 		{"legacy_driver", B_STRING_TYPE, {string: driverName}},
137 		{"legacy_driver_cookie", B_UINT64_TYPE, {ui64: (uint64)nodeCookie}},
138 		{NULL}
139 	};
140 	device_node *root, *pci, *node, *legacy;
141 
142 	status = B_DEVICE_NOT_FOUND;
143 	root = gDeviceManager->get_root_node();
144 	if (!root)
145 		return status;
146 
147 	pci = NULL;
148 	if (gDeviceManager->get_next_child_node(root, matchPCIRoot, &pci) < B_OK)
149 		goto err0;
150 
151 	node = NULL;
152 	if (gDeviceManager->get_next_child_node(pci, matchThis, &node) < B_OK)
153 		goto err1;
154 
155 	// common API for all legacy modules ?
156 	//status = legacy_driver_register(node, driverName, nodeCookie, PCI_LEGACY_DRIVER_MODULE_NAME);
157 
158 	status = gDeviceManager->register_node(node, PCI_LEGACY_DRIVER_MODULE_NAME,
159 		legacyAttrs, NULL, &legacy);
160 	if (status < B_OK)
161 		goto err2;
162 
163 	status = gDeviceManager->register_node(legacy, PCI_LEGACY_DRIVER_MODULE_NAME,
164 		drvAttrs, NULL, NULL);
165 	if (status < B_OK)
166 		goto err3;
167 
168 	gDeviceManager->put_node(node);
169 	gDeviceManager->put_node(pci);
170 	gDeviceManager->put_node(root);
171 
172 	return B_OK;
173 
174 err3:
175 	gDeviceManager->unregister_node(legacy);
176 err2:
177 	gDeviceManager->put_node(node);
178 err1:
179 	gDeviceManager->put_node(pci);
180 err0:
181 	gDeviceManager->put_node(root);
182 	TRACE(("pci_reserve_device for driver %s failed: %s\n", driverName,
183 		strerror(status)));
184 	return status;
185 }
186 
187 
188 status_t
189 pci_unreserve_device(uchar virtualBus, uchar device, uchar function,
190 	const char *driverName, void *nodeCookie)
191 {
192 	status_t status;
193 	uint8 bus;
194 	int domain;
195 	TRACE(("pci_unreserve_device(%d, %d, %d, %s)\n", virtualBus, device,
196 		function, driverName));
197 
198 	if (gPCI->ResolveVirtualBus(virtualBus, &domain, &bus) != B_OK)
199 		return B_ERROR;
200 
201 	//TRACE(("%s(%d [%d:%d], %d, %d, %s, %p)\n", __FUNCTION__, virtualBus,
202 	//	domain, bus, device, function, driverName, nodeCookie));
203 
204 	device_attr matchPCIRoot[] = {
205 		{B_DEVICE_PRETTY_NAME, B_STRING_TYPE, {string: "PCI"}},
206 		{NULL}
207 	};
208 	device_attr matchThis[] = {
209 		// info about device
210 		{B_DEVICE_BUS, B_STRING_TYPE, {string: "pci"}},
211 
212 		// location on PCI bus
213 		{B_PCI_DEVICE_DOMAIN, B_UINT32_TYPE, {ui32: domain}},
214 		{B_PCI_DEVICE_BUS, B_UINT8_TYPE, {ui8: bus}},
215 		{B_PCI_DEVICE_DEVICE, B_UINT8_TYPE, {ui8: device}},
216 		{B_PCI_DEVICE_FUNCTION, B_UINT8_TYPE, {ui8: function}},
217 		{NULL}
218 	};
219 	device_attr legacyAttrs[] = {
220 		// info about device
221 		{B_DEVICE_BUS, B_STRING_TYPE, {string: "legacy_driver"}},
222 		{B_DEVICE_PRETTY_NAME, B_STRING_TYPE, {string: "Legacy Driver Reservation"}},
223 		{NULL}
224 	};
225 	device_attr drvAttrs[] = {
226 		// info about device
227 		{B_DEVICE_BUS, B_STRING_TYPE, {string: "legacy_driver"}},
228 		{"legacy_driver", B_STRING_TYPE, {string: driverName}},
229 		{"legacy_driver_cookie", B_UINT64_TYPE, {ui64: (uint64)nodeCookie}},
230 		{NULL}
231 	};
232 	device_node *root, *pci, *node, *legacy, *drv;
233 
234 	status = B_DEVICE_NOT_FOUND;
235 	root = gDeviceManager->get_root_node();
236 	if (!root)
237 		return status;
238 
239 	pci = NULL;
240 	if (gDeviceManager->get_next_child_node(root, matchPCIRoot, &pci) < B_OK)
241 		goto err0;
242 
243 	node = NULL;
244 	if (gDeviceManager->get_next_child_node(pci, matchThis, &node) < B_OK)
245 		goto err1;
246 
247 	// common API for all legacy modules ?
248 	//status = legacy_driver_unregister(node, driverName, nodeCookie);
249 
250 	legacy = NULL;
251 	if (gDeviceManager->get_next_child_node(node, legacyAttrs, &legacy) < B_OK)
252 		goto err2;
253 
254 	drv = NULL;
255 	if (gDeviceManager->get_next_child_node(legacy, drvAttrs, &drv) < B_OK)
256 		goto err3;
257 
258 	gDeviceManager->put_node(drv);
259 	status = gDeviceManager->unregister_node(drv);
260 	//dprintf("unreg:drv:%s\n", strerror(status));
261 
262 	gDeviceManager->put_node(legacy);
263 	status = gDeviceManager->unregister_node(legacy);
264 	//dprintf("unreg:legacy:%s\n", strerror(status));
265 	// we'll get EBUSY here anyway...
266 
267 	gDeviceManager->put_node(node);
268 	gDeviceManager->put_node(pci);
269 	gDeviceManager->put_node(root);
270 	return B_OK;
271 
272 err3:
273 	gDeviceManager->put_node(legacy);
274 err2:
275 	gDeviceManager->put_node(node);
276 err1:
277 	gDeviceManager->put_node(pci);
278 err0:
279 	gDeviceManager->put_node(root);
280 	TRACE(("pci_unreserve_device for driver %s failed: %s\n", driverName,
281 		strerror(status)));
282 	return status;
283 }
284 
285 
286 status_t
287 pci_update_interrupt_line(uchar virtualBus, uchar device, uchar function,
288 	uchar newInterruptLineValue)
289 {
290 	uint8 bus;
291 	int domain;
292 	if (gPCI->ResolveVirtualBus(virtualBus, &domain, &bus) != B_OK)
293 		return B_ERROR;
294 
295 	return gPCI->UpdateInterruptLine(domain, bus, device, function,
296 		newInterruptLineValue);
297 }
298 
299 
300 // used by pci_info.cpp print_info_basic()
301 void
302 __pci_resolve_virtual_bus(uint8 virtualBus, int *domain, uint8 *bus)
303 {
304 	if (gPCI->ResolveVirtualBus(virtualBus, domain, bus) < B_OK)
305 		panic("ResolveVirtualBus failed");
306 }
307 
308 
309 // #pragma mark kernel debugger commands
310 
311 
312 static int
313 display_io(int argc, char **argv)
314 {
315 	int32 displayWidth;
316 	int32 itemSize;
317 	int32 num = 1;
318 	int address;
319 	int i = 1, j;
320 
321 	switch (argc) {
322 	case 3:
323 		num = atoi(argv[2]);
324 	case 2:
325 		address = strtoul(argv[1], NULL, 0);
326 		break;
327 	default:
328 		kprintf("usage: %s <address> [num]\n", argv[0]);
329 		return 0;
330 	}
331 
332 	// build the format string
333 	if (strcmp(argv[0], "inb") == 0 || strcmp(argv[0], "in8") == 0) {
334 		itemSize = 1;
335 		displayWidth = 16;
336 	} else if (strcmp(argv[0], "ins") == 0 || strcmp(argv[0], "in16") == 0) {
337 		itemSize = 2;
338 		displayWidth = 8;
339 	} else if (strcmp(argv[0], "inw") == 0 || strcmp(argv[0], "in32") == 0) {
340 		itemSize = 4;
341 		displayWidth = 4;
342 	} else {
343 		kprintf("display_io called in an invalid way!\n");
344 		return 0;
345 	}
346 
347 	for (i = 0; i < num; i++) {
348 		if ((i % displayWidth) == 0) {
349 			int32 displayed = min_c(displayWidth, (num-i)) * itemSize;
350 			if (i != 0)
351 				kprintf("\n");
352 
353 			kprintf("[0x%" B_PRIx32 "]  ", address + i * itemSize);
354 
355 			if (num > displayWidth) {
356 				// make sure the spacing in the last line is correct
357 				for (j = displayed; j < displayWidth * itemSize; j++)
358 					kprintf(" ");
359 			}
360 			kprintf("  ");
361 		}
362 
363 		switch (itemSize) {
364 			case 1:
365 				kprintf(" %02" B_PRIx8, pci_read_io_8(address + i * itemSize));
366 				break;
367 			case 2:
368 				kprintf(" %04" B_PRIx16, pci_read_io_16(address + i * itemSize));
369 				break;
370 			case 4:
371 				kprintf(" %08" B_PRIx32, pci_read_io_32(address + i * itemSize));
372 				break;
373 		}
374 	}
375 
376 	kprintf("\n");
377 	return 0;
378 }
379 
380 
381 static int
382 write_io(int argc, char **argv)
383 {
384 	int32 itemSize;
385 	uint32 value;
386 	int address;
387 	int i = 1;
388 
389 	if (argc < 3) {
390 		kprintf("usage: %s <address> <value> [value [...]]\n", argv[0]);
391 		return 0;
392 	}
393 
394 	address = strtoul(argv[1], NULL, 0);
395 
396 	if (strcmp(argv[0], "outb") == 0 || strcmp(argv[0], "out8") == 0) {
397 		itemSize = 1;
398 	} else if (strcmp(argv[0], "outs") == 0 || strcmp(argv[0], "out16") == 0) {
399 		itemSize = 2;
400 	} else if (strcmp(argv[0], "outw") == 0 || strcmp(argv[0], "out32") == 0) {
401 		itemSize = 4;
402 	} else {
403 		kprintf("write_io called in an invalid way!\n");
404 		return 0;
405 	}
406 
407 	// skip cmd name and address
408 	argv += 2;
409 	argc -= 2;
410 
411 	for (i = 0; i < argc; i++) {
412 		value = strtoul(argv[i], NULL, 0);
413 		switch (itemSize) {
414 			case 1:
415 				pci_write_io_8(address + i * itemSize, value);
416 				break;
417 			case 2:
418 				pci_write_io_16(address + i * itemSize, value);
419 				break;
420 			case 4:
421 				pci_write_io_32(address + i * itemSize, value);
422 				break;
423 		}
424 	}
425 
426 	return 0;
427 }
428 
429 
430 static int
431 pcistatus(int argc, char **argv)
432 {
433 	gPCI->ClearDeviceStatus(NULL, true);
434 	return 0;
435 }
436 
437 
438 static int
439 pcirefresh(int argc, char **argv)
440 {
441 	gPCI->RefreshDeviceInfo();
442 	pci_print_info();
443 	return 0;
444 }
445 
446 
447 // #pragma mark bus manager init/uninit
448 
449 
450 status_t
451 pci_init(void)
452 {
453 	gPCI = new PCI;
454 
455 	if (pci_io_init() != B_OK) {
456 		TRACE(("PCI: pci_io_init failed\n"));
457 		return B_ERROR;
458 	}
459 
460 	add_debugger_command("inw", &display_io, "dump io words (32-bit)");
461 	add_debugger_command("in32", &display_io, "dump io words (32-bit)");
462 	add_debugger_command("ins", &display_io, "dump io shorts (16-bit)");
463 	add_debugger_command("in16", &display_io, "dump io shorts (16-bit)");
464 	add_debugger_command("inb", &display_io, "dump io bytes (8-bit)");
465 	add_debugger_command("in8", &display_io, "dump io bytes (8-bit)");
466 
467 	add_debugger_command("outw", &write_io, "write io words (32-bit)");
468 	add_debugger_command("out32", &write_io, "write io words (32-bit)");
469 	add_debugger_command("outs", &write_io, "write io shorts (16-bit)");
470 	add_debugger_command("out16", &write_io, "write io shorts (16-bit)");
471 	add_debugger_command("outb", &write_io, "write io bytes (8-bit)");
472 	add_debugger_command("out8", &write_io, "write io bytes (8-bit)");
473 
474 	if (pci_controller_init() != B_OK) {
475 		TRACE(("PCI: pci_controller_init failed\n"));
476 		panic("PCI: pci_controller_init failed\n");
477 		return B_ERROR;
478 	}
479 
480 	gPCI->InitDomainData();
481 	gPCI->InitBus();
482 
483 	add_debugger_command("pcistatus", &pcistatus, "dump and clear pci device status registers");
484 	add_debugger_command("pcirefresh", &pcirefresh, "refresh and print all pci_info");
485 
486 	return B_OK;
487 }
488 
489 
490 void
491 pci_uninit(void)
492 {
493 	remove_debugger_command("outw", &write_io);
494 	remove_debugger_command("out32", &write_io);
495 	remove_debugger_command("outs", &write_io);
496 	remove_debugger_command("out16", &write_io);
497 	remove_debugger_command("outb", &write_io);
498 	remove_debugger_command("out8", &write_io);
499 
500 	remove_debugger_command("inw", &display_io);
501 	remove_debugger_command("in32", &display_io);
502 	remove_debugger_command("ins", &display_io);
503 	remove_debugger_command("in16", &display_io);
504 	remove_debugger_command("inb", &display_io);
505 	remove_debugger_command("in8", &display_io);
506 
507 	delete gPCI;
508 }
509 
510 
511 // #pragma mark PCI class
512 
513 
514 PCI::PCI()
515 	:
516 	fRootBus(0),
517 	fDomainCount(0),
518 	fBusEnumeration(false),
519 	fVirtualBusMap(),
520 	fNextVirtualBus(0)
521 {
522 	#if defined(__POWERPC__) || defined(__M68K__)
523 		fBusEnumeration = true;
524 	#endif
525 }
526 
527 
528 void
529 PCI::InitBus()
530 {
531 	PCIBus **nextBus = &fRootBus;
532 	for (int i = 0; i < fDomainCount; i++) {
533 		PCIBus *bus = new PCIBus;
534 		bus->next = NULL;
535 		bus->parent = NULL;
536 		bus->child = NULL;
537 		bus->domain = i;
538 		bus->bus = 0;
539 		*nextBus = bus;
540 		nextBus = &bus->next;
541 	}
542 
543 	if (fBusEnumeration) {
544 		for (int i = 0; i < fDomainCount; i++) {
545 			_EnumerateBus(i, 0);
546 		}
547 	}
548 
549 	if (1) {
550 		for (int i = 0; i < fDomainCount; i++) {
551 			_FixupDevices(i, 0);
552 		}
553 	}
554 
555 	if (fRootBus) {
556 		_DiscoverBus(fRootBus);
557 		_ConfigureBridges(fRootBus);
558 		ClearDeviceStatus(fRootBus, false);
559 		_RefreshDeviceInfo(fRootBus);
560 	}
561 }
562 
563 
564 PCI::~PCI()
565 {
566 }
567 
568 
569 status_t
570 PCI::_CreateVirtualBus(int domain, uint8 bus, uint8 *virtualBus)
571 {
572 #if defined(__INTEL__) || defined(__x86_64__)
573 
574 	// IA32 doesn't use domains
575 	if (domain)
576 		panic("PCI::CreateVirtualBus domain != 0");
577 	*virtualBus = bus;
578 	return B_OK;
579 
580 #else
581 
582 	if (fNextVirtualBus > 0xff)
583 		panic("PCI::CreateVirtualBus: virtual bus number space exhausted");
584 	if (unsigned(domain) > 0xff)
585 		panic("PCI::CreateVirtualBus: domain %d too large", domain);
586 
587 	uint16 value = domain << 8 | bus;
588 
589 	for (VirtualBusMap::Iterator it = fVirtualBusMap.Begin(); it != fVirtualBusMap.End(); ++it) {
590 		if (it->Value() == value) {
591 			*virtualBus = it->Key();
592 			FLOW("PCI::CreateVirtualBus: domain %d, bus %d already in map => virtualBus %d\n", domain, bus, *virtualBus);
593 			return B_OK;
594 		}
595 	}
596 
597 	*virtualBus = fNextVirtualBus++;
598 
599 	FLOW("PCI::CreateVirtualBus: domain %d, bus %d => virtualBus %d\n", domain, bus, *virtualBus);
600 
601 	return fVirtualBusMap.Insert(*virtualBus, value);
602 
603 #endif
604 }
605 
606 
607 status_t
608 PCI::ResolveVirtualBus(uint8 virtualBus, int *domain, uint8 *bus)
609 {
610 #if defined(__INTEL__) || defined(__x86_64__)
611 
612 	// IA32 doesn't use domains
613 	*bus = virtualBus;
614 	*domain = 0;
615 	return B_OK;
616 
617 #else
618 
619 	if (virtualBus >= fNextVirtualBus)
620 		return B_ERROR;
621 
622 	uint16 value = fVirtualBusMap.Get(virtualBus);
623 	*domain = value >> 8;
624 	*bus = value & 0xff;
625 	return B_OK;
626 
627 #endif
628 }
629 
630 
631 status_t
632 PCI::AddController(pci_controller *controller, void *controller_cookie)
633 {
634 	if (fDomainCount == MAX_PCI_DOMAINS)
635 		return B_ERROR;
636 
637 	fDomainData[fDomainCount].controller = controller;
638 	fDomainData[fDomainCount].controller_cookie = controller_cookie;
639 
640 	// initialized later to avoid call back into controller at this point
641 	fDomainData[fDomainCount].max_bus_devices = -1;
642 
643 	fDomainCount++;
644 	return B_OK;
645 }
646 
647 void
648 PCI::InitDomainData()
649 {
650 	for (int i = 0; i < fDomainCount; i++) {
651 		int32 count;
652 		status_t status;
653 
654 		status = (*fDomainData[i].controller->get_max_bus_devices)(fDomainData[i].controller_cookie, &count);
655 		fDomainData[i].max_bus_devices = (status == B_OK) ? count : 0;
656 	}
657 }
658 
659 
660 domain_data *
661 PCI::_GetDomainData(int domain)
662 {
663 	if (domain < 0 || domain >= fDomainCount)
664 		return NULL;
665 
666 	return &fDomainData[domain];
667 }
668 
669 
670 inline int
671 PCI::_NumFunctions(int domain, uint8 bus, uint8 device)
672 {
673 	uint8 type = ReadConfig(domain, bus, device,
674 		0, PCI_header_type, 1);
675 	return (type & PCI_multifunction) != 0 ? 8 : 1;
676 }
677 
678 
679 status_t
680 PCI::GetNthInfo(long index, pci_info *outInfo)
681 {
682 	long currentIndex = 0;
683 	if (!fRootBus)
684 		return B_ERROR;
685 
686 	return _GetNthInfo(fRootBus, &currentIndex, index, outInfo);
687 }
688 
689 
690 status_t
691 PCI::_GetNthInfo(PCIBus *bus, long *currentIndex, long wantIndex,
692 	pci_info *outInfo)
693 {
694 	// maps tree structure to linear indexed view
695 	PCIDev *dev = bus->child;
696 	while (dev) {
697 		if (*currentIndex == wantIndex) {
698 			*outInfo = dev->info;
699 			return B_OK;
700 		}
701 		*currentIndex += 1;
702 		if (dev->child && B_OK == _GetNthInfo(dev->child, currentIndex,
703 				wantIndex, outInfo))
704 			return B_OK;
705 		dev = dev->next;
706 	}
707 
708 	if (bus->next)
709 		return _GetNthInfo(bus->next, currentIndex, wantIndex, outInfo);
710 
711 	return B_ERROR;
712 }
713 
714 
715 void
716 PCI::_EnumerateBus(int domain, uint8 bus, uint8 *subordinateBus)
717 {
718 	TRACE(("PCI: EnumerateBus: domain %u, bus %u\n", domain, bus));
719 
720 	int maxBusDevices = _GetDomainData(domain)->max_bus_devices;
721 
722 	// step 1: disable all bridges on this bus
723 	for (int dev = 0; dev < maxBusDevices; dev++) {
724 		uint16 vendor_id = ReadConfig(domain, bus, dev, 0, PCI_vendor_id, 2);
725 		if (vendor_id == 0xffff)
726 			continue;
727 
728 		int numFunctions = _NumFunctions(domain, bus, dev);
729 		for (int function = 0; function < numFunctions; function++) {
730 			uint16 device_id = ReadConfig(domain, bus, dev, function,
731 				PCI_device_id, 2);
732 			if (device_id == 0xffff)
733 				continue;
734 
735 			uint8 baseClass = ReadConfig(domain, bus, dev, function,
736 				PCI_class_base, 1);
737 			uint8 subClass = ReadConfig(domain, bus, dev, function,
738 				PCI_class_sub, 1);
739 			if (baseClass != PCI_bridge || subClass != PCI_pci)
740 				continue;
741 
742 			// skip incorrectly configured devices
743 			uint8 headerType = ReadConfig(domain, bus, dev, function,
744 				PCI_header_type, 1) & PCI_header_type_mask;
745 			if (headerType != PCI_header_type_PCI_to_PCI_bridge)
746 				continue;
747 
748 			TRACE(("PCI: found PCI-PCI bridge: domain %u, bus %u, dev %u, func %u\n",
749 				domain, bus, dev, function));
750 			TRACE(("PCI: original settings: pcicmd %04" B_PRIx32 ", primary-bus "
751 				"%" B_PRIu32 ", secondary-bus %" B_PRIu32 ", subordinate-bus "
752 				"%" B_PRIu32 "\n",
753 				ReadConfig(domain, bus, dev, function, PCI_command, 2),
754 				ReadConfig(domain, bus, dev, function, PCI_primary_bus, 1),
755 				ReadConfig(domain, bus, dev, function, PCI_secondary_bus, 1),
756 				ReadConfig(domain, bus, dev, function, PCI_subordinate_bus, 1)));
757 
758 			// disable decoding
759 			uint16 pcicmd;
760 			pcicmd = ReadConfig(domain, bus, dev, function, PCI_command, 2);
761 			pcicmd &= ~(PCI_command_io | PCI_command_memory
762 				| PCI_command_master);
763 			WriteConfig(domain, bus, dev, function, PCI_command, 2, pcicmd);
764 
765 			// disable busses
766 			WriteConfig(domain, bus, dev, function, PCI_primary_bus, 1, 0);
767 			WriteConfig(domain, bus, dev, function, PCI_secondary_bus, 1, 0);
768 			WriteConfig(domain, bus, dev, function, PCI_subordinate_bus, 1, 0);
769 
770 			TRACE(("PCI: disabled settings: pcicmd %04" B_PRIx32 ", primary-bus "
771 				"%" B_PRIu32 ", secondary-bus %" B_PRIu32 ", subordinate-bus "
772 				"%" B_PRIu32 "\n",
773 				ReadConfig(domain, bus, dev, function, PCI_command, 2),
774 				ReadConfig(domain, bus, dev, function, PCI_primary_bus, 1),
775 				ReadConfig(domain, bus, dev, function, PCI_secondary_bus, 1),
776 				ReadConfig(domain, bus, dev, function, PCI_subordinate_bus, 1)));
777 		}
778 	}
779 
780 	uint8 lastUsedBusNumber = bus;
781 
782 	// step 2: assign busses to all bridges, and enable them again
783 	for (int dev = 0; dev < maxBusDevices; dev++) {
784 		uint16 vendor_id = ReadConfig(domain, bus, dev, 0, PCI_vendor_id, 2);
785 		if (vendor_id == 0xffff)
786 			continue;
787 
788 		int numFunctions = _NumFunctions(domain, bus, dev);
789 		for (int function = 0; function < numFunctions; function++) {
790 			uint16 deviceID = ReadConfig(domain, bus, dev, function,
791 				PCI_device_id, 2);
792 			if (deviceID == 0xffff)
793 				continue;
794 
795 			uint8 baseClass = ReadConfig(domain, bus, dev, function,
796 				PCI_class_base, 1);
797 			uint8 subClass = ReadConfig(domain, bus, dev, function,
798 				PCI_class_sub, 1);
799 			if (baseClass != PCI_bridge || subClass != PCI_pci)
800 				continue;
801 
802 			// skip incorrectly configured devices
803 			uint8 headerType = ReadConfig(domain, bus, dev, function,
804 				PCI_header_type, 1) & PCI_header_type_mask;
805 			if (headerType != PCI_header_type_PCI_to_PCI_bridge)
806 				continue;
807 
808 			TRACE(("PCI: configuring PCI-PCI bridge: domain %u, bus %u, dev %u, func %u\n",
809 				domain, bus, dev, function));
810 
811 			// open Scheunentor for enumerating the bus behind the bridge
812 			WriteConfig(domain, bus, dev, function, PCI_primary_bus, 1, bus);
813 			WriteConfig(domain, bus, dev, function, PCI_secondary_bus, 1,
814 				lastUsedBusNumber + 1);
815 			WriteConfig(domain, bus, dev, function, PCI_subordinate_bus, 1, 255);
816 
817 			// enable decoding (too early here?)
818 			uint16 pcicmd;
819 			pcicmd = ReadConfig(domain, bus, dev, function, PCI_command, 2);
820 			pcicmd |= PCI_command_io | PCI_command_memory | PCI_command_master;
821 			WriteConfig(domain, bus, dev, function, PCI_command, 2, pcicmd);
822 
823 			TRACE(("PCI: probing settings: pcicmd %04" B_PRIx32 ", primary-bus "
824 				"%" B_PRIu32 ", secondary-bus %" B_PRIu32 ", subordinate-bus "
825 				"%" B_PRIu32 "\n",
826 				ReadConfig(domain, bus, dev, function, PCI_command, 2),
827 				ReadConfig(domain, bus, dev, function, PCI_primary_bus, 1),
828 				ReadConfig(domain, bus, dev, function, PCI_secondary_bus, 1),
829 				ReadConfig(domain, bus, dev, function, PCI_subordinate_bus, 1)));
830 
831 			// enumerate bus
832 			_EnumerateBus(domain, lastUsedBusNumber + 1, &lastUsedBusNumber);
833 
834 			// close Scheunentor
835 			WriteConfig(domain, bus, dev, function, PCI_subordinate_bus, 1, lastUsedBusNumber);
836 
837 			TRACE(("PCI: configured settings: pcicmd %04" B_PRIx32 ", primary-bus "
838 				"%" B_PRIu32 ", secondary-bus %" B_PRIu32 ", subordinate-bus "
839 				"%" B_PRIu32 "\n",
840 				ReadConfig(domain, bus, dev, function, PCI_command, 2),
841 				ReadConfig(domain, bus, dev, function, PCI_primary_bus, 1),
842 				ReadConfig(domain, bus, dev, function, PCI_secondary_bus, 1),
843 				ReadConfig(domain, bus, dev, function, PCI_subordinate_bus, 1)));
844 			}
845 	}
846 	if (subordinateBus)
847 		*subordinateBus = lastUsedBusNumber;
848 
849 	TRACE(("PCI: EnumerateBus done: domain %u, bus %u, last used bus number %u\n", domain, bus, lastUsedBusNumber));
850 }
851 
852 
853 void
854 PCI::_FixupDevices(int domain, uint8 bus)
855 {
856 	FLOW("PCI: FixupDevices domain %u, bus %u\n", domain, bus);
857 
858 	int maxBusDevices = _GetDomainData(domain)->max_bus_devices;
859 	static int recursed = 0;
860 
861 	if (recursed++ > 10) {
862 		// guard against buggy chipsets
863 		// XXX: is there any official limit ?
864 		dprintf("PCI: FixupDevices: too many recursions (buggy chipset?)\n");
865 		recursed--;
866 		return;
867 	}
868 
869 	for (int dev = 0; dev < maxBusDevices; dev++) {
870 		uint16 vendorId = ReadConfig(domain, bus, dev, 0, PCI_vendor_id, 2);
871 		if (vendorId == 0xffff)
872 			continue;
873 
874 		int numFunctions = _NumFunctions(domain, bus, dev);
875 		for (int function = 0; function < numFunctions; function++) {
876 			uint16 deviceId = ReadConfig(domain, bus, dev, function,
877 				PCI_device_id, 2);
878 			if (deviceId == 0xffff)
879 				continue;
880 
881 			pci_fixup_device(this, domain, bus, dev, function);
882 
883 			uint8 baseClass = ReadConfig(domain, bus, dev, function,
884 				PCI_class_base, 1);
885 			if (baseClass != PCI_bridge)
886 				continue;
887 			uint8 subClass = ReadConfig(domain, bus, dev, function,
888 				PCI_class_sub, 1);
889 			if (subClass != PCI_pci)
890 				continue;
891 
892 			// some FIC motherboards have a buggy BIOS...
893 			// make sure the header type is correct for a bridge,
894 			uint8 headerType = ReadConfig(domain, bus, dev, function,
895 				PCI_header_type, 1) & PCI_header_type_mask;
896 			if (headerType != PCI_header_type_PCI_to_PCI_bridge) {
897 				dprintf("PCI: dom %u, bus %u, dev %2u, func %u, PCI bridge"
898 					" class but wrong header type 0x%02x, ignoring.\n",
899 					domain, bus, dev, function, headerType);
900 				continue;
901 			}
902 
903 
904 			int busBehindBridge = ReadConfig(domain, bus, dev, function,
905 				PCI_secondary_bus, 1);
906 
907 			TRACE(("PCI: FixupDevices: checking bus %d behind %04x:%04x\n",
908 				busBehindBridge, vendorId, deviceId));
909 			_FixupDevices(domain, busBehindBridge);
910 		}
911 	}
912 	recursed--;
913 }
914 
915 
916 void
917 PCI::_ConfigureBridges(PCIBus *bus)
918 {
919 	for (PCIDev *dev = bus->child; dev; dev = dev->next) {
920 		if (dev->info.class_base == PCI_bridge
921 			&& dev->info.class_sub == PCI_pci
922 			&& (dev->info.header_type & PCI_header_type_mask)
923 			== PCI_header_type_PCI_to_PCI_bridge) {
924 			uint16 bridgeControlOld = ReadConfig(dev->domain, dev->bus,
925 				dev->device, dev->function, PCI_bridge_control, 2);
926 			uint16 bridgeControlNew = bridgeControlOld;
927 			// Enable: Parity Error Response, SERR, Master Abort Mode, Discard
928 			// Timer SERR
929 			// Clear: Discard Timer Status
930 			bridgeControlNew |= PCI_bridge_parity_error_response
931 				| PCI_bridge_serr | PCI_bridge_master_abort
932 				| PCI_bridge_discard_timer_status
933 				| PCI_bridge_discard_timer_serr;
934 			// Set discard timer to 2^15 PCI clocks
935 			bridgeControlNew &= ~(PCI_bridge_primary_discard_timeout
936 				| PCI_bridge_secondary_discard_timeout);
937 			WriteConfig(dev->domain, dev->bus, dev->device, dev->function,
938 				PCI_bridge_control, 2, bridgeControlNew);
939 			bridgeControlNew = ReadConfig(dev->domain, dev->bus, dev->device,
940 				dev->function, PCI_bridge_control, 2);
941 			dprintf("PCI: dom %u, bus %u, dev %2u, func %u, changed PCI bridge"
942 				" control from 0x%04x to 0x%04x\n", dev->domain, dev->bus,
943 				dev->device, dev->function, bridgeControlOld,
944 				bridgeControlNew);
945 		}
946 
947 		if (dev->child)
948 			_ConfigureBridges(dev->child);
949 	}
950 
951 	if (bus->next)
952 		_ConfigureBridges(bus->next);
953 }
954 
955 
956 void
957 PCI::ClearDeviceStatus(PCIBus *bus, bool dumpStatus)
958 {
959 	if (!bus) {
960 		if (!fRootBus)
961 			return;
962 		bus = fRootBus;
963 	}
964 
965 	for (PCIDev *dev = bus->child; dev; dev = dev->next) {
966 		// Clear and dump PCI device status
967 		uint16 status = ReadConfig(dev->domain, dev->bus, dev->device,
968 			dev->function, PCI_status, 2);
969 		WriteConfig(dev->domain, dev->bus, dev->device, dev->function,
970 			PCI_status, 2, status);
971 		if (dumpStatus) {
972 			kprintf("domain %u, bus %u, dev %2u, func %u, PCI device status "
973 				"0x%04x\n", dev->domain, dev->bus, dev->device, dev->function,
974 				status);
975 			if (status & PCI_status_parity_error_detected)
976 				kprintf("  Detected Parity Error\n");
977 			if (status & PCI_status_serr_signalled)
978 				kprintf("  Signalled System Error\n");
979 			if (status & PCI_status_master_abort_received)
980 				kprintf("  Received Master-Abort\n");
981 			if (status & PCI_status_target_abort_received)
982 				kprintf("  Received Target-Abort\n");
983 			if (status & PCI_status_target_abort_signalled)
984 				kprintf("  Signalled Target-Abort\n");
985 			if (status & PCI_status_parity_signalled)
986 				kprintf("  Master Data Parity Error\n");
987 		}
988 
989 		if (dev->info.class_base == PCI_bridge
990 			&& dev->info.class_sub == PCI_pci) {
991 			// Clear and dump PCI bridge secondary status
992 			uint16 secondaryStatus = ReadConfig(dev->domain, dev->bus,
993 				dev->device, dev->function, PCI_secondary_status, 2);
994 			WriteConfig(dev->domain, dev->bus, dev->device, dev->function,
995 				PCI_secondary_status, 2, secondaryStatus);
996 			if (dumpStatus) {
997 				kprintf("domain %u, bus %u, dev %2u, func %u, PCI bridge "
998 					"secondary status 0x%04x\n", dev->domain, dev->bus,
999 					dev->device, dev->function, secondaryStatus);
1000 				if (secondaryStatus & PCI_status_parity_error_detected)
1001 					kprintf("  Detected Parity Error\n");
1002 				if (secondaryStatus & PCI_status_serr_signalled)
1003 					kprintf("  Received System Error\n");
1004 				if (secondaryStatus & PCI_status_master_abort_received)
1005 					kprintf("  Received Master-Abort\n");
1006 				if (secondaryStatus & PCI_status_target_abort_received)
1007 					kprintf("  Received Target-Abort\n");
1008 				if (secondaryStatus & PCI_status_target_abort_signalled)
1009 					kprintf("  Signalled Target-Abort\n");
1010 				if (secondaryStatus & PCI_status_parity_signalled)
1011 					kprintf("  Data Parity Reported\n");
1012 			}
1013 
1014 			// Clear and dump the discard-timer error bit located in bridge-control register
1015 			uint16 bridgeControl = ReadConfig(dev->domain, dev->bus,
1016 				dev->device, dev->function, PCI_bridge_control, 2);
1017 			WriteConfig(dev->domain, dev->bus, dev->device, dev->function,
1018 				PCI_bridge_control, 2, bridgeControl);
1019 			if (dumpStatus) {
1020 				kprintf("domain %u, bus %u, dev %2u, func %u, PCI bridge "
1021 					"control 0x%04x\n", dev->domain, dev->bus, dev->device,
1022 					dev->function, bridgeControl);
1023 				if (bridgeControl & PCI_bridge_discard_timer_status) {
1024 					kprintf("  bridge-control: Discard Timer Error\n");
1025 				}
1026 			}
1027 		}
1028 
1029 		if (dev->child)
1030 			ClearDeviceStatus(dev->child, dumpStatus);
1031 	}
1032 
1033 	if (bus->next)
1034 		ClearDeviceStatus(bus->next, dumpStatus);
1035 }
1036 
1037 
1038 void
1039 PCI::_DiscoverBus(PCIBus *bus)
1040 {
1041 	FLOW("PCI: DiscoverBus, domain %u, bus %u\n", bus->domain, bus->bus);
1042 
1043 	int maxBusDevices = _GetDomainData(bus->domain)->max_bus_devices;
1044 	static int recursed = 0;
1045 
1046 	if (recursed++ > 10) {
1047 		// guard against buggy chipsets
1048 		// XXX: is there any official limit ?
1049 		dprintf("PCI: DiscoverBus: too many recursions (buggy chipset?)\n");
1050 		recursed--;
1051 		return;
1052 	}
1053 
1054 	for (int dev = 0; dev < maxBusDevices; dev++) {
1055 		uint16 vendorID = ReadConfig(bus->domain, bus->bus, dev, 0,
1056 			PCI_vendor_id, 2);
1057 		if (vendorID == 0xffff)
1058 			continue;
1059 
1060 		int numFunctions = _NumFunctions(bus->domain, bus->bus, dev);
1061 		for (int function = 0; function < numFunctions; function++)
1062 			_DiscoverDevice(bus, dev, function);
1063 	}
1064 
1065 	if (bus->next)
1066 		_DiscoverBus(bus->next);
1067 	recursed--;
1068 }
1069 
1070 
1071 void
1072 PCI::_DiscoverDevice(PCIBus *bus, uint8 dev, uint8 function)
1073 {
1074 	FLOW("PCI: DiscoverDevice, domain %u, bus %u, dev %u, func %u\n", bus->domain, bus->bus, dev, function);
1075 
1076 	uint16 deviceID = ReadConfig(bus->domain, bus->bus, dev, function,
1077 		PCI_device_id, 2);
1078 	if (deviceID == 0xffff)
1079 		return;
1080 
1081 	PCIDev *newDev = _CreateDevice(bus, dev, function);
1082 
1083 	uint8 baseClass = ReadConfig(bus->domain, bus->bus, dev, function,
1084 		PCI_class_base, 1);
1085 	uint8 subClass = ReadConfig(bus->domain, bus->bus, dev, function,
1086 		PCI_class_sub, 1);
1087 	uint8 headerType = ReadConfig(bus->domain, bus->bus, dev, function,
1088 		PCI_header_type, 1) & PCI_header_type_mask;
1089 	if (baseClass == PCI_bridge && subClass == PCI_pci
1090 		&& headerType == PCI_header_type_PCI_to_PCI_bridge) {
1091 		uint8 secondaryBus = ReadConfig(bus->domain, bus->bus, dev, function,
1092 			PCI_secondary_bus, 1);
1093 		PCIBus *newBus = _CreateBus(newDev, bus->domain, secondaryBus);
1094 		_DiscoverBus(newBus);
1095 	}
1096 }
1097 
1098 
1099 PCIBus *
1100 PCI::_CreateBus(PCIDev *parent, int domain, uint8 bus)
1101 {
1102 	PCIBus *newBus = new(std::nothrow) PCIBus;
1103 	if (newBus == NULL)
1104 		return NULL;
1105 
1106 	newBus->next = NULL;
1107 	newBus->parent = parent;
1108 	newBus->child = NULL;
1109 	newBus->domain = domain;
1110 	newBus->bus = bus;
1111 
1112 	// append
1113 	parent->child = newBus;
1114 
1115 	return newBus;
1116 }
1117 
1118 
1119 PCIDev *
1120 PCI::_CreateDevice(PCIBus *parent, uint8 device, uint8 function)
1121 {
1122 	FLOW("PCI: CreateDevice, domain %u, bus %u, dev %u, func %u:\n", parent->domain, parent->bus, device, function);
1123 
1124 	PCIDev *newDev = new(std::nothrow) PCIDev;
1125 	if (newDev == NULL)
1126 		return NULL;
1127 
1128 	newDev->next = NULL;
1129 	newDev->parent = parent;
1130 	newDev->child = NULL;
1131 	newDev->domain = parent->domain;
1132 	newDev->bus = parent->bus;
1133 	newDev->device = device;
1134 	newDev->function = function;
1135 
1136 	_ReadBasicInfo(newDev);
1137 
1138 	FLOW("PCI: CreateDevice, vendor 0x%04x, device 0x%04x, class_base 0x%02x, class_sub 0x%02x\n",
1139 		newDev->info.vendor_id, newDev->info.device_id, newDev->info.class_base, newDev->info.class_sub);
1140 
1141 	// append
1142 	if (parent->child == NULL) {
1143 		parent->child = newDev;
1144 	} else {
1145 		PCIDev *sub = parent->child;
1146 		while (sub->next)
1147 			sub = sub->next;
1148 		sub->next = newDev;
1149 	}
1150 
1151 	return newDev;
1152 }
1153 
1154 
1155 uint32
1156 PCI::_BarSize(uint32 bits, uint32 mask)
1157 {
1158 	bits &= mask;
1159 	if (!bits)
1160 		return 0;
1161 	uint32 size = 1;
1162 	while (!(bits & size))
1163 		size <<= 1;
1164 	return size;
1165 }
1166 
1167 
1168 void
1169 PCI::_GetBarInfo(PCIDev *dev, uint8 offset, uint32 *_address, uint32 *_size,
1170 	uint8 *_flags)
1171 {
1172 	uint32 oldValue = ReadConfig(dev->domain, dev->bus, dev->device, dev->function,
1173 		offset, 4);
1174 	WriteConfig(dev->domain, dev->bus, dev->device, dev->function, offset, 4,
1175 		0xffffffff);
1176 	uint32 newValue = ReadConfig(dev->domain, dev->bus, dev->device, dev->function,
1177 		offset, 4);
1178 	WriteConfig(dev->domain, dev->bus, dev->device, dev->function, offset, 4,
1179 		oldValue);
1180 
1181 	*_address = oldValue & PCI_address_memory_32_mask;
1182 	if (_size != NULL)
1183 		*_size = _BarSize(newValue, PCI_address_memory_32_mask);
1184 	if (_flags != NULL)
1185 		*_flags = newValue & 0xf;
1186 }
1187 
1188 
1189 void
1190 PCI::_GetRomBarInfo(PCIDev *dev, uint8 offset, uint32 *_address, uint32 *_size,
1191 	uint8 *_flags)
1192 {
1193 	uint32 oldValue = ReadConfig(dev->domain, dev->bus, dev->device, dev->function,
1194 		offset, 4);
1195 	WriteConfig(dev->domain, dev->bus, dev->device, dev->function, offset, 4,
1196 		0xfffffffe); // LSB must be 0
1197 	uint32 newValue = ReadConfig(dev->domain, dev->bus, dev->device, dev->function,
1198 		offset, 4);
1199 	WriteConfig(dev->domain, dev->bus, dev->device, dev->function, offset, 4,
1200 		oldValue);
1201 
1202 	*_address = oldValue & PCI_rom_address_mask;
1203 	if (_size != NULL)
1204 		*_size = _BarSize(newValue, PCI_rom_address_mask);
1205 	if (_flags != NULL)
1206 		*_flags = newValue & 0xf;
1207 }
1208 
1209 
1210 void
1211 PCI::_ReadBasicInfo(PCIDev *dev)
1212 {
1213 	uint8 virtualBus;
1214 
1215 	if (_CreateVirtualBus(dev->domain, dev->bus, &virtualBus) != B_OK) {
1216 		dprintf("PCI: CreateVirtualBus failed, domain %u, bus %u\n", dev->domain, dev->bus);
1217 		return;
1218 	}
1219 
1220 	dev->info.vendor_id = ReadConfig(dev->domain, dev->bus, dev->device,
1221 		dev->function, PCI_vendor_id, 2);
1222 	dev->info.device_id = ReadConfig(dev->domain, dev->bus, dev->device,
1223 		dev->function, PCI_device_id, 2);
1224 	dev->info.bus = virtualBus;
1225 	dev->info.device = dev->device;
1226 	dev->info.function = dev->function;
1227 	dev->info.revision = ReadConfig(dev->domain, dev->bus, dev->device,
1228 		dev->function, PCI_revision, 1);
1229 	dev->info.class_api = ReadConfig(dev->domain, dev->bus, dev->device,
1230 		dev->function, PCI_class_api, 1);
1231 	dev->info.class_sub = ReadConfig(dev->domain, dev->bus, dev->device,
1232 		dev->function, PCI_class_sub, 1);
1233 	dev->info.class_base = ReadConfig(dev->domain, dev->bus, dev->device,
1234 		dev->function, PCI_class_base, 1);
1235 	dev->info.line_size = ReadConfig(dev->domain, dev->bus, dev->device,
1236 		dev->function, PCI_line_size, 1);
1237 	dev->info.latency = ReadConfig(dev->domain, dev->bus, dev->device,
1238 		dev->function, PCI_latency, 1);
1239 	// BeOS does not mask off the multifunction bit, developer must use
1240 	// (header_type & PCI_header_type_mask)
1241 	dev->info.header_type = ReadConfig(dev->domain, dev->bus, dev->device,
1242 		dev->function, PCI_header_type, 1);
1243 	dev->info.bist = ReadConfig(dev->domain, dev->bus, dev->device,
1244 		dev->function, PCI_bist, 1);
1245 	dev->info.reserved = 0;
1246 }
1247 
1248 
1249 void
1250 PCI::_ReadHeaderInfo(PCIDev *dev)
1251 {
1252 	switch (dev->info.header_type & PCI_header_type_mask) {
1253 		case PCI_header_type_generic:
1254 		{
1255 			// disable PCI device address decoding (io and memory) while BARs
1256 			// are modified
1257 			uint16 pcicmd = ReadConfig(dev->domain, dev->bus, dev->device,
1258 				dev->function, PCI_command, 2);
1259 			WriteConfig(dev->domain, dev->bus, dev->device, dev->function,
1260 				PCI_command, 2,
1261 				pcicmd & ~(PCI_command_io | PCI_command_memory));
1262 
1263 			// get BAR size infos
1264 			_GetRomBarInfo(dev, PCI_rom_base, &dev->info.u.h0.rom_base_pci,
1265 				&dev->info.u.h0.rom_size);
1266 			for (int i = 0; i < 6; i++) {
1267 				_GetBarInfo(dev, PCI_base_registers + 4*i,
1268 					&dev->info.u.h0.base_registers_pci[i],
1269 					&dev->info.u.h0.base_register_sizes[i],
1270 					&dev->info.u.h0.base_register_flags[i]);
1271 			}
1272 
1273 			// restore PCI device address decoding
1274 			WriteConfig(dev->domain, dev->bus, dev->device, dev->function,
1275 				PCI_command, 2, pcicmd);
1276 
1277 			dev->info.u.h0.rom_base = (addr_t)pci_ram_address(
1278 				(void *)(addr_t)dev->info.u.h0.rom_base_pci);
1279 			for (int i = 0; i < 6; i++) {
1280 				dev->info.u.h0.base_registers[i] = (addr_t)pci_ram_address(
1281 					(void *)(addr_t)dev->info.u.h0.base_registers_pci[i]);
1282 			}
1283 
1284 			dev->info.u.h0.cardbus_cis = ReadConfig(dev->domain, dev->bus,
1285 				dev->device, dev->function, PCI_cardbus_cis, 4);
1286 			dev->info.u.h0.subsystem_id = ReadConfig(dev->domain, dev->bus,
1287 				dev->device, dev->function, PCI_subsystem_id, 2);
1288 			dev->info.u.h0.subsystem_vendor_id = ReadConfig(dev->domain,
1289 				dev->bus, dev->device, dev->function, PCI_subsystem_vendor_id, 2);
1290 			dev->info.u.h0.interrupt_line = ReadConfig(dev->domain, dev->bus,
1291 				dev->device, dev->function, PCI_interrupt_line, 1);
1292 			dev->info.u.h0.interrupt_pin = ReadConfig(dev->domain, dev->bus,
1293 				dev->device, dev->function, PCI_interrupt_pin, 1);
1294 			dev->info.u.h0.min_grant = ReadConfig(dev->domain, dev->bus,
1295 				dev->device, dev->function, PCI_min_grant, 1);
1296 			dev->info.u.h0.max_latency = ReadConfig(dev->domain, dev->bus,
1297 				dev->device, dev->function, PCI_max_latency, 1);
1298 			break;
1299 		}
1300 
1301 		case PCI_header_type_PCI_to_PCI_bridge:
1302 		{
1303 			// disable PCI device address decoding (io and memory) while BARs are modified
1304 			uint16 pcicmd = ReadConfig(dev->domain, dev->bus, dev->device,
1305 				dev->function, PCI_command, 2);
1306 			WriteConfig(dev->domain, dev->bus, dev->device, dev->function,
1307 				PCI_command, 2,
1308 				pcicmd & ~(PCI_command_io | PCI_command_memory));
1309 
1310 			_GetRomBarInfo(dev, PCI_bridge_rom_base,
1311 				&dev->info.u.h1.rom_base_pci);
1312 			for (int i = 0; i < 2; i++) {
1313 				_GetBarInfo(dev, PCI_base_registers + 4*i,
1314 					&dev->info.u.h1.base_registers_pci[i],
1315 					&dev->info.u.h1.base_register_sizes[i],
1316 					&dev->info.u.h1.base_register_flags[i]);
1317 			}
1318 
1319 			// restore PCI device address decoding
1320 			WriteConfig(dev->domain, dev->bus, dev->device, dev->function,
1321 				PCI_command, 2, pcicmd);
1322 
1323 			dev->info.u.h1.rom_base = (addr_t)pci_ram_address(
1324 				(void *)(addr_t)dev->info.u.h1.rom_base_pci);
1325 			for (int i = 0; i < 2; i++) {
1326 				dev->info.u.h1.base_registers[i] = (addr_t)pci_ram_address(
1327 					(void *)(addr_t)dev->info.u.h1.base_registers_pci[i]);
1328 			}
1329 
1330 			dev->info.u.h1.primary_bus = ReadConfig(dev->domain, dev->bus,
1331 				dev->device, dev->function, PCI_primary_bus, 1);
1332 			dev->info.u.h1.secondary_bus = ReadConfig(dev->domain, dev->bus,
1333 				dev->device, dev->function, PCI_secondary_bus, 1);
1334 			dev->info.u.h1.subordinate_bus = ReadConfig(dev->domain,
1335 				dev->bus, dev->device, dev->function, PCI_subordinate_bus, 1);
1336 			dev->info.u.h1.secondary_latency = ReadConfig(dev->domain,
1337 				dev->bus, dev->device, dev->function, PCI_secondary_latency, 1);
1338 			dev->info.u.h1.io_base = ReadConfig(dev->domain, dev->bus,
1339 				dev->device, dev->function, PCI_io_base, 1);
1340 			dev->info.u.h1.io_limit = ReadConfig(dev->domain, dev->bus,
1341 				dev->device, dev->function, PCI_io_limit, 1);
1342 			dev->info.u.h1.secondary_status = ReadConfig(dev->domain,
1343 				dev->bus, dev->device, dev->function, PCI_secondary_status, 2);
1344 			dev->info.u.h1.memory_base = ReadConfig(dev->domain, dev->bus,
1345 				dev->device, dev->function, PCI_memory_base, 2);
1346 			dev->info.u.h1.memory_limit = ReadConfig(dev->domain, dev->bus,
1347 				dev->device, dev->function, PCI_memory_limit, 2);
1348 			dev->info.u.h1.prefetchable_memory_base = ReadConfig(dev->domain,
1349 				dev->bus, dev->device, dev->function, PCI_prefetchable_memory_base, 2);
1350 			dev->info.u.h1.prefetchable_memory_limit = ReadConfig(
1351 				dev->domain, dev->bus, dev->device, dev->function,
1352 				PCI_prefetchable_memory_limit, 2);
1353 			dev->info.u.h1.prefetchable_memory_base_upper32 = ReadConfig(
1354 				dev->domain, dev->bus, dev->device, dev->function,
1355 				PCI_prefetchable_memory_base_upper32, 4);
1356 			dev->info.u.h1.prefetchable_memory_limit_upper32 = ReadConfig(
1357 				dev->domain, dev->bus, dev->device, dev->function,
1358 				PCI_prefetchable_memory_limit_upper32, 4);
1359 			dev->info.u.h1.io_base_upper16 = ReadConfig(dev->domain,
1360 				dev->bus, dev->device, dev->function, PCI_io_base_upper16, 2);
1361 			dev->info.u.h1.io_limit_upper16 = ReadConfig(dev->domain,
1362 				dev->bus, dev->device, dev->function, PCI_io_limit_upper16, 2);
1363 			dev->info.u.h1.interrupt_line = ReadConfig(dev->domain, dev->bus,
1364 				dev->device, dev->function, PCI_interrupt_line, 1);
1365 			dev->info.u.h1.interrupt_pin = ReadConfig(dev->domain, dev->bus,
1366 				dev->device, dev->function, PCI_interrupt_pin, 1);
1367 			dev->info.u.h1.bridge_control = ReadConfig(dev->domain, dev->bus,
1368 				dev->device, dev->function, PCI_bridge_control, 2);
1369 			dev->info.u.h1.subsystem_id = ReadConfig(dev->domain, dev->bus,
1370 				dev->device, dev->function, PCI_sub_device_id_1, 2);
1371 			dev->info.u.h1.subsystem_vendor_id = ReadConfig(dev->domain,
1372 				dev->bus, dev->device, dev->function, PCI_sub_vendor_id_1, 2);
1373 			break;
1374 		}
1375 
1376 		case PCI_header_type_cardbus:
1377 		{
1378 			// for testing only, not final:
1379 			dev->info.u.h2.subsystem_id = ReadConfig(dev->domain, dev->bus,
1380 				dev->device, dev->function, PCI_sub_device_id_2, 2);
1381 			dev->info.u.h2.subsystem_vendor_id = ReadConfig(dev->domain,
1382 				dev->bus, dev->device, dev->function, PCI_sub_vendor_id_2, 2);
1383 			dev->info.u.h2.primary_bus = ReadConfig(dev->domain, dev->bus,
1384 				dev->device, dev->function, PCI_primary_bus_2, 1);
1385 			dev->info.u.h2.secondary_bus = ReadConfig(dev->domain, dev->bus,
1386 				dev->device, dev->function, PCI_secondary_bus_2, 1);
1387 			dev->info.u.h2.subordinate_bus = ReadConfig(dev->domain,
1388 				dev->bus, dev->device, dev->function, PCI_subordinate_bus_2, 1);
1389 			dev->info.u.h2.secondary_latency = ReadConfig(dev->domain,
1390 				dev->bus, dev->device, dev->function, PCI_secondary_latency_2, 1);
1391 			dev->info.u.h2.reserved = 0;
1392 			dev->info.u.h2.memory_base = ReadConfig(dev->domain, dev->bus,
1393 				dev->device, dev->function, PCI_memory_base0_2, 4);
1394 			dev->info.u.h2.memory_limit = ReadConfig(dev->domain, dev->bus,
1395 				dev->device, dev->function, PCI_memory_limit0_2, 4);
1396 			dev->info.u.h2.memory_base_upper32 = ReadConfig(dev->domain,
1397 				dev->bus, dev->device, dev->function, PCI_memory_base1_2, 4);
1398 			dev->info.u.h2.memory_limit_upper32 = ReadConfig(dev->domain,
1399 				dev->bus, dev->device, dev->function, PCI_memory_limit1_2, 4);
1400 			dev->info.u.h2.io_base = ReadConfig(dev->domain, dev->bus,
1401 				dev->device, dev->function, PCI_io_base0_2, 4);
1402 			dev->info.u.h2.io_limit = ReadConfig(dev->domain, dev->bus,
1403 				dev->device, dev->function, PCI_io_limit0_2, 4);
1404 			dev->info.u.h2.io_base_upper32 = ReadConfig(dev->domain,
1405 				dev->bus, dev->device, dev->function, PCI_io_base1_2, 4);
1406 			dev->info.u.h2.io_limit_upper32 = ReadConfig(dev->domain,
1407 				dev->bus, dev->device, dev->function, PCI_io_limit1_2, 4);
1408 			dev->info.u.h2.secondary_status = ReadConfig(dev->domain,
1409 				dev->bus, dev->device, dev->function, PCI_secondary_status_2, 2);
1410 			dev->info.u.h2.bridge_control = ReadConfig(dev->domain,
1411 				dev->bus, dev->device, dev->function, PCI_bridge_control_2, 2);
1412 			break;
1413 		}
1414 
1415 		default:
1416 			TRACE(("PCI: Header type unknown (0x%02x)\n", dev->info.header_type));
1417 			break;
1418 	}
1419 }
1420 
1421 
1422 void
1423 PCI::RefreshDeviceInfo()
1424 {
1425 	if (fRootBus == NULL)
1426 		return;
1427 
1428 	_RefreshDeviceInfo(fRootBus);
1429 }
1430 
1431 
1432 void
1433 PCI::_RefreshDeviceInfo(PCIBus *bus)
1434 {
1435 	for (PCIDev *dev = bus->child; dev; dev = dev->next) {
1436 		_ReadBasicInfo(dev);
1437 		_ReadHeaderInfo(dev);
1438 #if defined(__INTEL__) || defined(__x86_64__)
1439 		pci_read_arch_info(dev);
1440 #endif
1441 		if (dev->child)
1442 			_RefreshDeviceInfo(dev->child);
1443 	}
1444 
1445 	if (bus->next)
1446 		_RefreshDeviceInfo(bus->next);
1447 }
1448 
1449 
1450 status_t
1451 PCI::ReadConfig(int domain, uint8 bus, uint8 device, uint8 function,
1452 	uint8 offset, uint8 size, uint32 *value)
1453 {
1454 	domain_data *info = _GetDomainData(domain);
1455 	if (!info)
1456 		return B_ERROR;
1457 
1458 	if (device > (info->max_bus_devices - 1)
1459 		|| function > 7
1460 		|| (size != 1 && size != 2 && size != 4)
1461 		|| (size == 2 && (offset & 3) == 3)
1462 		|| (size == 4 && (offset & 3) != 0)) {
1463 		dprintf("PCI: can't read config for domain %d, bus %u, device %u, function %u, offset %u, size %u\n",
1464 			 domain, bus, device, function, offset, size);
1465 		return B_ERROR;
1466 	}
1467 
1468 	return (*info->controller->read_pci_config)(info->controller_cookie, bus,
1469 		device, function, offset, size, value);
1470 }
1471 
1472 
1473 uint32
1474 PCI::ReadConfig(int domain, uint8 bus, uint8 device, uint8 function,
1475 	uint8 offset, uint8 size)
1476 {
1477 	uint32 value;
1478 	if (ReadConfig(domain, bus, device, function, offset, size, &value)
1479 			!= B_OK)
1480 		return 0xffffffff;
1481 
1482 	return value;
1483 }
1484 
1485 
1486 uint32
1487 PCI::ReadConfig(PCIDev *device, uint8 offset, uint8 size)
1488 {
1489 	uint32 value;
1490 	if (ReadConfig(device->domain, device->bus, device->device,
1491 			device->function, offset, size, &value) != B_OK)
1492 		return 0xffffffff;
1493 
1494 	return value;
1495 }
1496 
1497 
1498 status_t
1499 PCI::WriteConfig(int domain, uint8 bus, uint8 device, uint8 function,
1500 	uint8 offset, uint8 size, uint32 value)
1501 {
1502 	domain_data *info = _GetDomainData(domain);
1503 	if (!info)
1504 		return B_ERROR;
1505 
1506 	if (device > (info->max_bus_devices - 1)
1507 		|| function > 7
1508 		|| (size != 1 && size != 2 && size != 4)
1509 		|| (size == 2 && (offset & 3) == 3)
1510 		|| (size == 4 && (offset & 3) != 0)) {
1511 		dprintf("PCI: can't write config for domain %d, bus %u, device %u, function %u, offset %u, size %u\n",
1512 			 domain, bus, device, function, offset, size);
1513 		return B_ERROR;
1514 	}
1515 
1516 	return (*info->controller->write_pci_config)(info->controller_cookie, bus,
1517 		device, function, offset, size, value);
1518 }
1519 
1520 
1521 status_t
1522 PCI::WriteConfig(PCIDev *device, uint8 offset, uint8 size, uint32 value)
1523 {
1524 	return WriteConfig(device->domain, device->bus, device->device,
1525 		device->function, offset, size, value);
1526 }
1527 
1528 
1529 status_t
1530 PCI::FindCapability(int domain, uint8 bus, uint8 device, uint8 function,
1531 	uint8 capID, uint8 *offset)
1532 {
1533 	if (offset == NULL) {
1534 		TRACE_CAP("PCI: FindCapability() ERROR %u:%u:%u capability %#02x offset NULL pointer\n", bus, device, function, capID);
1535 		return B_BAD_VALUE;
1536 	}
1537 
1538 	uint16 status = ReadConfig(domain, bus, device, function, PCI_status, 2);
1539 	if (!(status & PCI_status_capabilities)) {
1540 		TRACE_CAP("PCI: find_pci_capability ERROR %u:%u:%u capability %#02x not supported\n", bus, device, function, capID);
1541 		return B_ERROR;
1542 	}
1543 
1544 	uint8 headerType = ReadConfig(domain, bus, device, function,
1545 		PCI_header_type, 1);
1546 	uint8 capPointer;
1547 
1548 	switch (headerType & PCI_header_type_mask) {
1549 		case PCI_header_type_generic:
1550 		case PCI_header_type_PCI_to_PCI_bridge:
1551 			capPointer = ReadConfig(domain, bus, device, function,
1552 				PCI_capabilities_ptr, 1);
1553 			break;
1554 		case PCI_header_type_cardbus:
1555 			capPointer = ReadConfig(domain, bus, device, function,
1556 				PCI_capabilities_ptr_2, 1);
1557 			break;
1558 		default:
1559 			TRACE_CAP("PCI: find_pci_capability ERROR %u:%u:%u capability %#02x unknown header type\n", bus, device, function, capID);
1560 			return B_ERROR;
1561 	}
1562 
1563 	capPointer &= ~3;
1564 	if (capPointer == 0) {
1565 		TRACE_CAP("PCI: find_pci_capability ERROR %u:%u:%u capability %#02x empty list\n", bus, device, function, capID);
1566 		return B_NAME_NOT_FOUND;
1567 	}
1568 
1569 	for (int i = 0; i < 48; i++) {
1570 		if (ReadConfig(domain, bus, device, function, capPointer, 1) == capID) {
1571 			*offset = capPointer;
1572 			return B_OK;
1573 		}
1574 
1575 		capPointer = ReadConfig(domain, bus, device, function, capPointer + 1,
1576 			1);
1577 		capPointer &= ~3;
1578 
1579 		if (capPointer == 0)
1580 			return B_NAME_NOT_FOUND;
1581 	}
1582 
1583 	TRACE_CAP("PCI: find_pci_capability ERROR %u:%u:%u capability %#02x circular list\n", bus, device, function, capID);
1584 	return B_ERROR;
1585 }
1586 
1587 
1588 status_t
1589 PCI::FindCapability(PCIDev *device, uint8 capID, uint8 *offset)
1590 {
1591 	return FindCapability(device->domain, device->bus, device->device,
1592 		device->function, capID, offset);
1593 }
1594 
1595 
1596 PCIDev *
1597 PCI::FindDevice(int domain, uint8 bus, uint8 device, uint8 function)
1598 {
1599 	return _FindDevice(fRootBus, domain, bus, device, function);
1600 }
1601 
1602 
1603 PCIDev *
1604 PCI::_FindDevice(PCIBus *current, int domain, uint8 bus, uint8 device,
1605 	uint8 function)
1606 {
1607 	if (current->domain == domain) {
1608 		// search device on this bus
1609 
1610 		for (PCIDev *child = current->child; child != NULL;
1611 				child = child->next) {
1612 			if (child->bus == bus && child->device == device
1613 				&& child->function == function)
1614 				return child;
1615 
1616 			if (child->child != NULL) {
1617 				// search child busses
1618 				PCIDev *found = _FindDevice(child->child, domain, bus, device,
1619 					function);
1620 				if (found != NULL)
1621 					return found;
1622 			}
1623 		}
1624 	}
1625 
1626 	// search other busses
1627 	if (current->next != NULL)
1628 		return _FindDevice(current->next, domain, bus, device, function);
1629 
1630 	return NULL;
1631 }
1632 
1633 
1634 status_t
1635 PCI::UpdateInterruptLine(int domain, uint8 bus, uint8 _device, uint8 function,
1636 	uint8 newInterruptLineValue)
1637 {
1638 	PCIDev *device = FindDevice(domain, bus, _device, function);
1639 	if (device == NULL)
1640 		return B_ERROR;
1641 
1642 	pci_info &info = device->info;
1643 	switch (info.header_type & PCI_header_type_mask) {
1644 		case PCI_header_type_generic:
1645 			info.u.h0.interrupt_line = newInterruptLineValue;
1646 			break;
1647 
1648 		case PCI_header_type_PCI_to_PCI_bridge:
1649 			info.u.h1.interrupt_line = newInterruptLineValue;
1650 			break;
1651 
1652 		default:
1653 			return B_ERROR;
1654 	}
1655 
1656 	return WriteConfig(device, PCI_interrupt_line, 1, newInterruptLineValue);
1657 }
1658