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