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