1188 lines
38 KiB
C
1188 lines
38 KiB
C
/** @file
|
|
Implementation of PciResourceInitPei module for Crisis Recovery
|
|
|
|
;******************************************************************************
|
|
;* Copyright (c) 2019 - 2020, Insyde Software Corporation. All Rights Reserved.
|
|
;*
|
|
;* You may not reproduce, distribute, publish, display, perform, modify, adapt,
|
|
;* transmit, broadcast, present, recite, release, license or otherwise exploit
|
|
;* any part of this publication in any form, by any means, without the prior
|
|
;* written permission of Insyde Software Corporation.
|
|
;*
|
|
;******************************************************************************
|
|
*/
|
|
#include "PciResourceInitPei.h"
|
|
#include "XhciInit.h"
|
|
#include "AhciInit.h"
|
|
#include "NvmeInit.h"
|
|
#include "SdInit.h"
|
|
#include "UfsInit.h"
|
|
|
|
CONTROLLER_INIT_ROUTINE mPciControllerInitRoutineTable[] = {
|
|
InitXhciController,
|
|
InitAhciController,
|
|
InitNvmeController,
|
|
InitSdController,
|
|
InitUfsController,
|
|
NULL
|
|
};
|
|
|
|
EFI_PEI_NOTIFY_DESCRIPTOR mBridgeNotifyList = {
|
|
(EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
|
|
&gEfiEndOfPeiSignalPpiGuid,
|
|
BridgeEndOfPeiPpiNotifyCallback
|
|
};
|
|
|
|
LIST_ENTRY mBridgeListHead;
|
|
CHAR8 *mPciBarAttribName[] = {
|
|
ATTR_NAME_PCIE_PEI_BAR0,
|
|
ATTR_NAME_PCIE_PEI_BAR1,
|
|
ATTR_NAME_PCIE_PEI_BAR2,
|
|
ATTR_NAME_PCIE_PEI_BAR3,
|
|
ATTR_NAME_PCIE_PEI_BAR4,
|
|
ATTR_NAME_PCIE_PEI_BAR5
|
|
};
|
|
|
|
/**
|
|
Stop the bridge.
|
|
|
|
@param [in] Bus PCI Bus number.
|
|
@param [in] Device PCI Device number.
|
|
@param [in] Function PCI Function number.
|
|
|
|
@retval EFI_SUCCESS Operation completed successfully
|
|
@retval Others Operation failed
|
|
|
|
**/
|
|
VOID
|
|
StopP2pBridge (
|
|
IN UINT32 Bus,
|
|
IN UINT32 Device,
|
|
IN UINT32 Function
|
|
)
|
|
{
|
|
//
|
|
// Disable bus master
|
|
//
|
|
PciAnd16 (
|
|
PCI_LIB_ADDRESS (Bus, Device, Function, PCI_COMMAND_OFFSET),
|
|
(UINT16)~(EFI_PCI_COMMAND_BUS_MASTER | EFI_PCI_COMMAND_MEMORY_SPACE)
|
|
);
|
|
|
|
//
|
|
// Clear memory base
|
|
//
|
|
PciWrite32 (PCI_LIB_ADDRESS (Bus, Device, Function, PCI_BRIDGE_BASE_ADDRESS_REGISTER_OFFSET), 0);
|
|
PciWrite32 (PCI_LIB_ADDRESS (Bus, Device, Function, PCI_BRIDGE_BASE_ADDRESS_REGISTER_OFFSET + 4), 0);
|
|
|
|
//
|
|
// Clear bus number
|
|
//
|
|
PciWrite32 (PCI_LIB_ADDRESS (Bus, Device, Function, PCI_BRIDGE_PRIMARY_BUS_REGISTER_OFFSET), 0);
|
|
|
|
}
|
|
|
|
/**
|
|
Enable the bridge.
|
|
|
|
@param [in] Bus PCI Bus number.
|
|
@param [in] Device PCI Device number.
|
|
@param [in] Function PCI Function number.
|
|
@param [in] SecondaryBus Secondary Bus number.
|
|
@param [in] SubordinateBus Subordinate Bus number.
|
|
@param [in] MemBase Memory base address.
|
|
@param [in] MemLimit Memory base limit.
|
|
|
|
@retval EFI_SUCCESS Operation completed successfully
|
|
@retval Others Operation failed
|
|
|
|
**/
|
|
EFI_STATUS
|
|
InitP2pBridge (
|
|
IN UINT32 Bus,
|
|
IN UINT32 Device,
|
|
IN UINT32 Function,
|
|
IN UINT32 SecondaryBus,
|
|
IN UINT32 SubordinateBus,
|
|
IN UINT32 MemBase,
|
|
IN UINT32 MemLimit
|
|
)
|
|
{
|
|
UINT32 Register;
|
|
|
|
if (PciRead16 (PCI_LIB_ADDRESS (Bus, Device, 0, PCI_VENDOR_ID_OFFSET)) == 0xFFFF) {
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
//
|
|
// Assign bus numbers
|
|
//
|
|
PciWrite8 (PCI_LIB_ADDRESS (Bus, Device, Function, PCI_BRIDGE_PRIMARY_BUS_REGISTER_OFFSET), (UINT8)Bus);
|
|
PciWrite8 (PCI_LIB_ADDRESS (Bus, Device, Function, PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET), (UINT8)SecondaryBus);
|
|
PciWrite8 (PCI_LIB_ADDRESS (Bus, Device, Function, PCI_BRIDGE_SUBORDINATE_BUS_REGISTER_OFFSET), (UINT8)SubordinateBus);
|
|
|
|
//
|
|
// Assign base address
|
|
//
|
|
Register = ((MemBase & 0xFFF00000) >> 16) + ((MemBase + MemLimit - 1) & 0xFFF00000);
|
|
PciWrite32 (PCI_LIB_ADDRESS (Bus, Device, Function, PCI_BRIDGE_BASE_ADDRESS_REGISTER_OFFSET), Register);
|
|
|
|
//
|
|
// Set prefetchable BASE to be larger than LIMIT register since we are not use prefetchable memory in recovery
|
|
//
|
|
Register = 0xFFFF;
|
|
PciWrite16 (PCI_LIB_ADDRESS (Bus, Device, Function, PCI_BRIDGE_PREFETCHABLE_BASE_ADDRESS_REGISTER_OFFSET), (UINT16)Register);
|
|
Register = 0x0;
|
|
PciWrite16 (PCI_LIB_ADDRESS (Bus, Device, Function, PCI_BRIDGE_PREFETCHABLE_BASE_LIMIT_REGISTER_OFFSET), (UINT16)Register);
|
|
|
|
Register = 0xFFFFFFFF;
|
|
PciWrite32 (PCI_LIB_ADDRESS (Bus, Device, Function, PCI_BRIDGE_PREFETCHABLE_UPPER32BIT_BASE_ADDRESS_REGISTER_OFFSET), Register);
|
|
Register = 0x0;
|
|
PciWrite32 (PCI_LIB_ADDRESS (Bus, Device, Function, PCI_BRIDGE_PREFETCHABLE_UPPER32BIT_BASE_LIMIT_REGISTER_OFFSET), Register);
|
|
|
|
|
|
//
|
|
// Enable bus master
|
|
//
|
|
PciOr16 (PCI_LIB_ADDRESS (Bus, Device, Function, PCI_COMMAND_OFFSET), (EFI_PCI_COMMAND_BUS_MASTER | EFI_PCI_COMMAND_MEMORY_SPACE));
|
|
|
|
//
|
|
// A config write is required in order for the device to re-capture the Bus number,
|
|
// according to PCI Express Base Specification, 2.2.6.2
|
|
// Write to a read-only register VendorID to not cause any side effects.
|
|
//
|
|
PciWrite16 (PCI_LIB_ADDRESS (Bus, Device, Function, PCI_VENDOR_ID_OFFSET), 0);
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Find the first child node.
|
|
|
|
@param [in] ListHead List head.
|
|
@param [in] ParentLink Parent's link.
|
|
|
|
@retval Child info.
|
|
|
|
**/
|
|
PCI_INFO_NODE *
|
|
GetChildInfo (
|
|
IN LIST_ENTRY *ListHead,
|
|
IN LIST_ENTRY *ParentLink
|
|
)
|
|
{
|
|
LIST_ENTRY *Link;
|
|
PCI_INFO_NODE *PciInfo;
|
|
PCI_INFO_NODE *ParentInfo;
|
|
|
|
ParentInfo = PCI_INFO_NODE_FROM_LINK (ParentLink);
|
|
for (Link = GetFirstNode (ListHead); !IsNull (ListHead, Link); Link = GetNextNode (ListHead, Link)) {
|
|
PciInfo = PCI_INFO_NODE_FROM_LINK (Link);
|
|
if (PciInfo->Parent == ParentInfo) {
|
|
return PciInfo;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
/**
|
|
Find the child nodes.
|
|
|
|
@param [in] ListHead List head.
|
|
@param [in] ParentLink Parent's link.
|
|
@param [out] Child Child node pointer list.
|
|
@param [out] ChildNum Child node number.
|
|
|
|
@retval EFI_SUCCESS Child nodes found.
|
|
@retval EFI_INVALID_PARAMETER Invalid input.
|
|
@retval EFI_OUT_OF_RESOURCES Can't allocate enough memory.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
GetChildInfoBuffer (
|
|
IN LIST_ENTRY *ListHead,
|
|
IN LIST_ENTRY *ParentLink,
|
|
OUT PCI_INFO_NODE_PTR **Child,
|
|
OUT UINT32 *ChildNum
|
|
)
|
|
{
|
|
LIST_ENTRY *Link;
|
|
PCI_INFO_NODE *PciInfo;
|
|
UINT32 Count;
|
|
PCI_INFO_NODE *ParentInfo;
|
|
|
|
if (ChildNum == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
if (Child == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
ParentInfo = PCI_INFO_NODE_FROM_LINK (ParentLink);
|
|
Count = 0;
|
|
for (Link = GetFirstNode (ListHead); !IsNull (ListHead, Link); Link = GetNextNode (ListHead, Link)) {
|
|
PciInfo = PCI_INFO_NODE_FROM_LINK (Link);
|
|
if (PciInfo->Parent == ParentInfo) {
|
|
Count++;
|
|
}
|
|
}
|
|
|
|
if (Count == 0) {
|
|
*Child = NULL;
|
|
*ChildNum = 0;
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
*Child = AllocateZeroPool (sizeof (PCI_INFO_NODE *) * Count);
|
|
if (*Child == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
*ChildNum = 0;
|
|
for (Link = GetFirstNode (ListHead); !IsNull (ListHead, Link); Link = GetNextNode (ListHead, Link)) {
|
|
PciInfo = PCI_INFO_NODE_FROM_LINK (Link);
|
|
if (PciInfo->Parent == ParentInfo) {
|
|
(*Child)[(*ChildNum)++] = PciInfo;
|
|
if (*ChildNum == Count) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Check if it is supported device type.
|
|
|
|
@param [in] Bus PCI Bus number.
|
|
@param [in] Device PCI Device number.
|
|
@param [in] Function PCI Function number.
|
|
|
|
@retval Whether the device type is supported
|
|
|
|
**/
|
|
BOOLEAN
|
|
IsSupportedDevice (
|
|
IN UINT8 Bus,
|
|
IN UINT8 Device,
|
|
IN UINT8 Function
|
|
)
|
|
{
|
|
UINT8 ProgIf;
|
|
UINT8 BaseClass;
|
|
UINT8 SubClass;
|
|
|
|
ProgIf = PciRead8 (PCI_LIB_ADDRESS (Bus, Device, Function, PCI_CLASSCODE_OFFSET));
|
|
SubClass = PciRead8 (PCI_LIB_ADDRESS (Bus, Device, Function, PCI_CLASSCODE_OFFSET + 1));
|
|
BaseClass = PciRead8 (PCI_LIB_ADDRESS (Bus, Device, Function, PCI_CLASSCODE_OFFSET + 2));
|
|
|
|
// XHCI
|
|
if ((ProgIf == PCI_IF_XHCI) && (SubClass == PCI_CLASS_SERIAL_USB) && (BaseClass == PCI_CLASS_SERIAL)) {
|
|
if (!CheckUsbPolicy ()) {
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
// AHCI
|
|
if ((SubClass == PCI_CLASS_MASS_STORAGE_SATADPA) && (BaseClass == PCI_CLASS_MASS_STORAGE)) {
|
|
return TRUE;
|
|
}
|
|
// NVME
|
|
if ((SubClass == PCI_CLASS_MASS_STORAGE_SOLID_STATE) && (BaseClass == PCI_CLASS_MASS_STORAGE)) {
|
|
return TRUE;
|
|
}
|
|
// SD
|
|
if ((SubClass == PCI_SUBCLASS_SD_HOST_CONTROLLER) && (BaseClass == PCI_CLASS_SYSTEM_PERIPHERAL)) {
|
|
return TRUE;
|
|
}
|
|
// UFS
|
|
if ((SubClass == 0x09) && (BaseClass == PCI_CLASS_MEMORY_CONTROLLER)) {
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
/**
|
|
Update related PCI infos.
|
|
|
|
@param [in] ListHead The List head.
|
|
@param [in,out] NewPciInfo The new PCI info node.
|
|
|
|
@retval The subordinate bus number
|
|
|
|
**/
|
|
UINT8
|
|
UpdatePciTopology (
|
|
IN LIST_ENTRY *ListHead,
|
|
IN OUT PCI_INFO_NODE *NewPciInfo
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
LIST_ENTRY *Link;
|
|
LIST_ENTRY *NextLink;
|
|
PCI_INFO_NODE *PciInfo;
|
|
UINT32 MemBase;
|
|
UINT32 MemLimit;
|
|
UINT8 SecondaryBus;
|
|
UINT8 SubordinateBus;
|
|
PCI_INFO_NODE *ChildInfo;
|
|
UINT32 ChildNum;
|
|
UINT32 Index;
|
|
PCI_INFO_NODE *NewChildInfo;
|
|
PCI_INFO_NODE *ParentInfo;
|
|
BOOLEAN UpdateUpstream;
|
|
UINT8 MaxSubordinateBus;
|
|
PCI_INFO_NODE_PTR *ChildInfoBuffer;
|
|
|
|
UpdateUpstream = FALSE;
|
|
MemBase = NewPciInfo->MemBase;
|
|
MemLimit = NewPciInfo->MemLimit;
|
|
SecondaryBus = NewPciInfo->SecondaryBus;
|
|
SubordinateBus = NewPciInfo->SubordinateBus;
|
|
for (Link = GetFirstNode (ListHead); !IsNull (ListHead, Link); Link = NextLink) {
|
|
NextLink = GetNextNode (ListHead, Link);
|
|
PciInfo = PCI_INFO_NODE_FROM_LINK (Link);
|
|
if ((PciInfo->PciRes.Bus == NewPciInfo->PciRes.Bus) &&
|
|
(PciInfo->PciRes.Device == NewPciInfo->PciRes.Device) &&
|
|
(PciInfo->PciRes.Function == NewPciInfo->PciRes.Function)) {
|
|
//
|
|
// Identical device found.
|
|
//
|
|
Status = GetChildInfoBuffer (ListHead, Link, &ChildInfoBuffer, &ChildNum);
|
|
if (!EFI_ERROR (Status)) {
|
|
MemBase = MIN (NewPciInfo->MemBase, PciInfo->MemBase);
|
|
MemLimit = MAX (NewPciInfo->MemBase + NewPciInfo->MemLimit, PciInfo->MemBase + PciInfo->MemLimit) - MemBase;
|
|
SecondaryBus = MAX (SecondaryBus, PciInfo->SecondaryBus);
|
|
//
|
|
// Update downstream nodes.
|
|
//
|
|
MaxSubordinateBus = NewPciInfo->SubordinateBus;
|
|
for (Index = 0; Index < ChildNum; Index++) {
|
|
ChildInfo = (PCI_INFO_NODE *)ChildInfoBuffer[Index];
|
|
//
|
|
// Create updated node to replace the existing one.
|
|
//
|
|
NewChildInfo = (PCI_INFO_NODE *)AllocateCopyPool (sizeof (PCI_INFO_NODE), ChildInfo);
|
|
ASSERT (NewChildInfo != NULL);
|
|
if (NewChildInfo == NULL) {
|
|
continue;
|
|
}
|
|
NewChildInfo->PciRes.Bus = SecondaryBus;
|
|
NewChildInfo->Parent = NewPciInfo;
|
|
if (NewChildInfo->IsP2pBridge) {
|
|
//
|
|
// Arrange bus number if needed.
|
|
//
|
|
ASSERT (ChildInfo->SecondaryBus > ChildInfo->PciRes.Bus);
|
|
NewChildInfo->SecondaryBus = SecondaryBus + ChildInfo->SecondaryBus - ChildInfo->PciRes.Bus;
|
|
if (NewChildInfo->SecondaryBus == NewPciInfo->SubordinateBus) {
|
|
//
|
|
// Bus number is duplicated, adding one as new bus number.
|
|
//
|
|
NewChildInfo->SecondaryBus = MaxSubordinateBus + 1;
|
|
UpdateUpstream = TRUE;
|
|
}
|
|
}
|
|
//
|
|
// Assign new bus number.
|
|
//
|
|
ChildInfo->PciRes.Bus = NewChildInfo->PciRes.Bus;
|
|
//
|
|
// Update downstream recursively.
|
|
//
|
|
MaxSubordinateBus = UpdatePciTopology (ListHead, NewChildInfo);
|
|
SubordinateBus = MAX (SubordinateBus, MaxSubordinateBus);
|
|
}
|
|
}
|
|
RemoveEntryList (Link);
|
|
}
|
|
}
|
|
|
|
NewPciInfo->MemBase = MemBase;
|
|
NewPciInfo->MemLimit = MemLimit;
|
|
NewPciInfo->SecondaryBus = SecondaryBus;
|
|
NewPciInfo->SubordinateBus = SubordinateBus;
|
|
InsertTailList (ListHead, &NewPciInfo->Link);
|
|
|
|
if (UpdateUpstream) {
|
|
//
|
|
// Update upstream subordinate bus if child's subordinate bus is changed because of duplicated bus number.
|
|
//
|
|
ParentInfo = NewPciInfo->Parent;
|
|
while (ParentInfo != NULL) {
|
|
ParentInfo->SubordinateBus = SubordinateBus;
|
|
ParentInfo = ParentInfo->Parent;
|
|
}
|
|
}
|
|
|
|
return (NewPciInfo->IsP2pBridge) ? SubordinateBus : NewPciInfo->PciRes.Bus;
|
|
}
|
|
|
|
/**
|
|
Find the MMIO size of the device requires
|
|
|
|
@param [in] Bus PCI Bus number.
|
|
@param [in] Device PCI Device number.
|
|
@param [in] Function PCI Function number.
|
|
@param [out] MmioSize MMIO Size in bytes.
|
|
|
|
**/
|
|
VOID
|
|
FindDeviceMmioSize (
|
|
IN UINT8 Bus,
|
|
IN UINT8 Device,
|
|
IN UINT8 Function,
|
|
OUT UINT64 *MmioSize
|
|
)
|
|
{
|
|
UINT32 BarIndex;
|
|
UINT32 Size;
|
|
UINT64 CurrentSize;
|
|
UINT32 BarData;
|
|
|
|
*MmioSize = 0;
|
|
for (BarIndex = 0; BarIndex < PCI_MAX_BAR; BarIndex++) {
|
|
//
|
|
// Get MMIO region size.
|
|
//
|
|
BarData = PciRead32 (PCI_LIB_ADDRESS (Bus, Device, Function, PCI_BASE_ADDRESSREG_OFFSET + 4 * BarIndex)); // Backup Bar Data
|
|
PciWrite32 (PCI_LIB_ADDRESS (Bus, Device, Function, PCI_BASE_ADDRESSREG_OFFSET + 4 * BarIndex), 0xFFFFFFFF);
|
|
Size = PciRead32 (PCI_LIB_ADDRESS (Bus, Device, Function, PCI_BASE_ADDRESSREG_OFFSET + 4 * BarIndex));
|
|
PciWrite32 (PCI_LIB_ADDRESS (Bus, Device, Function, PCI_BASE_ADDRESSREG_OFFSET + 4 * BarIndex), BarData); // Restore Bar Data
|
|
switch (Size & 0x07) {
|
|
|
|
case 0x0:
|
|
//
|
|
// Memory space: anywhere in 32 bit address space
|
|
//
|
|
*MmioSize += (~(Size & 0xFFFFFFF0)) + 1;
|
|
break;
|
|
|
|
case 0x4:
|
|
//
|
|
// Memory space: anywhere in 64 bit address space
|
|
//
|
|
CurrentSize = Size & 0xFFFFFFF0;
|
|
BarData = PciRead32 (PCI_LIB_ADDRESS(Bus, Device, Function, PCI_BASE_ADDRESSREG_OFFSET + 4 * BarIndex + 4)); // Backup Bar Data
|
|
PciWrite32 (PCI_LIB_ADDRESS(Bus, Device, Function, PCI_BASE_ADDRESSREG_OFFSET + 4 * BarIndex + 4), 0xFFFFFFFF);
|
|
Size = PciRead32 (PCI_LIB_ADDRESS(Bus, Device, Function, PCI_BASE_ADDRESSREG_OFFSET + 4 * BarIndex + 4));
|
|
PciWrite32 (PCI_LIB_ADDRESS(Bus, Device, Function, PCI_BASE_ADDRESSREG_OFFSET + 4 * BarIndex + 4), BarData); // Restore Bar Data
|
|
//
|
|
// Fix the length to support some spefic 64 bit BAR
|
|
//
|
|
Size |= ((UINT32)(-1) << HighBitSet32 (Size));
|
|
//
|
|
// Calculate the size of 64bit bar
|
|
//
|
|
CurrentSize |= LShiftU64 ((UINT64) Size, 32);
|
|
CurrentSize = (~(CurrentSize)) + 1;
|
|
*MmioSize += CurrentSize;
|
|
//
|
|
// Skip next BAR
|
|
//
|
|
BarIndex++;
|
|
break;
|
|
|
|
default:
|
|
//
|
|
// Unknown BAR type
|
|
//
|
|
break;
|
|
};
|
|
}
|
|
}
|
|
|
|
/**
|
|
Reset all bus number from specific bridge.
|
|
|
|
@param[in] StartBusNumber Start bus number.
|
|
|
|
**/
|
|
VOID
|
|
ResetAllBridgeBusNumber (
|
|
IN UINT8 StartBusNumber
|
|
)
|
|
{
|
|
UINT8 Device;
|
|
UINT8 Function;
|
|
UINTN PciAddress;
|
|
UINT8 BaseClass;
|
|
UINT8 SubClass;
|
|
UINT8 SecondaryBus;
|
|
UINT8 HeaderType;
|
|
|
|
for (Device = 0; Device <= PCI_MAX_DEVICE; Device++) {
|
|
for (Function = 0; Function <= PCI_MAX_FUNC; Function++) {
|
|
PciAddress = PCI_LIB_ADDRESS (StartBusNumber, Device, Function, 0);
|
|
if (PciRead16 (PciAddress + PCI_VENDOR_ID_OFFSET) == 0xFFFF) {
|
|
if (Function == 0) {
|
|
//
|
|
// Skip sub functions
|
|
//
|
|
Function = PCI_MAX_FUNC;
|
|
}
|
|
continue;
|
|
}
|
|
|
|
SubClass = PciRead8 (PciAddress + PCI_CLASSCODE_OFFSET + 1);
|
|
BaseClass = PciRead8 (PciAddress + PCI_CLASSCODE_OFFSET + 2);
|
|
if ((BaseClass == PCI_CLASS_BRIDGE) && (SubClass == PCI_CLASS_BRIDGE_P2P)) {
|
|
SecondaryBus = PciRead8 (PciAddress + PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET);
|
|
if (SecondaryBus != 0) {
|
|
ResetAllBridgeBusNumber (SecondaryBus);
|
|
}
|
|
//
|
|
// Reset register 18h, 19h, 1Ah on PCI Bridge
|
|
//
|
|
PciWrite8 (PciAddress + PCI_BRIDGE_PRIMARY_BUS_REGISTER_OFFSET, 0);
|
|
PciWrite8 (PciAddress + PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET, 0);
|
|
PciWrite8 (PciAddress + PCI_BRIDGE_SUBORDINATE_BUS_REGISTER_OFFSET, 0);
|
|
}
|
|
|
|
HeaderType = PciRead8 (PciAddress + PCI_HEADER_TYPE_OFFSET);
|
|
if ((Function == 0) && ((HeaderType & HEADER_TYPE_MULTI_FUNCTION) == 0)) {
|
|
//
|
|
// Skip sub functions, this is not a multi function device
|
|
//
|
|
Function = PCI_MAX_FUNC;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
Calculate total MMIO size of a PCI device needs.
|
|
Enable the bridge if needed.
|
|
|
|
@param [in] ListHead List head.
|
|
|
|
@retval Total MMIO size.
|
|
|
|
**/
|
|
UINT64
|
|
FindMmioSizeFromPciInfoList (
|
|
IN LIST_ENTRY *ListHead
|
|
)
|
|
{
|
|
LIST_ENTRY *Link;
|
|
PCI_INFO_NODE *PciInfo;
|
|
PCI_INFO_NODE *ChildPciInfo;
|
|
UINT64 MmioSize;
|
|
UINTN PciAddress;
|
|
UINT8 Bus;
|
|
UINT8 Device;
|
|
UINT8 Function;
|
|
|
|
MmioSize = 0;
|
|
for (Link = GetFirstNode (ListHead); !IsNull (ListHead, Link); Link = GetNextNode (ListHead, Link)) {
|
|
PciInfo = PCI_INFO_NODE_FROM_LINK (Link);
|
|
Bus = PciInfo->PciRes.Bus;
|
|
Device = PciInfo->PciRes.Device;
|
|
Function = PciInfo->PciRes.Function;
|
|
PciAddress = PCI_LIB_ADDRESS (Bus, Device, Function , 0);
|
|
|
|
ChildPciInfo = GetChildInfo (ListHead, Link);
|
|
if (ChildPciInfo != NULL) {
|
|
PciWrite8 (PciAddress + PCI_BRIDGE_PRIMARY_BUS_REGISTER_OFFSET, (UINT8)Bus);
|
|
PciWrite8 (PciAddress + PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET, (UINT8)ChildPciInfo->PciRes.Bus);
|
|
//
|
|
// Assign temporary subordinate bus number so that device behind this bridge can be seen
|
|
//
|
|
PciWrite8 (PciAddress + PCI_BRIDGE_SUBORDINATE_BUS_REGISTER_OFFSET, 0xFF);
|
|
//
|
|
// A config write is required in order for the device to re-capture the Bus number,
|
|
// according to PCI Express Base Specification, 2.2.6.2
|
|
// Write to a read-only register VendorID to not cause any side effects.
|
|
//
|
|
PciWrite16 (PciAddress + PCI_VENDOR_ID_OFFSET, 0);
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// We've encountered hanging issue if accessing the specific controller during normal boot.
|
|
// So check the supporting policy before mmio it.
|
|
//
|
|
if (IsSupportedDevice (Bus, Device, Function)) {
|
|
FindDeviceMmioSize (Bus, Device, Function, &MmioSize);
|
|
}
|
|
break;
|
|
}
|
|
|
|
ResetAllBridgeBusNumber (0);
|
|
|
|
return MmioSize;
|
|
}
|
|
|
|
/**
|
|
Get PCI device info.
|
|
|
|
@param [in] ListHead List head.
|
|
@param [in] Bus PCI Bus number.
|
|
@param [in] Device PCI Device number.
|
|
@param [in] Function PCI Function number.
|
|
|
|
@retval Device info pointer.
|
|
|
|
**/
|
|
PCI_INFO_NODE *
|
|
GetPciInfoFromList (
|
|
IN LIST_ENTRY *ListHead,
|
|
IN UINT8 Bus,
|
|
IN UINT8 Device,
|
|
IN UINT8 Function
|
|
)
|
|
{
|
|
LIST_ENTRY *Link;
|
|
PCI_INFO_NODE *PciInfo;
|
|
|
|
for (Link = GetFirstNode (ListHead); !IsNull (ListHead, Link); Link = GetNextNode (ListHead, Link)) {
|
|
PciInfo = PCI_INFO_NODE_FROM_LINK (Link);
|
|
if ((Bus == PciInfo->PciRes.Bus) &&
|
|
(Device == PciInfo->PciRes.Device) &&
|
|
(Function == PciInfo->PciRes.Function)) {
|
|
return PciInfo;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/**
|
|
Returns the 16-bit Length field of a device path node.
|
|
|
|
Returns the 16-bit Length field of the device path node specified by Node.
|
|
Node is not required to be aligned on a 16-bit boundary, so it is recommended
|
|
that a function such as ReadUnaligned16() be used to extract the contents of
|
|
the Length field.
|
|
|
|
If Node is NULL, then ASSERT().
|
|
|
|
@param Node A pointer to a device path node data structure.
|
|
|
|
@return The 16-bit Length field of the device path node specified by Node.
|
|
|
|
**/
|
|
STATIC
|
|
UINTN
|
|
DevicePathNodeLength (
|
|
IN CONST VOID *Node
|
|
)
|
|
{
|
|
ASSERT (Node != NULL);
|
|
return ReadUnaligned16 ((UINT16 *)&((EFI_DEVICE_PATH_PROTOCOL *)(Node))->Length[0]);
|
|
}
|
|
|
|
/**
|
|
Returns a pointer to the next node in a device path.
|
|
|
|
Returns a pointer to the device path node that follows the device path node
|
|
specified by Node.
|
|
|
|
If Node is NULL, then ASSERT().
|
|
|
|
@param Node A pointer to a device path node data structure.
|
|
|
|
@return a pointer to the device path node that follows the device path node
|
|
specified by Node.
|
|
|
|
**/
|
|
STATIC
|
|
EFI_DEVICE_PATH_PROTOCOL *
|
|
NextDevicePathNode (
|
|
IN CONST VOID *Node
|
|
)
|
|
{
|
|
ASSERT (Node != NULL);
|
|
return (EFI_DEVICE_PATH_PROTOCOL *)((UINT8 *)(Node) + DevicePathNodeLength (Node));
|
|
}
|
|
|
|
/**
|
|
Determines if a device path node is an end node of an entire device path.
|
|
|
|
Determines if a device path node specified by Node is an end node of an entire
|
|
device path.
|
|
If Node represents the end of an entire device path, then TRUE is returned.
|
|
Otherwise, FALSE is returned.
|
|
|
|
If Node is NULL, then ASSERT().
|
|
|
|
@param Node A pointer to a device path node data structure.
|
|
|
|
@retval TRUE The device path node specified by Node is the end of an entire device path.
|
|
@retval FALSE The device path node specified by Node is not the end of an entire device path.
|
|
|
|
**/
|
|
STATIC
|
|
BOOLEAN
|
|
IsDevicePathEnd (
|
|
IN EFI_DEVICE_PATH_PROTOCOL *Node
|
|
)
|
|
{
|
|
ASSERT (Node != NULL);
|
|
return (BOOLEAN)((Node->Type == END_DEVICE_PATH_TYPE) && (Node->SubType == END_ENTIRE_DEVICE_PATH_SUBTYPE));
|
|
}
|
|
|
|
/**
|
|
Get PCI root bus number.
|
|
|
|
@param DevicePath A pointer to a device path data structure.
|
|
|
|
@retval TRUE The device path node specified by Node is the end of an entire device path.
|
|
@retval FALSE The device path node specified by Node is not the end of an entire device path.
|
|
|
|
**/
|
|
STATIC
|
|
UINT8
|
|
GetPciRootBus (
|
|
IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
|
|
)
|
|
{
|
|
//
|
|
// Return 0 for now.
|
|
//
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
Enumerate PCI devices from token space gH2ODeviceInfo2TokenSpaceGuid.
|
|
|
|
@param [in,out] ListHead List head.
|
|
|
|
@retval The bottommost bus number.
|
|
|
|
**/
|
|
UINT8
|
|
EnumerateFromPcd (
|
|
IN OUT LIST_ENTRY *ListHead
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINTN TokenNum;
|
|
LIST_ENTRY TempPciInfoHead;
|
|
PCI_INFO_NODE *PciInfo;
|
|
PCI_INFO_NODE *ChildPciInfo;
|
|
PCI_INFO_NODE *TempPciInfo;
|
|
PCI_DEVICE_PATH *PciDevicePath;
|
|
LIST_ENTRY *Link;
|
|
UINT8 SecondaryBus;
|
|
UINT8 PrimaryBus;
|
|
UINT64 MmioSize;
|
|
UINT8 SubordinateBus;
|
|
PCI_INFO_NODE *ParentInfo;
|
|
UINT32 DeviceAttribCount;
|
|
EFI_DEVICE_PATH_PROTOCOL *DevicePath;
|
|
EFI_DEVICE_PATH_PROTOCOL *DevicePathNode;
|
|
UINT32 Index;
|
|
UINT32 BarIndex;
|
|
CHAR8 *DeviceAttribValue;
|
|
UINT32 PciBar[6];
|
|
UINT32 NodeUid;
|
|
UINT32 MemBase;
|
|
UINT32 MemLimit;
|
|
UINT8 NewSubordinateBus;
|
|
UINT8 TempSubordinateBus;
|
|
UINT8 OrgSecondaryBus;
|
|
|
|
PrimaryBus = 0;
|
|
SecondaryBus = FIRST_DOWNSTREAM_NUM; // Downstream bus starts from 8
|
|
SubordinateBus = 0;
|
|
for (TokenNum = LibPcdGetNextToken (&gH2ODeviceInfo2TokenSpaceGuid, 0)
|
|
; TokenNum != 0
|
|
; TokenNum = LibPcdGetNextToken (&gH2ODeviceInfo2TokenSpaceGuid, TokenNum)
|
|
) {
|
|
|
|
Status = H2OGetDeviceInfo (TokenNum, &DevicePath, &DeviceAttribCount);
|
|
if (EFI_ERROR (Status)) {
|
|
continue;
|
|
}
|
|
|
|
if (DevicePath == NULL) {
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// pcie_pei_enable
|
|
//
|
|
Status = H2OGetDeviceInfoAttribByName (TokenNum, ATTR_NAME_PCIE_PEI_ENABLE, &DeviceAttribValue);
|
|
if (EFI_ERROR (Status)) {
|
|
continue;
|
|
}
|
|
|
|
if (AsciiStrCmp (DeviceAttribValue, ATTR_VALUE_CRISISRECOVERY) == 0) {
|
|
if (GetBootModeHob () != BOOT_IN_RECOVERY_MODE) {
|
|
continue;
|
|
}
|
|
} else if (AsciiStrCmp (DeviceAttribValue, ATTR_VALUE_YES) != 0) {
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// pcie_pei_barx
|
|
//
|
|
ZeroMem (&PciBar, sizeof (PciBar));
|
|
for (BarIndex = 0; BarIndex < ARRAY_SIZE (mPciBarAttribName); BarIndex++) {
|
|
Status = H2OGetDeviceInfoAttribByName (TokenNum, mPciBarAttribName[BarIndex], &DeviceAttribValue);
|
|
if (EFI_ERROR (Status)) {
|
|
continue;
|
|
}
|
|
PciBar[BarIndex] = (UINT32)AsciiStrHexToUint64 (DeviceAttribValue);
|
|
}
|
|
|
|
//
|
|
// Device is enabled.
|
|
// Enumerate PCI devices from device path
|
|
//
|
|
InitializeListHead (&TempPciInfoHead);
|
|
for (DevicePathNode = DevicePath, ParentInfo = NULL, OrgSecondaryBus = SecondaryBus
|
|
; !IsDevicePathEnd (DevicePathNode)
|
|
; DevicePathNode = NextDevicePathNode (DevicePathNode)
|
|
) {
|
|
|
|
if (IS_ACPI_DP (DevicePathNode)) {
|
|
NodeUid = ((ACPI_HID_DEVICE_PATH *)DevicePathNode)->UID;
|
|
PrimaryBus = GetPciRootBus (DevicePath);
|
|
ParentInfo = NULL;
|
|
continue;
|
|
}
|
|
|
|
if (IS_PCI_DP (DevicePathNode)) {
|
|
PciDevicePath = (PCI_DEVICE_PATH *)DevicePathNode;
|
|
|
|
TempPciInfo = (PCI_INFO_NODE *)AllocateZeroPool (sizeof (PCI_INFO_NODE));
|
|
ASSERT (TempPciInfo != NULL);
|
|
if (TempPciInfo == NULL) {
|
|
return 0;
|
|
}
|
|
|
|
TempPciInfo->Signature = PCI_INFO_NODE_SIGNATURE;
|
|
TempPciInfo->Parent = ParentInfo;
|
|
TempPciInfo->PciRes.Bus = PrimaryBus;
|
|
TempPciInfo->PciRes.Device = PciDevicePath->Device;
|
|
TempPciInfo->PciRes.Function = PciDevicePath->Function;
|
|
CopyMem (&TempPciInfo->PciRes.PciBar, &PciBar, sizeof (TempPciInfo->PciRes.PciBar));
|
|
InsertTailList (&TempPciInfoHead, &TempPciInfo->Link);
|
|
|
|
ParentInfo = TempPciInfo;
|
|
SubordinateBus = PrimaryBus;
|
|
if (!IsDevicePathEnd (NextDevicePathNode (DevicePathNode))) {
|
|
PrimaryBus = SecondaryBus;
|
|
SecondaryBus++;
|
|
}
|
|
}
|
|
}
|
|
|
|
MemLimit = 0;
|
|
MmioSize = FindMmioSizeFromPciInfoList (&TempPciInfoHead);
|
|
if (MmioSize > 0) {
|
|
//
|
|
// Device is present
|
|
// Find the required memery base & limit
|
|
//
|
|
for (Index = 0, MemBase = 0; Index < PCI_MAX_BAR; Index++) {
|
|
if (PciBar[Index] == 0) {
|
|
continue;
|
|
}
|
|
MemBase = (MemBase == 0) ? PciBar[Index] : MIN (PciBar[Index], MemBase);
|
|
MemLimit = MAX ((UINT32)MmioSize, PciBar[Index] - MemBase);
|
|
}
|
|
|
|
//
|
|
// Record the device info.
|
|
//
|
|
for (Link = GetFirstNode (&TempPciInfoHead), ParentInfo = NULL, TempSubordinateBus = SubordinateBus
|
|
; !IsNull (&TempPciInfoHead, Link)
|
|
; Link = GetNextNode (&TempPciInfoHead, Link), ParentInfo = PciInfo
|
|
) {
|
|
TempPciInfo = PCI_INFO_NODE_FROM_LINK (Link);
|
|
PciInfo = (PCI_INFO_NODE *)AllocateCopyPool (sizeof (PCI_INFO_NODE), TempPciInfo);
|
|
ASSERT (PciInfo != NULL);
|
|
if (PciInfo == NULL) {
|
|
return 0;
|
|
}
|
|
PciInfo->Parent = ParentInfo;
|
|
ChildPciInfo = GetChildInfo (&TempPciInfoHead, Link);
|
|
if (ChildPciInfo != NULL) {
|
|
//
|
|
// Assuming there is only one child in the temp linked list.
|
|
//
|
|
PciInfo->IsP2pBridge = TRUE;
|
|
PciInfo->SecondaryBus = ChildPciInfo->PciRes.Bus;
|
|
PciInfo->SubordinateBus = TempSubordinateBus;
|
|
PciInfo->MemBase = MemBase;
|
|
PciInfo->MemLimit = MemLimit;
|
|
}
|
|
//
|
|
// The bridge is possibly enumerated before.
|
|
// Update the existing info that is related to the bridge.
|
|
//
|
|
NewSubordinateBus = UpdatePciTopology (ListHead, PciInfo);
|
|
if (NewSubordinateBus > SubordinateBus) {
|
|
SubordinateBus = NewSubordinateBus;
|
|
SecondaryBus = SubordinateBus + 1;
|
|
}
|
|
}
|
|
} else {
|
|
SecondaryBus = OrgSecondaryBus;
|
|
}
|
|
}
|
|
|
|
return (SecondaryBus == FIRST_DOWNSTREAM_NUM) ? 0 : SecondaryBus;
|
|
}
|
|
|
|
/**
|
|
Program BAR register for PCI device.
|
|
|
|
@param [in] Bus PCI Bus number.
|
|
@param [in] Device PCI Device number.
|
|
@param [in] Function PCI Function number.
|
|
@param [in] BarIndex Index of BAR.
|
|
@param [in] BaseAddress Bass address.
|
|
@param [out] MmioSize MMIO size.
|
|
|
|
@retval EFI_SUCCESS Operation completed successfully.
|
|
@retval Others Operation failed.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
ProgramBar (
|
|
IN PCI_RESOURCE_DATA *PciRes
|
|
)
|
|
{
|
|
UINT32 Size;
|
|
UINT64 MmioSize;
|
|
UINT32 BarIndex;
|
|
UINT32 BaseAddress;
|
|
UINT8 Bus;
|
|
UINT8 Device;
|
|
UINT8 Function;
|
|
|
|
if (FeaturePcdGet (PcdH2OPeiCpPciEnumUpdateDevResourcesSupported)) {
|
|
H2O_PEI_CP_PCI_ENUM_UPDATE_DEV_RESOURCES CpPciEnumUpdateDevResourceData;
|
|
|
|
CpPciEnumUpdateDevResourceData.Size = sizeof (H2O_PEI_CP_PCI_ENUM_UPDATE_DEV_RESOURCES);
|
|
CpPciEnumUpdateDevResourceData.Status = H2O_CP_TASK_NORMAL;
|
|
CpPciEnumUpdateDevResourceData.NodeUid = PciRes->NodeUid;
|
|
CpPciEnumUpdateDevResourceData.Bus = PciRes->Bus;
|
|
CpPciEnumUpdateDevResourceData.Device = PciRes->Device;
|
|
CpPciEnumUpdateDevResourceData.Function = PciRes->Function;
|
|
CopyMem ((VOID *)&CpPciEnumUpdateDevResourceData.PciBar, (VOID *)&PciRes->PciBar, sizeof (CpPciEnumUpdateDevResourceData.PciBar));
|
|
|
|
DEBUG_CP ((DEBUG_INFO, "Checkpoint Trigger: %g\n", &gH2OPeiCpPciEnumUpdateDevResourcesGuid));
|
|
H2OCpTrigger (&gH2OPeiCpPciEnumUpdateDevResourcesGuid, &CpPciEnumUpdateDevResourceData);
|
|
DEBUG_CP ((DEBUG_INFO, "Checkpoint Result: %x\n", CpPciEnumUpdateDevResourceData.Status));
|
|
if (CpPciEnumUpdateDevResourceData.Status == H2O_CP_TASK_SKIP) {
|
|
return EFI_SUCCESS;
|
|
} else if (CpPciEnumUpdateDevResourceData.Status == H2O_BDS_TASK_UPDATE) {
|
|
CopyMem ((VOID *)&PciRes->PciBar, (VOID *)&CpPciEnumUpdateDevResourceData.PciBar, sizeof (PciRes->PciBar));
|
|
}
|
|
}
|
|
|
|
Bus = PciRes->Bus;
|
|
Device = PciRes->Device;
|
|
Function = PciRes->Function;
|
|
|
|
for (BarIndex = 0; BarIndex < PCI_MAX_BAR; BarIndex++) {
|
|
BaseAddress = PciRes->PciBar[BarIndex];
|
|
if (BaseAddress == 0) {
|
|
continue;
|
|
}
|
|
//
|
|
// Get MMIO region size.
|
|
//
|
|
PciAnd16 (PCI_LIB_ADDRESS (Bus, Device, Function, PCI_COMMAND_OFFSET), (UINT16)~(EFI_PCI_COMMAND_BUS_MASTER | EFI_PCI_COMMAND_MEMORY_SPACE));
|
|
PciWrite32 (PCI_LIB_ADDRESS (Bus, Device, Function, PCI_BASE_ADDRESSREG_OFFSET + 4 * BarIndex), 0xFFFFFFFF);
|
|
Size = PciRead32 (PCI_LIB_ADDRESS (Bus, Device, Function, PCI_BASE_ADDRESSREG_OFFSET + 4 * BarIndex));
|
|
|
|
switch (Size & 0x07) {
|
|
|
|
case 0x0:
|
|
DEBUG ((DEBUG_INFO, "PciResourceInitPei - ProgramBar -- BAR[%x] 32-bit memory space\n", BarIndex));
|
|
//
|
|
// Memory space: anywhere in 32 bit address space
|
|
//
|
|
MmioSize = (~(Size & 0xFFFFFFF0)) + 1;
|
|
break;
|
|
|
|
case 0x4:
|
|
DEBUG ((DEBUG_INFO, "PciResourceInitPei - ProgramBar -- BAR[%x] 64-bit memory space\n", BarIndex));
|
|
//
|
|
// Memory space: anywhere in 64 bit address space
|
|
//
|
|
MmioSize = Size & 0xFFFFFFF0;
|
|
PciWrite32 (PCI_LIB_ADDRESS(Bus, Device, Function, PCI_BASE_ADDRESSREG_OFFSET + 4 * BarIndex + 4), 0xFFFFFFFF);
|
|
Size = PciRead32 (PCI_LIB_ADDRESS(Bus, Device, Function, PCI_BASE_ADDRESSREG_OFFSET + 4 * BarIndex + 4));
|
|
//
|
|
// Fix the length to support some spefic 64 bit BAR
|
|
//
|
|
Size |= ((UINT32)(-1) << HighBitSet32 (Size));
|
|
//
|
|
// Calculate the size of 64bit bar
|
|
//
|
|
MmioSize |= LShiftU64 ((UINT64) Size, 32);
|
|
MmioSize = (~(MmioSize)) + 1;
|
|
//
|
|
// Clean the high 32bits of this 64bit BAR to 0 as we only allow a 32bit BAR.
|
|
//
|
|
PciWrite32 (PCI_LIB_ADDRESS (Bus, Device, Function, PCI_BASE_ADDRESSREG_OFFSET + 4 * BarIndex + 4), 0);
|
|
break;
|
|
|
|
default:
|
|
DEBUG ((DEBUG_INFO, "PciResourceInitPei - ProgramBar -- BAR[%x] unknown BAR type\n", BarIndex));
|
|
//
|
|
// Unknown BAR type
|
|
//
|
|
ASSERT (FALSE);
|
|
return EFI_UNSUPPORTED;
|
|
};
|
|
//
|
|
// Assign resource to the SdMmc Pci host controller's MMIO BAR.
|
|
// Enable the SdMmc Pci host controller by setting BME and MSE bits of PCI_CMD register.
|
|
//
|
|
PciWrite32 (PCI_LIB_ADDRESS (Bus, Device, Function, PCI_BASE_ADDRESSREG_OFFSET + 4 * BarIndex), BaseAddress);
|
|
PciOr16 (PCI_LIB_ADDRESS (Bus, Device, Function, PCI_COMMAND_OFFSET), (EFI_PCI_COMMAND_BUS_MASTER | EFI_PCI_COMMAND_MEMORY_SPACE));
|
|
|
|
DEBUG ((DEBUG_INFO, "PciResourceInitPei - ProgramBar -- BAR[%x]=0x%x, Size=0x%x\n", BarIndex, BaseAddress, MmioSize));
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Register notify ppi to reset the bridges.
|
|
|
|
@param[in] PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
|
|
@param[in] NotifyDescriptor Address of the notification descriptor data structure.
|
|
@param[in] Ppi Address of the PPI that was installed.
|
|
|
|
@retval EFI_SUCCESS Operation completed successfully
|
|
@retval Others Operation failed
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
BridgeEndOfPeiPpiNotifyCallback (
|
|
IN EFI_PEI_SERVICES **PeiServices,
|
|
IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
|
|
IN VOID *Ppi
|
|
)
|
|
{
|
|
LIST_ENTRY *Link;
|
|
PCI_INFO_NODE *PciInfo;
|
|
|
|
for (Link = GetFirstNode (&mBridgeListHead)
|
|
; !IsNull (&mBridgeListHead, Link)
|
|
; Link = GetNextNode (&mBridgeListHead, Link)
|
|
) {
|
|
PciInfo = PCI_INFO_NODE_FROM_LINK (Link);
|
|
StopP2pBridge (PciInfo->PciRes.Bus, PciInfo->PciRes.Device, PciInfo->PciRes.Function);
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
PEIM entry.
|
|
|
|
@param FileHandle Handle of the file being invoked.
|
|
@param PeiServices Describes the list of possible PEI Services.
|
|
|
|
@retval EFI_SUCCESS The driver is successfully initialized
|
|
@retval Others Can't initialize the driver
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
PeimInitializePciResourceInit (
|
|
IN EFI_PEI_FILE_HANDLE FileHandle,
|
|
IN CONST EFI_PEI_SERVICES **PeiServices
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINT8 Bus;
|
|
UINT8 Device;
|
|
UINT8 Function;
|
|
UINT8 BaseClass;
|
|
UINT8 SubClass;
|
|
CONTROLLER_INIT_ROUTINE *Routine;
|
|
LIST_ENTRY ListHead;
|
|
PCI_INFO_NODE *PciInfo;
|
|
PCI_INFO_NODE *BridgeInfo;
|
|
UINT8 MaxBus;
|
|
|
|
//
|
|
// Shadow this PEIM to run from memory
|
|
//
|
|
if (!EFI_ERROR (PeiServicesRegisterForShadow (FileHandle))) {
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
if (LibPcdGetNextToken (&gH2ODeviceInfo2TokenSpaceGuid, 0) == 0) {
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
InitializeListHead (&mBridgeListHead);
|
|
InitializeListHead (&ListHead);
|
|
|
|
MaxBus = EnumerateFromPcd (&ListHead);
|
|
|
|
for (Bus = 0; Bus <= MaxBus; Bus++) {
|
|
for (Device = 0; Device <= PCI_MAX_DEVICE; Device++) {
|
|
for (Function = 0; Function <= PCI_MAX_FUNC; Function++) {
|
|
PciInfo = GetPciInfoFromList (&ListHead, Bus, Device, Function);
|
|
if (PciInfo == NULL) {
|
|
continue;
|
|
}
|
|
|
|
SubClass = PciRead8 (PCI_LIB_ADDRESS (Bus, Device, Function, PCI_CLASSCODE_OFFSET + 1));
|
|
BaseClass = PciRead8 (PCI_LIB_ADDRESS (Bus, Device, Function, PCI_CLASSCODE_OFFSET + 2));
|
|
if ((BaseClass == PCI_CLASS_BRIDGE) && (SubClass == PCI_CLASS_BRIDGE_P2P)) {
|
|
Status = InitP2pBridge (
|
|
Bus,
|
|
Device,
|
|
Function,
|
|
PciInfo->SecondaryBus,
|
|
PciInfo->SubordinateBus,
|
|
PciInfo->MemBase,
|
|
PciInfo->MemLimit
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
continue;
|
|
}
|
|
//
|
|
// Stop the bridge at End of PEI
|
|
//
|
|
BridgeInfo = (PCI_INFO_NODE *)AllocateCopyPool (sizeof (PCI_INFO_NODE), (VOID *)PciInfo);
|
|
ASSERT (BridgeInfo != NULL);
|
|
InsertTailList (&mBridgeListHead, &BridgeInfo->Link);
|
|
} else if (IsSupportedDevice (Bus, Device, Function)) {
|
|
Routine = &mPciControllerInitRoutineTable[0];
|
|
while (*Routine != NULL) {
|
|
Status = (*Routine) (
|
|
PeiServices,
|
|
&PciInfo->PciRes
|
|
);
|
|
if (!EFI_ERROR (Status) || (EFI_ERROR (Status) && (Status != EFI_UNSUPPORTED))) {
|
|
break;
|
|
}
|
|
Routine++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!IsListEmpty (&mBridgeListHead)) {
|
|
//
|
|
// Stop PCI bridges at End of PEI
|
|
//
|
|
Status = PeiServicesNotifyPpi (&mBridgeNotifyList);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
}
|
|
return EFI_SUCCESS;
|
|
}
|