1 /*
2 * Copyright 2003-2008, Marcus Overhagen. All rights reserved.
3 * Copyright 2005-2008, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
4 *
5 * Distributed under the terms of the MIT License.
6 */
7
8
9 #include <string.h>
10 #include <KernelExport.h>
11 #define __HAIKU_PCI_BUS_MANAGER_TESTING 1
12 #include <PCI.h>
13 #include <arch/generic/msi.h>
14 #if defined(__i386__) || defined(__x86_64__)
15 #include <arch/x86/msi.h>
16 #endif
17
18 #include "util/kernel_cpp.h"
19 #include "pci_fixup.h"
20 #include "pci_info.h"
21 #include "pci_private.h"
22 #include "pci.h"
23
24
25 #define TRACE_CAP(x...) dprintf(x)
26 #define FLOW(x...)
27 //#define FLOW(x...) dprintf(x)
28
29
30 PCI *gPCI;
31
32
33 // #pragma mark bus manager exports
34
35
36 long
pci_get_nth_pci_info(long index,pci_info * outInfo)37 pci_get_nth_pci_info(long index, pci_info *outInfo)
38 {
39 return gPCI->GetNthInfo(index, outInfo);
40 }
41
42
43 uint32
pci_read_config(uint8 virtualBus,uint8 device,uint8 function,uint16 offset,uint8 size)44 pci_read_config(uint8 virtualBus, uint8 device, uint8 function, uint16 offset,
45 uint8 size)
46 {
47 uint8 bus;
48 uint8 domain;
49 uint32 value;
50
51 if (gPCI->ResolveVirtualBus(virtualBus, &domain, &bus) != B_OK)
52 return 0xffffffff;
53
54 if (gPCI->ReadConfig(domain, bus, device, function, offset, size,
55 &value) != B_OK)
56 return 0xffffffff;
57
58 return value;
59 }
60
61
62 void
pci_write_config(uint8 virtualBus,uint8 device,uint8 function,uint16 offset,uint8 size,uint32 value)63 pci_write_config(uint8 virtualBus, uint8 device, uint8 function, uint16 offset,
64 uint8 size, uint32 value)
65 {
66 uint8 bus;
67 uint8 domain;
68 if (gPCI->ResolveVirtualBus(virtualBus, &domain, &bus) != B_OK)
69 return;
70
71 gPCI->WriteConfig(domain, bus, device, function, offset, size, value);
72 }
73
74
75 phys_addr_t
pci_ram_address(phys_addr_t childAdr)76 pci_ram_address(phys_addr_t childAdr)
77 {
78 phys_addr_t hostAdr = 0;
79 #if defined(__i386__) || defined(__x86_64__)
80 hostAdr = childAdr;
81 #else
82 uint8 domain;
83 pci_resource_range range;
84 if (gPCI->LookupRange(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
92 status_t
pci_find_capability(uint8 virtualBus,uint8 device,uint8 function,uint8 capID,uint8 * offset)93 pci_find_capability(uint8 virtualBus, uint8 device, uint8 function,
94 uint8 capID, uint8 *offset)
95 {
96 uint8 bus;
97 uint8 domain;
98 if (gPCI->ResolveVirtualBus(virtualBus, &domain, &bus) != B_OK)
99 return B_ERROR;
100
101 return gPCI->FindCapability(domain, bus, device, function, capID, offset);
102 }
103
104
105 status_t
pci_find_extended_capability(uint8 virtualBus,uint8 device,uint8 function,uint16 capID,uint16 * offset)106 pci_find_extended_capability(uint8 virtualBus, uint8 device, uint8 function,
107 uint16 capID, uint16 *offset)
108 {
109 uint8 bus;
110 uint8 domain;
111 if (gPCI->ResolveVirtualBus(virtualBus, &domain, &bus) != B_OK)
112 return B_ERROR;
113
114 return gPCI->FindExtendedCapability(domain, bus, device, function, capID,
115 offset);
116 }
117
118
119 status_t
pci_reserve_device(uchar virtualBus,uchar device,uchar function,const char * driverName,void * nodeCookie)120 pci_reserve_device(uchar virtualBus, uchar device, uchar function,
121 const char *driverName, void *nodeCookie)
122 {
123 status_t status;
124 uint8 bus;
125 uint8 domain;
126 TRACE(("pci_reserve_device(%d, %d, %d, %s)\n", virtualBus, device, function,
127 driverName));
128
129 /*
130 * we add 2 nodes to the PCI devices, one with constant attributes,
131 * so adding for another driver fails, and a subnode with the
132 * driver-provided informations.
133 */
134
135 if (gPCI->ResolveVirtualBus(virtualBus, &domain, &bus) != B_OK)
136 return B_ERROR;
137
138 //TRACE(("%s(%d [%d:%d], %d, %d, %s, %p)\n", __FUNCTION__, virtualBus,
139 // domain, bus, device, function, driverName, nodeCookie));
140
141 device_attr matchThis[] = {
142 // info about device
143 {B_DEVICE_BUS, B_STRING_TYPE, {.string = "pci"}},
144
145 // location on PCI bus
146 {B_PCI_DEVICE_DOMAIN, B_UINT8_TYPE, {.ui8 = domain}},
147 {B_PCI_DEVICE_BUS, B_UINT8_TYPE, {.ui8 = bus}},
148 {B_PCI_DEVICE_DEVICE, B_UINT8_TYPE, {.ui8 = device}},
149 {B_PCI_DEVICE_FUNCTION, B_UINT8_TYPE, {.ui8 = function}},
150 {NULL}
151 };
152 device_attr legacyAttrs[] = {
153 // info about device
154 {B_DEVICE_BUS, B_STRING_TYPE, {.string = "legacy_driver"}},
155 {B_DEVICE_PRETTY_NAME, B_STRING_TYPE, {.string = "Legacy Driver Reservation"}},
156 {NULL}
157 };
158 device_attr drvAttrs[] = {
159 // info about device
160 {B_DEVICE_BUS, B_STRING_TYPE, {.string = "legacy_driver"}},
161 {B_DEVICE_PRETTY_NAME, B_STRING_TYPE, {.string = driverName}},
162 {"legacy_driver", B_STRING_TYPE, {.string = driverName}},
163 {"legacy_driver_cookie", B_UINT64_TYPE, {.ui64 = (uint64)nodeCookie}},
164 {NULL}
165 };
166 device_node *node, *legacy;
167
168 status = B_DEVICE_NOT_FOUND;
169 device_node *root_pci_node = gPCI->_GetDomainData(domain)->root_node;
170
171 node = NULL;
172 if (gDeviceManager->get_next_child_node(root_pci_node,
173 matchThis, &node) < B_OK) {
174 goto err1;
175 }
176
177 // common API for all legacy modules ?
178 //status = legacy_driver_register(node, driverName, nodeCookie, PCI_LEGACY_DRIVER_MODULE_NAME);
179
180 status = gDeviceManager->register_node(node, PCI_LEGACY_DRIVER_MODULE_NAME,
181 legacyAttrs, NULL, &legacy);
182 if (status < B_OK)
183 goto err2;
184
185 status = gDeviceManager->register_node(legacy, PCI_LEGACY_DRIVER_MODULE_NAME,
186 drvAttrs, NULL, NULL);
187 if (status < B_OK)
188 goto err3;
189
190 gDeviceManager->put_node(node);
191
192 return B_OK;
193
194 err3:
195 gDeviceManager->unregister_node(legacy);
196 err2:
197 gDeviceManager->put_node(node);
198 err1:
199 TRACE(("pci_reserve_device for driver %s failed: %s\n", driverName,
200 strerror(status)));
201 return status;
202 }
203
204
205 status_t
pci_unreserve_device(uchar virtualBus,uchar device,uchar function,const char * driverName,void * nodeCookie)206 pci_unreserve_device(uchar virtualBus, uchar device, uchar function,
207 const char *driverName, void *nodeCookie)
208 {
209 status_t status;
210 uint8 bus;
211 uint8 domain;
212 TRACE(("pci_unreserve_device(%d, %d, %d, %s)\n", virtualBus, device,
213 function, driverName));
214
215 if (gPCI->ResolveVirtualBus(virtualBus, &domain, &bus) != B_OK)
216 return B_ERROR;
217
218 //TRACE(("%s(%d [%d:%d], %d, %d, %s, %p)\n", __FUNCTION__, virtualBus,
219 // domain, bus, device, function, driverName, nodeCookie));
220
221 device_attr matchThis[] = {
222 // info about device
223 {B_DEVICE_BUS, B_STRING_TYPE, {.string = "pci"}},
224
225 // location on PCI bus
226 {B_PCI_DEVICE_DOMAIN, B_UINT8_TYPE, {.ui8 = domain}},
227 {B_PCI_DEVICE_BUS, B_UINT8_TYPE, {.ui8 = bus}},
228 {B_PCI_DEVICE_DEVICE, B_UINT8_TYPE, {.ui8 = device}},
229 {B_PCI_DEVICE_FUNCTION, B_UINT8_TYPE, {.ui8 = function}},
230 {NULL}
231 };
232 device_attr legacyAttrs[] = {
233 // info about device
234 {B_DEVICE_BUS, B_STRING_TYPE, {.string = "legacy_driver"}},
235 {B_DEVICE_PRETTY_NAME, B_STRING_TYPE, {.string = "Legacy Driver Reservation"}},
236 {NULL}
237 };
238 device_attr drvAttrs[] = {
239 // info about device
240 {B_DEVICE_BUS, B_STRING_TYPE, {.string = "legacy_driver"}},
241 {"legacy_driver", B_STRING_TYPE, {.string = driverName}},
242 {"legacy_driver_cookie", B_UINT64_TYPE, {.ui64 = (uint64)nodeCookie}},
243 {NULL}
244 };
245 device_node *pci, *node, *legacy, *drv;
246
247 status = B_DEVICE_NOT_FOUND;
248
249 pci = gPCI->_GetDomainData(domain)->root_node;
250
251 node = NULL;
252 if (gDeviceManager->get_next_child_node(pci, matchThis, &node) < B_OK)
253 goto err1;
254
255 // common API for all legacy modules ?
256 //status = legacy_driver_unregister(node, driverName, nodeCookie);
257
258 legacy = NULL;
259 if (gDeviceManager->get_next_child_node(node, legacyAttrs, &legacy) < B_OK)
260 goto err2;
261
262 drv = NULL;
263 if (gDeviceManager->get_next_child_node(legacy, drvAttrs, &drv) < B_OK)
264 goto err3;
265
266 gDeviceManager->put_node(drv);
267 status = gDeviceManager->unregister_node(drv);
268 //dprintf("unreg:drv:%s\n", strerror(status));
269
270 gDeviceManager->put_node(legacy);
271 status = gDeviceManager->unregister_node(legacy);
272 //dprintf("unreg:legacy:%s\n", strerror(status));
273 // we'll get EBUSY here anyway...
274
275 gDeviceManager->put_node(node);
276 return B_OK;
277
278 err3:
279 gDeviceManager->put_node(legacy);
280 err2:
281 gDeviceManager->put_node(node);
282 err1:
283 TRACE(("pci_unreserve_device for driver %s failed: %s\n", driverName,
284 strerror(status)));
285 return status;
286 }
287
288
289 status_t
pci_update_interrupt_line(uchar virtualBus,uchar device,uchar function,uchar newInterruptLineValue)290 pci_update_interrupt_line(uchar virtualBus, uchar device, uchar function,
291 uchar newInterruptLineValue)
292 {
293 uint8 bus;
294 uint8 domain;
295 if (gPCI->ResolveVirtualBus(virtualBus, &domain, &bus) != B_OK)
296 return B_ERROR;
297
298 return gPCI->UpdateInterruptLine(domain, bus, device, function,
299 newInterruptLineValue);
300 }
301
302
303 status_t
pci_get_powerstate(uchar virtualBus,uint8 device,uint8 function,uint8 * state)304 pci_get_powerstate(uchar virtualBus, uint8 device, uint8 function, uint8* state)
305 {
306 uint8 bus;
307 uint8 domain;
308 if (gPCI->ResolveVirtualBus(virtualBus, &domain, &bus) != B_OK)
309 return B_ERROR;
310
311 return gPCI->GetPowerstate(domain, bus, device, function, state);
312 }
313
314
315 status_t
pci_set_powerstate(uchar virtualBus,uint8 device,uint8 function,uint8 newState)316 pci_set_powerstate(uchar virtualBus, uint8 device, uint8 function, uint8 newState)
317 {
318 uint8 bus;
319 uint8 domain;
320 if (gPCI->ResolveVirtualBus(virtualBus, &domain, &bus) != B_OK)
321 return B_ERROR;
322
323 return gPCI->SetPowerstate(domain, bus, device, function, newState);
324 }
325
326
327 // used by pci_info.cpp print_info_basic()
328 void
__pci_resolve_virtual_bus(uint8 virtualBus,uint8 * domain,uint8 * bus)329 __pci_resolve_virtual_bus(uint8 virtualBus, uint8 *domain, uint8 *bus)
330 {
331 if (gPCI->ResolveVirtualBus(virtualBus, domain, bus) < B_OK)
332 panic("ResolveVirtualBus failed");
333 }
334
335
336 // #pragma mark kernel debugger commands
337
338
339 static int
display_io(int argc,char ** argv)340 display_io(int argc, char **argv)
341 {
342 int32 displayWidth;
343 int32 itemSize;
344 int32 num = 1;
345 int address;
346 int i = 1, j;
347
348 switch (argc) {
349 case 3:
350 num = atoi(argv[2]);
351 case 2:
352 address = strtoul(argv[1], NULL, 0);
353 break;
354 default:
355 kprintf("usage: %s <address> [num]\n", argv[0]);
356 return 0;
357 }
358
359 // build the format string
360 if (strcmp(argv[0], "inb") == 0 || strcmp(argv[0], "in8") == 0) {
361 itemSize = 1;
362 displayWidth = 16;
363 } else if (strcmp(argv[0], "ins") == 0 || strcmp(argv[0], "in16") == 0) {
364 itemSize = 2;
365 displayWidth = 8;
366 } else if (strcmp(argv[0], "inw") == 0 || strcmp(argv[0], "in32") == 0) {
367 itemSize = 4;
368 displayWidth = 4;
369 } else {
370 kprintf("display_io called in an invalid way!\n");
371 return 0;
372 }
373
374 for (i = 0; i < num; i++) {
375 if ((i % displayWidth) == 0) {
376 int32 displayed = min_c(displayWidth, (num-i)) * itemSize;
377 if (i != 0)
378 kprintf("\n");
379
380 kprintf("[0x%" B_PRIx32 "] ", address + i * itemSize);
381
382 if (num > displayWidth) {
383 // make sure the spacing in the last line is correct
384 for (j = displayed; j < displayWidth * itemSize; j++)
385 kprintf(" ");
386 }
387 kprintf(" ");
388 }
389
390 switch (itemSize) {
391 case 1:
392 kprintf(" %02" B_PRIx8, pci_read_io_8(address + i * itemSize));
393 break;
394 case 2:
395 kprintf(" %04" B_PRIx16, pci_read_io_16(address + i * itemSize));
396 break;
397 case 4:
398 kprintf(" %08" B_PRIx32, pci_read_io_32(address + i * itemSize));
399 break;
400 }
401 }
402
403 kprintf("\n");
404 return 0;
405 }
406
407
408 static int
write_io(int argc,char ** argv)409 write_io(int argc, char **argv)
410 {
411 int32 itemSize;
412 uint32 value;
413 int address;
414 int i = 1;
415
416 if (argc < 3) {
417 kprintf("usage: %s <address> <value> [value [...]]\n", argv[0]);
418 return 0;
419 }
420
421 address = strtoul(argv[1], NULL, 0);
422
423 if (strcmp(argv[0], "outb") == 0 || strcmp(argv[0], "out8") == 0) {
424 itemSize = 1;
425 } else if (strcmp(argv[0], "outs") == 0 || strcmp(argv[0], "out16") == 0) {
426 itemSize = 2;
427 } else if (strcmp(argv[0], "outw") == 0 || strcmp(argv[0], "out32") == 0) {
428 itemSize = 4;
429 } else {
430 kprintf("write_io called in an invalid way!\n");
431 return 0;
432 }
433
434 // skip cmd name and address
435 argv += 2;
436 argc -= 2;
437
438 for (i = 0; i < argc; i++) {
439 value = strtoul(argv[i], NULL, 0);
440 switch (itemSize) {
441 case 1:
442 pci_write_io_8(address + i * itemSize, value);
443 break;
444 case 2:
445 pci_write_io_16(address + i * itemSize, value);
446 break;
447 case 4:
448 pci_write_io_32(address + i * itemSize, value);
449 break;
450 }
451 }
452
453 return 0;
454 }
455
456
457 static int
pcistatus(int argc,char ** argv)458 pcistatus(int argc, char **argv)
459 {
460 for (uint32 domain = 0; ; domain++) {
461 domain_data *data = gPCI->_GetDomainData(domain);
462 if (data == NULL)
463 break;
464
465 gPCI->ClearDeviceStatus(data->bus, true);
466 }
467
468 return 0;
469 }
470
471
472 static int
pcirefresh(int argc,char ** argv)473 pcirefresh(int argc, char **argv)
474 {
475 gPCI->RefreshDeviceInfo();
476 pci_print_info();
477 return 0;
478 }
479
480
481 // #pragma mark bus manager init/uninit
482
483
484 status_t
pci_init(void)485 pci_init(void)
486 {
487 gPCI = new PCI;
488
489 add_debugger_command("inw", &display_io, "dump io words (32-bit)");
490 add_debugger_command("in32", &display_io, "dump io words (32-bit)");
491 add_debugger_command("ins", &display_io, "dump io shorts (16-bit)");
492 add_debugger_command("in16", &display_io, "dump io shorts (16-bit)");
493 add_debugger_command("inb", &display_io, "dump io bytes (8-bit)");
494 add_debugger_command("in8", &display_io, "dump io bytes (8-bit)");
495
496 add_debugger_command("outw", &write_io, "write io words (32-bit)");
497 add_debugger_command("out32", &write_io, "write io words (32-bit)");
498 add_debugger_command("outs", &write_io, "write io shorts (16-bit)");
499 add_debugger_command("out16", &write_io, "write io shorts (16-bit)");
500 add_debugger_command("outb", &write_io, "write io bytes (8-bit)");
501 add_debugger_command("out8", &write_io, "write io bytes (8-bit)");
502
503 add_debugger_command("pcistatus", &pcistatus, "dump and clear pci device status registers");
504 add_debugger_command("pcirefresh", &pcirefresh, "refresh and print all pci_info");
505
506 return B_OK;
507 }
508
509
510 void
pci_uninit(void)511 pci_uninit(void)
512 {
513 delete gPCI;
514
515 remove_debugger_command("outw", &write_io);
516 remove_debugger_command("out32", &write_io);
517 remove_debugger_command("outs", &write_io);
518 remove_debugger_command("out16", &write_io);
519 remove_debugger_command("outb", &write_io);
520 remove_debugger_command("out8", &write_io);
521
522 remove_debugger_command("inw", &display_io);
523 remove_debugger_command("in32", &display_io);
524 remove_debugger_command("ins", &display_io);
525 remove_debugger_command("in16", &display_io);
526 remove_debugger_command("inb", &display_io);
527 remove_debugger_command("in8", &display_io);
528
529 remove_debugger_command("pcistatus", &pcistatus);
530 remove_debugger_command("pcirefresh", &pcirefresh);
531 }
532
533
534 // #pragma mark PCI class
535
536
PCI()537 PCI::PCI()
538 :
539 fDomainCount(0),
540 fBusEnumeration(false),
541 fVirtualBusMap(),
542 fNextVirtualBus(0)
543 {
544 #if defined(__POWERPC__) || defined(__M68K__)
545 fBusEnumeration = true;
546 #endif
547 }
548
549
550 void
InitBus(PCIBus * bus)551 PCI::InitBus(PCIBus *bus)
552 {
553 if (fBusEnumeration) {
554 _EnumerateBus(bus->domain, 0);
555 }
556
557 if (1) {
558 _FixupDevices(bus->domain, 0);
559 }
560
561 _DiscoverBus(bus);
562 _ConfigureBridges(bus);
563 ClearDeviceStatus(bus, false);
564 _RefreshDeviceInfo(bus);
565 }
566
567
~PCI()568 PCI::~PCI()
569 {
570 }
571
572
573 status_t
_CreateVirtualBus(uint8 domain,uint8 bus,uint8 * virtualBus)574 PCI::_CreateVirtualBus(uint8 domain, uint8 bus, uint8 *virtualBus)
575 {
576 #if defined(__i386__) || defined(__x86_64__)
577
578 // IA32 doesn't use domains
579 if (domain)
580 panic("PCI::CreateVirtualBus domain != 0");
581 *virtualBus = bus;
582 return B_OK;
583
584 #else
585
586 if (fNextVirtualBus > 0xff)
587 panic("PCI::CreateVirtualBus: virtual bus number space exhausted");
588
589 uint16 value = domain << 8 | bus;
590
591 for (VirtualBusMap::Iterator it = fVirtualBusMap.Begin();
592 it != fVirtualBusMap.End(); ++it) {
593 if (it->Value() == value) {
594 *virtualBus = it->Key();
595 FLOW("PCI::CreateVirtualBus: domain %d, bus %d already in map => "
596 "virtualBus %d\n", domain, bus, *virtualBus);
597 return B_OK;
598 }
599 }
600
601 *virtualBus = fNextVirtualBus++;
602
603 FLOW("PCI::CreateVirtualBus: domain %d, bus %d => virtualBus %d\n", domain,
604 bus, *virtualBus);
605
606 return fVirtualBusMap.Insert(*virtualBus, value);
607
608 #endif
609 }
610
611
612 status_t
ResolveVirtualBus(uint8 virtualBus,uint8 * domain,uint8 * bus)613 PCI::ResolveVirtualBus(uint8 virtualBus, uint8 *domain, uint8 *bus)
614 {
615 #if defined(__i386__) || defined(__x86_64__)
616
617 // IA32 doesn't use domains
618 *bus = virtualBus;
619 *domain = 0;
620 return B_OK;
621
622 #else
623
624 if (virtualBus >= fNextVirtualBus)
625 return B_ERROR;
626
627 uint16 value = fVirtualBusMap.Get(virtualBus);
628 *domain = value >> 8;
629 *bus = value & 0xff;
630 return B_OK;
631
632 #endif
633 }
634
635
636 status_t
AddController(pci_controller_module_info * controller,void * controllerCookie,device_node * rootNode,domain_data ** domainData)637 PCI::AddController(pci_controller_module_info *controller,
638 void *controllerCookie, device_node *rootNode, domain_data **domainData)
639 {
640 if (fDomainCount == MAX_PCI_DOMAINS)
641 return B_ERROR;
642
643 uint8 domain = fDomainCount;
644 domain_data& data = fDomainData[domain];
645
646 data.controller = controller;
647 data.controller_cookie = controllerCookie;
648 data.root_node = rootNode;
649
650 data.bus = new(std::nothrow) PCIBus {.domain = domain};
651 if (data.bus == NULL)
652 return B_NO_MEMORY;
653
654 // initialized later to avoid call back into controller at this point
655 data.max_bus_devices = -1;
656
657 fDomainCount++;
658
659 InitDomainData(data);
660 InitBus(data.bus);
661 if (data.controller->finalize != NULL)
662 data.controller->finalize(data.controller_cookie);
663 _RefreshDeviceInfo(data.bus);
664
665 pci_print_info();
666
667 *domainData = &data;
668 return B_OK;
669 }
670
671
672 status_t
LookupRange(uint32 type,phys_addr_t pciAddr,uint8 & domain,pci_resource_range & range,uint8 ** mappedAdr)673 PCI::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
701 void
InitDomainData(domain_data & data)702 PCI::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
739 domain_data *
_GetDomainData(uint8 domain)740 PCI::_GetDomainData(uint8 domain)
741 {
742 if (domain >= fDomainCount)
743 return NULL;
744
745 return &fDomainData[domain];
746 }
747
748
749 inline int
_NumFunctions(uint8 domain,uint8 bus,uint8 device)750 PCI::_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
758 status_t
GetNthInfo(long index,pci_info * outInfo)759 PCI::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, ¤tIndex, index, outInfo) >= B_OK)
765 return B_OK;
766 }
767
768 return B_ERROR;
769 }
770
771
772 status_t
_GetNthInfo(PCIBus * bus,long * currentIndex,long wantIndex,pci_info * outInfo)773 PCI::_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
794 void
_EnumerateBus(uint8 domain,uint8 bus,uint8 * subordinateBus)795 PCI::_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
932 void
_FixupDevices(uint8 domain,uint8 bus)933 PCI::_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
995 void
_ConfigureBridges(PCIBus * bus)996 PCI::_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
1032 void
ClearDeviceStatus(PCIBus * bus,bool dumpStatus)1033 PCI::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
1105 void
_DiscoverBus(PCIBus * bus)1106 PCI::_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
1136 void
_DiscoverDevice(PCIBus * bus,uint8 dev,uint8 function)1137 PCI::_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
1164 PCIBus *
_CreateBus(PCIDev * parent,uint8 domain,uint8 bus)1165 PCI::_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
1183 PCIDev *
_CreateDevice(PCIBus * parent,uint8 device,uint8 function)1184 PCI::_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
1222 uint64
_BarSize(uint64 bits)1223 PCI::_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
1236 size_t
_GetBarInfo(PCIDev * dev,uint8 offset,uint32 & _ramAddress,uint32 & _pciAddress,uint32 & _size,uint8 & flags,uint32 * _highRAMAddress,uint32 * _highPCIAddress,uint32 * _highSize)1237 PCI::_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
1297 void
_GetRomBarInfo(PCIDev * dev,uint8 offset,uint32 & _address,uint32 * _size,uint8 * _flags)1298 PCI::_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
1318 void
_ReadBasicInfo(PCIDev * dev)1319 PCI::_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
1357 void
_ReadHeaderInfo(PCIDev * dev)1358 PCI::_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
1533 void
RefreshDeviceInfo()1534 PCI::RefreshDeviceInfo()
1535 {
1536 for (uint32 domain = 0; domain < fDomainCount; domain++)
1537 _RefreshDeviceInfo(fDomainData[domain].bus);
1538 }
1539
1540
1541 void
_RefreshDeviceInfo(PCIBus * bus)1542 PCI::_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
1556 status_t
ReadConfig(uint8 domain,uint8 bus,uint8 device,uint8 function,uint16 offset,uint8 size,uint32 * value)1557 PCI::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, %u:%u:%u, offset %u, size %u\n",
1570 domain, bus, device, function, offset, size);
1571 return B_ERROR;
1572 }
1573
1574 status_t status = (*info->controller->read_pci_config)(info->controller_cookie,
1575 bus, device, function, offset, size, value);
1576 if (status != B_OK) {
1577 dprintf("PCI: failed to read config for domain %d, %u:%u:%u, offset %u, size %u\n",
1578 domain, bus, device, function, offset, size);
1579 }
1580 return status;
1581 }
1582
1583
1584 uint32
ReadConfig(uint8 domain,uint8 bus,uint8 device,uint8 function,uint16 offset,uint8 size)1585 PCI::ReadConfig(uint8 domain, uint8 bus, uint8 device, uint8 function,
1586 uint16 offset, uint8 size)
1587 {
1588 uint32 value;
1589 if (ReadConfig(domain, bus, device, function, offset, size, &value)
1590 != B_OK)
1591 return 0xffffffff;
1592
1593 return value;
1594 }
1595
1596
1597 uint32
ReadConfig(PCIDev * device,uint16 offset,uint8 size)1598 PCI::ReadConfig(PCIDev *device, uint16 offset, uint8 size)
1599 {
1600 uint32 value;
1601 if (ReadConfig(device->domain, device->bus, device->device,
1602 device->function, offset, size, &value) != B_OK)
1603 return 0xffffffff;
1604
1605 return value;
1606 }
1607
1608
1609 status_t
WriteConfig(uint8 domain,uint8 bus,uint8 device,uint8 function,uint16 offset,uint8 size,uint32 value)1610 PCI::WriteConfig(uint8 domain, uint8 bus, uint8 device, uint8 function,
1611 uint16 offset, uint8 size, uint32 value)
1612 {
1613 domain_data *info = _GetDomainData(domain);
1614 if (!info)
1615 return B_ERROR;
1616
1617 if (device > (info->max_bus_devices - 1)
1618 || function > 7
1619 || (size != 1 && size != 2 && size != 4)
1620 || (size == 2 && (offset & 3) == 3)
1621 || (size == 4 && (offset & 3) != 0)) {
1622 dprintf("PCI: can't write config for domain %d, bus %u, device %u, function %u, offset %u, size %u\n",
1623 domain, bus, device, function, offset, size);
1624 return B_ERROR;
1625 }
1626
1627 return (*info->controller->write_pci_config)(info->controller_cookie, bus,
1628 device, function, offset, size, value);
1629 }
1630
1631
1632 status_t
WriteConfig(PCIDev * device,uint16 offset,uint8 size,uint32 value)1633 PCI::WriteConfig(PCIDev *device, uint16 offset, uint8 size, uint32 value)
1634 {
1635 return WriteConfig(device->domain, device->bus, device->device,
1636 device->function, offset, size, value);
1637 }
1638
1639
1640 status_t
FindCapability(uint8 domain,uint8 bus,uint8 device,uint8 function,uint8 capID,uint8 * offset)1641 PCI::FindCapability(uint8 domain, uint8 bus, uint8 device, uint8 function,
1642 uint8 capID, uint8 *offset)
1643 {
1644 uint16 status = ReadConfig(domain, bus, device, function, PCI_status, 2);
1645 if (!(status & PCI_status_capabilities)) {
1646 FLOW("PCI: find_pci_capability ERROR %u:%u:%u capability %#02x "
1647 "not supported\n", bus, device, function, capID);
1648 return B_ERROR;
1649 }
1650
1651 uint8 headerType = ReadConfig(domain, bus, device, function,
1652 PCI_header_type, 1);
1653 uint8 capPointer;
1654
1655 switch (headerType & PCI_header_type_mask) {
1656 case PCI_header_type_generic:
1657 case PCI_header_type_PCI_to_PCI_bridge:
1658 capPointer = PCI_capabilities_ptr;
1659 break;
1660 case PCI_header_type_cardbus:
1661 capPointer = PCI_capabilities_ptr_2;
1662 break;
1663 default:
1664 TRACE_CAP("PCI: find_pci_capability ERROR %u:%u:%u capability "
1665 "%#02x unknown header type\n", bus, device, function, capID);
1666 return B_ERROR;
1667 }
1668
1669 capPointer = ReadConfig(domain, bus, device, function, capPointer, 1);
1670 capPointer &= ~3;
1671 if (capPointer == 0) {
1672 TRACE_CAP("PCI: find_pci_capability ERROR %u:%u:%u capability %#02x "
1673 "empty list\n", bus, device, function, capID);
1674 return B_NAME_NOT_FOUND;
1675 }
1676
1677 for (int i = 0; i < 48; i++) {
1678 if (ReadConfig(domain, bus, device, function, capPointer, 1) == capID) {
1679 if (offset != NULL)
1680 *offset = capPointer;
1681 return B_OK;
1682 }
1683
1684 capPointer = ReadConfig(domain, bus, device, function, capPointer + 1,
1685 1);
1686 capPointer &= ~3;
1687
1688 if (capPointer == 0)
1689 return B_NAME_NOT_FOUND;
1690 }
1691
1692 TRACE_CAP("PCI: find_pci_capability ERROR %u:%u:%u capability %#02x circular list\n", bus, device, function, capID);
1693 return B_ERROR;
1694 }
1695
1696
1697 status_t
FindCapability(PCIDev * device,uint8 capID,uint8 * offset)1698 PCI::FindCapability(PCIDev *device, uint8 capID, uint8 *offset)
1699 {
1700 return FindCapability(device->domain, device->bus, device->device,
1701 device->function, capID, offset);
1702 }
1703
1704
1705 status_t
FindExtendedCapability(uint8 domain,uint8 bus,uint8 device,uint8 function,uint16 capID,uint16 * offset)1706 PCI::FindExtendedCapability(uint8 domain, uint8 bus, uint8 device,
1707 uint8 function, uint16 capID, uint16 *offset)
1708 {
1709 if (FindCapability(domain, bus, device, function, PCI_cap_id_pcie)
1710 != B_OK) {
1711 FLOW("PCI:FindExtendedCapability ERROR %u:%u:%u capability %#02x "
1712 "not supported\n", bus, device, function, capID);
1713 return B_ERROR;
1714 }
1715 uint16 capPointer = PCI_extended_capability;
1716 uint32 capability = ReadConfig(domain, bus, device, function,
1717 capPointer, 4);
1718
1719 if (capability == 0 || capability == 0xffffffff)
1720 return B_NAME_NOT_FOUND;
1721
1722 for (int i = 0; i < 48; i++) {
1723 if (PCI_extcap_id(capability) == capID) {
1724 if (offset != NULL)
1725 *offset = capPointer;
1726 return B_OK;
1727 }
1728
1729 capPointer = PCI_extcap_next_ptr(capability) & ~3;
1730 if (capPointer < PCI_extended_capability)
1731 return B_NAME_NOT_FOUND;
1732 capability = ReadConfig(domain, bus, device, function,
1733 capPointer, 4);
1734 }
1735
1736 TRACE_CAP("PCI:FindExtendedCapability ERROR %u:%u:%u capability %#04x "
1737 "circular list\n", bus, device, function, capID);
1738 return B_ERROR;
1739 }
1740
1741
1742 status_t
FindExtendedCapability(PCIDev * device,uint16 capID,uint16 * offset)1743 PCI::FindExtendedCapability(PCIDev *device, uint16 capID, uint16 *offset)
1744 {
1745 return FindExtendedCapability(device->domain, device->bus, device->device,
1746 device->function, capID, offset);
1747 }
1748
1749
1750 status_t
FindHTCapability(uint8 domain,uint8 bus,uint8 device,uint8 function,uint16 capID,uint8 * offset)1751 PCI::FindHTCapability(uint8 domain, uint8 bus, uint8 device,
1752 uint8 function, uint16 capID, uint8 *offset)
1753 {
1754 uint8 capPointer;
1755 // consider the passed offset as the current ht capability block pointer
1756 // when it's non zero
1757 if (offset != NULL && *offset != 0) {
1758 capPointer = ReadConfig(domain, bus, device, function, *offset + 1,
1759 1);
1760 } else if (FindCapability(domain, bus, device, function, PCI_cap_id_ht,
1761 &capPointer) != B_OK) {
1762 FLOW("PCI:FindHTCapability ERROR %u:%u:%u capability %#02x "
1763 "not supported\n", bus, device, function, capID);
1764 return B_NAME_NOT_FOUND;
1765 }
1766
1767 uint16 mask = PCI_ht_command_cap_mask_5_bits;
1768 if (capID == PCI_ht_command_cap_slave || capID == PCI_ht_command_cap_host)
1769 mask = PCI_ht_command_cap_mask_3_bits;
1770 for (int i = 0; i < 48; i++) {
1771 capPointer &= ~3;
1772 if (capPointer == 0)
1773 return B_NAME_NOT_FOUND;
1774
1775 uint8 capability = ReadConfig(domain, bus, device, function,
1776 capPointer, 1);
1777 if (capability == PCI_cap_id_ht) {
1778 if ((ReadConfig(domain, bus, device, function,
1779 capPointer + PCI_ht_command, 2) & mask) == capID) {
1780 if (offset != NULL)
1781 *offset = capPointer;
1782 return B_OK;
1783 }
1784 }
1785
1786 capPointer = ReadConfig(domain, bus, device, function, capPointer + 1,
1787 1);
1788 }
1789
1790 TRACE_CAP("PCI:FindHTCapability ERROR %u:%u:%u capability %#04x "
1791 "circular list\n", bus, device, function, capID);
1792 return B_ERROR;
1793 }
1794
1795
1796 status_t
FindHTCapability(PCIDev * device,uint16 capID,uint8 * offset)1797 PCI::FindHTCapability(PCIDev *device, uint16 capID, uint8 *offset)
1798 {
1799 return FindHTCapability(device->domain, device->bus, device->device,
1800 device->function, capID, offset);
1801 }
1802
1803
1804 PCIDev *
FindDevice(uint8 domain,uint8 bus,uint8 device,uint8 function)1805 PCI::FindDevice(uint8 domain, uint8 bus, uint8 device, uint8 function)
1806 {
1807 if (domain >= fDomainCount)
1808 return NULL;
1809
1810 return _FindDevice(fDomainData[domain].bus, domain, bus, device, function);
1811 }
1812
1813
1814 PCIDev *
_FindDevice(PCIBus * current,uint8 domain,uint8 bus,uint8 device,uint8 function)1815 PCI::_FindDevice(PCIBus *current, uint8 domain, uint8 bus, uint8 device,
1816 uint8 function)
1817 {
1818 if (current->domain == domain) {
1819 // search device on this bus
1820
1821 for (PCIDev *child = current->child; child != NULL;
1822 child = child->next) {
1823 if (child->bus == bus && child->device == device
1824 && child->function == function)
1825 return child;
1826
1827 if (child->child != NULL) {
1828 // search child busses
1829 PCIDev *found = _FindDevice(child->child, domain, bus, device,
1830 function);
1831 if (found != NULL)
1832 return found;
1833 }
1834 }
1835 }
1836
1837 return NULL;
1838 }
1839
1840
1841 status_t
UpdateInterruptLine(uint8 domain,uint8 bus,uint8 _device,uint8 function,uint8 newInterruptLineValue)1842 PCI::UpdateInterruptLine(uint8 domain, uint8 bus, uint8 _device, uint8 function,
1843 uint8 newInterruptLineValue)
1844 {
1845 PCIDev *device = FindDevice(domain, bus, _device, function);
1846 if (device == NULL)
1847 return B_ERROR;
1848
1849 pci_info &info = device->info;
1850 switch (info.header_type & PCI_header_type_mask) {
1851 case PCI_header_type_generic:
1852 info.u.h0.interrupt_line = newInterruptLineValue;
1853 break;
1854
1855 case PCI_header_type_PCI_to_PCI_bridge:
1856 info.u.h1.interrupt_line = newInterruptLineValue;
1857 break;
1858
1859 default:
1860 return B_ERROR;
1861 }
1862
1863 return WriteConfig(device, PCI_interrupt_line, 1, newInterruptLineValue);
1864 }
1865
1866
1867 uint8
GetPowerstate(PCIDev * device)1868 PCI::GetPowerstate(PCIDev *device)
1869 {
1870 uint8 capabilityOffset;
1871 status_t res = FindCapability(device, PCI_cap_id_pm, &capabilityOffset);
1872 if (res == B_OK) {
1873 uint32 state = ReadConfig(device, capabilityOffset + PCI_pm_status, 2);
1874 return (state & PCI_pm_mask);
1875 }
1876 return PCI_pm_state_d0;
1877 }
1878
1879
1880 void
SetPowerstate(PCIDev * device,uint8 newState)1881 PCI::SetPowerstate(PCIDev *device, uint8 newState)
1882 {
1883 uint8 capabilityOffset;
1884 status_t res = FindCapability(device, PCI_cap_id_pm, &capabilityOffset);
1885 if (res == B_OK) {
1886 uint32 state = ReadConfig(device, capabilityOffset + PCI_pm_status, 2);
1887 if ((state & PCI_pm_mask) != newState) {
1888 WriteConfig(device, capabilityOffset + PCI_pm_status, 2,
1889 (state & ~PCI_pm_mask) | newState);
1890 if ((state & PCI_pm_mask) == PCI_pm_state_d3)
1891 snooze(10);
1892 }
1893 }
1894 }
1895
1896
1897 status_t
GetPowerstate(uint8 domain,uint8 bus,uint8 _device,uint8 function,uint8 * state)1898 PCI::GetPowerstate(uint8 domain, uint8 bus, uint8 _device, uint8 function,
1899 uint8* state)
1900 {
1901 PCIDev *device = FindDevice(domain, bus, _device, function);
1902 if (device == NULL)
1903 return B_ERROR;
1904
1905 *state = GetPowerstate(device);
1906 return B_OK;
1907 }
1908
1909
1910 status_t
SetPowerstate(uint8 domain,uint8 bus,uint8 _device,uint8 function,uint8 newState)1911 PCI::SetPowerstate(uint8 domain, uint8 bus, uint8 _device, uint8 function,
1912 uint8 newState)
1913 {
1914 PCIDev *device = FindDevice(domain, bus, _device, function);
1915 if (device == NULL)
1916 return B_ERROR;
1917
1918 SetPowerstate(device, newState);
1919 return B_OK;
1920 }
1921
1922
1923 //#pragma mark - MSI
1924
1925 uint32
GetMSICount(PCIDev * device)1926 PCI::GetMSICount(PCIDev *device)
1927 {
1928 if (!msi_supported())
1929 return 0;
1930
1931 msi_info *info = &device->msi;
1932 if (!info->msi_capable)
1933 return 0;
1934
1935 return info->message_count;
1936 }
1937
1938
1939 status_t
ConfigureMSI(PCIDev * device,uint32 count,uint32 * startVector)1940 PCI::ConfigureMSI(PCIDev *device, uint32 count, uint32 *startVector)
1941 {
1942 if (!msi_supported())
1943 return B_UNSUPPORTED;
1944
1945 if (count == 0 || startVector == NULL)
1946 return B_BAD_VALUE;
1947
1948 msi_info *info = &device->msi;
1949 if (!info->msi_capable)
1950 return B_UNSUPPORTED;
1951
1952 if (count > 32 || count > info->message_count
1953 || ((count - 1) & count) != 0 /* needs to be a power of 2 */) {
1954 return B_BAD_VALUE;
1955 }
1956
1957 if (info->configured_count != 0)
1958 return B_BUSY;
1959
1960 status_t result = msi_allocate_vectors(count, &info->start_vector,
1961 &info->address_value, &info->data_value);
1962 if (result != B_OK)
1963 return result;
1964
1965 uint8 offset = info->capability_offset;
1966 WriteConfig(device, offset + PCI_msi_address, 4,
1967 info->address_value & 0xffffffff);
1968 if (info->control_value & PCI_msi_control_64bit) {
1969 WriteConfig(device, offset + PCI_msi_address_high, 4,
1970 info->address_value >> 32);
1971 WriteConfig(device, offset + PCI_msi_data_64bit, 2,
1972 info->data_value);
1973 } else
1974 WriteConfig(device, offset + PCI_msi_data, 2, info->data_value);
1975
1976 info->control_value &= ~PCI_msi_control_mme_mask;
1977 info->control_value |= (ffs(count) - 1) << 4;
1978 WriteConfig(device, offset + PCI_msi_control, 2, info->control_value);
1979
1980 info->configured_count = count;
1981 *startVector = info->start_vector;
1982 return B_OK;
1983 }
1984
1985
1986 status_t
UnconfigureMSI(PCIDev * device)1987 PCI::UnconfigureMSI(PCIDev *device)
1988 {
1989 if (!msi_supported())
1990 return B_UNSUPPORTED;
1991
1992 // try MSI-X
1993 status_t result = _UnconfigureMSIX(device);
1994 if (result != B_UNSUPPORTED && result != B_NO_INIT)
1995 return result;
1996
1997 msi_info *info = &device->msi;
1998 if (!info->msi_capable)
1999 return B_UNSUPPORTED;
2000
2001 if (info->configured_count == 0)
2002 return B_NO_INIT;
2003
2004 msi_free_vectors(info->configured_count, info->start_vector);
2005
2006 info->control_value &= ~PCI_msi_control_mme_mask;
2007 WriteConfig(device, info->capability_offset + PCI_msi_control, 2,
2008 info->control_value);
2009
2010 info->configured_count = 0;
2011 info->address_value = 0;
2012 info->data_value = 0;
2013 return B_OK;
2014 }
2015
2016
2017 status_t
EnableMSI(PCIDev * device)2018 PCI::EnableMSI(PCIDev *device)
2019 {
2020 if (!msi_supported())
2021 return B_UNSUPPORTED;
2022
2023 msi_info *info = &device->msi;
2024 if (!info->msi_capable)
2025 return B_UNSUPPORTED;
2026
2027 if (info->configured_count == 0)
2028 return B_NO_INIT;
2029
2030 // ensure the pinned interrupt is disabled
2031 WriteConfig(device, PCI_command, 2,
2032 ReadConfig(device, PCI_command, 2) | PCI_command_int_disable);
2033
2034 // enable msi generation
2035 info->control_value |= PCI_msi_control_enable;
2036 WriteConfig(device, info->capability_offset + PCI_msi_control, 2,
2037 info->control_value);
2038
2039 // enable HT msi mapping (if applicable)
2040 _HtMSIMap(device, info->address_value);
2041
2042 dprintf("msi enabled: 0x%04" B_PRIx32 "\n",
2043 ReadConfig(device, info->capability_offset + PCI_msi_control, 2));
2044 return B_OK;
2045 }
2046
2047
2048 status_t
DisableMSI(PCIDev * device)2049 PCI::DisableMSI(PCIDev *device)
2050 {
2051 if (!msi_supported())
2052 return B_UNSUPPORTED;
2053
2054 // try MSI-X
2055 status_t result = _DisableMSIX(device);
2056 if (result != B_UNSUPPORTED && result != B_NO_INIT)
2057 return result;
2058
2059 msi_info *info = &device->msi;
2060 if (!info->msi_capable)
2061 return B_UNSUPPORTED;
2062
2063 if (info->configured_count == 0)
2064 return B_NO_INIT;
2065
2066 // disable HT msi mapping (if applicable)
2067 _HtMSIMap(device, 0);
2068
2069 // disable msi generation
2070 info->control_value &= ~PCI_msi_control_enable;
2071 WriteConfig(device, info->capability_offset + PCI_msi_control, 2,
2072 info->control_value);
2073
2074 return B_OK;
2075 }
2076
2077
2078 uint32
GetMSIXCount(PCIDev * device)2079 PCI::GetMSIXCount(PCIDev *device)
2080 {
2081 if (!msi_supported())
2082 return 0;
2083
2084 msix_info *info = &device->msix;
2085 if (!info->msix_capable)
2086 return 0;
2087
2088 return info->message_count;
2089 }
2090
2091
2092 status_t
ConfigureMSIX(PCIDev * device,uint32 count,uint32 * startVector)2093 PCI::ConfigureMSIX(PCIDev *device, uint32 count, uint32 *startVector)
2094 {
2095 if (!msi_supported())
2096 return B_UNSUPPORTED;
2097
2098 if (count == 0 || startVector == NULL)
2099 return B_BAD_VALUE;
2100
2101 msix_info *info = &device->msix;
2102 if (!info->msix_capable)
2103 return B_UNSUPPORTED;
2104
2105 if (count > 32 || count > info->message_count) {
2106 return B_BAD_VALUE;
2107 }
2108
2109 if (info->configured_count != 0)
2110 return B_BUSY;
2111
2112 // map the table bar
2113 size_t tableSize = info->message_count * 16;
2114 addr_t address;
2115 phys_addr_t barAddr = device->info.u.h0.base_registers[info->table_bar];
2116 uchar flags = device->info.u.h0.base_register_flags[info->table_bar];
2117 if ((flags & PCI_address_type) == PCI_address_type_64) {
2118 barAddr |= (uint64)device->info.u.h0.base_registers[
2119 info->table_bar + 1] << 32;
2120 }
2121 area_id area = map_physical_memory("msi table map",
2122 barAddr, tableSize + info->table_offset,
2123 B_ANY_KERNEL_ADDRESS, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA,
2124 (void**)&address);
2125 if (area < 0)
2126 return area;
2127 info->table_area_id = area;
2128 info->table_address = address + info->table_offset;
2129
2130 // and the pba bar if necessary
2131 if (info->table_bar != info->pba_bar) {
2132 barAddr = device->info.u.h0.base_registers[info->pba_bar];
2133 flags = device->info.u.h0.base_register_flags[info->pba_bar];
2134 if ((flags & PCI_address_type) == PCI_address_type_64) {
2135 barAddr |= (uint64)device->info.u.h0.base_registers[
2136 info->pba_bar + 1] << 32;
2137 }
2138 area = map_physical_memory("msi pba map",
2139 barAddr, tableSize + info->pba_offset,
2140 B_ANY_KERNEL_ADDRESS, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA,
2141 (void**)&address);
2142 if (area < 0) {
2143 delete_area(info->table_area_id);
2144 info->table_area_id = -1;
2145 return area;
2146 }
2147 info->pba_area_id = area;
2148 } else
2149 info->pba_area_id = -1;
2150 info->pba_address = address + info->pba_offset;
2151
2152 status_t result = msi_allocate_vectors(count, &info->start_vector,
2153 &info->address_value, &info->data_value);
2154 if (result != B_OK) {
2155 delete_area(info->pba_area_id);
2156 delete_area(info->table_area_id);
2157 info->pba_area_id = -1;
2158 info->table_area_id = -1;
2159 return result;
2160 }
2161
2162 // ensure the memory i/o is enabled
2163 WriteConfig(device, PCI_command, 2,
2164 ReadConfig(device, PCI_command, 2) | PCI_command_memory);
2165
2166 uint32 data_value = info->data_value;
2167 for (uint32 index = 0; index < count; index++) {
2168 volatile uint32 *entry = (uint32*)(info->table_address + 16 * index);
2169 *(entry + 3) |= PCI_msix_vctrl_mask;
2170 *entry++ = info->address_value & 0xffffffff;
2171 *entry++ = info->address_value >> 32;
2172 *entry++ = data_value++;
2173 *entry &= ~PCI_msix_vctrl_mask;
2174 }
2175
2176 info->configured_count = count;
2177 *startVector = info->start_vector;
2178 dprintf("msix configured for %" B_PRIu32 " vectors\n", count);
2179 return B_OK;
2180 }
2181
2182
2183 status_t
EnableMSIX(PCIDev * device)2184 PCI::EnableMSIX(PCIDev *device)
2185 {
2186 if (!msi_supported())
2187 return B_UNSUPPORTED;
2188
2189 msix_info *info = &device->msix;
2190 if (!info->msix_capable)
2191 return B_UNSUPPORTED;
2192
2193 if (info->configured_count == 0)
2194 return B_NO_INIT;
2195
2196 // ensure the pinned interrupt is disabled
2197 WriteConfig(device, PCI_command, 2,
2198 ReadConfig(device, PCI_command, 2) | PCI_command_int_disable);
2199
2200 // enable msi-x generation
2201 info->control_value |= PCI_msix_control_enable;
2202 WriteConfig(device, info->capability_offset + PCI_msix_control, 2,
2203 info->control_value);
2204
2205 // enable HT msi mapping (if applicable)
2206 _HtMSIMap(device, info->address_value);
2207
2208 dprintf("msi-x enabled: 0x%04" B_PRIx32 "\n",
2209 ReadConfig(device, info->capability_offset + PCI_msix_control, 2));
2210 return B_OK;
2211 }
2212
2213
2214 void
_HtMSIMap(PCIDev * device,uint64 address)2215 PCI::_HtMSIMap(PCIDev *device, uint64 address)
2216 {
2217 ht_mapping_info *info = &device->ht_mapping;
2218 if (!info->ht_mapping_capable)
2219 return;
2220
2221 bool enabled = (info->control_value & PCI_ht_command_msi_enable) != 0;
2222 if ((address != 0) != enabled) {
2223 if (enabled) {
2224 info->control_value &= ~PCI_ht_command_msi_enable;
2225 } else {
2226 if ((address >> 20) != (info->address_value >> 20))
2227 return;
2228 dprintf("ht msi mapping enabled\n");
2229 info->control_value |= PCI_ht_command_msi_enable;
2230 }
2231 WriteConfig(device, info->capability_offset + PCI_ht_command, 2,
2232 info->control_value);
2233 }
2234 }
2235
2236
2237 void
_ReadMSIInfo(PCIDev * device)2238 PCI::_ReadMSIInfo(PCIDev *device)
2239 {
2240 if (!msi_supported())
2241 return;
2242
2243 msi_info *info = &device->msi;
2244 info->msi_capable = false;
2245 status_t result = FindCapability(device->domain, device->bus,
2246 device->device, device->function, PCI_cap_id_msi,
2247 &info->capability_offset);
2248 if (result != B_OK)
2249 return;
2250
2251 info->msi_capable = true;
2252 info->control_value = ReadConfig(device->domain, device->bus,
2253 device->device, device->function,
2254 info->capability_offset + PCI_msi_control, 2);
2255 info->message_count
2256 = 1 << ((info->control_value & PCI_msi_control_mmc_mask) >> 1);
2257 info->configured_count = 0;
2258 info->data_value = 0;
2259 info->address_value = 0;
2260 }
2261
2262
2263 void
_ReadMSIXInfo(PCIDev * device)2264 PCI::_ReadMSIXInfo(PCIDev *device)
2265 {
2266 if (!msi_supported())
2267 return;
2268
2269 msix_info *info = &device->msix;
2270 info->msix_capable = false;
2271 status_t result = FindCapability(device->domain, device->bus,
2272 device->device, device->function, PCI_cap_id_msix,
2273 &info->capability_offset);
2274 if (result != B_OK)
2275 return;
2276
2277 info->msix_capable = true;
2278 info->control_value = ReadConfig(device->domain, device->bus,
2279 device->device, device->function,
2280 info->capability_offset + PCI_msix_control, 2);
2281 info->message_count
2282 = (info->control_value & PCI_msix_control_table_size) + 1;
2283 info->configured_count = 0;
2284 info->data_value = 0;
2285 info->address_value = 0;
2286 info->table_area_id = -1;
2287 info->pba_area_id = -1;
2288 uint32 table_value = ReadConfig(device->domain, device->bus,
2289 device->device, device->function,
2290 info->capability_offset + PCI_msix_table, 4);
2291 uint32 pba_value = ReadConfig(device->domain, device->bus,
2292 device->device, device->function,
2293 info->capability_offset + PCI_msix_pba, 4);
2294
2295 info->table_bar = table_value & PCI_msix_bir_mask;
2296 info->table_offset = table_value & PCI_msix_offset_mask;
2297 info->pba_bar = pba_value & PCI_msix_bir_mask;
2298 info->pba_offset = pba_value & PCI_msix_offset_mask;
2299 }
2300
2301
2302 void
_ReadHtMappingInfo(PCIDev * device)2303 PCI::_ReadHtMappingInfo(PCIDev *device)
2304 {
2305 if (!msi_supported())
2306 return;
2307
2308 ht_mapping_info *info = &device->ht_mapping;
2309 info->ht_mapping_capable = false;
2310
2311 uint8 offset = 0;
2312 if (FindHTCapability(device, PCI_ht_command_cap_msi_mapping,
2313 &offset) == B_OK) {
2314 info->control_value = ReadConfig(device, offset + PCI_ht_command,
2315 2);
2316 info->capability_offset = offset;
2317 info->ht_mapping_capable = true;
2318 if ((info->control_value & PCI_ht_command_msi_fixed) != 0) {
2319 #if defined(__i386__) || defined(__x86_64__)
2320 info->address_value = MSI_ADDRESS_BASE;
2321 #else
2322 // TODO: investigate what should be set here for non-x86
2323 dprintf("PCI_ht_command_msi_fixed flag unimplemented\n");
2324 info->address_value = 0;
2325 #endif
2326 } else {
2327 info->address_value = ReadConfig(device, offset
2328 + PCI_ht_msi_address_high, 4);
2329 info->address_value <<= 32;
2330 info->address_value |= ReadConfig(device, offset
2331 + PCI_ht_msi_address_low, 4);
2332 }
2333 dprintf("found an ht msi mapping at %#" B_PRIx64 "\n",
2334 info->address_value);
2335 }
2336 }
2337
2338
2339 status_t
_UnconfigureMSIX(PCIDev * device)2340 PCI::_UnconfigureMSIX(PCIDev *device)
2341 {
2342 msix_info *info = &device->msix;
2343 if (!info->msix_capable)
2344 return B_UNSUPPORTED;
2345
2346 if (info->configured_count == 0)
2347 return B_NO_INIT;
2348
2349 // disable msi-x generation
2350 info->control_value &= ~PCI_msix_control_enable;
2351 WriteConfig(device, info->capability_offset + PCI_msix_control, 2,
2352 info->control_value);
2353
2354 msi_free_vectors(info->configured_count, info->start_vector);
2355 for (uint8 index = 0; index < info->configured_count; index++) {
2356 volatile uint32 *entry = (uint32*)(info->table_address + 16 * index);
2357 if ((*(entry + 3) & PCI_msix_vctrl_mask) == 0)
2358 *(entry + 3) |= PCI_msix_vctrl_mask;
2359 }
2360
2361 if (info->pba_area_id != -1)
2362 delete_area(info->pba_area_id);
2363 if (info->table_area_id != -1)
2364 delete_area(info->table_area_id);
2365 info->pba_area_id= -1;
2366 info->table_area_id = -1;
2367
2368 info->configured_count = 0;
2369 info->address_value = 0;
2370 info->data_value = 0;
2371 return B_OK;
2372 }
2373
2374
2375 status_t
_DisableMSIX(PCIDev * device)2376 PCI::_DisableMSIX(PCIDev *device)
2377 {
2378 msix_info *info = &device->msix;
2379 if (!info->msix_capable)
2380 return B_UNSUPPORTED;
2381
2382 if (info->configured_count == 0)
2383 return B_NO_INIT;
2384
2385 // disable HT msi mapping (if applicable)
2386 _HtMSIMap(device, 0);
2387
2388 // disable msi-x generation
2389 info->control_value &= ~PCI_msix_control_enable;
2390 gPCI->WriteConfig(device, info->capability_offset + PCI_msix_control, 2,
2391 info->control_value);
2392
2393 return B_OK;
2394 }
2395