1 /* 2 * Copyright 2022, Haiku, Inc. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 7 #include "X86PCIController.h" 8 9 #include <ioapic.h> 10 11 #include <AutoDeleterDrivers.h> 12 #include <util/AutoLock.h> 13 14 #include <string.h> 15 #include <new> 16 17 18 #define PCI_MECH1_REQ_PORT 0xCF8 19 #define PCI_MECH1_DATA_PORT 0xCFC 20 #define PCI_MECH1_REQ_DATA(bus, device, func, offset) \ 21 (0x80000000 | (bus << 16) | (device << 11) | (func << 8) | (offset & ~3)) 22 23 #define PCI_MECH2_ENABLE_PORT 0x0cf8 24 #define PCI_MECH2_FORWARD_PORT 0x0cfa 25 #define PCI_MECH2_CONFIG_PORT(dev, offset) \ 26 (uint16)(0xC00 | (dev << 8) | offset) 27 28 29 //#pragma mark - driver 30 31 32 float 33 X86PCIController::SupportsDevice(device_node* parent) 34 { 35 const char* bus; 36 if (gDeviceManager->get_attr_string(parent, B_DEVICE_BUS, &bus, false) < B_OK) 37 return -1.0f; 38 39 if (strcmp(bus, "root") == 0) 40 return 1.0f; 41 42 return 0.0; 43 } 44 45 46 status_t 47 X86PCIController::RegisterDevice(device_node* parent) 48 { 49 device_attr attrs[] = { 50 { B_DEVICE_PRETTY_NAME, B_STRING_TYPE, {.string = "X86 PCI Host Controller"} }, 51 { B_DEVICE_FIXED_CHILD, B_STRING_TYPE, {.string = "bus_managers/pci/root/driver_v1"} }, 52 {} 53 }; 54 55 return gDeviceManager->register_node(parent, PCI_X86_DRIVER_MODULE_NAME, attrs, NULL, NULL); 56 } 57 58 59 status_t 60 X86PCIController::InitDriver(device_node* node, X86PCIController*& outDriver) 61 { 62 bool search_mech1 = true; 63 bool search_mech2 = true; 64 bool search_mechpcie = true; 65 void *config = NULL; 66 67 config = load_driver_settings("pci"); 68 if (config) { 69 const char *mech = get_driver_parameter(config, "mechanism", NULL, NULL); 70 if (mech) { 71 search_mech1 = search_mech2 = search_mechpcie = false; 72 if (strcmp(mech, "1") == 0) 73 search_mech1 = true; 74 else if (strcmp(mech, "2") == 0) 75 search_mech2 = true; 76 else if (strcmp(mech, "pcie") == 0) 77 search_mechpcie = true; 78 else 79 panic("Unknown pci config mechanism setting %s\n", mech); 80 } 81 unload_driver_settings(config); 82 } 83 84 // PCI configuration mechanism PCIe is the preferred one. 85 // If it doesn't work, try mechanism 1. 86 // If it doesn't work, try mechanism 2. 87 88 if (search_mechpcie) { 89 if (CreateDriver(node, new(std::nothrow) X86PCIControllerMethPcie(), outDriver) >= B_OK) 90 return B_OK; 91 } 92 if (search_mech1) { 93 if (CreateDriver(node, new(std::nothrow) X86PCIControllerMeth1(), outDriver) >= B_OK) 94 return B_OK; 95 } 96 if (search_mech2) { 97 if (CreateDriver(node, new(std::nothrow) X86PCIControllerMeth2(), outDriver) >= B_OK) 98 return B_OK; 99 } 100 101 dprintf("PCI: no configuration mechanism found\n"); 102 return B_ERROR; 103 } 104 105 106 status_t 107 X86PCIController::CreateDriver(device_node* node, X86PCIController* driverIn, 108 X86PCIController*& driverOut) 109 { 110 ObjectDeleter<X86PCIController> driver(driverIn); 111 if (!driver.IsSet()) 112 return B_NO_MEMORY; 113 114 CHECK_RET(driver->InitDriverInt(node)); 115 driverOut = driver.Detach(); 116 return B_OK; 117 } 118 119 120 status_t 121 X86PCIController::InitDriverInt(device_node* node) 122 { 123 fNode = node; 124 return B_OK; 125 } 126 127 128 void 129 X86PCIController::UninitDriver() 130 { 131 delete this; 132 } 133 134 135 //#pragma mark - PCI controller 136 137 138 status_t 139 X86PCIController::ReadIrq(uint8 bus, uint8 device, uint8 function, 140 uint8 pin, uint8& irq) 141 { 142 return B_UNSUPPORTED; 143 } 144 145 146 status_t 147 X86PCIController::WriteIrq(uint8 bus, uint8 device, uint8 function, 148 uint8 pin, uint8 irq) 149 { 150 return B_UNSUPPORTED; 151 } 152 153 154 status_t 155 X86PCIController::GetRange(uint32 index, pci_resource_range* range) 156 { 157 return B_BAD_INDEX; 158 } 159 160 161 status_t 162 X86PCIController::Finalize() 163 { 164 ioapic_init(); 165 return B_OK; 166 } 167 168 169 //#pragma mark - X86PCIControllerMeth1 170 171 172 status_t 173 X86PCIControllerMeth1::InitDriverInt(device_node* node) 174 { 175 CHECK_RET(X86PCIController::InitDriverInt(node)); 176 177 // check for mechanism 1 178 out32(0x80000000, PCI_MECH1_REQ_PORT); 179 if (0x80000000 == in32(PCI_MECH1_REQ_PORT)) { 180 dprintf("PCI: mechanism 1 controller found\n"); 181 return B_OK; 182 } 183 return B_ERROR; 184 } 185 186 187 status_t 188 X86PCIControllerMeth1::ReadConfig( 189 uint8 bus, uint8 device, uint8 function, 190 uint16 offset, uint8 size, uint32 &value) 191 { 192 if (offset > 0xff) 193 return ERANGE; 194 195 InterruptsSpinLocker lock(fLock); 196 out32(PCI_MECH1_REQ_DATA(bus, device, function, offset), PCI_MECH1_REQ_PORT); 197 switch (size) { 198 case 1: 199 value = in8(PCI_MECH1_DATA_PORT + (offset & 3)); 200 break; 201 case 2: 202 value = in16(PCI_MECH1_DATA_PORT + (offset & 3)); 203 break; 204 case 4: 205 value = in32(PCI_MECH1_DATA_PORT); 206 break; 207 default: 208 return B_BAD_VALUE; 209 } 210 211 return B_OK; 212 } 213 214 215 status_t 216 X86PCIControllerMeth1::WriteConfig( 217 uint8 bus, uint8 device, uint8 function, 218 uint16 offset, uint8 size, uint32 value) 219 { 220 if (offset > 0xff) 221 return ERANGE; 222 223 InterruptsSpinLocker lock(fLock); 224 out32(PCI_MECH1_REQ_DATA(bus, device, function, offset), PCI_MECH1_REQ_PORT); 225 switch (size) { 226 case 1: 227 out8(value, PCI_MECH1_DATA_PORT + (offset & 3)); 228 break; 229 case 2: 230 out16(value, PCI_MECH1_DATA_PORT + (offset & 3)); 231 break; 232 case 4: 233 out32(value, PCI_MECH1_DATA_PORT); 234 break; 235 default: 236 return B_BAD_VALUE; 237 } 238 239 return B_OK; 240 } 241 242 243 status_t X86PCIControllerMeth1::GetMaxBusDevices(int32& count) 244 { 245 count = 32; 246 return B_OK; 247 } 248 249 250 //#pragma mark - X86PCIControllerMeth2 251 252 253 status_t 254 X86PCIControllerMeth2::InitDriverInt(device_node* node) 255 { 256 CHECK_RET(X86PCIController::InitDriverInt(node)); 257 258 // check for mechanism 2 259 out8(0x00, 0xCFB); 260 out8(0x00, 0xCF8); 261 out8(0x00, 0xCFA); 262 if (in8(0xCF8) == 0x00 && in8(0xCFA) == 0x00) { 263 dprintf("PCI: mechanism 2 controller found\n"); 264 return B_OK; 265 } 266 return B_ERROR; 267 } 268 269 270 status_t 271 X86PCIControllerMeth2::ReadConfig( 272 uint8 bus, uint8 device, uint8 function, 273 uint16 offset, uint8 size, uint32 &value) 274 { 275 if (offset > 0xff) 276 return ERANGE; 277 278 InterruptsSpinLocker lock(fLock); 279 out8((uint8)(0xf0 | (function << 1)), PCI_MECH2_ENABLE_PORT); 280 out8(bus, PCI_MECH2_FORWARD_PORT); 281 switch (size) { 282 case 1: 283 value = in8(PCI_MECH2_CONFIG_PORT(device, offset)); 284 break; 285 case 2: 286 value = in16(PCI_MECH2_CONFIG_PORT(device, offset)); 287 break; 288 case 4: 289 value = in32(PCI_MECH2_CONFIG_PORT(device, offset)); 290 break; 291 default: 292 return B_BAD_VALUE; 293 } 294 out8(0, PCI_MECH2_ENABLE_PORT); 295 296 return B_OK; 297 } 298 299 300 status_t 301 X86PCIControllerMeth2::WriteConfig( 302 uint8 bus, uint8 device, uint8 function, 303 uint16 offset, uint8 size, uint32 value) 304 { 305 if (offset > 0xff) 306 return ERANGE; 307 308 InterruptsSpinLocker lock(fLock); 309 out8((uint8)(0xf0 | (function << 1)), PCI_MECH2_ENABLE_PORT); 310 out8(bus, PCI_MECH2_FORWARD_PORT); 311 switch (size) { 312 case 1: 313 out8(value, PCI_MECH2_CONFIG_PORT(device, offset)); 314 break; 315 case 2: 316 out16(value, PCI_MECH2_CONFIG_PORT(device, offset)); 317 break; 318 case 4: 319 out32(value, PCI_MECH2_CONFIG_PORT(device, offset)); 320 break; 321 default: 322 return B_BAD_VALUE; 323 } 324 out8(0, PCI_MECH2_ENABLE_PORT); 325 326 return B_OK; 327 } 328 329 330 status_t X86PCIControllerMeth2::GetMaxBusDevices(int32& count) 331 { 332 count = 16; 333 return B_OK; 334 } 335 336 337 //#pragma mark - X86PCIControllerMethPcie 338 339 340 status_t 341 X86PCIControllerMethPcie::InitDriverInt(device_node* node) 342 { 343 status_t status = X86PCIController::InitDriverInt(node); 344 if (status != B_OK) 345 return status; 346 347 // search ACPI 348 device_node *acpiNode = NULL; 349 { 350 device_node* deviceRoot = gDeviceManager->get_root_node(); 351 device_attr acpiAttrs[] = { 352 { B_DEVICE_BUS, B_STRING_TYPE, { .string = "acpi" }}, 353 { ACPI_DEVICE_HID_ITEM, B_STRING_TYPE, { .string = "PNP0A08" }}, 354 { NULL } 355 }; 356 if (gDeviceManager->find_child_node(deviceRoot, acpiAttrs, &acpiNode) != B_OK) 357 return ENODEV; 358 } 359 360 status = fECAMPCIController.ReadResourceInfo(acpiNode); 361 gDeviceManager->put_node(acpiNode); 362 return status; 363 } 364 365 366 status_t 367 X86PCIControllerMethPcie::ReadConfig( 368 uint8 bus, uint8 device, uint8 function, 369 uint16 offset, uint8 size, uint32 &value) 370 { 371 // fallback to mechanism 1 for out of range busses 372 if (bus < fECAMPCIController.fStartBusNumber || bus > fECAMPCIController.fEndBusNumber) { 373 return X86PCIControllerMeth1::ReadConfig(bus, device, function, offset, 374 size, value); 375 } 376 377 return fECAMPCIController.ReadConfig(bus, device, function, offset, size, value); 378 } 379 380 381 status_t 382 X86PCIControllerMethPcie::WriteConfig( 383 uint8 bus, uint8 device, uint8 function, 384 uint16 offset, uint8 size, uint32 value) 385 { 386 // fallback to mechanism 1 for out of range busses 387 if (bus < fECAMPCIController.fStartBusNumber || bus > fECAMPCIController.fEndBusNumber) { 388 return X86PCIControllerMeth1::WriteConfig(bus, device, function, offset, 389 size, value); 390 } 391 392 return fECAMPCIController.WriteConfig(bus, device, function, offset, size, value); 393 } 394 395 396 status_t 397 X86PCIControllerMethPcie::GetMaxBusDevices(int32& count) 398 { 399 return fECAMPCIController.GetMaxBusDevices(count); 400 } 401 402 403 status_t 404 X86PCIControllerMethPcie::GetRange(uint32 index, pci_resource_range* range) 405 { 406 return fECAMPCIController.GetRange(index, range); 407 } 408