1 /* 2 * Copyright 2022, Haiku, Inc. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 7 #include "ECAMPCIController.h" 8 #include <acpi.h> 9 10 #include <AutoDeleterDrivers.h> 11 12 #include "acpi_irq_routing_table.h" 13 14 #include <string.h> 15 #include <new> 16 17 18 //#pragma mark - driver 19 20 21 float 22 ECAMPCIController::SupportsDevice(device_node* parent) 23 { 24 const char* bus; 25 status_t status = gDeviceManager->get_attr_string(parent, B_DEVICE_BUS, &bus, false); 26 if (status < B_OK) 27 return -1.0f; 28 29 if (strcmp(bus, "fdt") == 0) { 30 const char* compatible; 31 status = gDeviceManager->get_attr_string(parent, "fdt/compatible", &compatible, false); 32 if (status < B_OK) 33 return -1.0f; 34 35 if (strcmp(compatible, "pci-host-ecam-generic") != 0) 36 return 0.0f; 37 38 return 1.0f; 39 } 40 41 if (strcmp(bus, "acpi") == 0) { 42 const char* hid; 43 if (gDeviceManager->get_attr_string(parent, ACPI_DEVICE_HID_ITEM, &hid, false) < B_OK) 44 return -1.0f; 45 46 if (strcmp(hid, "PNP0A03") != 0 && strcmp(hid, "PNP0A08") != 0) 47 return 0.0f; 48 49 return 1.0f; 50 } 51 52 return 0.0f; 53 } 54 55 56 status_t 57 ECAMPCIController::RegisterDevice(device_node* parent) 58 { 59 device_attr attrs[] = { 60 { B_DEVICE_PRETTY_NAME, B_STRING_TYPE, {.string = "ECAM PCI Host Controller"} }, 61 { B_DEVICE_FIXED_CHILD, B_STRING_TYPE, {.string = "bus_managers/pci/root/driver_v1"} }, 62 {} 63 }; 64 65 return gDeviceManager->register_node(parent, ECAM_PCI_DRIVER_MODULE_NAME, attrs, NULL, NULL); 66 } 67 68 69 #if !defined(ECAM_PCI_CONTROLLER_NO_INIT) 70 status_t 71 ECAMPCIController::InitDriver(device_node* node, ECAMPCIController*& outDriver) 72 { 73 dprintf("+ECAMPCIController::InitDriver()\n"); 74 DeviceNodePutter<&gDeviceManager> parentNode(gDeviceManager->get_parent_node(node)); 75 76 ObjectDeleter<ECAMPCIController> driver; 77 78 const char* bus; 79 CHECK_RET(gDeviceManager->get_attr_string(parentNode.Get(), B_DEVICE_BUS, &bus, false)); 80 if (strcmp(bus, "fdt") == 0) 81 driver.SetTo(new(std::nothrow) ECAMPCIControllerFDT()); 82 else if (strcmp(bus, "acpi") == 0) 83 driver.SetTo(new(std::nothrow) ECAMPCIControllerACPI()); 84 else 85 return B_ERROR; 86 87 if (!driver.IsSet()) 88 return B_NO_MEMORY; 89 90 driver->fNode = node; 91 92 CHECK_RET(driver->ReadResourceInfo()); 93 outDriver = driver.Detach(); 94 95 dprintf("-ECAMPCIController::InitDriver()\n"); 96 return B_OK; 97 } 98 99 100 void 101 ECAMPCIController::UninitDriver() 102 { 103 delete this; 104 } 105 #endif 106 107 108 /** Compute the virtual address for accessing a PCI ECAM register. 109 * 110 * \returns NULL if the address is out of bounds. 111 */ 112 addr_t 113 ECAMPCIController::ConfigAddress(uint8 bus, uint8 device, uint8 function, uint16 offset) 114 { 115 PciAddressEcam address { 116 .offset = offset, 117 .function = function, 118 .device = device, 119 .bus = bus 120 }; 121 if ((ROUNDDOWN(address.val, 4) + 4) > fRegsLen) 122 return 0; 123 124 return (addr_t)fRegs + address.val; 125 } 126 127 128 //#pragma mark - PCI controller 129 130 131 status_t 132 ECAMPCIController::ReadConfig(uint8 bus, uint8 device, uint8 function, 133 uint16 offset, uint8 size, uint32& value) 134 { 135 addr_t address = ConfigAddress(bus, device, function, offset); 136 if (address == 0) 137 return ERANGE; 138 139 switch (size) { 140 case 1: value = *(vuint8*)address; break; 141 case 2: value = *(vuint16*)address; break; 142 case 4: value = *(vuint32*)address; break; 143 default: 144 return B_BAD_VALUE; 145 } 146 147 return B_OK; 148 } 149 150 151 status_t 152 ECAMPCIController::WriteConfig(uint8 bus, uint8 device, uint8 function, 153 uint16 offset, uint8 size, uint32 value) 154 { 155 addr_t address = ConfigAddress(bus, device, function, offset); 156 if (address == 0) 157 return ERANGE; 158 159 switch (size) { 160 case 1: *(vuint8*)address = value; break; 161 case 2: *(vuint16*)address = value; break; 162 case 4: *(vuint32*)address = value; break; 163 default: 164 return B_BAD_VALUE; 165 } 166 167 return B_OK; 168 } 169 170 171 status_t 172 ECAMPCIController::GetMaxBusDevices(int32& count) 173 { 174 count = 32; 175 return B_OK; 176 } 177 178 179 status_t 180 ECAMPCIController::ReadIrq(uint8 bus, uint8 device, uint8 function, 181 uint8 pin, uint8& irq) 182 { 183 return B_UNSUPPORTED; 184 } 185 186 187 status_t 188 ECAMPCIController::WriteIrq(uint8 bus, uint8 device, uint8 function, 189 uint8 pin, uint8 irq) 190 { 191 return B_UNSUPPORTED; 192 } 193 194 195 status_t 196 ECAMPCIController::GetRange(uint32 index, pci_resource_range* range) 197 { 198 if (index >= (uint32)fResourceRanges.Count()) 199 return B_BAD_INDEX; 200 201 *range = fResourceRanges[index]; 202 return B_OK; 203 } 204