Add IncompatiblePciDeviceSupportDxe module in IntelFrameworkModulePkg.
[edk2.git] / IntelFrameworkModulePkg / Bus / Pci / PciBusDxe / PciEnumeratorSupport.c
blob49c7ec4ee02fa60818c0c1166c8f72e9ff71d446
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);
370 return PciIoDevice;
374 Create PCI device instance for PCI-PCI bridge.
376 @param Bridge Parent bridge instance.
377 @param Pci Input PCI device information block.
378 @param Bus PCI device Bus NO.
379 @param Device PCI device Device NO.
380 @param Func PCI device's func NO.
382 @return Created PCI device instance.
385 PCI_IO_DEVICE *
386 GatherPpbInfo (
387 IN PCI_IO_DEVICE *Bridge,
388 IN PCI_TYPE00 *Pci,
389 IN UINT8 Bus,
390 IN UINT8 Device,
391 IN UINT8 Func
394 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;
395 PCI_IO_DEVICE *PciIoDevice;
396 EFI_STATUS Status;
397 UINT8 Value;
398 EFI_PCI_IO_PROTOCOL *PciIo;
399 UINT8 Temp;
401 PciRootBridgeIo = Bridge->PciRootBridgeIo;
402 PciIoDevice = CreatePciIoDevice (
403 PciRootBridgeIo,
404 Pci,
405 Bus,
406 Device,
407 Func
410 if (PciIoDevice == NULL) {
411 return NULL;
415 // Create a device path for this PCI device and store it into its private data
417 CreatePciDevicePath (
418 Bridge->DevicePath,
419 PciIoDevice
422 if (gFullEnumeration) {
423 PCI_DISABLE_COMMAND_REGISTER (PciIoDevice, EFI_PCI_COMMAND_BITS_OWNED);
426 // Initalize the bridge control register
428 PCI_DISABLE_BRIDGE_CONTROL_REGISTER (PciIoDevice, EFI_PCI_BRIDGE_CONTROL_BITS_OWNED);
433 // PPB can have two BARs
435 if (PciParseBar (PciIoDevice, 0x10, PPB_BAR_0) == 0x14) {
437 // Not 64-bit bar
439 PciParseBar (PciIoDevice, 0x14, PPB_BAR_1);
442 PciIo = &PciIoDevice->PciIo;
445 // Test whether it support 32 decode or not
447 PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8, 0x1C, 1, &Temp);
448 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x1C, 1, &gAllOne);
449 PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8, 0x1C, 1, &Value);
450 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x1C, 1, &Temp);
452 if (Value != 0) {
453 if ((Value & 0x01) != 0) {
454 PciIoDevice->Decodes |= EFI_BRIDGE_IO32_DECODE_SUPPORTED;
455 } else {
456 PciIoDevice->Decodes |= EFI_BRIDGE_IO16_DECODE_SUPPORTED;
460 Status = BarExisted (
461 PciIoDevice,
462 0x24,
463 NULL,
464 NULL
468 // Test if it supports 64 memory or not
470 if (!EFI_ERROR (Status)) {
472 Status = BarExisted (
473 PciIoDevice,
474 0x28,
475 NULL,
476 NULL
479 if (!EFI_ERROR (Status)) {
480 PciIoDevice->Decodes |= EFI_BRIDGE_PMEM32_DECODE_SUPPORTED;
481 PciIoDevice->Decodes |= EFI_BRIDGE_PMEM64_DECODE_SUPPORTED;
482 } else {
483 PciIoDevice->Decodes |= EFI_BRIDGE_PMEM32_DECODE_SUPPORTED;
488 // Memory 32 code is required for ppb
490 PciIoDevice->Decodes |= EFI_BRIDGE_MEM32_DECODE_SUPPORTED;
492 GetResourcePaddingPpb (PciIoDevice);
494 return PciIoDevice;
499 Create PCI device instance for PCI Card bridge device.
501 @param Bridge Parent bridge instance.
502 @param Pci Input PCI device information block.
503 @param Bus PCI device Bus NO.
504 @param Device PCI device Device NO.
505 @param Func PCI device's func NO.
507 @return Created PCI device instance.
510 PCI_IO_DEVICE *
511 GatherP2CInfo (
512 IN PCI_IO_DEVICE *Bridge,
513 IN PCI_TYPE00 *Pci,
514 IN UINT8 Bus,
515 IN UINT8 Device,
516 IN UINT8 Func
519 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;
520 PCI_IO_DEVICE *PciIoDevice;
522 PciRootBridgeIo = Bridge->PciRootBridgeIo;
523 PciIoDevice = CreatePciIoDevice (
524 PciRootBridgeIo,
525 Pci,
526 Bus,
527 Device,
528 Func
531 if (PciIoDevice == NULL) {
532 return NULL;
536 // Create a device path for this PCI device and store it into its private data
538 CreatePciDevicePath (
539 Bridge->DevicePath,
540 PciIoDevice
543 if (gFullEnumeration) {
544 PCI_DISABLE_COMMAND_REGISTER (PciIoDevice, EFI_PCI_COMMAND_BITS_OWNED);
547 // Initalize the bridge control register
549 PCI_DISABLE_BRIDGE_CONTROL_REGISTER (PciIoDevice, EFI_PCCARD_BRIDGE_CONTROL_BITS_OWNED);
553 // P2C only has one bar that is in 0x10
555 PciParseBar (PciIoDevice, 0x10, P2C_BAR_0);
558 // Read PciBar information from the bar register
560 GetBackPcCardBar (PciIoDevice);
561 PciIoDevice->Decodes = EFI_BRIDGE_MEM32_DECODE_SUPPORTED |
562 EFI_BRIDGE_PMEM32_DECODE_SUPPORTED |
563 EFI_BRIDGE_IO32_DECODE_SUPPORTED;
565 return PciIoDevice;
569 Create device path for pci deivce.
571 @param ParentDevicePath Parent bridge's path.
572 @param PciIoDevice Pci device instance.
574 @return Device path protocol instance for specific pci device.
577 EFI_DEVICE_PATH_PROTOCOL *
578 CreatePciDevicePath (
579 IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath,
580 IN PCI_IO_DEVICE *PciIoDevice
584 PCI_DEVICE_PATH PciNode;
587 // Create PCI device path
589 PciNode.Header.Type = HARDWARE_DEVICE_PATH;
590 PciNode.Header.SubType = HW_PCI_DP;
591 SetDevicePathNodeLength (&PciNode.Header, sizeof (PciNode));
593 PciNode.Device = PciIoDevice->DeviceNumber;
594 PciNode.Function = PciIoDevice->FunctionNumber;
595 PciIoDevice->DevicePath = AppendDevicePathNode (ParentDevicePath, &PciNode.Header);
597 return PciIoDevice->DevicePath;
601 Check whether the bar is existed or not.
603 @param PciIoDevice A pointer to the PCI_IO_DEVICE.
604 @param Offset The offset.
605 @param BarLengthValue The bar length value returned.
606 @param OriginalBarValue The original bar value returned.
608 @retval EFI_NOT_FOUND The bar doesn't exist.
609 @retval EFI_SUCCESS The bar exist.
612 EFI_STATUS
613 BarExisted (
614 IN PCI_IO_DEVICE *PciIoDevice,
615 IN UINTN Offset,
616 OUT UINT32 *BarLengthValue,
617 OUT UINT32 *OriginalBarValue
620 EFI_PCI_IO_PROTOCOL *PciIo;
621 UINT32 OriginalValue;
622 UINT32 Value;
623 EFI_TPL OldTpl;
625 PciIo = &PciIoDevice->PciIo;
628 // Preserve the original value
630 PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, (UINT8) Offset, 1, &OriginalValue);
633 // Raise TPL to high level to disable timer interrupt while the BAR is probed
635 OldTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);
637 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, (UINT8) Offset, 1, &gAllOne);
638 PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, (UINT8) Offset, 1, &Value);
641 // Write back the original value
643 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, (UINT8) Offset, 1, &OriginalValue);
646 // Restore TPL to its original level
648 gBS->RestoreTPL (OldTpl);
650 if (BarLengthValue != NULL) {
651 *BarLengthValue = Value;
654 if (OriginalBarValue != NULL) {
655 *OriginalBarValue = OriginalValue;
658 if (Value == 0) {
659 return EFI_NOT_FOUND;
660 } else {
661 return EFI_SUCCESS;
666 Test whether the device can support given attributes.
668 @param PciIoDevice Pci device instance.
669 @param Command Input command register value, and
670 returned supported register value.
671 @param BridgeControl Inout bridge control value for PPB or P2C, and
672 returned supported bridge control value.
673 @param OldCommand Returned and stored old command register offset.
674 @param OldBridgeControl Returned and stored old Bridge control value for PPB or P2C.
677 VOID
678 PciTestSupportedAttribute (
679 IN PCI_IO_DEVICE *PciIoDevice,
680 IN OUT UINT16 *Command,
681 IN OUT UINT16 *BridgeControl,
682 OUT UINT16 *OldCommand,
683 OUT UINT16 *OldBridgeControl
686 EFI_TPL OldTpl;
689 // Preserve the original value
691 PCI_READ_COMMAND_REGISTER (PciIoDevice, OldCommand);
694 // Raise TPL to high level to disable timer interrupt while the BAR is probed
696 OldTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);
698 PCI_SET_COMMAND_REGISTER (PciIoDevice, *Command);
699 PCI_READ_COMMAND_REGISTER (PciIoDevice, Command);
702 // Write back the original value
704 PCI_SET_COMMAND_REGISTER (PciIoDevice, *OldCommand);
707 // Restore TPL to its original level
709 gBS->RestoreTPL (OldTpl);
711 if (IS_PCI_BRIDGE (&PciIoDevice->Pci) || IS_CARDBUS_BRIDGE (&PciIoDevice->Pci)) {
714 // Preserve the original value
716 PCI_READ_BRIDGE_CONTROL_REGISTER (PciIoDevice, OldBridgeControl);
719 // Raise TPL to high level to disable timer interrupt while the BAR is probed
721 OldTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);
723 PCI_SET_BRIDGE_CONTROL_REGISTER (PciIoDevice, *BridgeControl);
724 PCI_READ_BRIDGE_CONTROL_REGISTER (PciIoDevice, BridgeControl);
727 // Write back the original value
729 PCI_SET_BRIDGE_CONTROL_REGISTER (PciIoDevice, *OldBridgeControl);
732 // Restore TPL to its original level
734 gBS->RestoreTPL (OldTpl);
736 } else {
737 *OldBridgeControl = 0;
738 *BridgeControl = 0;
743 Set the supported or current attributes of a PCI device.
745 @param PciIoDevice Structure pointer for PCI device.
746 @param Command Command register value.
747 @param BridgeControl Bridge control value for PPB or P2C.
748 @param Option Make a choice of EFI_SET_SUPPORTS or EFI_SET_ATTRIBUTES.
751 VOID
752 PciSetDeviceAttribute (
753 IN PCI_IO_DEVICE *PciIoDevice,
754 IN UINT16 Command,
755 IN UINT16 BridgeControl,
756 IN UINTN Option
759 UINT64 Attributes;
761 Attributes = 0;
763 if ((Command & EFI_PCI_COMMAND_IO_SPACE) != 0) {
764 Attributes |= EFI_PCI_IO_ATTRIBUTE_IO;
767 if ((Command & EFI_PCI_COMMAND_MEMORY_SPACE) != 0) {
768 Attributes |= EFI_PCI_IO_ATTRIBUTE_MEMORY;
771 if ((Command & EFI_PCI_COMMAND_BUS_MASTER) != 0) {
772 Attributes |= EFI_PCI_IO_ATTRIBUTE_BUS_MASTER;
775 if ((Command & EFI_PCI_COMMAND_VGA_PALETTE_SNOOP) != 0) {
776 Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO;
779 if ((BridgeControl & EFI_PCI_BRIDGE_CONTROL_ISA) != 0) {
780 Attributes |= EFI_PCI_IO_ATTRIBUTE_ISA_IO;
783 if ((BridgeControl & EFI_PCI_BRIDGE_CONTROL_VGA) != 0) {
784 Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_IO;
785 Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY;
786 Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO;
789 if ((BridgeControl & EFI_PCI_BRIDGE_CONTROL_VGA_16) != 0) {
790 Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_IO_16;
791 Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO_16;
794 if (Option == EFI_SET_SUPPORTS) {
796 Attributes |= EFI_PCI_IO_ATTRIBUTE_MEMORY_WRITE_COMBINE |
797 EFI_PCI_IO_ATTRIBUTE_MEMORY_CACHED |
798 EFI_PCI_IO_ATTRIBUTE_MEMORY_DISABLE |
799 EFI_PCI_IO_ATTRIBUTE_EMBEDDED_DEVICE |
800 EFI_PCI_IO_ATTRIBUTE_EMBEDDED_ROM |
801 EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE;
803 if ((Attributes & EFI_PCI_IO_ATTRIBUTE_IO) != 0) {
804 Attributes |= EFI_PCI_IO_ATTRIBUTE_ISA_MOTHERBOARD_IO;
805 Attributes |= EFI_PCI_IO_ATTRIBUTE_ISA_IO;
808 if (IS_PCI_BRIDGE (&PciIoDevice->Pci) || IS_CARDBUS_BRIDGE (&PciIoDevice->Pci)) {
810 // For bridge, it should support IDE attributes
812 Attributes |= EFI_PCI_IO_ATTRIBUTE_IDE_SECONDARY_IO;
813 Attributes |= EFI_PCI_IO_ATTRIBUTE_IDE_PRIMARY_IO;
814 } else {
816 if (IS_PCI_IDE (&PciIoDevice->Pci)) {
817 Attributes |= EFI_PCI_IO_ATTRIBUTE_IDE_SECONDARY_IO;
818 Attributes |= EFI_PCI_IO_ATTRIBUTE_IDE_PRIMARY_IO;
821 if (IS_PCI_VGA (&PciIoDevice->Pci)) {
822 Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY;
823 Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_IO;
827 PciIoDevice->Supports = Attributes;
828 PciIoDevice->Supports &= ( (PciIoDevice->Parent->Supports) | \
829 EFI_PCI_IO_ATTRIBUTE_IO | EFI_PCI_IO_ATTRIBUTE_MEMORY | \
830 EFI_PCI_IO_ATTRIBUTE_BUS_MASTER );
832 } else {
833 PciIoDevice->Attributes = Attributes;
838 Determine if the device can support Fast Back to Back attribute.
840 @param PciIoDevice Pci device instance.
841 @param StatusIndex Status register value.
843 @retval EFI_SUCCESS This device support Fast Back to Back attribute.
844 @retval EFI_UNSUPPORTED This device doesn't support Fast Back to Back attribute.
847 EFI_STATUS
848 GetFastBackToBackSupport (
849 IN PCI_IO_DEVICE *PciIoDevice,
850 IN UINT8 StatusIndex
853 EFI_PCI_IO_PROTOCOL *PciIo;
854 EFI_STATUS Status;
855 UINT32 StatusRegister;
858 // Read the status register
860 PciIo = &PciIoDevice->PciIo;
861 Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint16, StatusIndex, 1, &StatusRegister);
862 if (EFI_ERROR (Status)) {
863 return EFI_UNSUPPORTED;
867 // Check the Fast B2B bit
869 if ((StatusRegister & EFI_PCI_FAST_BACK_TO_BACK_CAPABLE) != 0) {
870 return EFI_SUCCESS;
871 } else {
872 return EFI_UNSUPPORTED;
877 Process the option ROM for all the children of the specified parent PCI device.
878 It can only be used after the first full Option ROM process.
880 @param PciIoDevice Pci device instance.
883 VOID
884 ProcessOptionRomLight (
885 IN PCI_IO_DEVICE *PciIoDevice
888 PCI_IO_DEVICE *Temp;
889 LIST_ENTRY *CurrentLink;
892 // For RootBridge, PPB , P2C, go recursively to traverse all its children
894 CurrentLink = PciIoDevice->ChildList.ForwardLink;
895 while (CurrentLink != NULL && CurrentLink != &PciIoDevice->ChildList) {
897 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
899 if (!IsListEmpty (&Temp->ChildList)) {
900 ProcessOptionRomLight (Temp);
903 PciRomGetImageMapping (Temp);
906 // The OpRom has already been processed in the first round
908 Temp->AllOpRomProcessed = TRUE;
910 CurrentLink = CurrentLink->ForwardLink;
915 Determine the related attributes of all devices under a Root Bridge.
917 @param PciIoDevice PCI device instance.
920 EFI_STATUS
921 DetermineDeviceAttribute (
922 IN PCI_IO_DEVICE *PciIoDevice
925 UINT16 Command;
926 UINT16 BridgeControl;
927 UINT16 OldCommand;
928 UINT16 OldBridgeControl;
929 BOOLEAN FastB2BSupport;
930 PCI_IO_DEVICE *Temp;
931 LIST_ENTRY *CurrentLink;
932 EFI_STATUS Status;
935 // For Root Bridge, just copy it by RootBridgeIo proctocol
936 // so as to keep consistent with the actual attribute
938 if (PciIoDevice->Parent == NULL) {
939 Status = PciIoDevice->PciRootBridgeIo->GetAttributes (
940 PciIoDevice->PciRootBridgeIo,
941 &PciIoDevice->Supports,
942 &PciIoDevice->Attributes
944 if (EFI_ERROR (Status)) {
945 return Status;
947 } else {
950 // Set the attributes to be checked for common PCI devices and PPB or P2C
951 // Since some devices only support part of them, it is better to set the
952 // attribute according to its command or bridge control register
954 Command = EFI_PCI_COMMAND_IO_SPACE |
955 EFI_PCI_COMMAND_MEMORY_SPACE |
956 EFI_PCI_COMMAND_BUS_MASTER |
957 EFI_PCI_COMMAND_VGA_PALETTE_SNOOP;
959 BridgeControl = EFI_PCI_BRIDGE_CONTROL_ISA | EFI_PCI_BRIDGE_CONTROL_VGA | EFI_PCI_BRIDGE_CONTROL_VGA_16;
962 // Test whether the device can support attributes above
964 PciTestSupportedAttribute (PciIoDevice, &Command, &BridgeControl, &OldCommand, &OldBridgeControl);
967 // Set the supported attributes for specified PCI device
969 PciSetDeviceAttribute (PciIoDevice, Command, BridgeControl, EFI_SET_SUPPORTS);
972 // Set the current attributes for specified PCI device
974 PciSetDeviceAttribute (PciIoDevice, OldCommand, OldBridgeControl, EFI_SET_ATTRIBUTES);
977 // Enable other supported attributes but not defined in PCI_IO_PROTOCOL
979 PCI_ENABLE_COMMAND_REGISTER (PciIoDevice, EFI_PCI_COMMAND_MEMORY_WRITE_AND_INVALIDATE);
982 FastB2BSupport = TRUE;
985 // P2C can not support FB2B on the secondary side
987 if (IS_CARDBUS_BRIDGE (&PciIoDevice->Pci)) {
988 FastB2BSupport = FALSE;
992 // For RootBridge, PPB , P2C, go recursively to traverse all its children
994 CurrentLink = PciIoDevice->ChildList.ForwardLink;
995 while (CurrentLink != NULL && CurrentLink != &PciIoDevice->ChildList) {
997 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
998 Status = DetermineDeviceAttribute (Temp);
999 if (EFI_ERROR (Status)) {
1000 return Status;
1003 // Detect Fast Bact to Bact support for the device under the bridge
1005 Status = GetFastBackToBackSupport (Temp, PCI_PRIMARY_STATUS_OFFSET);
1006 if (FastB2BSupport && EFI_ERROR (Status)) {
1007 FastB2BSupport = FALSE;
1010 CurrentLink = CurrentLink->ForwardLink;
1013 // Set or clear Fast Back to Back bit for the whole bridge
1015 if (!IsListEmpty (&PciIoDevice->ChildList)) {
1017 if (IS_PCI_BRIDGE (&PciIoDevice->Pci)) {
1019 Status = GetFastBackToBackSupport (PciIoDevice, PCI_BRIDGE_STATUS_REGISTER_OFFSET);
1021 if (EFI_ERROR (Status) || (!FastB2BSupport)) {
1022 FastB2BSupport = FALSE;
1023 PCI_DISABLE_BRIDGE_CONTROL_REGISTER (PciIoDevice, EFI_PCI_BRIDGE_CONTROL_FAST_BACK_TO_BACK);
1024 } else {
1025 PCI_ENABLE_BRIDGE_CONTROL_REGISTER (PciIoDevice, EFI_PCI_BRIDGE_CONTROL_FAST_BACK_TO_BACK);
1029 CurrentLink = PciIoDevice->ChildList.ForwardLink;
1030 while (CurrentLink != NULL && CurrentLink != &PciIoDevice->ChildList) {
1031 Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
1032 if (FastB2BSupport) {
1033 PCI_ENABLE_COMMAND_REGISTER (Temp, EFI_PCI_COMMAND_FAST_BACK_TO_BACK);
1034 } else {
1035 PCI_DISABLE_COMMAND_REGISTER (Temp, EFI_PCI_COMMAND_FAST_BACK_TO_BACK);
1038 CurrentLink = CurrentLink->ForwardLink;
1042 // End for IsListEmpty
1044 return EFI_SUCCESS;
1048 This routine is used to update the bar information for those incompatible PCI device.
1050 @param PciIoDevice Input Pci device instance. Output Pci device instance with updated
1051 Bar information.
1053 @retval EFI_SUCCESS Successfully updated bar information.
1054 @retval EFI_UNSUPPORTED Given PCI device doesn't belong to incompatible PCI device list.
1057 EFI_STATUS
1058 UpdatePciInfo (
1059 IN OUT PCI_IO_DEVICE *PciIoDevice
1062 EFI_STATUS Status;
1063 UINTN BarIndex;
1064 UINTN BarEndIndex;
1065 BOOLEAN SetFlag;
1066 VOID *Configuration;
1067 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Ptr;
1069 Configuration = NULL;
1070 Status = EFI_SUCCESS;
1072 if (gEfiIncompatiblePciDeviceSupport == NULL) {
1074 // It can only be supported after the Incompatible PCI Device
1075 // Support Protocol has been installed
1077 Status = gBS->LocateProtocol (
1078 &gEfiIncompatiblePciDeviceSupportProtocolGuid,
1079 NULL,
1080 (VOID **) &gEfiIncompatiblePciDeviceSupport
1083 if (Status == EFI_SUCCESS) {
1085 // Check whether the device belongs to incompatible devices from protocol or not
1086 // If it is , then get its special requirement in the ACPI table
1088 Status = gEfiIncompatiblePciDeviceSupport->CheckDevice (
1089 gEfiIncompatiblePciDeviceSupport,
1090 PciIoDevice->Pci.Hdr.VendorId,
1091 PciIoDevice->Pci.Hdr.DeviceId,
1092 PciIoDevice->Pci.Hdr.RevisionID,
1093 PciIoDevice->Pci.Device.SubsystemVendorID,
1094 PciIoDevice->Pci.Device.SubsystemID,
1095 &Configuration
1100 if (EFI_ERROR (Status) || Configuration == NULL ) {
1101 return EFI_UNSUPPORTED;
1105 // Update PCI device information from the ACPI table
1107 Ptr = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Configuration;
1109 while (Ptr->Desc != ACPI_END_TAG_DESCRIPTOR) {
1111 if (Ptr->Desc != ACPI_ADDRESS_SPACE_DESCRIPTOR) {
1113 // The format is not support
1115 break;
1118 BarIndex = (UINTN) Ptr->AddrTranslationOffset;
1119 BarEndIndex = BarIndex;
1122 // Update all the bars in the device
1124 if (BarIndex == PCI_BAR_ALL) {
1125 BarIndex = 0;
1126 BarEndIndex = PCI_MAX_BAR - 1;
1129 if (BarIndex >= PCI_MAX_BAR) {
1130 Ptr++;
1131 continue;
1134 for (; BarIndex <= BarEndIndex; BarIndex++) {
1135 SetFlag = FALSE;
1136 switch (Ptr->ResType) {
1137 case ACPI_ADDRESS_SPACE_TYPE_MEM:
1140 // Make sure the bar is memory type
1142 if (CheckBarType (PciIoDevice, (UINT8) BarIndex, PciBarTypeMem)) {
1143 SetFlag = TRUE;
1145 break;
1147 case ACPI_ADDRESS_SPACE_TYPE_IO:
1150 // Make sure the bar is IO type
1152 if (CheckBarType (PciIoDevice, (UINT8) BarIndex, PciBarTypeIo)) {
1153 SetFlag = TRUE;
1155 break;
1158 if (SetFlag) {
1161 // Update the new alignment for the device
1163 SetNewAlign (&(PciIoDevice->PciBar[BarIndex].Alignment), Ptr->AddrRangeMax);
1166 // Update the new length for the device
1168 if (Ptr->AddrLen != PCI_BAR_NOCHANGE) {
1169 PciIoDevice->PciBar[BarIndex].Length = Ptr->AddrLen;
1174 Ptr++;
1177 FreePool (Configuration);
1179 return EFI_SUCCESS;
1183 This routine will update the alignment with the new alignment.
1185 @param Alignment Input Old alignment. Output updated alignment.
1186 @param NewAlignment New alignment.
1189 VOID
1190 SetNewAlign (
1191 IN OUT UINT64 *Alignment,
1192 IN UINT64 NewAlignment
1195 UINT64 OldAlignment;
1196 UINTN ShiftBit;
1199 // The new alignment is the same as the original,
1200 // so skip it
1202 if (NewAlignment == PCI_BAR_OLD_ALIGN) {
1203 return ;
1206 // Check the validity of the parameter
1208 if (NewAlignment != PCI_BAR_EVEN_ALIGN &&
1209 NewAlignment != PCI_BAR_SQUAD_ALIGN &&
1210 NewAlignment != PCI_BAR_DQUAD_ALIGN ) {
1211 *Alignment = NewAlignment;
1212 return ;
1215 OldAlignment = (*Alignment) + 1;
1216 ShiftBit = 0;
1219 // Get the first non-zero hex value of the length
1221 while ((OldAlignment & 0x0F) == 0x00) {
1222 OldAlignment = RShiftU64 (OldAlignment, 4);
1223 ShiftBit += 4;
1227 // Adjust the alignment to even, quad or double quad boundary
1229 if (NewAlignment == PCI_BAR_EVEN_ALIGN) {
1230 if ((OldAlignment & 0x01) != 0) {
1231 OldAlignment = OldAlignment + 2 - (OldAlignment & 0x01);
1233 } else if (NewAlignment == PCI_BAR_SQUAD_ALIGN) {
1234 if ((OldAlignment & 0x03) != 0) {
1235 OldAlignment = OldAlignment + 4 - (OldAlignment & 0x03);
1237 } else if (NewAlignment == PCI_BAR_DQUAD_ALIGN) {
1238 if ((OldAlignment & 0x07) != 0) {
1239 OldAlignment = OldAlignment + 8 - (OldAlignment & 0x07);
1244 // Update the old value
1246 NewAlignment = LShiftU64 (OldAlignment, ShiftBit) - 1;
1247 *Alignment = NewAlignment;
1249 return ;
1253 Parse PCI bar information and fill them into PCI device instance.
1255 @param PciIoDevice Pci device instance.
1256 @param Offset Bar offset.
1257 @param BarIndex Bar index.
1259 @return Next bar offset.
1262 UINTN
1263 PciParseBar (
1264 IN PCI_IO_DEVICE *PciIoDevice,
1265 IN UINTN Offset,
1266 IN UINTN BarIndex
1269 UINT32 Value;
1270 UINT32 OriginalValue;
1271 UINT32 Mask;
1272 UINT32 Data;
1273 UINT8 Index;
1274 EFI_STATUS Status;
1276 OriginalValue = 0;
1277 Value = 0;
1279 Status = BarExisted (
1280 PciIoDevice,
1281 Offset,
1282 &Value,
1283 &OriginalValue
1286 if (EFI_ERROR (Status)) {
1287 PciIoDevice->PciBar[BarIndex].BaseAddress = 0;
1288 PciIoDevice->PciBar[BarIndex].Length = 0;
1289 PciIoDevice->PciBar[BarIndex].Alignment = 0;
1292 // Some devices don't fully comply to PCI spec 2.2. So be to scan all the BARs anyway
1294 PciIoDevice->PciBar[BarIndex].Offset = (UINT8) Offset;
1295 return Offset + 4;
1298 PciIoDevice->PciBar[BarIndex].Offset = (UINT8) Offset;
1299 if ((Value & 0x01) != 0) {
1301 // Device I/Os
1303 Mask = 0xfffffffc;
1305 if ((Value & 0xFFFF0000) != 0) {
1307 // It is a IO32 bar
1309 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeIo32;
1310 PciIoDevice->PciBar[BarIndex].Length = ((~(Value & Mask)) + 1);
1311 PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;
1313 } else {
1315 // It is a IO16 bar
1317 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeIo16;
1318 PciIoDevice->PciBar[BarIndex].Length = 0x0000FFFF & ((~(Value & Mask)) + 1);
1319 PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;
1323 // Workaround. Some platforms inplement IO bar with 0 length
1324 // Need to treat it as no-bar
1326 if (PciIoDevice->PciBar[BarIndex].Length == 0) {
1327 PciIoDevice->PciBar[BarIndex].BarType = (PCI_BAR_TYPE) 0;
1330 PciIoDevice->PciBar[BarIndex].Prefetchable = FALSE;
1331 PciIoDevice->PciBar[BarIndex].BaseAddress = OriginalValue & Mask;
1333 } else {
1335 Mask = 0xfffffff0;
1337 PciIoDevice->PciBar[BarIndex].BaseAddress = OriginalValue & Mask;
1339 switch (Value & 0x07) {
1342 //memory space; anywhere in 32 bit address space
1344 case 0x00:
1345 if ((Value & 0x08) != 0) {
1346 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypePMem32;
1347 } else {
1348 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeMem32;
1351 PciIoDevice->PciBar[BarIndex].Length = (~(Value & Mask)) + 1;
1352 PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;
1354 break;
1357 // memory space; anywhere in 64 bit address space
1359 case 0x04:
1360 if ((Value & 0x08) != 0) {
1361 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypePMem64;
1362 } else {
1363 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeMem64;
1367 // According to PCI 2.2,if the bar indicates a memory 64 decoding, next bar
1368 // is regarded as an extension for the first bar. As a result
1369 // the sizing will be conducted on combined 64 bit value
1370 // Here just store the masked first 32bit value for future size
1371 // calculation
1373 PciIoDevice->PciBar[BarIndex].Length = Value & Mask;
1374 PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;
1377 // Increment the offset to point to next DWORD
1379 Offset += 4;
1381 Status = BarExisted (
1382 PciIoDevice,
1383 Offset,
1384 &Value,
1385 &OriginalValue
1388 if (EFI_ERROR (Status)) {
1389 return Offset + 4;
1393 // Fix the length to support some spefic 64 bit BAR
1395 Data = Value;
1396 Index = 0;
1397 for (Data = Value; Data != 0; Data >>= 1) {
1398 Index ++;
1400 Value |= ((UINT32)(-1) << Index);
1403 // Calculate the size of 64bit bar
1405 PciIoDevice->PciBar[BarIndex].BaseAddress |= LShiftU64 ((UINT64) OriginalValue, 32);
1407 PciIoDevice->PciBar[BarIndex].Length = PciIoDevice->PciBar[BarIndex].Length | LShiftU64 ((UINT64) Value, 32);
1408 PciIoDevice->PciBar[BarIndex].Length = (~(PciIoDevice->PciBar[BarIndex].Length)) + 1;
1409 PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;
1411 break;
1414 // reserved
1416 default:
1417 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeUnknown;
1418 PciIoDevice->PciBar[BarIndex].Length = (~(Value & Mask)) + 1;
1419 PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;
1421 break;
1426 // Check the length again so as to keep compatible with some special bars
1428 if (PciIoDevice->PciBar[BarIndex].Length == 0) {
1429 PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeUnknown;
1430 PciIoDevice->PciBar[BarIndex].BaseAddress = 0;
1431 PciIoDevice->PciBar[BarIndex].Alignment = 0;
1435 // Increment number of bar
1437 return Offset + 4;
1441 This routine is used to initialize the bar of a PCI device.
1443 @param PciIoDevice Pci device instance.
1445 @note It can be called typically when a device is going to be rejected.
1448 VOID
1449 InitializePciDevice (
1450 IN PCI_IO_DEVICE *PciIoDevice
1453 EFI_PCI_IO_PROTOCOL *PciIo;
1454 UINT8 Offset;
1456 PciIo = &(PciIoDevice->PciIo);
1459 // Put all the resource apertures
1460 // Resource base is set to all ones so as to indicate its resource
1461 // has not been alloacted
1463 for (Offset = 0x10; Offset <= 0x24; Offset += sizeof (UINT32)) {
1464 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, Offset, 1, &gAllOne);
1469 This routine is used to initialize the bar of a PCI-PCI Bridge device.
1471 @param PciIoDevice PCI-PCI bridge device instance.
1474 VOID
1475 InitializePpb (
1476 IN PCI_IO_DEVICE *PciIoDevice
1479 EFI_PCI_IO_PROTOCOL *PciIo;
1481 PciIo = &(PciIoDevice->PciIo);
1484 // Put all the resource apertures including IO16
1485 // Io32, pMem32, pMem64 to quiescent state
1486 // Resource base all ones, Resource limit all zeros
1488 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x1C, 1, &gAllOne);
1489 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x1D, 1, &gAllZero);
1491 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x20, 1, &gAllOne);
1492 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x22, 1, &gAllZero);
1494 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x24, 1, &gAllOne);
1495 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x26, 1, &gAllZero);
1497 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x28, 1, &gAllOne);
1498 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x2C, 1, &gAllZero);
1501 // Don't support use io32 as for now
1503 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x30, 1, &gAllOne);
1504 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x32, 1, &gAllZero);
1507 // Force Interrupt line to zero for cards that come up randomly
1509 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x3C, 1, &gAllZero);
1513 This routine is used to initialize the bar of a PCI Card Bridge device.
1515 @param PciIoDevice PCI Card bridge device.
1518 VOID
1519 InitializeP2C (
1520 IN PCI_IO_DEVICE *PciIoDevice
1523 EFI_PCI_IO_PROTOCOL *PciIo;
1525 PciIo = &(PciIoDevice->PciIo);
1528 // Put all the resource apertures including IO16
1529 // Io32, pMem32, pMem64 to quiescent state(
1530 // Resource base all ones, Resource limit all zeros
1532 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x1c, 1, &gAllOne);
1533 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x20, 1, &gAllZero);
1535 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x24, 1, &gAllOne);
1536 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x28, 1, &gAllZero);
1538 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x2c, 1, &gAllOne);
1539 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x30, 1, &gAllZero);
1541 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x34, 1, &gAllOne);
1542 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x38, 1, &gAllZero);
1545 // Force Interrupt line to zero for cards that come up randomly
1547 PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x3C, 1, &gAllZero);
1551 Create and initiliaze general PCI I/O device instance for
1552 PCI device/bridge device/hotplug bridge device.
1554 @param PciRootBridgeIo Pointer to instance of EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
1555 @param Pci Input Pci information block.
1556 @param Bus Device Bus NO.
1557 @param Device Device device NO.
1558 @param Func Device func NO.
1560 @return Instance of PCI device. NULL means no instance created.
1563 PCI_IO_DEVICE *
1564 CreatePciIoDevice (
1565 IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo,
1566 IN PCI_TYPE00 *Pci,
1567 IN UINT8 Bus,
1568 IN UINT8 Device,
1569 IN UINT8 Func
1572 PCI_IO_DEVICE *PciIoDevice;
1574 PciIoDevice = AllocateZeroPool (sizeof (PCI_IO_DEVICE));
1575 if (PciIoDevice == NULL) {
1576 return NULL;
1579 PciIoDevice->Signature = PCI_IO_DEVICE_SIGNATURE;
1580 PciIoDevice->Handle = NULL;
1581 PciIoDevice->PciRootBridgeIo = PciRootBridgeIo;
1582 PciIoDevice->DevicePath = NULL;
1583 PciIoDevice->BusNumber = Bus;
1584 PciIoDevice->DeviceNumber = Device;
1585 PciIoDevice->FunctionNumber = Func;
1586 PciIoDevice->Decodes = 0;
1588 if (gFullEnumeration) {
1589 PciIoDevice->Allocated = FALSE;
1590 } else {
1591 PciIoDevice->Allocated = TRUE;
1594 PciIoDevice->Registered = FALSE;
1595 PciIoDevice->Attributes = 0;
1596 PciIoDevice->Supports = 0;
1597 PciIoDevice->BusOverride = FALSE;
1598 PciIoDevice->AllOpRomProcessed = FALSE;
1600 PciIoDevice->IsPciExp = FALSE;
1602 CopyMem (&(PciIoDevice->Pci), Pci, sizeof (PCI_TYPE01));
1605 // Initialize the PCI I/O instance structure
1607 InitializePciIoInstance (PciIoDevice);
1608 InitializePciDriverOverrideInstance (PciIoDevice);
1609 InitializePciLoadFile2 (PciIoDevice);
1612 // Initialize the reserved resource list
1614 InitializeListHead (&PciIoDevice->ReservedResourceList);
1617 // Initialize the driver list
1619 InitializeListHead (&PciIoDevice->OptionRomDriverList);
1622 // Initialize the child list
1624 InitializeListHead (&PciIoDevice->ChildList);
1626 return PciIoDevice;
1630 This routine is used to enumerate entire pci bus system
1631 in a given platform.
1633 It is only called on the second start on the same Root Bridge.
1635 @param Controller Parent bridge handler.
1637 @retval EFI_SUCCESS PCI enumeration finished successfully.
1638 @retval other Some error occurred when enumerating the pci bus system.
1641 EFI_STATUS
1642 PciEnumeratorLight (
1643 IN EFI_HANDLE Controller
1647 EFI_STATUS Status;
1648 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;
1649 PCI_IO_DEVICE *RootBridgeDev;
1650 UINT16 MinBus;
1651 UINT16 MaxBus;
1652 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptors;
1654 MinBus = 0;
1655 MaxBus = PCI_MAX_BUS;
1656 Descriptors = NULL;
1659 // If this root bridge has been already enumerated, then return successfully
1661 if (GetRootBridgeByHandle (Controller) != NULL) {
1662 return EFI_SUCCESS;
1666 // Open pci root bridge io protocol
1668 Status = gBS->OpenProtocol (
1669 Controller,
1670 &gEfiPciRootBridgeIoProtocolGuid,
1671 (VOID **) &PciRootBridgeIo,
1672 gPciBusDriverBinding.DriverBindingHandle,
1673 Controller,
1674 EFI_OPEN_PROTOCOL_BY_DRIVER
1676 if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {
1677 return Status;
1680 Status = PciRootBridgeIo->Configuration (PciRootBridgeIo, (VOID **) &Descriptors);
1682 if (EFI_ERROR (Status)) {
1683 return Status;
1686 while (PciGetBusRange (&Descriptors, &MinBus, &MaxBus, NULL) == EFI_SUCCESS) {
1689 // Create a device node for root bridge device with a NULL host bridge controller handle
1691 RootBridgeDev = CreateRootBridge (Controller);
1693 if (RootBridgeDev == NULL) {
1694 Descriptors++;
1695 continue;
1699 // Record the root bridgeio protocol
1701 RootBridgeDev->PciRootBridgeIo = PciRootBridgeIo;
1703 Status = PciPciDeviceInfoCollector (
1704 RootBridgeDev,
1705 (UINT8) MinBus
1708 if (!EFI_ERROR (Status)) {
1711 // Remove those PCI devices which are rejected when full enumeration
1713 RemoveRejectedPciDevices (RootBridgeDev->Handle, RootBridgeDev);
1716 // Process option rom light
1718 ProcessOptionRomLight (RootBridgeDev);
1721 // Determine attributes for all devices under this root bridge
1723 DetermineDeviceAttribute (RootBridgeDev);
1726 // If successfully, insert the node into device pool
1728 InsertRootBridge (RootBridgeDev);
1729 } else {
1732 // If unsuccessly, destroy the entire node
1734 DestroyRootBridge (RootBridgeDev);
1737 Descriptors++;
1740 return EFI_SUCCESS;
1744 Get bus range from PCI resource descriptor list.
1746 @param Descriptors A pointer to the address space descriptor.
1747 @param MinBus The min bus returned.
1748 @param MaxBus The max bus returned.
1749 @param BusRange The bus range returned.
1751 @retval EFI_SUCCESS Successfully got bus range.
1752 @retval EFI_NOT_FOUND Can not find the specific bus.
1755 EFI_STATUS
1756 PciGetBusRange (
1757 IN EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR **Descriptors,
1758 OUT UINT16 *MinBus,
1759 OUT UINT16 *MaxBus,
1760 OUT UINT16 *BusRange
1763 while ((*Descriptors)->Desc != ACPI_END_TAG_DESCRIPTOR) {
1764 if ((*Descriptors)->ResType == ACPI_ADDRESS_SPACE_TYPE_BUS) {
1765 if (MinBus != NULL) {
1766 *MinBus = (UINT16) (*Descriptors)->AddrRangeMin;
1769 if (MaxBus != NULL) {
1770 *MaxBus = (UINT16) (*Descriptors)->AddrRangeMax;
1773 if (BusRange != NULL) {
1774 *BusRange = (UINT16) (*Descriptors)->AddrLen;
1777 return EFI_SUCCESS;
1780 (*Descriptors)++;
1783 return EFI_NOT_FOUND;
1787 This routine can be used to start the root bridge.
1789 @param RootBridgeDev Pci device instance.
1791 @retval EFI_SUCCESS This device started.
1792 @retval other Failed to get PCI Root Bridge I/O protocol.
1795 EFI_STATUS
1796 StartManagingRootBridge (
1797 IN PCI_IO_DEVICE *RootBridgeDev
1800 EFI_HANDLE RootBridgeHandle;
1801 EFI_STATUS Status;
1802 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;
1805 // Get the root bridge handle
1807 RootBridgeHandle = RootBridgeDev->Handle;
1808 PciRootBridgeIo = NULL;
1811 // Get the pci root bridge io protocol
1813 Status = gBS->OpenProtocol (
1814 RootBridgeHandle,
1815 &gEfiPciRootBridgeIoProtocolGuid,
1816 (VOID **) &PciRootBridgeIo,
1817 gPciBusDriverBinding.DriverBindingHandle,
1818 RootBridgeHandle,
1819 EFI_OPEN_PROTOCOL_BY_DRIVER
1822 if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {
1823 return Status;
1827 // Store the PciRootBridgeIo protocol into root bridge private data
1829 RootBridgeDev->PciRootBridgeIo = PciRootBridgeIo;
1831 return EFI_SUCCESS;
1836 This routine can be used to check whether a PCI device should be rejected when light enumeration.
1838 @param PciIoDevice Pci device instance.
1840 @retval TRUE This device should be rejected.
1841 @retval FALSE This device shouldn't be rejected.
1844 BOOLEAN
1845 IsPciDeviceRejected (
1846 IN PCI_IO_DEVICE *PciIoDevice
1849 EFI_STATUS Status;
1850 UINT32 TestValue;
1851 UINT32 OldValue;
1852 UINT32 Mask;
1853 UINT8 BarOffset;
1856 // PPB should be skip!
1858 if (IS_PCI_BRIDGE (&PciIoDevice->Pci)) {
1859 return FALSE;
1862 if (IS_CARDBUS_BRIDGE (&PciIoDevice->Pci)) {
1864 // Only test base registers for P2C
1866 for (BarOffset = 0x1C; BarOffset <= 0x38; BarOffset += 2 * sizeof (UINT32)) {
1868 Mask = (BarOffset < 0x2C) ? 0xFFFFF000 : 0xFFFFFFFC;
1869 Status = BarExisted (PciIoDevice, BarOffset, &TestValue, &OldValue);
1870 if (EFI_ERROR (Status)) {
1871 continue;
1874 TestValue = TestValue & Mask;
1875 if ((TestValue != 0) && (TestValue == (OldValue & Mask))) {
1877 // The bar isn't programed, so it should be rejected
1879 return TRUE;
1883 return FALSE;
1886 for (BarOffset = 0x14; BarOffset <= 0x24; BarOffset += sizeof (UINT32)) {
1888 // Test PCI devices
1890 Status = BarExisted (PciIoDevice, BarOffset, &TestValue, &OldValue);
1891 if (EFI_ERROR (Status)) {
1892 continue;
1895 if ((TestValue & 0x01) != 0) {
1898 // IO Bar
1900 Mask = 0xFFFFFFFC;
1901 TestValue = TestValue & Mask;
1902 if ((TestValue != 0) && (TestValue == (OldValue & Mask))) {
1903 return TRUE;
1906 } else {
1909 // Mem Bar
1911 Mask = 0xFFFFFFF0;
1912 TestValue = TestValue & Mask;
1914 if ((TestValue & 0x07) == 0x04) {
1917 // Mem64 or PMem64
1919 BarOffset += sizeof (UINT32);
1920 if ((TestValue != 0) && (TestValue == (OldValue & Mask))) {
1923 // Test its high 32-Bit BAR
1925 Status = BarExisted (PciIoDevice, BarOffset, &TestValue, &OldValue);
1926 if (TestValue == OldValue) {
1927 return TRUE;
1931 } else {
1934 // Mem32 or PMem32
1936 if ((TestValue != 0) && (TestValue == (OldValue & Mask))) {
1937 return TRUE;
1943 return FALSE;
1947 Reset all bus number from specific bridge.
1949 @param Bridge Parent specific bridge.
1950 @param StartBusNumber Start bus number.
1953 VOID
1954 ResetAllPpbBusNumber (
1955 IN PCI_IO_DEVICE *Bridge,
1956 IN UINT8 StartBusNumber
1959 EFI_STATUS Status;
1960 PCI_TYPE00 Pci;
1961 UINT8 Device;
1962 UINT32 Register;
1963 UINT8 Func;
1964 UINT64 Address;
1965 UINT8 SecondaryBus;
1966 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;
1968 PciRootBridgeIo = Bridge->PciRootBridgeIo;
1970 for (Device = 0; Device <= PCI_MAX_DEVICE; Device++) {
1971 for (Func = 0; Func <= PCI_MAX_FUNC; Func++) {
1974 // Check to see whether a pci device is present
1976 Status = PciDevicePresent (
1977 PciRootBridgeIo,
1978 &Pci,
1979 StartBusNumber,
1980 Device,
1981 Func
1984 if (!EFI_ERROR (Status) && (IS_PCI_BRIDGE (&Pci))) {
1986 Register = 0;
1987 Address = EFI_PCI_ADDRESS (StartBusNumber, Device, Func, 0x18);
1988 Status = PciRootBridgeIo->Pci.Read (
1989 PciRootBridgeIo,
1990 EfiPciWidthUint32,
1991 Address,
1993 &Register
1995 SecondaryBus = (UINT8)(Register >> 8);
1997 if (SecondaryBus != 0) {
1998 ResetAllPpbBusNumber (Bridge, SecondaryBus);
2002 // Reset register 18h, 19h, 1Ah on PCI Bridge
2004 Register &= 0xFF000000;
2005 Status = PciRootBridgeIo->Pci.Write (
2006 PciRootBridgeIo,
2007 EfiPciWidthUint32,
2008 Address,
2010 &Register
2014 if (Func == 0 && !IS_PCI_MULTI_FUNC (&Pci)) {
2016 // Skip sub functions, this is not a multi function device
2018 Func = PCI_MAX_FUNC;