add SR-IOV support in EDK II.
[edk2.git] / IntelFrameworkModulePkg / Bus / Pci / PciBusDxe / PciEnumeratorSupport.c
blob66183960f16b3aed78476837b869df6b529ebd2b
1 /** @file
2 PCI emumeration support functions implementation for PCI Bus module.
4 Copyright (c) 2006 - 2009, Intel Corporation
5 All rights reserved. This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13 **/
15 #include "PciBus.h"
17 /**
18 This routine is used to check whether the pci device is present.
20 @param PciRootBridgeIo Pointer to instance of EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
21 @param Pci Output buffer for PCI device configuration space.
22 @param Bus PCI bus NO.
23 @param Device PCI device NO.
24 @param Func PCI Func NO.
26 @retval EFI_NOT_FOUND PCI device not present.
27 @retval EFI_SUCCESS PCI device is found.
29 **/
30 EFI_STATUS
31 PciDevicePresent (
32 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo,
33 OUT PCI_TYPE00 *Pci,
34 IN UINT8 Bus,
35 IN UINT8 Device,
36 IN UINT8 Func
39 UINT64 Address;
40 EFI_STATUS Status;
43 // Create PCI address map in terms of Bus, Device and Func
45 Address = EFI_PCI_ADDRESS (Bus, Device, Func, 0);
48 // Read the Vendor ID register
50 Status = PciRootBridgeIo->Pci.Read (
51 PciRootBridgeIo,
52 EfiPciWidthUint32,
53 Address,
55 Pci
58 if (!EFI_ERROR (Status) && (Pci->Hdr).VendorId != 0xffff) {
60 // Read the entire config header for the device
62 Status = PciRootBridgeIo->Pci.Read (
63 PciRootBridgeIo,
64 EfiPciWidthUint32,
65 Address,
66 sizeof (PCI_TYPE00) / sizeof (UINT32),
67 Pci
70 return EFI_SUCCESS;
73 return EFI_NOT_FOUND;
76 /**
77 Collect all the resource information under this root bridge.
79 A database that records all the information about pci device subject to this
80 root bridge will then be created.
82 @param Bridge Parent bridge instance.
83 @param StartBusNumber Bus number of begining.
85 @retval EFI_SUCCESS PCI device is found.
86 @retval other Some error occurred when reading PCI bridge information.
88 **/
89 EFI_STATUS
90 PciPciDeviceInfoCollector (
91 IN PCI_IO_DEVICE *Bridge,
92 IN UINT8 StartBusNumber
95 EFI_STATUS Status;
96 PCI_TYPE00 Pci;
97 UINT8 Device;
98 UINT8 Func;
99 UINT8 SecBus;
100 PCI_IO_DEVICE *PciIoDevice;
101 EFI_PCI_IO_PROTOCOL *PciIo;
103 Status = EFI_SUCCESS;
104 SecBus = 0;
106 for (Device = 0; Device <= PCI_MAX_DEVICE; Device++) {
108 for (Func = 0; Func <= PCI_MAX_FUNC; Func++) {
111 // Check to see whether PCI device is present
113 Status = PciDevicePresent (
114 Bridge->PciRootBridgeIo,
115 &Pci,
116 (UINT8) StartBusNumber,
117 (UINT8) Device,
118 (UINT8) Func
120 if (!EFI_ERROR (Status)) {
123 // Call back to host bridge function
125 PreprocessController (Bridge, (UINT8) StartBusNumber, Device, Func, EfiPciBeforeResourceCollection);
128 // Collect all the information about the PCI device discovered
130 Status = PciSearchDevice (
131 Bridge,
132 &Pci,
133 (UINT8) StartBusNumber,
134 Device,
135 Func,
136 &PciIoDevice
140 // Recursively scan PCI busses on the other side of PCI-PCI bridges
143 if (!EFI_ERROR (Status) && (IS_PCI_BRIDGE (&Pci) || IS_CARDBUS_BRIDGE (&Pci))) {
146 // If it is PPB, we need to get the secondary bus to continue the enumeration
148 PciIo = &(PciIoDevice->PciIo);
150 Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8, PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET, 1, &SecBus);
152 if (EFI_ERROR (Status)) {
153 return Status;
157 // Get resource padding for PPB
159 GetResourcePaddingPpb (PciIoDevice);
162 // Deep enumerate the next level bus
164 Status = PciPciDeviceInfoCollector (
165 PciIoDevice,
166 (UINT8) (SecBus)
171 if (Func == 0 && !IS_PCI_MULTI_FUNC (&Pci)) {
174 // Skip sub functions, this is not a multi function device
176 Func = PCI_MAX_FUNC;
183 return EFI_SUCCESS;
187 Seach required device and create PCI device instance.
189 @param Bridge Parent bridge instance.
190 @param Pci Input PCI device information block.
191 @param Bus PCI bus NO.
192 @param Device PCI device NO.
193 @param Func PCI func NO.
194 @param PciDevice Output of searched PCI device instance.
196 @retval EFI_SUCCESS Successfully created PCI device instance.
197 @retval EFI_OUT_OF_RESOURCES Cannot get PCI device information.
200 EFI_STATUS
201 PciSearchDevice (
202 IN PCI_IO_DEVICE *Bridge,
203 IN PCI_TYPE00 *Pci,
204 IN UINT8 Bus,
205 IN UINT8 Device,
206 IN UINT8 Func,
207 OUT PCI_IO_DEVICE **PciDevice
210 PCI_IO_DEVICE *PciIoDevice;
212 PciIoDevice = NULL;
214 if (!IS_PCI_BRIDGE (Pci)) {
216 if (IS_CARDBUS_BRIDGE (Pci)) {
217 PciIoDevice = GatherP2CInfo (
218 Bridge,
219 Pci,
220 Bus,
221 Device,
222 Func
224 if ((PciIoDevice != NULL) && gFullEnumeration) {
225 InitializeP2C (PciIoDevice);
227 } else {
230 // Create private data for Pci Device
232 PciIoDevice = GatherDeviceInfo (
233 Bridge,
234 Pci,
235 Bus,
236 Device,
237 Func
242 } else {
245 // Create private data for PPB
247 PciIoDevice = GatherPpbInfo (
248 Bridge,
249 Pci,
250 Bus,
251 Device,
252 Func
256 // Special initialization for PPB including making the PPB quiet
258 if ((PciIoDevice != NULL) && gFullEnumeration) {
259 InitializePpb (PciIoDevice);
263 if (PciIoDevice == NULL) {
264 return EFI_OUT_OF_RESOURCES;
268 // Update the bar information for this PCI device so as to support some specific device
270 UpdatePciInfo (PciIoDevice);
272 if (PciIoDevice->DevicePath == NULL) {
273 return EFI_OUT_OF_RESOURCES;
277 // Detect this function has option rom
279 if (gFullEnumeration) {
281 if (!IS_CARDBUS_BRIDGE (Pci)) {
283 GetOpRomInfo (PciIoDevice);
287 ResetPowerManagementFeature (PciIoDevice);
292 // Insert it into a global tree for future reference
294 InsertPciDevice (Bridge, PciIoDevice);
297 // Determine PCI device attributes
300 if (PciDevice != NULL) {
301 *PciDevice = PciIoDevice;
304 return EFI_SUCCESS;
308 Create PCI device instance for PCI device.
310 @param Bridge Parent bridge instance.
311 @param Pci Input PCI device information block.
312 @param Bus PCI device Bus NO.
313 @param Device PCI device Device NO.
314 @param Func PCI device's func NO.
316 @return Created PCI device instance.
319 PCI_IO_DEVICE *
320 GatherDeviceInfo (
321 IN PCI_IO_DEVICE *Bridge,
322 IN PCI_TYPE00 *Pci,
323 IN UINT8 Bus,
324 IN UINT8 Device,
325 IN UINT8 Func
328 UINTN Offset;
329 UINTN BarIndex;
330 PCI_IO_DEVICE *PciIoDevice;
331 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;
333 PciRootBridgeIo = Bridge->PciRootBridgeIo;
334 PciIoDevice = CreatePciIoDevice (
335 PciRootBridgeIo,
336 Pci,
337 Bus,
338 Device,
339 Func
342 if (PciIoDevice == NULL) {
343 return NULL;
347 // Create a device path for this PCI device and store it into its private data
349 CreatePciDevicePath (
350 Bridge->DevicePath,
351 PciIoDevice
355 // If it is a full enumeration, disconnect the device in advance
357 if (gFullEnumeration) {
359 PCI_DISABLE_COMMAND_REGISTER (PciIoDevice, EFI_PCI_COMMAND_BITS_OWNED);
364 // Start to parse the bars
366 for (Offset = 0x10, BarIndex = 0; Offset <= 0x24 && BarIndex < PCI_MAX_BAR; BarIndex++) {
367 Offset = PciParseBar (PciIoDevice, Offset, BarIndex);
371 // Parse the SR-IOV VF bars
373 if ((PciIoDevice->SrIovCapabilityOffset != 0) && ((FeaturePcdGet(PcdSrIovSupport)& EFI_PCI_IOV_POLICY_SRIOV) != 0)) {
374 for (Offset = PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_BAR0, BarIndex = 0;
375 Offset <= PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_BAR5;
376 BarIndex++) {
377 Offset = PciIovParseVfBar (PciIoDevice, Offset, BarIndex);
380 return PciIoDevice;
384 Create PCI device instance for PCI-PCI bridge.
386 @param Bridge Parent bridge instance.
387 @param Pci Input PCI device information block.
388 @param Bus PCI device Bus NO.
389 @param Device PCI device Device NO.
390 @param Func PCI device's func NO.
392 @return Created PCI device instance.
395 PCI_IO_DEVICE *
396 GatherPpbInfo (
397 IN PCI_IO_DEVICE *Bridge,
398 IN PCI_TYPE00 *Pci,
399 IN UINT8 Bus,
400 IN UINT8 Device,
401 IN UINT8 Func
404 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;
405 PCI_IO_DEVICE *PciIoDevice;
406 EFI_STATUS Status;
407 UINT8 Value;
408 EFI_PCI_IO_PROTOCOL *PciIo;
409 UINT8 Temp;
411 PciRootBridgeIo = Bridge->PciRootBridgeIo;
412 PciIoDevice = CreatePciIoDevice (
413 PciRootBridgeIo,
414 Pci,
415 Bus,
416 Device,
417 Func
420 if (PciIoDevice == NULL) {
421 return NULL;
425 // Create a device path for this PCI device and store it into its private data
427 CreatePciDevicePath (
428 Bridge->DevicePath,
429 PciIoDevice
432 if (gFullEnumeration) {
433 PCI_DISABLE_COMMAND_REGISTER (PciIoDevice, EFI_PCI_COMMAND_BITS_OWNED);
436 // Initalize the bridge control register
438 PCI_DISABLE_BRIDGE_CONTROL_REGISTER (PciIoDevice, EFI_PCI_BRIDGE_CONTROL_BITS_OWNED);
443 // PPB can have two BARs
445 if (PciParseBar (PciIoDevice, 0x10, PPB_BAR_0) == 0x14) {
447 // Not 64-bit bar
449 PciParseBar (PciIoDevice, 0x14, PPB_BAR_1);
452 PciIo = &PciIoDevice->PciIo;
455 // Test whether it support 32 decode or not
457 PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8, 0x1C, 1, &Temp);
458 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x1C, 1, &gAllOne);
459 PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8, 0x1C, 1, &Value);
460 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x1C, 1, &Temp);
462 if (Value != 0) {
463 if ((Value & 0x01) != 0) {
464 PciIoDevice->Decodes |= EFI_BRIDGE_IO32_DECODE_SUPPORTED;
465 } else {
466 PciIoDevice->Decodes |= EFI_BRIDGE_IO16_DECODE_SUPPORTED;
470 Status = BarExisted (
471 PciIoDevice,
472 0x24,
473 NULL,
474 NULL
478 // Test if it supports 64 memory or not
480 if (!EFI_ERROR (Status)) {
482 Status = BarExisted (
483 PciIoDevice,
484 0x28,
485 NULL,
486 NULL
489 if (!EFI_ERROR (Status)) {
490 PciIoDevice->Decodes |= EFI_BRIDGE_PMEM32_DECODE_SUPPORTED;
491 PciIoDevice->Decodes |= EFI_BRIDGE_PMEM64_DECODE_SUPPORTED;
492 } else {
493 PciIoDevice->Decodes |= EFI_BRIDGE_PMEM32_DECODE_SUPPORTED;
498 // Memory 32 code is required for ppb
500 PciIoDevice->Decodes |= EFI_BRIDGE_MEM32_DECODE_SUPPORTED;
502 GetResourcePaddingPpb (PciIoDevice);
504 return PciIoDevice;
509 Create PCI device instance for PCI Card bridge device.
511 @param Bridge Parent bridge instance.
512 @param Pci Input PCI device information block.
513 @param Bus PCI device Bus NO.
514 @param Device PCI device Device NO.
515 @param Func PCI device's func NO.
517 @return Created PCI device instance.
520 PCI_IO_DEVICE *
521 GatherP2CInfo (
522 IN PCI_IO_DEVICE *Bridge,
523 IN PCI_TYPE00 *Pci,
524 IN UINT8 Bus,
525 IN UINT8 Device,
526 IN UINT8 Func
529 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;
530 PCI_IO_DEVICE *PciIoDevice;
532 PciRootBridgeIo = Bridge->PciRootBridgeIo;
533 PciIoDevice = CreatePciIoDevice (
534 PciRootBridgeIo,
535 Pci,
536 Bus,
537 Device,
538 Func
541 if (PciIoDevice == NULL) {
542 return NULL;
546 // Create a device path for this PCI device and store it into its private data
548 CreatePciDevicePath (
549 Bridge->DevicePath,
550 PciIoDevice
553 if (gFullEnumeration) {
554 PCI_DISABLE_COMMAND_REGISTER (PciIoDevice, EFI_PCI_COMMAND_BITS_OWNED);
557 // Initalize the bridge control register
559 PCI_DISABLE_BRIDGE_CONTROL_REGISTER (PciIoDevice, EFI_PCCARD_BRIDGE_CONTROL_BITS_OWNED);
563 // P2C only has one bar that is in 0x10
565 PciParseBar (PciIoDevice, 0x10, P2C_BAR_0);
568 // Read PciBar information from the bar register
570 GetBackPcCardBar (PciIoDevice);
571 PciIoDevice->Decodes = EFI_BRIDGE_MEM32_DECODE_SUPPORTED |
572 EFI_BRIDGE_PMEM32_DECODE_SUPPORTED |
573 EFI_BRIDGE_IO32_DECODE_SUPPORTED;
575 return PciIoDevice;
579 Create device path for pci deivce.
581 @param ParentDevicePath Parent bridge's path.
582 @param PciIoDevice Pci device instance.
584 @return Device path protocol instance for specific pci device.
587 EFI_DEVICE_PATH_PROTOCOL *
588 CreatePciDevicePath (
589 IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath,
590 IN PCI_IO_DEVICE *PciIoDevice
594 PCI_DEVICE_PATH PciNode;
597 // Create PCI device path
599 PciNode.Header.Type = HARDWARE_DEVICE_PATH;
600 PciNode.Header.SubType = HW_PCI_DP;
601 SetDevicePathNodeLength (&PciNode.Header, sizeof (PciNode));
603 PciNode.Device = PciIoDevice->DeviceNumber;
604 PciNode.Function = PciIoDevice->FunctionNumber;
605 PciIoDevice->DevicePath = AppendDevicePathNode (ParentDevicePath, &PciNode.Header);
607 return PciIoDevice->DevicePath;
611 Check whether the PCI IOV VF bar is existed or not.
613 @param PciIoDevice A pointer to the PCI_IO_DEVICE.
614 @param Offset The offset.
615 @param BarLengthValue The bar length value returned.
616 @param OriginalBarValue The original bar value returned.
618 @retval EFI_NOT_FOUND The bar doesn't exist.
619 @retval EFI_SUCCESS The bar exist.
622 EFI_STATUS
623 VfBarExisted (
624 IN PCI_IO_DEVICE *PciIoDevice,
625 IN UINTN Offset,
626 OUT UINT32 *BarLengthValue,
627 OUT UINT32 *OriginalBarValue
630 EFI_PCI_IO_PROTOCOL *PciIo;
631 UINT32 OriginalValue;
632 UINT32 Value;
633 EFI_TPL OldTpl;
636 // Ensure it is called properly
638 ASSERT (PciIoDevice->SrIovCapabilityOffset != 0);
639 if (PciIoDevice->SrIovCapabilityOffset == 0) {
640 return EFI_NOT_FOUND;
643 PciIo = &PciIoDevice->PciIo;
646 // Preserve the original value
649 PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, (UINT32)Offset, 1, &OriginalValue);
652 // Raise TPL to high level to disable timer interrupt while the BAR is probed
654 OldTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);
656 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, (UINT32)Offset, 1, &gAllOne);
657 PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, (UINT32)Offset, 1, &Value);
660 // Write back the original value
662 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, (UINT32)Offset, 1, &OriginalValue);
665 // Restore TPL to its original level
667 gBS->RestoreTPL (OldTpl);
669 if (BarLengthValue != NULL) {
670 *BarLengthValue = Value;
673 if (OriginalBarValue != NULL) {
674 *OriginalBarValue = OriginalValue;
677 if (Value == 0) {
678 return EFI_NOT_FOUND;
679 } else {
680 return EFI_SUCCESS;
685 Check whether the bar is existed or not.
687 @param PciIoDevice A pointer to the PCI_IO_DEVICE.
688 @param Offset The offset.
689 @param BarLengthValue The bar length value returned.
690 @param OriginalBarValue The original bar value returned.
692 @retval EFI_NOT_FOUND The bar doesn't exist.
693 @retval EFI_SUCCESS The bar exist.
696 EFI_STATUS
697 BarExisted (
698 IN PCI_IO_DEVICE *PciIoDevice,
699 IN UINTN Offset,
700 OUT UINT32 *BarLengthValue,
701 OUT UINT32 *OriginalBarValue
704 EFI_PCI_IO_PROTOCOL *PciIo;
705 UINT32 OriginalValue;
706 UINT32 Value;
707 EFI_TPL OldTpl;
709 PciIo = &PciIoDevice->PciIo;
712 // Preserve the original value
714 PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, (UINT8) Offset, 1, &OriginalValue);
717 // Raise TPL to high level to disable timer interrupt while the BAR is probed
719 OldTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);
721 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, (UINT8) Offset, 1, &gAllOne);
722 PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, (UINT8) Offset, 1, &Value);
725 // Write back the original value
727 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, (UINT8) Offset, 1, &OriginalValue);
730 // Restore TPL to its original level
732 gBS->RestoreTPL (OldTpl);
734 if (BarLengthValue != NULL) {
735 *BarLengthValue = Value;
738 if (OriginalBarValue != NULL) {
739 *OriginalBarValue = OriginalValue;
742 if (Value == 0) {
743 return EFI_NOT_FOUND;
744 } else {
745 return EFI_SUCCESS;
750 Test whether the device can support given attributes.
752 @param PciIoDevice Pci device instance.
753 @param Command Input command register value, and
754 returned supported register value.
755 @param BridgeControl Inout bridge control value for PPB or P2C, and
756 returned supported bridge control value.
757 @param OldCommand Returned and stored old command register offset.
758 @param OldBridgeControl Returned and stored old Bridge control value for PPB or P2C.
761 VOID
762 PciTestSupportedAttribute (
763 IN PCI_IO_DEVICE *PciIoDevice,
764 IN OUT UINT16 *Command,
765 IN OUT UINT16 *BridgeControl,
766 OUT UINT16 *OldCommand,
767 OUT UINT16 *OldBridgeControl
770 EFI_TPL OldTpl;
773 // Preserve the original value
775 PCI_READ_COMMAND_REGISTER (PciIoDevice, OldCommand);
778 // Raise TPL to high level to disable timer interrupt while the BAR is probed
780 OldTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);
782 PCI_SET_COMMAND_REGISTER (PciIoDevice, *Command);
783 PCI_READ_COMMAND_REGISTER (PciIoDevice, Command);
786 // Write back the original value
788 PCI_SET_COMMAND_REGISTER (PciIoDevice, *OldCommand);
791 // Restore TPL to its original level
793 gBS->RestoreTPL (OldTpl);
795 if (IS_PCI_BRIDGE (&PciIoDevice->Pci) || IS_CARDBUS_BRIDGE (&PciIoDevice->Pci)) {
798 // Preserve the original value
800 PCI_READ_BRIDGE_CONTROL_REGISTER (PciIoDevice, OldBridgeControl);
803 // Raise TPL to high level to disable timer interrupt while the BAR is probed
805 OldTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);
807 PCI_SET_BRIDGE_CONTROL_REGISTER (PciIoDevice, *BridgeControl);
808 PCI_READ_BRIDGE_CONTROL_REGISTER (PciIoDevice, BridgeControl);
811 // Write back the original value
813 PCI_SET_BRIDGE_CONTROL_REGISTER (PciIoDevice, *OldBridgeControl);
816 // Restore TPL to its original level
818 gBS->RestoreTPL (OldTpl);
820 } else {
821 *OldBridgeControl = 0;
822 *BridgeControl = 0;
827 Set the supported or current attributes of a PCI device.
829 @param PciIoDevice Structure pointer for PCI device.
830 @param Command Command register value.
831 @param BridgeControl Bridge control value for PPB or P2C.
832 @param Option Make a choice of EFI_SET_SUPPORTS or EFI_SET_ATTRIBUTES.
835 VOID
836 PciSetDeviceAttribute (
837 IN PCI_IO_DEVICE *PciIoDevice,
838 IN UINT16 Command,
839 IN UINT16 BridgeControl,
840 IN UINTN Option
843 UINT64 Attributes;
845 Attributes = 0;
847 if ((Command & EFI_PCI_COMMAND_IO_SPACE) != 0) {
848 Attributes |= EFI_PCI_IO_ATTRIBUTE_IO;
851 if ((Command & EFI_PCI_COMMAND_MEMORY_SPACE) != 0) {
852 Attributes |= EFI_PCI_IO_ATTRIBUTE_MEMORY;
855 if ((Command & EFI_PCI_COMMAND_BUS_MASTER) != 0) {
856 Attributes |= EFI_PCI_IO_ATTRIBUTE_BUS_MASTER;
859 if ((Command & EFI_PCI_COMMAND_VGA_PALETTE_SNOOP) != 0) {
860 Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO;
863 if ((BridgeControl & EFI_PCI_BRIDGE_CONTROL_ISA) != 0) {
864 Attributes |= EFI_PCI_IO_ATTRIBUTE_ISA_IO;
867 if ((BridgeControl & EFI_PCI_BRIDGE_CONTROL_VGA) != 0) {
868 Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_IO;
869 Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY;
870 Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO;
873 if ((BridgeControl & EFI_PCI_BRIDGE_CONTROL_VGA_16) != 0) {
874 Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_IO_16;
875 Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO_16;
878 if (Option == EFI_SET_SUPPORTS) {
880 Attributes |= EFI_PCI_IO_ATTRIBUTE_MEMORY_WRITE_COMBINE |
881 EFI_PCI_IO_ATTRIBUTE_MEMORY_CACHED |
882 EFI_PCI_IO_ATTRIBUTE_MEMORY_DISABLE |
883 EFI_PCI_IO_ATTRIBUTE_EMBEDDED_DEVICE |
884 EFI_PCI_IO_ATTRIBUTE_EMBEDDED_ROM |
885 EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE;
887 if ((Attributes & EFI_PCI_IO_ATTRIBUTE_IO) != 0) {
888 Attributes |= EFI_PCI_IO_ATTRIBUTE_ISA_MOTHERBOARD_IO;
889 Attributes |= EFI_PCI_IO_ATTRIBUTE_ISA_IO;
892 if (IS_PCI_BRIDGE (&PciIoDevice->Pci) || IS_CARDBUS_BRIDGE (&PciIoDevice->Pci)) {
894 // For bridge, it should support IDE attributes
896 Attributes |= EFI_PCI_IO_ATTRIBUTE_IDE_SECONDARY_IO;
897 Attributes |= EFI_PCI_IO_ATTRIBUTE_IDE_PRIMARY_IO;
898 } else {
900 if (IS_PCI_IDE (&PciIoDevice->Pci)) {
901 Attributes |= EFI_PCI_IO_ATTRIBUTE_IDE_SECONDARY_IO;
902 Attributes |= EFI_PCI_IO_ATTRIBUTE_IDE_PRIMARY_IO;
905 if (IS_PCI_VGA (&PciIoDevice->Pci)) {
906 Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY;
907 Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_IO;
911 PciIoDevice->Supports = Attributes;
912 PciIoDevice->Supports &= ( (PciIoDevice->Parent->Supports) | \
913 EFI_PCI_IO_ATTRIBUTE_IO | EFI_PCI_IO_ATTRIBUTE_MEMORY | \
914 EFI_PCI_IO_ATTRIBUTE_BUS_MASTER );
916 } else {
917 PciIoDevice->Attributes = Attributes;
922 Determine if the device can support Fast Back to Back attribute.
924 @param PciIoDevice Pci device instance.
925 @param StatusIndex Status register value.
927 @retval EFI_SUCCESS This device support Fast Back to Back attribute.
928 @retval EFI_UNSUPPORTED This device doesn't support Fast Back to Back attribute.
931 EFI_STATUS
932 GetFastBackToBackSupport (
933 IN PCI_IO_DEVICE *PciIoDevice,
934 IN UINT8 StatusIndex
937 EFI_PCI_IO_PROTOCOL *PciIo;
938 EFI_STATUS Status;
939 UINT32 StatusRegister;
942 // Read the status register
944 PciIo = &PciIoDevice->PciIo;
945 Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint16, StatusIndex, 1, &StatusRegister);
946 if (EFI_ERROR (Status)) {
947 return EFI_UNSUPPORTED;
951 // Check the Fast B2B bit
953 if ((StatusRegister & EFI_PCI_FAST_BACK_TO_BACK_CAPABLE) != 0) {
954 return EFI_SUCCESS;
955 } else {
956 return EFI_UNSUPPORTED;
961 Process the option ROM for all the children of the specified parent PCI device.
962 It can only be used after the first full Option ROM process.
964 @param PciIoDevice Pci device instance.
967 VOID
968 ProcessOptionRomLight (
969 IN PCI_IO_DEVICE *PciIoDevice
972 PCI_IO_DEVICE *Temp;
973 LIST_ENTRY *CurrentLink;
976 // For RootBridge, PPB , P2C, go recursively to traverse all its children
978 CurrentLink = PciIoDevice->ChildList.ForwardLink;
979 while (CurrentLink != NULL && CurrentLink != &PciIoDevice->ChildList) {
981 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
983 if (!IsListEmpty (&Temp->ChildList)) {
984 ProcessOptionRomLight (Temp);
987 PciRomGetImageMapping (Temp);
990 // The OpRom has already been processed in the first round
992 Temp->AllOpRomProcessed = TRUE;
994 CurrentLink = CurrentLink->ForwardLink;
999 Determine the related attributes of all devices under a Root Bridge.
1001 @param PciIoDevice PCI device instance.
1004 EFI_STATUS
1005 DetermineDeviceAttribute (
1006 IN PCI_IO_DEVICE *PciIoDevice
1009 UINT16 Command;
1010 UINT16 BridgeControl;
1011 UINT16 OldCommand;
1012 UINT16 OldBridgeControl;
1013 BOOLEAN FastB2BSupport;
1014 PCI_IO_DEVICE *Temp;
1015 LIST_ENTRY *CurrentLink;
1016 EFI_STATUS Status;
1019 // For Root Bridge, just copy it by RootBridgeIo proctocol
1020 // so as to keep consistent with the actual attribute
1022 if (PciIoDevice->Parent == NULL) {
1023 Status = PciIoDevice->PciRootBridgeIo->GetAttributes (
1024 PciIoDevice->PciRootBridgeIo,
1025 &PciIoDevice->Supports,
1026 &PciIoDevice->Attributes
1028 if (EFI_ERROR (Status)) {
1029 return Status;
1031 } else {
1034 // Set the attributes to be checked for common PCI devices and PPB or P2C
1035 // Since some devices only support part of them, it is better to set the
1036 // attribute according to its command or bridge control register
1038 Command = EFI_PCI_COMMAND_IO_SPACE |
1039 EFI_PCI_COMMAND_MEMORY_SPACE |
1040 EFI_PCI_COMMAND_BUS_MASTER |
1041 EFI_PCI_COMMAND_VGA_PALETTE_SNOOP;
1043 BridgeControl = EFI_PCI_BRIDGE_CONTROL_ISA | EFI_PCI_BRIDGE_CONTROL_VGA | EFI_PCI_BRIDGE_CONTROL_VGA_16;
1046 // Test whether the device can support attributes above
1048 PciTestSupportedAttribute (PciIoDevice, &Command, &BridgeControl, &OldCommand, &OldBridgeControl);
1051 // Set the supported attributes for specified PCI device
1053 PciSetDeviceAttribute (PciIoDevice, Command, BridgeControl, EFI_SET_SUPPORTS);
1056 // Set the current attributes for specified PCI device
1058 PciSetDeviceAttribute (PciIoDevice, OldCommand, OldBridgeControl, EFI_SET_ATTRIBUTES);
1061 // Enable other supported attributes but not defined in PCI_IO_PROTOCOL
1063 PCI_ENABLE_COMMAND_REGISTER (PciIoDevice, EFI_PCI_COMMAND_MEMORY_WRITE_AND_INVALIDATE);
1066 FastB2BSupport = TRUE;
1069 // P2C can not support FB2B on the secondary side
1071 if (IS_CARDBUS_BRIDGE (&PciIoDevice->Pci)) {
1072 FastB2BSupport = FALSE;
1076 // For RootBridge, PPB , P2C, go recursively to traverse all its children
1078 CurrentLink = PciIoDevice->ChildList.ForwardLink;
1079 while (CurrentLink != NULL && CurrentLink != &PciIoDevice->ChildList) {
1081 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
1082 Status = DetermineDeviceAttribute (Temp);
1083 if (EFI_ERROR (Status)) {
1084 return Status;
1087 // Detect Fast Bact to Bact support for the device under the bridge
1089 Status = GetFastBackToBackSupport (Temp, PCI_PRIMARY_STATUS_OFFSET);
1090 if (FastB2BSupport && EFI_ERROR (Status)) {
1091 FastB2BSupport = FALSE;
1094 CurrentLink = CurrentLink->ForwardLink;
1097 // Set or clear Fast Back to Back bit for the whole bridge
1099 if (!IsListEmpty (&PciIoDevice->ChildList)) {
1101 if (IS_PCI_BRIDGE (&PciIoDevice->Pci)) {
1103 Status = GetFastBackToBackSupport (PciIoDevice, PCI_BRIDGE_STATUS_REGISTER_OFFSET);
1105 if (EFI_ERROR (Status) || (!FastB2BSupport)) {
1106 FastB2BSupport = FALSE;
1107 PCI_DISABLE_BRIDGE_CONTROL_REGISTER (PciIoDevice, EFI_PCI_BRIDGE_CONTROL_FAST_BACK_TO_BACK);
1108 } else {
1109 PCI_ENABLE_BRIDGE_CONTROL_REGISTER (PciIoDevice, EFI_PCI_BRIDGE_CONTROL_FAST_BACK_TO_BACK);
1113 CurrentLink = PciIoDevice->ChildList.ForwardLink;
1114 while (CurrentLink != NULL && CurrentLink != &PciIoDevice->ChildList) {
1115 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
1116 if (FastB2BSupport) {
1117 PCI_ENABLE_COMMAND_REGISTER (Temp, EFI_PCI_COMMAND_FAST_BACK_TO_BACK);
1118 } else {
1119 PCI_DISABLE_COMMAND_REGISTER (Temp, EFI_PCI_COMMAND_FAST_BACK_TO_BACK);
1122 CurrentLink = CurrentLink->ForwardLink;
1126 // End for IsListEmpty
1128 return EFI_SUCCESS;
1132 This routine is used to update the bar information for those incompatible PCI device.
1134 @param PciIoDevice Input Pci device instance. Output Pci device instance with updated
1135 Bar information.
1137 @retval EFI_SUCCESS Successfully updated bar information.
1138 @retval EFI_UNSUPPORTED Given PCI device doesn't belong to incompatible PCI device list.
1141 EFI_STATUS
1142 UpdatePciInfo (
1143 IN OUT PCI_IO_DEVICE *PciIoDevice
1146 EFI_STATUS Status;
1147 UINTN BarIndex;
1148 UINTN BarEndIndex;
1149 BOOLEAN SetFlag;
1150 VOID *Configuration;
1151 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Ptr;
1153 Configuration = NULL;
1154 Status = EFI_SUCCESS;
1156 if (gEfiIncompatiblePciDeviceSupport == NULL) {
1158 // It can only be supported after the Incompatible PCI Device
1159 // Support Protocol has been installed
1161 Status = gBS->LocateProtocol (
1162 &gEfiIncompatiblePciDeviceSupportProtocolGuid,
1163 NULL,
1164 (VOID **) &gEfiIncompatiblePciDeviceSupport
1167 if (Status == EFI_SUCCESS) {
1169 // Check whether the device belongs to incompatible devices from protocol or not
1170 // If it is , then get its special requirement in the ACPI table
1172 Status = gEfiIncompatiblePciDeviceSupport->CheckDevice (
1173 gEfiIncompatiblePciDeviceSupport,
1174 PciIoDevice->Pci.Hdr.VendorId,
1175 PciIoDevice->Pci.Hdr.DeviceId,
1176 PciIoDevice->Pci.Hdr.RevisionID,
1177 PciIoDevice->Pci.Device.SubsystemVendorID,
1178 PciIoDevice->Pci.Device.SubsystemID,
1179 &Configuration
1184 if (EFI_ERROR (Status) || Configuration == NULL ) {
1185 return EFI_UNSUPPORTED;
1189 // Update PCI device information from the ACPI table
1191 Ptr = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Configuration;
1193 while (Ptr->Desc != ACPI_END_TAG_DESCRIPTOR) {
1195 if (Ptr->Desc != ACPI_ADDRESS_SPACE_DESCRIPTOR) {
1197 // The format is not support
1199 break;
1202 BarIndex = (UINTN) Ptr->AddrTranslationOffset;
1203 BarEndIndex = BarIndex;
1206 // Update all the bars in the device
1208 if (BarIndex == PCI_BAR_ALL) {
1209 BarIndex = 0;
1210 BarEndIndex = PCI_MAX_BAR - 1;
1213 if (BarIndex > PCI_MAX_BAR) {
1214 Ptr++;
1215 continue;
1218 for (; BarIndex <= BarEndIndex; BarIndex++) {
1219 SetFlag = FALSE;
1220 switch (Ptr->ResType) {
1221 case ACPI_ADDRESS_SPACE_TYPE_MEM:
1224 // Make sure the bar is memory type
1226 if (CheckBarType (PciIoDevice, (UINT8) BarIndex, PciBarTypeMem)) {
1227 SetFlag = TRUE;
1229 break;
1231 case ACPI_ADDRESS_SPACE_TYPE_IO:
1234 // Make sure the bar is IO type
1236 if (CheckBarType (PciIoDevice, (UINT8) BarIndex, PciBarTypeIo)) {
1237 SetFlag = TRUE;
1239 break;
1242 if (SetFlag) {
1245 // Update the new alignment for the device
1247 SetNewAlign (&(PciIoDevice->PciBar[BarIndex].Alignment), Ptr->AddrRangeMax);
1250 // Update the new length for the device
1252 if (Ptr->AddrLen != PCI_BAR_NOCHANGE) {
1253 PciIoDevice->PciBar[BarIndex].Length = Ptr->AddrLen;
1258 Ptr++;
1261 FreePool (Configuration);
1263 return EFI_SUCCESS;
1267 This routine will update the alignment with the new alignment.
1269 @param Alignment Input Old alignment. Output updated alignment.
1270 @param NewAlignment New alignment.
1273 VOID
1274 SetNewAlign (
1275 IN OUT UINT64 *Alignment,
1276 IN UINT64 NewAlignment
1279 UINT64 OldAlignment;
1280 UINTN ShiftBit;
1283 // The new alignment is the same as the original,
1284 // so skip it
1286 if (NewAlignment == PCI_BAR_OLD_ALIGN) {
1287 return ;
1290 // Check the validity of the parameter
1292 if (NewAlignment != PCI_BAR_EVEN_ALIGN &&
1293 NewAlignment != PCI_BAR_SQUAD_ALIGN &&
1294 NewAlignment != PCI_BAR_DQUAD_ALIGN ) {
1295 *Alignment = NewAlignment;
1296 return ;
1299 OldAlignment = (*Alignment) + 1;
1300 ShiftBit = 0;
1303 // Get the first non-zero hex value of the length
1305 while ((OldAlignment & 0x0F) == 0x00) {
1306 OldAlignment = RShiftU64 (OldAlignment, 4);
1307 ShiftBit += 4;
1311 // Adjust the alignment to even, quad or double quad boundary
1313 if (NewAlignment == PCI_BAR_EVEN_ALIGN) {
1314 if ((OldAlignment & 0x01) != 0) {
1315 OldAlignment = OldAlignment + 2 - (OldAlignment & 0x01);
1317 } else if (NewAlignment == PCI_BAR_SQUAD_ALIGN) {
1318 if ((OldAlignment & 0x03) != 0) {
1319 OldAlignment = OldAlignment + 4 - (OldAlignment & 0x03);
1321 } else if (NewAlignment == PCI_BAR_DQUAD_ALIGN) {
1322 if ((OldAlignment & 0x07) != 0) {
1323 OldAlignment = OldAlignment + 8 - (OldAlignment & 0x07);
1328 // Update the old value
1330 NewAlignment = LShiftU64 (OldAlignment, ShiftBit) - 1;
1331 *Alignment = NewAlignment;
1333 return ;
1337 Parse PCI IOV VF bar information and fill them into PCI device instance.
1339 @param PciIoDevice Pci device instance.
1340 @param Offset Bar offset.
1341 @param BarIndex Bar index.
1343 @return Next bar offset.
1346 UINTN
1347 PciIovParseVfBar (
1348 IN PCI_IO_DEVICE *PciIoDevice,
1349 IN UINTN Offset,
1350 IN UINTN BarIndex
1353 UINT32 Value;
1354 UINT64 BarValue64;
1355 UINT32 OriginalValue;
1356 UINT32 Mask;
1357 UINT32 Data;
1358 UINT8 Index;
1359 EFI_STATUS Status;
1362 // Ensure it is called properly
1364 ASSERT (PciIoDevice->SrIovCapabilityOffset != 0);
1365 if (PciIoDevice->SrIovCapabilityOffset == 0) {
1366 return 0;
1369 OriginalValue = 0;
1370 Value = 0;
1371 BarValue64 = 0;
1373 Status = VfBarExisted (
1374 PciIoDevice,
1375 Offset,
1376 &Value,
1377 &OriginalValue
1380 if (EFI_ERROR (Status)) {
1381 PciIoDevice->VfPciBar[BarIndex].BaseAddress = 0;
1382 PciIoDevice->VfPciBar[BarIndex].Length = 0;
1383 PciIoDevice->VfPciBar[BarIndex].Alignment = 0;
1386 // Scan all the BARs anyway
1388 PciIoDevice->VfPciBar[BarIndex].Offset = (UINT8) Offset;
1389 return Offset + 4;
1392 PciIoDevice->VfPciBar[BarIndex].Offset = (UINT8) Offset;
1393 if (Value & 0x01) {
1395 // Device I/Os. Impossible
1397 ASSERT (FALSE);
1398 return Offset + 4;
1400 } else {
1402 Mask = 0xfffffff0;
1404 PciIoDevice->VfPciBar[BarIndex].BaseAddress = OriginalValue & Mask;
1406 switch (Value & 0x07) {
1409 //memory space; anywhere in 32 bit address space
1411 case 0x00:
1412 if (Value & 0x08) {
1413 PciIoDevice->VfPciBar[BarIndex].BarType = PciBarTypePMem32;
1414 } else {
1415 PciIoDevice->VfPciBar[BarIndex].BarType = PciBarTypeMem32;
1418 PciIoDevice->VfPciBar[BarIndex].Length = (~(Value & Mask)) + 1;
1419 PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->VfPciBar[BarIndex].Length - 1;
1422 // Adjust Length
1424 PciIoDevice->VfPciBar[BarIndex].Length = MultU64x32 (PciIoDevice->VfPciBar[BarIndex].Length, PciIoDevice->InitialVFs);
1426 // Adjust Alignment
1428 if (PciIoDevice->VfPciBar[BarIndex].Alignment < PciIoDevice->SystemPageSize - 1) {
1429 PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->SystemPageSize - 1;
1432 break;
1435 // memory space; anywhere in 64 bit address space
1437 case 0x04:
1438 if (Value & 0x08) {
1439 PciIoDevice->VfPciBar[BarIndex].BarType = PciBarTypePMem64;
1440 } else {
1441 PciIoDevice->VfPciBar[BarIndex].BarType = PciBarTypeMem64;
1445 // According to PCI 2.2,if the bar indicates a memory 64 decoding, next bar
1446 // is regarded as an extension for the first bar. As a result
1447 // the sizing will be conducted on combined 64 bit value
1448 // Here just store the masked first 32bit value for future size
1449 // calculation
1451 PciIoDevice->VfPciBar[BarIndex].Length = Value & Mask;
1452 PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->VfPciBar[BarIndex].Length - 1;
1454 if (PciIoDevice->VfPciBar[BarIndex].Alignment < PciIoDevice->SystemPageSize - 1) {
1455 PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->SystemPageSize - 1;
1459 // Increment the offset to point to next DWORD
1461 Offset += 4;
1463 Status = VfBarExisted (
1464 PciIoDevice,
1465 Offset,
1466 &Value,
1467 &OriginalValue
1470 if (EFI_ERROR (Status)) {
1471 return Offset + 4;
1475 // Fix the length to support some spefic 64 bit BAR
1477 Data = Value;
1478 Index = 0;
1479 for (Data = Value; Data != 0; Data >>= 1) {
1480 Index ++;
1482 Value |= ((UINT32)(-1) << Index);
1485 // Calculate the size of 64bit bar
1487 PciIoDevice->VfPciBar[BarIndex].BaseAddress |= LShiftU64 ((UINT64) OriginalValue, 32);
1489 PciIoDevice->VfPciBar[BarIndex].Length = PciIoDevice->VfPciBar[BarIndex].Length | LShiftU64 ((UINT64) Value, 32);
1490 PciIoDevice->VfPciBar[BarIndex].Length = (~(PciIoDevice->VfPciBar[BarIndex].Length)) + 1;
1491 PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->VfPciBar[BarIndex].Length - 1;
1494 // Adjust Length
1496 PciIoDevice->VfPciBar[BarIndex].Length = MultU64x32 (PciIoDevice->VfPciBar[BarIndex].Length, PciIoDevice->InitialVFs);
1498 // Adjust Alignment
1500 if (PciIoDevice->VfPciBar[BarIndex].Alignment < PciIoDevice->SystemPageSize - 1) {
1501 PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->SystemPageSize - 1;
1504 break;
1507 // reserved
1509 default:
1510 PciIoDevice->VfPciBar[BarIndex].BarType = PciBarTypeUnknown;
1511 PciIoDevice->VfPciBar[BarIndex].Length = (~(Value & Mask)) + 1;
1512 PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->VfPciBar[BarIndex].Length - 1;
1514 if (PciIoDevice->VfPciBar[BarIndex].Alignment < PciIoDevice->SystemPageSize - 1) {
1515 PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->SystemPageSize - 1;
1518 break;
1523 // Check the length again so as to keep compatible with some special bars
1525 if (PciIoDevice->VfPciBar[BarIndex].Length == 0) {
1526 PciIoDevice->VfPciBar[BarIndex].BarType = PciBarTypeUnknown;
1527 PciIoDevice->VfPciBar[BarIndex].BaseAddress = 0;
1528 PciIoDevice->VfPciBar[BarIndex].Alignment = 0;
1532 // Increment number of bar
1534 return Offset + 4;
1538 Parse PCI bar information and fill them into PCI device instance.
1540 @param PciIoDevice Pci device instance.
1541 @param Offset Bar offset.
1542 @param BarIndex Bar index.
1544 @return Next bar offset.
1547 UINTN
1548 PciParseBar (
1549 IN PCI_IO_DEVICE *PciIoDevice,
1550 IN UINTN Offset,
1551 IN UINTN BarIndex
1554 UINT32 Value;
1555 UINT32 OriginalValue;
1556 UINT32 Mask;
1557 UINT32 Data;
1558 UINT8 Index;
1559 EFI_STATUS Status;
1561 OriginalValue = 0;
1562 Value = 0;
1564 Status = BarExisted (
1565 PciIoDevice,
1566 Offset,
1567 &Value,
1568 &OriginalValue
1571 if (EFI_ERROR (Status)) {
1572 PciIoDevice->PciBar[BarIndex].BaseAddress = 0;
1573 PciIoDevice->PciBar[BarIndex].Length = 0;
1574 PciIoDevice->PciBar[BarIndex].Alignment = 0;
1577 // Some devices don't fully comply to PCI spec 2.2. So be to scan all the BARs anyway
1579 PciIoDevice->PciBar[BarIndex].Offset = (UINT8) Offset;
1580 return Offset + 4;
1583 PciIoDevice->PciBar[BarIndex].Offset = (UINT8) Offset;
1584 if ((Value & 0x01) != 0) {
1586 // Device I/Os
1588 Mask = 0xfffffffc;
1590 if ((Value & 0xFFFF0000) != 0) {
1592 // It is a IO32 bar
1594 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeIo32;
1595 PciIoDevice->PciBar[BarIndex].Length = ((~(Value & Mask)) + 1);
1596 PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;
1598 } else {
1600 // It is a IO16 bar
1602 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeIo16;
1603 PciIoDevice->PciBar[BarIndex].Length = 0x0000FFFF & ((~(Value & Mask)) + 1);
1604 PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;
1608 // Workaround. Some platforms inplement IO bar with 0 length
1609 // Need to treat it as no-bar
1611 if (PciIoDevice->PciBar[BarIndex].Length == 0) {
1612 PciIoDevice->PciBar[BarIndex].BarType = (PCI_BAR_TYPE) 0;
1615 PciIoDevice->PciBar[BarIndex].Prefetchable = FALSE;
1616 PciIoDevice->PciBar[BarIndex].BaseAddress = OriginalValue & Mask;
1618 } else {
1620 Mask = 0xfffffff0;
1622 PciIoDevice->PciBar[BarIndex].BaseAddress = OriginalValue & Mask;
1624 switch (Value & 0x07) {
1627 //memory space; anywhere in 32 bit address space
1629 case 0x00:
1630 if ((Value & 0x08) != 0) {
1631 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypePMem32;
1632 } else {
1633 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeMem32;
1636 PciIoDevice->PciBar[BarIndex].Length = (~(Value & Mask)) + 1;
1637 if (PciIoDevice->PciBar[BarIndex].Length < (SIZE_4KB)) {
1639 // Force minimum 4KByte alignment for Virtualization technology for Directed I/O
1641 PciIoDevice->PciBar[BarIndex].Alignment = (SIZE_4KB - 1);
1642 } else {
1643 PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;
1645 break;
1648 // memory space; anywhere in 64 bit address space
1650 case 0x04:
1651 if ((Value & 0x08) != 0) {
1652 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypePMem64;
1653 } else {
1654 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeMem64;
1658 // According to PCI 2.2,if the bar indicates a memory 64 decoding, next bar
1659 // is regarded as an extension for the first bar. As a result
1660 // the sizing will be conducted on combined 64 bit value
1661 // Here just store the masked first 32bit value for future size
1662 // calculation
1664 PciIoDevice->PciBar[BarIndex].Length = Value & Mask;
1665 PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;
1668 // Increment the offset to point to next DWORD
1670 Offset += 4;
1672 Status = BarExisted (
1673 PciIoDevice,
1674 Offset,
1675 &Value,
1676 &OriginalValue
1679 if (EFI_ERROR (Status)) {
1681 // the high 32 bit does not claim any BAR, we need to re-check the low 32 bit BAR again
1683 if (PciIoDevice->PciBar[BarIndex].Length == 0) {
1685 // some device implement MMIO bar with 0 length, need to treat it as no-bar
1687 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeUnknown;
1689 return Offset + 4;
1693 // Fix the length to support some spefic 64 bit BAR
1695 Data = Value;
1696 Index = 0;
1697 for (Data = Value; Data != 0; Data >>= 1) {
1698 Index ++;
1700 Value |= ((UINT32)(-1) << Index);
1703 // Calculate the size of 64bit bar
1705 PciIoDevice->PciBar[BarIndex].BaseAddress |= LShiftU64 ((UINT64) OriginalValue, 32);
1707 PciIoDevice->PciBar[BarIndex].Length = PciIoDevice->PciBar[BarIndex].Length | LShiftU64 ((UINT64) Value, 32);
1708 PciIoDevice->PciBar[BarIndex].Length = (~(PciIoDevice->PciBar[BarIndex].Length)) + 1;
1709 if (PciIoDevice->PciBar[BarIndex].Length < (SIZE_4KB)) {
1711 // Force minimum 4KByte alignment for Virtualization technology for Directed I/O
1713 PciIoDevice->PciBar[BarIndex].Alignment = (SIZE_4KB - 1);
1714 } else {
1715 PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;
1718 break;
1721 // reserved
1723 default:
1724 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeUnknown;
1725 PciIoDevice->PciBar[BarIndex].Length = (~(Value & Mask)) + 1;
1726 if (PciIoDevice->PciBar[BarIndex].Length < (SIZE_4KB)) {
1728 // Force minimum 4KByte alignment for Virtualization technology for Directed I/O
1730 PciIoDevice->PciBar[BarIndex].Alignment = (SIZE_4KB - 1);
1731 } else {
1732 PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;
1734 break;
1739 // Check the length again so as to keep compatible with some special bars
1741 if (PciIoDevice->PciBar[BarIndex].Length == 0) {
1742 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeUnknown;
1743 PciIoDevice->PciBar[BarIndex].BaseAddress = 0;
1744 PciIoDevice->PciBar[BarIndex].Alignment = 0;
1748 // Increment number of bar
1750 return Offset + 4;
1754 This routine is used to initialize the bar of a PCI device.
1756 @param PciIoDevice Pci device instance.
1758 @note It can be called typically when a device is going to be rejected.
1761 VOID
1762 InitializePciDevice (
1763 IN PCI_IO_DEVICE *PciIoDevice
1766 EFI_PCI_IO_PROTOCOL *PciIo;
1767 UINT8 Offset;
1769 PciIo = &(PciIoDevice->PciIo);
1772 // Put all the resource apertures
1773 // Resource base is set to all ones so as to indicate its resource
1774 // has not been alloacted
1776 for (Offset = 0x10; Offset <= 0x24; Offset += sizeof (UINT32)) {
1777 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, Offset, 1, &gAllOne);
1782 This routine is used to initialize the bar of a PCI-PCI Bridge device.
1784 @param PciIoDevice PCI-PCI bridge device instance.
1787 VOID
1788 InitializePpb (
1789 IN PCI_IO_DEVICE *PciIoDevice
1792 EFI_PCI_IO_PROTOCOL *PciIo;
1794 PciIo = &(PciIoDevice->PciIo);
1797 // Put all the resource apertures including IO16
1798 // Io32, pMem32, pMem64 to quiescent state
1799 // Resource base all ones, Resource limit all zeros
1801 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x1C, 1, &gAllOne);
1802 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x1D, 1, &gAllZero);
1804 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x20, 1, &gAllOne);
1805 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x22, 1, &gAllZero);
1807 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x24, 1, &gAllOne);
1808 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x26, 1, &gAllZero);
1810 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x28, 1, &gAllOne);
1811 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x2C, 1, &gAllZero);
1814 // Don't support use io32 as for now
1816 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x30, 1, &gAllOne);
1817 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x32, 1, &gAllZero);
1820 // Force Interrupt line to zero for cards that come up randomly
1822 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x3C, 1, &gAllZero);
1826 This routine is used to initialize the bar of a PCI Card Bridge device.
1828 @param PciIoDevice PCI Card bridge device.
1831 VOID
1832 InitializeP2C (
1833 IN PCI_IO_DEVICE *PciIoDevice
1836 EFI_PCI_IO_PROTOCOL *PciIo;
1838 PciIo = &(PciIoDevice->PciIo);
1841 // Put all the resource apertures including IO16
1842 // Io32, pMem32, pMem64 to quiescent state(
1843 // Resource base all ones, Resource limit all zeros
1845 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x1c, 1, &gAllOne);
1846 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x20, 1, &gAllZero);
1848 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x24, 1, &gAllOne);
1849 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x28, 1, &gAllZero);
1851 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x2c, 1, &gAllOne);
1852 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x30, 1, &gAllZero);
1854 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x34, 1, &gAllOne);
1855 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x38, 1, &gAllZero);
1858 // Force Interrupt line to zero for cards that come up randomly
1860 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x3C, 1, &gAllZero);
1864 Create and initiliaze general PCI I/O device instance for
1865 PCI device/bridge device/hotplug bridge device.
1867 @param PciRootBridgeIo Pointer to instance of EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
1868 @param Pci Input Pci information block.
1869 @param Bus Device Bus NO.
1870 @param Device Device device NO.
1871 @param Func Device func NO.
1873 @return Instance of PCI device. NULL means no instance created.
1876 PCI_IO_DEVICE *
1877 CreatePciIoDevice (
1878 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo,
1879 IN PCI_TYPE00 *Pci,
1880 IN UINT8 Bus,
1881 IN UINT8 Device,
1882 IN UINT8 Func
1885 PCI_IO_DEVICE *PciIoDevice;
1886 EFI_PCI_IO_PROTOCOL *PciIo;
1887 EFI_STATUS Status;
1889 PciIoDevice = AllocateZeroPool (sizeof (PCI_IO_DEVICE));
1890 if (PciIoDevice == NULL) {
1891 return NULL;
1894 PciIoDevice->Signature = PCI_IO_DEVICE_SIGNATURE;
1895 PciIoDevice->Handle = NULL;
1896 PciIoDevice->PciRootBridgeIo = PciRootBridgeIo;
1897 PciIoDevice->DevicePath = NULL;
1898 PciIoDevice->BusNumber = Bus;
1899 PciIoDevice->DeviceNumber = Device;
1900 PciIoDevice->FunctionNumber = Func;
1901 PciIoDevice->Decodes = 0;
1903 if (gFullEnumeration) {
1904 PciIoDevice->Allocated = FALSE;
1905 } else {
1906 PciIoDevice->Allocated = TRUE;
1909 PciIoDevice->Registered = FALSE;
1910 PciIoDevice->Attributes = 0;
1911 PciIoDevice->Supports = 0;
1912 PciIoDevice->BusOverride = FALSE;
1913 PciIoDevice->AllOpRomProcessed = FALSE;
1915 PciIoDevice->IsPciExp = FALSE;
1917 CopyMem (&(PciIoDevice->Pci), Pci, sizeof (PCI_TYPE01));
1920 // Initialize the PCI I/O instance structure
1922 InitializePciIoInstance (PciIoDevice);
1923 InitializePciDriverOverrideInstance (PciIoDevice);
1924 InitializePciLoadFile2 (PciIoDevice);
1925 PciIo = &PciIoDevice->PciIo;
1928 // Detect if PCI Express Device
1930 PciIoDevice->PciExpressCapabilityOffset = 0;
1931 Status = LocateCapabilityRegBlock (
1932 PciIoDevice,
1933 EFI_PCI_CAPABILITY_ID_PCIEXP,
1934 &PciIoDevice->PciExpressCapabilityOffset,
1935 NULL
1937 if (!EFI_ERROR (Status)) {
1938 PciIoDevice->IsPciExp = TRUE;
1942 // Initialize for PCI IOV
1946 // Check ARI for function 0 only
1948 Status = LocatePciExpressCapabilityRegBlock (
1949 PciIoDevice,
1950 EFI_PCIE_CAPABILITY_ID_ARI,
1951 &PciIoDevice->AriCapabilityOffset,
1952 NULL
1954 if (!EFI_ERROR (Status)) {
1955 DEBUG ((
1956 EFI_D_INFO,
1957 "PCI-IOV B%x.D%x.F%x - ARI Cap offset - 0x%x\n",
1958 (UINTN)Bus,
1959 (UINTN)Device,
1960 (UINTN)Func,
1961 (UINTN)PciIoDevice->AriCapabilityOffset
1965 Status = LocatePciExpressCapabilityRegBlock (
1966 PciIoDevice,
1967 EFI_PCIE_CAPABILITY_ID_SRIOV,
1968 &PciIoDevice->SrIovCapabilityOffset,
1969 NULL
1971 if (!EFI_ERROR (Status)) {
1972 DEBUG ((
1973 EFI_D_INFO,
1974 "PCI-IOV B%x.D%x.F%x - SRIOV Cap offset - 0x%x\n",
1975 (UINTN)Bus,
1976 (UINTN)Device,
1977 (UINTN)Func,
1978 (UINTN)PciIoDevice->SrIovCapabilityOffset
1982 Status = LocatePciExpressCapabilityRegBlock (
1983 PciIoDevice,
1984 EFI_PCIE_CAPABILITY_ID_MRIOV,
1985 &PciIoDevice->MrIovCapabilityOffset,
1986 NULL
1988 if (!EFI_ERROR (Status)) {
1989 DEBUG ((
1990 EFI_D_INFO,
1991 "PCI-IOV B%x.D%x.F%x - MRIOV Cap offset - 0x%x\n",
1992 (UINTN)Bus,
1993 (UINTN)Device,
1994 (UINTN)Func,
1995 (UINTN)PciIoDevice->MrIovCapabilityOffset
2000 // Calculate SystemPageSize
2002 if ((PciIoDevice->SrIovCapabilityOffset != 0) && ((FeaturePcdGet(PcdSrIovSupport)& EFI_PCI_IOV_POLICY_SRIOV) != 0)) {
2004 PciIo->Pci.Read (
2005 PciIo,
2006 EfiPciIoWidthUint32,
2007 PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_SUPPORTED_PAGE_SIZE,
2009 &PciIoDevice->SystemPageSize
2011 DEBUG ((EFI_D_INFO, "PCI-IOV B%x.D%x.F%x - SupportedPageSize - 0x%x\n", (UINTN)Bus, (UINTN)Device, (UINTN)Func, PciIoDevice->SystemPageSize));
2013 PciIoDevice->SystemPageSize = (PcdGet32(PcdSrIovSystemPageSize) & PciIoDevice->SystemPageSize);
2014 ASSERT (PciIoDevice->SystemPageSize != 0);
2016 PciIo->Pci.Write (
2017 PciIo,
2018 EfiPciIoWidthUint32,
2019 PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_SYSTEM_PAGE_SIZE,
2021 &PciIoDevice->SystemPageSize
2023 DEBUG ((EFI_D_INFO, "PCI-IOV B%x.D%x.F%x - SystemPageSize - 0x%x\n", (UINTN)Bus, (UINTN)Device, (UINTN)Func, PciIoDevice->SystemPageSize));
2025 // Adjust SystemPageSize for Alignment usage later
2027 PciIoDevice->SystemPageSize <<= 12;
2030 // Calculate BusReservation for PCI IOV
2032 if ((PciIoDevice->SrIovCapabilityOffset != 0) && ((FeaturePcdGet(PcdSrIovSupport)& EFI_PCI_IOV_POLICY_SRIOV) != 0)) {
2033 UINT16 VFStride;
2034 UINT16 FirstVFOffset;
2035 UINT32 PFRID;
2036 UINT32 LastVF;
2039 // Read First FirstVFOffset, InitialVFs, and VFStride
2041 PciIo->Pci.Read (
2042 PciIo,
2043 EfiPciIoWidthUint16,
2044 PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_FIRSTVF,
2046 &FirstVFOffset
2048 DEBUG ((EFI_D_INFO, "PCI-IOV B%x.D%x.F%x - FirstVFOffset - 0x%x\n", (UINTN)Bus, (UINTN)Device, (UINTN)Func, (UINTN)FirstVFOffset));
2050 PciIo->Pci.Read (
2051 PciIo,
2052 EfiPciIoWidthUint16,
2053 PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_INITIALVFS,
2055 &PciIoDevice->InitialVFs
2057 DEBUG ((EFI_D_INFO, "PCI-IOV B%x.D%x.F%x - InitialVFs - 0x%x\n", (UINTN)Bus, (UINTN)Device, (UINTN)Func, (UINTN)PciIoDevice->InitialVFs));
2059 PciIo->Pci.Read (
2060 PciIo,
2061 EfiPciIoWidthUint16,
2062 PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_VFSTRIDE,
2064 &VFStride
2066 DEBUG ((EFI_D_INFO, "PCI-IOV B%x.D%x.F%x - VFStride - 0x%x\n", (UINTN)Bus, (UINTN)Device, (UINTN)Func, (UINTN)VFStride));
2069 // Calculate LastVF
2071 PFRID = EFI_PCI_RID(Bus, Device, Func);
2072 LastVF = PFRID + FirstVFOffset + (PciIoDevice->InitialVFs - 1) * VFStride;
2075 // Calculate ReservedBusNum for this PF
2077 PciIoDevice->ReservedBusNum = (UINT16)(EFI_PCI_BUS_OF_RID (LastVF) - Bus + 1);
2078 DEBUG ((EFI_D_INFO, "PCI-IOV B%x.D%x.F%x - reserved bus number - 0x%x\n", (UINTN)Bus, (UINTN)Device, (UINTN)Func, (UINTN)PciIoDevice->ReservedBusNum));
2083 // Initialize the reserved resource list
2085 InitializeListHead (&PciIoDevice->ReservedResourceList);
2088 // Initialize the driver list
2090 InitializeListHead (&PciIoDevice->OptionRomDriverList);
2093 // Initialize the child list
2095 InitializeListHead (&PciIoDevice->ChildList);
2097 return PciIoDevice;
2101 This routine is used to enumerate entire pci bus system
2102 in a given platform.
2104 It is only called on the second start on the same Root Bridge.
2106 @param Controller Parent bridge handler.
2108 @retval EFI_SUCCESS PCI enumeration finished successfully.
2109 @retval other Some error occurred when enumerating the pci bus system.
2112 EFI_STATUS
2113 PciEnumeratorLight (
2114 IN EFI_HANDLE Controller
2118 EFI_STATUS Status;
2119 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;
2120 PCI_IO_DEVICE *RootBridgeDev;
2121 UINT16 MinBus;
2122 UINT16 MaxBus;
2123 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptors;
2125 MinBus = 0;
2126 MaxBus = PCI_MAX_BUS;
2127 Descriptors = NULL;
2130 // If this root bridge has been already enumerated, then return successfully
2132 if (GetRootBridgeByHandle (Controller) != NULL) {
2133 return EFI_SUCCESS;
2137 // Open pci root bridge io protocol
2139 Status = gBS->OpenProtocol (
2140 Controller,
2141 &gEfiPciRootBridgeIoProtocolGuid,
2142 (VOID **) &PciRootBridgeIo,
2143 gPciBusDriverBinding.DriverBindingHandle,
2144 Controller,
2145 EFI_OPEN_PROTOCOL_BY_DRIVER
2147 if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {
2148 return Status;
2151 Status = PciRootBridgeIo->Configuration (PciRootBridgeIo, (VOID **) &Descriptors);
2153 if (EFI_ERROR (Status)) {
2154 return Status;
2157 while (PciGetBusRange (&Descriptors, &MinBus, &MaxBus, NULL) == EFI_SUCCESS) {
2160 // Create a device node for root bridge device with a NULL host bridge controller handle
2162 RootBridgeDev = CreateRootBridge (Controller);
2164 if (RootBridgeDev == NULL) {
2165 Descriptors++;
2166 continue;
2170 // Record the root bridgeio protocol
2172 RootBridgeDev->PciRootBridgeIo = PciRootBridgeIo;
2174 Status = PciPciDeviceInfoCollector (
2175 RootBridgeDev,
2176 (UINT8) MinBus
2179 if (!EFI_ERROR (Status)) {
2182 // Remove those PCI devices which are rejected when full enumeration
2184 RemoveRejectedPciDevices (RootBridgeDev->Handle, RootBridgeDev);
2187 // Process option rom light
2189 ProcessOptionRomLight (RootBridgeDev);
2192 // Determine attributes for all devices under this root bridge
2194 DetermineDeviceAttribute (RootBridgeDev);
2197 // If successfully, insert the node into device pool
2199 InsertRootBridge (RootBridgeDev);
2200 } else {
2203 // If unsuccessly, destroy the entire node
2205 DestroyRootBridge (RootBridgeDev);
2208 Descriptors++;
2211 return EFI_SUCCESS;
2215 Get bus range from PCI resource descriptor list.
2217 @param Descriptors A pointer to the address space descriptor.
2218 @param MinBus The min bus returned.
2219 @param MaxBus The max bus returned.
2220 @param BusRange The bus range returned.
2222 @retval EFI_SUCCESS Successfully got bus range.
2223 @retval EFI_NOT_FOUND Can not find the specific bus.
2226 EFI_STATUS
2227 PciGetBusRange (
2228 IN EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR **Descriptors,
2229 OUT UINT16 *MinBus,
2230 OUT UINT16 *MaxBus,
2231 OUT UINT16 *BusRange
2234 while ((*Descriptors)->Desc != ACPI_END_TAG_DESCRIPTOR) {
2235 if ((*Descriptors)->ResType == ACPI_ADDRESS_SPACE_TYPE_BUS) {
2236 if (MinBus != NULL) {
2237 *MinBus = (UINT16) (*Descriptors)->AddrRangeMin;
2240 if (MaxBus != NULL) {
2241 *MaxBus = (UINT16) (*Descriptors)->AddrRangeMax;
2244 if (BusRange != NULL) {
2245 *BusRange = (UINT16) (*Descriptors)->AddrLen;
2248 return EFI_SUCCESS;
2251 (*Descriptors)++;
2254 return EFI_NOT_FOUND;
2258 This routine can be used to start the root bridge.
2260 @param RootBridgeDev Pci device instance.
2262 @retval EFI_SUCCESS This device started.
2263 @retval other Failed to get PCI Root Bridge I/O protocol.
2266 EFI_STATUS
2267 StartManagingRootBridge (
2268 IN PCI_IO_DEVICE *RootBridgeDev
2271 EFI_HANDLE RootBridgeHandle;
2272 EFI_STATUS Status;
2273 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;
2276 // Get the root bridge handle
2278 RootBridgeHandle = RootBridgeDev->Handle;
2279 PciRootBridgeIo = NULL;
2282 // Get the pci root bridge io protocol
2284 Status = gBS->OpenProtocol (
2285 RootBridgeHandle,
2286 &gEfiPciRootBridgeIoProtocolGuid,
2287 (VOID **) &PciRootBridgeIo,
2288 gPciBusDriverBinding.DriverBindingHandle,
2289 RootBridgeHandle,
2290 EFI_OPEN_PROTOCOL_BY_DRIVER
2293 if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {
2294 return Status;
2298 // Store the PciRootBridgeIo protocol into root bridge private data
2300 RootBridgeDev->PciRootBridgeIo = PciRootBridgeIo;
2302 return EFI_SUCCESS;
2307 This routine can be used to check whether a PCI device should be rejected when light enumeration.
2309 @param PciIoDevice Pci device instance.
2311 @retval TRUE This device should be rejected.
2312 @retval FALSE This device shouldn't be rejected.
2315 BOOLEAN
2316 IsPciDeviceRejected (
2317 IN PCI_IO_DEVICE *PciIoDevice
2320 EFI_STATUS Status;
2321 UINT32 TestValue;
2322 UINT32 OldValue;
2323 UINT32 Mask;
2324 UINT8 BarOffset;
2327 // PPB should be skip!
2329 if (IS_PCI_BRIDGE (&PciIoDevice->Pci)) {
2330 return FALSE;
2333 if (IS_CARDBUS_BRIDGE (&PciIoDevice->Pci)) {
2335 // Only test base registers for P2C
2337 for (BarOffset = 0x1C; BarOffset <= 0x38; BarOffset += 2 * sizeof (UINT32)) {
2339 Mask = (BarOffset < 0x2C) ? 0xFFFFF000 : 0xFFFFFFFC;
2340 Status = BarExisted (PciIoDevice, BarOffset, &TestValue, &OldValue);
2341 if (EFI_ERROR (Status)) {
2342 continue;
2345 TestValue = TestValue & Mask;
2346 if ((TestValue != 0) && (TestValue == (OldValue & Mask))) {
2348 // The bar isn't programed, so it should be rejected
2350 return TRUE;
2354 return FALSE;
2357 for (BarOffset = 0x14; BarOffset <= 0x24; BarOffset += sizeof (UINT32)) {
2359 // Test PCI devices
2361 Status = BarExisted (PciIoDevice, BarOffset, &TestValue, &OldValue);
2362 if (EFI_ERROR (Status)) {
2363 continue;
2366 if ((TestValue & 0x01) != 0) {
2369 // IO Bar
2371 Mask = 0xFFFFFFFC;
2372 TestValue = TestValue & Mask;
2373 if ((TestValue != 0) && (TestValue == (OldValue & Mask))) {
2374 return TRUE;
2377 } else {
2380 // Mem Bar
2382 Mask = 0xFFFFFFF0;
2383 TestValue = TestValue & Mask;
2385 if ((TestValue & 0x07) == 0x04) {
2388 // Mem64 or PMem64
2390 BarOffset += sizeof (UINT32);
2391 if ((TestValue != 0) && (TestValue == (OldValue & Mask))) {
2394 // Test its high 32-Bit BAR
2396 Status = BarExisted (PciIoDevice, BarOffset, &TestValue, &OldValue);
2397 if (TestValue == OldValue) {
2398 return TRUE;
2402 } else {
2405 // Mem32 or PMem32
2407 if ((TestValue != 0) && (TestValue == (OldValue & Mask))) {
2408 return TRUE;
2414 return FALSE;
2418 Reset all bus number from specific bridge.
2420 @param Bridge Parent specific bridge.
2421 @param StartBusNumber Start bus number.
2424 VOID
2425 ResetAllPpbBusNumber (
2426 IN PCI_IO_DEVICE *Bridge,
2427 IN UINT8 StartBusNumber
2430 EFI_STATUS Status;
2431 PCI_TYPE00 Pci;
2432 UINT8 Device;
2433 UINT32 Register;
2434 UINT8 Func;
2435 UINT64 Address;
2436 UINT8 SecondaryBus;
2437 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;
2439 PciRootBridgeIo = Bridge->PciRootBridgeIo;
2441 for (Device = 0; Device <= PCI_MAX_DEVICE; Device++) {
2442 for (Func = 0; Func <= PCI_MAX_FUNC; Func++) {
2445 // Check to see whether a pci device is present
2447 Status = PciDevicePresent (
2448 PciRootBridgeIo,
2449 &Pci,
2450 StartBusNumber,
2451 Device,
2452 Func
2455 if (!EFI_ERROR (Status) && (IS_PCI_BRIDGE (&Pci))) {
2457 Register = 0;
2458 Address = EFI_PCI_ADDRESS (StartBusNumber, Device, Func, 0x18);
2459 Status = PciRootBridgeIo->Pci.Read (
2460 PciRootBridgeIo,
2461 EfiPciWidthUint32,
2462 Address,
2464 &Register
2466 SecondaryBus = (UINT8)(Register >> 8);
2468 if (SecondaryBus != 0) {
2469 ResetAllPpbBusNumber (Bridge, SecondaryBus);
2473 // Reset register 18h, 19h, 1Ah on PCI Bridge
2475 Register &= 0xFF000000;
2476 Status = PciRootBridgeIo->Pci.Write (
2477 PciRootBridgeIo,
2478 EfiPciWidthUint32,
2479 Address,
2481 &Register
2485 if (Func == 0 && !IS_PCI_MULTI_FUNC (&Pci)) {
2487 // Skip sub functions, this is not a multi function device
2489 Func = PCI_MAX_FUNC;