1 /** @file 2 Scan the entire PCI bus for root bridges to support coreboot UEFI payload. 3 4 Copyright (c) 2016, Intel Corporation. All rights reserved.<BR> 5 6 This program and the accompanying materials are licensed and made available 7 under the terms and conditions of the BSD License which accompanies this 8 distribution. The full text of the license may be found at 9 http://opensource.org/licenses/bsd-license.php. 10 11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT 12 WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 13 14 **/ 15 16 #include <PiDxe.h> 17 #include <IndustryStandard/Pci.h> 18 #include <Protocol/PciHostBridgeResourceAllocation.h> 19 #include <Protocol/PciRootBridgeIo.h> 20 #include <Library/BaseMemoryLib.h> 21 #include <Library/DebugLib.h> 22 #include <Library/MemoryAllocationLib.h> 23 #include <Library/PciHostBridgeLib.h> 24 #include <Library/PciLib.h> 25 #include "PciHostBridge.h" 26 27 /** 28 Adjust the collected PCI resource. 29 30 @param[in] Io IO aperture. 31 32 @param[in] Mem MMIO aperture. 33 34 @param[in] MemAbove4G MMIO aperture above 4G. 35 36 @param[in] PMem Prefetchable MMIO aperture. 37 38 @param[in] PMemAbove4G Prefetchable MMIO aperture above 4G. 39 **/ 40 VOID 41 AdjustRootBridgeResource ( 42 IN PCI_ROOT_BRIDGE_APERTURE *Io, 43 IN PCI_ROOT_BRIDGE_APERTURE *Mem, 44 IN PCI_ROOT_BRIDGE_APERTURE *MemAbove4G, 45 IN PCI_ROOT_BRIDGE_APERTURE *PMem, 46 IN PCI_ROOT_BRIDGE_APERTURE *PMemAbove4G 47 ) 48 { 49 UINT64 Mask; 50 51 // 52 // For now try to downgrade everything into MEM32 since 53 // - coreboot does not assign resource above 4GB 54 // - coreboot might allocate interleaved MEM32 and PMEM32 resource 55 // in some cases 56 // 57 if (PMem->Base < Mem->Base) { 58 Mem->Base = PMem->Base; 59 } 60 61 if (PMem->Limit > Mem->Limit) { 62 Mem->Limit = PMem->Limit; 63 } 64 65 PMem->Base = MAX_UINT64; 66 PMem->Limit = 0; 67 68 if (MemAbove4G->Base < 0x100000000ULL) { 69 if (MemAbove4G->Base < Mem->Base) { 70 Mem->Base = MemAbove4G->Base; 71 } 72 if (MemAbove4G->Limit > Mem->Limit) { 73 Mem->Limit = MemAbove4G->Limit; 74 } 75 MemAbove4G->Base = MAX_UINT64; 76 MemAbove4G->Limit = 0; 77 } 78 79 if (PMemAbove4G->Base < 0x100000000ULL) { 80 if (PMemAbove4G->Base < Mem->Base) { 81 Mem->Base = PMemAbove4G->Base; 82 } 83 if (PMemAbove4G->Limit > Mem->Limit) { 84 Mem->Limit = PMemAbove4G->Limit; 85 } 86 PMemAbove4G->Base = MAX_UINT64; 87 PMemAbove4G->Limit = 0; 88 } 89 90 // 91 // Align IO resource at 4K boundary 92 // 93 Mask = 0xFFFULL; 94 Io->Limit = ((Io->Limit + Mask) & ~Mask) - 1; 95 if (Io->Base != MAX_UINT64) { 96 Io->Base &= ~Mask; 97 } 98 99 // 100 // Align MEM resource at 1MB boundary 101 // 102 Mask = 0xFFFFFULL; 103 Mem->Limit = ((Mem->Limit + Mask) & ~Mask) - 1; 104 if (Mem->Base != MAX_UINT64) { 105 Mem->Base &= ~Mask; 106 } 107 } 108 109 /** 110 Probe a bar is existed or not. 111 112 @param[in] Address PCI address for the BAR. 113 @param[out] OriginalValue The original bar value returned. 114 @param[out] Value The probed bar value returned. 115 **/ 116 STATIC 117 VOID 118 PcatPciRootBridgeBarExisted ( 119 IN UINT64 Address, 120 OUT UINT32 *OriginalValue, 121 OUT UINT32 *Value 122 ) 123 { 124 UINTN PciAddress; 125 126 PciAddress = (UINTN)Address; 127 128 // 129 // Preserve the original value 130 // 131 *OriginalValue = PciRead32 (PciAddress); 132 133 // 134 // Disable timer interrupt while the BAR is probed 135 // 136 DisableInterrupts (); 137 138 PciWrite32 (PciAddress, 0xFFFFFFFF); 139 *Value = PciRead32 (PciAddress); 140 PciWrite32 (PciAddress, *OriginalValue); 141 142 // 143 // Enable interrupt 144 // 145 EnableInterrupts (); 146 } 147 148 /** 149 Parse PCI bar and collect the assigned PCI resouce information. 150 151 @param[in] Command Supported attributes. 152 153 @param[in] Bus PCI bus number. 154 155 @param[in] Device PCI device number. 156 157 @param[in] Function PCI function number. 158 159 @param[in] BarOffsetBase PCI bar start offset. 160 161 @param[in] BarOffsetEnd PCI bar end offset. 162 163 @param[in] Io IO aperture. 164 165 @param[in] Mem MMIO aperture. 166 167 @param[in] MemAbove4G MMIO aperture above 4G. 168 169 @param[in] PMem Prefetchable MMIO aperture. 170 171 @param[in] PMemAbove4G Prefetchable MMIO aperture above 4G. 172 **/ 173 STATIC 174 VOID 175 PcatPciRootBridgeParseBars ( 176 IN UINT16 Command, 177 IN UINTN Bus, 178 IN UINTN Device, 179 IN UINTN Function, 180 IN UINTN BarOffsetBase, 181 IN UINTN BarOffsetEnd, 182 IN PCI_ROOT_BRIDGE_APERTURE *Io, 183 IN PCI_ROOT_BRIDGE_APERTURE *Mem, 184 IN PCI_ROOT_BRIDGE_APERTURE *MemAbove4G, 185 IN PCI_ROOT_BRIDGE_APERTURE *PMem, 186 IN PCI_ROOT_BRIDGE_APERTURE *PMemAbove4G 187 188 ) 189 { 190 UINT32 OriginalValue; 191 UINT32 Value; 192 UINT32 OriginalUpperValue; 193 UINT32 UpperValue; 194 UINT64 Mask; 195 UINTN Offset; 196 UINTN LowBit; 197 UINT64 Base; 198 UINT64 Length; 199 UINT64 Limit; 200 PCI_ROOT_BRIDGE_APERTURE *MemAperture; 201 202 for (Offset = BarOffsetBase; Offset < BarOffsetEnd; Offset += sizeof (UINT32)) { 203 PcatPciRootBridgeBarExisted ( 204 PCI_LIB_ADDRESS (Bus, Device, Function, Offset), 205 &OriginalValue, &Value 206 ); 207 if (Value == 0) { 208 continue; 209 } 210 if ((Value & BIT0) == BIT0) { 211 // 212 // IO Bar 213 // 214 if (Command & EFI_PCI_COMMAND_IO_SPACE) { 215 Mask = 0xfffffffc; 216 Base = OriginalValue & Mask; 217 Length = ((~(Value & Mask)) & Mask) + 0x04; 218 if (!(Value & 0xFFFF0000)) { 219 Length &= 0x0000FFFF; 220 } 221 Limit = Base + Length - 1; 222 223 if ((Base > 0) && (Base < Limit)) { 224 if (Io->Base > Base) { 225 Io->Base = Base; 226 } 227 if (Io->Limit < Limit) { 228 Io->Limit = Limit; 229 } 230 } 231 } 232 } else { 233 // 234 // Mem Bar 235 // 236 if (Command & EFI_PCI_COMMAND_MEMORY_SPACE) { 237 238 Mask = 0xfffffff0; 239 Base = OriginalValue & Mask; 240 Length = Value & Mask; 241 242 if ((Value & (BIT1 | BIT2)) == 0) { 243 // 244 // 32bit 245 // 246 Length = ((~Length) + 1) & 0xffffffff; 247 248 if ((Value & BIT3) == BIT3) { 249 MemAperture = PMem; 250 } else { 251 MemAperture = Mem; 252 } 253 } else { 254 // 255 // 64bit 256 // 257 Offset += 4; 258 PcatPciRootBridgeBarExisted ( 259 PCI_LIB_ADDRESS (Bus, Device, Function, Offset), 260 &OriginalUpperValue, 261 &UpperValue 262 ); 263 264 Base = Base | LShiftU64 ((UINT64) OriginalUpperValue, 32); 265 Length = Length | LShiftU64 ((UINT64) UpperValue, 32); 266 if (Length != 0) { 267 LowBit = LowBitSet64 (Length); 268 Length = LShiftU64 (1ULL, LowBit); 269 } 270 271 if ((Value & BIT3) == BIT3) { 272 MemAperture = PMemAbove4G; 273 } else { 274 MemAperture = MemAbove4G; 275 } 276 } 277 278 Limit = Base + Length - 1; 279 if ((Base > 0) && (Base < Limit)) { 280 if (MemAperture->Base > Base) { 281 MemAperture->Base = Base; 282 } 283 if (MemAperture->Limit < Limit) { 284 MemAperture->Limit = Limit; 285 } 286 } 287 } 288 } 289 } 290 } 291 292 /** 293 Scan for all root bridges in platform. 294 295 @param[out] NumberOfRootBridges Number of root bridges detected 296 297 @retval Pointer to the allocated PCI_ROOT_BRIDGE structure array. 298 **/ 299 PCI_ROOT_BRIDGE * 300 ScanForRootBridges ( 301 OUT UINTN *NumberOfRootBridges 302 ) 303 { 304 UINTN PrimaryBus; 305 UINTN SubBus; 306 UINT8 Device; 307 UINT8 Function; 308 UINTN NumberOfDevices; 309 UINTN Address; 310 PCI_TYPE01 Pci; 311 UINT64 Attributes; 312 UINT64 Base; 313 UINT64 Limit; 314 UINT64 Value; 315 PCI_ROOT_BRIDGE_APERTURE Io, Mem, MemAbove4G, PMem, PMemAbove4G, *MemAperture; 316 PCI_ROOT_BRIDGE *RootBridges; 317 UINTN BarOffsetEnd; 318 319 320 *NumberOfRootBridges = 0; 321 RootBridges = NULL; 322 323 // 324 // After scanning all the PCI devices on the PCI root bridge's primary bus, 325 // update the Primary Bus Number for the next PCI root bridge to be this PCI 326 // root bridge's subordinate bus number + 1. 327 // 328 for (PrimaryBus = 0; PrimaryBus <= PCI_MAX_BUS; PrimaryBus = SubBus + 1) { 329 SubBus = PrimaryBus; 330 Attributes = 0; 331 Io.Base = Mem.Base = MemAbove4G.Base = PMem.Base = PMemAbove4G.Base = MAX_UINT64; 332 Io.Limit = Mem.Limit = MemAbove4G.Limit = PMem.Limit = PMemAbove4G.Limit = 0; 333 // 334 // Scan all the PCI devices on the primary bus of the PCI root bridge 335 // 336 for (Device = 0, NumberOfDevices = 0; Device <= PCI_MAX_DEVICE; Device++) { 337 338 for (Function = 0; Function <= PCI_MAX_FUNC; Function++) { 339 340 // 341 // Compute the PCI configuration address of the PCI device to probe 342 // 343 Address = PCI_LIB_ADDRESS (PrimaryBus, Device, Function, 0); 344 345 // 346 // Read the Vendor ID from the PCI Configuration Header 347 // 348 if (PciRead16 (Address) == MAX_UINT16) { 349 if (Function == 0) { 350 // 351 // If the PCI Configuration Read fails, or a PCI device does not 352 // exist, then skip this entire PCI device 353 // 354 break; 355 } else { 356 // 357 // If PCI function != 0, VendorId == 0xFFFF, we continue to search 358 // PCI function. 359 // 360 continue; 361 } 362 } 363 364 // 365 // Read the entire PCI Configuration Header 366 // 367 PciReadBuffer (Address, sizeof (Pci), &Pci); 368 369 // 370 // Increment the number of PCI device found on the primary bus of the 371 // PCI root bridge 372 // 373 NumberOfDevices++; 374 375 // 376 // Look for devices with the VGA Palette Snoop enabled in the COMMAND 377 // register of the PCI Config Header 378 // 379 if ((Pci.Hdr.Command & EFI_PCI_COMMAND_VGA_PALETTE_SNOOP) != 0) { 380 Attributes |= EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO; 381 Attributes |= EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO_16; 382 } 383 384 BarOffsetEnd = 0; 385 386 // 387 // PCI-PCI Bridge 388 // 389 if (IS_PCI_BRIDGE (&Pci)) { 390 // 391 // Get the Bus range that the PPB is decoding 392 // 393 if (Pci.Bridge.SubordinateBus > SubBus) { 394 // 395 // If the suborinate bus number of the PCI-PCI bridge is greater 396 // than the PCI root bridge's current subordinate bus number, 397 // then update the PCI root bridge's subordinate bus number 398 // 399 SubBus = Pci.Bridge.SubordinateBus; 400 } 401 402 // 403 // Get the I/O range that the PPB is decoding 404 // 405 Value = Pci.Bridge.IoBase & 0x0f; 406 Base = ((UINT32) Pci.Bridge.IoBase & 0xf0) << 8; 407 Limit = (((UINT32) Pci.Bridge.IoLimit & 0xf0) << 8) | 0x0fff; 408 if (Value == BIT0) { 409 Base |= ((UINT32) Pci.Bridge.IoBaseUpper16 << 16); 410 Limit |= ((UINT32) Pci.Bridge.IoLimitUpper16 << 16); 411 } 412 if ((Base > 0) && (Base < Limit)) { 413 if (Io.Base > Base) { 414 Io.Base = Base; 415 } 416 if (Io.Limit < Limit) { 417 Io.Limit = Limit; 418 } 419 } 420 421 // 422 // Get the Memory range that the PPB is decoding 423 // 424 Base = ((UINT32) Pci.Bridge.MemoryBase & 0xfff0) << 16; 425 Limit = (((UINT32) Pci.Bridge.MemoryLimit & 0xfff0) << 16) | 0xfffff; 426 if ((Base > 0) && (Base < Limit)) { 427 if (Mem.Base > Base) { 428 Mem.Base = Base; 429 } 430 if (Mem.Limit < Limit) { 431 Mem.Limit = Limit; 432 } 433 } 434 435 // 436 // Get the Prefetchable Memory range that the PPB is decoding 437 // 438 Value = Pci.Bridge.PrefetchableMemoryBase & 0x0f; 439 Base = ((UINT32) Pci.Bridge.PrefetchableMemoryBase & 0xfff0) << 16; 440 Limit = (((UINT32) Pci.Bridge.PrefetchableMemoryLimit & 0xfff0) 441 << 16) | 0xfffff; 442 MemAperture = &PMem; 443 if (Value == BIT0) { 444 Base |= LShiftU64 (Pci.Bridge.PrefetchableBaseUpper32, 32); 445 Limit |= LShiftU64 (Pci.Bridge.PrefetchableLimitUpper32, 32); 446 MemAperture = &PMemAbove4G; 447 } 448 if ((Base > 0) && (Base < Limit)) { 449 if (MemAperture->Base > Base) { 450 MemAperture->Base = Base; 451 } 452 if (MemAperture->Limit < Limit) { 453 MemAperture->Limit = Limit; 454 } 455 } 456 457 // 458 // Look at the PPB Configuration for legacy decoding attributes 459 // 460 if ((Pci.Bridge.BridgeControl & EFI_PCI_BRIDGE_CONTROL_ISA) 461 == EFI_PCI_BRIDGE_CONTROL_ISA) { 462 Attributes |= EFI_PCI_ATTRIBUTE_ISA_IO; 463 Attributes |= EFI_PCI_ATTRIBUTE_ISA_IO_16; 464 Attributes |= EFI_PCI_ATTRIBUTE_ISA_MOTHERBOARD_IO; 465 } 466 if ((Pci.Bridge.BridgeControl & EFI_PCI_BRIDGE_CONTROL_VGA) 467 == EFI_PCI_BRIDGE_CONTROL_VGA) { 468 Attributes |= EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO; 469 Attributes |= EFI_PCI_ATTRIBUTE_VGA_MEMORY; 470 Attributes |= EFI_PCI_ATTRIBUTE_VGA_IO; 471 if ((Pci.Bridge.BridgeControl & EFI_PCI_BRIDGE_CONTROL_VGA_16) 472 != 0) { 473 Attributes |= EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO_16; 474 Attributes |= EFI_PCI_ATTRIBUTE_VGA_IO_16; 475 } 476 } 477 478 BarOffsetEnd = OFFSET_OF (PCI_TYPE01, Bridge.Bar[2]); 479 } else { 480 // 481 // Parse the BARs of the PCI device to get what I/O Ranges, Memory 482 // Ranges, and Prefetchable Memory Ranges the device is decoding 483 // 484 if ((Pci.Hdr.HeaderType & HEADER_LAYOUT_CODE) == HEADER_TYPE_DEVICE) { 485 BarOffsetEnd = OFFSET_OF (PCI_TYPE00, Device.Bar[6]); 486 } 487 } 488 489 PcatPciRootBridgeParseBars ( 490 Pci.Hdr.Command, 491 PrimaryBus, 492 Device, 493 Function, 494 OFFSET_OF (PCI_TYPE00, Device.Bar), 495 BarOffsetEnd, 496 &Io, 497 &Mem, &MemAbove4G, 498 &PMem, &PMemAbove4G 499 ); 500 501 // 502 // See if the PCI device is an IDE controller 503 // 504 if (IS_CLASS2 (&Pci, PCI_CLASS_MASS_STORAGE, 505 PCI_CLASS_MASS_STORAGE_IDE)) { 506 if (Pci.Hdr.ClassCode[0] & 0x80) { 507 Attributes |= EFI_PCI_ATTRIBUTE_IDE_PRIMARY_IO; 508 Attributes |= EFI_PCI_ATTRIBUTE_IDE_SECONDARY_IO; 509 } 510 if (Pci.Hdr.ClassCode[0] & 0x01) { 511 Attributes |= EFI_PCI_ATTRIBUTE_IDE_PRIMARY_IO; 512 } 513 if (Pci.Hdr.ClassCode[0] & 0x04) { 514 Attributes |= EFI_PCI_ATTRIBUTE_IDE_SECONDARY_IO; 515 } 516 } 517 518 // 519 // See if the PCI device is a legacy VGA controller or 520 // a standard VGA controller 521 // 522 if (IS_CLASS2 (&Pci, PCI_CLASS_OLD, PCI_CLASS_OLD_VGA) || 523 IS_CLASS2 (&Pci, PCI_CLASS_DISPLAY, PCI_CLASS_DISPLAY_VGA) 524 ) { 525 Attributes |= EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO; 526 Attributes |= EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO_16; 527 Attributes |= EFI_PCI_ATTRIBUTE_VGA_MEMORY; 528 Attributes |= EFI_PCI_ATTRIBUTE_VGA_IO; 529 Attributes |= EFI_PCI_ATTRIBUTE_VGA_IO_16; 530 } 531 532 // 533 // See if the PCI Device is a PCI - ISA or PCI - EISA 534 // or ISA_POSITIVIE_DECODE Bridge device 535 // 536 if (Pci.Hdr.ClassCode[2] == PCI_CLASS_BRIDGE) { 537 if (Pci.Hdr.ClassCode[1] == PCI_CLASS_BRIDGE_ISA || 538 Pci.Hdr.ClassCode[1] == PCI_CLASS_BRIDGE_EISA || 539 Pci.Hdr.ClassCode[1] == PCI_CLASS_BRIDGE_ISA_PDECODE) { 540 Attributes |= EFI_PCI_ATTRIBUTE_ISA_IO; 541 Attributes |= EFI_PCI_ATTRIBUTE_ISA_IO_16; 542 Attributes |= EFI_PCI_ATTRIBUTE_ISA_MOTHERBOARD_IO; 543 } 544 } 545 546 // 547 // If this device is not a multi function device, then skip the rest 548 // of this PCI device 549 // 550 if (Function == 0 && !IS_PCI_MULTI_FUNC (&Pci)) { 551 break; 552 } 553 } 554 } 555 556 // 557 // If at least one PCI device was found on the primary bus of this PCI 558 // root bridge, then the PCI root bridge exists. 559 // 560 if (NumberOfDevices > 0) { 561 RootBridges = ReallocatePool ( 562 (*NumberOfRootBridges) * sizeof (PCI_ROOT_BRIDGE), 563 (*NumberOfRootBridges + 1) * sizeof (PCI_ROOT_BRIDGE), 564 RootBridges 565 ); 566 ASSERT (RootBridges != NULL); 567 568 AdjustRootBridgeResource (&Io, &Mem, &MemAbove4G, &PMem, &PMemAbove4G); 569 570 InitRootBridge ( 571 Attributes, Attributes, 0, 572 (UINT8) PrimaryBus, (UINT8) SubBus, 573 &Io, &Mem, &MemAbove4G, &PMem, &PMemAbove4G, 574 &RootBridges[*NumberOfRootBridges] 575 ); 576 RootBridges[*NumberOfRootBridges].ResourceAssigned = TRUE; 577 // 578 // Increment the index for the next PCI Root Bridge 579 // 580 (*NumberOfRootBridges)++; 581 } 582 } 583 584 return RootBridges; 585 } 586