+/** @file\r
+ PCI emumeration support functions implementation for PCI Bus module.\r
+\r
+Copyright (c) 2006 - 2009, Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "PciBus.h"\r
+\r
+/**\r
+ This routine is used to check whether the pci device is present.\r
+\r
+ @param PciRootBridgeIo Pointer to instance of EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.\r
+ @param Pci Output buffer for PCI device configuration space.\r
+ @param Bus PCI bus NO.\r
+ @param Device PCI device NO.\r
+ @param Func PCI Func NO.\r
+\r
+ @retval EFI_NOT_FOUND PCI device not present.\r
+ @retval EFI_SUCCESS PCI device is found.\r
+\r
+**/\r
+EFI_STATUS\r
+PciDevicePresent (\r
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo,\r
+ OUT PCI_TYPE00 *Pci,\r
+ IN UINT8 Bus,\r
+ IN UINT8 Device,\r
+ IN UINT8 Func\r
+ )\r
+{\r
+ UINT64 Address;\r
+ EFI_STATUS Status;\r
+\r
+ //\r
+ // Create PCI address map in terms of Bus, Device and Func\r
+ //\r
+ Address = EFI_PCI_ADDRESS (Bus, Device, Func, 0);\r
+\r
+ //\r
+ // Read the Vendor ID register\r
+ //\r
+ Status = PciRootBridgeIo->Pci.Read (\r
+ PciRootBridgeIo,\r
+ EfiPciWidthUint32,\r
+ Address,\r
+ 1,\r
+ Pci\r
+ );\r
+\r
+ if (!EFI_ERROR (Status) && (Pci->Hdr).VendorId != 0xffff) {\r
+ //\r
+ // Read the entire config header for the device\r
+ //\r
+ Status = PciRootBridgeIo->Pci.Read (\r
+ PciRootBridgeIo,\r
+ EfiPciWidthUint32,\r
+ Address,\r
+ sizeof (PCI_TYPE00) / sizeof (UINT32),\r
+ Pci\r
+ );\r
+\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ return EFI_NOT_FOUND;\r
+}\r
+\r
+/**\r
+ Collect all the resource information under this root bridge.\r
+\r
+ A database that records all the information about pci device subject to this\r
+ root bridge will then be created.\r
+\r
+ @param Bridge Parent bridge instance.\r
+ @param StartBusNumber Bus number of begining.\r
+\r
+ @retval EFI_SUCCESS PCI device is found.\r
+ @retval other Some error occurred when reading PCI bridge information.\r
+\r
+**/\r
+EFI_STATUS\r
+PciPciDeviceInfoCollector (\r
+ IN PCI_IO_DEVICE *Bridge,\r
+ IN UINT8 StartBusNumber\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ PCI_TYPE00 Pci;\r
+ UINT8 Device;\r
+ UINT8 Func;\r
+ UINT8 SecBus;\r
+ PCI_IO_DEVICE *PciIoDevice;\r
+ EFI_PCI_IO_PROTOCOL *PciIo;\r
+\r
+ Status = EFI_SUCCESS;\r
+ SecBus = 0;\r
+\r
+ for (Device = 0; Device <= PCI_MAX_DEVICE; Device++) {\r
+\r
+ for (Func = 0; Func <= PCI_MAX_FUNC; Func++) {\r
+\r
+ //\r
+ // Check to see whether PCI device is present\r
+ //\r
+ Status = PciDevicePresent (\r
+ Bridge->PciRootBridgeIo,\r
+ &Pci,\r
+ (UINT8) StartBusNumber,\r
+ (UINT8) Device,\r
+ (UINT8) Func\r
+ );\r
+ if (!EFI_ERROR (Status)) {\r
+\r
+ //\r
+ // Call back to host bridge function\r
+ //\r
+ PreprocessController (Bridge, (UINT8) StartBusNumber, Device, Func, EfiPciBeforeResourceCollection);\r
+\r
+ //\r
+ // Collect all the information about the PCI device discovered\r
+ //\r
+ Status = PciSearchDevice (\r
+ Bridge,\r
+ &Pci,\r
+ (UINT8) StartBusNumber,\r
+ Device,\r
+ Func,\r
+ &PciIoDevice\r
+ );\r
+\r
+ //\r
+ // Recursively scan PCI busses on the other side of PCI-PCI bridges\r
+ //\r
+ //\r
+ if (!EFI_ERROR (Status) && (IS_PCI_BRIDGE (&Pci) || IS_CARDBUS_BRIDGE (&Pci))) {\r
+\r
+ //\r
+ // If it is PPB, we need to get the secondary bus to continue the enumeration\r
+ //\r
+ PciIo = &(PciIoDevice->PciIo);\r
+\r
+ Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8, PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET, 1, &SecBus);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Get resource padding for PPB\r
+ //\r
+ GetResourcePaddingPpb (PciIoDevice);\r
+\r
+ //\r
+ // Deep enumerate the next level bus\r
+ //\r
+ Status = PciPciDeviceInfoCollector (\r
+ PciIoDevice,\r
+ (UINT8) (SecBus)\r
+ );\r
+\r
+ }\r
+\r
+ if (Func == 0 && !IS_PCI_MULTI_FUNC (&Pci)) {\r
+\r
+ //\r
+ // Skip sub functions, this is not a multi function device\r
+ //\r
+ Func = PCI_MAX_FUNC;\r
+ }\r
+ }\r
+\r
+ }\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Seach required device and create PCI device instance.\r
+\r
+ @param Bridge Parent bridge instance.\r
+ @param Pci Input PCI device information block.\r
+ @param Bus PCI bus NO.\r
+ @param Device PCI device NO.\r
+ @param Func PCI func NO.\r
+ @param PciDevice Output of searched PCI device instance.\r
+\r
+ @retval EFI_SUCCESS Successfully created PCI device instance.\r
+ @retval EFI_OUT_OF_RESOURCES Cannot get PCI device information.\r
+\r
+**/\r
+EFI_STATUS\r
+PciSearchDevice (\r
+ IN PCI_IO_DEVICE *Bridge,\r
+ IN PCI_TYPE00 *Pci,\r
+ IN UINT8 Bus,\r
+ IN UINT8 Device,\r
+ IN UINT8 Func,\r
+ OUT PCI_IO_DEVICE **PciDevice\r
+ )\r
+{\r
+ PCI_IO_DEVICE *PciIoDevice;\r
+\r
+ PciIoDevice = NULL;\r
+\r
+ if (!IS_PCI_BRIDGE (Pci)) {\r
+\r
+ if (IS_CARDBUS_BRIDGE (Pci)) {\r
+ PciIoDevice = GatherP2CInfo (\r
+ Bridge,\r
+ Pci,\r
+ Bus,\r
+ Device,\r
+ Func\r
+ );\r
+ if ((PciIoDevice != NULL) && gFullEnumeration) {\r
+ InitializeP2C (PciIoDevice);\r
+ }\r
+ } else {\r
+\r
+ //\r
+ // Create private data for Pci Device\r
+ //\r
+ PciIoDevice = GatherDeviceInfo (\r
+ Bridge,\r
+ Pci,\r
+ Bus,\r
+ Device,\r
+ Func\r
+ );\r
+\r
+ }\r
+\r
+ } else {\r
+\r
+ //\r
+ // Create private data for PPB\r
+ //\r
+ PciIoDevice = GatherPpbInfo (\r
+ Bridge,\r
+ Pci,\r
+ Bus,\r
+ Device,\r
+ Func\r
+ );\r
+\r
+ //\r
+ // Special initialization for PPB including making the PPB quiet\r
+ //\r
+ if ((PciIoDevice != NULL) && gFullEnumeration) {\r
+ InitializePpb (PciIoDevice);\r
+ }\r
+ }\r
+\r
+ if (PciIoDevice == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ //\r
+ // Update the bar information for this PCI device so as to support some specific device\r
+ //\r
+ UpdatePciInfo (PciIoDevice);\r
+\r
+ if (PciIoDevice->DevicePath == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ //\r
+ // Detect this function has option rom\r
+ //\r
+ if (gFullEnumeration) {\r
+\r
+ if (!IS_CARDBUS_BRIDGE (Pci)) {\r
+\r
+ GetOpRomInfo (PciIoDevice);\r
+\r
+ }\r
+\r
+ ResetPowerManagementFeature (PciIoDevice);\r
+\r
+ }\r
+\r
+ //\r
+ // Insert it into a global tree for future reference\r
+ //\r
+ InsertPciDevice (Bridge, PciIoDevice);\r
+\r
+ //\r
+ // Determine PCI device attributes\r
+ //\r
+\r
+ if (PciDevice != NULL) {\r
+ *PciDevice = PciIoDevice;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Create PCI device instance for PCI device.\r
+\r
+ @param Bridge Parent bridge instance.\r
+ @param Pci Input PCI device information block.\r
+ @param Bus PCI device Bus NO.\r
+ @param Device PCI device Device NO.\r
+ @param Func PCI device's func NO.\r
+\r
+ @return Created PCI device instance.\r
+\r
+**/\r
+PCI_IO_DEVICE *\r
+GatherDeviceInfo (\r
+ IN PCI_IO_DEVICE *Bridge,\r
+ IN PCI_TYPE00 *Pci,\r
+ IN UINT8 Bus,\r
+ IN UINT8 Device,\r
+ IN UINT8 Func\r
+ )\r
+{\r
+ UINTN Offset;\r
+ UINTN BarIndex;\r
+ PCI_IO_DEVICE *PciIoDevice;\r
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;\r
+\r
+ PciRootBridgeIo = Bridge->PciRootBridgeIo;\r
+ PciIoDevice = CreatePciIoDevice (\r
+ PciRootBridgeIo,\r
+ Pci,\r
+ Bus,\r
+ Device,\r
+ Func\r
+ );\r
+\r
+ if (PciIoDevice == NULL) {\r
+ return NULL;\r
+ }\r
+\r
+ //\r
+ // Create a device path for this PCI device and store it into its private data\r
+ //\r
+ CreatePciDevicePath (\r
+ Bridge->DevicePath,\r
+ PciIoDevice\r
+ );\r
+\r
+ //\r
+ // If it is a full enumeration, disconnect the device in advance\r
+ //\r
+ if (gFullEnumeration) {\r
+\r
+ PCI_DISABLE_COMMAND_REGISTER (PciIoDevice, EFI_PCI_COMMAND_BITS_OWNED);\r
+\r
+ }\r
+\r
+ //\r
+ // Start to parse the bars\r
+ //\r
+ for (Offset = 0x10, BarIndex = 0; Offset <= 0x24 && BarIndex < PCI_MAX_BAR; BarIndex++) {\r
+ Offset = PciParseBar (PciIoDevice, Offset, BarIndex);\r
+ }\r
+\r
+ //\r
+ // Parse the SR-IOV VF bars\r
+ //\r
+ if ((PciIoDevice->SrIovCapabilityOffset != 0) && ((FeaturePcdGet(PcdSrIovSupport)& EFI_PCI_IOV_POLICY_SRIOV) != 0)) {\r
+ for (Offset = PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_BAR0, BarIndex = 0;\r
+ Offset <= PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_BAR5;\r
+ BarIndex++) {\r
+\r
+ ASSERT (BarIndex < PCI_MAX_BAR);\r
+ Offset = PciIovParseVfBar (PciIoDevice, Offset, BarIndex);\r
+ }\r
+ }\r
+ return PciIoDevice;\r
+}\r
+\r
+/**\r
+ Create PCI device instance for PCI-PCI bridge.\r
+\r
+ @param Bridge Parent bridge instance.\r
+ @param Pci Input PCI device information block.\r
+ @param Bus PCI device Bus NO.\r
+ @param Device PCI device Device NO.\r
+ @param Func PCI device's func NO.\r
+\r
+ @return Created PCI device instance.\r
+\r
+**/\r
+PCI_IO_DEVICE *\r
+GatherPpbInfo (\r
+ IN PCI_IO_DEVICE *Bridge,\r
+ IN PCI_TYPE00 *Pci,\r
+ IN UINT8 Bus,\r
+ IN UINT8 Device,\r
+ IN UINT8 Func\r
+ )\r
+{\r
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;\r
+ PCI_IO_DEVICE *PciIoDevice;\r
+ EFI_STATUS Status;\r
+ UINT8 Value;\r
+ EFI_PCI_IO_PROTOCOL *PciIo;\r
+ UINT8 Temp;\r
+\r
+ PciRootBridgeIo = Bridge->PciRootBridgeIo;\r
+ PciIoDevice = CreatePciIoDevice (\r
+ PciRootBridgeIo,\r
+ Pci,\r
+ Bus,\r
+ Device,\r
+ Func\r
+ );\r
+\r
+ if (PciIoDevice == NULL) {\r
+ return NULL;\r
+ }\r
+\r
+ //\r
+ // Create a device path for this PCI device and store it into its private data\r
+ //\r
+ CreatePciDevicePath (\r
+ Bridge->DevicePath,\r
+ PciIoDevice\r
+ );\r
+\r
+ if (gFullEnumeration) {\r
+ PCI_DISABLE_COMMAND_REGISTER (PciIoDevice, EFI_PCI_COMMAND_BITS_OWNED);\r
+\r
+ //\r
+ // Initalize the bridge control register\r
+ //\r
+ PCI_DISABLE_BRIDGE_CONTROL_REGISTER (PciIoDevice, EFI_PCI_BRIDGE_CONTROL_BITS_OWNED);\r
+\r
+ }\r
+\r
+ //\r
+ // PPB can have two BARs\r
+ //\r
+ if (PciParseBar (PciIoDevice, 0x10, PPB_BAR_0) == 0x14) {\r
+ //\r
+ // Not 64-bit bar\r
+ //\r
+ PciParseBar (PciIoDevice, 0x14, PPB_BAR_1);\r
+ }\r
+\r
+ PciIo = &PciIoDevice->PciIo;\r
+\r
+ //\r
+ // Test whether it support 32 decode or not\r
+ //\r
+ PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8, 0x1C, 1, &Temp);\r
+ PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x1C, 1, &gAllOne);\r
+ PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8, 0x1C, 1, &Value);\r
+ PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x1C, 1, &Temp);\r
+\r
+ if (Value != 0) {\r
+ if ((Value & 0x01) != 0) {\r
+ PciIoDevice->Decodes |= EFI_BRIDGE_IO32_DECODE_SUPPORTED;\r
+ } else {\r
+ PciIoDevice->Decodes |= EFI_BRIDGE_IO16_DECODE_SUPPORTED;\r
+ }\r
+ }\r
+\r
+ Status = BarExisted (\r
+ PciIoDevice,\r
+ 0x24,\r
+ NULL,\r
+ NULL\r
+ );\r
+\r
+ //\r
+ // Test if it supports 64 memory or not\r
+ //\r
+ if (!EFI_ERROR (Status)) {\r
+\r
+ Status = BarExisted (\r
+ PciIoDevice,\r
+ 0x28,\r
+ NULL,\r
+ NULL\r
+ );\r
+\r
+ if (!EFI_ERROR (Status)) {\r
+ PciIoDevice->Decodes |= EFI_BRIDGE_PMEM32_DECODE_SUPPORTED;\r
+ PciIoDevice->Decodes |= EFI_BRIDGE_PMEM64_DECODE_SUPPORTED;\r
+ } else {\r
+ PciIoDevice->Decodes |= EFI_BRIDGE_PMEM32_DECODE_SUPPORTED;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Memory 32 code is required for ppb\r
+ //\r
+ PciIoDevice->Decodes |= EFI_BRIDGE_MEM32_DECODE_SUPPORTED;\r
+\r
+ GetResourcePaddingPpb (PciIoDevice);\r
+\r
+ return PciIoDevice;\r
+}\r
+\r
+\r
+/**\r
+ Create PCI device instance for PCI Card bridge device.\r
+\r
+ @param Bridge Parent bridge instance.\r
+ @param Pci Input PCI device information block.\r
+ @param Bus PCI device Bus NO.\r
+ @param Device PCI device Device NO.\r
+ @param Func PCI device's func NO.\r
+\r
+ @return Created PCI device instance.\r
+\r
+**/\r
+PCI_IO_DEVICE *\r
+GatherP2CInfo (\r
+ IN PCI_IO_DEVICE *Bridge,\r
+ IN PCI_TYPE00 *Pci,\r
+ IN UINT8 Bus,\r
+ IN UINT8 Device,\r
+ IN UINT8 Func\r
+ )\r
+{\r
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;\r
+ PCI_IO_DEVICE *PciIoDevice;\r
+\r
+ PciRootBridgeIo = Bridge->PciRootBridgeIo;\r
+ PciIoDevice = CreatePciIoDevice (\r
+ PciRootBridgeIo,\r
+ Pci,\r
+ Bus,\r
+ Device,\r
+ Func\r
+ );\r
+\r
+ if (PciIoDevice == NULL) {\r
+ return NULL;\r
+ }\r
+\r
+ //\r
+ // Create a device path for this PCI device and store it into its private data\r
+ //\r
+ CreatePciDevicePath (\r
+ Bridge->DevicePath,\r
+ PciIoDevice\r
+ );\r
+\r
+ if (gFullEnumeration) {\r
+ PCI_DISABLE_COMMAND_REGISTER (PciIoDevice, EFI_PCI_COMMAND_BITS_OWNED);\r
+\r
+ //\r
+ // Initalize the bridge control register\r
+ //\r
+ PCI_DISABLE_BRIDGE_CONTROL_REGISTER (PciIoDevice, EFI_PCCARD_BRIDGE_CONTROL_BITS_OWNED);\r
+ }\r
+\r
+ //\r
+ // P2C only has one bar that is in 0x10\r
+ //\r
+ PciParseBar (PciIoDevice, 0x10, P2C_BAR_0);\r
+\r
+ //\r
+ // Read PciBar information from the bar register\r
+ //\r
+ GetBackPcCardBar (PciIoDevice);\r
+ PciIoDevice->Decodes = EFI_BRIDGE_MEM32_DECODE_SUPPORTED |\r
+ EFI_BRIDGE_PMEM32_DECODE_SUPPORTED |\r
+ EFI_BRIDGE_IO32_DECODE_SUPPORTED;\r
+\r
+ return PciIoDevice;\r
+}\r
+\r
+/**\r
+ Create device path for pci deivce.\r
+\r
+ @param ParentDevicePath Parent bridge's path.\r
+ @param PciIoDevice Pci device instance.\r
+\r
+ @return Device path protocol instance for specific pci device.\r
+\r
+**/\r
+EFI_DEVICE_PATH_PROTOCOL *\r
+CreatePciDevicePath (\r
+ IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath,\r
+ IN PCI_IO_DEVICE *PciIoDevice\r
+ )\r
+{\r
+\r
+ PCI_DEVICE_PATH PciNode;\r
+\r
+ //\r
+ // Create PCI device path\r
+ //\r
+ PciNode.Header.Type = HARDWARE_DEVICE_PATH;\r
+ PciNode.Header.SubType = HW_PCI_DP;\r
+ SetDevicePathNodeLength (&PciNode.Header, sizeof (PciNode));\r
+\r
+ PciNode.Device = PciIoDevice->DeviceNumber;\r
+ PciNode.Function = PciIoDevice->FunctionNumber;\r
+ PciIoDevice->DevicePath = AppendDevicePathNode (ParentDevicePath, &PciNode.Header);\r
+\r
+ return PciIoDevice->DevicePath;\r
+}\r
+\r
+/**\r
+ Check whether the PCI IOV VF bar is existed or not.\r
+\r
+ @param PciIoDevice A pointer to the PCI_IO_DEVICE.\r
+ @param Offset The offset.\r
+ @param BarLengthValue The bar length value returned.\r
+ @param OriginalBarValue The original bar value returned.\r
+\r
+ @retval EFI_NOT_FOUND The bar doesn't exist.\r
+ @retval EFI_SUCCESS The bar exist.\r
+\r
+**/\r
+EFI_STATUS\r
+VfBarExisted (\r
+ IN PCI_IO_DEVICE *PciIoDevice,\r
+ IN UINTN Offset,\r
+ OUT UINT32 *BarLengthValue,\r
+ OUT UINT32 *OriginalBarValue\r
+ )\r
+{\r
+ EFI_PCI_IO_PROTOCOL *PciIo;\r
+ UINT32 OriginalValue;\r
+ UINT32 Value;\r
+ EFI_TPL OldTpl;\r
+\r
+ //\r
+ // Ensure it is called properly\r
+ //\r
+ ASSERT (PciIoDevice->SrIovCapabilityOffset != 0);\r
+ if (PciIoDevice->SrIovCapabilityOffset == 0) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ PciIo = &PciIoDevice->PciIo;\r
+\r
+ //\r
+ // Preserve the original value\r
+ //\r
+\r
+ PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, (UINT32)Offset, 1, &OriginalValue);\r
+\r
+ //\r
+ // Raise TPL to high level to disable timer interrupt while the BAR is probed\r
+ //\r
+ OldTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);\r
+\r
+ PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, (UINT32)Offset, 1, &gAllOne);\r
+ PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, (UINT32)Offset, 1, &Value);\r
+\r
+ //\r
+ // Write back the original value\r
+ //\r
+ PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, (UINT32)Offset, 1, &OriginalValue);\r
+\r
+ //\r
+ // Restore TPL to its original level\r
+ //\r
+ gBS->RestoreTPL (OldTpl);\r
+\r
+ if (BarLengthValue != NULL) {\r
+ *BarLengthValue = Value;\r
+ }\r
+\r
+ if (OriginalBarValue != NULL) {\r
+ *OriginalBarValue = OriginalValue;\r
+ }\r
+\r
+ if (Value == 0) {\r
+ return EFI_NOT_FOUND;\r
+ } else {\r
+ return EFI_SUCCESS;\r
+ }\r
+}\r
+\r
+/**\r
+ Check whether the bar is existed or not.\r
+\r
+ @param PciIoDevice A pointer to the PCI_IO_DEVICE.\r
+ @param Offset The offset.\r
+ @param BarLengthValue The bar length value returned.\r
+ @param OriginalBarValue The original bar value returned.\r
+\r
+ @retval EFI_NOT_FOUND The bar doesn't exist.\r
+ @retval EFI_SUCCESS The bar exist.\r
+\r
+**/\r
+EFI_STATUS\r
+BarExisted (\r
+ IN PCI_IO_DEVICE *PciIoDevice,\r
+ IN UINTN Offset,\r
+ OUT UINT32 *BarLengthValue,\r
+ OUT UINT32 *OriginalBarValue\r
+ )\r
+{\r
+ EFI_PCI_IO_PROTOCOL *PciIo;\r
+ UINT32 OriginalValue;\r
+ UINT32 Value;\r
+ EFI_TPL OldTpl;\r
+\r
+ PciIo = &PciIoDevice->PciIo;\r
+\r
+ //\r
+ // Preserve the original value\r
+ //\r
+ PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, (UINT8) Offset, 1, &OriginalValue);\r
+\r
+ //\r
+ // Raise TPL to high level to disable timer interrupt while the BAR is probed\r
+ //\r
+ OldTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);\r
+\r
+ PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, (UINT8) Offset, 1, &gAllOne);\r
+ PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, (UINT8) Offset, 1, &Value);\r
+\r
+ //\r
+ // Write back the original value\r
+ //\r
+ PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, (UINT8) Offset, 1, &OriginalValue);\r
+\r
+ //\r
+ // Restore TPL to its original level\r
+ //\r
+ gBS->RestoreTPL (OldTpl);\r
+\r
+ if (BarLengthValue != NULL) {\r
+ *BarLengthValue = Value;\r
+ }\r
+\r
+ if (OriginalBarValue != NULL) {\r
+ *OriginalBarValue = OriginalValue;\r
+ }\r
+\r
+ if (Value == 0) {\r
+ return EFI_NOT_FOUND;\r
+ } else {\r
+ return EFI_SUCCESS;\r
+ }\r
+}\r
+\r
+/**\r
+ Test whether the device can support given attributes.\r
+\r
+ @param PciIoDevice Pci device instance.\r
+ @param Command Input command register value, and\r
+ returned supported register value.\r
+ @param BridgeControl Inout bridge control value for PPB or P2C, and\r
+ returned supported bridge control value.\r
+ @param OldCommand Returned and stored old command register offset.\r
+ @param OldBridgeControl Returned and stored old Bridge control value for PPB or P2C.\r
+\r
+**/\r
+VOID\r
+PciTestSupportedAttribute (\r
+ IN PCI_IO_DEVICE *PciIoDevice,\r
+ IN OUT UINT16 *Command,\r
+ IN OUT UINT16 *BridgeControl,\r
+ OUT UINT16 *OldCommand,\r
+ OUT UINT16 *OldBridgeControl\r
+ )\r
+{\r
+ EFI_TPL OldTpl;\r
+\r
+ //\r
+ // Preserve the original value\r
+ //\r
+ PCI_READ_COMMAND_REGISTER (PciIoDevice, OldCommand);\r
+\r
+ //\r
+ // Raise TPL to high level to disable timer interrupt while the BAR is probed\r
+ //\r
+ OldTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);\r
+\r
+ PCI_SET_COMMAND_REGISTER (PciIoDevice, *Command);\r
+ PCI_READ_COMMAND_REGISTER (PciIoDevice, Command);\r
+\r
+ //\r
+ // Write back the original value\r
+ //\r
+ PCI_SET_COMMAND_REGISTER (PciIoDevice, *OldCommand);\r
+\r
+ //\r
+ // Restore TPL to its original level\r
+ //\r
+ gBS->RestoreTPL (OldTpl);\r
+\r
+ if (IS_PCI_BRIDGE (&PciIoDevice->Pci) || IS_CARDBUS_BRIDGE (&PciIoDevice->Pci)) {\r
+\r
+ //\r
+ // Preserve the original value\r
+ //\r
+ PCI_READ_BRIDGE_CONTROL_REGISTER (PciIoDevice, OldBridgeControl);\r
+\r
+ //\r
+ // Raise TPL to high level to disable timer interrupt while the BAR is probed\r
+ //\r
+ OldTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);\r
+\r
+ PCI_SET_BRIDGE_CONTROL_REGISTER (PciIoDevice, *BridgeControl);\r
+ PCI_READ_BRIDGE_CONTROL_REGISTER (PciIoDevice, BridgeControl);\r
+\r
+ //\r
+ // Write back the original value\r
+ //\r
+ PCI_SET_BRIDGE_CONTROL_REGISTER (PciIoDevice, *OldBridgeControl);\r
+\r
+ //\r
+ // Restore TPL to its original level\r
+ //\r
+ gBS->RestoreTPL (OldTpl);\r
+\r
+ } else {\r
+ *OldBridgeControl = 0;\r
+ *BridgeControl = 0;\r
+ }\r
+}\r
+\r
+/**\r
+ Set the supported or current attributes of a PCI device.\r
+\r
+ @param PciIoDevice Structure pointer for PCI device.\r
+ @param Command Command register value.\r
+ @param BridgeControl Bridge control value for PPB or P2C.\r
+ @param Option Make a choice of EFI_SET_SUPPORTS or EFI_SET_ATTRIBUTES.\r
+\r
+**/\r
+VOID\r
+PciSetDeviceAttribute (\r
+ IN PCI_IO_DEVICE *PciIoDevice,\r
+ IN UINT16 Command,\r
+ IN UINT16 BridgeControl,\r
+ IN UINTN Option\r
+ )\r
+{\r
+ UINT64 Attributes;\r
+\r
+ Attributes = 0;\r
+\r
+ if ((Command & EFI_PCI_COMMAND_IO_SPACE) != 0) {\r
+ Attributes |= EFI_PCI_IO_ATTRIBUTE_IO;\r
+ }\r
+\r
+ if ((Command & EFI_PCI_COMMAND_MEMORY_SPACE) != 0) {\r
+ Attributes |= EFI_PCI_IO_ATTRIBUTE_MEMORY;\r
+ }\r
+\r
+ if ((Command & EFI_PCI_COMMAND_BUS_MASTER) != 0) {\r
+ Attributes |= EFI_PCI_IO_ATTRIBUTE_BUS_MASTER;\r
+ }\r
+\r
+ if ((Command & EFI_PCI_COMMAND_VGA_PALETTE_SNOOP) != 0) {\r
+ Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO;\r
+ }\r
+\r
+ if ((BridgeControl & EFI_PCI_BRIDGE_CONTROL_ISA) != 0) {\r
+ Attributes |= EFI_PCI_IO_ATTRIBUTE_ISA_IO;\r
+ }\r
+\r
+ if ((BridgeControl & EFI_PCI_BRIDGE_CONTROL_VGA) != 0) {\r
+ Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_IO;\r
+ Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY;\r
+ Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO;\r
+ }\r
+\r
+ if ((BridgeControl & EFI_PCI_BRIDGE_CONTROL_VGA_16) != 0) {\r
+ Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_IO_16;\r
+ Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO_16;\r
+ }\r
+\r
+ if (Option == EFI_SET_SUPPORTS) {\r
+\r
+ Attributes |= EFI_PCI_IO_ATTRIBUTE_MEMORY_WRITE_COMBINE |\r
+ EFI_PCI_IO_ATTRIBUTE_MEMORY_CACHED |\r
+ EFI_PCI_IO_ATTRIBUTE_MEMORY_DISABLE |\r
+ EFI_PCI_IO_ATTRIBUTE_EMBEDDED_DEVICE |\r
+ EFI_PCI_IO_ATTRIBUTE_EMBEDDED_ROM |\r
+ EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE;\r
+\r
+ if ((Attributes & EFI_PCI_IO_ATTRIBUTE_IO) != 0) {\r
+ Attributes |= EFI_PCI_IO_ATTRIBUTE_ISA_MOTHERBOARD_IO;\r
+ Attributes |= EFI_PCI_IO_ATTRIBUTE_ISA_IO;\r
+ }\r
+\r
+ if (IS_PCI_BRIDGE (&PciIoDevice->Pci) || IS_CARDBUS_BRIDGE (&PciIoDevice->Pci)) {\r
+ //\r
+ // For bridge, it should support IDE attributes\r
+ //\r
+ Attributes |= EFI_PCI_IO_ATTRIBUTE_IDE_SECONDARY_IO;\r
+ Attributes |= EFI_PCI_IO_ATTRIBUTE_IDE_PRIMARY_IO;\r
+ } else {\r
+\r
+ if (IS_PCI_IDE (&PciIoDevice->Pci)) {\r
+ Attributes |= EFI_PCI_IO_ATTRIBUTE_IDE_SECONDARY_IO;\r
+ Attributes |= EFI_PCI_IO_ATTRIBUTE_IDE_PRIMARY_IO;\r
+ }\r
+\r
+ if (IS_PCI_VGA (&PciIoDevice->Pci)) {\r
+ Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY;\r
+ Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_IO;\r
+ }\r
+ }\r
+\r
+ PciIoDevice->Supports = Attributes;\r
+ PciIoDevice->Supports &= ( (PciIoDevice->Parent->Supports) | \\r
+ EFI_PCI_IO_ATTRIBUTE_IO | EFI_PCI_IO_ATTRIBUTE_MEMORY | \\r
+ EFI_PCI_IO_ATTRIBUTE_BUS_MASTER );\r
+\r
+ } else {\r
+ PciIoDevice->Attributes = Attributes;\r
+ }\r
+}\r
+\r
+/**\r
+ Determine if the device can support Fast Back to Back attribute.\r
+\r
+ @param PciIoDevice Pci device instance.\r
+ @param StatusIndex Status register value.\r
+\r
+ @retval EFI_SUCCESS This device support Fast Back to Back attribute.\r
+ @retval EFI_UNSUPPORTED This device doesn't support Fast Back to Back attribute.\r
+\r
+**/\r
+EFI_STATUS\r
+GetFastBackToBackSupport (\r
+ IN PCI_IO_DEVICE *PciIoDevice,\r
+ IN UINT8 StatusIndex\r
+ )\r
+{\r
+ EFI_PCI_IO_PROTOCOL *PciIo;\r
+ EFI_STATUS Status;\r
+ UINT32 StatusRegister;\r
+\r
+ //\r
+ // Read the status register\r
+ //\r
+ PciIo = &PciIoDevice->PciIo;\r
+ Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint16, StatusIndex, 1, &StatusRegister);\r
+ if (EFI_ERROR (Status)) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ //\r
+ // Check the Fast B2B bit\r
+ //\r
+ if ((StatusRegister & EFI_PCI_FAST_BACK_TO_BACK_CAPABLE) != 0) {\r
+ return EFI_SUCCESS;\r
+ } else {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+}\r
+\r
+/**\r
+ Process the option ROM for all the children of the specified parent PCI device.\r
+ It can only be used after the first full Option ROM process.\r
+\r
+ @param PciIoDevice Pci device instance.\r
+\r
+**/\r
+VOID\r
+ProcessOptionRomLight (\r
+ IN PCI_IO_DEVICE *PciIoDevice\r
+ )\r
+{\r
+ PCI_IO_DEVICE *Temp;\r
+ LIST_ENTRY *CurrentLink;\r
+\r
+ //\r
+ // For RootBridge, PPB , P2C, go recursively to traverse all its children\r
+ //\r
+ CurrentLink = PciIoDevice->ChildList.ForwardLink;\r
+ while (CurrentLink != NULL && CurrentLink != &PciIoDevice->ChildList) {\r
+\r
+ Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
+\r
+ if (!IsListEmpty (&Temp->ChildList)) {\r
+ ProcessOptionRomLight (Temp);\r
+ }\r
+\r
+ PciRomGetImageMapping (Temp);\r
+\r
+ //\r
+ // The OpRom has already been processed in the first round\r
+ //\r
+ Temp->AllOpRomProcessed = TRUE;\r
+\r
+ CurrentLink = CurrentLink->ForwardLink;\r
+ }\r
+}\r
+\r
+/**\r
+ Determine the related attributes of all devices under a Root Bridge.\r
+\r
+ @param PciIoDevice PCI device instance.\r
+\r
+**/\r
+EFI_STATUS\r
+DetermineDeviceAttribute (\r
+ IN PCI_IO_DEVICE *PciIoDevice\r
+ )\r
+{\r
+ UINT16 Command;\r
+ UINT16 BridgeControl;\r
+ UINT16 OldCommand;\r
+ UINT16 OldBridgeControl;\r
+ BOOLEAN FastB2BSupport;\r
+ PCI_IO_DEVICE *Temp;\r
+ LIST_ENTRY *CurrentLink;\r
+ EFI_STATUS Status;\r
+\r
+ //\r
+ // For Root Bridge, just copy it by RootBridgeIo proctocol\r
+ // so as to keep consistent with the actual attribute\r
+ //\r
+ if (PciIoDevice->Parent == NULL) {\r
+ Status = PciIoDevice->PciRootBridgeIo->GetAttributes (\r
+ PciIoDevice->PciRootBridgeIo,\r
+ &PciIoDevice->Supports,\r
+ &PciIoDevice->Attributes\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ } else {\r
+\r
+ //\r
+ // Set the attributes to be checked for common PCI devices and PPB or P2C\r
+ // Since some devices only support part of them, it is better to set the\r
+ // attribute according to its command or bridge control register\r
+ //\r
+ Command = EFI_PCI_COMMAND_IO_SPACE |\r
+ EFI_PCI_COMMAND_MEMORY_SPACE |\r
+ EFI_PCI_COMMAND_BUS_MASTER |\r
+ EFI_PCI_COMMAND_VGA_PALETTE_SNOOP;\r
+\r
+ BridgeControl = EFI_PCI_BRIDGE_CONTROL_ISA | EFI_PCI_BRIDGE_CONTROL_VGA | EFI_PCI_BRIDGE_CONTROL_VGA_16;\r
+\r
+ //\r
+ // Test whether the device can support attributes above\r
+ //\r
+ PciTestSupportedAttribute (PciIoDevice, &Command, &BridgeControl, &OldCommand, &OldBridgeControl);\r
+\r
+ //\r
+ // Set the supported attributes for specified PCI device\r
+ //\r
+ PciSetDeviceAttribute (PciIoDevice, Command, BridgeControl, EFI_SET_SUPPORTS);\r
+\r
+ //\r
+ // Set the current attributes for specified PCI device\r
+ //\r
+ PciSetDeviceAttribute (PciIoDevice, OldCommand, OldBridgeControl, EFI_SET_ATTRIBUTES);\r
+\r
+ //\r
+ // Enable other supported attributes but not defined in PCI_IO_PROTOCOL\r
+ //\r
+ PCI_ENABLE_COMMAND_REGISTER (PciIoDevice, EFI_PCI_COMMAND_MEMORY_WRITE_AND_INVALIDATE);\r
+ }\r
+\r
+ FastB2BSupport = TRUE;\r
+\r
+ //\r
+ // P2C can not support FB2B on the secondary side\r
+ //\r
+ if (IS_CARDBUS_BRIDGE (&PciIoDevice->Pci)) {\r
+ FastB2BSupport = FALSE;\r
+ }\r
+\r
+ //\r
+ // For RootBridge, PPB , P2C, go recursively to traverse all its children\r
+ //\r
+ CurrentLink = PciIoDevice->ChildList.ForwardLink;\r
+ while (CurrentLink != NULL && CurrentLink != &PciIoDevice->ChildList) {\r
+\r
+ Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
+ Status = DetermineDeviceAttribute (Temp);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ //\r
+ // Detect Fast Bact to Bact support for the device under the bridge\r
+ //\r
+ Status = GetFastBackToBackSupport (Temp, PCI_PRIMARY_STATUS_OFFSET);\r
+ if (FastB2BSupport && EFI_ERROR (Status)) {\r
+ FastB2BSupport = FALSE;\r
+ }\r
+\r
+ CurrentLink = CurrentLink->ForwardLink;\r
+ }\r
+ //\r
+ // Set or clear Fast Back to Back bit for the whole bridge\r
+ //\r
+ if (!IsListEmpty (&PciIoDevice->ChildList)) {\r
+\r
+ if (IS_PCI_BRIDGE (&PciIoDevice->Pci)) {\r
+\r
+ Status = GetFastBackToBackSupport (PciIoDevice, PCI_BRIDGE_STATUS_REGISTER_OFFSET);\r
+\r
+ if (EFI_ERROR (Status) || (!FastB2BSupport)) {\r
+ FastB2BSupport = FALSE;\r
+ PCI_DISABLE_BRIDGE_CONTROL_REGISTER (PciIoDevice, EFI_PCI_BRIDGE_CONTROL_FAST_BACK_TO_BACK);\r
+ } else {\r
+ PCI_ENABLE_BRIDGE_CONTROL_REGISTER (PciIoDevice, EFI_PCI_BRIDGE_CONTROL_FAST_BACK_TO_BACK);\r
+ }\r
+ }\r
+\r
+ CurrentLink = PciIoDevice->ChildList.ForwardLink;\r
+ while (CurrentLink != NULL && CurrentLink != &PciIoDevice->ChildList) {\r
+ Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);\r
+ if (FastB2BSupport) {\r
+ PCI_ENABLE_COMMAND_REGISTER (Temp, EFI_PCI_COMMAND_FAST_BACK_TO_BACK);\r
+ } else {\r
+ PCI_DISABLE_COMMAND_REGISTER (Temp, EFI_PCI_COMMAND_FAST_BACK_TO_BACK);\r
+ }\r
+\r
+ CurrentLink = CurrentLink->ForwardLink;\r
+ }\r
+ }\r
+ //\r
+ // End for IsListEmpty\r
+ //\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ This routine is used to update the bar information for those incompatible PCI device.\r
+\r
+ @param PciIoDevice Input Pci device instance. Output Pci device instance with updated\r
+ Bar information.\r
+\r
+ @retval EFI_SUCCESS Successfully updated bar information.\r
+ @retval EFI_UNSUPPORTED Given PCI device doesn't belong to incompatible PCI device list.\r
+\r
+**/\r
+EFI_STATUS\r
+UpdatePciInfo (\r
+ IN OUT PCI_IO_DEVICE *PciIoDevice\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINTN BarIndex;\r
+ UINTN BarEndIndex;\r
+ BOOLEAN SetFlag;\r
+ VOID *Configuration;\r
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Ptr;\r
+\r
+ Configuration = NULL;\r
+ Status = EFI_SUCCESS;\r
+\r
+ if (gEfiIncompatiblePciDeviceSupport == NULL) {\r
+ //\r
+ // It can only be supported after the Incompatible PCI Device\r
+ // Support Protocol has been installed\r
+ //\r
+ Status = gBS->LocateProtocol (\r
+ &gEfiIncompatiblePciDeviceSupportProtocolGuid,\r
+ NULL,\r
+ (VOID **) &gEfiIncompatiblePciDeviceSupport\r
+ );\r
+ }\r
+ if (Status == EFI_SUCCESS) {\r
+ //\r
+ // Check whether the device belongs to incompatible devices from protocol or not\r
+ // If it is , then get its special requirement in the ACPI table\r
+ //\r
+ Status = gEfiIncompatiblePciDeviceSupport->CheckDevice (\r
+ gEfiIncompatiblePciDeviceSupport,\r
+ PciIoDevice->Pci.Hdr.VendorId,\r
+ PciIoDevice->Pci.Hdr.DeviceId,\r
+ PciIoDevice->Pci.Hdr.RevisionID,\r
+ PciIoDevice->Pci.Device.SubsystemVendorID,\r
+ PciIoDevice->Pci.Device.SubsystemID,\r
+ &Configuration\r
+ );\r
+\r
+ }\r
+\r
+ if (EFI_ERROR (Status) || Configuration == NULL ) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ //\r
+ // Update PCI device information from the ACPI table\r
+ //\r
+ Ptr = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Configuration;\r
+\r
+ while (Ptr->Desc != ACPI_END_TAG_DESCRIPTOR) {\r
+\r
+ if (Ptr->Desc != ACPI_ADDRESS_SPACE_DESCRIPTOR) {\r
+ //\r
+ // The format is not support\r
+ //\r
+ break;\r
+ }\r
+\r
+ BarIndex = (UINTN) Ptr->AddrTranslationOffset;\r
+ BarEndIndex = BarIndex;\r
+\r
+ //\r
+ // Update all the bars in the device\r
+ //\r
+ if (BarIndex == PCI_BAR_ALL) {\r
+ BarIndex = 0;\r
+ BarEndIndex = PCI_MAX_BAR - 1;\r
+ }\r
+\r
+ if (BarIndex > PCI_MAX_BAR) {\r
+ Ptr++;\r
+ continue;\r
+ }\r
+\r
+ for (; BarIndex <= BarEndIndex; BarIndex++) {\r
+ SetFlag = FALSE;\r
+ switch (Ptr->ResType) {\r
+ case ACPI_ADDRESS_SPACE_TYPE_MEM:\r
+\r
+ //\r
+ // Make sure the bar is memory type\r
+ //\r
+ if (CheckBarType (PciIoDevice, (UINT8) BarIndex, PciBarTypeMem)) {\r
+ SetFlag = TRUE;\r
+ }\r
+ break;\r
+\r
+ case ACPI_ADDRESS_SPACE_TYPE_IO:\r
+\r
+ //\r
+ // Make sure the bar is IO type\r
+ //\r
+ if (CheckBarType (PciIoDevice, (UINT8) BarIndex, PciBarTypeIo)) {\r
+ SetFlag = TRUE;\r
+ }\r
+ break;\r
+ }\r
+\r
+ if (SetFlag) {\r
+\r
+ //\r
+ // Update the new alignment for the device\r
+ //\r
+ SetNewAlign (&(PciIoDevice->PciBar[BarIndex].Alignment), Ptr->AddrRangeMax);\r
+\r
+ //\r
+ // Update the new length for the device\r
+ //\r
+ if (Ptr->AddrLen != PCI_BAR_NOCHANGE) {\r
+ PciIoDevice->PciBar[BarIndex].Length = Ptr->AddrLen;\r
+ }\r
+ }\r
+ }\r
+\r
+ Ptr++;\r
+ }\r
+\r
+ FreePool (Configuration);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ This routine will update the alignment with the new alignment.\r
+\r
+ @param Alignment Input Old alignment. Output updated alignment.\r
+ @param NewAlignment New alignment.\r
+\r
+**/\r
+VOID\r
+SetNewAlign (\r
+ IN OUT UINT64 *Alignment,\r
+ IN UINT64 NewAlignment\r
+ )\r
+{\r
+ UINT64 OldAlignment;\r
+ UINTN ShiftBit;\r
+\r
+ //\r
+ // The new alignment is the same as the original,\r
+ // so skip it\r
+ //\r
+ if (NewAlignment == PCI_BAR_OLD_ALIGN) {\r
+ return ;\r
+ }\r
+ //\r
+ // Check the validity of the parameter\r
+ //\r
+ if (NewAlignment != PCI_BAR_EVEN_ALIGN &&\r
+ NewAlignment != PCI_BAR_SQUAD_ALIGN &&\r
+ NewAlignment != PCI_BAR_DQUAD_ALIGN ) {\r
+ *Alignment = NewAlignment;\r
+ return ;\r
+ }\r
+\r
+ OldAlignment = (*Alignment) + 1;\r
+ ShiftBit = 0;\r
+\r
+ //\r
+ // Get the first non-zero hex value of the length\r
+ //\r
+ while ((OldAlignment & 0x0F) == 0x00) {\r
+ OldAlignment = RShiftU64 (OldAlignment, 4);\r
+ ShiftBit += 4;\r
+ }\r
+\r
+ //\r
+ // Adjust the alignment to even, quad or double quad boundary\r
+ //\r
+ if (NewAlignment == PCI_BAR_EVEN_ALIGN) {\r
+ if ((OldAlignment & 0x01) != 0) {\r
+ OldAlignment = OldAlignment + 2 - (OldAlignment & 0x01);\r
+ }\r
+ } else if (NewAlignment == PCI_BAR_SQUAD_ALIGN) {\r
+ if ((OldAlignment & 0x03) != 0) {\r
+ OldAlignment = OldAlignment + 4 - (OldAlignment & 0x03);\r
+ }\r
+ } else if (NewAlignment == PCI_BAR_DQUAD_ALIGN) {\r
+ if ((OldAlignment & 0x07) != 0) {\r
+ OldAlignment = OldAlignment + 8 - (OldAlignment & 0x07);\r
+ }\r
+ }\r
+\r
+ //\r
+ // Update the old value\r
+ //\r
+ NewAlignment = LShiftU64 (OldAlignment, ShiftBit) - 1;\r
+ *Alignment = NewAlignment;\r
+\r
+ return ;\r
+}\r
+\r
+/**\r
+ Parse PCI IOV VF bar information and fill them into PCI device instance.\r
+\r
+ @param PciIoDevice Pci device instance.\r
+ @param Offset Bar offset.\r
+ @param BarIndex Bar index.\r
+\r
+ @return Next bar offset.\r
+\r
+**/\r
+UINTN\r
+PciIovParseVfBar (\r
+ IN PCI_IO_DEVICE *PciIoDevice,\r
+ IN UINTN Offset,\r
+ IN UINTN BarIndex\r
+ )\r
+{\r
+ UINT32 Value;\r
+ UINT32 OriginalValue;\r
+ UINT32 Mask;\r
+ UINT32 Data;\r
+ UINT8 Index;\r
+ EFI_STATUS Status;\r
+\r
+ //\r
+ // Ensure it is called properly\r
+ //\r
+ ASSERT (PciIoDevice->SrIovCapabilityOffset != 0);\r
+ if (PciIoDevice->SrIovCapabilityOffset == 0) {\r
+ return 0;\r
+ }\r
+\r
+ OriginalValue = 0;\r
+ Value = 0;\r
+\r
+ Status = VfBarExisted (\r
+ PciIoDevice,\r
+ Offset,\r
+ &Value,\r
+ &OriginalValue\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ PciIoDevice->VfPciBar[BarIndex].BaseAddress = 0;\r
+ PciIoDevice->VfPciBar[BarIndex].Length = 0;\r
+ PciIoDevice->VfPciBar[BarIndex].Alignment = 0;\r
+\r
+ //\r
+ // Scan all the BARs anyway\r
+ //\r
+ PciIoDevice->VfPciBar[BarIndex].Offset = (UINT8) Offset;\r
+ return Offset + 4;\r
+ }\r
+\r
+ PciIoDevice->VfPciBar[BarIndex].Offset = (UINT8) Offset;\r
+ if (Value & 0x01) {\r
+ //\r
+ // Device I/Os. Impossible\r
+ //\r
+ ASSERT (FALSE);\r
+ return Offset + 4;\r
+\r
+ } else {\r
+\r
+ Mask = 0xfffffff0;\r
+\r
+ PciIoDevice->VfPciBar[BarIndex].BaseAddress = OriginalValue & Mask;\r
+\r
+ switch (Value & 0x07) {\r
+\r
+ //\r
+ //memory space; anywhere in 32 bit address space\r
+ //\r
+ case 0x00:\r
+ if (Value & 0x08) {\r
+ PciIoDevice->VfPciBar[BarIndex].BarType = PciBarTypePMem32;\r
+ } else {\r
+ PciIoDevice->VfPciBar[BarIndex].BarType = PciBarTypeMem32;\r
+ }\r
+\r
+ PciIoDevice->VfPciBar[BarIndex].Length = (~(Value & Mask)) + 1;\r
+ PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->VfPciBar[BarIndex].Length - 1;\r
+\r
+ //\r
+ // Adjust Length\r
+ //\r
+ PciIoDevice->VfPciBar[BarIndex].Length = MultU64x32 (PciIoDevice->VfPciBar[BarIndex].Length, PciIoDevice->InitialVFs);\r
+ //\r
+ // Adjust Alignment\r
+ //\r
+ if (PciIoDevice->VfPciBar[BarIndex].Alignment < PciIoDevice->SystemPageSize - 1) {\r
+ PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->SystemPageSize - 1;\r
+ }\r
+\r
+ break;\r
+\r
+ //\r
+ // memory space; anywhere in 64 bit address space\r
+ //\r
+ case 0x04:\r
+ if (Value & 0x08) {\r
+ PciIoDevice->VfPciBar[BarIndex].BarType = PciBarTypePMem64;\r
+ } else {\r
+ PciIoDevice->VfPciBar[BarIndex].BarType = PciBarTypeMem64;\r
+ }\r
+\r
+ //\r
+ // According to PCI 2.2,if the bar indicates a memory 64 decoding, next bar\r
+ // is regarded as an extension for the first bar. As a result\r
+ // the sizing will be conducted on combined 64 bit value\r
+ // Here just store the masked first 32bit value for future size\r
+ // calculation\r
+ //\r
+ PciIoDevice->VfPciBar[BarIndex].Length = Value & Mask;\r
+ PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->VfPciBar[BarIndex].Length - 1;\r
+\r
+ if (PciIoDevice->VfPciBar[BarIndex].Alignment < PciIoDevice->SystemPageSize - 1) {\r
+ PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->SystemPageSize - 1;\r
+ }\r
+\r
+ //\r
+ // Increment the offset to point to next DWORD\r
+ //\r
+ Offset += 4;\r
+\r
+ Status = VfBarExisted (\r
+ PciIoDevice,\r
+ Offset,\r
+ &Value,\r
+ &OriginalValue\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Offset + 4;\r
+ }\r
+\r
+ //\r
+ // Fix the length to support some spefic 64 bit BAR\r
+ //\r
+ Data = Value;\r
+ Index = 0;\r
+ for (Data = Value; Data != 0; Data >>= 1) {\r
+ Index ++;\r
+ }\r
+ Value |= ((UINT32)(-1) << Index); \r
+\r
+ //\r
+ // Calculate the size of 64bit bar\r
+ //\r
+ PciIoDevice->VfPciBar[BarIndex].BaseAddress |= LShiftU64 ((UINT64) OriginalValue, 32);\r
+\r
+ PciIoDevice->VfPciBar[BarIndex].Length = PciIoDevice->VfPciBar[BarIndex].Length | LShiftU64 ((UINT64) Value, 32);\r
+ PciIoDevice->VfPciBar[BarIndex].Length = (~(PciIoDevice->VfPciBar[BarIndex].Length)) + 1;\r
+ PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->VfPciBar[BarIndex].Length - 1;\r
+\r
+ //\r
+ // Adjust Length\r
+ //\r
+ PciIoDevice->VfPciBar[BarIndex].Length = MultU64x32 (PciIoDevice->VfPciBar[BarIndex].Length, PciIoDevice->InitialVFs);\r
+ //\r
+ // Adjust Alignment\r
+ //\r
+ if (PciIoDevice->VfPciBar[BarIndex].Alignment < PciIoDevice->SystemPageSize - 1) {\r
+ PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->SystemPageSize - 1;\r
+ }\r
+\r
+ break;\r
+\r
+ //\r
+ // reserved\r
+ //\r
+ default:\r
+ PciIoDevice->VfPciBar[BarIndex].BarType = PciBarTypeUnknown;\r
+ PciIoDevice->VfPciBar[BarIndex].Length = (~(Value & Mask)) + 1;\r
+ PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->VfPciBar[BarIndex].Length - 1;\r
+\r
+ if (PciIoDevice->VfPciBar[BarIndex].Alignment < PciIoDevice->SystemPageSize - 1) {\r
+ PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->SystemPageSize - 1;\r
+ }\r
+\r
+ break;\r
+ }\r
+ }\r
+ \r
+ //\r
+ // Check the length again so as to keep compatible with some special bars\r
+ //\r
+ if (PciIoDevice->VfPciBar[BarIndex].Length == 0) {\r
+ PciIoDevice->VfPciBar[BarIndex].BarType = PciBarTypeUnknown;\r
+ PciIoDevice->VfPciBar[BarIndex].BaseAddress = 0;\r
+ PciIoDevice->VfPciBar[BarIndex].Alignment = 0;\r
+ }\r
+ \r
+ //\r
+ // Increment number of bar\r
+ //\r
+ return Offset + 4;\r
+}\r
+\r
+/**\r
+ Parse PCI bar information and fill them into PCI device instance.\r
+\r
+ @param PciIoDevice Pci device instance.\r
+ @param Offset Bar offset.\r
+ @param BarIndex Bar index.\r
+\r
+ @return Next bar offset.\r
+\r
+**/\r
+UINTN\r
+PciParseBar (\r
+ IN PCI_IO_DEVICE *PciIoDevice,\r
+ IN UINTN Offset,\r
+ IN UINTN BarIndex\r
+ )\r
+{\r
+ UINT32 Value;\r
+ UINT32 OriginalValue;\r
+ UINT32 Mask;\r
+ UINT32 Data;\r
+ UINT8 Index;\r
+ EFI_STATUS Status;\r
+\r
+ OriginalValue = 0;\r
+ Value = 0;\r
+\r
+ Status = BarExisted (\r
+ PciIoDevice,\r
+ Offset,\r
+ &Value,\r
+ &OriginalValue\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ PciIoDevice->PciBar[BarIndex].BaseAddress = 0;\r
+ PciIoDevice->PciBar[BarIndex].Length = 0;\r
+ PciIoDevice->PciBar[BarIndex].Alignment = 0;\r
+\r
+ //\r
+ // Some devices don't fully comply to PCI spec 2.2. So be to scan all the BARs anyway\r
+ //\r
+ PciIoDevice->PciBar[BarIndex].Offset = (UINT8) Offset;\r
+ return Offset + 4;\r
+ }\r
+\r
+ PciIoDevice->PciBar[BarIndex].Offset = (UINT8) Offset;\r
+ if ((Value & 0x01) != 0) {\r
+ //\r
+ // Device I/Os\r
+ //\r
+ Mask = 0xfffffffc;\r
+\r
+ if ((Value & 0xFFFF0000) != 0) {\r
+ //\r
+ // It is a IO32 bar\r
+ //\r
+ PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeIo32;\r
+ PciIoDevice->PciBar[BarIndex].Length = ((~(Value & Mask)) + 1);\r
+ PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;\r
+\r
+ } else {\r
+ //\r
+ // It is a IO16 bar\r
+ //\r
+ PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeIo16;\r
+ PciIoDevice->PciBar[BarIndex].Length = 0x0000FFFF & ((~(Value & Mask)) + 1);\r
+ PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;\r
+\r
+ }\r
+ //\r
+ // Workaround. Some platforms inplement IO bar with 0 length\r
+ // Need to treat it as no-bar\r
+ //\r
+ if (PciIoDevice->PciBar[BarIndex].Length == 0) {\r
+ PciIoDevice->PciBar[BarIndex].BarType = (PCI_BAR_TYPE) 0;\r
+ }\r
+\r
+ PciIoDevice->PciBar[BarIndex].Prefetchable = FALSE;\r
+ PciIoDevice->PciBar[BarIndex].BaseAddress = OriginalValue & Mask;\r
+\r
+ } else {\r
+\r
+ Mask = 0xfffffff0;\r
+\r
+ PciIoDevice->PciBar[BarIndex].BaseAddress = OriginalValue & Mask;\r
+\r
+ switch (Value & 0x07) {\r
+\r
+ //\r
+ //memory space; anywhere in 32 bit address space\r
+ //\r
+ case 0x00:\r
+ if ((Value & 0x08) != 0) {\r
+ PciIoDevice->PciBar[BarIndex].BarType = PciBarTypePMem32;\r
+ } else {\r
+ PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeMem32;\r
+ }\r
+\r
+ PciIoDevice->PciBar[BarIndex].Length = (~(Value & Mask)) + 1;\r
+ if (PciIoDevice->PciBar[BarIndex].Length < (SIZE_4KB)) {\r
+ //\r
+ // Force minimum 4KByte alignment for Virtualization technology for Directed I/O\r
+ //\r
+ PciIoDevice->PciBar[BarIndex].Alignment = (SIZE_4KB - 1);\r
+ } else {\r
+ PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;\r
+ }\r
+ break;\r
+\r
+ //\r
+ // memory space; anywhere in 64 bit address space\r
+ //\r
+ case 0x04:\r
+ if ((Value & 0x08) != 0) {\r
+ PciIoDevice->PciBar[BarIndex].BarType = PciBarTypePMem64;\r
+ } else {\r
+ PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeMem64;\r
+ }\r
+\r
+ //\r
+ // According to PCI 2.2,if the bar indicates a memory 64 decoding, next bar\r
+ // is regarded as an extension for the first bar. As a result\r
+ // the sizing will be conducted on combined 64 bit value\r
+ // Here just store the masked first 32bit value for future size\r
+ // calculation\r
+ //\r
+ PciIoDevice->PciBar[BarIndex].Length = Value & Mask;\r
+ PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;\r
+\r
+ //\r
+ // Increment the offset to point to next DWORD\r
+ //\r
+ Offset += 4;\r
+\r
+ Status = BarExisted (\r
+ PciIoDevice,\r
+ Offset,\r
+ &Value,\r
+ &OriginalValue\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ //\r
+ // the high 32 bit does not claim any BAR, we need to re-check the low 32 bit BAR again\r
+ //\r
+ if (PciIoDevice->PciBar[BarIndex].Length == 0) {\r
+ //\r
+ // some device implement MMIO bar with 0 length, need to treat it as no-bar\r
+ //\r
+ PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeUnknown;\r
+ }\r
+ return Offset + 4;\r
+ }\r
+\r
+ //\r
+ // Fix the length to support some spefic 64 bit BAR\r
+ //\r
+ Data = Value;\r
+ Index = 0;\r
+ for (Data = Value; Data != 0; Data >>= 1) {\r
+ Index ++;\r
+ }\r
+ Value |= ((UINT32)(-1) << Index);\r
+\r
+ //\r
+ // Calculate the size of 64bit bar\r
+ //\r
+ PciIoDevice->PciBar[BarIndex].BaseAddress |= LShiftU64 ((UINT64) OriginalValue, 32);\r
+\r
+ PciIoDevice->PciBar[BarIndex].Length = PciIoDevice->PciBar[BarIndex].Length | LShiftU64 ((UINT64) Value, 32);\r
+ PciIoDevice->PciBar[BarIndex].Length = (~(PciIoDevice->PciBar[BarIndex].Length)) + 1;\r
+ if (PciIoDevice->PciBar[BarIndex].Length < (SIZE_4KB)) {\r
+ //\r
+ // Force minimum 4KByte alignment for Virtualization technology for Directed I/O\r
+ //\r
+ PciIoDevice->PciBar[BarIndex].Alignment = (SIZE_4KB - 1);\r
+ } else {\r
+ PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;\r
+ }\r
+\r
+ break;\r
+\r
+ //\r
+ // reserved\r
+ //\r
+ default:\r
+ PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeUnknown;\r
+ PciIoDevice->PciBar[BarIndex].Length = (~(Value & Mask)) + 1;\r
+ if (PciIoDevice->PciBar[BarIndex].Length < (SIZE_4KB)) {\r
+ //\r
+ // Force minimum 4KByte alignment for Virtualization technology for Directed I/O\r
+ //\r
+ PciIoDevice->PciBar[BarIndex].Alignment = (SIZE_4KB - 1);\r
+ } else {\r
+ PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1;\r
+ }\r
+ break;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Check the length again so as to keep compatible with some special bars\r
+ //\r
+ if (PciIoDevice->PciBar[BarIndex].Length == 0) {\r
+ PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeUnknown;\r
+ PciIoDevice->PciBar[BarIndex].BaseAddress = 0;\r
+ PciIoDevice->PciBar[BarIndex].Alignment = 0;\r
+ }\r
+\r
+ //\r
+ // Increment number of bar\r
+ //\r
+ return Offset + 4;\r
+}\r
+\r
+/**\r
+ This routine is used to initialize the bar of a PCI device.\r
+\r
+ @param PciIoDevice Pci device instance.\r
+\r
+ @note It can be called typically when a device is going to be rejected.\r
+\r
+**/\r
+VOID\r
+InitializePciDevice (\r
+ IN PCI_IO_DEVICE *PciIoDevice\r
+ )\r
+{\r
+ EFI_PCI_IO_PROTOCOL *PciIo;\r
+ UINT8 Offset;\r
+\r
+ PciIo = &(PciIoDevice->PciIo);\r
+\r
+ //\r
+ // Put all the resource apertures\r
+ // Resource base is set to all ones so as to indicate its resource\r
+ // has not been alloacted\r
+ //\r
+ for (Offset = 0x10; Offset <= 0x24; Offset += sizeof (UINT32)) {\r
+ PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, Offset, 1, &gAllOne);\r
+ }\r
+}\r
+\r
+/**\r
+ This routine is used to initialize the bar of a PCI-PCI Bridge device.\r
+\r
+ @param PciIoDevice PCI-PCI bridge device instance.\r
+\r
+**/\r
+VOID\r
+InitializePpb (\r
+ IN PCI_IO_DEVICE *PciIoDevice\r
+ )\r
+{\r
+ EFI_PCI_IO_PROTOCOL *PciIo;\r
+\r
+ PciIo = &(PciIoDevice->PciIo);\r
+\r
+ //\r
+ // Put all the resource apertures including IO16\r
+ // Io32, pMem32, pMem64 to quiescent state\r
+ // Resource base all ones, Resource limit all zeros\r
+ //\r
+ PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x1C, 1, &gAllOne);\r
+ PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x1D, 1, &gAllZero);\r
+\r
+ PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x20, 1, &gAllOne);\r
+ PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x22, 1, &gAllZero);\r
+\r
+ PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x24, 1, &gAllOne);\r
+ PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x26, 1, &gAllZero);\r
+\r
+ PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x28, 1, &gAllOne);\r
+ PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x2C, 1, &gAllZero);\r
+\r
+ //\r
+ // Don't support use io32 as for now\r
+ //\r
+ PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x30, 1, &gAllOne);\r
+ PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x32, 1, &gAllZero);\r
+\r
+ //\r
+ // Force Interrupt line to zero for cards that come up randomly\r
+ //\r
+ PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x3C, 1, &gAllZero);\r
+}\r
+\r
+/**\r
+ This routine is used to initialize the bar of a PCI Card Bridge device.\r
+\r
+ @param PciIoDevice PCI Card bridge device.\r
+\r
+**/\r
+VOID\r
+InitializeP2C (\r
+ IN PCI_IO_DEVICE *PciIoDevice\r
+ )\r
+{\r
+ EFI_PCI_IO_PROTOCOL *PciIo;\r
+\r
+ PciIo = &(PciIoDevice->PciIo);\r
+\r
+ //\r
+ // Put all the resource apertures including IO16\r
+ // Io32, pMem32, pMem64 to quiescent state(\r
+ // Resource base all ones, Resource limit all zeros\r
+ //\r
+ PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x1c, 1, &gAllOne);\r
+ PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x20, 1, &gAllZero);\r
+\r
+ PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x24, 1, &gAllOne);\r
+ PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x28, 1, &gAllZero);\r
+\r
+ PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x2c, 1, &gAllOne);\r
+ PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x30, 1, &gAllZero);\r
+\r
+ PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x34, 1, &gAllOne);\r
+ PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x38, 1, &gAllZero);\r
+\r
+ //\r
+ // Force Interrupt line to zero for cards that come up randomly\r
+ //\r
+ PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x3C, 1, &gAllZero);\r
+}\r
+\r
+/**\r
+ Create and initiliaze general PCI I/O device instance for\r
+ PCI device/bridge device/hotplug bridge device.\r
+\r
+ @param PciRootBridgeIo Pointer to instance of EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.\r
+ @param Pci Input Pci information block.\r
+ @param Bus Device Bus NO.\r
+ @param Device Device device NO.\r
+ @param Func Device func NO.\r
+\r
+ @return Instance of PCI device. NULL means no instance created.\r
+\r
+**/\r
+PCI_IO_DEVICE *\r
+CreatePciIoDevice (\r
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo,\r
+ IN PCI_TYPE00 *Pci,\r
+ IN UINT8 Bus,\r
+ IN UINT8 Device,\r
+ IN UINT8 Func\r
+ )\r
+{\r
+ PCI_IO_DEVICE *PciIoDevice;\r
+ EFI_PCI_IO_PROTOCOL *PciIo;\r
+ EFI_STATUS Status;\r
+\r
+ PciIoDevice = AllocateZeroPool (sizeof (PCI_IO_DEVICE));\r
+ if (PciIoDevice == NULL) {\r
+ return NULL;\r
+ }\r
+\r
+ PciIoDevice->Signature = PCI_IO_DEVICE_SIGNATURE;\r
+ PciIoDevice->Handle = NULL;\r
+ PciIoDevice->PciRootBridgeIo = PciRootBridgeIo;\r
+ PciIoDevice->DevicePath = NULL;\r
+ PciIoDevice->BusNumber = Bus;\r
+ PciIoDevice->DeviceNumber = Device;\r
+ PciIoDevice->FunctionNumber = Func;\r
+ PciIoDevice->Decodes = 0;\r
+\r
+ if (gFullEnumeration) {\r
+ PciIoDevice->Allocated = FALSE;\r
+ } else {\r
+ PciIoDevice->Allocated = TRUE;\r
+ }\r
+\r
+ PciIoDevice->Registered = FALSE;\r
+ PciIoDevice->Attributes = 0;\r
+ PciIoDevice->Supports = 0;\r
+ PciIoDevice->BusOverride = FALSE;\r
+ PciIoDevice->AllOpRomProcessed = FALSE;\r
+\r
+ PciIoDevice->IsPciExp = FALSE;\r
+\r
+ CopyMem (&(PciIoDevice->Pci), Pci, sizeof (PCI_TYPE01));\r
+\r
+ //\r
+ // Initialize the PCI I/O instance structure\r
+ //\r
+ InitializePciIoInstance (PciIoDevice);\r
+ InitializePciDriverOverrideInstance (PciIoDevice);\r
+ InitializePciLoadFile2 (PciIoDevice);\r
+ PciIo = &PciIoDevice->PciIo;\r
+\r
+ //\r
+ // Detect if PCI Express Device\r
+ //\r
+ PciIoDevice->PciExpressCapabilityOffset = 0;\r
+ Status = LocateCapabilityRegBlock (\r
+ PciIoDevice,\r
+ EFI_PCI_CAPABILITY_ID_PCIEXP,\r
+ &PciIoDevice->PciExpressCapabilityOffset,\r
+ NULL\r
+ );\r
+ if (!EFI_ERROR (Status)) {\r
+ PciIoDevice->IsPciExp = TRUE;\r
+ }\r
+\r
+ //\r
+ // Initialize for PCI IOV\r
+ //\r
+\r
+ //\r
+ // Check ARI for function 0 only\r
+ //\r
+ Status = LocatePciExpressCapabilityRegBlock (\r
+ PciIoDevice,\r
+ EFI_PCIE_CAPABILITY_ID_ARI,\r
+ &PciIoDevice->AriCapabilityOffset,\r
+ NULL\r
+ );\r
+ if (!EFI_ERROR (Status)) {\r
+ DEBUG ((\r
+ EFI_D_INFO,\r
+ "PCI-IOV B%x.D%x.F%x - ARI Cap offset - 0x%x\n",\r
+ (UINTN)Bus,\r
+ (UINTN)Device,\r
+ (UINTN)Func,\r
+ (UINTN)PciIoDevice->AriCapabilityOffset\r
+ ));\r
+ }\r
+\r
+ Status = LocatePciExpressCapabilityRegBlock (\r
+ PciIoDevice,\r
+ EFI_PCIE_CAPABILITY_ID_SRIOV,\r
+ &PciIoDevice->SrIovCapabilityOffset,\r
+ NULL\r
+ );\r
+ if (!EFI_ERROR (Status)) {\r
+ DEBUG ((\r
+ EFI_D_INFO,\r
+ "PCI-IOV B%x.D%x.F%x - SRIOV Cap offset - 0x%x\n",\r
+ (UINTN)Bus,\r
+ (UINTN)Device,\r
+ (UINTN)Func,\r
+ (UINTN)PciIoDevice->SrIovCapabilityOffset\r
+ ));\r
+ }\r
+\r
+ Status = LocatePciExpressCapabilityRegBlock (\r
+ PciIoDevice,\r
+ EFI_PCIE_CAPABILITY_ID_MRIOV,\r
+ &PciIoDevice->MrIovCapabilityOffset,\r
+ NULL\r
+ );\r
+ if (!EFI_ERROR (Status)) {\r
+ DEBUG ((\r
+ EFI_D_INFO,\r
+ "PCI-IOV B%x.D%x.F%x - MRIOV Cap offset - 0x%x\n",\r
+ (UINTN)Bus,\r
+ (UINTN)Device,\r
+ (UINTN)Func,\r
+ (UINTN)PciIoDevice->MrIovCapabilityOffset\r
+ ));\r
+ }\r
+\r
+ //\r
+ // Calculate SystemPageSize\r
+ //\r
+ if ((PciIoDevice->SrIovCapabilityOffset != 0) && ((FeaturePcdGet(PcdSrIovSupport)& EFI_PCI_IOV_POLICY_SRIOV) != 0)) {\r
+\r
+ PciIo->Pci.Read (\r
+ PciIo,\r
+ EfiPciIoWidthUint32,\r
+ PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_SUPPORTED_PAGE_SIZE,\r
+ 1,\r
+ &PciIoDevice->SystemPageSize\r
+ );\r
+ DEBUG ((EFI_D_INFO, "PCI-IOV B%x.D%x.F%x - SupportedPageSize - 0x%x\n", (UINTN)Bus, (UINTN)Device, (UINTN)Func, PciIoDevice->SystemPageSize));\r
+\r
+ PciIoDevice->SystemPageSize = (PcdGet32(PcdSrIovSystemPageSize) & PciIoDevice->SystemPageSize);\r
+ ASSERT (PciIoDevice->SystemPageSize != 0);\r
+\r
+ PciIo->Pci.Write (\r
+ PciIo,\r
+ EfiPciIoWidthUint32,\r
+ PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_SYSTEM_PAGE_SIZE,\r
+ 1,\r
+ &PciIoDevice->SystemPageSize\r
+ );\r
+ DEBUG ((EFI_D_INFO, "PCI-IOV B%x.D%x.F%x - SystemPageSize - 0x%x\n", (UINTN)Bus, (UINTN)Device, (UINTN)Func, PciIoDevice->SystemPageSize));\r
+ //\r
+ // Adjust SystemPageSize for Alignment usage later\r
+ //\r
+ PciIoDevice->SystemPageSize <<= 12;\r
+ }\r
+\r
+ // Calculate BusReservation for PCI IOV\r
+ //\r
+ if ((PciIoDevice->SrIovCapabilityOffset != 0) && ((FeaturePcdGet(PcdSrIovSupport)& EFI_PCI_IOV_POLICY_SRIOV) != 0)) {\r
+ UINT16 VFStride;\r
+ UINT16 FirstVFOffset;\r
+ UINT32 PFRID;\r
+ UINT32 LastVF;\r
+\r
+ //\r
+ // Read First FirstVFOffset, InitialVFs, and VFStride\r
+ //\r
+ PciIo->Pci.Read (\r
+ PciIo,\r
+ EfiPciIoWidthUint16,\r
+ PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_FIRSTVF,\r
+ 1,\r
+ &FirstVFOffset\r
+ );\r
+ DEBUG ((EFI_D_INFO, "PCI-IOV B%x.D%x.F%x - FirstVFOffset - 0x%x\n", (UINTN)Bus, (UINTN)Device, (UINTN)Func, (UINTN)FirstVFOffset));\r
+\r
+ PciIo->Pci.Read (\r
+ PciIo,\r
+ EfiPciIoWidthUint16,\r
+ PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_INITIALVFS,\r
+ 1,\r
+ &PciIoDevice->InitialVFs\r
+ );\r
+ 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));\r
+\r
+ PciIo->Pci.Read (\r
+ PciIo,\r
+ EfiPciIoWidthUint16,\r
+ PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_VFSTRIDE,\r
+ 1,\r
+ &VFStride\r
+ );\r
+ DEBUG ((EFI_D_INFO, "PCI-IOV B%x.D%x.F%x - VFStride - 0x%x\n", (UINTN)Bus, (UINTN)Device, (UINTN)Func, (UINTN)VFStride));\r
+\r
+ //\r
+ // Calculate LastVF\r
+ //\r
+ PFRID = EFI_PCI_RID(Bus, Device, Func);\r
+ LastVF = PFRID + FirstVFOffset + (PciIoDevice->InitialVFs - 1) * VFStride;\r
+\r
+ //\r
+ // Calculate ReservedBusNum for this PF\r
+ //\r
+ PciIoDevice->ReservedBusNum = (UINT16)(EFI_PCI_BUS_OF_RID (LastVF) - Bus + 1);\r
+ 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));\r
+ }\r
+\r
+\r
+ //\r
+ // Initialize the reserved resource list\r
+ //\r
+ InitializeListHead (&PciIoDevice->ReservedResourceList);\r
+\r
+ //\r
+ // Initialize the driver list\r
+ //\r
+ InitializeListHead (&PciIoDevice->OptionRomDriverList);\r
+\r
+ //\r
+ // Initialize the child list\r
+ //\r
+ InitializeListHead (&PciIoDevice->ChildList);\r
+\r
+ return PciIoDevice;\r
+}\r
+\r
+/**\r
+ This routine is used to enumerate entire pci bus system\r
+ in a given platform.\r
+\r
+ It is only called on the second start on the same Root Bridge.\r
+\r
+ @param Controller Parent bridge handler.\r
+\r
+ @retval EFI_SUCCESS PCI enumeration finished successfully.\r
+ @retval other Some error occurred when enumerating the pci bus system.\r
+\r
+**/\r
+EFI_STATUS\r
+PciEnumeratorLight (\r
+ IN EFI_HANDLE Controller\r
+ )\r
+{\r
+\r
+ EFI_STATUS Status;\r
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;\r
+ PCI_IO_DEVICE *RootBridgeDev;\r
+ UINT16 MinBus;\r
+ UINT16 MaxBus;\r
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptors;\r
+\r
+ MinBus = 0;\r
+ MaxBus = PCI_MAX_BUS;\r
+ Descriptors = NULL;\r
+\r
+ //\r
+ // If this root bridge has been already enumerated, then return successfully\r
+ //\r
+ if (GetRootBridgeByHandle (Controller) != NULL) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ //\r
+ // Open pci root bridge io protocol\r
+ //\r
+ Status = gBS->OpenProtocol (\r
+ Controller,\r
+ &gEfiPciRootBridgeIoProtocolGuid,\r
+ (VOID **) &PciRootBridgeIo,\r
+ gPciBusDriverBinding.DriverBindingHandle,\r
+ Controller,\r
+ EFI_OPEN_PROTOCOL_BY_DRIVER\r
+ );\r
+ if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {\r
+ return Status;\r
+ }\r
+\r
+ Status = PciRootBridgeIo->Configuration (PciRootBridgeIo, (VOID **) &Descriptors);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ while (PciGetBusRange (&Descriptors, &MinBus, &MaxBus, NULL) == EFI_SUCCESS) {\r
+\r
+ //\r
+ // Create a device node for root bridge device with a NULL host bridge controller handle\r
+ //\r
+ RootBridgeDev = CreateRootBridge (Controller);\r
+\r
+ if (RootBridgeDev == NULL) {\r
+ Descriptors++;\r
+ continue;\r
+ }\r
+\r
+ //\r
+ // Record the root bridgeio protocol\r
+ //\r
+ RootBridgeDev->PciRootBridgeIo = PciRootBridgeIo;\r
+\r
+ Status = PciPciDeviceInfoCollector (\r
+ RootBridgeDev,\r
+ (UINT8) MinBus\r
+ );\r
+\r
+ if (!EFI_ERROR (Status)) {\r
+\r
+ //\r
+ // Remove those PCI devices which are rejected when full enumeration\r
+ //\r
+ RemoveRejectedPciDevices (RootBridgeDev->Handle, RootBridgeDev);\r
+\r
+ //\r
+ // Process option rom light\r
+ //\r
+ ProcessOptionRomLight (RootBridgeDev);\r
+\r
+ //\r
+ // Determine attributes for all devices under this root bridge\r
+ //\r
+ DetermineDeviceAttribute (RootBridgeDev);\r
+\r
+ //\r
+ // If successfully, insert the node into device pool\r
+ //\r
+ InsertRootBridge (RootBridgeDev);\r
+ } else {\r
+\r
+ //\r
+ // If unsuccessly, destroy the entire node\r
+ //\r
+ DestroyRootBridge (RootBridgeDev);\r
+ }\r
+\r
+ Descriptors++;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Get bus range from PCI resource descriptor list.\r
+\r
+ @param Descriptors A pointer to the address space descriptor.\r
+ @param MinBus The min bus returned.\r
+ @param MaxBus The max bus returned.\r
+ @param BusRange The bus range returned.\r
+\r
+ @retval EFI_SUCCESS Successfully got bus range.\r
+ @retval EFI_NOT_FOUND Can not find the specific bus.\r
+\r
+**/\r
+EFI_STATUS\r
+PciGetBusRange (\r
+ IN EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR **Descriptors,\r
+ OUT UINT16 *MinBus,\r
+ OUT UINT16 *MaxBus,\r
+ OUT UINT16 *BusRange\r
+ )\r
+{\r
+ while ((*Descriptors)->Desc != ACPI_END_TAG_DESCRIPTOR) {\r
+ if ((*Descriptors)->ResType == ACPI_ADDRESS_SPACE_TYPE_BUS) {\r
+ if (MinBus != NULL) {\r
+ *MinBus = (UINT16) (*Descriptors)->AddrRangeMin;\r
+ }\r
+\r
+ if (MaxBus != NULL) {\r
+ *MaxBus = (UINT16) (*Descriptors)->AddrRangeMax;\r
+ }\r
+\r
+ if (BusRange != NULL) {\r
+ *BusRange = (UINT16) (*Descriptors)->AddrLen;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ (*Descriptors)++;\r
+ }\r
+\r
+ return EFI_NOT_FOUND;\r
+}\r
+\r
+/**\r
+ This routine can be used to start the root bridge.\r
+\r
+ @param RootBridgeDev Pci device instance.\r
+\r
+ @retval EFI_SUCCESS This device started.\r
+ @retval other Failed to get PCI Root Bridge I/O protocol.\r
+\r
+**/\r
+EFI_STATUS\r
+StartManagingRootBridge (\r
+ IN PCI_IO_DEVICE *RootBridgeDev\r
+ )\r
+{\r
+ EFI_HANDLE RootBridgeHandle;\r
+ EFI_STATUS Status;\r
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;\r
+\r
+ //\r
+ // Get the root bridge handle\r
+ //\r
+ RootBridgeHandle = RootBridgeDev->Handle;\r
+ PciRootBridgeIo = NULL;\r
+\r
+ //\r
+ // Get the pci root bridge io protocol\r
+ //\r
+ Status = gBS->OpenProtocol (\r
+ RootBridgeHandle,\r
+ &gEfiPciRootBridgeIoProtocolGuid,\r
+ (VOID **) &PciRootBridgeIo,\r
+ gPciBusDriverBinding.DriverBindingHandle,\r
+ RootBridgeHandle,\r
+ EFI_OPEN_PROTOCOL_BY_DRIVER\r
+ );\r
+\r
+ if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Store the PciRootBridgeIo protocol into root bridge private data\r
+ //\r
+ RootBridgeDev->PciRootBridgeIo = PciRootBridgeIo;\r
+\r
+ return EFI_SUCCESS;\r
+\r
+}\r
+\r
+/**\r
+ This routine can be used to check whether a PCI device should be rejected when light enumeration.\r
+\r
+ @param PciIoDevice Pci device instance.\r
+\r
+ @retval TRUE This device should be rejected.\r
+ @retval FALSE This device shouldn't be rejected.\r
+\r
+**/\r
+BOOLEAN\r
+IsPciDeviceRejected (\r
+ IN PCI_IO_DEVICE *PciIoDevice\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT32 TestValue;\r
+ UINT32 OldValue;\r
+ UINT32 Mask;\r
+ UINT8 BarOffset;\r
+\r
+ //\r
+ // PPB should be skip!\r
+ //\r
+ if (IS_PCI_BRIDGE (&PciIoDevice->Pci)) {\r
+ return FALSE;\r
+ }\r
+\r
+ if (IS_CARDBUS_BRIDGE (&PciIoDevice->Pci)) {\r
+ //\r
+ // Only test base registers for P2C\r
+ //\r
+ for (BarOffset = 0x1C; BarOffset <= 0x38; BarOffset += 2 * sizeof (UINT32)) {\r
+\r
+ Mask = (BarOffset < 0x2C) ? 0xFFFFF000 : 0xFFFFFFFC;\r
+ Status = BarExisted (PciIoDevice, BarOffset, &TestValue, &OldValue);\r
+ if (EFI_ERROR (Status)) {\r
+ continue;\r
+ }\r
+\r
+ TestValue = TestValue & Mask;\r
+ if ((TestValue != 0) && (TestValue == (OldValue & Mask))) {\r
+ //\r
+ // The bar isn't programed, so it should be rejected\r
+ //\r
+ return TRUE;\r
+ }\r
+ }\r
+\r
+ return FALSE;\r
+ }\r
+\r
+ for (BarOffset = 0x14; BarOffset <= 0x24; BarOffset += sizeof (UINT32)) {\r
+ //\r
+ // Test PCI devices\r
+ //\r
+ Status = BarExisted (PciIoDevice, BarOffset, &TestValue, &OldValue);\r
+ if (EFI_ERROR (Status)) {\r
+ continue;\r
+ }\r
+\r
+ if ((TestValue & 0x01) != 0) {\r
+\r
+ //\r
+ // IO Bar\r
+ //\r
+ Mask = 0xFFFFFFFC;\r
+ TestValue = TestValue & Mask;\r
+ if ((TestValue != 0) && (TestValue == (OldValue & Mask))) {\r
+ return TRUE;\r
+ }\r
+\r
+ } else {\r
+\r
+ //\r
+ // Mem Bar\r
+ //\r
+ Mask = 0xFFFFFFF0;\r
+ TestValue = TestValue & Mask;\r
+\r
+ if ((TestValue & 0x07) == 0x04) {\r
+\r
+ //\r
+ // Mem64 or PMem64\r
+ //\r
+ BarOffset += sizeof (UINT32);\r
+ if ((TestValue != 0) && (TestValue == (OldValue & Mask))) {\r
+\r
+ //\r
+ // Test its high 32-Bit BAR\r
+ //\r
+ Status = BarExisted (PciIoDevice, BarOffset, &TestValue, &OldValue);\r
+ if (TestValue == OldValue) {\r
+ return TRUE;\r
+ }\r
+ }\r
+\r
+ } else {\r
+\r
+ //\r
+ // Mem32 or PMem32\r
+ //\r
+ if ((TestValue != 0) && (TestValue == (OldValue & Mask))) {\r
+ return TRUE;\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ return FALSE;\r
+}\r
+\r
+/**\r
+ Reset all bus number from specific bridge.\r
+\r
+ @param Bridge Parent specific bridge.\r
+ @param StartBusNumber Start bus number.\r
+\r
+**/\r
+VOID\r
+ResetAllPpbBusNumber (\r
+ IN PCI_IO_DEVICE *Bridge,\r
+ IN UINT8 StartBusNumber\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ PCI_TYPE00 Pci;\r
+ UINT8 Device;\r
+ UINT32 Register;\r
+ UINT8 Func;\r
+ UINT64 Address;\r
+ UINT8 SecondaryBus;\r
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;\r
+\r
+ PciRootBridgeIo = Bridge->PciRootBridgeIo;\r
+\r
+ for (Device = 0; Device <= PCI_MAX_DEVICE; Device++) {\r
+ for (Func = 0; Func <= PCI_MAX_FUNC; Func++) {\r
+\r
+ //\r
+ // Check to see whether a pci device is present\r
+ //\r
+ Status = PciDevicePresent (\r
+ PciRootBridgeIo,\r
+ &Pci,\r
+ StartBusNumber,\r
+ Device,\r
+ Func\r
+ );\r
+\r
+ if (!EFI_ERROR (Status) && (IS_PCI_BRIDGE (&Pci))) {\r
+\r
+ Register = 0;\r
+ Address = EFI_PCI_ADDRESS (StartBusNumber, Device, Func, 0x18);\r
+ Status = PciRootBridgeIo->Pci.Read (\r
+ PciRootBridgeIo,\r
+ EfiPciWidthUint32,\r
+ Address,\r
+ 1,\r
+ &Register\r
+ );\r
+ SecondaryBus = (UINT8)(Register >> 8);\r
+\r
+ if (SecondaryBus != 0) {\r
+ ResetAllPpbBusNumber (Bridge, SecondaryBus);\r
+ }\r
+\r
+ //\r
+ // Reset register 18h, 19h, 1Ah on PCI Bridge\r
+ //\r
+ Register &= 0xFF000000;\r
+ Status = PciRootBridgeIo->Pci.Write (\r
+ PciRootBridgeIo,\r
+ EfiPciWidthUint32,\r
+ Address,\r
+ 1,\r
+ &Register\r
+ );\r
+ }\r
+\r
+ if (Func == 0 && !IS_PCI_MULTI_FUNC (&Pci)) {\r
+ //\r
+ // Skip sub functions, this is not a multi function device\r
+ //\r
+ Func = PCI_MAX_FUNC;\r
+ }\r
+ }\r
+ }\r
+}\r
+\r