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
30PCI *gPCI;
31
32
33// #pragma mark bus manager exports
34
35
36long
37pci_get_nth_pci_info(long index, pci_info *outInfo)
38{
39	return gPCI->GetNthInfo(index, outInfo);
40}
41
42
43uint32
44pci_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
62void
63pci_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
75phys_addr_t
76pci_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(B_IO_MEMORY, childAdr, domain, range) >= B_OK)
85		hostAdr = childAdr - range.pci_address + range.host_address;
86#endif
87	//dprintf("pci_ram_address(%#" B_PRIx64 ") -> %#" B_PRIx64 "\n", childAdr, hostAdr);
88	return hostAdr;
89}
90
91
92status_t
93pci_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
105status_t
106pci_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
119status_t
120pci_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
194err3:
195	gDeviceManager->unregister_node(legacy);
196err2:
197	gDeviceManager->put_node(node);
198err1:
199	TRACE(("pci_reserve_device for driver %s failed: %s\n", driverName,
200		strerror(status)));
201	return status;
202}
203
204
205status_t
206pci_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
278err3:
279	gDeviceManager->put_node(legacy);
280err2:
281	gDeviceManager->put_node(node);
282err1:
283	TRACE(("pci_unreserve_device for driver %s failed: %s\n", driverName,
284		strerror(status)));
285	return status;
286}
287
288
289status_t
290pci_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
303status_t
304pci_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
315status_t
316pci_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()
328void
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
339static int
340display_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
408static int
409write_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
457static int
458pcistatus(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
472static int
473pcirefresh(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
484status_t
485pci_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
510void
511pci_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
537PCI::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
550void
551PCI::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
568PCI::~PCI()
569{
570}
571
572
573status_t
574PCI::_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
612status_t
613PCI::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
636status_t
637PCI::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
672status_t
673PCI::LookupRange(uint32 type, phys_addr_t pciAddr,
674	uint8 &domain, pci_resource_range &range, uint8 **mappedAdr)
675{
676	for (uint8 curDomain = 0; curDomain < fDomainCount; curDomain++) {
677		const auto &ranges = fDomainData[curDomain].ranges;
678
679		for (int32 i = 0; i < ranges.Count(); i++) {
680			const pci_resource_range curRange = ranges[i];
681			if (curRange.type != type)
682				continue;
683
684			if (pciAddr >= curRange.pci_address
685					&& pciAddr < (curRange.pci_address + curRange.size)) {
686				domain = curDomain;
687				range = curRange;
688#if !(defined(__i386__) || defined(__x86_64__))
689				if (type == B_IO_PORT && mappedAdr != NULL)
690					*mappedAdr = fDomainData[curDomain].io_port_adr;
691#endif
692				return B_OK;
693			}
694		}
695	}
696
697	return B_ENTRY_NOT_FOUND;
698}
699
700
701void
702PCI::InitDomainData(domain_data &data)
703{
704	int32 count;
705	status_t status;
706
707	pci_controller_module_info *ctrl = data.controller;
708	void *ctrlCookie = data.controller_cookie;
709
710	status = ctrl->get_max_bus_devices(ctrlCookie, &count);
711	data.max_bus_devices = (status == B_OK) ? count : 0;
712
713	pci_resource_range range;
714	for (uint32 j = 0; ctrl->get_range(ctrlCookie, j, &range) >= B_OK; j++)
715		data.ranges.Add(range);
716
717#if !(defined(__i386__) || defined(__x86_64__))
718	for (int32 i = 0; i < data.ranges.Count(); i++) {
719		pci_resource_range &ioPortRange = data.ranges[i];
720		if (ioPortRange.type != B_IO_PORT)
721			continue;
722
723		if (ioPortRange.size > 0) {
724			data.io_port_area = map_physical_memory("PCI IO Ports",
725				ioPortRange.host_address, ioPortRange.size, B_ANY_KERNEL_ADDRESS,
726				B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA, (void **)&data.io_port_adr);
727
728			if (data.io_port_area < B_OK)
729				data.io_port_adr = NULL;
730
731			// TODO: Map other IO ports (if any.)
732			break;
733		}
734	}
735#endif
736}
737
738
739domain_data *
740PCI::_GetDomainData(uint8 domain)
741{
742	if (domain >= fDomainCount)
743		return NULL;
744
745	return &fDomainData[domain];
746}
747
748
749inline int
750PCI::_NumFunctions(uint8 domain, uint8 bus, uint8 device)
751{
752	uint8 type = ReadConfig(domain, bus, device,
753		0, PCI_header_type, 1);
754	return (type & PCI_multifunction) != 0 ? 8 : 1;
755}
756
757
758status_t
759PCI::GetNthInfo(long index, pci_info *outInfo)
760{
761	long currentIndex = 0;
762
763	for (uint32 domain = 0; domain < fDomainCount; domain++) {
764		if (_GetNthInfo(fDomainData[domain].bus, &currentIndex, index, outInfo) >= B_OK)
765			return B_OK;
766	}
767
768	return B_ERROR;
769}
770
771
772status_t
773PCI::_GetNthInfo(PCIBus *bus, long *currentIndex, long wantIndex,
774	pci_info *outInfo)
775{
776	// maps tree structure to linear indexed view
777	PCIDev *dev = bus->child;
778	while (dev) {
779		if (*currentIndex == wantIndex) {
780			*outInfo = dev->info;
781			return B_OK;
782		}
783		*currentIndex += 1;
784		if (dev->child && B_OK == _GetNthInfo(dev->child, currentIndex,
785				wantIndex, outInfo))
786			return B_OK;
787		dev = dev->next;
788	}
789
790	return B_ERROR;
791}
792
793
794void
795PCI::_EnumerateBus(uint8 domain, uint8 bus, uint8 *subordinateBus)
796{
797	TRACE(("PCI: EnumerateBus: domain %u, bus %u\n", domain, bus));
798
799	int maxBusDevices = _GetDomainData(domain)->max_bus_devices;
800
801	// step 1: disable all bridges on this bus
802	for (int dev = 0; dev < maxBusDevices; dev++) {
803		uint16 vendor_id = ReadConfig(domain, bus, dev, 0, PCI_vendor_id, 2);
804		if (vendor_id == 0xffff)
805			continue;
806
807		int numFunctions = _NumFunctions(domain, bus, dev);
808		for (int function = 0; function < numFunctions; function++) {
809			uint16 device_id = ReadConfig(domain, bus, dev, function,
810				PCI_device_id, 2);
811			if (device_id == 0xffff)
812				continue;
813
814			uint8 baseClass = ReadConfig(domain, bus, dev, function,
815				PCI_class_base, 1);
816			uint8 subClass = ReadConfig(domain, bus, dev, function,
817				PCI_class_sub, 1);
818			if (baseClass != PCI_bridge || subClass != PCI_pci)
819				continue;
820
821			// skip incorrectly configured devices
822			uint8 headerType = ReadConfig(domain, bus, dev, function,
823				PCI_header_type, 1) & PCI_header_type_mask;
824			if (headerType != PCI_header_type_PCI_to_PCI_bridge)
825				continue;
826
827			TRACE(("PCI: found PCI-PCI bridge: domain %u, bus %u, dev %u, func %u\n",
828				domain, bus, dev, function));
829			TRACE(("PCI: original settings: pcicmd %04" B_PRIx32 ", primary-bus "
830				"%" B_PRIu32 ", secondary-bus %" B_PRIu32 ", subordinate-bus "
831				"%" B_PRIu32 "\n",
832				ReadConfig(domain, bus, dev, function, PCI_command, 2),
833				ReadConfig(domain, bus, dev, function, PCI_primary_bus, 1),
834				ReadConfig(domain, bus, dev, function, PCI_secondary_bus, 1),
835				ReadConfig(domain, bus, dev, function, PCI_subordinate_bus, 1)));
836
837			// disable decoding
838			uint16 pcicmd;
839			pcicmd = ReadConfig(domain, bus, dev, function, PCI_command, 2);
840			pcicmd &= ~(PCI_command_io | PCI_command_memory
841				| PCI_command_master);
842			WriteConfig(domain, bus, dev, function, PCI_command, 2, pcicmd);
843
844			// disable busses
845			WriteConfig(domain, bus, dev, function, PCI_primary_bus, 1, 0);
846			WriteConfig(domain, bus, dev, function, PCI_secondary_bus, 1, 0);
847			WriteConfig(domain, bus, dev, function, PCI_subordinate_bus, 1, 0);
848
849			TRACE(("PCI: disabled settings: pcicmd %04" B_PRIx32 ", primary-bus "
850				"%" B_PRIu32 ", secondary-bus %" B_PRIu32 ", subordinate-bus "
851				"%" B_PRIu32 "\n",
852				ReadConfig(domain, bus, dev, function, PCI_command, 2),
853				ReadConfig(domain, bus, dev, function, PCI_primary_bus, 1),
854				ReadConfig(domain, bus, dev, function, PCI_secondary_bus, 1),
855				ReadConfig(domain, bus, dev, function, PCI_subordinate_bus, 1)));
856		}
857	}
858
859	uint8 lastUsedBusNumber = bus;
860
861	// step 2: assign busses to all bridges, and enable them again
862	for (int dev = 0; dev < maxBusDevices; dev++) {
863		uint16 vendor_id = ReadConfig(domain, bus, dev, 0, PCI_vendor_id, 2);
864		if (vendor_id == 0xffff)
865			continue;
866
867		int numFunctions = _NumFunctions(domain, bus, dev);
868		for (int function = 0; function < numFunctions; function++) {
869			uint16 deviceID = ReadConfig(domain, bus, dev, function,
870				PCI_device_id, 2);
871			if (deviceID == 0xffff)
872				continue;
873
874			uint8 baseClass = ReadConfig(domain, bus, dev, function,
875				PCI_class_base, 1);
876			uint8 subClass = ReadConfig(domain, bus, dev, function,
877				PCI_class_sub, 1);
878			if (baseClass != PCI_bridge || subClass != PCI_pci)
879				continue;
880
881			// skip incorrectly configured devices
882			uint8 headerType = ReadConfig(domain, bus, dev, function,
883				PCI_header_type, 1) & PCI_header_type_mask;
884			if (headerType != PCI_header_type_PCI_to_PCI_bridge)
885				continue;
886
887			TRACE(("PCI: configuring PCI-PCI bridge: domain %u, bus %u, dev %u, func %u\n",
888				domain, bus, dev, function));
889
890			// open Scheunentor for enumerating the bus behind the bridge
891			WriteConfig(domain, bus, dev, function, PCI_primary_bus, 1, bus);
892			WriteConfig(domain, bus, dev, function, PCI_secondary_bus, 1,
893				lastUsedBusNumber + 1);
894			WriteConfig(domain, bus, dev, function, PCI_subordinate_bus, 1, 255);
895
896			// enable decoding (too early here?)
897			uint16 pcicmd;
898			pcicmd = ReadConfig(domain, bus, dev, function, PCI_command, 2);
899			pcicmd |= PCI_command_io | PCI_command_memory | PCI_command_master;
900			WriteConfig(domain, bus, dev, function, PCI_command, 2, pcicmd);
901
902			TRACE(("PCI: probing settings: pcicmd %04" B_PRIx32 ", primary-bus "
903				"%" B_PRIu32 ", secondary-bus %" B_PRIu32 ", subordinate-bus "
904				"%" B_PRIu32 "\n",
905				ReadConfig(domain, bus, dev, function, PCI_command, 2),
906				ReadConfig(domain, bus, dev, function, PCI_primary_bus, 1),
907				ReadConfig(domain, bus, dev, function, PCI_secondary_bus, 1),
908				ReadConfig(domain, bus, dev, function, PCI_subordinate_bus, 1)));
909
910			// enumerate bus
911			_EnumerateBus(domain, lastUsedBusNumber + 1, &lastUsedBusNumber);
912
913			// close Scheunentor
914			WriteConfig(domain, bus, dev, function, PCI_subordinate_bus, 1, lastUsedBusNumber);
915
916			TRACE(("PCI: configured settings: pcicmd %04" B_PRIx32 ", primary-bus "
917				"%" B_PRIu32 ", secondary-bus %" B_PRIu32 ", subordinate-bus "
918				"%" B_PRIu32 "\n",
919				ReadConfig(domain, bus, dev, function, PCI_command, 2),
920				ReadConfig(domain, bus, dev, function, PCI_primary_bus, 1),
921				ReadConfig(domain, bus, dev, function, PCI_secondary_bus, 1),
922				ReadConfig(domain, bus, dev, function, PCI_subordinate_bus, 1)));
923			}
924	}
925	if (subordinateBus)
926		*subordinateBus = lastUsedBusNumber;
927
928	TRACE(("PCI: EnumerateBus done: domain %u, bus %u, last used bus number %u\n", domain, bus, lastUsedBusNumber));
929}
930
931
932void
933PCI::_FixupDevices(uint8 domain, uint8 bus)
934{
935	FLOW("PCI: FixupDevices domain %u, bus %u\n", domain, bus);
936
937	int maxBusDevices = _GetDomainData(domain)->max_bus_devices;
938	static int recursed = 0;
939
940	if (recursed++ > 10) {
941		// guard against buggy chipsets
942		// XXX: is there any official limit ?
943		dprintf("PCI: FixupDevices: too many recursions (buggy chipset?)\n");
944		recursed--;
945		return;
946	}
947
948	for (int dev = 0; dev < maxBusDevices; dev++) {
949		uint16 vendorId = ReadConfig(domain, bus, dev, 0, PCI_vendor_id, 2);
950		if (vendorId == 0xffff)
951			continue;
952
953		int numFunctions = _NumFunctions(domain, bus, dev);
954		for (int function = 0; function < numFunctions; function++) {
955			uint16 deviceId = ReadConfig(domain, bus, dev, function,
956				PCI_device_id, 2);
957			if (deviceId == 0xffff)
958				continue;
959
960			pci_fixup_device(this, domain, bus, dev, function);
961
962			uint8 baseClass = ReadConfig(domain, bus, dev, function,
963				PCI_class_base, 1);
964			if (baseClass != PCI_bridge)
965				continue;
966			uint8 subClass = ReadConfig(domain, bus, dev, function,
967				PCI_class_sub, 1);
968			if (subClass != PCI_pci)
969				continue;
970
971			// some FIC motherboards have a buggy BIOS...
972			// make sure the header type is correct for a bridge,
973			uint8 headerType = ReadConfig(domain, bus, dev, function,
974				PCI_header_type, 1) & PCI_header_type_mask;
975			if (headerType != PCI_header_type_PCI_to_PCI_bridge) {
976				dprintf("PCI: dom %u, bus %u, dev %2u, func %u, PCI bridge"
977					" class but wrong header type 0x%02x, ignoring.\n",
978					domain, bus, dev, function, headerType);
979				continue;
980			}
981
982
983			int busBehindBridge = ReadConfig(domain, bus, dev, function,
984				PCI_secondary_bus, 1);
985
986			TRACE(("PCI: FixupDevices: checking bus %d behind %04x:%04x\n",
987				busBehindBridge, vendorId, deviceId));
988			_FixupDevices(domain, busBehindBridge);
989		}
990	}
991	recursed--;
992}
993
994
995void
996PCI::_ConfigureBridges(PCIBus *bus)
997{
998	for (PCIDev *dev = bus->child; dev; dev = dev->next) {
999		if (dev->info.class_base == PCI_bridge
1000			&& dev->info.class_sub == PCI_pci
1001			&& (dev->info.header_type & PCI_header_type_mask)
1002			== PCI_header_type_PCI_to_PCI_bridge) {
1003			uint16 bridgeControlOld = ReadConfig(dev->domain, dev->bus,
1004				dev->device, dev->function, PCI_bridge_control, 2);
1005			uint16 bridgeControlNew = bridgeControlOld;
1006			// Enable: Parity Error Response, SERR, Master Abort Mode, Discard
1007			// Timer SERR
1008			// Clear: Discard Timer Status
1009			bridgeControlNew |= PCI_bridge_parity_error_response
1010				| PCI_bridge_serr | PCI_bridge_master_abort
1011				| PCI_bridge_discard_timer_status
1012				| PCI_bridge_discard_timer_serr;
1013			// Set discard timer to 2^15 PCI clocks
1014			bridgeControlNew &= ~(PCI_bridge_primary_discard_timeout
1015				| PCI_bridge_secondary_discard_timeout);
1016			WriteConfig(dev->domain, dev->bus, dev->device, dev->function,
1017				PCI_bridge_control, 2, bridgeControlNew);
1018			bridgeControlNew = ReadConfig(dev->domain, dev->bus, dev->device,
1019				dev->function, PCI_bridge_control, 2);
1020			dprintf("PCI: dom %u, bus %u, dev %2u, func %u, changed PCI bridge"
1021				" control from 0x%04x to 0x%04x\n", dev->domain, dev->bus,
1022				dev->device, dev->function, bridgeControlOld,
1023				bridgeControlNew);
1024		}
1025
1026		if (dev->child)
1027			_ConfigureBridges(dev->child);
1028	}
1029}
1030
1031
1032void
1033PCI::ClearDeviceStatus(PCIBus *bus, bool dumpStatus)
1034{
1035	for (PCIDev *dev = bus->child; dev; dev = dev->next) {
1036		// Clear and dump PCI device status
1037		uint16 status = ReadConfig(dev->domain, dev->bus, dev->device,
1038			dev->function, PCI_status, 2);
1039		WriteConfig(dev->domain, dev->bus, dev->device, dev->function,
1040			PCI_status, 2, status);
1041		if (dumpStatus) {
1042			kprintf("domain %u, bus %u, dev %2u, func %u, PCI device status "
1043				"0x%04x\n", dev->domain, dev->bus, dev->device, dev->function,
1044				status);
1045			if (status & PCI_status_parity_error_detected)
1046				kprintf("  Detected Parity Error\n");
1047			if (status & PCI_status_serr_signalled)
1048				kprintf("  Signalled System Error\n");
1049			if (status & PCI_status_master_abort_received)
1050				kprintf("  Received Master-Abort\n");
1051			if (status & PCI_status_target_abort_received)
1052				kprintf("  Received Target-Abort\n");
1053			if (status & PCI_status_target_abort_signalled)
1054				kprintf("  Signalled Target-Abort\n");
1055			if (status & PCI_status_parity_signalled)
1056				kprintf("  Master Data Parity Error\n");
1057		}
1058
1059		if (dev->info.class_base == PCI_bridge
1060			&& dev->info.class_sub == PCI_pci) {
1061			// Clear and dump PCI bridge secondary status
1062			uint16 secondaryStatus = ReadConfig(dev->domain, dev->bus,
1063				dev->device, dev->function, PCI_secondary_status, 2);
1064			WriteConfig(dev->domain, dev->bus, dev->device, dev->function,
1065				PCI_secondary_status, 2, secondaryStatus);
1066			if (dumpStatus) {
1067				kprintf("domain %u, bus %u, dev %2u, func %u, PCI bridge "
1068					"secondary status 0x%04x\n", dev->domain, dev->bus,
1069					dev->device, dev->function, secondaryStatus);
1070				if (secondaryStatus & PCI_status_parity_error_detected)
1071					kprintf("  Detected Parity Error\n");
1072				if (secondaryStatus & PCI_status_serr_signalled)
1073					kprintf("  Received System Error\n");
1074				if (secondaryStatus & PCI_status_master_abort_received)
1075					kprintf("  Received Master-Abort\n");
1076				if (secondaryStatus & PCI_status_target_abort_received)
1077					kprintf("  Received Target-Abort\n");
1078				if (secondaryStatus & PCI_status_target_abort_signalled)
1079					kprintf("  Signalled Target-Abort\n");
1080				if (secondaryStatus & PCI_status_parity_signalled)
1081					kprintf("  Data Parity Reported\n");
1082			}
1083
1084			// Clear and dump the discard-timer error bit located in bridge-control register
1085			uint16 bridgeControl = ReadConfig(dev->domain, dev->bus,
1086				dev->device, dev->function, PCI_bridge_control, 2);
1087			WriteConfig(dev->domain, dev->bus, dev->device, dev->function,
1088				PCI_bridge_control, 2, bridgeControl);
1089			if (dumpStatus) {
1090				kprintf("domain %u, bus %u, dev %2u, func %u, PCI bridge "
1091					"control 0x%04x\n", dev->domain, dev->bus, dev->device,
1092					dev->function, bridgeControl);
1093				if (bridgeControl & PCI_bridge_discard_timer_status) {
1094					kprintf("  bridge-control: Discard Timer Error\n");
1095				}
1096			}
1097		}
1098
1099		if (dev->child)
1100			ClearDeviceStatus(dev->child, dumpStatus);
1101	}
1102}
1103
1104
1105void
1106PCI::_DiscoverBus(PCIBus *bus)
1107{
1108	FLOW("PCI: DiscoverBus, domain %u, bus %u\n", bus->domain, bus->bus);
1109
1110	int maxBusDevices = _GetDomainData(bus->domain)->max_bus_devices;
1111	static int recursed = 0;
1112
1113	if (recursed++ > 10) {
1114		// guard against buggy chipsets
1115		// XXX: is there any official limit ?
1116		dprintf("PCI: DiscoverBus: too many recursions (buggy chipset?)\n");
1117		recursed--;
1118		return;
1119	}
1120
1121	for (int dev = 0; dev < maxBusDevices; dev++) {
1122		uint16 vendorID = ReadConfig(bus->domain, bus->bus, dev, 0,
1123			PCI_vendor_id, 2);
1124		if (vendorID == 0xffff)
1125			continue;
1126
1127		int numFunctions = _NumFunctions(bus->domain, bus->bus, dev);
1128		for (int function = 0; function < numFunctions; function++)
1129			_DiscoverDevice(bus, dev, function);
1130	}
1131
1132	recursed--;
1133}
1134
1135
1136void
1137PCI::_DiscoverDevice(PCIBus *bus, uint8 dev, uint8 function)
1138{
1139	FLOW("PCI: DiscoverDevice, domain %u, bus %u, dev %u, func %u\n", bus->domain, bus->bus, dev, function);
1140
1141	uint16 deviceID = ReadConfig(bus->domain, bus->bus, dev, function,
1142		PCI_device_id, 2);
1143	if (deviceID == 0xffff)
1144		return;
1145
1146	PCIDev *newDev = _CreateDevice(bus, dev, function);
1147
1148	uint8 baseClass = ReadConfig(bus->domain, bus->bus, dev, function,
1149		PCI_class_base, 1);
1150	uint8 subClass = ReadConfig(bus->domain, bus->bus, dev, function,
1151		PCI_class_sub, 1);
1152	uint8 headerType = ReadConfig(bus->domain, bus->bus, dev, function,
1153		PCI_header_type, 1) & PCI_header_type_mask;
1154	if (baseClass == PCI_bridge && subClass == PCI_pci
1155		&& headerType == PCI_header_type_PCI_to_PCI_bridge) {
1156		uint8 secondaryBus = ReadConfig(bus->domain, bus->bus, dev, function,
1157			PCI_secondary_bus, 1);
1158		PCIBus *newBus = _CreateBus(newDev, bus->domain, secondaryBus);
1159		_DiscoverBus(newBus);
1160	}
1161}
1162
1163
1164PCIBus *
1165PCI::_CreateBus(PCIDev *parent, uint8 domain, uint8 bus)
1166{
1167	PCIBus *newBus = new(std::nothrow) PCIBus;
1168	if (newBus == NULL)
1169		return NULL;
1170
1171	newBus->parent = parent;
1172	newBus->child = NULL;
1173	newBus->domain = domain;
1174	newBus->bus = bus;
1175
1176	// append
1177	parent->child = newBus;
1178
1179	return newBus;
1180}
1181
1182
1183PCIDev *
1184PCI::_CreateDevice(PCIBus *parent, uint8 device, uint8 function)
1185{
1186	FLOW("PCI: CreateDevice, domain %u, bus %u, dev %u, func %u:\n", parent->domain,
1187		parent->bus, device, function);
1188
1189	PCIDev *newDev = new(std::nothrow) PCIDev;
1190	if (newDev == NULL)
1191		return NULL;
1192
1193	newDev->next = NULL;
1194	newDev->parent = parent;
1195	newDev->child = NULL;
1196	newDev->domain = parent->domain;
1197	newDev->bus = parent->bus;
1198	newDev->device = device;
1199	newDev->function = function;
1200	memset(&newDev->info, 0, sizeof(newDev->info));
1201
1202	_ReadBasicInfo(newDev);
1203
1204	FLOW("PCI: CreateDevice, vendor 0x%04x, device 0x%04x, class_base 0x%02x, "
1205		"class_sub 0x%02x\n", newDev->info.vendor_id, newDev->info.device_id,
1206		newDev->info.class_base, newDev->info.class_sub);
1207
1208	// append
1209	if (parent->child == NULL) {
1210		parent->child = newDev;
1211	} else {
1212		PCIDev *sub = parent->child;
1213		while (sub->next)
1214			sub = sub->next;
1215		sub->next = newDev;
1216	}
1217
1218	return newDev;
1219}
1220
1221
1222uint64
1223PCI::_BarSize(uint64 bits)
1224{
1225	if (!bits)
1226		return 0;
1227
1228	uint64 size = 1;
1229	while ((bits & size) == 0)
1230		size <<= 1;
1231
1232	return size;
1233}
1234
1235
1236size_t
1237PCI::_GetBarInfo(PCIDev *dev, uint8 offset, uint32 &_ramAddress,
1238	uint32 &_pciAddress, uint32 &_size, uint8 &flags, uint32 *_highRAMAddress,
1239	uint32 *_highPCIAddress, uint32 *_highSize)
1240{
1241	uint64 pciAddress = ReadConfig(dev->domain, dev->bus, dev->device,
1242		dev->function, offset, 4);
1243	WriteConfig(dev->domain, dev->bus, dev->device, dev->function, offset, 4,
1244		0xffffffff);
1245	uint64 size = ReadConfig(dev->domain, dev->bus, dev->device, dev->function,
1246		offset, 4);
1247	WriteConfig(dev->domain, dev->bus, dev->device, dev->function, offset, 4,
1248		pciAddress);
1249
1250	uint32 mask = PCI_address_memory_32_mask;
1251	bool is64bit = false;
1252	if ((pciAddress & PCI_address_space) != 0)
1253		mask = PCI_address_io_mask;
1254	else {
1255		is64bit = (pciAddress & PCI_address_type) == PCI_address_type_64;
1256
1257		if (is64bit && _highRAMAddress != NULL) {
1258			uint64 highPCIAddress = ReadConfig(dev->domain, dev->bus,
1259				dev->device, dev->function, offset + 4, 4);
1260			WriteConfig(dev->domain, dev->bus, dev->device, dev->function,
1261				offset + 4, 4, 0xffffffff);
1262			uint64 highSize = ReadConfig(dev->domain, dev->bus, dev->device,
1263				dev->function, offset + 4, 4);
1264			WriteConfig(dev->domain, dev->bus, dev->device, dev->function,
1265				offset + 4, 4, highPCIAddress);
1266
1267			pciAddress |= highPCIAddress << 32;
1268			size |= highSize << 32;
1269		}
1270	}
1271
1272	flags = (uint32)pciAddress & ~mask;
1273	pciAddress &= ((uint64)0xffffffff << 32) | mask;
1274	size &= ((uint64)0xffffffff << 32) | mask;
1275
1276	size = _BarSize(size);
1277	uint64 ramAddress = pci_ram_address(pciAddress);
1278
1279	_ramAddress = ramAddress;
1280	_pciAddress = pciAddress;
1281	_size = size;
1282	if (!is64bit)
1283		return 1;
1284
1285	if (_highRAMAddress == NULL || _highPCIAddress == NULL || _highSize == NULL)
1286		panic("64 bit PCI BAR but no space to store high values\n");
1287	else {
1288		*_highRAMAddress = ramAddress >> 32;
1289		*_highPCIAddress = pciAddress >> 32;
1290		*_highSize = size >> 32;
1291	}
1292
1293	return 2;
1294}
1295
1296
1297void
1298PCI::_GetRomBarInfo(PCIDev *dev, uint8 offset, uint32 &_address, uint32 *_size,
1299	uint8 *_flags)
1300{
1301	uint32 oldValue = ReadConfig(dev->domain, dev->bus, dev->device, dev->function,
1302		offset, 4);
1303	WriteConfig(dev->domain, dev->bus, dev->device, dev->function, offset, 4,
1304		0xfffffffe); // LSB must be 0
1305	uint32 newValue = ReadConfig(dev->domain, dev->bus, dev->device, dev->function,
1306		offset, 4);
1307	WriteConfig(dev->domain, dev->bus, dev->device, dev->function, offset, 4,
1308		oldValue);
1309
1310	_address = oldValue & PCI_rom_address_mask;
1311	if (_size != NULL)
1312		*_size = _BarSize(newValue & PCI_rom_address_mask);
1313	if (_flags != NULL)
1314		*_flags = newValue & 0xf;
1315}
1316
1317
1318void
1319PCI::_ReadBasicInfo(PCIDev *dev)
1320{
1321	uint8 virtualBus;
1322
1323	if (_CreateVirtualBus(dev->domain, dev->bus, &virtualBus) != B_OK) {
1324		dprintf("PCI: CreateVirtualBus failed, domain %u, bus %u\n", dev->domain, dev->bus);
1325		return;
1326	}
1327
1328	dev->info.vendor_id = ReadConfig(dev->domain, dev->bus, dev->device,
1329		dev->function, PCI_vendor_id, 2);
1330	dev->info.device_id = ReadConfig(dev->domain, dev->bus, dev->device,
1331		dev->function, PCI_device_id, 2);
1332	dev->info.bus = virtualBus;
1333	dev->info.device = dev->device;
1334	dev->info.function = dev->function;
1335	dev->info.revision = ReadConfig(dev->domain, dev->bus, dev->device,
1336		dev->function, PCI_revision, 1);
1337	dev->info.class_api = ReadConfig(dev->domain, dev->bus, dev->device,
1338		dev->function, PCI_class_api, 1);
1339	dev->info.class_sub = ReadConfig(dev->domain, dev->bus, dev->device,
1340		dev->function, PCI_class_sub, 1);
1341	dev->info.class_base = ReadConfig(dev->domain, dev->bus, dev->device,
1342		dev->function, PCI_class_base, 1);
1343	dev->info.line_size = ReadConfig(dev->domain, dev->bus, dev->device,
1344		dev->function, PCI_line_size, 1);
1345	dev->info.latency = ReadConfig(dev->domain, dev->bus, dev->device,
1346		dev->function, PCI_latency, 1);
1347	// BeOS does not mask off the multifunction bit, developer must use
1348	// (header_type & PCI_header_type_mask)
1349	dev->info.header_type = ReadConfig(dev->domain, dev->bus, dev->device,
1350		dev->function, PCI_header_type, 1);
1351	dev->info.bist = ReadConfig(dev->domain, dev->bus, dev->device,
1352		dev->function, PCI_bist, 1);
1353	dev->info.reserved = 0;
1354}
1355
1356
1357void
1358PCI::_ReadHeaderInfo(PCIDev *dev)
1359{
1360	switch (dev->info.header_type & PCI_header_type_mask) {
1361		case PCI_header_type_generic:
1362		{
1363			// disable PCI device address decoding (io and memory) while BARs
1364			// are modified
1365			uint16 pcicmd = ReadConfig(dev->domain, dev->bus, dev->device,
1366				dev->function, PCI_command, 2);
1367			WriteConfig(dev->domain, dev->bus, dev->device, dev->function,
1368				PCI_command, 2,
1369				pcicmd & ~(PCI_command_io | PCI_command_memory));
1370
1371			// get BAR size infos
1372			_GetRomBarInfo(dev, PCI_rom_base, dev->info.u.h0.rom_base_pci,
1373				&dev->info.u.h0.rom_size);
1374			for (int i = 0; i < 6;) {
1375				i += _GetBarInfo(dev, PCI_base_registers + 4 * i,
1376					dev->info.u.h0.base_registers[i],
1377					dev->info.u.h0.base_registers_pci[i],
1378					dev->info.u.h0.base_register_sizes[i],
1379					dev->info.u.h0.base_register_flags[i],
1380					i < 5 ? &dev->info.u.h0.base_registers[i + 1] : NULL,
1381					i < 5 ? &dev->info.u.h0.base_registers_pci[i + 1] : NULL,
1382					i < 5 ? &dev->info.u.h0.base_register_sizes[i + 1] : NULL);
1383			}
1384
1385			// restore PCI device address decoding
1386			WriteConfig(dev->domain, dev->bus, dev->device, dev->function,
1387				PCI_command, 2, pcicmd);
1388
1389			dev->info.u.h0.rom_base = (uint32)pci_ram_address(
1390				dev->info.u.h0.rom_base_pci);
1391
1392			dev->info.u.h0.cardbus_cis = ReadConfig(dev->domain, dev->bus,
1393				dev->device, dev->function, PCI_cardbus_cis, 4);
1394			dev->info.u.h0.subsystem_id = ReadConfig(dev->domain, dev->bus,
1395				dev->device, dev->function, PCI_subsystem_id, 2);
1396			dev->info.u.h0.subsystem_vendor_id = ReadConfig(dev->domain,
1397				dev->bus, dev->device, dev->function, PCI_subsystem_vendor_id,
1398				2);
1399			dev->info.u.h0.interrupt_line = ReadConfig(dev->domain, dev->bus,
1400				dev->device, dev->function, PCI_interrupt_line, 1);
1401			dev->info.u.h0.interrupt_pin = ReadConfig(dev->domain, dev->bus,
1402				dev->device, dev->function, PCI_interrupt_pin, 1);
1403			dev->info.u.h0.min_grant = ReadConfig(dev->domain, dev->bus,
1404				dev->device, dev->function, PCI_min_grant, 1);
1405			dev->info.u.h0.max_latency = ReadConfig(dev->domain, dev->bus,
1406				dev->device, dev->function, PCI_max_latency, 1);
1407			break;
1408		}
1409
1410		case PCI_header_type_PCI_to_PCI_bridge:
1411		{
1412			// disable PCI device address decoding (io and memory) while BARs
1413			// are modified
1414			uint16 pcicmd = ReadConfig(dev->domain, dev->bus, dev->device,
1415				dev->function, PCI_command, 2);
1416			WriteConfig(dev->domain, dev->bus, dev->device, dev->function,
1417				PCI_command, 2,
1418				pcicmd & ~(PCI_command_io | PCI_command_memory));
1419
1420			_GetRomBarInfo(dev, PCI_bridge_rom_base,
1421				dev->info.u.h1.rom_base_pci);
1422			for (int i = 0; i < 2;) {
1423				i += _GetBarInfo(dev, PCI_base_registers + 4 * i,
1424					dev->info.u.h1.base_registers[i],
1425					dev->info.u.h1.base_registers_pci[i],
1426					dev->info.u.h1.base_register_sizes[i],
1427					dev->info.u.h1.base_register_flags[i],
1428					i < 1 ? &dev->info.u.h1.base_registers[i + 1] : NULL,
1429					i < 1 ? &dev->info.u.h1.base_registers_pci[i + 1] : NULL,
1430					i < 1 ? &dev->info.u.h1.base_register_sizes[i + 1] : NULL);
1431			}
1432
1433			// restore PCI device address decoding
1434			WriteConfig(dev->domain, dev->bus, dev->device, dev->function,
1435				PCI_command, 2, pcicmd);
1436
1437			dev->info.u.h1.rom_base = (uint32)pci_ram_address(
1438				dev->info.u.h1.rom_base_pci);
1439
1440			dev->info.u.h1.primary_bus = ReadConfig(dev->domain, dev->bus,
1441				dev->device, dev->function, PCI_primary_bus, 1);
1442			dev->info.u.h1.secondary_bus = ReadConfig(dev->domain, dev->bus,
1443				dev->device, dev->function, PCI_secondary_bus, 1);
1444			dev->info.u.h1.subordinate_bus = ReadConfig(dev->domain,
1445				dev->bus, dev->device, dev->function, PCI_subordinate_bus, 1);
1446			dev->info.u.h1.secondary_latency = ReadConfig(dev->domain,
1447				dev->bus, dev->device, dev->function, PCI_secondary_latency, 1);
1448			dev->info.u.h1.io_base = ReadConfig(dev->domain, dev->bus,
1449				dev->device, dev->function, PCI_io_base, 1);
1450			dev->info.u.h1.io_limit = ReadConfig(dev->domain, dev->bus,
1451				dev->device, dev->function, PCI_io_limit, 1);
1452			dev->info.u.h1.secondary_status = ReadConfig(dev->domain,
1453				dev->bus, dev->device, dev->function, PCI_secondary_status, 2);
1454			dev->info.u.h1.memory_base = ReadConfig(dev->domain, dev->bus,
1455				dev->device, dev->function, PCI_memory_base, 2);
1456			dev->info.u.h1.memory_limit = ReadConfig(dev->domain, dev->bus,
1457				dev->device, dev->function, PCI_memory_limit, 2);
1458			dev->info.u.h1.prefetchable_memory_base = ReadConfig(dev->domain,
1459				dev->bus, dev->device, dev->function,
1460				PCI_prefetchable_memory_base, 2);
1461			dev->info.u.h1.prefetchable_memory_limit = ReadConfig(
1462				dev->domain, dev->bus, dev->device, dev->function,
1463				PCI_prefetchable_memory_limit, 2);
1464			dev->info.u.h1.prefetchable_memory_base_upper32 = ReadConfig(
1465				dev->domain, dev->bus, dev->device, dev->function,
1466				PCI_prefetchable_memory_base_upper32, 4);
1467			dev->info.u.h1.prefetchable_memory_limit_upper32 = ReadConfig(
1468				dev->domain, dev->bus, dev->device, dev->function,
1469				PCI_prefetchable_memory_limit_upper32, 4);
1470			dev->info.u.h1.io_base_upper16 = ReadConfig(dev->domain,
1471				dev->bus, dev->device, dev->function, PCI_io_base_upper16, 2);
1472			dev->info.u.h1.io_limit_upper16 = ReadConfig(dev->domain,
1473				dev->bus, dev->device, dev->function, PCI_io_limit_upper16, 2);
1474			dev->info.u.h1.interrupt_line = ReadConfig(dev->domain, dev->bus,
1475				dev->device, dev->function, PCI_interrupt_line, 1);
1476			dev->info.u.h1.interrupt_pin = ReadConfig(dev->domain, dev->bus,
1477				dev->device, dev->function, PCI_interrupt_pin, 1);
1478			dev->info.u.h1.bridge_control = ReadConfig(dev->domain, dev->bus,
1479				dev->device, dev->function, PCI_bridge_control, 2);
1480			dev->info.u.h1.subsystem_id = ReadConfig(dev->domain, dev->bus,
1481				dev->device, dev->function, PCI_sub_device_id_1, 2);
1482			dev->info.u.h1.subsystem_vendor_id = ReadConfig(dev->domain,
1483				dev->bus, dev->device, dev->function, PCI_sub_vendor_id_1, 2);
1484			break;
1485		}
1486
1487		case PCI_header_type_cardbus:
1488		{
1489			// for testing only, not final:
1490			dev->info.u.h2.subsystem_id = ReadConfig(dev->domain, dev->bus,
1491				dev->device, dev->function, PCI_sub_device_id_2, 2);
1492			dev->info.u.h2.subsystem_vendor_id = ReadConfig(dev->domain,
1493				dev->bus, dev->device, dev->function, PCI_sub_vendor_id_2, 2);
1494			dev->info.u.h2.primary_bus = ReadConfig(dev->domain, dev->bus,
1495				dev->device, dev->function, PCI_primary_bus_2, 1);
1496			dev->info.u.h2.secondary_bus = ReadConfig(dev->domain, dev->bus,
1497				dev->device, dev->function, PCI_secondary_bus_2, 1);
1498			dev->info.u.h2.subordinate_bus = ReadConfig(dev->domain,
1499				dev->bus, dev->device, dev->function, PCI_subordinate_bus_2, 1);
1500			dev->info.u.h2.secondary_latency = ReadConfig(dev->domain,
1501				dev->bus, dev->device, dev->function, PCI_secondary_latency_2, 1);
1502			dev->info.u.h2.reserved = 0;
1503			dev->info.u.h2.memory_base = ReadConfig(dev->domain, dev->bus,
1504				dev->device, dev->function, PCI_memory_base0_2, 4);
1505			dev->info.u.h2.memory_limit = ReadConfig(dev->domain, dev->bus,
1506				dev->device, dev->function, PCI_memory_limit0_2, 4);
1507			dev->info.u.h2.memory_base_upper32 = ReadConfig(dev->domain,
1508				dev->bus, dev->device, dev->function, PCI_memory_base1_2, 4);
1509			dev->info.u.h2.memory_limit_upper32 = ReadConfig(dev->domain,
1510				dev->bus, dev->device, dev->function, PCI_memory_limit1_2, 4);
1511			dev->info.u.h2.io_base = ReadConfig(dev->domain, dev->bus,
1512				dev->device, dev->function, PCI_io_base0_2, 4);
1513			dev->info.u.h2.io_limit = ReadConfig(dev->domain, dev->bus,
1514				dev->device, dev->function, PCI_io_limit0_2, 4);
1515			dev->info.u.h2.io_base_upper32 = ReadConfig(dev->domain,
1516				dev->bus, dev->device, dev->function, PCI_io_base1_2, 4);
1517			dev->info.u.h2.io_limit_upper32 = ReadConfig(dev->domain,
1518				dev->bus, dev->device, dev->function, PCI_io_limit1_2, 4);
1519			dev->info.u.h2.secondary_status = ReadConfig(dev->domain,
1520				dev->bus, dev->device, dev->function, PCI_secondary_status_2, 2);
1521			dev->info.u.h2.bridge_control = ReadConfig(dev->domain,
1522				dev->bus, dev->device, dev->function, PCI_bridge_control_2, 2);
1523			break;
1524		}
1525
1526		default:
1527			TRACE(("PCI: Header type unknown (0x%02x)\n", dev->info.header_type));
1528			break;
1529	}
1530}
1531
1532
1533void
1534PCI::RefreshDeviceInfo()
1535{
1536	for (uint32 domain = 0; domain < fDomainCount; domain++)
1537		_RefreshDeviceInfo(fDomainData[domain].bus);
1538}
1539
1540
1541void
1542PCI::_RefreshDeviceInfo(PCIBus *bus)
1543{
1544	for (PCIDev *dev = bus->child; dev; dev = dev->next) {
1545		_ReadBasicInfo(dev);
1546		_ReadHeaderInfo(dev);
1547		_ReadMSIInfo(dev);
1548		_ReadMSIXInfo(dev);
1549		_ReadHtMappingInfo(dev);
1550		if (dev->child)
1551			_RefreshDeviceInfo(dev->child);
1552	}
1553}
1554
1555
1556status_t
1557PCI::ReadConfig(uint8 domain, uint8 bus, uint8 device, uint8 function,
1558	uint16 offset, uint8 size, uint32 *value)
1559{
1560	domain_data *info = _GetDomainData(domain);
1561	if (!info)
1562		return B_ERROR;
1563
1564	if (device > (info->max_bus_devices - 1)
1565		|| function > 7
1566		|| (size != 1 && size != 2 && size != 4)
1567		|| (size == 2 && (offset & 3) == 3)
1568		|| (size == 4 && (offset & 3) != 0)) {
1569		dprintf("PCI: can't read config for domain %d, bus %u, device %u, function %u, offset %u, size %u\n",
1570			 domain, bus, device, function, offset, size);
1571		return B_ERROR;
1572	}
1573
1574	return (*info->controller->read_pci_config)(info->controller_cookie, bus,
1575		device, function, offset, size, value);
1576}
1577
1578
1579uint32
1580PCI::ReadConfig(uint8 domain, uint8 bus, uint8 device, uint8 function,
1581	uint16 offset, uint8 size)
1582{
1583	uint32 value;
1584	if (ReadConfig(domain, bus, device, function, offset, size, &value)
1585			!= B_OK)
1586		return 0xffffffff;
1587
1588	return value;
1589}
1590
1591
1592uint32
1593PCI::ReadConfig(PCIDev *device, uint16 offset, uint8 size)
1594{
1595	uint32 value;
1596	if (ReadConfig(device->domain, device->bus, device->device,
1597			device->function, offset, size, &value) != B_OK)
1598		return 0xffffffff;
1599
1600	return value;
1601}
1602
1603
1604status_t
1605PCI::WriteConfig(uint8 domain, uint8 bus, uint8 device, uint8 function,
1606	uint16 offset, uint8 size, uint32 value)
1607{
1608	domain_data *info = _GetDomainData(domain);
1609	if (!info)
1610		return B_ERROR;
1611
1612	if (device > (info->max_bus_devices - 1)
1613		|| function > 7
1614		|| (size != 1 && size != 2 && size != 4)
1615		|| (size == 2 && (offset & 3) == 3)
1616		|| (size == 4 && (offset & 3) != 0)) {
1617		dprintf("PCI: can't write config for domain %d, bus %u, device %u, function %u, offset %u, size %u\n",
1618			 domain, bus, device, function, offset, size);
1619		return B_ERROR;
1620	}
1621
1622	return (*info->controller->write_pci_config)(info->controller_cookie, bus,
1623		device, function, offset, size, value);
1624}
1625
1626
1627status_t
1628PCI::WriteConfig(PCIDev *device, uint16 offset, uint8 size, uint32 value)
1629{
1630	return WriteConfig(device->domain, device->bus, device->device,
1631		device->function, offset, size, value);
1632}
1633
1634
1635status_t
1636PCI::FindCapability(uint8 domain, uint8 bus, uint8 device, uint8 function,
1637	uint8 capID, uint8 *offset)
1638{
1639	uint16 status = ReadConfig(domain, bus, device, function, PCI_status, 2);
1640	if (!(status & PCI_status_capabilities)) {
1641		FLOW("PCI: find_pci_capability ERROR %u:%u:%u capability %#02x "
1642			"not supported\n", bus, device, function, capID);
1643		return B_ERROR;
1644	}
1645
1646	uint8 headerType = ReadConfig(domain, bus, device, function,
1647		PCI_header_type, 1);
1648	uint8 capPointer;
1649
1650	switch (headerType & PCI_header_type_mask) {
1651		case PCI_header_type_generic:
1652		case PCI_header_type_PCI_to_PCI_bridge:
1653			capPointer = PCI_capabilities_ptr;
1654			break;
1655		case PCI_header_type_cardbus:
1656			capPointer = PCI_capabilities_ptr_2;
1657			break;
1658		default:
1659			TRACE_CAP("PCI: find_pci_capability ERROR %u:%u:%u capability "
1660				"%#02x unknown header type\n", bus, device, function, capID);
1661			return B_ERROR;
1662	}
1663
1664	capPointer = ReadConfig(domain, bus, device, function, capPointer, 1);
1665	capPointer &= ~3;
1666	if (capPointer == 0) {
1667		TRACE_CAP("PCI: find_pci_capability ERROR %u:%u:%u capability %#02x "
1668			"empty list\n", bus, device, function, capID);
1669		return B_NAME_NOT_FOUND;
1670	}
1671
1672	for (int i = 0; i < 48; i++) {
1673		if (ReadConfig(domain, bus, device, function, capPointer, 1) == capID) {
1674			if (offset != NULL)
1675				*offset = capPointer;
1676			return B_OK;
1677		}
1678
1679		capPointer = ReadConfig(domain, bus, device, function, capPointer + 1,
1680			1);
1681		capPointer &= ~3;
1682
1683		if (capPointer == 0)
1684			return B_NAME_NOT_FOUND;
1685	}
1686
1687	TRACE_CAP("PCI: find_pci_capability ERROR %u:%u:%u capability %#02x circular list\n", bus, device, function, capID);
1688	return B_ERROR;
1689}
1690
1691
1692status_t
1693PCI::FindCapability(PCIDev *device, uint8 capID, uint8 *offset)
1694{
1695	return FindCapability(device->domain, device->bus, device->device,
1696		device->function, capID, offset);
1697}
1698
1699
1700status_t
1701PCI::FindExtendedCapability(uint8 domain, uint8 bus, uint8 device,
1702	uint8 function, uint16 capID, uint16 *offset)
1703{
1704	if (FindCapability(domain, bus, device, function, PCI_cap_id_pcie)
1705		!= B_OK) {
1706		FLOW("PCI:FindExtendedCapability ERROR %u:%u:%u capability %#02x "
1707			"not supported\n", bus, device, function, capID);
1708		return B_ERROR;
1709	}
1710	uint16 capPointer = PCI_extended_capability;
1711	uint32 capability = ReadConfig(domain, bus, device, function,
1712		capPointer, 4);
1713
1714	if (capability == 0 || capability == 0xffffffff)
1715			return B_NAME_NOT_FOUND;
1716
1717	for (int i = 0; i < 48; i++) {
1718		if (PCI_extcap_id(capability) == capID) {
1719			if (offset != NULL)
1720				*offset = capPointer;
1721			return B_OK;
1722		}
1723
1724		capPointer = PCI_extcap_next_ptr(capability) & ~3;
1725		if (capPointer < PCI_extended_capability)
1726			return B_NAME_NOT_FOUND;
1727		capability = ReadConfig(domain, bus, device, function,
1728			capPointer, 4);
1729	}
1730
1731	TRACE_CAP("PCI:FindExtendedCapability ERROR %u:%u:%u capability %#04x "
1732		"circular list\n", bus, device, function, capID);
1733	return B_ERROR;
1734}
1735
1736
1737status_t
1738PCI::FindExtendedCapability(PCIDev *device, uint16 capID, uint16 *offset)
1739{
1740	return FindExtendedCapability(device->domain, device->bus, device->device,
1741		device->function, capID, offset);
1742}
1743
1744
1745status_t
1746PCI::FindHTCapability(uint8 domain, uint8 bus, uint8 device,
1747	uint8 function, uint16 capID, uint8 *offset)
1748{
1749	uint8 capPointer;
1750	// consider the passed offset as the current ht capability block pointer
1751	// when it's non zero
1752	if (offset != NULL && *offset != 0) {
1753		capPointer = ReadConfig(domain, bus, device, function, *offset + 1,
1754			1);
1755	} else if (FindCapability(domain, bus, device, function, PCI_cap_id_ht,
1756		&capPointer) != B_OK) {
1757		FLOW("PCI:FindHTCapability ERROR %u:%u:%u capability %#02x "
1758			"not supported\n", bus, device, function, capID);
1759		return B_NAME_NOT_FOUND;
1760	}
1761
1762	uint16 mask = PCI_ht_command_cap_mask_5_bits;
1763	if (capID == PCI_ht_command_cap_slave || capID == PCI_ht_command_cap_host)
1764		mask = PCI_ht_command_cap_mask_3_bits;
1765	for (int i = 0; i < 48; i++) {
1766		capPointer &= ~3;
1767		if (capPointer == 0)
1768			return B_NAME_NOT_FOUND;
1769
1770		uint8 capability = ReadConfig(domain, bus, device, function,
1771			capPointer, 1);
1772		if (capability == PCI_cap_id_ht) {
1773			if ((ReadConfig(domain, bus, device, function,
1774					capPointer + PCI_ht_command, 2) & mask) == capID) {
1775				if (offset != NULL)
1776					*offset = capPointer;
1777				return B_OK;
1778			}
1779		}
1780
1781		capPointer = ReadConfig(domain, bus, device, function, capPointer + 1,
1782			1);
1783	}
1784
1785	TRACE_CAP("PCI:FindHTCapability ERROR %u:%u:%u capability %#04x "
1786		"circular list\n", bus, device, function, capID);
1787	return B_ERROR;
1788}
1789
1790
1791status_t
1792PCI::FindHTCapability(PCIDev *device, uint16 capID, uint8 *offset)
1793{
1794	return FindHTCapability(device->domain, device->bus, device->device,
1795		device->function, capID, offset);
1796}
1797
1798
1799PCIDev *
1800PCI::FindDevice(uint8 domain, uint8 bus, uint8 device, uint8 function)
1801{
1802	if (domain >= fDomainCount)
1803		return NULL;
1804
1805	return _FindDevice(fDomainData[domain].bus, domain, bus, device, function);
1806}
1807
1808
1809PCIDev *
1810PCI::_FindDevice(PCIBus *current, uint8 domain, uint8 bus, uint8 device,
1811	uint8 function)
1812{
1813	if (current->domain == domain) {
1814		// search device on this bus
1815
1816		for (PCIDev *child = current->child; child != NULL;
1817				child = child->next) {
1818			if (child->bus == bus && child->device == device
1819				&& child->function == function)
1820				return child;
1821
1822			if (child->child != NULL) {
1823				// search child busses
1824				PCIDev *found = _FindDevice(child->child, domain, bus, device,
1825					function);
1826				if (found != NULL)
1827					return found;
1828			}
1829		}
1830	}
1831
1832	return NULL;
1833}
1834
1835
1836status_t
1837PCI::UpdateInterruptLine(uint8 domain, uint8 bus, uint8 _device, uint8 function,
1838	uint8 newInterruptLineValue)
1839{
1840	PCIDev *device = FindDevice(domain, bus, _device, function);
1841	if (device == NULL)
1842		return B_ERROR;
1843
1844	pci_info &info = device->info;
1845	switch (info.header_type & PCI_header_type_mask) {
1846		case PCI_header_type_generic:
1847			info.u.h0.interrupt_line = newInterruptLineValue;
1848			break;
1849
1850		case PCI_header_type_PCI_to_PCI_bridge:
1851			info.u.h1.interrupt_line = newInterruptLineValue;
1852			break;
1853
1854		default:
1855			return B_ERROR;
1856	}
1857
1858	return WriteConfig(device, PCI_interrupt_line, 1, newInterruptLineValue);
1859}
1860
1861
1862uint8
1863PCI::GetPowerstate(PCIDev *device)
1864{
1865	uint8 capabilityOffset;
1866	status_t res = FindCapability(device, PCI_cap_id_pm, &capabilityOffset);
1867	if (res == B_OK) {
1868		uint32 state = ReadConfig(device, capabilityOffset + PCI_pm_status, 2);
1869		return (state & PCI_pm_mask);
1870	}
1871	return PCI_pm_state_d0;
1872}
1873
1874
1875void
1876PCI::SetPowerstate(PCIDev *device, uint8 newState)
1877{
1878	uint8 capabilityOffset;
1879	status_t res = FindCapability(device, PCI_cap_id_pm, &capabilityOffset);
1880	if (res == B_OK) {
1881		uint32 state = ReadConfig(device, capabilityOffset + PCI_pm_status, 2);
1882		if ((state & PCI_pm_mask) != newState) {
1883			WriteConfig(device, capabilityOffset + PCI_pm_status, 2,
1884				(state & ~PCI_pm_mask) | newState);
1885			if ((state & PCI_pm_mask) == PCI_pm_state_d3)
1886				snooze(10);
1887		}
1888	}
1889}
1890
1891
1892status_t
1893PCI::GetPowerstate(uint8 domain, uint8 bus, uint8 _device, uint8 function,
1894	uint8* state)
1895{
1896	PCIDev *device = FindDevice(domain, bus, _device, function);
1897	if (device == NULL)
1898		return B_ERROR;
1899
1900	*state = GetPowerstate(device);
1901	return B_OK;
1902}
1903
1904
1905status_t
1906PCI::SetPowerstate(uint8 domain, uint8 bus, uint8 _device, uint8 function,
1907	uint8 newState)
1908{
1909	PCIDev *device = FindDevice(domain, bus, _device, function);
1910	if (device == NULL)
1911		return B_ERROR;
1912
1913	SetPowerstate(device, newState);
1914	return B_OK;
1915}
1916
1917
1918//#pragma mark - MSI
1919
1920uint32
1921PCI::GetMSICount(PCIDev *device)
1922{
1923	if (!msi_supported())
1924		return 0;
1925
1926	msi_info *info = &device->msi;
1927	if (!info->msi_capable)
1928		return 0;
1929
1930	return info->message_count;
1931}
1932
1933
1934status_t
1935PCI::ConfigureMSI(PCIDev *device, uint32 count, uint32 *startVector)
1936{
1937	if (!msi_supported())
1938		return B_UNSUPPORTED;
1939
1940	if (count == 0 || startVector == NULL)
1941		return B_BAD_VALUE;
1942
1943	msi_info *info = &device->msi;
1944	if (!info->msi_capable)
1945		return B_UNSUPPORTED;
1946
1947	if (count > 32 || count > info->message_count
1948		|| ((count - 1) & count) != 0 /* needs to be a power of 2 */) {
1949		return B_BAD_VALUE;
1950	}
1951
1952	if (info->configured_count != 0)
1953		return B_BUSY;
1954
1955	status_t result = msi_allocate_vectors(count, &info->start_vector,
1956		&info->address_value, &info->data_value);
1957	if (result != B_OK)
1958		return result;
1959
1960	uint8 offset = info->capability_offset;
1961	WriteConfig(device, offset + PCI_msi_address, 4,
1962		info->address_value & 0xffffffff);
1963	if (info->control_value & PCI_msi_control_64bit) {
1964		WriteConfig(device, offset + PCI_msi_address_high, 4,
1965			info->address_value >> 32);
1966		WriteConfig(device, offset + PCI_msi_data_64bit, 2,
1967			info->data_value);
1968	} else
1969		WriteConfig(device, offset + PCI_msi_data, 2, info->data_value);
1970
1971	info->control_value &= ~PCI_msi_control_mme_mask;
1972	info->control_value |= (ffs(count) - 1) << 4;
1973	WriteConfig(device, offset + PCI_msi_control, 2, info->control_value);
1974
1975	info->configured_count = count;
1976	*startVector = info->start_vector;
1977	return B_OK;
1978}
1979
1980
1981status_t
1982PCI::UnconfigureMSI(PCIDev *device)
1983{
1984	if (!msi_supported())
1985		return B_UNSUPPORTED;
1986
1987	// try MSI-X
1988	status_t result = _UnconfigureMSIX(device);
1989	if (result != B_UNSUPPORTED && result != B_NO_INIT)
1990		return result;
1991
1992	msi_info *info =  &device->msi;
1993	if (!info->msi_capable)
1994		return B_UNSUPPORTED;
1995
1996	if (info->configured_count == 0)
1997		return B_NO_INIT;
1998
1999	msi_free_vectors(info->configured_count, info->start_vector);
2000
2001	info->control_value &= ~PCI_msi_control_mme_mask;
2002	WriteConfig(device, info->capability_offset + PCI_msi_control, 2,
2003		info->control_value);
2004
2005	info->configured_count = 0;
2006	info->address_value = 0;
2007	info->data_value = 0;
2008	return B_OK;
2009}
2010
2011
2012status_t
2013PCI::EnableMSI(PCIDev *device)
2014{
2015	if (!msi_supported())
2016		return B_UNSUPPORTED;
2017
2018	msi_info *info =  &device->msi;
2019	if (!info->msi_capable)
2020		return B_UNSUPPORTED;
2021
2022	if (info->configured_count == 0)
2023		return B_NO_INIT;
2024
2025	// ensure the pinned interrupt is disabled
2026	WriteConfig(device, PCI_command, 2,
2027		ReadConfig(device, PCI_command, 2) | PCI_command_int_disable);
2028
2029	// enable msi generation
2030	info->control_value |= PCI_msi_control_enable;
2031	WriteConfig(device, info->capability_offset + PCI_msi_control, 2,
2032		info->control_value);
2033
2034	// enable HT msi mapping (if applicable)
2035	_HtMSIMap(device, info->address_value);
2036
2037	dprintf("msi enabled: 0x%04" B_PRIx32 "\n",
2038		ReadConfig(device, info->capability_offset + PCI_msi_control, 2));
2039	return B_OK;
2040}
2041
2042
2043status_t
2044PCI::DisableMSI(PCIDev *device)
2045{
2046	if (!msi_supported())
2047		return B_UNSUPPORTED;
2048
2049	// try MSI-X
2050	status_t result = _DisableMSIX(device);
2051	if (result != B_UNSUPPORTED && result != B_NO_INIT)
2052		return result;
2053
2054	msi_info *info =  &device->msi;
2055	if (!info->msi_capable)
2056		return B_UNSUPPORTED;
2057
2058	if (info->configured_count == 0)
2059		return B_NO_INIT;
2060
2061	// disable HT msi mapping (if applicable)
2062	_HtMSIMap(device, 0);
2063
2064	// disable msi generation
2065	info->control_value &= ~PCI_msi_control_enable;
2066	WriteConfig(device, info->capability_offset + PCI_msi_control, 2,
2067		info->control_value);
2068
2069	return B_OK;
2070}
2071
2072
2073uint32
2074PCI::GetMSIXCount(PCIDev *device)
2075{
2076	if (!msi_supported())
2077		return 0;
2078
2079	msix_info *info = &device->msix;
2080	if (!info->msix_capable)
2081		return 0;
2082
2083	return info->message_count;
2084}
2085
2086
2087status_t
2088PCI::ConfigureMSIX(PCIDev *device, uint32 count, uint32 *startVector)
2089{
2090	if (!msi_supported())
2091		return B_UNSUPPORTED;
2092
2093	if (count == 0 || startVector == NULL)
2094		return B_BAD_VALUE;
2095
2096	msix_info *info = &device->msix;
2097	if (!info->msix_capable)
2098		return B_UNSUPPORTED;
2099
2100	if (count > 32 || count > info->message_count) {
2101		return B_BAD_VALUE;
2102	}
2103
2104	if (info->configured_count != 0)
2105		return B_BUSY;
2106
2107	// map the table bar
2108	size_t tableSize = info->message_count * 16;
2109	addr_t address;
2110	phys_addr_t barAddr = device->info.u.h0.base_registers[info->table_bar];
2111	uchar flags = device->info.u.h0.base_register_flags[info->table_bar];
2112	if ((flags & PCI_address_type) == PCI_address_type_64) {
2113		barAddr |= (uint64)device->info.u.h0.base_registers[
2114			info->table_bar + 1] << 32;
2115	}
2116	area_id area = map_physical_memory("msi table map",
2117		barAddr, tableSize + info->table_offset,
2118		B_ANY_KERNEL_ADDRESS, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA,
2119		(void**)&address);
2120	if (area < 0)
2121		return area;
2122	info->table_area_id = area;
2123	info->table_address = address + info->table_offset;
2124
2125	// and the pba bar if necessary
2126	if (info->table_bar != info->pba_bar) {
2127		barAddr = device->info.u.h0.base_registers[info->pba_bar];
2128		flags = device->info.u.h0.base_register_flags[info->pba_bar];
2129		if ((flags & PCI_address_type) == PCI_address_type_64) {
2130			barAddr |= (uint64)device->info.u.h0.base_registers[
2131				info->pba_bar + 1] << 32;
2132		}
2133		area = map_physical_memory("msi pba map",
2134			barAddr, tableSize + info->pba_offset,
2135			B_ANY_KERNEL_ADDRESS, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA,
2136			(void**)&address);
2137		if (area < 0) {
2138			delete_area(info->table_area_id);
2139			info->table_area_id = -1;
2140			return area;
2141		}
2142		info->pba_area_id = area;
2143	} else
2144		info->pba_area_id = -1;
2145	info->pba_address = address + info->pba_offset;
2146
2147	status_t result = msi_allocate_vectors(count, &info->start_vector,
2148		&info->address_value, &info->data_value);
2149	if (result != B_OK) {
2150		delete_area(info->pba_area_id);
2151		delete_area(info->table_area_id);
2152		info->pba_area_id = -1;
2153		info->table_area_id = -1;
2154		return result;
2155	}
2156
2157	// ensure the memory i/o is enabled
2158	WriteConfig(device, PCI_command, 2,
2159		ReadConfig(device, PCI_command, 2) | PCI_command_memory);
2160
2161	uint32 data_value = info->data_value;
2162	for (uint32 index = 0; index < count; index++) {
2163		volatile uint32 *entry = (uint32*)(info->table_address + 16 * index);
2164		*(entry + 3) |= PCI_msix_vctrl_mask;
2165		*entry++ = info->address_value & 0xffffffff;
2166		*entry++ = info->address_value >> 32;
2167		*entry++ = data_value++;
2168		*entry &= ~PCI_msix_vctrl_mask;
2169	}
2170
2171	info->configured_count = count;
2172	*startVector = info->start_vector;
2173	dprintf("msix configured for %" B_PRIu32 " vectors\n", count);
2174	return B_OK;
2175}
2176
2177
2178status_t
2179PCI::EnableMSIX(PCIDev *device)
2180{
2181	if (!msi_supported())
2182		return B_UNSUPPORTED;
2183
2184	msix_info *info = &device->msix;
2185	if (!info->msix_capable)
2186		return B_UNSUPPORTED;
2187
2188	if (info->configured_count == 0)
2189		return B_NO_INIT;
2190
2191	// ensure the pinned interrupt is disabled
2192	WriteConfig(device, PCI_command, 2,
2193		ReadConfig(device, PCI_command, 2) | PCI_command_int_disable);
2194
2195	// enable msi-x generation
2196	info->control_value |= PCI_msix_control_enable;
2197	WriteConfig(device, info->capability_offset + PCI_msix_control, 2,
2198		info->control_value);
2199
2200	// enable HT msi mapping (if applicable)
2201	_HtMSIMap(device, info->address_value);
2202
2203	dprintf("msi-x enabled: 0x%04" B_PRIx32 "\n",
2204		ReadConfig(device, info->capability_offset + PCI_msix_control, 2));
2205	return B_OK;
2206}
2207
2208
2209void
2210PCI::_HtMSIMap(PCIDev *device, uint64 address)
2211{
2212	ht_mapping_info *info = &device->ht_mapping;
2213	if (!info->ht_mapping_capable)
2214		return;
2215
2216	bool enabled = (info->control_value & PCI_ht_command_msi_enable) != 0;
2217	if ((address != 0) != enabled) {
2218		if (enabled) {
2219			info->control_value &= ~PCI_ht_command_msi_enable;
2220		} else {
2221			if ((address >> 20) != (info->address_value >> 20))
2222				return;
2223			dprintf("ht msi mapping enabled\n");
2224			info->control_value |= PCI_ht_command_msi_enable;
2225		}
2226		WriteConfig(device, info->capability_offset + PCI_ht_command, 2,
2227			info->control_value);
2228	}
2229}
2230
2231
2232void
2233PCI::_ReadMSIInfo(PCIDev *device)
2234{
2235	if (!msi_supported())
2236		return;
2237
2238	msi_info *info = &device->msi;
2239	info->msi_capable = false;
2240	status_t result = FindCapability(device->domain, device->bus,
2241		device->device, device->function, PCI_cap_id_msi,
2242		&info->capability_offset);
2243	if (result != B_OK)
2244		return;
2245
2246	info->msi_capable = true;
2247	info->control_value = ReadConfig(device->domain, device->bus,
2248		device->device, device->function,
2249		info->capability_offset + PCI_msi_control, 2);
2250	info->message_count
2251		= 1 << ((info->control_value & PCI_msi_control_mmc_mask) >> 1);
2252	info->configured_count = 0;
2253	info->data_value = 0;
2254	info->address_value = 0;
2255}
2256
2257
2258void
2259PCI::_ReadMSIXInfo(PCIDev *device)
2260{
2261	if (!msi_supported())
2262		return;
2263
2264	msix_info *info = &device->msix;
2265	info->msix_capable = false;
2266	status_t result = FindCapability(device->domain, device->bus,
2267		device->device, device->function, PCI_cap_id_msix,
2268		&info->capability_offset);
2269	if (result != B_OK)
2270		return;
2271
2272	info->msix_capable = true;
2273	info->control_value = ReadConfig(device->domain, device->bus,
2274		device->device, device->function,
2275		info->capability_offset + PCI_msix_control, 2);
2276	info->message_count
2277		= (info->control_value & PCI_msix_control_table_size) + 1;
2278	info->configured_count = 0;
2279	info->data_value = 0;
2280	info->address_value = 0;
2281	info->table_area_id = -1;
2282	info->pba_area_id = -1;
2283	uint32 table_value = ReadConfig(device->domain, device->bus,
2284		device->device, device->function,
2285		info->capability_offset + PCI_msix_table, 4);
2286	uint32 pba_value = ReadConfig(device->domain, device->bus,
2287		device->device, device->function,
2288		info->capability_offset + PCI_msix_pba, 4);
2289
2290	info->table_bar = table_value & PCI_msix_bir_mask;
2291	info->table_offset = table_value & PCI_msix_offset_mask;
2292	info->pba_bar = pba_value & PCI_msix_bir_mask;
2293	info->pba_offset = pba_value & PCI_msix_offset_mask;
2294}
2295
2296
2297void
2298PCI::_ReadHtMappingInfo(PCIDev *device)
2299{
2300	if (!msi_supported())
2301		return;
2302
2303	ht_mapping_info *info = &device->ht_mapping;
2304	info->ht_mapping_capable = false;
2305
2306	uint8 offset = 0;
2307	if (FindHTCapability(device, PCI_ht_command_cap_msi_mapping,
2308		&offset) == B_OK) {
2309		info->control_value = ReadConfig(device, offset + PCI_ht_command,
2310			2);
2311		info->capability_offset = offset;
2312		info->ht_mapping_capable = true;
2313		if ((info->control_value & PCI_ht_command_msi_fixed) != 0) {
2314#if defined(__i386__) || defined(__x86_64__)
2315			info->address_value = MSI_ADDRESS_BASE;
2316#else
2317			// TODO: investigate what should be set here for non-x86
2318			dprintf("PCI_ht_command_msi_fixed flag unimplemented\n");
2319			info->address_value = 0;
2320#endif
2321		} else {
2322			info->address_value = ReadConfig(device, offset
2323				+ PCI_ht_msi_address_high, 4);
2324			info->address_value <<= 32;
2325			info->address_value |= ReadConfig(device, offset
2326				+ PCI_ht_msi_address_low, 4);
2327		}
2328		dprintf("found an ht msi mapping at %#" B_PRIx64 "\n",
2329			info->address_value);
2330	}
2331}
2332
2333
2334status_t
2335PCI::_UnconfigureMSIX(PCIDev *device)
2336{
2337	msix_info *info =  &device->msix;
2338	if (!info->msix_capable)
2339		return B_UNSUPPORTED;
2340
2341	if (info->configured_count == 0)
2342		return B_NO_INIT;
2343
2344	// disable msi-x generation
2345	info->control_value &= ~PCI_msix_control_enable;
2346	WriteConfig(device, info->capability_offset + PCI_msix_control, 2,
2347		info->control_value);
2348
2349	msi_free_vectors(info->configured_count, info->start_vector);
2350	for (uint8 index = 0; index < info->configured_count; index++) {
2351		volatile uint32 *entry = (uint32*)(info->table_address + 16 * index);
2352		if ((*(entry + 3) & PCI_msix_vctrl_mask) == 0)
2353			*(entry + 3) |= PCI_msix_vctrl_mask;
2354	}
2355
2356	if (info->pba_area_id != -1)
2357		delete_area(info->pba_area_id);
2358	if (info->table_area_id != -1)
2359		delete_area(info->table_area_id);
2360	info->pba_area_id= -1;
2361	info->table_area_id = -1;
2362
2363	info->configured_count = 0;
2364	info->address_value = 0;
2365	info->data_value = 0;
2366	return B_OK;
2367}
2368
2369
2370status_t
2371PCI::_DisableMSIX(PCIDev *device)
2372{
2373	msix_info *info =  &device->msix;
2374	if (!info->msix_capable)
2375		return B_UNSUPPORTED;
2376
2377	if (info->configured_count == 0)
2378		return B_NO_INIT;
2379
2380	// disable HT msi mapping (if applicable)
2381	_HtMSIMap(device, 0);
2382
2383	// disable msi-x generation
2384	info->control_value &= ~PCI_msix_control_enable;
2385	gPCI->WriteConfig(device, info->capability_offset + PCI_msix_control, 2,
2386		info->control_value);
2387
2388	return B_OK;
2389}
2390