/** @file | |
PCI emumeration support functions implementation for PCI Bus module. | |
Copyright (c) 2006 - 2021, Intel Corporation. All rights reserved.<BR> | |
(C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR> | |
Copyright (C) 2023 Advanced Micro Devices, Inc. All rights reserved.<BR> | |
SPDX-License-Identifier: BSD-2-Clause-Patent | |
**/ | |
#include "PciBus.h" | |
extern CHAR16 *mBarTypeStr[]; | |
extern EDKII_DEVICE_SECURITY_PROTOCOL *mDeviceSecurityProtocol; | |
#define OLD_ALIGN 0xFFFFFFFFFFFFFFFFULL | |
#define EVEN_ALIGN 0xFFFFFFFFFFFFFFFEULL | |
#define SQUAD_ALIGN 0xFFFFFFFFFFFFFFFDULL | |
#define DQUAD_ALIGN 0xFFFFFFFFFFFFFFFCULL | |
/** | |
This routine is used to check whether the pci device is present. | |
@param PciRootBridgeIo Pointer to instance of EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL. | |
@param Pci Output buffer for PCI device configuration space. | |
@param Bus PCI bus NO. | |
@param Device PCI device NO. | |
@param Func PCI Func NO. | |
@retval EFI_NOT_FOUND PCI device not present. | |
@retval EFI_SUCCESS PCI device is found. | |
**/ | |
EFI_STATUS | |
PciDevicePresent ( | |
IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo, | |
OUT PCI_TYPE00 *Pci, | |
IN UINT8 Bus, | |
IN UINT8 Device, | |
IN UINT8 Func | |
) | |
{ | |
UINT64 Address; | |
EFI_STATUS Status; | |
// | |
// Create PCI address map in terms of Bus, Device and Func | |
// | |
Address = EFI_PCI_ADDRESS (Bus, Device, Func, 0); | |
// | |
// Read the Vendor ID register | |
// | |
Status = PciRootBridgeIo->Pci.Read ( | |
PciRootBridgeIo, | |
EfiPciWidthUint32, | |
Address, | |
1, | |
Pci | |
); | |
if (!EFI_ERROR (Status) && ((Pci->Hdr).VendorId != 0xffff)) { | |
// | |
// Read the entire config header for the device | |
// | |
Status = PciRootBridgeIo->Pci.Read ( | |
PciRootBridgeIo, | |
EfiPciWidthUint32, | |
Address, | |
sizeof (PCI_TYPE00) / sizeof (UINT32), | |
Pci | |
); | |
return EFI_SUCCESS; | |
} | |
return EFI_NOT_FOUND; | |
} | |
/** | |
Collect all the resource information under this root bridge. | |
A database that records all the information about pci device subject to this | |
root bridge will then be created. | |
@param Bridge Parent bridge instance. | |
@param StartBusNumber Bus number of beginning. | |
@retval EFI_SUCCESS PCI device is found. | |
@retval other Some error occurred when reading PCI bridge information. | |
**/ | |
EFI_STATUS | |
PciPciDeviceInfoCollector ( | |
IN PCI_IO_DEVICE *Bridge, | |
IN UINT8 StartBusNumber | |
) | |
{ | |
EFI_STATUS Status; | |
PCI_TYPE00 Pci; | |
UINT8 Device; | |
UINT8 Func; | |
UINT8 SecBus; | |
PCI_IO_DEVICE *PciIoDevice; | |
EFI_PCI_IO_PROTOCOL *PciIo; | |
Status = EFI_SUCCESS; | |
SecBus = 0; | |
for (Device = 0; Device <= PCI_MAX_DEVICE; Device++) { | |
for (Func = 0; Func <= PCI_MAX_FUNC; Func++) { | |
// | |
// Check to see whether PCI device is present | |
// | |
Status = PciDevicePresent ( | |
Bridge->PciRootBridgeIo, | |
&Pci, | |
(UINT8)StartBusNumber, | |
(UINT8)Device, | |
(UINT8)Func | |
); | |
if (EFI_ERROR (Status) && (Func == 0)) { | |
// | |
// go to next device if there is no Function 0 | |
// | |
break; | |
} | |
if (!EFI_ERROR (Status)) { | |
// | |
// Call back to host bridge function | |
// | |
PreprocessController (Bridge, (UINT8)StartBusNumber, Device, Func, EfiPciBeforeResourceCollection); | |
// | |
// Collect all the information about the PCI device discovered | |
// | |
Status = PciSearchDevice ( | |
Bridge, | |
&Pci, | |
(UINT8)StartBusNumber, | |
Device, | |
Func, | |
&PciIoDevice | |
); | |
// | |
// Recursively scan PCI busses on the other side of PCI-PCI bridges | |
// | |
// | |
if (!EFI_ERROR (Status) && (IS_PCI_BRIDGE (&Pci) || IS_CARDBUS_BRIDGE (&Pci))) { | |
// | |
// If it is PPB, we need to get the secondary bus to continue the enumeration | |
// | |
PciIo = &(PciIoDevice->PciIo); | |
Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8, PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET, 1, &SecBus); | |
if (EFI_ERROR (Status)) { | |
return Status; | |
} | |
// | |
// Ensure secondary bus number is greater than the primary bus number to avoid | |
// any potential dead loop when PcdPciDisableBusEnumeration is set to TRUE | |
// | |
if (SecBus <= StartBusNumber) { | |
break; | |
} | |
// | |
// Get resource padding for PPB | |
// | |
GetResourcePaddingPpb (PciIoDevice); | |
// | |
// Deep enumerate the next level bus | |
// | |
Status = PciPciDeviceInfoCollector ( | |
PciIoDevice, | |
(UINT8)(SecBus) | |
); | |
} | |
if ((Func == 0) && !IS_PCI_MULTI_FUNC (&Pci)) { | |
// | |
// Skip sub functions, this is not a multi function device | |
// | |
Func = PCI_MAX_FUNC; | |
} | |
} | |
} | |
} | |
return EFI_SUCCESS; | |
} | |
/** | |
Search required device and create PCI device instance. | |
@param Bridge Parent bridge instance. | |
@param Pci Input PCI device information block. | |
@param Bus PCI bus NO. | |
@param Device PCI device NO. | |
@param Func PCI func NO. | |
@param PciDevice Output of searched PCI device instance. | |
@retval EFI_SUCCESS Successfully created PCI device instance. | |
@retval EFI_OUT_OF_RESOURCES Cannot get PCI device information. | |
**/ | |
EFI_STATUS | |
PciSearchDevice ( | |
IN PCI_IO_DEVICE *Bridge, | |
IN PCI_TYPE00 *Pci, | |
IN UINT8 Bus, | |
IN UINT8 Device, | |
IN UINT8 Func, | |
OUT PCI_IO_DEVICE **PciDevice | |
) | |
{ | |
PCI_IO_DEVICE *PciIoDevice; | |
BOOLEAN IgnoreOptionRom; | |
PciIoDevice = NULL; | |
IgnoreOptionRom = FALSE; | |
DEBUG (( | |
DEBUG_INFO, | |
"PciBus: Discovered %s @ [%02x|%02x|%02x] [VID = 0x%x, DID = 0x%0x]\n", | |
IS_PCI_BRIDGE (Pci) ? L"PPB" : | |
IS_CARDBUS_BRIDGE (Pci) ? L"P2C" : | |
L"PCI", | |
Bus, | |
Device, | |
Func, | |
Pci->Hdr.VendorId, | |
Pci->Hdr.DeviceId | |
)); | |
if (!IS_PCI_BRIDGE (Pci)) { | |
if (IS_CARDBUS_BRIDGE (Pci)) { | |
PciIoDevice = GatherP2CInfo ( | |
Bridge, | |
Pci, | |
Bus, | |
Device, | |
Func | |
); | |
if ((PciIoDevice != NULL) && gFullEnumeration) { | |
InitializeP2C (PciIoDevice); | |
} | |
} else { | |
// | |
// Create private data for Pci Device | |
// | |
PciIoDevice = GatherDeviceInfo ( | |
Bridge, | |
Pci, | |
Bus, | |
Device, | |
Func | |
); | |
} | |
} else { | |
// | |
// Create private data for PPB | |
// | |
PciIoDevice = GatherPpbInfo ( | |
Bridge, | |
Pci, | |
Bus, | |
Device, | |
Func | |
); | |
// | |
// Special initialization for PPB including making the PPB quiet | |
// | |
if ((PciIoDevice != NULL) && gFullEnumeration) { | |
InitializePpb (PciIoDevice); | |
} | |
} | |
if (PciIoDevice == NULL) { | |
return EFI_OUT_OF_RESOURCES; | |
} | |
// | |
// Update the bar information for this PCI device so as to support some specific device | |
// | |
UpdatePciInfo (PciIoDevice, &IgnoreOptionRom); | |
if (PciIoDevice->DevicePath == NULL) { | |
return EFI_OUT_OF_RESOURCES; | |
} | |
// | |
// Detect this function has option rom | |
// | |
if (gFullEnumeration) { | |
if (!IS_CARDBUS_BRIDGE (Pci) && !IgnoreOptionRom) { | |
GetOpRomInfo (PciIoDevice); | |
} | |
ResetPowerManagementFeature (PciIoDevice); | |
} | |
// | |
// Insert it into a global tree for future reference | |
// | |
InsertPciDevice (Bridge, PciIoDevice); | |
// | |
// Determine PCI device attributes | |
// | |
if (PciDevice != NULL) { | |
*PciDevice = PciIoDevice; | |
} | |
return EFI_SUCCESS; | |
} | |
/** | |
Dump the PPB padding resource information. | |
@param PciIoDevice PCI IO instance. | |
@param ResourceType The desired resource type to dump. | |
PciBarTypeUnknown means to dump all types of resources. | |
**/ | |
VOID | |
DumpPpbPaddingResource ( | |
IN PCI_IO_DEVICE *PciIoDevice, | |
IN PCI_BAR_TYPE ResourceType | |
) | |
{ | |
EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptor; | |
PCI_BAR_TYPE Type; | |
if (PciIoDevice->ResourcePaddingDescriptors == NULL) { | |
return; | |
} | |
if ((ResourceType == PciBarTypeIo16) || (ResourceType == PciBarTypeIo32)) { | |
ResourceType = PciBarTypeIo; | |
} | |
for (Descriptor = PciIoDevice->ResourcePaddingDescriptors; Descriptor->Desc != ACPI_END_TAG_DESCRIPTOR; Descriptor++) { | |
Type = PciBarTypeUnknown; | |
if ((Descriptor->Desc == ACPI_ADDRESS_SPACE_DESCRIPTOR) && (Descriptor->ResType == ACPI_ADDRESS_SPACE_TYPE_IO)) { | |
Type = PciBarTypeIo; | |
} else if ((Descriptor->Desc == ACPI_ADDRESS_SPACE_DESCRIPTOR) && (Descriptor->ResType == ACPI_ADDRESS_SPACE_TYPE_MEM)) { | |
if (Descriptor->AddrSpaceGranularity == 32) { | |
// | |
// prefetchable | |
// | |
if (Descriptor->SpecificFlag == EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE) { | |
Type = PciBarTypePMem32; | |
} | |
// | |
// Non-prefetchable | |
// | |
if (Descriptor->SpecificFlag == 0) { | |
Type = PciBarTypeMem32; | |
} | |
} | |
if (Descriptor->AddrSpaceGranularity == 64) { | |
// | |
// prefetchable | |
// | |
if (Descriptor->SpecificFlag == EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE) { | |
Type = PciBarTypePMem64; | |
} | |
// | |
// Non-prefetchable | |
// | |
if (Descriptor->SpecificFlag == 0) { | |
Type = PciBarTypeMem64; | |
} | |
} | |
} | |
if ((Type != PciBarTypeUnknown) && ((ResourceType == PciBarTypeUnknown) || (ResourceType == Type))) { | |
DEBUG (( | |
DEBUG_INFO, | |
" Padding: Type = %s; Alignment = 0x%lx;\tLength = 0x%lx\n", | |
mBarTypeStr[Type], | |
Descriptor->AddrRangeMax, | |
Descriptor->AddrLen | |
)); | |
} | |
} | |
} | |
/** | |
Dump the PCI BAR information. | |
@param PciIoDevice PCI IO instance. | |
**/ | |
VOID | |
DumpPciBars ( | |
IN PCI_IO_DEVICE *PciIoDevice | |
) | |
{ | |
UINTN Index; | |
for (Index = 0; Index < PCI_MAX_BAR; Index++) { | |
if (PciIoDevice->PciBar[Index].BarType == PciBarTypeUnknown) { | |
continue; | |
} | |
DEBUG (( | |
DEBUG_INFO, | |
" BAR[%d]: Type = %s; Alignment = 0x%lx;\tLength = 0x%lx;\tOffset = 0x%02x\n", | |
Index, | |
mBarTypeStr[MIN (PciIoDevice->PciBar[Index].BarType, PciBarTypeMaxType)], | |
PciIoDevice->PciBar[Index].Alignment, | |
PciIoDevice->PciBar[Index].Length, | |
PciIoDevice->PciBar[Index].Offset | |
)); | |
} | |
for (Index = 0; Index < PCI_MAX_BAR; Index++) { | |
if ((PciIoDevice->VfPciBar[Index].BarType == PciBarTypeUnknown) && (PciIoDevice->VfPciBar[Index].Length == 0)) { | |
continue; | |
} | |
DEBUG (( | |
DEBUG_INFO, | |
" VFBAR[%d]: Type = %s; Alignment = 0x%lx;\tLength = 0x%lx;\tOffset = 0x%02x\n", | |
Index, | |
mBarTypeStr[MIN (PciIoDevice->VfPciBar[Index].BarType, PciBarTypeMaxType)], | |
PciIoDevice->VfPciBar[Index].Alignment, | |
PciIoDevice->VfPciBar[Index].Length, | |
PciIoDevice->VfPciBar[Index].Offset | |
)); | |
} | |
DEBUG ((DEBUG_INFO, "\n")); | |
} | |
/** | |
Create PCI device instance for PCI device. | |
@param Bridge Parent bridge instance. | |
@param Pci Input PCI device information block. | |
@param Bus PCI device Bus NO. | |
@param Device PCI device Device NO. | |
@param Func PCI device's func NO. | |
@return Created PCI device instance. | |
**/ | |
PCI_IO_DEVICE * | |
GatherDeviceInfo ( | |
IN PCI_IO_DEVICE *Bridge, | |
IN PCI_TYPE00 *Pci, | |
IN UINT8 Bus, | |
IN UINT8 Device, | |
IN UINT8 Func | |
) | |
{ | |
UINTN Offset; | |
UINTN BarIndex; | |
PCI_IO_DEVICE *PciIoDevice; | |
PciIoDevice = CreatePciIoDevice ( | |
Bridge, | |
Pci, | |
Bus, | |
Device, | |
Func | |
); | |
if (PciIoDevice == NULL) { | |
return NULL; | |
} | |
// | |
// If it is a full enumeration, disconnect the device in advance | |
// | |
if (gFullEnumeration) { | |
PCI_DISABLE_COMMAND_REGISTER (PciIoDevice, EFI_PCI_COMMAND_BITS_OWNED); | |
} | |
// | |
// Start to parse the bars | |
// | |
for (Offset = 0x10, BarIndex = 0; Offset <= 0x24 && BarIndex < PCI_MAX_BAR; BarIndex++) { | |
Offset = PciParseBar (PciIoDevice, Offset, BarIndex); | |
} | |
// | |
// Parse the SR-IOV VF bars | |
// | |
if (PcdGetBool (PcdSrIovSupport) && (PciIoDevice->SrIovCapabilityOffset != 0)) { | |
for (Offset = PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_BAR0, BarIndex = 0; | |
Offset <= PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_BAR5; | |
BarIndex++) | |
{ | |
ASSERT (BarIndex < PCI_MAX_BAR); | |
Offset = PciIovParseVfBar (PciIoDevice, Offset, BarIndex); | |
} | |
} | |
DEBUG_CODE ( | |
DumpPciBars (PciIoDevice); | |
); | |
return PciIoDevice; | |
} | |
/** | |
Create PCI device instance for PCI-PCI bridge. | |
@param Bridge Parent bridge instance. | |
@param Pci Input PCI device information block. | |
@param Bus PCI device Bus NO. | |
@param Device PCI device Device NO. | |
@param Func PCI device's func NO. | |
@return Created PCI device instance. | |
**/ | |
PCI_IO_DEVICE * | |
GatherPpbInfo ( | |
IN PCI_IO_DEVICE *Bridge, | |
IN PCI_TYPE00 *Pci, | |
IN UINT8 Bus, | |
IN UINT8 Device, | |
IN UINT8 Func | |
) | |
{ | |
PCI_IO_DEVICE *PciIoDevice; | |
EFI_STATUS Status; | |
UINT8 Value; | |
EFI_PCI_IO_PROTOCOL *PciIo; | |
UINT8 Temp; | |
UINT32 PMemBaseLimit; | |
UINT16 PrefetchableMemoryBase; | |
UINT16 PrefetchableMemoryLimit; | |
PciIoDevice = CreatePciIoDevice ( | |
Bridge, | |
Pci, | |
Bus, | |
Device, | |
Func | |
); | |
if (PciIoDevice == NULL) { | |
return NULL; | |
} | |
if (gFullEnumeration) { | |
PCI_DISABLE_COMMAND_REGISTER (PciIoDevice, EFI_PCI_COMMAND_BITS_OWNED); | |
// | |
// Initialize the bridge control register | |
// | |
PCI_DISABLE_BRIDGE_CONTROL_REGISTER (PciIoDevice, EFI_PCI_BRIDGE_CONTROL_BITS_OWNED); | |
} | |
// | |
// PPB can have two BARs | |
// | |
if (PciParseBar (PciIoDevice, 0x10, PPB_BAR_0) == 0x14) { | |
// | |
// Not 64-bit bar | |
// | |
PciParseBar (PciIoDevice, 0x14, PPB_BAR_1); | |
} | |
PciIo = &PciIoDevice->PciIo; | |
// | |
// Test whether it support 32 decode or not | |
// | |
PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8, 0x1C, 1, &Temp); | |
PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x1C, 1, &gAllOne); | |
PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8, 0x1C, 1, &Value); | |
PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x1C, 1, &Temp); | |
if (Value != 0) { | |
if ((Value & 0x01) != 0) { | |
PciIoDevice->Decodes |= EFI_BRIDGE_IO32_DECODE_SUPPORTED; | |
} else { | |
PciIoDevice->Decodes |= EFI_BRIDGE_IO16_DECODE_SUPPORTED; | |
} | |
} | |
// | |
// if PcdPciBridgeIoAlignmentProbe is TRUE, PCI bus driver probes | |
// PCI bridge supporting non-standard I/O window alignment less than 4K. | |
// | |
PciIoDevice->BridgeIoAlignment = 0xFFF; | |
if (FeaturePcdGet (PcdPciBridgeIoAlignmentProbe)) { | |
// | |
// Check any bits of bit 3-1 of I/O Base Register are writable. | |
// if so, it is assumed non-standard I/O window alignment is supported by this bridge. | |
// Per spec, bit 3-1 of I/O Base Register are reserved bits, so its content can't be assumed. | |
// | |
Value = (UINT8)(Temp ^ (BIT3 | BIT2 | BIT1)); | |
PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x1C, 1, &Value); | |
PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8, 0x1C, 1, &Value); | |
PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x1C, 1, &Temp); | |
Value = (UINT8)((Value ^ Temp) & (BIT3 | BIT2 | BIT1)); | |
switch (Value) { | |
case BIT3: | |
PciIoDevice->BridgeIoAlignment = 0x7FF; | |
break; | |
case BIT3 | BIT2: | |
PciIoDevice->BridgeIoAlignment = 0x3FF; | |
break; | |
case BIT3 | BIT2 | BIT1: | |
PciIoDevice->BridgeIoAlignment = 0x1FF; | |
break; | |
} | |
} | |
Status = BarExisted ( | |
PciIoDevice, | |
0x24, | |
NULL, | |
&PMemBaseLimit | |
); | |
// | |
// Test if it supports 64 memory or not | |
// | |
// The bottom 4 bits of both the Prefetchable Memory Base and Prefetchable Memory Limit | |
// registers: | |
// 0 - the bridge supports only 32 bit addresses. | |
// 1 - the bridge supports 64-bit addresses. | |
// | |
PrefetchableMemoryBase = (UINT16)(PMemBaseLimit & 0xffff); | |
PrefetchableMemoryLimit = (UINT16)(PMemBaseLimit >> 16); | |
if (!EFI_ERROR (Status) && | |
((PrefetchableMemoryBase & 0x000f) == 0x0001) && | |
((PrefetchableMemoryLimit & 0x000f) == 0x0001)) | |
{ | |
Status = BarExisted ( | |
PciIoDevice, | |
0x28, | |
NULL, | |
NULL | |
); | |
if (!EFI_ERROR (Status)) { | |
PciIoDevice->Decodes |= EFI_BRIDGE_PMEM32_DECODE_SUPPORTED; | |
PciIoDevice->Decodes |= EFI_BRIDGE_PMEM64_DECODE_SUPPORTED; | |
} else { | |
PciIoDevice->Decodes |= EFI_BRIDGE_PMEM32_DECODE_SUPPORTED; | |
} | |
} | |
// | |
// Memory 32 code is required for ppb | |
// | |
PciIoDevice->Decodes |= EFI_BRIDGE_MEM32_DECODE_SUPPORTED; | |
GetResourcePaddingPpb (PciIoDevice); | |
DEBUG_CODE ( | |
DumpPpbPaddingResource (PciIoDevice, PciBarTypeUnknown); | |
DumpPciBars (PciIoDevice); | |
); | |
return PciIoDevice; | |
} | |
/** | |
Create PCI device instance for PCI Card bridge device. | |
@param Bridge Parent bridge instance. | |
@param Pci Input PCI device information block. | |
@param Bus PCI device Bus NO. | |
@param Device PCI device Device NO. | |
@param Func PCI device's func NO. | |
@return Created PCI device instance. | |
**/ | |
PCI_IO_DEVICE * | |
GatherP2CInfo ( | |
IN PCI_IO_DEVICE *Bridge, | |
IN PCI_TYPE00 *Pci, | |
IN UINT8 Bus, | |
IN UINT8 Device, | |
IN UINT8 Func | |
) | |
{ | |
PCI_IO_DEVICE *PciIoDevice; | |
PciIoDevice = CreatePciIoDevice ( | |
Bridge, | |
Pci, | |
Bus, | |
Device, | |
Func | |
); | |
if (PciIoDevice == NULL) { | |
return NULL; | |
} | |
if (gFullEnumeration) { | |
PCI_DISABLE_COMMAND_REGISTER (PciIoDevice, EFI_PCI_COMMAND_BITS_OWNED); | |
// | |
// Initialize the bridge control register | |
// | |
PCI_DISABLE_BRIDGE_CONTROL_REGISTER (PciIoDevice, EFI_PCCARD_BRIDGE_CONTROL_BITS_OWNED); | |
} | |
// | |
// P2C only has one bar that is in 0x10 | |
// | |
PciParseBar (PciIoDevice, 0x10, P2C_BAR_0); | |
// | |
// Read PciBar information from the bar register | |
// | |
GetBackPcCardBar (PciIoDevice); | |
PciIoDevice->Decodes = EFI_BRIDGE_MEM32_DECODE_SUPPORTED | | |
EFI_BRIDGE_PMEM32_DECODE_SUPPORTED | | |
EFI_BRIDGE_IO32_DECODE_SUPPORTED; | |
DEBUG_CODE ( | |
DumpPciBars (PciIoDevice); | |
); | |
return PciIoDevice; | |
} | |
/** | |
Create device path for pci device. | |
@param ParentDevicePath Parent bridge's path. | |
@param PciIoDevice Pci device instance. | |
@return Device path protocol instance for specific pci device. | |
**/ | |
EFI_DEVICE_PATH_PROTOCOL * | |
CreatePciDevicePath ( | |
IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath, | |
IN PCI_IO_DEVICE *PciIoDevice | |
) | |
{ | |
PCI_DEVICE_PATH PciNode; | |
// | |
// Create PCI device path | |
// | |
PciNode.Header.Type = HARDWARE_DEVICE_PATH; | |
PciNode.Header.SubType = HW_PCI_DP; | |
SetDevicePathNodeLength (&PciNode.Header, sizeof (PciNode)); | |
PciNode.Device = PciIoDevice->DeviceNumber; | |
PciNode.Function = PciIoDevice->FunctionNumber; | |
PciIoDevice->DevicePath = AppendDevicePathNode (ParentDevicePath, &PciNode.Header); | |
return PciIoDevice->DevicePath; | |
} | |
/** | |
Check whether the PCI IOV VF bar is existed or not. | |
@param PciIoDevice A pointer to the PCI_IO_DEVICE. | |
@param Offset The offset. | |
@param BarLengthValue The bar length value returned. | |
@param OriginalBarValue The original bar value returned. | |
@retval EFI_NOT_FOUND The bar doesn't exist. | |
@retval EFI_SUCCESS The bar exist. | |
**/ | |
EFI_STATUS | |
VfBarExisted ( | |
IN PCI_IO_DEVICE *PciIoDevice, | |
IN UINTN Offset, | |
OUT UINT32 *BarLengthValue, | |
OUT UINT32 *OriginalBarValue | |
) | |
{ | |
EFI_PCI_IO_PROTOCOL *PciIo; | |
UINT32 OriginalValue; | |
UINT32 Value; | |
EFI_TPL OldTpl; | |
// | |
// Ensure it is called properly | |
// | |
ASSERT (PciIoDevice->SrIovCapabilityOffset != 0); | |
if (PciIoDevice->SrIovCapabilityOffset == 0) { | |
return EFI_NOT_FOUND; | |
} | |
PciIo = &PciIoDevice->PciIo; | |
// | |
// Preserve the original value | |
// | |
PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, (UINT32)Offset, 1, &OriginalValue); | |
// | |
// Raise TPL to high level to disable timer interrupt while the BAR is probed | |
// | |
OldTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL); | |
PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, (UINT32)Offset, 1, &gAllOne); | |
PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, (UINT32)Offset, 1, &Value); | |
// | |
// Write back the original value | |
// | |
PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, (UINT32)Offset, 1, &OriginalValue); | |
// | |
// Restore TPL to its original level | |
// | |
gBS->RestoreTPL (OldTpl); | |
if (BarLengthValue != NULL) { | |
*BarLengthValue = Value; | |
} | |
if (OriginalBarValue != NULL) { | |
*OriginalBarValue = OriginalValue; | |
} | |
if (Value == 0) { | |
return EFI_NOT_FOUND; | |
} else { | |
return EFI_SUCCESS; | |
} | |
} | |
/** | |
Check whether the bar is existed or not. | |
@param PciIoDevice A pointer to the PCI_IO_DEVICE. | |
@param Offset The offset. | |
@param BarLengthValue The bar length value returned. | |
@param OriginalBarValue The original bar value returned. | |
@retval EFI_NOT_FOUND The bar doesn't exist. | |
@retval EFI_SUCCESS The bar exist. | |
**/ | |
EFI_STATUS | |
BarExisted ( | |
IN PCI_IO_DEVICE *PciIoDevice, | |
IN UINTN Offset, | |
OUT UINT32 *BarLengthValue, | |
OUT UINT32 *OriginalBarValue | |
) | |
{ | |
EFI_PCI_IO_PROTOCOL *PciIo; | |
UINT32 OriginalValue; | |
UINT32 Value; | |
EFI_TPL OldTpl; | |
PciIo = &PciIoDevice->PciIo; | |
// | |
// Preserve the original value | |
// | |
PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, (UINT8)Offset, 1, &OriginalValue); | |
// | |
// Raise TPL to high level to disable timer interrupt while the BAR is probed | |
// | |
OldTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL); | |
PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, (UINT8)Offset, 1, &gAllOne); | |
PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, (UINT8)Offset, 1, &Value); | |
// | |
// Write back the original value | |
// | |
PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, (UINT8)Offset, 1, &OriginalValue); | |
// | |
// Restore TPL to its original level | |
// | |
gBS->RestoreTPL (OldTpl); | |
if (BarLengthValue != NULL) { | |
*BarLengthValue = Value; | |
} | |
if (OriginalBarValue != NULL) { | |
*OriginalBarValue = OriginalValue; | |
} | |
if (Value == 0) { | |
return EFI_NOT_FOUND; | |
} else { | |
return EFI_SUCCESS; | |
} | |
} | |
/** | |
Test whether the device can support given attributes. | |
@param PciIoDevice Pci device instance. | |
@param Command Input command register value, and | |
returned supported register value. | |
@param BridgeControl Input bridge control value for PPB or P2C, and | |
returned supported bridge control value. | |
@param OldCommand Returned and stored old command register offset. | |
@param OldBridgeControl Returned and stored old Bridge control value for PPB or P2C. | |
**/ | |
VOID | |
PciTestSupportedAttribute ( | |
IN PCI_IO_DEVICE *PciIoDevice, | |
IN OUT UINT16 *Command, | |
IN OUT UINT16 *BridgeControl, | |
OUT UINT16 *OldCommand, | |
OUT UINT16 *OldBridgeControl | |
) | |
{ | |
EFI_TPL OldTpl; | |
UINT16 CommandValue; | |
// | |
// Preserve the original value | |
// | |
PCI_READ_COMMAND_REGISTER (PciIoDevice, OldCommand); | |
// | |
// Raise TPL to high level to disable timer interrupt while the BAR is probed | |
// | |
OldTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL); | |
CommandValue = *Command | *OldCommand; | |
PCI_SET_COMMAND_REGISTER (PciIoDevice, CommandValue); | |
PCI_READ_COMMAND_REGISTER (PciIoDevice, &CommandValue); | |
*Command = *Command & CommandValue; | |
// | |
// Write back the original value | |
// | |
PCI_SET_COMMAND_REGISTER (PciIoDevice, *OldCommand); | |
// | |
// Restore TPL to its original level | |
// | |
gBS->RestoreTPL (OldTpl); | |
if (IS_PCI_BRIDGE (&PciIoDevice->Pci) || IS_CARDBUS_BRIDGE (&PciIoDevice->Pci)) { | |
// | |
// Preserve the original value | |
// | |
PCI_READ_BRIDGE_CONTROL_REGISTER (PciIoDevice, OldBridgeControl); | |
// | |
// Raise TPL to high level to disable timer interrupt while the BAR is probed | |
// | |
OldTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL); | |
PCI_SET_BRIDGE_CONTROL_REGISTER (PciIoDevice, *BridgeControl); | |
PCI_READ_BRIDGE_CONTROL_REGISTER (PciIoDevice, BridgeControl); | |
// | |
// Write back the original value | |
// | |
PCI_SET_BRIDGE_CONTROL_REGISTER (PciIoDevice, *OldBridgeControl); | |
// | |
// Restore TPL to its original level | |
// | |
gBS->RestoreTPL (OldTpl); | |
} else { | |
*OldBridgeControl = 0; | |
*BridgeControl = 0; | |
} | |
} | |
/** | |
Set the supported or current attributes of a PCI device. | |
@param PciIoDevice Structure pointer for PCI device. | |
@param Command Command register value. | |
@param BridgeControl Bridge control value for PPB or P2C. | |
@param Option Make a choice of EFI_SET_SUPPORTS or EFI_SET_ATTRIBUTES. | |
**/ | |
VOID | |
PciSetDeviceAttribute ( | |
IN PCI_IO_DEVICE *PciIoDevice, | |
IN UINT16 Command, | |
IN UINT16 BridgeControl, | |
IN UINTN Option | |
) | |
{ | |
UINT64 Attributes; | |
Attributes = 0; | |
if ((Command & EFI_PCI_COMMAND_IO_SPACE) != 0) { | |
Attributes |= EFI_PCI_IO_ATTRIBUTE_IO; | |
} | |
if ((Command & EFI_PCI_COMMAND_MEMORY_SPACE) != 0) { | |
Attributes |= EFI_PCI_IO_ATTRIBUTE_MEMORY; | |
} | |
if ((Command & EFI_PCI_COMMAND_BUS_MASTER) != 0) { | |
Attributes |= EFI_PCI_IO_ATTRIBUTE_BUS_MASTER; | |
} | |
if ((Command & EFI_PCI_COMMAND_VGA_PALETTE_SNOOP) != 0) { | |
Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO; | |
} | |
if ((BridgeControl & EFI_PCI_BRIDGE_CONTROL_ISA) != 0) { | |
Attributes |= EFI_PCI_IO_ATTRIBUTE_ISA_IO; | |
} | |
if ((BridgeControl & EFI_PCI_BRIDGE_CONTROL_VGA) != 0) { | |
Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_IO; | |
Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY; | |
Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO; | |
} | |
if ((BridgeControl & EFI_PCI_BRIDGE_CONTROL_VGA_16) != 0) { | |
Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_IO_16; | |
Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO_16; | |
} | |
if (Option == EFI_SET_SUPPORTS) { | |
Attributes |= (UINT64)(EFI_PCI_IO_ATTRIBUTE_MEMORY_WRITE_COMBINE | | |
EFI_PCI_IO_ATTRIBUTE_MEMORY_CACHED | | |
EFI_PCI_IO_ATTRIBUTE_MEMORY_DISABLE | | |
EFI_PCI_IO_ATTRIBUTE_EMBEDDED_DEVICE | | |
EFI_PCI_IO_ATTRIBUTE_EMBEDDED_ROM | | |
EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE); | |
if (IS_PCI_LPC (&PciIoDevice->Pci)) { | |
Attributes |= EFI_PCI_IO_ATTRIBUTE_ISA_MOTHERBOARD_IO; | |
Attributes |= (mReserveIsaAliases ? (UINT64)EFI_PCI_IO_ATTRIBUTE_ISA_IO : \ | |
(UINT64)EFI_PCI_IO_ATTRIBUTE_ISA_IO_16); | |
} | |
if (IS_PCI_BRIDGE (&PciIoDevice->Pci) || IS_CARDBUS_BRIDGE (&PciIoDevice->Pci)) { | |
// | |
// For bridge, it should support IDE attributes | |
// | |
Attributes |= EFI_PCI_IO_ATTRIBUTE_IDE_SECONDARY_IO; | |
Attributes |= EFI_PCI_IO_ATTRIBUTE_IDE_PRIMARY_IO; | |
if (mReserveVgaAliases) { | |
Attributes &= ~(UINT64)(EFI_PCI_IO_ATTRIBUTE_VGA_IO_16 | \ | |
EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO_16); | |
} else { | |
Attributes &= ~(UINT64)(EFI_PCI_IO_ATTRIBUTE_VGA_IO | \ | |
EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO); | |
} | |
} else { | |
if (IS_PCI_IDE (&PciIoDevice->Pci)) { | |
Attributes |= EFI_PCI_IO_ATTRIBUTE_IDE_SECONDARY_IO; | |
Attributes |= EFI_PCI_IO_ATTRIBUTE_IDE_PRIMARY_IO; | |
} | |
if (IS_PCI_VGA (&PciIoDevice->Pci)) { | |
Attributes |= EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY; | |
Attributes |= (mReserveVgaAliases ? (UINT64)EFI_PCI_IO_ATTRIBUTE_VGA_IO : \ | |
(UINT64)EFI_PCI_IO_ATTRIBUTE_VGA_IO_16); | |
} | |
} | |
PciIoDevice->Supports = Attributes; | |
PciIoDevice->Supports &= ((PciIoDevice->Parent->Supports) | \ | |
EFI_PCI_IO_ATTRIBUTE_IO | EFI_PCI_IO_ATTRIBUTE_MEMORY | \ | |
EFI_PCI_IO_ATTRIBUTE_BUS_MASTER); | |
} else { | |
// | |
// When this attribute is clear, the RomImage and RomSize fields in the PCI IO were | |
// initialized based on the PCI option ROM found through the ROM BAR of the PCI controller. | |
// When this attribute is set, the PCI option ROM described by the RomImage and RomSize | |
// fields is not from the the ROM BAR of the PCI controller. | |
// | |
if (!PciIoDevice->EmbeddedRom) { | |
Attributes |= EFI_PCI_IO_ATTRIBUTE_EMBEDDED_ROM; | |
} | |
PciIoDevice->Attributes = Attributes; | |
} | |
} | |
/** | |
Determine if the device can support Fast Back to Back attribute. | |
@param PciIoDevice Pci device instance. | |
@param StatusIndex Status register value. | |
@retval EFI_SUCCESS This device support Fast Back to Back attribute. | |
@retval EFI_UNSUPPORTED This device doesn't support Fast Back to Back attribute. | |
**/ | |
EFI_STATUS | |
GetFastBackToBackSupport ( | |
IN PCI_IO_DEVICE *PciIoDevice, | |
IN UINT8 StatusIndex | |
) | |
{ | |
EFI_PCI_IO_PROTOCOL *PciIo; | |
EFI_STATUS Status; | |
UINT32 StatusRegister; | |
// | |
// Read the status register | |
// | |
PciIo = &PciIoDevice->PciIo; | |
Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint16, StatusIndex, 1, &StatusRegister); | |
if (EFI_ERROR (Status)) { | |
return EFI_UNSUPPORTED; | |
} | |
// | |
// Check the Fast B2B bit | |
// | |
if ((StatusRegister & EFI_PCI_FAST_BACK_TO_BACK_CAPABLE) != 0) { | |
return EFI_SUCCESS; | |
} else { | |
return EFI_UNSUPPORTED; | |
} | |
} | |
/** | |
Process the option ROM for all the children of the specified parent PCI device. | |
It can only be used after the first full Option ROM process. | |
@param PciIoDevice Pci device instance. | |
**/ | |
VOID | |
ProcessOptionRomLight ( | |
IN PCI_IO_DEVICE *PciIoDevice | |
) | |
{ | |
PCI_IO_DEVICE *Temp; | |
LIST_ENTRY *CurrentLink; | |
// | |
// For RootBridge, PPB , P2C, go recursively to traverse all its children | |
// | |
CurrentLink = PciIoDevice->ChildList.ForwardLink; | |
while (CurrentLink != NULL && CurrentLink != &PciIoDevice->ChildList) { | |
Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink); | |
if (!IsListEmpty (&Temp->ChildList)) { | |
ProcessOptionRomLight (Temp); | |
} | |
Temp->AllOpRomProcessed = PciRomGetImageMapping (Temp); | |
CurrentLink = CurrentLink->ForwardLink; | |
} | |
} | |
/** | |
Determine the related attributes of all devices under a Root Bridge. | |
@param PciIoDevice PCI device instance. | |
**/ | |
EFI_STATUS | |
DetermineDeviceAttribute ( | |
IN PCI_IO_DEVICE *PciIoDevice | |
) | |
{ | |
UINT16 Command; | |
UINT16 BridgeControl; | |
UINT16 OldCommand; | |
UINT16 OldBridgeControl; | |
BOOLEAN FastB2BSupport; | |
PCI_IO_DEVICE *Temp; | |
LIST_ENTRY *CurrentLink; | |
EFI_STATUS Status; | |
// | |
// For Root Bridge, just copy it by RootBridgeIo protocol | |
// so as to keep consistent with the actual attribute | |
// | |
if (PciIoDevice->Parent == NULL) { | |
Status = PciIoDevice->PciRootBridgeIo->GetAttributes ( | |
PciIoDevice->PciRootBridgeIo, | |
&PciIoDevice->Supports, | |
&PciIoDevice->Attributes | |
); | |
if (EFI_ERROR (Status)) { | |
return Status; | |
} | |
// | |
// Assume the PCI Root Bridge supports DAC | |
// | |
PciIoDevice->Supports |= (UINT64)(EFI_PCI_IO_ATTRIBUTE_EMBEDDED_DEVICE | | |
EFI_PCI_IO_ATTRIBUTE_EMBEDDED_ROM | | |
EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE); | |
} else { | |
// | |
// Set the attributes to be checked for common PCI devices and PPB or P2C | |
// Since some devices only support part of them, it is better to set the | |
// attribute according to its command or bridge control register | |
// | |
Command = EFI_PCI_COMMAND_IO_SPACE | | |
EFI_PCI_COMMAND_MEMORY_SPACE | | |
EFI_PCI_COMMAND_BUS_MASTER | | |
EFI_PCI_COMMAND_VGA_PALETTE_SNOOP; | |
BridgeControl = EFI_PCI_BRIDGE_CONTROL_ISA | EFI_PCI_BRIDGE_CONTROL_VGA | EFI_PCI_BRIDGE_CONTROL_VGA_16; | |
// | |
// Test whether the device can support attributes above | |
// | |
PciTestSupportedAttribute (PciIoDevice, &Command, &BridgeControl, &OldCommand, &OldBridgeControl); | |
// | |
// Set the supported attributes for specified PCI device | |
// | |
PciSetDeviceAttribute (PciIoDevice, Command, BridgeControl, EFI_SET_SUPPORTS); | |
// | |
// Set the current attributes for specified PCI device | |
// | |
PciSetDeviceAttribute (PciIoDevice, OldCommand, OldBridgeControl, EFI_SET_ATTRIBUTES); | |
// | |
// Enable other PCI supported attributes but not defined in PCI_IO_PROTOCOL | |
// For PCI Express devices, Memory Write and Invalidate is hardwired to 0b so only enable it for PCI devices. | |
if (!PciIoDevice->IsPciExp) { | |
PCI_ENABLE_COMMAND_REGISTER (PciIoDevice, EFI_PCI_COMMAND_MEMORY_WRITE_AND_INVALIDATE); | |
} | |
} | |
FastB2BSupport = TRUE; | |
// | |
// P2C can not support FB2B on the secondary side | |
// | |
if (IS_CARDBUS_BRIDGE (&PciIoDevice->Pci)) { | |
FastB2BSupport = FALSE; | |
} | |
// | |
// For RootBridge, PPB , P2C, go recursively to traverse all its children | |
// | |
CurrentLink = PciIoDevice->ChildList.ForwardLink; | |
while (CurrentLink != NULL && CurrentLink != &PciIoDevice->ChildList) { | |
Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink); | |
Status = DetermineDeviceAttribute (Temp); | |
if (EFI_ERROR (Status)) { | |
return Status; | |
} | |
// | |
// Detect Fast Back to Back support for the device under the bridge | |
// | |
Status = GetFastBackToBackSupport (Temp, PCI_PRIMARY_STATUS_OFFSET); | |
if (FastB2BSupport && EFI_ERROR (Status)) { | |
FastB2BSupport = FALSE; | |
} | |
CurrentLink = CurrentLink->ForwardLink; | |
} | |
// | |
// Set or clear Fast Back to Back bit for the whole bridge | |
// | |
if (!IsListEmpty (&PciIoDevice->ChildList)) { | |
if (IS_PCI_BRIDGE (&PciIoDevice->Pci)) { | |
Status = GetFastBackToBackSupport (PciIoDevice, PCI_BRIDGE_STATUS_REGISTER_OFFSET); | |
if (EFI_ERROR (Status) || (!FastB2BSupport)) { | |
FastB2BSupport = FALSE; | |
PCI_DISABLE_BRIDGE_CONTROL_REGISTER (PciIoDevice, EFI_PCI_BRIDGE_CONTROL_FAST_BACK_TO_BACK); | |
} else { | |
PCI_ENABLE_BRIDGE_CONTROL_REGISTER (PciIoDevice, EFI_PCI_BRIDGE_CONTROL_FAST_BACK_TO_BACK); | |
} | |
} | |
CurrentLink = PciIoDevice->ChildList.ForwardLink; | |
while (CurrentLink != NULL && CurrentLink != &PciIoDevice->ChildList) { | |
Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink); | |
if (FastB2BSupport) { | |
PCI_ENABLE_COMMAND_REGISTER (Temp, EFI_PCI_COMMAND_FAST_BACK_TO_BACK); | |
} else { | |
PCI_DISABLE_COMMAND_REGISTER (Temp, EFI_PCI_COMMAND_FAST_BACK_TO_BACK); | |
} | |
CurrentLink = CurrentLink->ForwardLink; | |
} | |
} | |
// | |
// End for IsListEmpty | |
// | |
return EFI_SUCCESS; | |
} | |
/** | |
This routine is used to update the bar information for those incompatible PCI device. | |
@param PciIoDevice Input Pci device instance. Output Pci device instance with updated | |
Bar information. | |
@param IgnoreOptionRom Output If the option rom of incompatible device need to be ignored. | |
@retval EFI_SUCCESS Successfully updated bar information. | |
@retval EFI_UNSUPPORTED Given PCI device doesn't belong to incompatible PCI device list. | |
**/ | |
EFI_STATUS | |
UpdatePciInfo ( | |
IN OUT PCI_IO_DEVICE *PciIoDevice, | |
OUT BOOLEAN *IgnoreOptionRom | |
) | |
{ | |
EFI_STATUS Status; | |
UINTN BarIndex; | |
BOOLEAN SetFlag; | |
VOID *Configuration; | |
EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Ptr; | |
Configuration = NULL; | |
Status = EFI_SUCCESS; | |
if (gIncompatiblePciDeviceSupport == NULL) { | |
// | |
// It can only be supported after the Incompatible PCI Device | |
// Support Protocol has been installed | |
// | |
Status = gBS->LocateProtocol ( | |
&gEfiIncompatiblePciDeviceSupportProtocolGuid, | |
NULL, | |
(VOID **)&gIncompatiblePciDeviceSupport | |
); | |
} | |
if (Status == EFI_SUCCESS) { | |
// | |
// Check whether the device belongs to incompatible devices from protocol or not | |
// If it is , then get its special requirement in the ACPI table | |
// | |
Status = gIncompatiblePciDeviceSupport->CheckDevice ( | |
gIncompatiblePciDeviceSupport, | |
PciIoDevice->Pci.Hdr.VendorId, | |
PciIoDevice->Pci.Hdr.DeviceId, | |
PciIoDevice->Pci.Hdr.RevisionID, | |
PciIoDevice->Pci.Device.SubsystemVendorID, | |
PciIoDevice->Pci.Device.SubsystemID, | |
&Configuration | |
); | |
} | |
if (EFI_ERROR (Status) || (Configuration == NULL)) { | |
return EFI_UNSUPPORTED; | |
} | |
// | |
// Update PCI device information from the ACPI table | |
// | |
Ptr = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *)Configuration; | |
while (Ptr->Desc != ACPI_END_TAG_DESCRIPTOR) { | |
if (Ptr->Desc != ACPI_ADDRESS_SPACE_DESCRIPTOR) { | |
// | |
// The format is not support | |
// | |
break; | |
} | |
// | |
// According to "Table 20. ACPI 2.0 & 3.0 QWORD Address Space Descriptor Usage" | |
// in PI Spec 1.7, Type-specific flags can be set to 0 when Address Translation | |
// Offset == 6 to skip device option ROM (do not probe option rom BAR). | |
// | |
if (((Ptr->AddrTranslationOffset == PCI_MAX_BAR) && (Ptr->SpecificFlag == 0))) { | |
*IgnoreOptionRom = TRUE; | |
Ptr++; | |
continue; | |
} | |
for (BarIndex = 0; BarIndex < PCI_MAX_BAR; BarIndex++) { | |
if ((Ptr->AddrTranslationOffset != MAX_UINT64) && | |
(Ptr->AddrTranslationOffset != MAX_UINT8) && | |
(Ptr->AddrTranslationOffset != BarIndex) | |
) | |
{ | |
// | |
// Skip updating when AddrTranslationOffset is not MAX_UINT64 or MAX_UINT8 (wide match). | |
// Skip updating when current BarIndex doesn't equal to AddrTranslationOffset. | |
// Comparing against MAX_UINT8 is to keep backward compatibility. | |
// | |
continue; | |
} | |
SetFlag = FALSE; | |
switch (Ptr->ResType) { | |
case ACPI_ADDRESS_SPACE_TYPE_MEM: | |
// | |
// Make sure the bar is memory type | |
// | |
if (CheckBarType (PciIoDevice, (UINT8)BarIndex, PciBarTypeMem)) { | |
SetFlag = TRUE; | |
// | |
// Ignored if granularity is 0. | |
// Ignored if PCI BAR is I/O or 32-bit memory. | |
// If PCI BAR is 64-bit memory and granularity is 32, then | |
// the PCI BAR resource is allocated below 4GB. | |
// If PCI BAR is 64-bit memory and granularity is 64, then | |
// the PCI BAR resource is allocated above 4GB. | |
// | |
if (PciIoDevice->PciBar[BarIndex].BarType == PciBarTypeMem64) { | |
switch (Ptr->AddrSpaceGranularity) { | |
case 32: | |
PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeMem32; | |
case 64: | |
PciIoDevice->PciBar[BarIndex].BarTypeFixed = TRUE; | |
break; | |
default: | |
break; | |
} | |
} | |
if (PciIoDevice->PciBar[BarIndex].BarType == PciBarTypePMem64) { | |
switch (Ptr->AddrSpaceGranularity) { | |
case 32: | |
PciIoDevice->PciBar[BarIndex].BarType = PciBarTypePMem32; | |
case 64: | |
PciIoDevice->PciBar[BarIndex].BarTypeFixed = TRUE; | |
break; | |
default: | |
break; | |
} | |
} | |
} | |
break; | |
case ACPI_ADDRESS_SPACE_TYPE_IO: | |
// | |
// Make sure the bar is IO type | |
// | |
if (CheckBarType (PciIoDevice, (UINT8)BarIndex, PciBarTypeIo)) { | |
SetFlag = TRUE; | |
} | |
break; | |
} | |
if (SetFlag) { | |
// | |
// Update the new alignment for the device | |
// | |
SetNewAlign (&(PciIoDevice->PciBar[BarIndex].Alignment), Ptr->AddrRangeMax); | |
// | |
// Update the new length for the device | |
// | |
if (Ptr->AddrLen != 0) { | |
PciIoDevice->PciBar[BarIndex].Length = Ptr->AddrLen; | |
} | |
} | |
} | |
Ptr++; | |
} | |
FreePool (Configuration); | |
return EFI_SUCCESS; | |
} | |
/** | |
This routine will update the alignment with the new alignment. | |
Compare with OLD_ALIGN/EVEN_ALIGN/SQUAD_ALIGN/DQUAD_ALIGN is to keep | |
backward compatibility. | |
@param Alignment Input Old alignment. Output updated alignment. | |
@param NewAlignment New alignment. | |
**/ | |
VOID | |
SetNewAlign ( | |
IN OUT UINT64 *Alignment, | |
IN UINT64 NewAlignment | |
) | |
{ | |
UINT64 OldAlignment; | |
UINTN ShiftBit; | |
// | |
// The new alignment is the same as the original, | |
// so skip it | |
// | |
if ((NewAlignment == 0) || (NewAlignment == OLD_ALIGN)) { | |
return; | |
} | |
// | |
// Check the validity of the parameter | |
// | |
if ((NewAlignment != EVEN_ALIGN) && | |
(NewAlignment != SQUAD_ALIGN) && | |
(NewAlignment != DQUAD_ALIGN)) | |
{ | |
*Alignment = NewAlignment; | |
return; | |
} | |
OldAlignment = (*Alignment) + 1; | |
ShiftBit = 0; | |
// | |
// Get the first non-zero hex value of the length | |
// | |
while ((OldAlignment & 0x0F) == 0x00) { | |
OldAlignment = RShiftU64 (OldAlignment, 4); | |
ShiftBit += 4; | |
} | |
// | |
// Adjust the alignment to even, quad or double quad boundary | |
// | |
if (NewAlignment == EVEN_ALIGN) { | |
if ((OldAlignment & 0x01) != 0) { | |
OldAlignment = OldAlignment + 2 - (OldAlignment & 0x01); | |
} | |
} else if (NewAlignment == SQUAD_ALIGN) { | |
if ((OldAlignment & 0x03) != 0) { | |
OldAlignment = OldAlignment + 4 - (OldAlignment & 0x03); | |
} | |
} else if (NewAlignment == DQUAD_ALIGN) { | |
if ((OldAlignment & 0x07) != 0) { | |
OldAlignment = OldAlignment + 8 - (OldAlignment & 0x07); | |
} | |
} | |
// | |
// Update the old value | |
// | |
NewAlignment = LShiftU64 (OldAlignment, ShiftBit) - 1; | |
*Alignment = NewAlignment; | |
return; | |
} | |
/** | |
Parse PCI IOV VF bar information and fill them into PCI device instance. | |
@param PciIoDevice Pci device instance. | |
@param Offset Bar offset. | |
@param BarIndex Bar index. | |
@return Next bar offset. | |
**/ | |
UINTN | |
PciIovParseVfBar ( | |
IN PCI_IO_DEVICE *PciIoDevice, | |
IN UINTN Offset, | |
IN UINTN BarIndex | |
) | |
{ | |
UINT32 Value; | |
UINT32 OriginalValue; | |
UINT32 Mask; | |
EFI_STATUS Status; | |
// | |
// Ensure it is called properly | |
// | |
ASSERT (PciIoDevice->SrIovCapabilityOffset != 0); | |
if (PciIoDevice->SrIovCapabilityOffset == 0) { | |
return 0; | |
} | |
OriginalValue = 0; | |
Value = 0; | |
Status = VfBarExisted ( | |
PciIoDevice, | |
Offset, | |
&Value, | |
&OriginalValue | |
); | |
if (EFI_ERROR (Status)) { | |
PciIoDevice->VfPciBar[BarIndex].BaseAddress = 0; | |
PciIoDevice->VfPciBar[BarIndex].Length = 0; | |
PciIoDevice->VfPciBar[BarIndex].Alignment = 0; | |
// | |
// Scan all the BARs anyway | |
// | |
PciIoDevice->VfPciBar[BarIndex].Offset = (UINT16)Offset; | |
return Offset + 4; | |
} | |
PciIoDevice->VfPciBar[BarIndex].Offset = (UINT16)Offset; | |
if ((Value & 0x01) != 0) { | |
// | |
// Device I/Os. Impossible | |
// | |
ASSERT (FALSE); | |
return Offset + 4; | |
} else { | |
Mask = 0xfffffff0; | |
PciIoDevice->VfPciBar[BarIndex].BaseAddress = OriginalValue & Mask; | |
switch (Value & 0x07) { | |
// | |
// memory space; anywhere in 32 bit address space | |
// | |
case 0x00: | |
if ((Value & 0x08) != 0) { | |
PciIoDevice->VfPciBar[BarIndex].BarType = PciBarTypePMem32; | |
} else { | |
PciIoDevice->VfPciBar[BarIndex].BarType = PciBarTypeMem32; | |
} | |
PciIoDevice->VfPciBar[BarIndex].Length = (~(Value & Mask)) + 1; | |
PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->VfPciBar[BarIndex].Length - 1; | |
// | |
// Adjust Length | |
// | |
PciIoDevice->VfPciBar[BarIndex].Length = MultU64x32 (PciIoDevice->VfPciBar[BarIndex].Length, PciIoDevice->InitialVFs); | |
// | |
// Adjust Alignment | |
// | |
if (PciIoDevice->VfPciBar[BarIndex].Alignment < PciIoDevice->SystemPageSize - 1) { | |
PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->SystemPageSize - 1; | |
} | |
break; | |
// | |
// memory space; anywhere in 64 bit address space | |
// | |
case 0x04: | |
if ((Value & 0x08) != 0) { | |
PciIoDevice->VfPciBar[BarIndex].BarType = PciBarTypePMem64; | |
} else { | |
PciIoDevice->VfPciBar[BarIndex].BarType = PciBarTypeMem64; | |
} | |
// | |
// According to PCI 2.2,if the bar indicates a memory 64 decoding, next bar | |
// is regarded as an extension for the first bar. As a result | |
// the sizing will be conducted on combined 64 bit value | |
// Here just store the masked first 32bit value for future size | |
// calculation | |
// | |
PciIoDevice->VfPciBar[BarIndex].Length = Value & Mask; | |
PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->VfPciBar[BarIndex].Length - 1; | |
if (PciIoDevice->VfPciBar[BarIndex].Alignment < PciIoDevice->SystemPageSize - 1) { | |
PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->SystemPageSize - 1; | |
} | |
// | |
// Increment the offset to point to next DWORD | |
// | |
Offset += 4; | |
Status = VfBarExisted ( | |
PciIoDevice, | |
Offset, | |
&Value, | |
&OriginalValue | |
); | |
if (EFI_ERROR (Status)) { | |
PciIoDevice->VfPciBar[BarIndex].BarType = PciBarTypeUnknown; | |
return Offset + 4; | |
} | |
// | |
// Fix the length to support some special 64 bit BAR | |
// | |
Value |= ((UINT32)-1 << HighBitSet32 (Value)); | |
// | |
// Calculate the size of 64bit bar | |
// | |
PciIoDevice->VfPciBar[BarIndex].BaseAddress |= LShiftU64 ((UINT64)OriginalValue, 32); | |
PciIoDevice->VfPciBar[BarIndex].Length = PciIoDevice->VfPciBar[BarIndex].Length | LShiftU64 ((UINT64)Value, 32); | |
PciIoDevice->VfPciBar[BarIndex].Length = (~(PciIoDevice->VfPciBar[BarIndex].Length)) + 1; | |
PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->VfPciBar[BarIndex].Length - 1; | |
// | |
// Adjust Length | |
// | |
PciIoDevice->VfPciBar[BarIndex].Length = MultU64x32 (PciIoDevice->VfPciBar[BarIndex].Length, PciIoDevice->InitialVFs); | |
// | |
// Adjust Alignment | |
// | |
if (PciIoDevice->VfPciBar[BarIndex].Alignment < PciIoDevice->SystemPageSize - 1) { | |
PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->SystemPageSize - 1; | |
} | |
break; | |
// | |
// reserved | |
// | |
default: | |
PciIoDevice->VfPciBar[BarIndex].BarType = PciBarTypeUnknown; | |
PciIoDevice->VfPciBar[BarIndex].Length = (~(Value & Mask)) + 1; | |
PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->VfPciBar[BarIndex].Length - 1; | |
if (PciIoDevice->VfPciBar[BarIndex].Alignment < PciIoDevice->SystemPageSize - 1) { | |
PciIoDevice->VfPciBar[BarIndex].Alignment = PciIoDevice->SystemPageSize - 1; | |
} | |
break; | |
} | |
} | |
// | |
// Check the length again so as to keep compatible with some special bars | |
// | |
if (PciIoDevice->VfPciBar[BarIndex].Length == 0) { | |
PciIoDevice->VfPciBar[BarIndex].BarType = PciBarTypeUnknown; | |
PciIoDevice->VfPciBar[BarIndex].BaseAddress = 0; | |
PciIoDevice->VfPciBar[BarIndex].Alignment = 0; | |
} | |
// | |
// Increment number of bar | |
// | |
return Offset + 4; | |
} | |
/** | |
Parse PCI bar information and fill them into PCI device instance. | |
@param PciIoDevice Pci device instance. | |
@param Offset Bar offset. | |
@param BarIndex Bar index. | |
@return Next bar offset. | |
**/ | |
UINTN | |
PciParseBar ( | |
IN PCI_IO_DEVICE *PciIoDevice, | |
IN UINTN Offset, | |
IN UINTN BarIndex | |
) | |
{ | |
UINT32 Value; | |
UINT32 OriginalValue; | |
UINT32 Mask; | |
EFI_STATUS Status; | |
OriginalValue = 0; | |
Value = 0; | |
Status = BarExisted ( | |
PciIoDevice, | |
Offset, | |
&Value, | |
&OriginalValue | |
); | |
if (EFI_ERROR (Status)) { | |
PciIoDevice->PciBar[BarIndex].BaseAddress = 0; | |
PciIoDevice->PciBar[BarIndex].Length = 0; | |
PciIoDevice->PciBar[BarIndex].Alignment = 0; | |
// | |
// Some devices don't fully comply to PCI spec 2.2. So be to scan all the BARs anyway | |
// | |
PciIoDevice->PciBar[BarIndex].Offset = (UINT8)Offset; | |
return Offset + 4; | |
} | |
PciIoDevice->PciBar[BarIndex].BarTypeFixed = FALSE; | |
PciIoDevice->PciBar[BarIndex].Offset = (UINT8)Offset; | |
if ((Value & 0x01) != 0) { | |
// | |
// Device I/Os | |
// | |
Mask = 0xfffffffc; | |
if ((Value & 0xFFFF0000) != 0) { | |
// | |
// It is a IO32 bar | |
// | |
PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeIo32; | |
PciIoDevice->PciBar[BarIndex].Length = ((~(Value & Mask)) + 1); | |
PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1; | |
} else { | |
// | |
// It is a IO16 bar | |
// | |
PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeIo16; | |
PciIoDevice->PciBar[BarIndex].Length = 0x0000FFFF & ((~(Value & Mask)) + 1); | |
PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1; | |
} | |
// | |
// Workaround. Some platforms implement IO bar with 0 length | |
// Need to treat it as no-bar | |
// | |
if (PciIoDevice->PciBar[BarIndex].Length == 0) { | |
PciIoDevice->PciBar[BarIndex].BarType = (PCI_BAR_TYPE)0; | |
} | |
PciIoDevice->PciBar[BarIndex].BaseAddress = OriginalValue & Mask; | |
} else { | |
Mask = 0xfffffff0; | |
PciIoDevice->PciBar[BarIndex].BaseAddress = OriginalValue & Mask; | |
switch (Value & 0x07) { | |
// | |
// memory space; anywhere in 32 bit address space | |
// | |
case 0x00: | |
if ((Value & 0x08) != 0) { | |
PciIoDevice->PciBar[BarIndex].BarType = PciBarTypePMem32; | |
} else { | |
PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeMem32; | |
} | |
PciIoDevice->PciBar[BarIndex].Length = (~(Value & Mask)) + 1; | |
if (PciIoDevice->PciBar[BarIndex].Length < (SIZE_4KB)) { | |
// | |
// Force minimum 4KByte alignment for Virtualization technology for Directed I/O | |
// | |
PciIoDevice->PciBar[BarIndex].Alignment = (SIZE_4KB - 1); | |
} else { | |
PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1; | |
} | |
break; | |
// | |
// memory space; anywhere in 64 bit address space | |
// | |
case 0x04: | |
if ((Value & 0x08) != 0) { | |
PciIoDevice->PciBar[BarIndex].BarType = PciBarTypePMem64; | |
} else { | |
PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeMem64; | |
} | |
// | |
// According to PCI 2.2,if the bar indicates a memory 64 decoding, next bar | |
// is regarded as an extension for the first bar. As a result | |
// the sizing will be conducted on combined 64 bit value | |
// Here just store the masked first 32bit value for future size | |
// calculation | |
// | |
PciIoDevice->PciBar[BarIndex].Length = Value & Mask; | |
PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1; | |
// | |
// Increment the offset to point to next DWORD | |
// | |
Offset += 4; | |
Status = BarExisted ( | |
PciIoDevice, | |
Offset, | |
&Value, | |
&OriginalValue | |
); | |
if (EFI_ERROR (Status)) { | |
// | |
// the high 32 bit does not claim any BAR, we need to re-check the low 32 bit BAR again | |
// | |
if (PciIoDevice->PciBar[BarIndex].Length == 0) { | |
// | |
// some device implement MMIO bar with 0 length, need to treat it as no-bar | |
// | |
PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeUnknown; | |
return Offset + 4; | |
} | |
} | |
// | |
// Fix the length to support some special 64 bit BAR | |
// | |
if (Value == 0) { | |
DEBUG ((DEBUG_INFO, "[PciBus]BAR probing for upper 32bit of MEM64 BAR returns 0, change to 0xFFFFFFFF.\n")); | |
Value = (UINT32)-1; | |
} else { | |
Value |= ((UINT32)(-1) << HighBitSet32 (Value)); | |
} | |
// | |
// Calculate the size of 64bit bar | |
// | |
PciIoDevice->PciBar[BarIndex].BaseAddress |= LShiftU64 ((UINT64)OriginalValue, 32); | |
PciIoDevice->PciBar[BarIndex].Length = PciIoDevice->PciBar[BarIndex].Length | LShiftU64 ((UINT64)Value, 32); | |
PciIoDevice->PciBar[BarIndex].Length = (~(PciIoDevice->PciBar[BarIndex].Length)) + 1; | |
if (PciIoDevice->PciBar[BarIndex].Length < (SIZE_4KB)) { | |
// | |
// Force minimum 4KByte alignment for Virtualization technology for Directed I/O | |
// | |
PciIoDevice->PciBar[BarIndex].Alignment = (SIZE_4KB - 1); | |
} else { | |
PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1; | |
} | |
break; | |
// | |
// reserved | |
// | |
default: | |
PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeUnknown; | |
PciIoDevice->PciBar[BarIndex].Length = (~(Value & Mask)) + 1; | |
if (PciIoDevice->PciBar[BarIndex].Length < (SIZE_4KB)) { | |
// | |
// Force minimum 4KByte alignment for Virtualization technology for Directed I/O | |
// | |
PciIoDevice->PciBar[BarIndex].Alignment = (SIZE_4KB - 1); | |
} else { | |
PciIoDevice->PciBar[BarIndex].Alignment = PciIoDevice->PciBar[BarIndex].Length - 1; | |
} | |
break; | |
} | |
} | |
// | |
// Check the length again so as to keep compatible with some special bars | |
// | |
if (PciIoDevice->PciBar[BarIndex].Length == 0) { | |
PciIoDevice->PciBar[BarIndex].BarType = PciBarTypeUnknown; | |
PciIoDevice->PciBar[BarIndex].BaseAddress = 0; | |
PciIoDevice->PciBar[BarIndex].Alignment = 0; | |
} | |
// | |
// Increment number of bar | |
// | |
return Offset + 4; | |
} | |
/** | |
This routine is used to initialize the bar of a PCI device. | |
@param PciIoDevice Pci device instance. | |
@note It can be called typically when a device is going to be rejected. | |
**/ | |
VOID | |
InitializePciDevice ( | |
IN PCI_IO_DEVICE *PciIoDevice | |
) | |
{ | |
EFI_PCI_IO_PROTOCOL *PciIo; | |
UINT8 Offset; | |
PciIo = &(PciIoDevice->PciIo); | |
// | |
// Put all the resource apertures | |
// Resource base is set to all ones so as to indicate its resource | |
// has not been allocated | |
// | |
for (Offset = 0x10; Offset <= 0x24; Offset += sizeof (UINT32)) { | |
PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, Offset, 1, &gAllOne); | |
} | |
} | |
/** | |
This routine is used to initialize the bar of a PCI-PCI Bridge device. | |
@param PciIoDevice PCI-PCI bridge device instance. | |
**/ | |
VOID | |
InitializePpb ( | |
IN PCI_IO_DEVICE *PciIoDevice | |
) | |
{ | |
EFI_PCI_IO_PROTOCOL *PciIo; | |
PciIo = &(PciIoDevice->PciIo); | |
// | |
// Put all the resource apertures including IO16 | |
// Io32, pMem32, pMem64 to quiescent state | |
// Resource base all ones, Resource limit all zeros | |
// | |
PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x1C, 1, &gAllOne); | |
PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x1D, 1, &gAllZero); | |
PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x20, 1, &gAllOne); | |
PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x22, 1, &gAllZero); | |
PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x24, 1, &gAllOne); | |
PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x26, 1, &gAllZero); | |
PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x28, 1, &gAllOne); | |
PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x2C, 1, &gAllZero); | |
// | |
// Don't support use io32 as for now | |
// | |
PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x30, 1, &gAllOne); | |
PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x32, 1, &gAllZero); | |
// | |
// Force Interrupt line to zero for cards that come up randomly | |
// | |
PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x3C, 1, &gAllZero); | |
} | |
/** | |
This routine is used to initialize the bar of a PCI Card Bridge device. | |
@param PciIoDevice PCI Card bridge device. | |
**/ | |
VOID | |
InitializeP2C ( | |
IN PCI_IO_DEVICE *PciIoDevice | |
) | |
{ | |
EFI_PCI_IO_PROTOCOL *PciIo; | |
PciIo = &(PciIoDevice->PciIo); | |
// | |
// Put all the resource apertures including IO16 | |
// Io32, pMem32, pMem64 to quiescent state( | |
// Resource base all ones, Resource limit all zeros | |
// | |
PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x1c, 1, &gAllOne); | |
PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x20, 1, &gAllZero); | |
PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x24, 1, &gAllOne); | |
PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x28, 1, &gAllZero); | |
PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x2c, 1, &gAllOne); | |
PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x30, 1, &gAllZero); | |
PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x34, 1, &gAllOne); | |
PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x38, 1, &gAllZero); | |
// | |
// Force Interrupt line to zero for cards that come up randomly | |
// | |
PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x3C, 1, &gAllZero); | |
} | |
/** | |
Authenticate the PCI device by using DeviceSecurityProtocol. | |
@param PciIoDevice PCI device. | |
@retval EFI_SUCCESS The device passes the authentication. | |
@return not EFI_SUCCESS The device failes the authentication or | |
unexpected error happen during authentication. | |
**/ | |
EFI_STATUS | |
AuthenticatePciDevice ( | |
IN PCI_IO_DEVICE *PciIoDevice | |
) | |
{ | |
EDKII_DEVICE_IDENTIFIER DeviceIdentifier; | |
EFI_STATUS Status; | |
if (mDeviceSecurityProtocol != NULL) { | |
// | |
// Prepare the parameter | |
// | |
DeviceIdentifier.Version = EDKII_DEVICE_IDENTIFIER_REVISION; | |
CopyGuid (&DeviceIdentifier.DeviceType, &gEdkiiDeviceIdentifierTypePciGuid); | |
DeviceIdentifier.DeviceHandle = NULL; | |
Status = gBS->InstallMultipleProtocolInterfaces ( | |
&DeviceIdentifier.DeviceHandle, | |
&gEfiDevicePathProtocolGuid, | |
PciIoDevice->DevicePath, | |
&gEdkiiDeviceIdentifierTypePciGuid, | |
&PciIoDevice->PciIo, | |
NULL | |
); | |
if (EFI_ERROR (Status)) { | |
return Status; | |
} | |
// | |
// Do DeviceAuthentication | |
// | |
Status = mDeviceSecurityProtocol->DeviceAuthenticate (mDeviceSecurityProtocol, &DeviceIdentifier); | |
// | |
// Always uninstall, because they are only for Authentication. | |
// No need to check return Status. | |
// | |
gBS->UninstallMultipleProtocolInterfaces ( | |
DeviceIdentifier.DeviceHandle, | |
&gEfiDevicePathProtocolGuid, | |
PciIoDevice->DevicePath, | |
&gEdkiiDeviceIdentifierTypePciGuid, | |
&PciIoDevice->PciIo, | |
NULL | |
); | |
return Status; | |
} | |
// | |
// Device Security Protocol is not found, just return success | |
// | |
return EFI_SUCCESS; | |
} | |
/** | |
Checks if PCI device is Root Bridge. | |
@param PciIoDevice Instance of PCI device | |
@retval TRUE Device is Root Bridge | |
@retval FALSE Device is not Root Bridge | |
**/ | |
BOOLEAN | |
IsRootBridge ( | |
IN PCI_IO_DEVICE *PciIoDevice | |
) | |
{ | |
if (PciIoDevice->Parent == NULL) { | |
return TRUE; | |
} else { | |
return FALSE; | |
} | |
} | |
/** | |
Create and initialize general PCI I/O device instance for | |
PCI device/bridge device/hotplug bridge device. | |
@param Bridge Parent bridge instance. | |
@param Pci Input Pci information block. | |
@param Bus Device Bus NO. | |
@param Device Device device NO. | |
@param Func Device func NO. | |
@return Instance of PCI device. NULL means no instance created. | |
**/ | |
PCI_IO_DEVICE * | |
CreatePciIoDevice ( | |
IN PCI_IO_DEVICE *Bridge, | |
IN PCI_TYPE00 *Pci, | |
IN UINT8 Bus, | |
IN UINT8 Device, | |
IN UINT8 Func | |
) | |
{ | |
PCI_IO_DEVICE *PciIoDevice; | |
EFI_PCI_IO_PROTOCOL *PciIo; | |
EFI_STATUS Status; | |
PciIoDevice = AllocateZeroPool (sizeof (PCI_IO_DEVICE)); | |
if (PciIoDevice == NULL) { | |
return NULL; | |
} | |
PciIoDevice->Signature = PCI_IO_DEVICE_SIGNATURE; | |
PciIoDevice->Handle = NULL; | |
PciIoDevice->PciRootBridgeIo = Bridge->PciRootBridgeIo; | |
PciIoDevice->DevicePath = NULL; | |
PciIoDevice->BusNumber = Bus; | |
PciIoDevice->DeviceNumber = Device; | |
PciIoDevice->FunctionNumber = Func; | |
PciIoDevice->Decodes = 0; | |
if (gFullEnumeration) { | |
PciIoDevice->Allocated = FALSE; | |
} else { | |
PciIoDevice->Allocated = TRUE; | |
} | |
PciIoDevice->Registered = FALSE; | |
PciIoDevice->Attributes = 0; | |
PciIoDevice->Supports = 0; | |
PciIoDevice->BusOverride = FALSE; | |
PciIoDevice->AllOpRomProcessed = FALSE; | |
PciIoDevice->IsPciExp = FALSE; | |
CopyMem (&(PciIoDevice->Pci), Pci, sizeof (PCI_TYPE01)); | |
// | |
// Initialize the PCI I/O instance structure | |
// | |
InitializePciIoInstance (PciIoDevice); | |
InitializePciDriverOverrideInstance (PciIoDevice); | |
InitializePciLoadFile2 (PciIoDevice); | |
PciIo = &PciIoDevice->PciIo; | |
// | |
// Create a device path for this PCI device and store it into its private data | |
// | |
CreatePciDevicePath ( | |
Bridge->DevicePath, | |
PciIoDevice | |
); | |
// | |
// Detect if PCI Express Device | |
// | |
PciIoDevice->PciExpressCapabilityOffset = 0; | |
Status = LocateCapabilityRegBlock ( | |
PciIoDevice, | |
EFI_PCI_CAPABILITY_ID_PCIEXP, | |
&PciIoDevice->PciExpressCapabilityOffset, | |
NULL | |
); | |
if (!EFI_ERROR (Status)) { | |
PciIoDevice->IsPciExp = TRUE; | |
} | |
// | |
// Now we can do the authentication check for the device. | |
// | |
Status = AuthenticatePciDevice (PciIoDevice); | |
// | |
// If authentication fails, skip this device. | |
// | |
if (EFI_ERROR (Status)) { | |
if (PciIoDevice->DevicePath != NULL) { | |
FreePool (PciIoDevice->DevicePath); | |
} | |
FreePool (PciIoDevice); | |
return NULL; | |
} | |
// | |
// Check if device's parent is not Root Bridge | |
// | |
if (PcdGetBool (PcdAriSupport) && !IsRootBridge (Bridge)) { | |
// | |
// Check if the device is an ARI device. | |
// | |
Status = LocatePciExpressCapabilityRegBlock ( | |
PciIoDevice, | |
EFI_PCIE_CAPABILITY_ID_ARI, | |
&PciIoDevice->AriCapabilityOffset, | |
NULL | |
); | |
if (!EFI_ERROR (Status)) { | |
// | |
// We need to enable ARI feature before calculate BusReservation, | |
// because FirstVFOffset and VFStride may change after that. | |
// | |
EFI_PCI_IO_PROTOCOL *ParentPciIo; | |
UINT32 Data32; | |
// | |
// Check if its parent supports ARI forwarding. | |
// | |
ParentPciIo = &Bridge->PciIo; | |
ParentPciIo->Pci.Read ( | |
ParentPciIo, | |
EfiPciIoWidthUint32, | |
Bridge->PciExpressCapabilityOffset + EFI_PCIE_CAPABILITY_DEVICE_CAPABILITIES_2_OFFSET, | |
1, | |
&Data32 | |
); | |
if ((Data32 & EFI_PCIE_CAPABILITY_DEVICE_CAPABILITIES_2_ARI_FORWARDING) != 0) { | |
PciIoDevice->IsAriEnabled = TRUE; | |
// | |
// ARI forward support in bridge, so enable it. | |
// | |
ParentPciIo->Pci.Read ( | |
ParentPciIo, | |
EfiPciIoWidthUint32, | |
Bridge->PciExpressCapabilityOffset + EFI_PCIE_CAPABILITY_DEVICE_CONTROL_2_OFFSET, | |
1, | |
&Data32 | |
); | |
if ((Data32 & EFI_PCIE_CAPABILITY_DEVICE_CONTROL_2_ARI_FORWARDING) == 0) { | |
Data32 |= EFI_PCIE_CAPABILITY_DEVICE_CONTROL_2_ARI_FORWARDING; | |
ParentPciIo->Pci.Write ( | |
ParentPciIo, | |
EfiPciIoWidthUint32, | |
Bridge->PciExpressCapabilityOffset + EFI_PCIE_CAPABILITY_DEVICE_CONTROL_2_OFFSET, | |
1, | |
&Data32 | |
); | |
DEBUG (( | |
DEBUG_INFO, | |
" ARI: forwarding enabled for PPB[%02x:%02x:%02x]\n", | |
Bridge->BusNumber, | |
Bridge->DeviceNumber, | |
Bridge->FunctionNumber | |
)); | |
} | |
} | |
DEBUG ((DEBUG_INFO, " ARI: CapOffset = 0x%x\n", PciIoDevice->AriCapabilityOffset)); | |
} | |
} | |
// | |
// Initialization for SR-IOV | |
// | |
if (PcdGetBool (PcdSrIovSupport)) { | |
Status = LocatePciExpressCapabilityRegBlock ( | |
PciIoDevice, | |
EFI_PCIE_CAPABILITY_ID_SRIOV, | |
&PciIoDevice->SrIovCapabilityOffset, | |
NULL | |
); | |
if (!EFI_ERROR (Status)) { | |
UINT32 SupportedPageSize; | |
UINT16 VFStride; | |
UINT16 FirstVFOffset; | |
UINT16 Data16; | |
UINT32 PFRid; | |
UINT32 LastVF; | |
// | |
// If the SR-IOV device is an ARI device, then Set ARI Capable Hierarchy for the device. | |
// | |
if (PcdGetBool (PcdAriSupport) && (PciIoDevice->AriCapabilityOffset != 0)) { | |
PciIo->Pci.Read ( | |
PciIo, | |
EfiPciIoWidthUint16, | |
PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_CONTROL, | |
1, | |
&Data16 | |
); | |
Data16 |= EFI_PCIE_CAPABILITY_ID_SRIOV_CONTROL_ARI_HIERARCHY; | |
PciIo->Pci.Write ( | |
PciIo, | |
EfiPciIoWidthUint16, | |
PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_CONTROL, | |
1, | |
&Data16 | |
); | |
} | |
// | |
// Calculate SystemPageSize | |
// | |
PciIo->Pci.Read ( | |
PciIo, | |
EfiPciIoWidthUint32, | |
PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_SUPPORTED_PAGE_SIZE, | |
1, | |
&SupportedPageSize | |
); | |
PciIoDevice->SystemPageSize = (PcdGet32 (PcdSrIovSystemPageSize) & SupportedPageSize); | |
ASSERT (PciIoDevice->SystemPageSize != 0); | |
PciIo->Pci.Write ( | |
PciIo, | |
EfiPciIoWidthUint32, | |
PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_SYSTEM_PAGE_SIZE, | |
1, | |
&PciIoDevice->SystemPageSize | |
); | |
// | |
// Adjust SystemPageSize for Alignment usage later | |
// | |
PciIoDevice->SystemPageSize <<= 12; | |
// | |
// Calculate BusReservation for PCI IOV | |
// | |
// | |
// Read First FirstVFOffset, InitialVFs, and VFStride | |
// | |
PciIo->Pci.Read ( | |
PciIo, | |
EfiPciIoWidthUint16, | |
PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_FIRSTVF, | |
1, | |
&FirstVFOffset | |
); | |
PciIo->Pci.Read ( | |
PciIo, | |
EfiPciIoWidthUint16, | |
PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_INITIALVFS, | |
1, | |
&PciIoDevice->InitialVFs | |
); | |
PciIo->Pci.Read ( | |
PciIo, | |
EfiPciIoWidthUint16, | |
PciIoDevice->SrIovCapabilityOffset + EFI_PCIE_CAPABILITY_ID_SRIOV_VFSTRIDE, | |
1, | |
&VFStride | |
); | |
// | |
// Calculate LastVF | |
// | |
if (PciIoDevice->InitialVFs == 0) { | |
PciIoDevice->ReservedBusNum = 0; | |
} else { | |
PFRid = EFI_PCI_RID (Bus, Device, Func); | |
LastVF = PFRid + FirstVFOffset + (PciIoDevice->InitialVFs - 1) * VFStride; | |
// | |
// Calculate ReservedBusNum for this PF | |
// | |
PciIoDevice->ReservedBusNum = (UINT16)(EFI_PCI_BUS_OF_RID (LastVF) - Bus); | |
} | |
DEBUG (( | |
DEBUG_INFO, | |
" SR-IOV: SupportedPageSize = 0x%x; SystemPageSize = 0x%x; FirstVFOffset = 0x%x;\n", | |
SupportedPageSize, | |
PciIoDevice->SystemPageSize >> 12, | |
FirstVFOffset | |
)); | |
DEBUG (( | |
DEBUG_INFO, | |
" InitialVFs = 0x%x; ReservedBusNum = 0x%x; CapOffset = 0x%x\n", | |
PciIoDevice->InitialVFs, | |
PciIoDevice->ReservedBusNum, | |
PciIoDevice->SrIovCapabilityOffset | |
)); | |
} | |
} | |
if (PcdGetBool (PcdMrIovSupport)) { | |
Status = LocatePciExpressCapabilityRegBlock ( | |
PciIoDevice, | |
EFI_PCIE_CAPABILITY_ID_MRIOV, | |
&PciIoDevice->MrIovCapabilityOffset, | |
NULL | |
); | |
if (!EFI_ERROR (Status)) { | |
DEBUG ((DEBUG_INFO, " MR-IOV: CapOffset = 0x%x\n", PciIoDevice->MrIovCapabilityOffset)); | |
} | |
} | |
PciIoDevice->ResizableBarOffset = 0; | |
if (PcdGetBool (PcdPcieResizableBarSupport)) { | |
Status = LocatePciExpressCapabilityRegBlock ( | |
PciIoDevice, | |
PCI_EXPRESS_EXTENDED_CAPABILITY_RESIZABLE_BAR_ID, | |
&PciIoDevice->ResizableBarOffset, | |
NULL | |
); | |
if (!EFI_ERROR (Status)) { | |
PCI_EXPRESS_EXTENDED_CAPABILITIES_RESIZABLE_BAR_CONTROL ResizableBarControl; | |
UINT32 Offset; | |
Offset = PciIoDevice->ResizableBarOffset + sizeof (PCI_EXPRESS_EXTENDED_CAPABILITIES_HEADER) | |
+ sizeof (PCI_EXPRESS_EXTENDED_CAPABILITIES_RESIZABLE_BAR_CAPABILITY), | |
PciIo->Pci.Read ( | |
PciIo, | |
EfiPciIoWidthUint8, | |
Offset, | |
sizeof (PCI_EXPRESS_EXTENDED_CAPABILITIES_RESIZABLE_BAR_CONTROL), | |
&ResizableBarControl | |
); | |
PciIoDevice->ResizableBarNumber = ResizableBarControl.Bits.ResizableBarNumber; | |
PciProgramResizableBar (PciIoDevice, PciResizableBarMax); | |
} | |
} | |
// | |
// Initialize the reserved resource list | |
// | |
InitializeListHead (&PciIoDevice->ReservedResourceList); | |
// | |
// Initialize the driver list | |
// | |
InitializeListHead (&PciIoDevice->OptionRomDriverList); | |
// | |
// Initialize the child list | |
// | |
InitializeListHead (&PciIoDevice->ChildList); | |
return PciIoDevice; | |
} | |
/** | |
This routine is used to enumerate entire pci bus system | |
in a given platform. | |
It is only called on the second start on the same Root Bridge. | |
@param Controller Parent bridge handler. | |
@retval EFI_SUCCESS PCI enumeration finished successfully. | |
@retval other Some error occurred when enumerating the pci bus system. | |
**/ | |
EFI_STATUS | |
PciEnumeratorLight ( | |
IN EFI_HANDLE Controller | |
) | |
{ | |
EFI_STATUS Status; | |
EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo; | |
PCI_IO_DEVICE *RootBridgeDev; | |
UINT16 MinBus; | |
UINT16 MaxBus; | |
EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptors; | |
MinBus = 0; | |
MaxBus = PCI_MAX_BUS; | |
Descriptors = NULL; | |
// | |
// If this root bridge has been already enumerated, then return successfully | |
// | |
if (GetRootBridgeByHandle (Controller) != NULL) { | |
return EFI_SUCCESS; | |
} | |
// | |
// Open pci root bridge io protocol | |
// | |
Status = gBS->OpenProtocol ( | |
Controller, | |
&gEfiPciRootBridgeIoProtocolGuid, | |
(VOID **)&PciRootBridgeIo, | |
gPciBusDriverBinding.DriverBindingHandle, | |
Controller, | |
EFI_OPEN_PROTOCOL_BY_DRIVER | |
); | |
if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) { | |
return Status; | |
} | |
Status = PciRootBridgeIo->Configuration (PciRootBridgeIo, (VOID **)&Descriptors); | |
if (EFI_ERROR (Status)) { | |
return Status; | |
} | |
while (PciGetBusRange (&Descriptors, &MinBus, &MaxBus, NULL) == EFI_SUCCESS) { | |
// | |
// Create a device node for root bridge device with a NULL host bridge controller handle | |
// | |
RootBridgeDev = CreateRootBridge (Controller); | |
if (RootBridgeDev == NULL) { | |
Descriptors++; | |
continue; | |
} | |
// | |
// Record the root bridge-io protocol | |
// | |
RootBridgeDev->PciRootBridgeIo = PciRootBridgeIo; | |
Status = PciPciDeviceInfoCollector ( | |
RootBridgeDev, | |
(UINT8)MinBus | |
); | |
if (!EFI_ERROR (Status)) { | |
// | |
// Remove those PCI devices which are rejected when full enumeration | |
// | |
RemoveRejectedPciDevices (RootBridgeDev->Handle, RootBridgeDev); | |
// | |
// Process option rom light | |
// | |
ProcessOptionRomLight (RootBridgeDev); | |
// | |
// Determine attributes for all devices under this root bridge | |
// | |
DetermineDeviceAttribute (RootBridgeDev); | |
// | |
// If successfully, insert the node into device pool | |
// | |
InsertRootBridge (RootBridgeDev); | |
} else { | |
// | |
// If unsuccessfully, destroy the entire node | |
// | |
DestroyRootBridge (RootBridgeDev); | |
} | |
Descriptors++; | |
} | |
return EFI_SUCCESS; | |
} | |
/** | |
Get bus range from PCI resource descriptor list. | |
@param Descriptors A pointer to the address space descriptor. | |
@param MinBus The min bus returned. | |
@param MaxBus The max bus returned. | |
@param BusRange The bus range returned. | |
@retval EFI_SUCCESS Successfully got bus range. | |
@retval EFI_NOT_FOUND Can not find the specific bus. | |
**/ | |
EFI_STATUS | |
PciGetBusRange ( | |
IN EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR **Descriptors, | |
OUT UINT16 *MinBus, | |
OUT UINT16 *MaxBus, | |
OUT UINT16 *BusRange | |
) | |
{ | |
while ((*Descriptors)->Desc != ACPI_END_TAG_DESCRIPTOR) { | |
if ((*Descriptors)->ResType == ACPI_ADDRESS_SPACE_TYPE_BUS) { | |
if (MinBus != NULL) { | |
*MinBus = (UINT16)(*Descriptors)->AddrRangeMin; | |
} | |
if (MaxBus != NULL) { | |
*MaxBus = (UINT16)(*Descriptors)->AddrRangeMax; | |
} | |
if (BusRange != NULL) { | |
*BusRange = (UINT16)(*Descriptors)->AddrLen; | |
} | |
return EFI_SUCCESS; | |
} | |
(*Descriptors)++; | |
} | |
return EFI_NOT_FOUND; | |
} | |
/** | |
This routine can be used to start the root bridge. | |
@param RootBridgeDev Pci device instance. | |
@retval EFI_SUCCESS This device started. | |
@retval other Failed to get PCI Root Bridge I/O protocol. | |
**/ | |
EFI_STATUS | |
StartManagingRootBridge ( | |
IN PCI_IO_DEVICE *RootBridgeDev | |
) | |
{ | |
EFI_HANDLE RootBridgeHandle; | |
EFI_STATUS Status; | |
EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo; | |
// | |
// Get the root bridge handle | |
// | |
RootBridgeHandle = RootBridgeDev->Handle; | |
PciRootBridgeIo = NULL; | |
// | |
// Get the pci root bridge io protocol | |
// | |
Status = gBS->OpenProtocol ( | |
RootBridgeHandle, | |
&gEfiPciRootBridgeIoProtocolGuid, | |
(VOID **)&PciRootBridgeIo, | |
gPciBusDriverBinding.DriverBindingHandle, | |
RootBridgeHandle, | |
EFI_OPEN_PROTOCOL_BY_DRIVER | |
); | |
if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) { | |
return Status; | |
} | |
// | |
// Store the PciRootBridgeIo protocol into root bridge private data | |
// | |
RootBridgeDev->PciRootBridgeIo = PciRootBridgeIo; | |
return EFI_SUCCESS; | |
} | |
/** | |
This routine can be used to check whether a PCI device should be rejected when light enumeration. | |
@param PciIoDevice Pci device instance. | |
@retval TRUE This device should be rejected. | |
@retval FALSE This device shouldn't be rejected. | |
**/ | |
BOOLEAN | |
IsPciDeviceRejected ( | |
IN PCI_IO_DEVICE *PciIoDevice | |
) | |
{ | |
EFI_STATUS Status; | |
UINT32 TestValue; | |
UINT32 OldValue; | |
UINT32 Mask; | |
UINT8 BarOffset; | |
// | |
// PPB should be skip! | |
// | |
if (IS_PCI_BRIDGE (&PciIoDevice->Pci)) { | |
return FALSE; | |
} | |
if (IS_CARDBUS_BRIDGE (&PciIoDevice->Pci)) { | |
// | |
// Only test base registers for P2C | |
// | |
for (BarOffset = 0x1C; BarOffset <= 0x38; BarOffset += 2 * sizeof (UINT32)) { | |
Mask = (BarOffset < 0x2C) ? 0xFFFFF000 : 0xFFFFFFFC; | |
Status = BarExisted (PciIoDevice, BarOffset, &TestValue, &OldValue); | |
if (EFI_ERROR (Status)) { | |
continue; | |
} | |
TestValue = TestValue & Mask; | |
if ((TestValue != 0) && (TestValue == (OldValue & Mask))) { | |
// | |
// The bar isn't programed, so it should be rejected | |
// | |
return TRUE; | |
} | |
} | |
return FALSE; | |
} | |
for (BarOffset = 0x14; BarOffset <= 0x24; BarOffset += sizeof (UINT32)) { | |
// | |
// Test PCI devices | |
// | |
Status = BarExisted (PciIoDevice, BarOffset, &TestValue, &OldValue); | |
if (EFI_ERROR (Status)) { | |
continue; | |
} | |
if ((TestValue & 0x01) != 0) { | |
// | |
// IO Bar | |
// | |
Mask = 0xFFFFFFFC; | |
TestValue = TestValue & Mask; | |
if ((TestValue != 0) && (TestValue == (OldValue & Mask))) { | |
return TRUE; | |
} | |
} else { | |
// | |
// Mem Bar | |
// | |
Mask = 0xFFFFFFF0; | |
TestValue = TestValue & Mask; | |
if ((TestValue & 0x07) == 0x04) { | |
// | |
// Mem64 or PMem64 | |
// | |
BarOffset += sizeof (UINT32); | |
if ((TestValue != 0) && (TestValue == (OldValue & Mask))) { | |
// | |
// Test its high 32-Bit BAR | |
// | |
Status = BarExisted (PciIoDevice, BarOffset, &TestValue, &OldValue); | |
if (TestValue == OldValue) { | |
return TRUE; | |
} | |
} | |
} else { | |
// | |
// Mem32 or PMem32 | |
// | |
if ((TestValue != 0) && (TestValue == (OldValue & Mask))) { | |
return TRUE; | |
} | |
} | |
} | |
} | |
return FALSE; | |
} | |
/** | |
Reset all bus number from specific bridge. | |
@param Bridge Parent specific bridge. | |
@param StartBusNumber Start bus number. | |
**/ | |
VOID | |
ResetAllPpbBusNumber ( | |
IN PCI_IO_DEVICE *Bridge, | |
IN UINT8 StartBusNumber | |
) | |
{ | |
EFI_STATUS Status; | |
PCI_TYPE00 Pci; | |
UINT8 Device; | |
UINT32 Register; | |
UINT8 Func; | |
UINT64 Address; | |
UINT8 SecondaryBus; | |
EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo; | |
PciRootBridgeIo = Bridge->PciRootBridgeIo; | |
for (Device = 0; Device <= PCI_MAX_DEVICE; Device++) { | |
for (Func = 0; Func <= PCI_MAX_FUNC; Func++) { | |
// | |
// Check to see whether a pci device is present | |
// | |
Status = PciDevicePresent ( | |
PciRootBridgeIo, | |
&Pci, | |
StartBusNumber, | |
Device, | |
Func | |
); | |
if (EFI_ERROR (Status) && (Func == 0)) { | |
// | |
// go to next device if there is no Function 0 | |
// | |
break; | |
} | |
if (!EFI_ERROR (Status) && (IS_PCI_BRIDGE (&Pci))) { | |
Register = 0; | |
Address = EFI_PCI_ADDRESS (StartBusNumber, Device, Func, 0x18); | |
Status = PciRootBridgeIo->Pci.Read ( | |
PciRootBridgeIo, | |
EfiPciWidthUint32, | |
Address, | |
1, | |
&Register | |
); | |
SecondaryBus = (UINT8)(Register >> 8); | |
if (SecondaryBus != 0) { | |
ResetAllPpbBusNumber (Bridge, SecondaryBus); | |
} | |
// | |
// Reset register 18h, 19h, 1Ah on PCI Bridge | |
// | |
Register &= 0xFF000000; | |
Status = PciRootBridgeIo->Pci.Write ( | |
PciRootBridgeIo, | |
EfiPciWidthUint32, | |
Address, | |
1, | |
&Register | |
); | |
} | |
if ((Func == 0) && !IS_PCI_MULTI_FUNC (&Pci)) { | |
// | |
// Skip sub functions, this is not a multi function device | |
// | |
Func = PCI_MAX_FUNC; | |
} | |
} | |
} | |
} |