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