1 /* 2 * Copyright 2022, Haiku, Inc. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 7 #include "ECAMPCIController.h" 8 9 #include <AutoDeleterDrivers.h> 10 11 #include <string.h> 12 13 14 status_t 15 ECAMPCIControllerFDT::ReadResourceInfo() 16 { 17 DeviceNodePutter<&gDeviceManager> fdtNode(gDeviceManager->get_parent_node(fNode)); 18 19 fdt_device_module_info *fdtModule; 20 fdt_device* fdtDev; 21 CHECK_RET(gDeviceManager->get_driver(fdtNode.Get(), 22 (driver_module_info**)&fdtModule, (void**)&fdtDev)); 23 24 const void* prop; 25 int propLen; 26 27 prop = fdtModule->get_prop(fdtDev, "bus-range", &propLen); 28 if (prop != NULL && propLen == 8) { 29 uint32 busBeg = B_BENDIAN_TO_HOST_INT32(*((uint32*)prop + 0)); 30 uint32 busEnd = B_BENDIAN_TO_HOST_INT32(*((uint32*)prop + 1)); 31 dprintf(" bus-range: %" B_PRIu32 " - %" B_PRIu32 "\n", busBeg, busEnd); 32 } 33 34 prop = fdtModule->get_prop(fdtDev, "ranges", &propLen); 35 if (prop == NULL) { 36 dprintf(" \"ranges\" property not found"); 37 return B_ERROR; 38 } 39 dprintf(" ranges:\n"); 40 for (uint32_t *it = (uint32_t*)prop; (uint8_t*)it - (uint8_t*)prop < propLen; it += 7) { 41 dprintf(" "); 42 uint32_t type = B_BENDIAN_TO_HOST_INT32(*(it + 0)); 43 uint64_t childAdr = B_BENDIAN_TO_HOST_INT64(*(uint64_t*)(it + 1)); 44 uint64_t parentAdr = B_BENDIAN_TO_HOST_INT64(*(uint64_t*)(it + 3)); 45 uint64_t len = B_BENDIAN_TO_HOST_INT64(*(uint64_t*)(it + 5)); 46 47 uint32 outType = kPciRangeInvalid; 48 switch (type & fdtPciRangeTypeMask) { 49 case fdtPciRangeIoPort: 50 outType = kPciRangeIoPort; 51 break; 52 case fdtPciRangeMmio32Bit: 53 outType = kPciRangeMmio; 54 break; 55 case fdtPciRangeMmio64Bit: 56 outType = kPciRangeMmio + kPciRangeMmio64Bit; 57 break; 58 } 59 if (outType >= kPciRangeMmio && outType < kPciRangeMmioEnd 60 && (fdtPciRangePrefechable & type) != 0) 61 outType += kPciRangeMmioPrefetch; 62 63 if (outType != kPciRangeInvalid) { 64 fResourceRanges[outType].type = outType; 65 fResourceRanges[outType].host_addr = parentAdr; 66 fResourceRanges[outType].pci_addr = childAdr; 67 fResourceRanges[outType].size = len; 68 } 69 70 switch (type & fdtPciRangeTypeMask) { 71 case fdtPciRangeConfig: dprintf("CONFIG"); break; 72 case fdtPciRangeIoPort: dprintf("IOPORT"); break; 73 case fdtPciRangeMmio32Bit: dprintf("MMIO32"); break; 74 case fdtPciRangeMmio64Bit: dprintf("MMIO64"); break; 75 } 76 77 dprintf(" (0x%08" B_PRIx32 "): ", type); 78 dprintf("child: %08" B_PRIx64, childAdr); 79 dprintf(", parent: %08" B_PRIx64, parentAdr); 80 dprintf(", len: %" B_PRIx64 "\n", len); 81 } 82 83 uint64 regs = 0; 84 if (!fdtModule->get_reg(fdtDev, 0, ®s, &fRegsLen)) 85 return B_ERROR; 86 87 fRegsArea.SetTo(map_physical_memory("PCI Config MMIO", regs, fRegsLen, B_ANY_KERNEL_ADDRESS, 88 B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA, (void**)&fRegs)); 89 CHECK_RET(fRegsArea.Get()); 90 91 return B_OK; 92 } 93 94 95 status_t 96 ECAMPCIControllerFDT::Finalize() 97 { 98 dprintf("finalize PCI controller from FDT\n"); 99 100 DeviceNodePutter<&gDeviceManager> parent(gDeviceManager->get_parent_node(fNode)); 101 102 fdt_device_module_info* parentModule; 103 fdt_device* parentDev; 104 105 CHECK_RET(gDeviceManager->get_driver(parent.Get(), (driver_module_info**)&parentModule, 106 (void**)&parentDev)); 107 108 struct fdt_interrupt_map* interruptMap = parentModule->get_interrupt_map(parentDev); 109 parentModule->print_interrupt_map(interruptMap); 110 111 for (int bus = 0; bus < 8; bus++) { 112 // TODO: Proper multiple domain handling. (domain, bus) pair should be converted to virtual 113 // bus before calling PCI module interface. 114 for (int device = 0; device < 32; device++) { 115 uint32 vendorID = gPCI->read_pci_config(bus, device, 0, PCI_vendor_id, 2); 116 if ((vendorID != 0xffffffff) && (vendorID != 0xffff)) { 117 uint32 headerType = gPCI->read_pci_config(bus, device, 0, PCI_header_type, 1); 118 if ((headerType & 0x80) != 0) { 119 for (int function = 0; function < 8; function++) { 120 FinalizeInterrupts(parentModule, interruptMap, bus, device, function); 121 } 122 } else { 123 FinalizeInterrupts(parentModule, interruptMap, bus, device, 0); 124 } 125 } 126 } 127 } 128 129 return B_OK; 130 } 131 132 133 void 134 ECAMPCIControllerFDT::FinalizeInterrupts(fdt_device_module_info* fdtModule, 135 struct fdt_interrupt_map* interruptMap, int bus, int device, int function) 136 { 137 uint32 childAddr = ((bus & 0xff) << 16) | ((device & 0x1f) << 11) | ((function & 0x07) << 8); 138 uint32 interruptPin = gPCI->read_pci_config(bus, device, function, PCI_interrupt_pin, 1); 139 140 if (interruptPin == 0xffffffff) { 141 dprintf("Error: Unable to read interrupt pin!\n"); 142 return; 143 } 144 145 uint32 irq = fdtModule->lookup_interrupt_map(interruptMap, childAddr, interruptPin); 146 if (irq == 0xffffffff) { 147 dprintf("no interrupt mapping for childAddr: (%d:%d:%d), childIrq: %d)\n", 148 bus, device, function, interruptPin); 149 } else { 150 dprintf("configure interrupt (%d,%d,%d) --> %d\n", 151 bus, device, function, irq); 152 gPCI->update_interrupt_line(bus, device, function, irq); 153 } 154 } 155