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 32float 33X86PCIController::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 46status_t 47X86PCIController::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 59status_t 60X86PCIController::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 106status_t 107X86PCIController::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 120status_t 121X86PCIController::InitDriverInt(device_node* node) 122{ 123 fNode = node; 124 return B_OK; 125} 126 127 128void 129X86PCIController::UninitDriver() 130{ 131 delete this; 132} 133 134 135//#pragma mark - PCI controller 136 137 138status_t 139X86PCIController::ReadIrq(uint8 bus, uint8 device, uint8 function, 140 uint8 pin, uint8& irq) 141{ 142 return B_UNSUPPORTED; 143} 144 145 146status_t 147X86PCIController::WriteIrq(uint8 bus, uint8 device, uint8 function, 148 uint8 pin, uint8 irq) 149{ 150 return B_UNSUPPORTED; 151} 152 153 154status_t 155X86PCIController::GetRange(uint32 index, pci_resource_range* range) 156{ 157 return B_BAD_INDEX; 158} 159 160 161status_t 162X86PCIController::Finalize() 163{ 164 ioapic_init(); 165 return B_OK; 166} 167 168 169//#pragma mark - X86PCIControllerMeth1 170 171 172status_t 173X86PCIControllerMeth1::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 187status_t 188X86PCIControllerMeth1::ReadConfig( 189 uint8 bus, uint8 device, uint8 function, 190 uint16 offset, uint8 size, uint32 &value) 191{ 192 if (offset > 0xff) 193 return B_BAD_VALUE; 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_ERROR; 209 } 210 211 return B_OK; 212} 213 214 215status_t 216X86PCIControllerMeth1::WriteConfig( 217 uint8 bus, uint8 device, uint8 function, 218 uint16 offset, uint8 size, uint32 value) 219{ 220 if (offset > 0xff) 221 return B_BAD_VALUE; 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_ERROR; 237 } 238 239 return B_OK; 240} 241 242 243status_t X86PCIControllerMeth1::GetMaxBusDevices(int32& count) 244{ 245 count = 32; 246 return B_OK; 247} 248 249 250//#pragma mark - X86PCIControllerMeth2 251 252 253status_t 254X86PCIControllerMeth2::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 270status_t 271X86PCIControllerMeth2::ReadConfig( 272 uint8 bus, uint8 device, uint8 function, 273 uint16 offset, uint8 size, uint32 &value) 274{ 275 if (offset > 0xff) 276 return B_BAD_VALUE; 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_ERROR; 293 } 294 out8(0, PCI_MECH2_ENABLE_PORT); 295 296 return B_OK; 297} 298 299 300status_t 301X86PCIControllerMeth2::WriteConfig( 302 uint8 bus, uint8 device, uint8 function, 303 uint16 offset, uint8 size, uint32 value) 304{ 305 if (offset > 0xff) 306 return B_BAD_VALUE; 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_ERROR; 323 } 324 out8(0, PCI_MECH2_ENABLE_PORT); 325 326 return B_OK; 327} 328 329 330status_t X86PCIControllerMeth2::GetMaxBusDevices(int32& count) 331{ 332 count = 16; 333 return B_OK; 334} 335 336 337//#pragma mark - X86PCIControllerMethPcie 338 339 340status_t 341X86PCIControllerMethPcie::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 366status_t 367X86PCIControllerMethPcie::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 381status_t 382X86PCIControllerMethPcie::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 396status_t 397X86PCIControllerMethPcie::GetMaxBusDevices(int32& count) 398{ 399 return fECAMPCIController.GetMaxBusDevices(count); 400} 401 402 403status_t 404X86PCIControllerMethPcie::GetRange(uint32 index, pci_resource_range* range) 405{ 406 return fECAMPCIController.GetRange(index, range); 407} 408