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 pci_resource_range range = {}; 48 range.host_address = parentAdr; 49 range.pci_address = childAdr; 50 range.size = len; 51 52 if ((type & fdtPciRangePrefechable) != 0) 53 range.address_type |= PCI_address_prefetchable; 54 55 switch (type & fdtPciRangeTypeMask) { 56 case fdtPciRangeIoPort: 57 range.type = B_IO_PORT; 58 fResourceRanges.Add(range); 59 break; 60 case fdtPciRangeMmio32Bit: 61 range.type = B_IO_MEMORY; 62 range.address_type |= PCI_address_type_32; 63 fResourceRanges.Add(range); 64 break; 65 case fdtPciRangeMmio64Bit: 66 range.type = B_IO_MEMORY; 67 range.address_type |= PCI_address_type_64; 68 fResourceRanges.Add(range); 69 break; 70 } 71 72 switch (type & fdtPciRangeTypeMask) { 73 case fdtPciRangeConfig: dprintf("CONFIG"); break; 74 case fdtPciRangeIoPort: dprintf("IOPORT"); break; 75 case fdtPciRangeMmio32Bit: dprintf("MMIO32"); break; 76 case fdtPciRangeMmio64Bit: dprintf("MMIO64"); break; 77 } 78 79 dprintf(" (0x%08" B_PRIx32 "): ", type); 80 dprintf("child: %08" B_PRIx64, childAdr); 81 dprintf(", parent: %08" B_PRIx64, parentAdr); 82 dprintf(", len: %" B_PRIx64 "\n", len); 83 } 84 85 uint64 regs = 0; 86 if (!fdtModule->get_reg(fdtDev, 0, ®s, &fRegsLen)) 87 return B_ERROR; 88 89 fRegsArea.SetTo(map_physical_memory("PCI Config MMIO", regs, fRegsLen, B_ANY_KERNEL_ADDRESS, 90 B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA, (void**)&fRegs)); 91 CHECK_RET(fRegsArea.Get()); 92 93 return B_OK; 94 } 95 96 97 status_t 98 ECAMPCIControllerFDT::Finalize() 99 { 100 dprintf("finalize PCI controller from FDT\n"); 101 102 DeviceNodePutter<&gDeviceManager> parent(gDeviceManager->get_parent_node(fNode)); 103 104 fdt_device_module_info* parentModule; 105 fdt_device* parentDev; 106 107 CHECK_RET(gDeviceManager->get_driver(parent.Get(), (driver_module_info**)&parentModule, 108 (void**)&parentDev)); 109 110 struct fdt_interrupt_map* interruptMap = parentModule->get_interrupt_map(parentDev); 111 parentModule->print_interrupt_map(interruptMap); 112 113 for (int bus = 0; bus < 8; bus++) { 114 // TODO: Proper multiple domain handling. (domain, bus) pair should be converted to virtual 115 // bus before calling PCI module interface. 116 for (int device = 0; device < 32; device++) { 117 uint32 vendorID = gPCI->read_pci_config(bus, device, 0, PCI_vendor_id, 2); 118 if ((vendorID != 0xffffffff) && (vendorID != 0xffff)) { 119 uint32 headerType = gPCI->read_pci_config(bus, device, 0, PCI_header_type, 1); 120 if ((headerType & 0x80) != 0) { 121 for (int function = 0; function < 8; function++) { 122 FinalizeInterrupts(parentModule, interruptMap, bus, device, function); 123 } 124 } else { 125 FinalizeInterrupts(parentModule, interruptMap, bus, device, 0); 126 } 127 } 128 } 129 } 130 131 return B_OK; 132 } 133 134 135 void 136 ECAMPCIControllerFDT::FinalizeInterrupts(fdt_device_module_info* fdtModule, 137 struct fdt_interrupt_map* interruptMap, int bus, int device, int function) 138 { 139 uint32 childAddr = ((bus & 0xff) << 16) | ((device & 0x1f) << 11) | ((function & 0x07) << 8); 140 uint32 interruptPin = gPCI->read_pci_config(bus, device, function, PCI_interrupt_pin, 1); 141 142 if (interruptPin == 0xffffffff) { 143 dprintf("Error: Unable to read interrupt pin!\n"); 144 return; 145 } 146 147 uint32 irq = fdtModule->lookup_interrupt_map(interruptMap, childAddr, interruptPin); 148 if (irq == 0xffffffff) { 149 dprintf("no interrupt mapping for childAddr: (%d:%d:%d), childIrq: %d)\n", 150 bus, device, function, interruptPin); 151 } else { 152 dprintf("configure interrupt (%d,%d,%d) --> %d\n", 153 bus, device, function, irq); 154 gPCI->update_interrupt_line(bus, device, function, irq); 155 } 156 } 157