BPicture: Fix archive constructor.
[haiku.git] / src / add-ons / kernel / bus_managers / pci / pci.cpp
blob14ae42f23eff0324b4f6febbd0953db443e868de
1 /*
2 * Copyright 2003-2008, Marcus Overhagen. All rights reserved.
3 * Copyright 2005-2008, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
5 * Distributed under the terms of the MIT License.
6 */
9 #include <string.h>
10 #include <KernelExport.h>
11 #define __HAIKU_PCI_BUS_MANAGER_TESTING 1
12 #include <PCI.h>
14 #include "util/kernel_cpp.h"
15 #include "pci_fixup.h"
16 #include "pci_info.h"
17 #include "pci_private.h"
18 #include "pci.h"
20 #define TRACE_CAP(x...) dprintf(x)
21 #define FLOW(x...)
22 //#define FLOW(x...) dprintf(x)
25 PCI *gPCI;
28 // #pragma mark bus manager exports
31 status_t
32 pci_controller_add(pci_controller *controller, void *cookie)
34 return gPCI->AddController(controller, cookie);
38 long
39 pci_get_nth_pci_info(long index, pci_info *outInfo)
41 return gPCI->GetNthInfo(index, outInfo);
45 uint32
46 pci_read_config(uint8 virtualBus, uint8 device, uint8 function, uint16 offset,
47 uint8 size)
49 uint8 bus;
50 uint8 domain;
51 uint32 value;
53 if (gPCI->ResolveVirtualBus(virtualBus, &domain, &bus) != B_OK)
54 return 0xffffffff;
56 if (gPCI->ReadConfig(domain, bus, device, function, offset, size,
57 &value) != B_OK)
58 return 0xffffffff;
60 return value;
64 void
65 pci_write_config(uint8 virtualBus, uint8 device, uint8 function, uint16 offset,
66 uint8 size, uint32 value)
68 uint8 bus;
69 uint8 domain;
70 if (gPCI->ResolveVirtualBus(virtualBus, &domain, &bus) != B_OK)
71 return;
73 gPCI->WriteConfig(domain, bus, device, function, offset, size, value);
77 status_t
78 pci_find_capability(uint8 virtualBus, uint8 device, uint8 function,
79 uint8 capID, uint8 *offset)
81 uint8 bus;
82 uint8 domain;
83 if (gPCI->ResolveVirtualBus(virtualBus, &domain, &bus) != B_OK)
84 return B_ERROR;
86 return gPCI->FindCapability(domain, bus, device, function, capID, offset);
90 status_t
91 pci_find_extended_capability(uint8 virtualBus, uint8 device, uint8 function,
92 uint16 capID, uint16 *offset)
94 uint8 bus;
95 uint8 domain;
96 if (gPCI->ResolveVirtualBus(virtualBus, &domain, &bus) != B_OK)
97 return B_ERROR;
99 return gPCI->FindExtendedCapability(domain, bus, device, function, capID,
100 offset);
104 status_t
105 pci_reserve_device(uchar virtualBus, uchar device, uchar function,
106 const char *driverName, void *nodeCookie)
108 status_t status;
109 uint8 bus;
110 uint8 domain;
111 TRACE(("pci_reserve_device(%d, %d, %d, %s)\n", virtualBus, device, function,
112 driverName));
115 * we add 2 nodes to the PCI devices, one with constant attributes,
116 * so adding for another driver fails, and a subnode with the
117 * driver-provided informations.
120 if (gPCI->ResolveVirtualBus(virtualBus, &domain, &bus) != B_OK)
121 return B_ERROR;
123 //TRACE(("%s(%d [%d:%d], %d, %d, %s, %p)\n", __FUNCTION__, virtualBus,
124 // domain, bus, device, function, driverName, nodeCookie));
126 device_attr matchPCIRoot[] = {
127 {B_DEVICE_PRETTY_NAME, B_STRING_TYPE, {string: "PCI"}},
128 {NULL}
130 device_attr matchThis[] = {
131 // info about device
132 {B_DEVICE_BUS, B_STRING_TYPE, {string: "pci"}},
134 // location on PCI bus
135 {B_PCI_DEVICE_DOMAIN, B_UINT8_TYPE, {ui8: domain}},
136 {B_PCI_DEVICE_BUS, B_UINT8_TYPE, {ui8: bus}},
137 {B_PCI_DEVICE_DEVICE, B_UINT8_TYPE, {ui8: device}},
138 {B_PCI_DEVICE_FUNCTION, B_UINT8_TYPE, {ui8: function}},
139 {NULL}
141 device_attr legacyAttrs[] = {
142 // info about device
143 {B_DEVICE_BUS, B_STRING_TYPE, {string: "legacy_driver"}},
144 {B_DEVICE_PRETTY_NAME, B_STRING_TYPE, {string: "Legacy Driver Reservation"}},
145 {NULL}
147 device_attr drvAttrs[] = {
148 // info about device
149 {B_DEVICE_BUS, B_STRING_TYPE, {string: "legacy_driver"}},
150 {"legacy_driver", B_STRING_TYPE, {string: driverName}},
151 {"legacy_driver_cookie", B_UINT64_TYPE, {ui64: (uint64)nodeCookie}},
152 {NULL}
154 device_node *root, *pci, *node, *legacy;
156 status = B_DEVICE_NOT_FOUND;
157 root = gDeviceManager->get_root_node();
158 if (!root)
159 return status;
161 pci = NULL;
162 if (gDeviceManager->get_next_child_node(root, matchPCIRoot, &pci) < B_OK)
163 goto err0;
165 node = NULL;
166 if (gDeviceManager->get_next_child_node(pci, matchThis, &node) < B_OK)
167 goto err1;
169 // common API for all legacy modules ?
170 //status = legacy_driver_register(node, driverName, nodeCookie, PCI_LEGACY_DRIVER_MODULE_NAME);
172 status = gDeviceManager->register_node(node, PCI_LEGACY_DRIVER_MODULE_NAME,
173 legacyAttrs, NULL, &legacy);
174 if (status < B_OK)
175 goto err2;
177 status = gDeviceManager->register_node(legacy, PCI_LEGACY_DRIVER_MODULE_NAME,
178 drvAttrs, NULL, NULL);
179 if (status < B_OK)
180 goto err3;
182 gDeviceManager->put_node(node);
183 gDeviceManager->put_node(pci);
184 gDeviceManager->put_node(root);
186 return B_OK;
188 err3:
189 gDeviceManager->unregister_node(legacy);
190 err2:
191 gDeviceManager->put_node(node);
192 err1:
193 gDeviceManager->put_node(pci);
194 err0:
195 gDeviceManager->put_node(root);
196 TRACE(("pci_reserve_device for driver %s failed: %s\n", driverName,
197 strerror(status)));
198 return status;
202 status_t
203 pci_unreserve_device(uchar virtualBus, uchar device, uchar function,
204 const char *driverName, void *nodeCookie)
206 status_t status;
207 uint8 bus;
208 uint8 domain;
209 TRACE(("pci_unreserve_device(%d, %d, %d, %s)\n", virtualBus, device,
210 function, driverName));
212 if (gPCI->ResolveVirtualBus(virtualBus, &domain, &bus) != B_OK)
213 return B_ERROR;
215 //TRACE(("%s(%d [%d:%d], %d, %d, %s, %p)\n", __FUNCTION__, virtualBus,
216 // domain, bus, device, function, driverName, nodeCookie));
218 device_attr matchPCIRoot[] = {
219 {B_DEVICE_PRETTY_NAME, B_STRING_TYPE, {string: "PCI"}},
220 {NULL}
222 device_attr matchThis[] = {
223 // info about device
224 {B_DEVICE_BUS, B_STRING_TYPE, {string: "pci"}},
226 // location on PCI bus
227 {B_PCI_DEVICE_DOMAIN, B_UINT8_TYPE, {ui8: domain}},
228 {B_PCI_DEVICE_BUS, B_UINT8_TYPE, {ui8: bus}},
229 {B_PCI_DEVICE_DEVICE, B_UINT8_TYPE, {ui8: device}},
230 {B_PCI_DEVICE_FUNCTION, B_UINT8_TYPE, {ui8: function}},
231 {NULL}
233 device_attr legacyAttrs[] = {
234 // info about device
235 {B_DEVICE_BUS, B_STRING_TYPE, {string: "legacy_driver"}},
236 {B_DEVICE_PRETTY_NAME, B_STRING_TYPE, {string: "Legacy Driver Reservation"}},
237 {NULL}
239 device_attr drvAttrs[] = {
240 // info about device
241 {B_DEVICE_BUS, B_STRING_TYPE, {string: "legacy_driver"}},
242 {"legacy_driver", B_STRING_TYPE, {string: driverName}},
243 {"legacy_driver_cookie", B_UINT64_TYPE, {ui64: (uint64)nodeCookie}},
244 {NULL}
246 device_node *root, *pci, *node, *legacy, *drv;
248 status = B_DEVICE_NOT_FOUND;
249 root = gDeviceManager->get_root_node();
250 if (!root)
251 return status;
253 pci = NULL;
254 if (gDeviceManager->get_next_child_node(root, matchPCIRoot, &pci) < B_OK)
255 goto err0;
257 node = NULL;
258 if (gDeviceManager->get_next_child_node(pci, matchThis, &node) < B_OK)
259 goto err1;
261 // common API for all legacy modules ?
262 //status = legacy_driver_unregister(node, driverName, nodeCookie);
264 legacy = NULL;
265 if (gDeviceManager->get_next_child_node(node, legacyAttrs, &legacy) < B_OK)
266 goto err2;
268 drv = NULL;
269 if (gDeviceManager->get_next_child_node(legacy, drvAttrs, &drv) < B_OK)
270 goto err3;
272 gDeviceManager->put_node(drv);
273 status = gDeviceManager->unregister_node(drv);
274 //dprintf("unreg:drv:%s\n", strerror(status));
276 gDeviceManager->put_node(legacy);
277 status = gDeviceManager->unregister_node(legacy);
278 //dprintf("unreg:legacy:%s\n", strerror(status));
279 // we'll get EBUSY here anyway...
281 gDeviceManager->put_node(node);
282 gDeviceManager->put_node(pci);
283 gDeviceManager->put_node(root);
284 return B_OK;
286 err3:
287 gDeviceManager->put_node(legacy);
288 err2:
289 gDeviceManager->put_node(node);
290 err1:
291 gDeviceManager->put_node(pci);
292 err0:
293 gDeviceManager->put_node(root);
294 TRACE(("pci_unreserve_device for driver %s failed: %s\n", driverName,
295 strerror(status)));
296 return status;
300 status_t
301 pci_update_interrupt_line(uchar virtualBus, uchar device, uchar function,
302 uchar newInterruptLineValue)
304 uint8 bus;
305 uint8 domain;
306 if (gPCI->ResolveVirtualBus(virtualBus, &domain, &bus) != B_OK)
307 return B_ERROR;
309 return gPCI->UpdateInterruptLine(domain, bus, device, function,
310 newInterruptLineValue);
314 // used by pci_info.cpp print_info_basic()
315 void
316 __pci_resolve_virtual_bus(uint8 virtualBus, uint8 *domain, uint8 *bus)
318 if (gPCI->ResolveVirtualBus(virtualBus, domain, bus) < B_OK)
319 panic("ResolveVirtualBus failed");
323 // #pragma mark kernel debugger commands
326 static int
327 display_io(int argc, char **argv)
329 int32 displayWidth;
330 int32 itemSize;
331 int32 num = 1;
332 int address;
333 int i = 1, j;
335 switch (argc) {
336 case 3:
337 num = atoi(argv[2]);
338 case 2:
339 address = strtoul(argv[1], NULL, 0);
340 break;
341 default:
342 kprintf("usage: %s <address> [num]\n", argv[0]);
343 return 0;
346 // build the format string
347 if (strcmp(argv[0], "inb") == 0 || strcmp(argv[0], "in8") == 0) {
348 itemSize = 1;
349 displayWidth = 16;
350 } else if (strcmp(argv[0], "ins") == 0 || strcmp(argv[0], "in16") == 0) {
351 itemSize = 2;
352 displayWidth = 8;
353 } else if (strcmp(argv[0], "inw") == 0 || strcmp(argv[0], "in32") == 0) {
354 itemSize = 4;
355 displayWidth = 4;
356 } else {
357 kprintf("display_io called in an invalid way!\n");
358 return 0;
361 for (i = 0; i < num; i++) {
362 if ((i % displayWidth) == 0) {
363 int32 displayed = min_c(displayWidth, (num-i)) * itemSize;
364 if (i != 0)
365 kprintf("\n");
367 kprintf("[0x%" B_PRIx32 "] ", address + i * itemSize);
369 if (num > displayWidth) {
370 // make sure the spacing in the last line is correct
371 for (j = displayed; j < displayWidth * itemSize; j++)
372 kprintf(" ");
374 kprintf(" ");
377 switch (itemSize) {
378 case 1:
379 kprintf(" %02" B_PRIx8, pci_read_io_8(address + i * itemSize));
380 break;
381 case 2:
382 kprintf(" %04" B_PRIx16, pci_read_io_16(address + i * itemSize));
383 break;
384 case 4:
385 kprintf(" %08" B_PRIx32, pci_read_io_32(address + i * itemSize));
386 break;
390 kprintf("\n");
391 return 0;
395 static int
396 write_io(int argc, char **argv)
398 int32 itemSize;
399 uint32 value;
400 int address;
401 int i = 1;
403 if (argc < 3) {
404 kprintf("usage: %s <address> <value> [value [...]]\n", argv[0]);
405 return 0;
408 address = strtoul(argv[1], NULL, 0);
410 if (strcmp(argv[0], "outb") == 0 || strcmp(argv[0], "out8") == 0) {
411 itemSize = 1;
412 } else if (strcmp(argv[0], "outs") == 0 || strcmp(argv[0], "out16") == 0) {
413 itemSize = 2;
414 } else if (strcmp(argv[0], "outw") == 0 || strcmp(argv[0], "out32") == 0) {
415 itemSize = 4;
416 } else {
417 kprintf("write_io called in an invalid way!\n");
418 return 0;
421 // skip cmd name and address
422 argv += 2;
423 argc -= 2;
425 for (i = 0; i < argc; i++) {
426 value = strtoul(argv[i], NULL, 0);
427 switch (itemSize) {
428 case 1:
429 pci_write_io_8(address + i * itemSize, value);
430 break;
431 case 2:
432 pci_write_io_16(address + i * itemSize, value);
433 break;
434 case 4:
435 pci_write_io_32(address + i * itemSize, value);
436 break;
440 return 0;
444 static int
445 pcistatus(int argc, char **argv)
447 gPCI->ClearDeviceStatus(NULL, true);
448 return 0;
452 static int
453 pcirefresh(int argc, char **argv)
455 gPCI->RefreshDeviceInfo();
456 pci_print_info();
457 return 0;
461 // #pragma mark bus manager init/uninit
464 status_t
465 pci_init(void)
467 gPCI = new PCI;
469 if (pci_io_init() != B_OK) {
470 TRACE(("PCI: pci_io_init failed\n"));
471 return B_ERROR;
474 add_debugger_command("inw", &display_io, "dump io words (32-bit)");
475 add_debugger_command("in32", &display_io, "dump io words (32-bit)");
476 add_debugger_command("ins", &display_io, "dump io shorts (16-bit)");
477 add_debugger_command("in16", &display_io, "dump io shorts (16-bit)");
478 add_debugger_command("inb", &display_io, "dump io bytes (8-bit)");
479 add_debugger_command("in8", &display_io, "dump io bytes (8-bit)");
481 add_debugger_command("outw", &write_io, "write io words (32-bit)");
482 add_debugger_command("out32", &write_io, "write io words (32-bit)");
483 add_debugger_command("outs", &write_io, "write io shorts (16-bit)");
484 add_debugger_command("out16", &write_io, "write io shorts (16-bit)");
485 add_debugger_command("outb", &write_io, "write io bytes (8-bit)");
486 add_debugger_command("out8", &write_io, "write io bytes (8-bit)");
488 if (pci_controller_init() != B_OK) {
489 TRACE(("PCI: pci_controller_init failed\n"));
490 panic("PCI: pci_controller_init failed\n");
491 return B_ERROR;
494 gPCI->InitDomainData();
495 gPCI->InitBus();
497 add_debugger_command("pcistatus", &pcistatus, "dump and clear pci device status registers");
498 add_debugger_command("pcirefresh", &pcirefresh, "refresh and print all pci_info");
500 return B_OK;
504 void
505 pci_uninit(void)
507 remove_debugger_command("outw", &write_io);
508 remove_debugger_command("out32", &write_io);
509 remove_debugger_command("outs", &write_io);
510 remove_debugger_command("out16", &write_io);
511 remove_debugger_command("outb", &write_io);
512 remove_debugger_command("out8", &write_io);
514 remove_debugger_command("inw", &display_io);
515 remove_debugger_command("in32", &display_io);
516 remove_debugger_command("ins", &display_io);
517 remove_debugger_command("in16", &display_io);
518 remove_debugger_command("inb", &display_io);
519 remove_debugger_command("in8", &display_io);
521 remove_debugger_command("pcistatus", &pcistatus);
522 remove_debugger_command("pcirefresh", &pcirefresh);
524 delete gPCI;
528 // #pragma mark PCI class
531 PCI::PCI()
533 fRootBus(0),
534 fDomainCount(0),
535 fBusEnumeration(false),
536 fVirtualBusMap(),
537 fNextVirtualBus(0)
539 #if defined(__POWERPC__) || defined(__M68K__)
540 fBusEnumeration = true;
541 #endif
545 void
546 PCI::InitBus()
548 PCIBus **nextBus = &fRootBus;
549 for (uint8 i = 0; i < fDomainCount; i++) {
550 PCIBus *bus = new PCIBus;
551 bus->next = NULL;
552 bus->parent = NULL;
553 bus->child = NULL;
554 bus->domain = i;
555 bus->bus = 0;
556 *nextBus = bus;
557 nextBus = &bus->next;
560 if (fBusEnumeration) {
561 for (uint8 i = 0; i < fDomainCount; i++) {
562 _EnumerateBus(i, 0);
566 if (1) {
567 for (uint8 i = 0; i < fDomainCount; i++) {
568 _FixupDevices(i, 0);
572 if (fRootBus) {
573 _DiscoverBus(fRootBus);
574 _ConfigureBridges(fRootBus);
575 ClearDeviceStatus(fRootBus, false);
576 _RefreshDeviceInfo(fRootBus);
581 PCI::~PCI()
586 status_t
587 PCI::_CreateVirtualBus(uint8 domain, uint8 bus, uint8 *virtualBus)
589 #if defined(__INTEL__) || defined(__x86_64__)
591 // IA32 doesn't use domains
592 if (domain)
593 panic("PCI::CreateVirtualBus domain != 0");
594 *virtualBus = bus;
595 return B_OK;
597 #else
599 if (fNextVirtualBus > 0xff)
600 panic("PCI::CreateVirtualBus: virtual bus number space exhausted");
602 uint16 value = domain << 8 | bus;
604 for (VirtualBusMap::Iterator it = fVirtualBusMap.Begin();
605 it != fVirtualBusMap.End(); ++it) {
606 if (it->Value() == value) {
607 *virtualBus = it->Key();
608 FLOW("PCI::CreateVirtualBus: domain %d, bus %d already in map => "
609 "virtualBus %d\n", domain, bus, *virtualBus);
610 return B_OK;
614 *virtualBus = fNextVirtualBus++;
616 FLOW("PCI::CreateVirtualBus: domain %d, bus %d => virtualBus %d\n", domain,
617 bus, *virtualBus);
619 return fVirtualBusMap.Insert(*virtualBus, value);
621 #endif
625 status_t
626 PCI::ResolveVirtualBus(uint8 virtualBus, uint8 *domain, uint8 *bus)
628 #if defined(__INTEL__) || defined(__x86_64__)
630 // IA32 doesn't use domains
631 *bus = virtualBus;
632 *domain = 0;
633 return B_OK;
635 #else
637 if (virtualBus >= fNextVirtualBus)
638 return B_ERROR;
640 uint16 value = fVirtualBusMap.Get(virtualBus);
641 *domain = value >> 8;
642 *bus = value & 0xff;
643 return B_OK;
645 #endif
649 status_t
650 PCI::AddController(pci_controller *controller, void *controller_cookie)
652 if (fDomainCount == MAX_PCI_DOMAINS)
653 return B_ERROR;
655 fDomainData[fDomainCount].controller = controller;
656 fDomainData[fDomainCount].controller_cookie = controller_cookie;
658 // initialized later to avoid call back into controller at this point
659 fDomainData[fDomainCount].max_bus_devices = -1;
661 fDomainCount++;
662 return B_OK;
665 void
666 PCI::InitDomainData()
668 for (uint8 i = 0; i < fDomainCount; i++) {
669 int32 count;
670 status_t status;
672 status = (*fDomainData[i].controller->get_max_bus_devices)(
673 fDomainData[i].controller_cookie, &count);
674 fDomainData[i].max_bus_devices = (status == B_OK) ? count : 0;
679 domain_data *
680 PCI::_GetDomainData(uint8 domain)
682 if (domain >= fDomainCount)
683 return NULL;
685 return &fDomainData[domain];
689 inline int
690 PCI::_NumFunctions(uint8 domain, uint8 bus, uint8 device)
692 uint8 type = ReadConfig(domain, bus, device,
693 0, PCI_header_type, 1);
694 return (type & PCI_multifunction) != 0 ? 8 : 1;
698 status_t
699 PCI::GetNthInfo(long index, pci_info *outInfo)
701 long currentIndex = 0;
702 if (!fRootBus)
703 return B_ERROR;
705 return _GetNthInfo(fRootBus, &currentIndex, index, outInfo);
709 status_t
710 PCI::_GetNthInfo(PCIBus *bus, long *currentIndex, long wantIndex,
711 pci_info *outInfo)
713 // maps tree structure to linear indexed view
714 PCIDev *dev = bus->child;
715 while (dev) {
716 if (*currentIndex == wantIndex) {
717 *outInfo = dev->info;
718 return B_OK;
720 *currentIndex += 1;
721 if (dev->child && B_OK == _GetNthInfo(dev->child, currentIndex,
722 wantIndex, outInfo))
723 return B_OK;
724 dev = dev->next;
727 if (bus->next)
728 return _GetNthInfo(bus->next, currentIndex, wantIndex, outInfo);
730 return B_ERROR;
734 void
735 PCI::_EnumerateBus(uint8 domain, uint8 bus, uint8 *subordinateBus)
737 TRACE(("PCI: EnumerateBus: domain %u, bus %u\n", domain, bus));
739 int maxBusDevices = _GetDomainData(domain)->max_bus_devices;
741 // step 1: disable all bridges on this bus
742 for (int dev = 0; dev < maxBusDevices; dev++) {
743 uint16 vendor_id = ReadConfig(domain, bus, dev, 0, PCI_vendor_id, 2);
744 if (vendor_id == 0xffff)
745 continue;
747 int numFunctions = _NumFunctions(domain, bus, dev);
748 for (int function = 0; function < numFunctions; function++) {
749 uint16 device_id = ReadConfig(domain, bus, dev, function,
750 PCI_device_id, 2);
751 if (device_id == 0xffff)
752 continue;
754 uint8 baseClass = ReadConfig(domain, bus, dev, function,
755 PCI_class_base, 1);
756 uint8 subClass = ReadConfig(domain, bus, dev, function,
757 PCI_class_sub, 1);
758 if (baseClass != PCI_bridge || subClass != PCI_pci)
759 continue;
761 // skip incorrectly configured devices
762 uint8 headerType = ReadConfig(domain, bus, dev, function,
763 PCI_header_type, 1) & PCI_header_type_mask;
764 if (headerType != PCI_header_type_PCI_to_PCI_bridge)
765 continue;
767 TRACE(("PCI: found PCI-PCI bridge: domain %u, bus %u, dev %u, func %u\n",
768 domain, bus, dev, function));
769 TRACE(("PCI: original settings: pcicmd %04" B_PRIx32 ", primary-bus "
770 "%" B_PRIu32 ", secondary-bus %" B_PRIu32 ", subordinate-bus "
771 "%" B_PRIu32 "\n",
772 ReadConfig(domain, bus, dev, function, PCI_command, 2),
773 ReadConfig(domain, bus, dev, function, PCI_primary_bus, 1),
774 ReadConfig(domain, bus, dev, function, PCI_secondary_bus, 1),
775 ReadConfig(domain, bus, dev, function, PCI_subordinate_bus, 1)));
777 // disable decoding
778 uint16 pcicmd;
779 pcicmd = ReadConfig(domain, bus, dev, function, PCI_command, 2);
780 pcicmd &= ~(PCI_command_io | PCI_command_memory
781 | PCI_command_master);
782 WriteConfig(domain, bus, dev, function, PCI_command, 2, pcicmd);
784 // disable busses
785 WriteConfig(domain, bus, dev, function, PCI_primary_bus, 1, 0);
786 WriteConfig(domain, bus, dev, function, PCI_secondary_bus, 1, 0);
787 WriteConfig(domain, bus, dev, function, PCI_subordinate_bus, 1, 0);
789 TRACE(("PCI: disabled settings: pcicmd %04" B_PRIx32 ", primary-bus "
790 "%" B_PRIu32 ", secondary-bus %" B_PRIu32 ", subordinate-bus "
791 "%" B_PRIu32 "\n",
792 ReadConfig(domain, bus, dev, function, PCI_command, 2),
793 ReadConfig(domain, bus, dev, function, PCI_primary_bus, 1),
794 ReadConfig(domain, bus, dev, function, PCI_secondary_bus, 1),
795 ReadConfig(domain, bus, dev, function, PCI_subordinate_bus, 1)));
799 uint8 lastUsedBusNumber = bus;
801 // step 2: assign busses to all bridges, and enable them again
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;
807 int numFunctions = _NumFunctions(domain, bus, dev);
808 for (int function = 0; function < numFunctions; function++) {
809 uint16 deviceID = ReadConfig(domain, bus, dev, function,
810 PCI_device_id, 2);
811 if (deviceID == 0xffff)
812 continue;
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;
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;
827 TRACE(("PCI: configuring PCI-PCI bridge: domain %u, bus %u, dev %u, func %u\n",
828 domain, bus, dev, function));
830 // open Scheunentor for enumerating the bus behind the bridge
831 WriteConfig(domain, bus, dev, function, PCI_primary_bus, 1, bus);
832 WriteConfig(domain, bus, dev, function, PCI_secondary_bus, 1,
833 lastUsedBusNumber + 1);
834 WriteConfig(domain, bus, dev, function, PCI_subordinate_bus, 1, 255);
836 // enable decoding (too early here?)
837 uint16 pcicmd;
838 pcicmd = ReadConfig(domain, bus, dev, function, PCI_command, 2);
839 pcicmd |= PCI_command_io | PCI_command_memory | PCI_command_master;
840 WriteConfig(domain, bus, dev, function, PCI_command, 2, pcicmd);
842 TRACE(("PCI: probing settings: pcicmd %04" B_PRIx32 ", primary-bus "
843 "%" B_PRIu32 ", secondary-bus %" B_PRIu32 ", subordinate-bus "
844 "%" B_PRIu32 "\n",
845 ReadConfig(domain, bus, dev, function, PCI_command, 2),
846 ReadConfig(domain, bus, dev, function, PCI_primary_bus, 1),
847 ReadConfig(domain, bus, dev, function, PCI_secondary_bus, 1),
848 ReadConfig(domain, bus, dev, function, PCI_subordinate_bus, 1)));
850 // enumerate bus
851 _EnumerateBus(domain, lastUsedBusNumber + 1, &lastUsedBusNumber);
853 // close Scheunentor
854 WriteConfig(domain, bus, dev, function, PCI_subordinate_bus, 1, lastUsedBusNumber);
856 TRACE(("PCI: configured settings: pcicmd %04" B_PRIx32 ", primary-bus "
857 "%" B_PRIu32 ", secondary-bus %" B_PRIu32 ", subordinate-bus "
858 "%" B_PRIu32 "\n",
859 ReadConfig(domain, bus, dev, function, PCI_command, 2),
860 ReadConfig(domain, bus, dev, function, PCI_primary_bus, 1),
861 ReadConfig(domain, bus, dev, function, PCI_secondary_bus, 1),
862 ReadConfig(domain, bus, dev, function, PCI_subordinate_bus, 1)));
865 if (subordinateBus)
866 *subordinateBus = lastUsedBusNumber;
868 TRACE(("PCI: EnumerateBus done: domain %u, bus %u, last used bus number %u\n", domain, bus, lastUsedBusNumber));
872 void
873 PCI::_FixupDevices(uint8 domain, uint8 bus)
875 FLOW("PCI: FixupDevices domain %u, bus %u\n", domain, bus);
877 int maxBusDevices = _GetDomainData(domain)->max_bus_devices;
878 static int recursed = 0;
880 if (recursed++ > 10) {
881 // guard against buggy chipsets
882 // XXX: is there any official limit ?
883 dprintf("PCI: FixupDevices: too many recursions (buggy chipset?)\n");
884 recursed--;
885 return;
888 for (int dev = 0; dev < maxBusDevices; dev++) {
889 uint16 vendorId = ReadConfig(domain, bus, dev, 0, PCI_vendor_id, 2);
890 if (vendorId == 0xffff)
891 continue;
893 int numFunctions = _NumFunctions(domain, bus, dev);
894 for (int function = 0; function < numFunctions; function++) {
895 uint16 deviceId = ReadConfig(domain, bus, dev, function,
896 PCI_device_id, 2);
897 if (deviceId == 0xffff)
898 continue;
900 pci_fixup_device(this, domain, bus, dev, function);
902 uint8 baseClass = ReadConfig(domain, bus, dev, function,
903 PCI_class_base, 1);
904 if (baseClass != PCI_bridge)
905 continue;
906 uint8 subClass = ReadConfig(domain, bus, dev, function,
907 PCI_class_sub, 1);
908 if (subClass != PCI_pci)
909 continue;
911 // some FIC motherboards have a buggy BIOS...
912 // make sure the header type is correct for a bridge,
913 uint8 headerType = ReadConfig(domain, bus, dev, function,
914 PCI_header_type, 1) & PCI_header_type_mask;
915 if (headerType != PCI_header_type_PCI_to_PCI_bridge) {
916 dprintf("PCI: dom %u, bus %u, dev %2u, func %u, PCI bridge"
917 " class but wrong header type 0x%02x, ignoring.\n",
918 domain, bus, dev, function, headerType);
919 continue;
923 int busBehindBridge = ReadConfig(domain, bus, dev, function,
924 PCI_secondary_bus, 1);
926 TRACE(("PCI: FixupDevices: checking bus %d behind %04x:%04x\n",
927 busBehindBridge, vendorId, deviceId));
928 _FixupDevices(domain, busBehindBridge);
931 recursed--;
935 void
936 PCI::_ConfigureBridges(PCIBus *bus)
938 for (PCIDev *dev = bus->child; dev; dev = dev->next) {
939 if (dev->info.class_base == PCI_bridge
940 && dev->info.class_sub == PCI_pci
941 && (dev->info.header_type & PCI_header_type_mask)
942 == PCI_header_type_PCI_to_PCI_bridge) {
943 uint16 bridgeControlOld = ReadConfig(dev->domain, dev->bus,
944 dev->device, dev->function, PCI_bridge_control, 2);
945 uint16 bridgeControlNew = bridgeControlOld;
946 // Enable: Parity Error Response, SERR, Master Abort Mode, Discard
947 // Timer SERR
948 // Clear: Discard Timer Status
949 bridgeControlNew |= PCI_bridge_parity_error_response
950 | PCI_bridge_serr | PCI_bridge_master_abort
951 | PCI_bridge_discard_timer_status
952 | PCI_bridge_discard_timer_serr;
953 // Set discard timer to 2^15 PCI clocks
954 bridgeControlNew &= ~(PCI_bridge_primary_discard_timeout
955 | PCI_bridge_secondary_discard_timeout);
956 WriteConfig(dev->domain, dev->bus, dev->device, dev->function,
957 PCI_bridge_control, 2, bridgeControlNew);
958 bridgeControlNew = ReadConfig(dev->domain, dev->bus, dev->device,
959 dev->function, PCI_bridge_control, 2);
960 dprintf("PCI: dom %u, bus %u, dev %2u, func %u, changed PCI bridge"
961 " control from 0x%04x to 0x%04x\n", dev->domain, dev->bus,
962 dev->device, dev->function, bridgeControlOld,
963 bridgeControlNew);
966 if (dev->child)
967 _ConfigureBridges(dev->child);
970 if (bus->next)
971 _ConfigureBridges(bus->next);
975 void
976 PCI::ClearDeviceStatus(PCIBus *bus, bool dumpStatus)
978 if (!bus) {
979 if (!fRootBus)
980 return;
981 bus = fRootBus;
984 for (PCIDev *dev = bus->child; dev; dev = dev->next) {
985 // Clear and dump PCI device status
986 uint16 status = ReadConfig(dev->domain, dev->bus, dev->device,
987 dev->function, PCI_status, 2);
988 WriteConfig(dev->domain, dev->bus, dev->device, dev->function,
989 PCI_status, 2, status);
990 if (dumpStatus) {
991 kprintf("domain %u, bus %u, dev %2u, func %u, PCI device status "
992 "0x%04x\n", dev->domain, dev->bus, dev->device, dev->function,
993 status);
994 if (status & PCI_status_parity_error_detected)
995 kprintf(" Detected Parity Error\n");
996 if (status & PCI_status_serr_signalled)
997 kprintf(" Signalled System Error\n");
998 if (status & PCI_status_master_abort_received)
999 kprintf(" Received Master-Abort\n");
1000 if (status & PCI_status_target_abort_received)
1001 kprintf(" Received Target-Abort\n");
1002 if (status & PCI_status_target_abort_signalled)
1003 kprintf(" Signalled Target-Abort\n");
1004 if (status & PCI_status_parity_signalled)
1005 kprintf(" Master Data Parity Error\n");
1008 if (dev->info.class_base == PCI_bridge
1009 && dev->info.class_sub == PCI_pci) {
1010 // Clear and dump PCI bridge secondary status
1011 uint16 secondaryStatus = ReadConfig(dev->domain, dev->bus,
1012 dev->device, dev->function, PCI_secondary_status, 2);
1013 WriteConfig(dev->domain, dev->bus, dev->device, dev->function,
1014 PCI_secondary_status, 2, secondaryStatus);
1015 if (dumpStatus) {
1016 kprintf("domain %u, bus %u, dev %2u, func %u, PCI bridge "
1017 "secondary status 0x%04x\n", dev->domain, dev->bus,
1018 dev->device, dev->function, secondaryStatus);
1019 if (secondaryStatus & PCI_status_parity_error_detected)
1020 kprintf(" Detected Parity Error\n");
1021 if (secondaryStatus & PCI_status_serr_signalled)
1022 kprintf(" Received System Error\n");
1023 if (secondaryStatus & PCI_status_master_abort_received)
1024 kprintf(" Received Master-Abort\n");
1025 if (secondaryStatus & PCI_status_target_abort_received)
1026 kprintf(" Received Target-Abort\n");
1027 if (secondaryStatus & PCI_status_target_abort_signalled)
1028 kprintf(" Signalled Target-Abort\n");
1029 if (secondaryStatus & PCI_status_parity_signalled)
1030 kprintf(" Data Parity Reported\n");
1033 // Clear and dump the discard-timer error bit located in bridge-control register
1034 uint16 bridgeControl = ReadConfig(dev->domain, dev->bus,
1035 dev->device, dev->function, PCI_bridge_control, 2);
1036 WriteConfig(dev->domain, dev->bus, dev->device, dev->function,
1037 PCI_bridge_control, 2, bridgeControl);
1038 if (dumpStatus) {
1039 kprintf("domain %u, bus %u, dev %2u, func %u, PCI bridge "
1040 "control 0x%04x\n", dev->domain, dev->bus, dev->device,
1041 dev->function, bridgeControl);
1042 if (bridgeControl & PCI_bridge_discard_timer_status) {
1043 kprintf(" bridge-control: Discard Timer Error\n");
1048 if (dev->child)
1049 ClearDeviceStatus(dev->child, dumpStatus);
1052 if (bus->next)
1053 ClearDeviceStatus(bus->next, dumpStatus);
1057 void
1058 PCI::_DiscoverBus(PCIBus *bus)
1060 FLOW("PCI: DiscoverBus, domain %u, bus %u\n", bus->domain, bus->bus);
1062 int maxBusDevices = _GetDomainData(bus->domain)->max_bus_devices;
1063 static int recursed = 0;
1065 if (recursed++ > 10) {
1066 // guard against buggy chipsets
1067 // XXX: is there any official limit ?
1068 dprintf("PCI: DiscoverBus: too many recursions (buggy chipset?)\n");
1069 recursed--;
1070 return;
1073 for (int dev = 0; dev < maxBusDevices; dev++) {
1074 uint16 vendorID = ReadConfig(bus->domain, bus->bus, dev, 0,
1075 PCI_vendor_id, 2);
1076 if (vendorID == 0xffff)
1077 continue;
1079 int numFunctions = _NumFunctions(bus->domain, bus->bus, dev);
1080 for (int function = 0; function < numFunctions; function++)
1081 _DiscoverDevice(bus, dev, function);
1084 if (bus->next)
1085 _DiscoverBus(bus->next);
1086 recursed--;
1090 void
1091 PCI::_DiscoverDevice(PCIBus *bus, uint8 dev, uint8 function)
1093 FLOW("PCI: DiscoverDevice, domain %u, bus %u, dev %u, func %u\n", bus->domain, bus->bus, dev, function);
1095 uint16 deviceID = ReadConfig(bus->domain, bus->bus, dev, function,
1096 PCI_device_id, 2);
1097 if (deviceID == 0xffff)
1098 return;
1100 PCIDev *newDev = _CreateDevice(bus, dev, function);
1102 uint8 baseClass = ReadConfig(bus->domain, bus->bus, dev, function,
1103 PCI_class_base, 1);
1104 uint8 subClass = ReadConfig(bus->domain, bus->bus, dev, function,
1105 PCI_class_sub, 1);
1106 uint8 headerType = ReadConfig(bus->domain, bus->bus, dev, function,
1107 PCI_header_type, 1) & PCI_header_type_mask;
1108 if (baseClass == PCI_bridge && subClass == PCI_pci
1109 && headerType == PCI_header_type_PCI_to_PCI_bridge) {
1110 uint8 secondaryBus = ReadConfig(bus->domain, bus->bus, dev, function,
1111 PCI_secondary_bus, 1);
1112 PCIBus *newBus = _CreateBus(newDev, bus->domain, secondaryBus);
1113 _DiscoverBus(newBus);
1118 PCIBus *
1119 PCI::_CreateBus(PCIDev *parent, uint8 domain, uint8 bus)
1121 PCIBus *newBus = new(std::nothrow) PCIBus;
1122 if (newBus == NULL)
1123 return NULL;
1125 newBus->next = NULL;
1126 newBus->parent = parent;
1127 newBus->child = NULL;
1128 newBus->domain = domain;
1129 newBus->bus = bus;
1131 // append
1132 parent->child = newBus;
1134 return newBus;
1138 PCIDev *
1139 PCI::_CreateDevice(PCIBus *parent, uint8 device, uint8 function)
1141 FLOW("PCI: CreateDevice, domain %u, bus %u, dev %u, func %u:\n", parent->domain,
1142 parent->bus, device, function);
1144 PCIDev *newDev = new(std::nothrow) PCIDev;
1145 if (newDev == NULL)
1146 return NULL;
1148 newDev->next = NULL;
1149 newDev->parent = parent;
1150 newDev->child = NULL;
1151 newDev->domain = parent->domain;
1152 newDev->bus = parent->bus;
1153 newDev->device = device;
1154 newDev->function = function;
1155 memset(&newDev->info, 0, sizeof(newDev->info));
1157 _ReadBasicInfo(newDev);
1159 FLOW("PCI: CreateDevice, vendor 0x%04x, device 0x%04x, class_base 0x%02x, "
1160 "class_sub 0x%02x\n", newDev->info.vendor_id, newDev->info.device_id,
1161 newDev->info.class_base, newDev->info.class_sub);
1163 // append
1164 if (parent->child == NULL) {
1165 parent->child = newDev;
1166 } else {
1167 PCIDev *sub = parent->child;
1168 while (sub->next)
1169 sub = sub->next;
1170 sub->next = newDev;
1173 return newDev;
1177 uint32
1178 PCI::_BarSize(uint32 bits, uint32 mask)
1180 bits &= mask;
1181 if (!bits)
1182 return 0;
1183 uint32 size = 1;
1184 while (!(bits & size))
1185 size <<= 1;
1186 return size;
1190 size_t
1191 PCI::_GetBarInfo(PCIDev *dev, uint8 offset, uint32 *_address, uint32 *_size,
1192 uint8 *_flags, uint32 *_highAddress)
1194 uint32 oldValue = ReadConfig(dev->domain, dev->bus, dev->device, dev->function,
1195 offset, 4);
1196 WriteConfig(dev->domain, dev->bus, dev->device, dev->function, offset, 4,
1197 0xffffffff);
1198 uint32 newValue = ReadConfig(dev->domain, dev->bus, dev->device, dev->function,
1199 offset, 4);
1200 WriteConfig(dev->domain, dev->bus, dev->device, dev->function, offset, 4,
1201 oldValue);
1203 uint32 mask = PCI_address_memory_32_mask;
1204 bool is64bit = (oldValue & PCI_address_type_64) != 0;
1205 if ((oldValue & PCI_address_space) == PCI_address_space)
1206 mask = PCI_address_io_mask;
1207 else if (is64bit && _highAddress != NULL) {
1208 *_highAddress = ReadConfig(dev->domain, dev->bus, dev->device,
1209 dev->function, offset + 4, 4);
1212 *_address = oldValue & mask;
1213 if (_size != NULL)
1214 *_size = _BarSize(newValue, mask);
1215 if (_flags != NULL)
1216 *_flags = oldValue & ~mask;
1217 return is64bit ? 2 : 1;
1221 void
1222 PCI::_GetRomBarInfo(PCIDev *dev, uint8 offset, uint32 *_address, uint32 *_size,
1223 uint8 *_flags)
1225 uint32 oldValue = ReadConfig(dev->domain, dev->bus, dev->device, dev->function,
1226 offset, 4);
1227 WriteConfig(dev->domain, dev->bus, dev->device, dev->function, offset, 4,
1228 0xfffffffe); // LSB must be 0
1229 uint32 newValue = ReadConfig(dev->domain, dev->bus, dev->device, dev->function,
1230 offset, 4);
1231 WriteConfig(dev->domain, dev->bus, dev->device, dev->function, offset, 4,
1232 oldValue);
1234 *_address = oldValue & PCI_rom_address_mask;
1235 if (_size != NULL)
1236 *_size = _BarSize(newValue, PCI_rom_address_mask);
1237 if (_flags != NULL)
1238 *_flags = newValue & 0xf;
1242 void
1243 PCI::_ReadBasicInfo(PCIDev *dev)
1245 uint8 virtualBus;
1247 if (_CreateVirtualBus(dev->domain, dev->bus, &virtualBus) != B_OK) {
1248 dprintf("PCI: CreateVirtualBus failed, domain %u, bus %u\n", dev->domain, dev->bus);
1249 return;
1252 dev->info.vendor_id = ReadConfig(dev->domain, dev->bus, dev->device,
1253 dev->function, PCI_vendor_id, 2);
1254 dev->info.device_id = ReadConfig(dev->domain, dev->bus, dev->device,
1255 dev->function, PCI_device_id, 2);
1256 dev->info.bus = virtualBus;
1257 dev->info.device = dev->device;
1258 dev->info.function = dev->function;
1259 dev->info.revision = ReadConfig(dev->domain, dev->bus, dev->device,
1260 dev->function, PCI_revision, 1);
1261 dev->info.class_api = ReadConfig(dev->domain, dev->bus, dev->device,
1262 dev->function, PCI_class_api, 1);
1263 dev->info.class_sub = ReadConfig(dev->domain, dev->bus, dev->device,
1264 dev->function, PCI_class_sub, 1);
1265 dev->info.class_base = ReadConfig(dev->domain, dev->bus, dev->device,
1266 dev->function, PCI_class_base, 1);
1267 dev->info.line_size = ReadConfig(dev->domain, dev->bus, dev->device,
1268 dev->function, PCI_line_size, 1);
1269 dev->info.latency = ReadConfig(dev->domain, dev->bus, dev->device,
1270 dev->function, PCI_latency, 1);
1271 // BeOS does not mask off the multifunction bit, developer must use
1272 // (header_type & PCI_header_type_mask)
1273 dev->info.header_type = ReadConfig(dev->domain, dev->bus, dev->device,
1274 dev->function, PCI_header_type, 1);
1275 dev->info.bist = ReadConfig(dev->domain, dev->bus, dev->device,
1276 dev->function, PCI_bist, 1);
1277 dev->info.reserved = 0;
1281 void
1282 PCI::_ReadHeaderInfo(PCIDev *dev)
1284 switch (dev->info.header_type & PCI_header_type_mask) {
1285 case PCI_header_type_generic:
1287 // disable PCI device address decoding (io and memory) while BARs
1288 // are modified
1289 uint16 pcicmd = ReadConfig(dev->domain, dev->bus, dev->device,
1290 dev->function, PCI_command, 2);
1291 WriteConfig(dev->domain, dev->bus, dev->device, dev->function,
1292 PCI_command, 2,
1293 pcicmd & ~(PCI_command_io | PCI_command_memory));
1295 // get BAR size infos
1296 _GetRomBarInfo(dev, PCI_rom_base, &dev->info.u.h0.rom_base_pci,
1297 &dev->info.u.h0.rom_size);
1298 for (int i = 0; i < 6;) {
1299 size_t barSize = _GetBarInfo(dev, PCI_base_registers + 4 * i,
1300 &dev->info.u.h0.base_registers_pci[i],
1301 &dev->info.u.h0.base_register_sizes[i],
1302 &dev->info.u.h0.base_register_flags[i],
1303 i < 5 ? &dev->info.u.h0.base_registers_pci[i + 1] : NULL);
1304 dev->info.u.h0.base_registers[i] = (addr_t)pci_ram_address(
1305 (void *)(addr_t)dev->info.u.h0.base_registers_pci[i]);
1306 i += barSize;
1309 // restore PCI device address decoding
1310 WriteConfig(dev->domain, dev->bus, dev->device, dev->function,
1311 PCI_command, 2, pcicmd);
1313 dev->info.u.h0.rom_base = (addr_t)pci_ram_address(
1314 (void *)(addr_t)dev->info.u.h0.rom_base_pci);
1316 dev->info.u.h0.cardbus_cis = ReadConfig(dev->domain, dev->bus,
1317 dev->device, dev->function, PCI_cardbus_cis, 4);
1318 dev->info.u.h0.subsystem_id = ReadConfig(dev->domain, dev->bus,
1319 dev->device, dev->function, PCI_subsystem_id, 2);
1320 dev->info.u.h0.subsystem_vendor_id = ReadConfig(dev->domain,
1321 dev->bus, dev->device, dev->function, PCI_subsystem_vendor_id, 2);
1322 dev->info.u.h0.interrupt_line = ReadConfig(dev->domain, dev->bus,
1323 dev->device, dev->function, PCI_interrupt_line, 1);
1324 dev->info.u.h0.interrupt_pin = ReadConfig(dev->domain, dev->bus,
1325 dev->device, dev->function, PCI_interrupt_pin, 1);
1326 dev->info.u.h0.min_grant = ReadConfig(dev->domain, dev->bus,
1327 dev->device, dev->function, PCI_min_grant, 1);
1328 dev->info.u.h0.max_latency = ReadConfig(dev->domain, dev->bus,
1329 dev->device, dev->function, PCI_max_latency, 1);
1330 break;
1333 case PCI_header_type_PCI_to_PCI_bridge:
1335 // disable PCI device address decoding (io and memory) while BARs are modified
1336 uint16 pcicmd = ReadConfig(dev->domain, dev->bus, dev->device,
1337 dev->function, PCI_command, 2);
1338 WriteConfig(dev->domain, dev->bus, dev->device, dev->function,
1339 PCI_command, 2,
1340 pcicmd & ~(PCI_command_io | PCI_command_memory));
1342 _GetRomBarInfo(dev, PCI_bridge_rom_base,
1343 &dev->info.u.h1.rom_base_pci);
1344 for (int i = 0; i < 2;) {
1345 size_t barSize = _GetBarInfo(dev, PCI_base_registers + 4 * i,
1346 &dev->info.u.h1.base_registers_pci[i],
1347 &dev->info.u.h1.base_register_sizes[i],
1348 &dev->info.u.h1.base_register_flags[i],
1349 i < 5 ? &dev->info.u.h1.base_registers_pci[i + 1] : NULL);
1350 dev->info.u.h1.base_registers[i] = (addr_t)pci_ram_address(
1351 (void *)(addr_t)dev->info.u.h1.base_registers_pci[i]);
1352 i += barSize;
1355 // restore PCI device address decoding
1356 WriteConfig(dev->domain, dev->bus, dev->device, dev->function,
1357 PCI_command, 2, pcicmd);
1359 dev->info.u.h1.rom_base = (addr_t)pci_ram_address(
1360 (void *)(addr_t)dev->info.u.h1.rom_base_pci);
1362 dev->info.u.h1.primary_bus = ReadConfig(dev->domain, dev->bus,
1363 dev->device, dev->function, PCI_primary_bus, 1);
1364 dev->info.u.h1.secondary_bus = ReadConfig(dev->domain, dev->bus,
1365 dev->device, dev->function, PCI_secondary_bus, 1);
1366 dev->info.u.h1.subordinate_bus = ReadConfig(dev->domain,
1367 dev->bus, dev->device, dev->function, PCI_subordinate_bus, 1);
1368 dev->info.u.h1.secondary_latency = ReadConfig(dev->domain,
1369 dev->bus, dev->device, dev->function, PCI_secondary_latency, 1);
1370 dev->info.u.h1.io_base = ReadConfig(dev->domain, dev->bus,
1371 dev->device, dev->function, PCI_io_base, 1);
1372 dev->info.u.h1.io_limit = ReadConfig(dev->domain, dev->bus,
1373 dev->device, dev->function, PCI_io_limit, 1);
1374 dev->info.u.h1.secondary_status = ReadConfig(dev->domain,
1375 dev->bus, dev->device, dev->function, PCI_secondary_status, 2);
1376 dev->info.u.h1.memory_base = ReadConfig(dev->domain, dev->bus,
1377 dev->device, dev->function, PCI_memory_base, 2);
1378 dev->info.u.h1.memory_limit = ReadConfig(dev->domain, dev->bus,
1379 dev->device, dev->function, PCI_memory_limit, 2);
1380 dev->info.u.h1.prefetchable_memory_base = ReadConfig(dev->domain,
1381 dev->bus, dev->device, dev->function, PCI_prefetchable_memory_base, 2);
1382 dev->info.u.h1.prefetchable_memory_limit = ReadConfig(
1383 dev->domain, dev->bus, dev->device, dev->function,
1384 PCI_prefetchable_memory_limit, 2);
1385 dev->info.u.h1.prefetchable_memory_base_upper32 = ReadConfig(
1386 dev->domain, dev->bus, dev->device, dev->function,
1387 PCI_prefetchable_memory_base_upper32, 4);
1388 dev->info.u.h1.prefetchable_memory_limit_upper32 = ReadConfig(
1389 dev->domain, dev->bus, dev->device, dev->function,
1390 PCI_prefetchable_memory_limit_upper32, 4);
1391 dev->info.u.h1.io_base_upper16 = ReadConfig(dev->domain,
1392 dev->bus, dev->device, dev->function, PCI_io_base_upper16, 2);
1393 dev->info.u.h1.io_limit_upper16 = ReadConfig(dev->domain,
1394 dev->bus, dev->device, dev->function, PCI_io_limit_upper16, 2);
1395 dev->info.u.h1.interrupt_line = ReadConfig(dev->domain, dev->bus,
1396 dev->device, dev->function, PCI_interrupt_line, 1);
1397 dev->info.u.h1.interrupt_pin = ReadConfig(dev->domain, dev->bus,
1398 dev->device, dev->function, PCI_interrupt_pin, 1);
1399 dev->info.u.h1.bridge_control = ReadConfig(dev->domain, dev->bus,
1400 dev->device, dev->function, PCI_bridge_control, 2);
1401 dev->info.u.h1.subsystem_id = ReadConfig(dev->domain, dev->bus,
1402 dev->device, dev->function, PCI_sub_device_id_1, 2);
1403 dev->info.u.h1.subsystem_vendor_id = ReadConfig(dev->domain,
1404 dev->bus, dev->device, dev->function, PCI_sub_vendor_id_1, 2);
1405 break;
1408 case PCI_header_type_cardbus:
1410 // for testing only, not final:
1411 dev->info.u.h2.subsystem_id = ReadConfig(dev->domain, dev->bus,
1412 dev->device, dev->function, PCI_sub_device_id_2, 2);
1413 dev->info.u.h2.subsystem_vendor_id = ReadConfig(dev->domain,
1414 dev->bus, dev->device, dev->function, PCI_sub_vendor_id_2, 2);
1415 dev->info.u.h2.primary_bus = ReadConfig(dev->domain, dev->bus,
1416 dev->device, dev->function, PCI_primary_bus_2, 1);
1417 dev->info.u.h2.secondary_bus = ReadConfig(dev->domain, dev->bus,
1418 dev->device, dev->function, PCI_secondary_bus_2, 1);
1419 dev->info.u.h2.subordinate_bus = ReadConfig(dev->domain,
1420 dev->bus, dev->device, dev->function, PCI_subordinate_bus_2, 1);
1421 dev->info.u.h2.secondary_latency = ReadConfig(dev->domain,
1422 dev->bus, dev->device, dev->function, PCI_secondary_latency_2, 1);
1423 dev->info.u.h2.reserved = 0;
1424 dev->info.u.h2.memory_base = ReadConfig(dev->domain, dev->bus,
1425 dev->device, dev->function, PCI_memory_base0_2, 4);
1426 dev->info.u.h2.memory_limit = ReadConfig(dev->domain, dev->bus,
1427 dev->device, dev->function, PCI_memory_limit0_2, 4);
1428 dev->info.u.h2.memory_base_upper32 = ReadConfig(dev->domain,
1429 dev->bus, dev->device, dev->function, PCI_memory_base1_2, 4);
1430 dev->info.u.h2.memory_limit_upper32 = ReadConfig(dev->domain,
1431 dev->bus, dev->device, dev->function, PCI_memory_limit1_2, 4);
1432 dev->info.u.h2.io_base = ReadConfig(dev->domain, dev->bus,
1433 dev->device, dev->function, PCI_io_base0_2, 4);
1434 dev->info.u.h2.io_limit = ReadConfig(dev->domain, dev->bus,
1435 dev->device, dev->function, PCI_io_limit0_2, 4);
1436 dev->info.u.h2.io_base_upper32 = ReadConfig(dev->domain,
1437 dev->bus, dev->device, dev->function, PCI_io_base1_2, 4);
1438 dev->info.u.h2.io_limit_upper32 = ReadConfig(dev->domain,
1439 dev->bus, dev->device, dev->function, PCI_io_limit1_2, 4);
1440 dev->info.u.h2.secondary_status = ReadConfig(dev->domain,
1441 dev->bus, dev->device, dev->function, PCI_secondary_status_2, 2);
1442 dev->info.u.h2.bridge_control = ReadConfig(dev->domain,
1443 dev->bus, dev->device, dev->function, PCI_bridge_control_2, 2);
1444 break;
1447 default:
1448 TRACE(("PCI: Header type unknown (0x%02x)\n", dev->info.header_type));
1449 break;
1454 void
1455 PCI::RefreshDeviceInfo()
1457 if (fRootBus == NULL)
1458 return;
1460 _RefreshDeviceInfo(fRootBus);
1464 void
1465 PCI::_RefreshDeviceInfo(PCIBus *bus)
1467 for (PCIDev *dev = bus->child; dev; dev = dev->next) {
1468 _ReadBasicInfo(dev);
1469 _ReadHeaderInfo(dev);
1470 #if defined(__INTEL__) || defined(__x86_64__)
1471 pci_read_arch_info(dev);
1472 #endif
1473 if (dev->child)
1474 _RefreshDeviceInfo(dev->child);
1477 if (bus->next)
1478 _RefreshDeviceInfo(bus->next);
1482 status_t
1483 PCI::ReadConfig(uint8 domain, uint8 bus, uint8 device, uint8 function,
1484 uint16 offset, uint8 size, uint32 *value)
1486 domain_data *info = _GetDomainData(domain);
1487 if (!info)
1488 return B_ERROR;
1490 if (device > (info->max_bus_devices - 1)
1491 || function > 7
1492 || (size != 1 && size != 2 && size != 4)
1493 || (size == 2 && (offset & 3) == 3)
1494 || (size == 4 && (offset & 3) != 0)) {
1495 dprintf("PCI: can't read config for domain %d, bus %u, device %u, function %u, offset %u, size %u\n",
1496 domain, bus, device, function, offset, size);
1497 return B_ERROR;
1500 return (*info->controller->read_pci_config)(info->controller_cookie, bus,
1501 device, function, offset, size, value);
1505 uint32
1506 PCI::ReadConfig(uint8 domain, uint8 bus, uint8 device, uint8 function,
1507 uint16 offset, uint8 size)
1509 uint32 value;
1510 if (ReadConfig(domain, bus, device, function, offset, size, &value)
1511 != B_OK)
1512 return 0xffffffff;
1514 return value;
1518 uint32
1519 PCI::ReadConfig(PCIDev *device, uint16 offset, uint8 size)
1521 uint32 value;
1522 if (ReadConfig(device->domain, device->bus, device->device,
1523 device->function, offset, size, &value) != B_OK)
1524 return 0xffffffff;
1526 return value;
1530 status_t
1531 PCI::WriteConfig(uint8 domain, uint8 bus, uint8 device, uint8 function,
1532 uint16 offset, uint8 size, uint32 value)
1534 domain_data *info = _GetDomainData(domain);
1535 if (!info)
1536 return B_ERROR;
1538 if (device > (info->max_bus_devices - 1)
1539 || function > 7
1540 || (size != 1 && size != 2 && size != 4)
1541 || (size == 2 && (offset & 3) == 3)
1542 || (size == 4 && (offset & 3) != 0)) {
1543 dprintf("PCI: can't write config for domain %d, bus %u, device %u, function %u, offset %u, size %u\n",
1544 domain, bus, device, function, offset, size);
1545 return B_ERROR;
1548 return (*info->controller->write_pci_config)(info->controller_cookie, bus,
1549 device, function, offset, size, value);
1553 status_t
1554 PCI::WriteConfig(PCIDev *device, uint16 offset, uint8 size, uint32 value)
1556 return WriteConfig(device->domain, device->bus, device->device,
1557 device->function, offset, size, value);
1561 status_t
1562 PCI::FindCapability(uint8 domain, uint8 bus, uint8 device, uint8 function,
1563 uint8 capID, uint8 *offset)
1565 uint16 status = ReadConfig(domain, bus, device, function, PCI_status, 2);
1566 if (!(status & PCI_status_capabilities)) {
1567 FLOW("PCI: find_pci_capability ERROR %u:%u:%u capability %#02x "
1568 "not supported\n", bus, device, function, capID);
1569 return B_ERROR;
1572 uint8 headerType = ReadConfig(domain, bus, device, function,
1573 PCI_header_type, 1);
1574 uint8 capPointer;
1576 switch (headerType & PCI_header_type_mask) {
1577 case PCI_header_type_generic:
1578 case PCI_header_type_PCI_to_PCI_bridge:
1579 capPointer = PCI_capabilities_ptr;
1580 break;
1581 case PCI_header_type_cardbus:
1582 capPointer = PCI_capabilities_ptr_2;
1583 break;
1584 default:
1585 TRACE_CAP("PCI: find_pci_capability ERROR %u:%u:%u capability "
1586 "%#02x unknown header type\n", bus, device, function, capID);
1587 return B_ERROR;
1590 capPointer = ReadConfig(domain, bus, device, function, capPointer, 1);
1591 capPointer &= ~3;
1592 if (capPointer == 0) {
1593 TRACE_CAP("PCI: find_pci_capability ERROR %u:%u:%u capability %#02x "
1594 "empty list\n", bus, device, function, capID);
1595 return B_NAME_NOT_FOUND;
1598 for (int i = 0; i < 48; i++) {
1599 if (ReadConfig(domain, bus, device, function, capPointer, 1) == capID) {
1600 if (offset != NULL)
1601 *offset = capPointer;
1602 return B_OK;
1605 capPointer = ReadConfig(domain, bus, device, function, capPointer + 1,
1607 capPointer &= ~3;
1609 if (capPointer == 0)
1610 return B_NAME_NOT_FOUND;
1613 TRACE_CAP("PCI: find_pci_capability ERROR %u:%u:%u capability %#02x circular list\n", bus, device, function, capID);
1614 return B_ERROR;
1618 status_t
1619 PCI::FindCapability(PCIDev *device, uint8 capID, uint8 *offset)
1621 return FindCapability(device->domain, device->bus, device->device,
1622 device->function, capID, offset);
1626 status_t
1627 PCI::FindExtendedCapability(uint8 domain, uint8 bus, uint8 device,
1628 uint8 function, uint16 capID, uint16 *offset)
1630 if (FindCapability(domain, bus, device, function, PCI_cap_id_pcie)
1631 != B_OK) {
1632 FLOW("PCI:FindExtendedCapability ERROR %u:%u:%u capability %#02x "
1633 "not supported\n", bus, device, function, capID);
1634 return B_ERROR;
1636 uint16 capPointer = PCI_extended_capability;
1637 uint32 capability = ReadConfig(domain, bus, device, function,
1638 capPointer, 4);
1640 if (capability == 0 || capability == 0xffffffff)
1641 return B_NAME_NOT_FOUND;
1643 for (int i = 0; i < 48; i++) {
1644 if (PCI_extcap_id(capability) == capID) {
1645 if (offset != NULL)
1646 *offset = capPointer;
1647 return B_OK;
1650 capPointer = PCI_extcap_next_ptr(capability) & ~3;
1651 if (capPointer < PCI_extended_capability)
1652 return B_NAME_NOT_FOUND;
1653 capability = ReadConfig(domain, bus, device, function,
1654 capPointer, 4);
1657 TRACE_CAP("PCI:FindExtendedCapability ERROR %u:%u:%u capability %#04x "
1658 "circular list\n", bus, device, function, capID);
1659 return B_ERROR;
1663 status_t
1664 PCI::FindExtendedCapability(PCIDev *device, uint16 capID, uint16 *offset)
1666 return FindExtendedCapability(device->domain, device->bus, device->device,
1667 device->function, capID, offset);
1671 status_t
1672 PCI::FindHTCapability(uint8 domain, uint8 bus, uint8 device,
1673 uint8 function, uint16 capID, uint8 *offset)
1675 uint8 capPointer;
1676 // consider the passed offset as the current ht capability block pointer
1677 // when it's non zero
1678 if (offset != NULL && *offset != 0) {
1679 capPointer = ReadConfig(domain, bus, device, function, *offset + 1,
1681 } else if (FindCapability(domain, bus, device, function, PCI_cap_id_ht,
1682 &capPointer) != B_OK) {
1683 FLOW("PCI:FindHTCapability ERROR %u:%u:%u capability %#02x "
1684 "not supported\n", bus, device, function, capID);
1685 return B_NAME_NOT_FOUND;
1688 uint16 mask = PCI_ht_command_cap_mask_5_bits;
1689 if (capID == PCI_ht_command_cap_slave || capID == PCI_ht_command_cap_host)
1690 mask = PCI_ht_command_cap_mask_3_bits;
1691 for (int i = 0; i < 48; i++) {
1692 capPointer &= ~3;
1693 if (capPointer == 0)
1694 return B_NAME_NOT_FOUND;
1696 uint8 capability = ReadConfig(domain, bus, device, function,
1697 capPointer, 1);
1698 if (capability == PCI_cap_id_ht) {
1699 if ((ReadConfig(domain, bus, device, function,
1700 capPointer + PCI_ht_command, 2) & mask) == capID) {
1701 if (offset != NULL)
1702 *offset = capPointer;
1703 return B_OK;
1707 capPointer = ReadConfig(domain, bus, device, function, capPointer + 1,
1711 TRACE_CAP("PCI:FindHTCapability ERROR %u:%u:%u capability %#04x "
1712 "circular list\n", bus, device, function, capID);
1713 return B_ERROR;
1717 status_t
1718 PCI::FindHTCapability(PCIDev *device, uint16 capID, uint8 *offset)
1720 return FindHTCapability(device->domain, device->bus, device->device,
1721 device->function, capID, offset);
1725 PCIDev *
1726 PCI::FindDevice(uint8 domain, uint8 bus, uint8 device, uint8 function)
1728 return _FindDevice(fRootBus, domain, bus, device, function);
1732 PCIDev *
1733 PCI::_FindDevice(PCIBus *current, uint8 domain, uint8 bus, uint8 device,
1734 uint8 function)
1736 if (current->domain == domain) {
1737 // search device on this bus
1739 for (PCIDev *child = current->child; child != NULL;
1740 child = child->next) {
1741 if (child->bus == bus && child->device == device
1742 && child->function == function)
1743 return child;
1745 if (child->child != NULL) {
1746 // search child busses
1747 PCIDev *found = _FindDevice(child->child, domain, bus, device,
1748 function);
1749 if (found != NULL)
1750 return found;
1755 // search other busses
1756 if (current->next != NULL)
1757 return _FindDevice(current->next, domain, bus, device, function);
1759 return NULL;
1763 status_t
1764 PCI::UpdateInterruptLine(uint8 domain, uint8 bus, uint8 _device, uint8 function,
1765 uint8 newInterruptLineValue)
1767 PCIDev *device = FindDevice(domain, bus, _device, function);
1768 if (device == NULL)
1769 return B_ERROR;
1771 pci_info &info = device->info;
1772 switch (info.header_type & PCI_header_type_mask) {
1773 case PCI_header_type_generic:
1774 info.u.h0.interrupt_line = newInterruptLineValue;
1775 break;
1777 case PCI_header_type_PCI_to_PCI_bridge:
1778 info.u.h1.interrupt_line = newInterruptLineValue;
1779 break;
1781 default:
1782 return B_ERROR;
1785 return WriteConfig(device, PCI_interrupt_line, 1, newInterruptLineValue);