1 /** @file 2 PCI emumeration support functions implementation for PCI Bus module. 3 4 Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR> 5 (C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR> 6 This program and the accompanying materials 7 are licensed and made available under the terms and conditions of the BSD License 8 which accompanies this 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, 12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 13 14 **/ 15 16 #include "PciBus.h" 17 18 extern CHAR16 *mBarTypeStr[]; 19 20 /** 21 This routine is used to check whether the pci device is present. 22 23 @param PciRootBridgeIo Pointer to instance of EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL. 24 @param Pci Output buffer for PCI device configuration space. 25 @param Bus PCI bus NO. 26 @param Device PCI device NO. 27 @param Func PCI Func NO. 28 29 @retval EFI_NOT_FOUND PCI device not present. 30 @retval EFI_SUCCESS PCI device is found. 31 32 **/ 33 EFI_STATUS 34 PciDevicePresent ( 35 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo, 36 OUT PCI_TYPE00 *Pci, 37 IN UINT8 Bus, 38 IN UINT8 Device, 39 IN UINT8 Func 40 ) 41 { 42 UINT64 Address; 43 EFI_STATUS Status; 44 45 // 46 // Create PCI address map in terms of Bus, Device and Func 47 // 48 Address = EFI_PCI_ADDRESS (Bus, Device, Func, 0); 49 50 // 51 // Read the Vendor ID register 52 // 53 Status = PciRootBridgeIo->Pci.Read ( 54 PciRootBridgeIo, 55 EfiPciWidthUint32, 56 Address, 57 1, 58 Pci 59 ); 60 61 if (!EFI_ERROR (Status) && (Pci->Hdr).VendorId != 0xffff) { 62 // 63 // Read the entire config header for the device 64 // 65 Status = PciRootBridgeIo->Pci.Read ( 66 PciRootBridgeIo, 67 EfiPciWidthUint32, 68 Address, 69 sizeof (PCI_TYPE00) / sizeof (UINT32), 70 Pci 71 ); 72 73 return EFI_SUCCESS; 74 } 75 76 return EFI_NOT_FOUND; 77 } 78 79 /** 80 Collect all the resource information under this root bridge. 81 82 A database that records all the information about pci device subject to this 83 root bridge will then be created. 84 85 @param Bridge Parent bridge instance. 86 @param StartBusNumber Bus number of begining. 87 88 @retval EFI_SUCCESS PCI device is found. 89 @retval other Some error occurred when reading PCI bridge information. 90 91 **/ 92 EFI_STATUS 93 PciPciDeviceInfoCollector ( 94 IN PCI_IO_DEVICE *Bridge, 95 IN UINT8 StartBusNumber 96 ) 97 { 98 EFI_STATUS Status; 99 PCI_TYPE00 Pci; 100 UINT8 Device; 101 UINT8 Func; 102 UINT8 SecBus; 103 PCI_IO_DEVICE *PciIoDevice; 104 EFI_PCI_IO_PROTOCOL *PciIo; 105 106 Status = EFI_SUCCESS; 107 SecBus = 0; 108 109 for (Device = 0; Device <= PCI_MAX_DEVICE; Device++) { 110 111 for (Func = 0; Func <= PCI_MAX_FUNC; Func++) { 112 113 // 114 // Check to see whether PCI device is present 115 // 116 Status = PciDevicePresent ( 117 Bridge->PciRootBridgeIo, 118 &Pci, 119 (UINT8) StartBusNumber, 120 (UINT8) Device, 121 (UINT8) Func 122 ); 123 124 if (EFI_ERROR (Status) && Func == 0) { 125 // 126 // go to next device if there is no Function 0 127 // 128 break; 129 } 130 131 if (!EFI_ERROR (Status)) { 132 133 // 134 // Call back to host bridge function 135 // 136 PreprocessController (Bridge, (UINT8) StartBusNumber, Device, Func, EfiPciBeforeResourceCollection); 137 138 // 139 // Collect all the information about the PCI device discovered 140 // 141 Status = PciSearchDevice ( 142 Bridge, 143 &Pci, 144 (UINT8) StartBusNumber, 145 Device, 146 Func, 147 &PciIoDevice 148 ); 149 150 // 151 // Recursively scan PCI busses on the other side of PCI-PCI bridges 152 // 153 // 154 if (!EFI_ERROR (Status) && (IS_PCI_BRIDGE (&Pci) || IS_CARDBUS_BRIDGE (&Pci))) { 155 156 // 157 // If it is PPB, we need to get the secondary bus to continue the enumeration 158 // 159 PciIo = &(PciIoDevice->PciIo); 160 161 Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8, PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET, 1, &SecBus); 162 163 if (EFI_ERROR (Status)) { 164 return Status; 165 } 166 167 // 168 // Get resource padding for PPB 169 // 170 GetResourcePaddingPpb (PciIoDevice); 171 172 // 173 // Deep enumerate the next level bus 174 // 175 Status = PciPciDeviceInfoCollector ( 176 PciIoDevice, 177 (UINT8) (SecBus) 178 ); 179 180 } 181 182 if (Func == 0 && !IS_PCI_MULTI_FUNC (&Pci)) { 183 184 // 185 // Skip sub functions, this is not a multi function device 186 // 187 Func = PCI_MAX_FUNC; 188 } 189 } 190 191 } 192 } 193 194 return EFI_SUCCESS; 195 } 196 197 /** 198 Seach required device and create PCI device instance. 199 200 @param Bridge Parent bridge instance. 201 @param Pci Input PCI device information block. 202 @param Bus PCI bus NO. 203 @param Device PCI device NO. 204 @param Func PCI func NO. 205 @param PciDevice Output of searched PCI device instance. 206 207 @retval EFI_SUCCESS Successfully created PCI device instance. 208 @retval EFI_OUT_OF_RESOURCES Cannot get PCI device information. 209 210 **/ 211 EFI_STATUS 212 PciSearchDevice ( 213 IN PCI_IO_DEVICE *Bridge, 214 IN PCI_TYPE00 *Pci, 215 IN UINT8 Bus, 216 IN UINT8 Device, 217 IN UINT8 Func, 218 OUT PCI_IO_DEVICE **PciDevice 219 ) 220 { 221 PCI_IO_DEVICE *PciIoDevice; 222 223 PciIoDevice = NULL; 224 225 DEBUG (( 226 EFI_D_INFO, 227 "PciBus: Discovered %s @ [%02x|%02x|%02x]\n", 228 IS_PCI_BRIDGE (Pci) ? L"PPB" : 229 IS_CARDBUS_BRIDGE (Pci) ? L"P2C" : 230 L"PCI", 231 Bus, Device, Func 232 )); 233 234 if (!IS_PCI_BRIDGE (Pci)) { 235 236 if (IS_CARDBUS_BRIDGE (Pci)) { 237 PciIoDevice = GatherP2CInfo ( 238 Bridge, 239 Pci, 240 Bus, 241 Device, 242 Func 243 ); 244 if ((PciIoDevice != NULL) && gFullEnumeration) { 245 InitializeP2C (PciIoDevice); 246 } 247 } else { 248 249 // 250 // Create private data for Pci Device 251 // 252 PciIoDevice = GatherDeviceInfo ( 253 Bridge, 254 Pci, 255 Bus, 256 Device, 257 Func 258 ); 259 260 } 261 262 } else { 263 264 // 265 // Create private data for PPB 266 // 267 PciIoDevice = GatherPpbInfo ( 268 Bridge, 269 Pci, 270 Bus, 271 Device, 272 Func 273 ); 274 275 // 276 // Special initialization for PPB including making the PPB quiet 277 // 278 if ((PciIoDevice != NULL) && gFullEnumeration) { 279 InitializePpb (PciIoDevice); 280 } 281 } 282 283 if (PciIoDevice == NULL) { 284 return EFI_OUT_OF_RESOURCES; 285 } 286 287 // 288 // Update the bar information for this PCI device so as to support some specific device 289 // 290 UpdatePciInfo (PciIoDevice); 291 292 if (PciIoDevice->DevicePath == NULL) { 293 return EFI_OUT_OF_RESOURCES; 294 } 295 296 // 297 // Detect this function has option rom 298 // 299 if (gFullEnumeration) { 300 301 if (!IS_CARDBUS_BRIDGE (Pci)) { 302 303 GetOpRomInfo (PciIoDevice); 304 305 } 306 307 ResetPowerManagementFeature (PciIoDevice); 308 309 } 310 311 // 312 // Insert it into a global tree for future reference 313 // 314 InsertPciDevice (Bridge, PciIoDevice); 315 316 // 317 // Determine PCI device attributes 318 // 319 320 if (PciDevice != NULL) { 321 *PciDevice = PciIoDevice; 322 } 323 324 return EFI_SUCCESS; 325 } 326 327 /** 328 Dump the PPB padding resource information. 329 330 @param PciIoDevice PCI IO instance. 331 @param ResourceType The desired resource type to dump. 332 PciBarTypeUnknown means to dump all types of resources. 333 **/ 334 VOID 335 DumpPpbPaddingResource ( 336 IN PCI_IO_DEVICE *PciIoDevice, 337 IN PCI_BAR_TYPE ResourceType 338 ) 339 { 340 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptor; 341 PCI_BAR_TYPE Type; 342 343 if (PciIoDevice->ResourcePaddingDescriptors == NULL) { 344 return; 345 } 346 347 if (ResourceType == PciBarTypeIo16 || ResourceType == PciBarTypeIo32) { 348 ResourceType = PciBarTypeIo; 349 } 350 351 for (Descriptor = PciIoDevice->ResourcePaddingDescriptors; Descriptor->Desc != ACPI_END_TAG_DESCRIPTOR; Descriptor++) { 352 353 Type = PciBarTypeUnknown; 354 if (Descriptor->Desc == ACPI_ADDRESS_SPACE_DESCRIPTOR && Descriptor->ResType == ACPI_ADDRESS_SPACE_TYPE_IO) { 355 Type = PciBarTypeIo; 356 } else if (Descriptor->Desc == ACPI_ADDRESS_SPACE_DESCRIPTOR && Descriptor->ResType == ACPI_ADDRESS_SPACE_TYPE_MEM) { 357 358 if (Descriptor->AddrSpaceGranularity == 32) { 359 // 360 // prefechable 361 // 362 if (Descriptor->SpecificFlag == EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE) { 363 Type = PciBarTypePMem32; 364 } 365 366 // 367 // Non-prefechable 368 // 369 if (Descriptor->SpecificFlag == 0) { 370 Type = PciBarTypeMem32; 371 } 372 } 373 374 if (Descriptor->AddrSpaceGranularity == 64) { 375 // 376 // prefechable 377 // 378 if (Descriptor->SpecificFlag == EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE) { 379 Type = PciBarTypePMem64; 380 } 381 382 // 383 // Non-prefechable 384 // 385 if (Descriptor->SpecificFlag == 0) { 386 Type = PciBarTypeMem64; 387 } 388 } 389 } 390 391 if ((Type != PciBarTypeUnknown) && ((ResourceType == PciBarTypeUnknown) || (ResourceType == Type))) { 392 DEBUG (( 393 EFI_D_INFO, 394 " Padding: Type = %s; Alignment = 0x%lx;\tLength = 0x%lx\n", 395 mBarTypeStr[Type], Descriptor->AddrRangeMax, Descriptor->AddrLen 396 )); 397 } 398 } 399 400 } 401 402 /** 403 Dump the PCI BAR information. 404 405 @param PciIoDevice PCI IO instance. 406 **/ 407 VOID 408 DumpPciBars ( 409 IN PCI_IO_DEVICE *PciIoDevice 410 ) 411 { 412 UINTN Index; 413 414 for (Index = 0; Index < PCI_MAX_BAR; Index++) { 415 if (PciIoDevice->PciBar[Index].BarType == PciBarTypeUnknown) { 416 continue; 417 } 418 419 DEBUG (( 420 EFI_D_INFO, 421 " BAR[%d]: Type = %s; Alignment = 0x%lx;\tLength = 0x%lx;\tOffset = 0x%02x\n", 422 Index, mBarTypeStr[MIN (PciIoDevice->PciBar[Index].BarType, PciBarTypeMaxType)], 423 PciIoDevice->PciBar[Index].Alignment, PciIoDevice->PciBar[Index].Length, PciIoDevice->PciBar[Index].Offset 424 )); 425 } 426 427 for (Index = 0; Index < PCI_MAX_BAR; Index++) { 428 if ((PciIoDevice->VfPciBar[Index].BarType == PciBarTypeUnknown) && (PciIoDevice->VfPciBar[Index].Length == 0)) { 429 continue; 430 } 431 432 DEBUG (( 433 EFI_D_INFO, 434 " VFBAR[%d]: Type = %s; Alignment = 0x%lx;\tLength = 0x%lx;\tOffset = 0x%02x\n", 435 Index, mBarTypeStr[MIN (PciIoDevice->VfPciBar[Index].BarType, PciBarTypeMaxType)], 436 PciIoDevice->VfPciBar[Index].Alignment, PciIoDevice->VfPciBar[Index].Length, PciIoDevice->VfPciBar[Index].Offset 437 )); 438 } 439 DEBUG ((EFI_D_INFO, "\n")); 440 } 441 442 /** 443 Create PCI device instance for PCI device. 444 445 @param Bridge Parent bridge instance. 446 @param Pci Input PCI device information block. 447 @param Bus PCI device Bus NO. 448 @param Device PCI device Device NO. 449 @param Func PCI device's func NO. 450 451 @return Created PCI device instance. 452 453 **/ 454 PCI_IO_DEVICE * 455 GatherDeviceInfo ( 456 IN PCI_IO_DEVICE *Bridge, 457 IN PCI_TYPE00 *Pci, 458 IN UINT8 Bus, 459 IN UINT8 Device, 460 IN UINT8 Func 461 ) 462 { 463 UINTN Offset; 464 UINTN BarIndex; 465 PCI_IO_DEVICE *PciIoDevice; 466 467 PciIoDevice = CreatePciIoDevice ( 468 Bridge, 469 Pci, 470 Bus, 471 Device, 472 Func 473 ); 474 475 if (PciIoDevice == NULL) { 476 return NULL; 477 } 478 479 // 480 // If it is a full enumeration, disconnect the device in advance 481 // 482 if (gFullEnumeration) { 483 484 PCI_DISABLE_COMMAND_REGISTER (PciIoDevice, EFI_PCI_COMMAND_BITS_OWNED); 485 486 } 487 488 // 489 // Start to parse the bars 490 // 491 for (Offset = 0x10, BarIndex = 0; Offset <= 0x24 && BarIndex < PCI_MAX_BAR; BarIndex++) { 492 Offset = PciParseBar (PciIoDevice, Offset, BarIndex); 493 } 494 495 // 496 // Parse the SR-IOV VF bars 497 // 498 if (PcdGetBool (PcdSrIovSupport) && PciIoDevice->SrIovCapabilityOffset != 0) { 499 for (Offset = PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_BAR0, BarIndex = 0; 500 Offset <= PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_BAR5; 501 BarIndex++) { 502 503 ASSERT (BarIndex < PCI_MAX_BAR); 504 Offset = PciIovParseVfBar (PciIoDevice, Offset, BarIndex); 505 } 506 } 507 508 DEBUG_CODE (DumpPciBars (PciIoDevice);); 509 return PciIoDevice; 510 } 511 512 /** 513 Create PCI device instance for PCI-PCI bridge. 514 515 @param Bridge Parent bridge instance. 516 @param Pci Input PCI device information block. 517 @param Bus PCI device Bus NO. 518 @param Device PCI device Device NO. 519 @param Func PCI device's func NO. 520 521 @return Created PCI device instance. 522 523 **/ 524 PCI_IO_DEVICE * 525 GatherPpbInfo ( 526 IN PCI_IO_DEVICE *Bridge, 527 IN PCI_TYPE00 *Pci, 528 IN UINT8 Bus, 529 IN UINT8 Device, 530 IN UINT8 Func 531 ) 532 { 533 PCI_IO_DEVICE *PciIoDevice; 534 EFI_STATUS Status; 535 UINT8 Value; 536 EFI_PCI_IO_PROTOCOL *PciIo; 537 UINT8 Temp; 538 UINT32 PMemBaseLimit; 539 UINT16 PrefetchableMemoryBase; 540 UINT16 PrefetchableMemoryLimit; 541 542 PciIoDevice = CreatePciIoDevice ( 543 Bridge, 544 Pci, 545 Bus, 546 Device, 547 Func 548 ); 549 550 if (PciIoDevice == NULL) { 551 return NULL; 552 } 553 554 if (gFullEnumeration) { 555 PCI_DISABLE_COMMAND_REGISTER (PciIoDevice, EFI_PCI_COMMAND_BITS_OWNED); 556 557 // 558 // Initalize the bridge control register 559 // 560 PCI_DISABLE_BRIDGE_CONTROL_REGISTER (PciIoDevice, EFI_PCI_BRIDGE_CONTROL_BITS_OWNED); 561 562 } 563 564 // 565 // PPB can have two BARs 566 // 567 if (PciParseBar (PciIoDevice, 0x10, PPB_BAR_0) == 0x14) { 568 // 569 // Not 64-bit bar 570 // 571 PciParseBar (PciIoDevice, 0x14, PPB_BAR_1); 572 } 573 574 PciIo = &PciIoDevice->PciIo; 575 576 // 577 // Test whether it support 32 decode or not 578 // 579 PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8, 0x1C, 1, &Temp); 580 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x1C, 1, &gAllOne); 581 PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8, 0x1C, 1, &Value); 582 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x1C, 1, &Temp); 583 584 if (Value != 0) { 585 if ((Value & 0x01) != 0) { 586 PciIoDevice->Decodes |= EFI_BRIDGE_IO32_DECODE_SUPPORTED; 587 } else { 588 PciIoDevice->Decodes |= EFI_BRIDGE_IO16_DECODE_SUPPORTED; 589 } 590 } 591 592 // 593 // if PcdPciBridgeIoAlignmentProbe is TRUE, PCI bus driver probes 594 // PCI bridge supporting non-stardard I/O window alignment less than 4K. 595 // 596 597 PciIoDevice->BridgeIoAlignment = 0xFFF; 598 if (FeaturePcdGet (PcdPciBridgeIoAlignmentProbe)) { 599 // 600 // Check any bits of bit 3-1 of I/O Base Register are writable. 601 // if so, it is assumed non-stardard I/O window alignment is supported by this bridge. 602 // Per spec, bit 3-1 of I/O Base Register are reserved bits, so its content can't be assumed. 603 // 604 Value = (UINT8)(Temp ^ (BIT3 | BIT2 | BIT1)); 605 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x1C, 1, &Value); 606 PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8, 0x1C, 1, &Value); 607 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x1C, 1, &Temp); 608 Value = (UINT8)((Value ^ Temp) & (BIT3 | BIT2 | BIT1)); 609 switch (Value) { 610 case BIT3: 611 PciIoDevice->BridgeIoAlignment = 0x7FF; 612 break; 613 case BIT3 | BIT2: 614 PciIoDevice->BridgeIoAlignment = 0x3FF; 615 break; 616 case BIT3 | BIT2 | BIT1: 617 PciIoDevice->BridgeIoAlignment = 0x1FF; 618 break; 619 } 620 } 621 622 Status = BarExisted ( 623 PciIoDevice, 624 0x24, 625 NULL, 626 &PMemBaseLimit 627 ); 628 629 // 630 // Test if it supports 64 memory or not 631 // 632 // The bottom 4 bits of both the Prefetchable Memory Base and Prefetchable Memory Limit 633 // registers: 634 // 0 - the bridge supports only 32 bit addresses. 635 // 1 - the bridge supports 64-bit addresses. 636 // 637 PrefetchableMemoryBase = (UINT16)(PMemBaseLimit & 0xffff); 638 PrefetchableMemoryLimit = (UINT16)(PMemBaseLimit >> 16); 639 if (!EFI_ERROR (Status) && 640 (PrefetchableMemoryBase & 0x000f) == 0x0001 && 641 (PrefetchableMemoryLimit & 0x000f) == 0x0001) { 642 Status = BarExisted ( 643 PciIoDevice, 644 0x28, 645 NULL, 646 NULL 647 ); 648 649 if (!EFI_ERROR (Status)) { 650 PciIoDevice->Decodes |= EFI_BRIDGE_PMEM32_DECODE_SUPPORTED; 651 PciIoDevice->Decodes |= EFI_BRIDGE_PMEM64_DECODE_SUPPORTED; 652 } else { 653 PciIoDevice->Decodes |= EFI_BRIDGE_PMEM32_DECODE_SUPPORTED; 654 } 655 } 656 657 // 658 // Memory 32 code is required for ppb 659 // 660 PciIoDevice->Decodes |= EFI_BRIDGE_MEM32_DECODE_SUPPORTED; 661 662 GetResourcePaddingPpb (PciIoDevice); 663 664 DEBUG_CODE ( 665 DumpPpbPaddingResource (PciIoDevice, PciBarTypeUnknown); 666 DumpPciBars (PciIoDevice); 667 ); 668 669 return PciIoDevice; 670 } 671 672 673 /** 674 Create PCI device instance for PCI Card bridge device. 675 676 @param Bridge Parent bridge instance. 677 @param Pci Input PCI device information block. 678 @param Bus PCI device Bus NO. 679 @param Device PCI device Device NO. 680 @param Func PCI device's func NO. 681 682 @return Created PCI device instance. 683 684 **/ 685 PCI_IO_DEVICE * 686 GatherP2CInfo ( 687 IN PCI_IO_DEVICE *Bridge, 688 IN PCI_TYPE00 *Pci, 689 IN UINT8 Bus, 690 IN UINT8 Device, 691 IN UINT8 Func 692 ) 693 { 694 PCI_IO_DEVICE *PciIoDevice; 695 696 PciIoDevice = CreatePciIoDevice ( 697 Bridge, 698 Pci, 699 Bus, 700 Device, 701 Func 702 ); 703 704 if (PciIoDevice == NULL) { 705 return NULL; 706 } 707 708 if (gFullEnumeration) { 709 PCI_DISABLE_COMMAND_REGISTER (PciIoDevice, EFI_PCI_COMMAND_BITS_OWNED); 710 711 // 712 // Initalize the bridge control register 713 // 714 PCI_DISABLE_BRIDGE_CONTROL_REGISTER (PciIoDevice, EFI_PCCARD_BRIDGE_CONTROL_BITS_OWNED); 715 } 716 717 // 718 // P2C only has one bar that is in 0x10 719 // 720 PciParseBar (PciIoDevice, 0x10, P2C_BAR_0); 721 722 // 723 // Read PciBar information from the bar register 724 // 725 GetBackPcCardBar (PciIoDevice); 726 PciIoDevice->Decodes = EFI_BRIDGE_MEM32_DECODE_SUPPORTED | 727 EFI_BRIDGE_PMEM32_DECODE_SUPPORTED | 728 EFI_BRIDGE_IO32_DECODE_SUPPORTED; 729 730 DEBUG_CODE (DumpPciBars (PciIoDevice);); 731 732 return PciIoDevice; 733 } 734 735 /** 736 Create device path for pci deivce. 737 738 @param ParentDevicePath Parent bridge's path. 739 @param PciIoDevice Pci device instance. 740 741 @return Device path protocol instance for specific pci device. 742 743 **/ 744 EFI_DEVICE_PATH_PROTOCOL * 745 CreatePciDevicePath ( 746 IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath, 747 IN PCI_IO_DEVICE *PciIoDevice 748 ) 749 { 750 751 PCI_DEVICE_PATH PciNode; 752 753 // 754 // Create PCI device path 755 // 756 PciNode.Header.Type = HARDWARE_DEVICE_PATH; 757 PciNode.Header.SubType = HW_PCI_DP; 758 SetDevicePathNodeLength (&PciNode.Header, sizeof (PciNode)); 759 760 PciNode.Device = PciIoDevice->DeviceNumber; 761 PciNode.Function = PciIoDevice->FunctionNumber; 762 PciIoDevice->DevicePath = AppendDevicePathNode (ParentDevicePath, &PciNode.Header); 763 764 return PciIoDevice->DevicePath; 765 } 766 767 /** 768 Check whether the PCI IOV VF bar is existed or not. 769 770 @param PciIoDevice A pointer to the PCI_IO_DEVICE. 771 @param Offset The offset. 772 @param BarLengthValue The bar length value returned. 773 @param OriginalBarValue The original bar value returned. 774 775 @retval EFI_NOT_FOUND The bar doesn't exist. 776 @retval EFI_SUCCESS The bar exist. 777 778 **/ 779 EFI_STATUS 780 VfBarExisted ( 781 IN PCI_IO_DEVICE *PciIoDevice, 782 IN UINTN Offset, 783 OUT UINT32 *BarLengthValue, 784 OUT UINT32 *OriginalBarValue 785 ) 786 { 787 EFI_PCI_IO_PROTOCOL *PciIo; 788 UINT32 OriginalValue; 789 UINT32 Value; 790 EFI_TPL OldTpl; 791 792 // 793 // Ensure it is called properly 794 // 795 ASSERT (PciIoDevice->SrIovCapabilityOffset != 0); 796 if (PciIoDevice->SrIovCapabilityOffset == 0) { 797 return EFI_NOT_FOUND; 798 } 799 800 PciIo = &PciIoDevice->PciIo; 801 802 // 803 // Preserve the original value 804 // 805 806 PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, (UINT32)Offset, 1, &OriginalValue); 807 808 // 809 // Raise TPL to high level to disable timer interrupt while the BAR is probed 810 // 811 OldTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL); 812 813 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, (UINT32)Offset, 1, &gAllOne); 814 PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, (UINT32)Offset, 1, &Value); 815 816 // 817 // Write back the original value 818 // 819 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, (UINT32)Offset, 1, &OriginalValue); 820 821 // 822 // Restore TPL to its original level 823 // 824 gBS->RestoreTPL (OldTpl); 825 826 if (BarLengthValue != NULL) { 827 *BarLengthValue = Value; 828 } 829 830 if (OriginalBarValue != NULL) { 831 *OriginalBarValue = OriginalValue; 832 } 833 834 if (Value == 0) { 835 return EFI_NOT_FOUND; 836 } else { 837 return EFI_SUCCESS; 838 } 839 } 840 841 /** 842 Check whether the bar is existed or not. 843 844 @param PciIoDevice A pointer to the PCI_IO_DEVICE. 845 @param Offset The offset. 846 @param BarLengthValue The bar length value returned. 847 @param OriginalBarValue The original bar value returned. 848 849 @retval EFI_NOT_FOUND The bar doesn't exist. 850 @retval EFI_SUCCESS The bar exist. 851 852 **/ 853 EFI_STATUS 854 BarExisted ( 855 IN PCI_IO_DEVICE *PciIoDevice, 856 IN UINTN Offset, 857 OUT UINT32 *BarLengthValue, 858 OUT UINT32 *OriginalBarValue 859 ) 860 { 861 EFI_PCI_IO_PROTOCOL *PciIo; 862 UINT32 OriginalValue; 863 UINT32 Value; 864 EFI_TPL OldTpl; 865 866 PciIo = &PciIoDevice->PciIo; 867 868 // 869 // Preserve the original value 870 // 871 PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, (UINT8) Offset, 1, &OriginalValue); 872 873 // 874 // Raise TPL to high level to disable timer interrupt while the BAR is probed 875 // 876 OldTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL); 877 878 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, (UINT8) Offset, 1, &gAllOne); 879 PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, (UINT8) Offset, 1, &Value); 880 881 // 882 // Write back the original value 883 // 884 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, (UINT8) Offset, 1, &OriginalValue); 885 886 // 887 // Restore TPL to its original level 888 // 889 gBS->RestoreTPL (OldTpl); 890 891 if (BarLengthValue != NULL) { 892 *BarLengthValue = Value; 893 } 894 895 if (OriginalBarValue != NULL) { 896 *OriginalBarValue = OriginalValue; 897 } 898 899 if (Value == 0) { 900 return EFI_NOT_FOUND; 901 } else { 902 return EFI_SUCCESS; 903 } 904 } 905 906 /** 907 Test whether the device can support given attributes. 908 909 @param PciIoDevice Pci device instance. 910 @param Command Input command register value, and 911 returned supported register value. 912 @param BridgeControl Inout bridge control value for PPB or P2C, and 913 returned supported bridge control value. 914 @param OldCommand Returned and stored old command register offset. 915 @param OldBridgeControl Returned and stored old Bridge control value for PPB or P2C. 916 917 **/ 918 VOID 919 PciTestSupportedAttribute ( 920 IN PCI_IO_DEVICE *PciIoDevice, 921 IN OUT UINT16 *Command, 922 IN OUT UINT16 *BridgeControl, 923 OUT UINT16 *OldCommand, 924 OUT UINT16 *OldBridgeControl 925 ) 926 { 927 EFI_TPL OldTpl; 928 929 // 930 // Preserve the original value 931 // 932 PCI_READ_COMMAND_REGISTER (PciIoDevice, OldCommand); 933 934 // 935 // Raise TPL to high level to disable timer interrupt while the BAR is probed 936 // 937 OldTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL); 938 939 PCI_SET_COMMAND_REGISTER (PciIoDevice, *Command); 940 PCI_READ_COMMAND_REGISTER (PciIoDevice, Command); 941 942 // 943 // Write back the original value 944 // 945 PCI_SET_COMMAND_REGISTER (PciIoDevice, *OldCommand); 946 947 // 948 // Restore TPL to its original level 949 // 950 gBS->RestoreTPL (OldTpl); 951 952 if (IS_PCI_BRIDGE (&PciIoDevice->Pci) || IS_CARDBUS_BRIDGE (&PciIoDevice->Pci)) { 953 954 // 955 // Preserve the original value 956 // 957 PCI_READ_BRIDGE_CONTROL_REGISTER (PciIoDevice, OldBridgeControl); 958 959 // 960 // Raise TPL to high level to disable timer interrupt while the BAR is probed 961 // 962 OldTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL); 963 964 PCI_SET_BRIDGE_CONTROL_REGISTER (PciIoDevice, *BridgeControl); 965 PCI_READ_BRIDGE_CONTROL_REGISTER (PciIoDevice, BridgeControl); 966 967 // 968 // Write back the original value 969 // 970 PCI_SET_BRIDGE_CONTROL_REGISTER (PciIoDevice, *OldBridgeControl); 971 972 // 973 // Restore TPL to its original level 974 // 975 gBS->RestoreTPL (OldTpl); 976 977 } else { 978 *OldBridgeControl = 0; 979 *BridgeControl = 0; 980 } 981 } 982 983 /** 984 Set the supported or current attributes of a PCI device. 985 986 @param PciIoDevice Structure pointer for PCI device. 987 @param Command Command register value. 988 @param BridgeControl Bridge control value for PPB or P2C. 989 @param Option Make a choice of EFI_SET_SUPPORTS or EFI_SET_ATTRIBUTES. 990 991 **/ 992 VOID 993 PciSetDeviceAttribute ( 994 IN PCI_IO_DEVICE *PciIoDevice, 995 IN UINT16 Command, 996 IN UINT16 BridgeControl, 997 IN UINTN Option 998 ) 999 { 1000 UINT64 Attributes; 1001 1002 Attributes = 0; 1003 1004 if ((Command & EFI_PCI_COMMAND_IO_SPACE) != 0) { 1005 Attributes |= EFI_PCI_IO_ATTRIBUTE_IO; 1006 } 1007 1008 if ((Command & EFI_PCI_COMMAND_MEMORY_SPACE) != 0) { 1009 Attributes |= EFI_PCI_IO_ATTRIBUTE_MEMORY; 1010 } 1011 1012 if ((Command & EFI_PCI_COMMAND_BUS_MASTER) != 0) { 1013 Attributes |= EFI_PCI_IO_ATTRIBUTE_BUS_MASTER; 1014 } 1015 1016 if ((Command & EFI_PCI_COMMAND_VGA_PALETTE_SNOOP) != 0) { 1017 Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO; 1018 } 1019 1020 if ((BridgeControl & EFI_PCI_BRIDGE_CONTROL_ISA) != 0) { 1021 Attributes |= EFI_PCI_IO_ATTRIBUTE_ISA_IO; 1022 } 1023 1024 if ((BridgeControl & EFI_PCI_BRIDGE_CONTROL_VGA) != 0) { 1025 Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_IO; 1026 Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY; 1027 Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO; 1028 } 1029 1030 if ((BridgeControl & EFI_PCI_BRIDGE_CONTROL_VGA_16) != 0) { 1031 Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_IO_16; 1032 Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO_16; 1033 } 1034 1035 if (Option == EFI_SET_SUPPORTS) { 1036 1037 Attributes |= (UINT64) (EFI_PCI_IO_ATTRIBUTE_MEMORY_WRITE_COMBINE | 1038 EFI_PCI_IO_ATTRIBUTE_MEMORY_CACHED | 1039 EFI_PCI_IO_ATTRIBUTE_MEMORY_DISABLE | 1040 EFI_PCI_IO_ATTRIBUTE_EMBEDDED_DEVICE | 1041 EFI_PCI_IO_ATTRIBUTE_EMBEDDED_ROM | 1042 EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE); 1043 1044 if (IS_PCI_LPC (&PciIoDevice->Pci)) { 1045 Attributes |= EFI_PCI_IO_ATTRIBUTE_ISA_MOTHERBOARD_IO; 1046 Attributes |= (mReserveIsaAliases ? (UINT64) EFI_PCI_IO_ATTRIBUTE_ISA_IO : \ 1047 (UINT64) EFI_PCI_IO_ATTRIBUTE_ISA_IO_16); 1048 } 1049 1050 if (IS_PCI_BRIDGE (&PciIoDevice->Pci) || IS_CARDBUS_BRIDGE (&PciIoDevice->Pci)) { 1051 // 1052 // For bridge, it should support IDE attributes 1053 // 1054 Attributes |= EFI_PCI_IO_ATTRIBUTE_IDE_SECONDARY_IO; 1055 Attributes |= EFI_PCI_IO_ATTRIBUTE_IDE_PRIMARY_IO; 1056 1057 if (mReserveVgaAliases) { 1058 Attributes &= ~(UINT64)(EFI_PCI_IO_ATTRIBUTE_VGA_IO_16 | \ 1059 EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO_16); 1060 } else { 1061 Attributes &= ~(UINT64)(EFI_PCI_IO_ATTRIBUTE_VGA_IO | \ 1062 EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO); 1063 } 1064 } else { 1065 1066 if (IS_PCI_IDE (&PciIoDevice->Pci)) { 1067 Attributes |= EFI_PCI_IO_ATTRIBUTE_IDE_SECONDARY_IO; 1068 Attributes |= EFI_PCI_IO_ATTRIBUTE_IDE_PRIMARY_IO; 1069 } 1070 1071 if (IS_PCI_VGA (&PciIoDevice->Pci)) { 1072 Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY; 1073 Attributes |= (mReserveVgaAliases ? (UINT64) EFI_PCI_IO_ATTRIBUTE_VGA_IO : \ 1074 (UINT64) EFI_PCI_IO_ATTRIBUTE_VGA_IO_16); 1075 } 1076 } 1077 1078 PciIoDevice->Supports = Attributes; 1079 PciIoDevice->Supports &= ( (PciIoDevice->Parent->Supports) | \ 1080 EFI_PCI_IO_ATTRIBUTE_IO | EFI_PCI_IO_ATTRIBUTE_MEMORY | \ 1081 EFI_PCI_IO_ATTRIBUTE_BUS_MASTER ); 1082 1083 } else { 1084 // 1085 // When this attribute is clear, the RomImage and RomSize fields in the PCI IO were 1086 // initialized based on the PCI option ROM found through the ROM BAR of the PCI controller. 1087 // When this attribute is set, the PCI option ROM described by the RomImage and RomSize 1088 // fields is not from the the ROM BAR of the PCI controller. 1089 // 1090 if (!PciIoDevice->EmbeddedRom) { 1091 Attributes |= EFI_PCI_IO_ATTRIBUTE_EMBEDDED_ROM; 1092 } 1093 PciIoDevice->Attributes = Attributes; 1094 } 1095 } 1096 1097 /** 1098 Determine if the device can support Fast Back to Back attribute. 1099 1100 @param PciIoDevice Pci device instance. 1101 @param StatusIndex Status register value. 1102 1103 @retval EFI_SUCCESS This device support Fast Back to Back attribute. 1104 @retval EFI_UNSUPPORTED This device doesn't support Fast Back to Back attribute. 1105 1106 **/ 1107 EFI_STATUS 1108 GetFastBackToBackSupport ( 1109 IN PCI_IO_DEVICE *PciIoDevice, 1110 IN UINT8 StatusIndex 1111 ) 1112 { 1113 EFI_PCI_IO_PROTOCOL *PciIo; 1114 EFI_STATUS Status; 1115 UINT32 StatusRegister; 1116 1117 // 1118 // Read the status register 1119 // 1120 PciIo = &PciIoDevice->PciIo; 1121 Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint16, StatusIndex, 1, &StatusRegister); 1122 if (EFI_ERROR (Status)) { 1123 return EFI_UNSUPPORTED; 1124 } 1125 1126 // 1127 // Check the Fast B2B bit 1128 // 1129 if ((StatusRegister & EFI_PCI_FAST_BACK_TO_BACK_CAPABLE) != 0) { 1130 return EFI_SUCCESS; 1131 } else { 1132 return EFI_UNSUPPORTED; 1133 } 1134 } 1135 1136 /** 1137 Process the option ROM for all the children of the specified parent PCI device. 1138 It can only be used after the first full Option ROM process. 1139 1140 @param PciIoDevice Pci device instance. 1141 1142 **/ 1143 VOID 1144 ProcessOptionRomLight ( 1145 IN PCI_IO_DEVICE *PciIoDevice 1146 ) 1147 { 1148 PCI_IO_DEVICE *Temp; 1149 LIST_ENTRY *CurrentLink; 1150 1151 // 1152 // For RootBridge, PPB , P2C, go recursively to traverse all its children 1153 // 1154 CurrentLink = PciIoDevice->ChildList.ForwardLink; 1155 while (CurrentLink != NULL && CurrentLink != &PciIoDevice->ChildList) { 1156 1157 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink); 1158 1159 if (!IsListEmpty (&Temp->ChildList)) { 1160 ProcessOptionRomLight (Temp); 1161 } 1162 1163 PciRomGetImageMapping (Temp); 1164 1165 // 1166 // The OpRom has already been processed in the first round 1167 // 1168 Temp->AllOpRomProcessed = TRUE; 1169 1170 CurrentLink = CurrentLink->ForwardLink; 1171 } 1172 } 1173 1174 /** 1175 Determine the related attributes of all devices under a Root Bridge. 1176 1177 @param PciIoDevice PCI device instance. 1178 1179 **/ 1180 EFI_STATUS 1181 DetermineDeviceAttribute ( 1182 IN PCI_IO_DEVICE *PciIoDevice 1183 ) 1184 { 1185 UINT16 Command; 1186 UINT16 BridgeControl; 1187 UINT16 OldCommand; 1188 UINT16 OldBridgeControl; 1189 BOOLEAN FastB2BSupport; 1190 PCI_IO_DEVICE *Temp; 1191 LIST_ENTRY *CurrentLink; 1192 EFI_STATUS Status; 1193 1194 // 1195 // For Root Bridge, just copy it by RootBridgeIo proctocol 1196 // so as to keep consistent with the actual attribute 1197 // 1198 if (PciIoDevice->Parent == NULL) { 1199 Status = PciIoDevice->PciRootBridgeIo->GetAttributes ( 1200 PciIoDevice->PciRootBridgeIo, 1201 &PciIoDevice->Supports, 1202 &PciIoDevice->Attributes 1203 ); 1204 if (EFI_ERROR (Status)) { 1205 return Status; 1206 } 1207 // 1208 // Assume the PCI Root Bridge supports DAC 1209 // 1210 PciIoDevice->Supports |= (UINT64)(EFI_PCI_IO_ATTRIBUTE_EMBEDDED_DEVICE | 1211 EFI_PCI_IO_ATTRIBUTE_EMBEDDED_ROM | 1212 EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE); 1213 1214 } else { 1215 1216 // 1217 // Set the attributes to be checked for common PCI devices and PPB or P2C 1218 // Since some devices only support part of them, it is better to set the 1219 // attribute according to its command or bridge control register 1220 // 1221 Command = EFI_PCI_COMMAND_IO_SPACE | 1222 EFI_PCI_COMMAND_MEMORY_SPACE | 1223 EFI_PCI_COMMAND_BUS_MASTER | 1224 EFI_PCI_COMMAND_VGA_PALETTE_SNOOP; 1225 1226 BridgeControl = EFI_PCI_BRIDGE_CONTROL_ISA | EFI_PCI_BRIDGE_CONTROL_VGA | EFI_PCI_BRIDGE_CONTROL_VGA_16; 1227 1228 // 1229 // Test whether the device can support attributes above 1230 // 1231 PciTestSupportedAttribute (PciIoDevice, &Command, &BridgeControl, &OldCommand, &OldBridgeControl); 1232 1233 // 1234 // Set the supported attributes for specified PCI device 1235 // 1236 PciSetDeviceAttribute (PciIoDevice, Command, BridgeControl, EFI_SET_SUPPORTS); 1237 1238 // 1239 // Set the current attributes for specified PCI device 1240 // 1241 PciSetDeviceAttribute (PciIoDevice, OldCommand, OldBridgeControl, EFI_SET_ATTRIBUTES); 1242 1243 // 1244 // Enable other supported attributes but not defined in PCI_IO_PROTOCOL 1245 // 1246 PCI_ENABLE_COMMAND_REGISTER (PciIoDevice, EFI_PCI_COMMAND_MEMORY_WRITE_AND_INVALIDATE); 1247 } 1248 1249 FastB2BSupport = TRUE; 1250 1251 // 1252 // P2C can not support FB2B on the secondary side 1253 // 1254 if (IS_CARDBUS_BRIDGE (&PciIoDevice->Pci)) { 1255 FastB2BSupport = FALSE; 1256 } 1257 1258 // 1259 // For RootBridge, PPB , P2C, go recursively to traverse all its children 1260 // 1261 CurrentLink = PciIoDevice->ChildList.ForwardLink; 1262 while (CurrentLink != NULL && CurrentLink != &PciIoDevice->ChildList) { 1263 1264 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink); 1265 Status = DetermineDeviceAttribute (Temp); 1266 if (EFI_ERROR (Status)) { 1267 return Status; 1268 } 1269 // 1270 // Detect Fast Bact to Bact support for the device under the bridge 1271 // 1272 Status = GetFastBackToBackSupport (Temp, PCI_PRIMARY_STATUS_OFFSET); 1273 if (FastB2BSupport && EFI_ERROR (Status)) { 1274 FastB2BSupport = FALSE; 1275 } 1276 1277 CurrentLink = CurrentLink->ForwardLink; 1278 } 1279 // 1280 // Set or clear Fast Back to Back bit for the whole bridge 1281 // 1282 if (!IsListEmpty (&PciIoDevice->ChildList)) { 1283 1284 if (IS_PCI_BRIDGE (&PciIoDevice->Pci)) { 1285 1286 Status = GetFastBackToBackSupport (PciIoDevice, PCI_BRIDGE_STATUS_REGISTER_OFFSET); 1287 1288 if (EFI_ERROR (Status) || (!FastB2BSupport)) { 1289 FastB2BSupport = FALSE; 1290 PCI_DISABLE_BRIDGE_CONTROL_REGISTER (PciIoDevice, EFI_PCI_BRIDGE_CONTROL_FAST_BACK_TO_BACK); 1291 } else { 1292 PCI_ENABLE_BRIDGE_CONTROL_REGISTER (PciIoDevice, EFI_PCI_BRIDGE_CONTROL_FAST_BACK_TO_BACK); 1293 } 1294 } 1295 1296 CurrentLink = PciIoDevice->ChildList.ForwardLink; 1297 while (CurrentLink != NULL && CurrentLink != &PciIoDevice->ChildList) { 1298 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink); 1299 if (FastB2BSupport) { 1300 PCI_ENABLE_COMMAND_REGISTER (Temp, EFI_PCI_COMMAND_FAST_BACK_TO_BACK); 1301 } else { 1302 PCI_DISABLE_COMMAND_REGISTER (Temp, EFI_PCI_COMMAND_FAST_BACK_TO_BACK); 1303 } 1304 1305 CurrentLink = CurrentLink->ForwardLink; 1306 } 1307 } 1308 // 1309 // End for IsListEmpty 1310 // 1311 return EFI_SUCCESS; 1312 } 1313 1314 /** 1315 This routine is used to update the bar information for those incompatible PCI device. 1316 1317 @param PciIoDevice Input Pci device instance. Output Pci device instance with updated 1318 Bar information. 1319 1320 @retval EFI_SUCCESS Successfully updated bar information. 1321 @retval EFI_UNSUPPORTED Given PCI device doesn't belong to incompatible PCI device list. 1322 1323 **/ 1324 EFI_STATUS 1325 UpdatePciInfo ( 1326 IN OUT PCI_IO_DEVICE *PciIoDevice 1327 ) 1328 { 1329 EFI_STATUS Status; 1330 UINTN BarIndex; 1331 UINTN BarEndIndex; 1332 BOOLEAN SetFlag; 1333 VOID *Configuration; 1334 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Ptr; 1335 1336 Configuration = NULL; 1337 Status = EFI_SUCCESS; 1338 1339 if (gEfiIncompatiblePciDeviceSupport == NULL) { 1340 // 1341 // It can only be supported after the Incompatible PCI Device 1342 // Support Protocol has been installed 1343 // 1344 Status = gBS->LocateProtocol ( 1345 &gEfiIncompatiblePciDeviceSupportProtocolGuid, 1346 NULL, 1347 (VOID **) &gEfiIncompatiblePciDeviceSupport 1348 ); 1349 } 1350 if (Status == EFI_SUCCESS) { 1351 // 1352 // Check whether the device belongs to incompatible devices from protocol or not 1353 // If it is , then get its special requirement in the ACPI table 1354 // 1355 Status = gEfiIncompatiblePciDeviceSupport->CheckDevice ( 1356 gEfiIncompatiblePciDeviceSupport, 1357 PciIoDevice->Pci.Hdr.VendorId, 1358 PciIoDevice->Pci.Hdr.DeviceId, 1359 PciIoDevice->Pci.Hdr.RevisionID, 1360 PciIoDevice->Pci.Device.SubsystemVendorID, 1361 PciIoDevice->Pci.Device.SubsystemID, 1362 &Configuration 1363 ); 1364 1365 } 1366 1367 if (EFI_ERROR (Status) || Configuration == NULL ) { 1368 return EFI_UNSUPPORTED; 1369 } 1370 1371 // 1372 // Update PCI device information from the ACPI table 1373 // 1374 Ptr = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Configuration; 1375 1376 while (Ptr->Desc != ACPI_END_TAG_DESCRIPTOR) { 1377 1378 if (Ptr->Desc != ACPI_ADDRESS_SPACE_DESCRIPTOR) { 1379 // 1380 // The format is not support 1381 // 1382 break; 1383 } 1384 1385 BarIndex = (UINTN) Ptr->AddrTranslationOffset; 1386 BarEndIndex = BarIndex; 1387 1388 // 1389 // Update all the bars in the device 1390 // 1391 if (BarIndex == PCI_BAR_ALL) { 1392 BarIndex = 0; 1393 BarEndIndex = PCI_MAX_BAR - 1; 1394 } 1395 1396 if (BarIndex > PCI_MAX_BAR) { 1397 Ptr++; 1398 continue; 1399 } 1400 1401 for (; BarIndex <= BarEndIndex; BarIndex++) { 1402 SetFlag = FALSE; 1403 switch (Ptr->ResType) { 1404 case ACPI_ADDRESS_SPACE_TYPE_MEM: 1405 1406 // 1407 // Make sure the bar is memory type 1408 // 1409 if (CheckBarType (PciIoDevice, (UINT8) BarIndex, PciBarTypeMem)) { 1410 SetFlag = TRUE; 1411 } 1412 break; 1413 1414 case ACPI_ADDRESS_SPACE_TYPE_IO: 1415 1416 // 1417 // Make sure the bar is IO type 1418 // 1419 if (CheckBarType (PciIoDevice, (UINT8) BarIndex, PciBarTypeIo)) { 1420 SetFlag = TRUE; 1421 } 1422 break; 1423 } 1424 1425 if (SetFlag) { 1426 1427 // 1428 // Update the new alignment for the device 1429 // 1430 SetNewAlign (&(PciIoDevice->PciBar[BarIndex].Alignment), Ptr->AddrRangeMax); 1431 1432 // 1433 // Update the new length for the device 1434 // 1435 if (Ptr->AddrLen != PCI_BAR_NOCHANGE) { 1436 PciIoDevice->PciBar[BarIndex].Length = Ptr->AddrLen; 1437 } 1438 } 1439 } 1440 1441 Ptr++; 1442 } 1443 1444 FreePool (Configuration); 1445 1446 return EFI_SUCCESS; 1447 } 1448 1449 /** 1450 This routine will update the alignment with the new alignment. 1451 1452 @param Alignment Input Old alignment. Output updated alignment. 1453 @param NewAlignment New alignment. 1454 1455 **/ 1456 VOID 1457 SetNewAlign ( 1458 IN OUT UINT64 *Alignment, 1459 IN UINT64 NewAlignment 1460 ) 1461 { 1462 UINT64 OldAlignment; 1463 UINTN ShiftBit; 1464 1465 // 1466 // The new alignment is the same as the original, 1467 // so skip it 1468 // 1469 if (NewAlignment == PCI_BAR_OLD_ALIGN) { 1470 return ; 1471 } 1472 // 1473 // Check the validity of the parameter 1474 // 1475 if (NewAlignment != PCI_BAR_EVEN_ALIGN && 1476 NewAlignment != PCI_BAR_SQUAD_ALIGN && 1477 NewAlignment != PCI_BAR_DQUAD_ALIGN ) { 1478 *Alignment = NewAlignment; 1479 return ; 1480 } 1481 1482 OldAlignment = (*Alignment) + 1; 1483 ShiftBit = 0; 1484 1485 // 1486 // Get the first non-zero hex value of the length 1487 // 1488 while ((OldAlignment & 0x0F) == 0x00) { 1489 OldAlignment = RShiftU64 (OldAlignment, 4); 1490 ShiftBit += 4; 1491 } 1492 1493 // 1494 // Adjust the alignment to even, quad or double quad boundary 1495 // 1496 if (NewAlignment == PCI_BAR_EVEN_ALIGN) { 1497 if ((OldAlignment & 0x01) != 0) { 1498 OldAlignment = OldAlignment + 2 - (OldAlignment & 0x01); 1499 } 1500 } else if (NewAlignment == PCI_BAR_SQUAD_ALIGN) { 1501 if ((OldAlignment & 0x03) != 0) { 1502 OldAlignment = OldAlignment + 4 - (OldAlignment & 0x03); 1503 } 1504 } else if (NewAlignment == PCI_BAR_DQUAD_ALIGN) { 1505 if ((OldAlignment & 0x07) != 0) { 1506 OldAlignment = OldAlignment + 8 - (OldAlignment & 0x07); 1507 } 1508 } 1509 1510 // 1511 // Update the old value 1512 // 1513 NewAlignment = LShiftU64 (OldAlignment, ShiftBit) - 1; 1514 *Alignment = NewAlignment; 1515 1516 return ; 1517 } 1518 1519 /** 1520 Parse PCI IOV VF bar information and fill them into PCI device instance. 1521 1522 @param PciIoDevice Pci device instance. 1523 @param Offset Bar offset. 1524 @param BarIndex Bar index. 1525 1526 @return Next bar offset. 1527 1528 **/ 1529 UINTN 1530 PciIovParseVfBar ( 1531 IN PCI_IO_DEVICE *PciIoDevice, 1532 IN UINTN Offset, 1533 IN UINTN BarIndex 1534 ) 1535 { 1536 UINT32 Value; 1537 UINT32 OriginalValue; 1538 UINT32 Mask; 1539 EFI_STATUS Status; 1540 1541 // 1542 // Ensure it is called properly 1543 // 1544 ASSERT (PciIoDevice->SrIovCapabilityOffset != 0); 1545 if (PciIoDevice->SrIovCapabilityOffset == 0) { 1546 return 0; 1547 } 1548 1549 OriginalValue = 0; 1550 Value = 0; 1551 1552 Status = VfBarExisted ( 1553 PciIoDevice, 1554 Offset, 1555 &Value, 1556 &OriginalValue 1557 ); 1558 1559 if (EFI_ERROR (Status)) { 1560 PciIoDevice->VfPciBar[BarIndex].BaseAddress = 0; 1561 PciIoDevice->VfPciBar[BarIndex].Length = 0; 1562 PciIoDevice->VfPciBar[BarIndex].Alignment = 0; 1563 1564 // 1565 // Scan all the BARs anyway 1566 // 1567 PciIoDevice->VfPciBar[BarIndex].Offset = (UINT16) Offset; 1568 return Offset + 4; 1569 } 1570 1571 PciIoDevice->VfPciBar[BarIndex].Offset = (UINT16) Offset; 1572 if ((Value & 0x01) != 0) { 1573 // 1574 // Device I/Os. Impossible 1575 // 1576 ASSERT (FALSE); 1577 return Offset + 4; 1578 1579 } else { 1580 1581 Mask = 0xfffffff0; 1582 1583 PciIoDevice->VfPciBar[BarIndex].BaseAddress = OriginalValue & Mask; 1584 1585 switch (Value & 0x07) { 1586 1587 // 1588 //memory space; anywhere in 32 bit address space 1589 // 1590 case 0x00: 1591 if ((Value & 0x08) != 0) { 1592 PciIoDevice->VfPciBar[BarIndex].BarType = PciBarTypePMem32; 1593 } else { 1594 PciIoDevice->VfPciBar[BarIndex].BarType = PciBarTypeMem32; 1595 } 1596 1597 PciIoDevice->VfPciBar[BarIndex].Length = (~(Value & Mask)) + 1; 1598 PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->VfPciBar[BarIndex].Length - 1; 1599 1600 // 1601 // Adjust Length 1602 // 1603 PciIoDevice->VfPciBar[BarIndex].Length = MultU64x32 (PciIoDevice->VfPciBar[BarIndex].Length, PciIoDevice->InitialVFs); 1604 // 1605 // Adjust Alignment 1606 // 1607 if (PciIoDevice->VfPciBar[BarIndex].Alignment < PciIoDevice->SystemPageSize - 1) { 1608 PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->SystemPageSize - 1; 1609 } 1610 1611 break; 1612 1613 // 1614 // memory space; anywhere in 64 bit address space 1615 // 1616 case 0x04: 1617 if ((Value & 0x08) != 0) { 1618 PciIoDevice->VfPciBar[BarIndex].BarType = PciBarTypePMem64; 1619 } else { 1620 PciIoDevice->VfPciBar[BarIndex].BarType = PciBarTypeMem64; 1621 } 1622 1623 // 1624 // According to PCI 2.2,if the bar indicates a memory 64 decoding, next bar 1625 // is regarded as an extension for the first bar. As a result 1626 // the sizing will be conducted on combined 64 bit value 1627 // Here just store the masked first 32bit value for future size 1628 // calculation 1629 // 1630 PciIoDevice->VfPciBar[BarIndex].Length = Value & Mask; 1631 PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->VfPciBar[BarIndex].Length - 1; 1632 1633 if (PciIoDevice->VfPciBar[BarIndex].Alignment < PciIoDevice->SystemPageSize - 1) { 1634 PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->SystemPageSize - 1; 1635 } 1636 1637 // 1638 // Increment the offset to point to next DWORD 1639 // 1640 Offset += 4; 1641 1642 Status = VfBarExisted ( 1643 PciIoDevice, 1644 Offset, 1645 &Value, 1646 &OriginalValue 1647 ); 1648 1649 if (EFI_ERROR (Status)) { 1650 return Offset + 4; 1651 } 1652 1653 // 1654 // Fix the length to support some spefic 64 bit BAR 1655 // 1656 Value |= ((UINT32) -1 << HighBitSet32 (Value)); 1657 1658 // 1659 // Calculate the size of 64bit bar 1660 // 1661 PciIoDevice->VfPciBar[BarIndex].BaseAddress |= LShiftU64 ((UINT64) OriginalValue, 32); 1662 1663 PciIoDevice->VfPciBar[BarIndex].Length = PciIoDevice->VfPciBar[BarIndex].Length | LShiftU64 ((UINT64) Value, 32); 1664 PciIoDevice->VfPciBar[BarIndex].Length = (~(PciIoDevice->VfPciBar[BarIndex].Length)) + 1; 1665 PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->VfPciBar[BarIndex].Length - 1; 1666 1667 // 1668 // Adjust Length 1669 // 1670 PciIoDevice->VfPciBar[BarIndex].Length = MultU64x32 (PciIoDevice->VfPciBar[BarIndex].Length, PciIoDevice->InitialVFs); 1671 // 1672 // Adjust Alignment 1673 // 1674 if (PciIoDevice->VfPciBar[BarIndex].Alignment < PciIoDevice->SystemPageSize - 1) { 1675 PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->SystemPageSize - 1; 1676 } 1677 1678 break; 1679 1680 // 1681 // reserved 1682 // 1683 default: 1684 PciIoDevice->VfPciBar[BarIndex].BarType = PciBarTypeUnknown; 1685 PciIoDevice->VfPciBar[BarIndex].Length = (~(Value & Mask)) + 1; 1686 PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->VfPciBar[BarIndex].Length - 1; 1687 1688 if (PciIoDevice->VfPciBar[BarIndex].Alignment < PciIoDevice->SystemPageSize - 1) { 1689 PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->SystemPageSize - 1; 1690 } 1691 1692 break; 1693 } 1694 } 1695 1696 // 1697 // Check the length again so as to keep compatible with some special bars 1698 // 1699 if (PciIoDevice->VfPciBar[BarIndex].Length == 0) { 1700 PciIoDevice->VfPciBar[BarIndex].BarType = PciBarTypeUnknown; 1701 PciIoDevice->VfPciBar[BarIndex].BaseAddress = 0; 1702 PciIoDevice->VfPciBar[BarIndex].Alignment = 0; 1703 } 1704 1705 // 1706 // Increment number of bar 1707 // 1708 return Offset + 4; 1709 } 1710 1711 /** 1712 Parse PCI bar information and fill them into PCI device instance. 1713 1714 @param PciIoDevice Pci device instance. 1715 @param Offset Bar offset. 1716 @param BarIndex Bar index. 1717 1718 @return Next bar offset. 1719 1720 **/ 1721 UINTN 1722 PciParseBar ( 1723 IN PCI_IO_DEVICE *PciIoDevice, 1724 IN UINTN Offset, 1725 IN UINTN BarIndex 1726 ) 1727 { 1728 UINT32 Value; 1729 UINT32 OriginalValue; 1730 UINT32 Mask; 1731 EFI_STATUS Status; 1732 1733 OriginalValue = 0; 1734 Value = 0; 1735 1736 Status = BarExisted ( 1737 PciIoDevice, 1738 Offset, 1739 &Value, 1740 &OriginalValue 1741 ); 1742 1743 if (EFI_ERROR (Status)) { 1744 PciIoDevice->PciBar[BarIndex].BaseAddress = 0; 1745 PciIoDevice->PciBar[BarIndex].Length = 0; 1746 PciIoDevice->PciBar[BarIndex].Alignment = 0; 1747 1748 // 1749 // Some devices don't fully comply to PCI spec 2.2. So be to scan all the BARs anyway 1750 // 1751 PciIoDevice->PciBar[BarIndex].Offset = (UINT8) Offset; 1752 return Offset + 4; 1753 } 1754 1755 PciIoDevice->PciBar[BarIndex].Offset = (UINT8) Offset; 1756 if ((Value & 0x01) != 0) { 1757 // 1758 // Device I/Os 1759 // 1760 Mask = 0xfffffffc; 1761 1762 if ((Value & 0xFFFF0000) != 0) { 1763 // 1764 // It is a IO32 bar 1765 // 1766 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeIo32; 1767 PciIoDevice->PciBar[BarIndex].Length = ((~(Value & Mask)) + 1); 1768 PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1; 1769 1770 } else { 1771 // 1772 // It is a IO16 bar 1773 // 1774 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeIo16; 1775 PciIoDevice->PciBar[BarIndex].Length = 0x0000FFFF & ((~(Value & Mask)) + 1); 1776 PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1; 1777 1778 } 1779 // 1780 // Workaround. Some platforms inplement IO bar with 0 length 1781 // Need to treat it as no-bar 1782 // 1783 if (PciIoDevice->PciBar[BarIndex].Length == 0) { 1784 PciIoDevice->PciBar[BarIndex].BarType = (PCI_BAR_TYPE) 0; 1785 } 1786 1787 PciIoDevice->PciBar[BarIndex].Prefetchable = FALSE; 1788 PciIoDevice->PciBar[BarIndex].BaseAddress = OriginalValue & Mask; 1789 1790 } else { 1791 1792 Mask = 0xfffffff0; 1793 1794 PciIoDevice->PciBar[BarIndex].BaseAddress = OriginalValue & Mask; 1795 1796 switch (Value & 0x07) { 1797 1798 // 1799 //memory space; anywhere in 32 bit address space 1800 // 1801 case 0x00: 1802 if ((Value & 0x08) != 0) { 1803 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypePMem32; 1804 } else { 1805 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeMem32; 1806 } 1807 1808 PciIoDevice->PciBar[BarIndex].Length = (~(Value & Mask)) + 1; 1809 if (PciIoDevice->PciBar[BarIndex].Length < (SIZE_4KB)) { 1810 // 1811 // Force minimum 4KByte alignment for Virtualization technology for Directed I/O 1812 // 1813 PciIoDevice->PciBar[BarIndex].Alignment = (SIZE_4KB - 1); 1814 } else { 1815 PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1; 1816 } 1817 break; 1818 1819 // 1820 // memory space; anywhere in 64 bit address space 1821 // 1822 case 0x04: 1823 if ((Value & 0x08) != 0) { 1824 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypePMem64; 1825 } else { 1826 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeMem64; 1827 } 1828 1829 // 1830 // According to PCI 2.2,if the bar indicates a memory 64 decoding, next bar 1831 // is regarded as an extension for the first bar. As a result 1832 // the sizing will be conducted on combined 64 bit value 1833 // Here just store the masked first 32bit value for future size 1834 // calculation 1835 // 1836 PciIoDevice->PciBar[BarIndex].Length = Value & Mask; 1837 PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1; 1838 1839 // 1840 // Increment the offset to point to next DWORD 1841 // 1842 Offset += 4; 1843 1844 Status = BarExisted ( 1845 PciIoDevice, 1846 Offset, 1847 &Value, 1848 &OriginalValue 1849 ); 1850 1851 if (EFI_ERROR (Status)) { 1852 // 1853 // the high 32 bit does not claim any BAR, we need to re-check the low 32 bit BAR again 1854 // 1855 if (PciIoDevice->PciBar[BarIndex].Length == 0) { 1856 // 1857 // some device implement MMIO bar with 0 length, need to treat it as no-bar 1858 // 1859 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeUnknown; 1860 return Offset + 4; 1861 } 1862 } 1863 1864 // 1865 // Fix the length to support some spefic 64 bit BAR 1866 // 1867 if (Value == 0) { 1868 DEBUG ((EFI_D_INFO, "[PciBus]BAR probing for upper 32bit of MEM64 BAR returns 0, change to 0xFFFFFFFF.\n")); 1869 Value = (UINT32) -1; 1870 } else { 1871 Value |= ((UINT32)(-1) << HighBitSet32 (Value)); 1872 } 1873 1874 // 1875 // Calculate the size of 64bit bar 1876 // 1877 PciIoDevice->PciBar[BarIndex].BaseAddress |= LShiftU64 ((UINT64) OriginalValue, 32); 1878 1879 PciIoDevice->PciBar[BarIndex].Length = PciIoDevice->PciBar[BarIndex].Length | LShiftU64 ((UINT64) Value, 32); 1880 PciIoDevice->PciBar[BarIndex].Length = (~(PciIoDevice->PciBar[BarIndex].Length)) + 1; 1881 if (PciIoDevice->PciBar[BarIndex].Length < (SIZE_4KB)) { 1882 // 1883 // Force minimum 4KByte alignment for Virtualization technology for Directed I/O 1884 // 1885 PciIoDevice->PciBar[BarIndex].Alignment = (SIZE_4KB - 1); 1886 } else { 1887 PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1; 1888 } 1889 1890 break; 1891 1892 // 1893 // reserved 1894 // 1895 default: 1896 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeUnknown; 1897 PciIoDevice->PciBar[BarIndex].Length = (~(Value & Mask)) + 1; 1898 if (PciIoDevice->PciBar[BarIndex].Length < (SIZE_4KB)) { 1899 // 1900 // Force minimum 4KByte alignment for Virtualization technology for Directed I/O 1901 // 1902 PciIoDevice->PciBar[BarIndex].Alignment = (SIZE_4KB - 1); 1903 } else { 1904 PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1; 1905 } 1906 break; 1907 } 1908 } 1909 1910 // 1911 // Check the length again so as to keep compatible with some special bars 1912 // 1913 if (PciIoDevice->PciBar[BarIndex].Length == 0) { 1914 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeUnknown; 1915 PciIoDevice->PciBar[BarIndex].BaseAddress = 0; 1916 PciIoDevice->PciBar[BarIndex].Alignment = 0; 1917 } 1918 1919 // 1920 // Increment number of bar 1921 // 1922 return Offset + 4; 1923 } 1924 1925 /** 1926 This routine is used to initialize the bar of a PCI device. 1927 1928 @param PciIoDevice Pci device instance. 1929 1930 @note It can be called typically when a device is going to be rejected. 1931 1932 **/ 1933 VOID 1934 InitializePciDevice ( 1935 IN PCI_IO_DEVICE *PciIoDevice 1936 ) 1937 { 1938 EFI_PCI_IO_PROTOCOL *PciIo; 1939 UINT8 Offset; 1940 1941 PciIo = &(PciIoDevice->PciIo); 1942 1943 // 1944 // Put all the resource apertures 1945 // Resource base is set to all ones so as to indicate its resource 1946 // has not been alloacted 1947 // 1948 for (Offset = 0x10; Offset <= 0x24; Offset += sizeof (UINT32)) { 1949 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, Offset, 1, &gAllOne); 1950 } 1951 } 1952 1953 /** 1954 This routine is used to initialize the bar of a PCI-PCI Bridge device. 1955 1956 @param PciIoDevice PCI-PCI bridge device instance. 1957 1958 **/ 1959 VOID 1960 InitializePpb ( 1961 IN PCI_IO_DEVICE *PciIoDevice 1962 ) 1963 { 1964 EFI_PCI_IO_PROTOCOL *PciIo; 1965 1966 PciIo = &(PciIoDevice->PciIo); 1967 1968 // 1969 // Put all the resource apertures including IO16 1970 // Io32, pMem32, pMem64 to quiescent state 1971 // Resource base all ones, Resource limit all zeros 1972 // 1973 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x1C, 1, &gAllOne); 1974 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x1D, 1, &gAllZero); 1975 1976 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x20, 1, &gAllOne); 1977 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x22, 1, &gAllZero); 1978 1979 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x24, 1, &gAllOne); 1980 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x26, 1, &gAllZero); 1981 1982 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x28, 1, &gAllOne); 1983 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x2C, 1, &gAllZero); 1984 1985 // 1986 // Don't support use io32 as for now 1987 // 1988 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x30, 1, &gAllOne); 1989 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x32, 1, &gAllZero); 1990 1991 // 1992 // Force Interrupt line to zero for cards that come up randomly 1993 // 1994 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x3C, 1, &gAllZero); 1995 } 1996 1997 /** 1998 This routine is used to initialize the bar of a PCI Card Bridge device. 1999 2000 @param PciIoDevice PCI Card bridge device. 2001 2002 **/ 2003 VOID 2004 InitializeP2C ( 2005 IN PCI_IO_DEVICE *PciIoDevice 2006 ) 2007 { 2008 EFI_PCI_IO_PROTOCOL *PciIo; 2009 2010 PciIo = &(PciIoDevice->PciIo); 2011 2012 // 2013 // Put all the resource apertures including IO16 2014 // Io32, pMem32, pMem64 to quiescent state( 2015 // Resource base all ones, Resource limit all zeros 2016 // 2017 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x1c, 1, &gAllOne); 2018 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x20, 1, &gAllZero); 2019 2020 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x24, 1, &gAllOne); 2021 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x28, 1, &gAllZero); 2022 2023 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x2c, 1, &gAllOne); 2024 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x30, 1, &gAllZero); 2025 2026 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x34, 1, &gAllOne); 2027 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x38, 1, &gAllZero); 2028 2029 // 2030 // Force Interrupt line to zero for cards that come up randomly 2031 // 2032 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x3C, 1, &gAllZero); 2033 } 2034 2035 /** 2036 Create and initiliaze general PCI I/O device instance for 2037 PCI device/bridge device/hotplug bridge device. 2038 2039 @param PciRootBridgeIo Pointer to instance of EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL. 2040 @param Pci Input Pci information block. 2041 @param Bus Device Bus NO. 2042 @param Device Device device NO. 2043 @param Func Device func NO. 2044 2045 @return Instance of PCI device. NULL means no instance created. 2046 2047 **/ 2048 PCI_IO_DEVICE * 2049 CreatePciIoDevice ( 2050 IN PCI_IO_DEVICE *Bridge, 2051 IN PCI_TYPE00 *Pci, 2052 IN UINT8 Bus, 2053 IN UINT8 Device, 2054 IN UINT8 Func 2055 ) 2056 { 2057 PCI_IO_DEVICE *PciIoDevice; 2058 EFI_PCI_IO_PROTOCOL *PciIo; 2059 EFI_STATUS Status; 2060 2061 PciIoDevice = AllocateZeroPool (sizeof (PCI_IO_DEVICE)); 2062 if (PciIoDevice == NULL) { 2063 return NULL; 2064 } 2065 2066 PciIoDevice->Signature = PCI_IO_DEVICE_SIGNATURE; 2067 PciIoDevice->Handle = NULL; 2068 PciIoDevice->PciRootBridgeIo = Bridge->PciRootBridgeIo; 2069 PciIoDevice->DevicePath = NULL; 2070 PciIoDevice->BusNumber = Bus; 2071 PciIoDevice->DeviceNumber = Device; 2072 PciIoDevice->FunctionNumber = Func; 2073 PciIoDevice->Decodes = 0; 2074 2075 if (gFullEnumeration) { 2076 PciIoDevice->Allocated = FALSE; 2077 } else { 2078 PciIoDevice->Allocated = TRUE; 2079 } 2080 2081 PciIoDevice->Registered = FALSE; 2082 PciIoDevice->Attributes = 0; 2083 PciIoDevice->Supports = 0; 2084 PciIoDevice->BusOverride = FALSE; 2085 PciIoDevice->AllOpRomProcessed = FALSE; 2086 2087 PciIoDevice->IsPciExp = FALSE; 2088 2089 CopyMem (&(PciIoDevice->Pci), Pci, sizeof (PCI_TYPE01)); 2090 2091 // 2092 // Initialize the PCI I/O instance structure 2093 // 2094 InitializePciIoInstance (PciIoDevice); 2095 InitializePciDriverOverrideInstance (PciIoDevice); 2096 InitializePciLoadFile2 (PciIoDevice); 2097 PciIo = &PciIoDevice->PciIo; 2098 2099 // 2100 // Create a device path for this PCI device and store it into its private data 2101 // 2102 CreatePciDevicePath ( 2103 Bridge->DevicePath, 2104 PciIoDevice 2105 ); 2106 2107 // 2108 // Detect if PCI Express Device 2109 // 2110 PciIoDevice->PciExpressCapabilityOffset = 0; 2111 Status = LocateCapabilityRegBlock ( 2112 PciIoDevice, 2113 EFI_PCI_CAPABILITY_ID_PCIEXP, 2114 &PciIoDevice->PciExpressCapabilityOffset, 2115 NULL 2116 ); 2117 if (!EFI_ERROR (Status)) { 2118 PciIoDevice->IsPciExp = TRUE; 2119 } 2120 2121 if (PcdGetBool (PcdAriSupport)) { 2122 // 2123 // Check if the device is an ARI device. 2124 // 2125 Status = LocatePciExpressCapabilityRegBlock ( 2126 PciIoDevice, 2127 EFI_PCIE_CAPABILITY_ID_ARI, 2128 &PciIoDevice->AriCapabilityOffset, 2129 NULL 2130 ); 2131 if (!EFI_ERROR (Status)) { 2132 // 2133 // We need to enable ARI feature before calculate BusReservation, 2134 // because FirstVFOffset and VFStride may change after that. 2135 // 2136 EFI_PCI_IO_PROTOCOL *ParentPciIo; 2137 UINT32 Data32; 2138 2139 // 2140 // Check if its parent supports ARI forwarding. 2141 // 2142 ParentPciIo = &Bridge->PciIo; 2143 ParentPciIo->Pci.Read ( 2144 ParentPciIo, 2145 EfiPciIoWidthUint32, 2146 Bridge->PciExpressCapabilityOffset + EFI_PCIE_CAPABILITY_DEVICE_CAPABILITIES_2_OFFSET, 2147 1, 2148 &Data32 2149 ); 2150 if ((Data32 & EFI_PCIE_CAPABILITY_DEVICE_CAPABILITIES_2_ARI_FORWARDING) != 0) { 2151 // 2152 // ARI forward support in bridge, so enable it. 2153 // 2154 ParentPciIo->Pci.Read ( 2155 ParentPciIo, 2156 EfiPciIoWidthUint32, 2157 Bridge->PciExpressCapabilityOffset + EFI_PCIE_CAPABILITY_DEVICE_CONTROL_2_OFFSET, 2158 1, 2159 &Data32 2160 ); 2161 if ((Data32 & EFI_PCIE_CAPABILITY_DEVICE_CONTROL_2_ARI_FORWARDING) == 0) { 2162 Data32 |= EFI_PCIE_CAPABILITY_DEVICE_CONTROL_2_ARI_FORWARDING; 2163 ParentPciIo->Pci.Write ( 2164 ParentPciIo, 2165 EfiPciIoWidthUint32, 2166 Bridge->PciExpressCapabilityOffset + EFI_PCIE_CAPABILITY_DEVICE_CONTROL_2_OFFSET, 2167 1, 2168 &Data32 2169 ); 2170 DEBUG (( 2171 EFI_D_INFO, 2172 " ARI: forwarding enabled for PPB[%02x:%02x:%02x]\n", 2173 Bridge->BusNumber, 2174 Bridge->DeviceNumber, 2175 Bridge->FunctionNumber 2176 )); 2177 } 2178 } 2179 2180 DEBUG ((EFI_D_INFO, " ARI: CapOffset = 0x%x\n", PciIoDevice->AriCapabilityOffset)); 2181 } 2182 } 2183 2184 // 2185 // Initialization for SR-IOV 2186 // 2187 2188 if (PcdGetBool (PcdSrIovSupport)) { 2189 Status = LocatePciExpressCapabilityRegBlock ( 2190 PciIoDevice, 2191 EFI_PCIE_CAPABILITY_ID_SRIOV, 2192 &PciIoDevice->SrIovCapabilityOffset, 2193 NULL 2194 ); 2195 if (!EFI_ERROR (Status)) { 2196 UINT32 SupportedPageSize; 2197 UINT16 VFStride; 2198 UINT16 FirstVFOffset; 2199 UINT16 Data16; 2200 UINT32 PFRid; 2201 UINT32 LastVF; 2202 2203 // 2204 // If the SR-IOV device is an ARI device, then Set ARI Capable Hierarchy for the device. 2205 // 2206 if (PcdGetBool (PcdAriSupport) && PciIoDevice->AriCapabilityOffset != 0) { 2207 PciIo->Pci.Read ( 2208 PciIo, 2209 EfiPciIoWidthUint16, 2210 PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_CONTROL, 2211 1, 2212 &Data16 2213 ); 2214 Data16 |= EFI_PCIE_CAPABILITY_ID_SRIOV_CONTROL_ARI_HIERARCHY; 2215 PciIo->Pci.Write ( 2216 PciIo, 2217 EfiPciIoWidthUint16, 2218 PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_CONTROL, 2219 1, 2220 &Data16 2221 ); 2222 } 2223 2224 // 2225 // Calculate SystemPageSize 2226 // 2227 2228 PciIo->Pci.Read ( 2229 PciIo, 2230 EfiPciIoWidthUint32, 2231 PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_SUPPORTED_PAGE_SIZE, 2232 1, 2233 &SupportedPageSize 2234 ); 2235 PciIoDevice->SystemPageSize = (PcdGet32 (PcdSrIovSystemPageSize) & SupportedPageSize); 2236 ASSERT (PciIoDevice->SystemPageSize != 0); 2237 2238 PciIo->Pci.Write ( 2239 PciIo, 2240 EfiPciIoWidthUint32, 2241 PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_SYSTEM_PAGE_SIZE, 2242 1, 2243 &PciIoDevice->SystemPageSize 2244 ); 2245 // 2246 // Adjust SystemPageSize for Alignment usage later 2247 // 2248 PciIoDevice->SystemPageSize <<= 12; 2249 2250 // 2251 // Calculate BusReservation for PCI IOV 2252 // 2253 2254 // 2255 // Read First FirstVFOffset, InitialVFs, and VFStride 2256 // 2257 PciIo->Pci.Read ( 2258 PciIo, 2259 EfiPciIoWidthUint16, 2260 PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_FIRSTVF, 2261 1, 2262 &FirstVFOffset 2263 ); 2264 PciIo->Pci.Read ( 2265 PciIo, 2266 EfiPciIoWidthUint16, 2267 PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_INITIALVFS, 2268 1, 2269 &PciIoDevice->InitialVFs 2270 ); 2271 PciIo->Pci.Read ( 2272 PciIo, 2273 EfiPciIoWidthUint16, 2274 PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_VFSTRIDE, 2275 1, 2276 &VFStride 2277 ); 2278 // 2279 // Calculate LastVF 2280 // 2281 PFRid = EFI_PCI_RID(Bus, Device, Func); 2282 LastVF = PFRid + FirstVFOffset + (PciIoDevice->InitialVFs - 1) * VFStride; 2283 2284 // 2285 // Calculate ReservedBusNum for this PF 2286 // 2287 PciIoDevice->ReservedBusNum = (UINT16)(EFI_PCI_BUS_OF_RID (LastVF) - Bus + 1); 2288 2289 DEBUG (( 2290 EFI_D_INFO, 2291 " SR-IOV: SupportedPageSize = 0x%x; SystemPageSize = 0x%x; FirstVFOffset = 0x%x;\n", 2292 SupportedPageSize, PciIoDevice->SystemPageSize >> 12, FirstVFOffset 2293 )); 2294 DEBUG (( 2295 EFI_D_INFO, 2296 " InitialVFs = 0x%x; ReservedBusNum = 0x%x; CapOffset = 0x%x\n", 2297 PciIoDevice->InitialVFs, PciIoDevice->ReservedBusNum, PciIoDevice->SrIovCapabilityOffset 2298 )); 2299 } 2300 } 2301 2302 if (PcdGetBool (PcdMrIovSupport)) { 2303 Status = LocatePciExpressCapabilityRegBlock ( 2304 PciIoDevice, 2305 EFI_PCIE_CAPABILITY_ID_MRIOV, 2306 &PciIoDevice->MrIovCapabilityOffset, 2307 NULL 2308 ); 2309 if (!EFI_ERROR (Status)) { 2310 DEBUG ((EFI_D_INFO, " MR-IOV: CapOffset = 0x%x\n", PciIoDevice->MrIovCapabilityOffset)); 2311 } 2312 } 2313 2314 // 2315 // Initialize the reserved resource list 2316 // 2317 InitializeListHead (&PciIoDevice->ReservedResourceList); 2318 2319 // 2320 // Initialize the driver list 2321 // 2322 InitializeListHead (&PciIoDevice->OptionRomDriverList); 2323 2324 // 2325 // Initialize the child list 2326 // 2327 InitializeListHead (&PciIoDevice->ChildList); 2328 2329 return PciIoDevice; 2330 } 2331 2332 /** 2333 This routine is used to enumerate entire pci bus system 2334 in a given platform. 2335 2336 It is only called on the second start on the same Root Bridge. 2337 2338 @param Controller Parent bridge handler. 2339 2340 @retval EFI_SUCCESS PCI enumeration finished successfully. 2341 @retval other Some error occurred when enumerating the pci bus system. 2342 2343 **/ 2344 EFI_STATUS 2345 PciEnumeratorLight ( 2346 IN EFI_HANDLE Controller 2347 ) 2348 { 2349 2350 EFI_STATUS Status; 2351 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo; 2352 PCI_IO_DEVICE *RootBridgeDev; 2353 UINT16 MinBus; 2354 UINT16 MaxBus; 2355 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptors; 2356 2357 MinBus = 0; 2358 MaxBus = PCI_MAX_BUS; 2359 Descriptors = NULL; 2360 2361 // 2362 // If this root bridge has been already enumerated, then return successfully 2363 // 2364 if (GetRootBridgeByHandle (Controller) != NULL) { 2365 return EFI_SUCCESS; 2366 } 2367 2368 // 2369 // Open pci root bridge io protocol 2370 // 2371 Status = gBS->OpenProtocol ( 2372 Controller, 2373 &gEfiPciRootBridgeIoProtocolGuid, 2374 (VOID **) &PciRootBridgeIo, 2375 gPciBusDriverBinding.DriverBindingHandle, 2376 Controller, 2377 EFI_OPEN_PROTOCOL_BY_DRIVER 2378 ); 2379 if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) { 2380 return Status; 2381 } 2382 2383 Status = PciRootBridgeIo->Configuration (PciRootBridgeIo, (VOID **) &Descriptors); 2384 2385 if (EFI_ERROR (Status)) { 2386 return Status; 2387 } 2388 2389 while (PciGetBusRange (&Descriptors, &MinBus, &MaxBus, NULL) == EFI_SUCCESS) { 2390 2391 // 2392 // Create a device node for root bridge device with a NULL host bridge controller handle 2393 // 2394 RootBridgeDev = CreateRootBridge (Controller); 2395 2396 if (RootBridgeDev == NULL) { 2397 Descriptors++; 2398 continue; 2399 } 2400 2401 // 2402 // Record the root bridgeio protocol 2403 // 2404 RootBridgeDev->PciRootBridgeIo = PciRootBridgeIo; 2405 2406 Status = PciPciDeviceInfoCollector ( 2407 RootBridgeDev, 2408 (UINT8) MinBus 2409 ); 2410 2411 if (!EFI_ERROR (Status)) { 2412 2413 // 2414 // Remove those PCI devices which are rejected when full enumeration 2415 // 2416 RemoveRejectedPciDevices (RootBridgeDev->Handle, RootBridgeDev); 2417 2418 // 2419 // Process option rom light 2420 // 2421 ProcessOptionRomLight (RootBridgeDev); 2422 2423 // 2424 // Determine attributes for all devices under this root bridge 2425 // 2426 DetermineDeviceAttribute (RootBridgeDev); 2427 2428 // 2429 // If successfully, insert the node into device pool 2430 // 2431 InsertRootBridge (RootBridgeDev); 2432 } else { 2433 2434 // 2435 // If unsuccessly, destroy the entire node 2436 // 2437 DestroyRootBridge (RootBridgeDev); 2438 } 2439 2440 Descriptors++; 2441 } 2442 2443 return EFI_SUCCESS; 2444 } 2445 2446 /** 2447 Get bus range from PCI resource descriptor list. 2448 2449 @param Descriptors A pointer to the address space descriptor. 2450 @param MinBus The min bus returned. 2451 @param MaxBus The max bus returned. 2452 @param BusRange The bus range returned. 2453 2454 @retval EFI_SUCCESS Successfully got bus range. 2455 @retval EFI_NOT_FOUND Can not find the specific bus. 2456 2457 **/ 2458 EFI_STATUS 2459 PciGetBusRange ( 2460 IN EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR **Descriptors, 2461 OUT UINT16 *MinBus, 2462 OUT UINT16 *MaxBus, 2463 OUT UINT16 *BusRange 2464 ) 2465 { 2466 while ((*Descriptors)->Desc != ACPI_END_TAG_DESCRIPTOR) { 2467 if ((*Descriptors)->ResType == ACPI_ADDRESS_SPACE_TYPE_BUS) { 2468 if (MinBus != NULL) { 2469 *MinBus = (UINT16) (*Descriptors)->AddrRangeMin; 2470 } 2471 2472 if (MaxBus != NULL) { 2473 *MaxBus = (UINT16) (*Descriptors)->AddrRangeMax; 2474 } 2475 2476 if (BusRange != NULL) { 2477 *BusRange = (UINT16) (*Descriptors)->AddrLen; 2478 } 2479 2480 return EFI_SUCCESS; 2481 } 2482 2483 (*Descriptors)++; 2484 } 2485 2486 return EFI_NOT_FOUND; 2487 } 2488 2489 /** 2490 This routine can be used to start the root bridge. 2491 2492 @param RootBridgeDev Pci device instance. 2493 2494 @retval EFI_SUCCESS This device started. 2495 @retval other Failed to get PCI Root Bridge I/O protocol. 2496 2497 **/ 2498 EFI_STATUS 2499 StartManagingRootBridge ( 2500 IN PCI_IO_DEVICE *RootBridgeDev 2501 ) 2502 { 2503 EFI_HANDLE RootBridgeHandle; 2504 EFI_STATUS Status; 2505 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo; 2506 2507 // 2508 // Get the root bridge handle 2509 // 2510 RootBridgeHandle = RootBridgeDev->Handle; 2511 PciRootBridgeIo = NULL; 2512 2513 // 2514 // Get the pci root bridge io protocol 2515 // 2516 Status = gBS->OpenProtocol ( 2517 RootBridgeHandle, 2518 &gEfiPciRootBridgeIoProtocolGuid, 2519 (VOID **) &PciRootBridgeIo, 2520 gPciBusDriverBinding.DriverBindingHandle, 2521 RootBridgeHandle, 2522 EFI_OPEN_PROTOCOL_BY_DRIVER 2523 ); 2524 2525 if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) { 2526 return Status; 2527 } 2528 2529 // 2530 // Store the PciRootBridgeIo protocol into root bridge private data 2531 // 2532 RootBridgeDev->PciRootBridgeIo = PciRootBridgeIo; 2533 2534 return EFI_SUCCESS; 2535 2536 } 2537 2538 /** 2539 This routine can be used to check whether a PCI device should be rejected when light enumeration. 2540 2541 @param PciIoDevice Pci device instance. 2542 2543 @retval TRUE This device should be rejected. 2544 @retval FALSE This device shouldn't be rejected. 2545 2546 **/ 2547 BOOLEAN 2548 IsPciDeviceRejected ( 2549 IN PCI_IO_DEVICE *PciIoDevice 2550 ) 2551 { 2552 EFI_STATUS Status; 2553 UINT32 TestValue; 2554 UINT32 OldValue; 2555 UINT32 Mask; 2556 UINT8 BarOffset; 2557 2558 // 2559 // PPB should be skip! 2560 // 2561 if (IS_PCI_BRIDGE (&PciIoDevice->Pci)) { 2562 return FALSE; 2563 } 2564 2565 if (IS_CARDBUS_BRIDGE (&PciIoDevice->Pci)) { 2566 // 2567 // Only test base registers for P2C 2568 // 2569 for (BarOffset = 0x1C; BarOffset <= 0x38; BarOffset += 2 * sizeof (UINT32)) { 2570 2571 Mask = (BarOffset < 0x2C) ? 0xFFFFF000 : 0xFFFFFFFC; 2572 Status = BarExisted (PciIoDevice, BarOffset, &TestValue, &OldValue); 2573 if (EFI_ERROR (Status)) { 2574 continue; 2575 } 2576 2577 TestValue = TestValue & Mask; 2578 if ((TestValue != 0) && (TestValue == (OldValue & Mask))) { 2579 // 2580 // The bar isn't programed, so it should be rejected 2581 // 2582 return TRUE; 2583 } 2584 } 2585 2586 return FALSE; 2587 } 2588 2589 for (BarOffset = 0x14; BarOffset <= 0x24; BarOffset += sizeof (UINT32)) { 2590 // 2591 // Test PCI devices 2592 // 2593 Status = BarExisted (PciIoDevice, BarOffset, &TestValue, &OldValue); 2594 if (EFI_ERROR (Status)) { 2595 continue; 2596 } 2597 2598 if ((TestValue & 0x01) != 0) { 2599 2600 // 2601 // IO Bar 2602 // 2603 Mask = 0xFFFFFFFC; 2604 TestValue = TestValue & Mask; 2605 if ((TestValue != 0) && (TestValue == (OldValue & Mask))) { 2606 return TRUE; 2607 } 2608 2609 } else { 2610 2611 // 2612 // Mem Bar 2613 // 2614 Mask = 0xFFFFFFF0; 2615 TestValue = TestValue & Mask; 2616 2617 if ((TestValue & 0x07) == 0x04) { 2618 2619 // 2620 // Mem64 or PMem64 2621 // 2622 BarOffset += sizeof (UINT32); 2623 if ((TestValue != 0) && (TestValue == (OldValue & Mask))) { 2624 2625 // 2626 // Test its high 32-Bit BAR 2627 // 2628 Status = BarExisted (PciIoDevice, BarOffset, &TestValue, &OldValue); 2629 if (TestValue == OldValue) { 2630 return TRUE; 2631 } 2632 } 2633 2634 } else { 2635 2636 // 2637 // Mem32 or PMem32 2638 // 2639 if ((TestValue != 0) && (TestValue == (OldValue & Mask))) { 2640 return TRUE; 2641 } 2642 } 2643 } 2644 } 2645 2646 return FALSE; 2647 } 2648 2649 /** 2650 Reset all bus number from specific bridge. 2651 2652 @param Bridge Parent specific bridge. 2653 @param StartBusNumber Start bus number. 2654 2655 **/ 2656 VOID 2657 ResetAllPpbBusNumber ( 2658 IN PCI_IO_DEVICE *Bridge, 2659 IN UINT8 StartBusNumber 2660 ) 2661 { 2662 EFI_STATUS Status; 2663 PCI_TYPE00 Pci; 2664 UINT8 Device; 2665 UINT32 Register; 2666 UINT8 Func; 2667 UINT64 Address; 2668 UINT8 SecondaryBus; 2669 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo; 2670 2671 PciRootBridgeIo = Bridge->PciRootBridgeIo; 2672 2673 for (Device = 0; Device <= PCI_MAX_DEVICE; Device++) { 2674 for (Func = 0; Func <= PCI_MAX_FUNC; Func++) { 2675 2676 // 2677 // Check to see whether a pci device is present 2678 // 2679 Status = PciDevicePresent ( 2680 PciRootBridgeIo, 2681 &Pci, 2682 StartBusNumber, 2683 Device, 2684 Func 2685 ); 2686 2687 if (EFI_ERROR (Status) && Func == 0) { 2688 // 2689 // go to next device if there is no Function 0 2690 // 2691 break; 2692 } 2693 2694 if (!EFI_ERROR (Status) && (IS_PCI_BRIDGE (&Pci))) { 2695 2696 Register = 0; 2697 Address = EFI_PCI_ADDRESS (StartBusNumber, Device, Func, 0x18); 2698 Status = PciRootBridgeIo->Pci.Read ( 2699 PciRootBridgeIo, 2700 EfiPciWidthUint32, 2701 Address, 2702 1, 2703 &Register 2704 ); 2705 SecondaryBus = (UINT8)(Register >> 8); 2706 2707 if (SecondaryBus != 0) { 2708 ResetAllPpbBusNumber (Bridge, SecondaryBus); 2709 } 2710 2711 // 2712 // Reset register 18h, 19h, 1Ah on PCI Bridge 2713 // 2714 Register &= 0xFF000000; 2715 Status = PciRootBridgeIo->Pci.Write ( 2716 PciRootBridgeIo, 2717 EfiPciWidthUint32, 2718 Address, 2719 1, 2720 &Register 2721 ); 2722 } 2723 2724 if (Func == 0 && !IS_PCI_MULTI_FUNC (&Pci)) { 2725 // 2726 // Skip sub functions, this is not a multi function device 2727 // 2728 Func = PCI_MAX_FUNC; 2729 } 2730 } 2731 } 2732 } 2733 2734