2. Used EdkPciIncompatibleDeviceSupportLib in PciBus driver. 3. Redirect all Pci Configuration access to new APIs added in PciLib.c for PciBus driver. 4. Added one PCD PcdIncompatibleDeviceSupportMask in EdkModulePkg.spd to provide mask of PCI devices incompatibility check. git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@2562 6f19259b-4bc3-4df7-8a09-765794883524
2315 lines
52 KiB
C
2315 lines
52 KiB
C
/*++
|
|
|
|
Copyright (c) 2006 - 2007, Intel Corporation
|
|
All rights reserved. This program and the accompanying materials
|
|
are licensed and made available under the terms and conditions of the BSD License
|
|
which accompanies this distribution. The full text of the license may be found at
|
|
http://opensource.org/licenses/bsd-license.php
|
|
|
|
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
|
|
|
Module Name:
|
|
|
|
PciResourceSupport.c
|
|
|
|
Abstract:
|
|
|
|
PCI Bus Driver
|
|
|
|
Revision History
|
|
|
|
--*/
|
|
|
|
#include "pcibus.h"
|
|
#include "PciResourceSupport.h"
|
|
#include "PciCommand.h"
|
|
|
|
EFI_STATUS
|
|
SkipVGAAperture (
|
|
OUT UINT64 *Start,
|
|
IN UINT64 Length
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
The function is used to skip VGA range
|
|
|
|
Arguments:
|
|
|
|
Returns:
|
|
|
|
None
|
|
|
|
--*/
|
|
// TODO: Start - add argument and description to function comment
|
|
// TODO: Length - add argument and description to function comment
|
|
// TODO: EFI_SUCCESS - add return value to function comment
|
|
{
|
|
UINT64 Original;
|
|
UINT64 Mask;
|
|
UINT64 StartOffset;
|
|
UINT64 LimitOffset;
|
|
|
|
//
|
|
// For legacy VGA, bit 10 to bit 15 is not decoded
|
|
//
|
|
Mask = 0x3FF;
|
|
|
|
Original = *Start;
|
|
StartOffset = Original & Mask;
|
|
LimitOffset = ((*Start) + Length - 1) & Mask;
|
|
if (LimitOffset >= VGABASE1) {
|
|
*Start = *Start - StartOffset + VGALIMIT2 + 1;
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
EFI_STATUS
|
|
SkipIsaAliasAperture (
|
|
OUT UINT64 *Start,
|
|
IN UINT64 Length
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is used to skip ISA aliasing aperture
|
|
|
|
Arguments:
|
|
|
|
Returns:
|
|
|
|
None
|
|
|
|
--*/
|
|
// TODO: Start - add argument and description to function comment
|
|
// TODO: Length - add argument and description to function comment
|
|
// TODO: EFI_SUCCESS - add return value to function comment
|
|
{
|
|
|
|
UINT64 Original;
|
|
UINT64 Mask;
|
|
UINT64 StartOffset;
|
|
UINT64 LimitOffset;
|
|
|
|
//
|
|
// For legacy ISA, bit 10 to bit 15 is not decoded
|
|
//
|
|
Mask = 0x3FF;
|
|
|
|
Original = *Start;
|
|
StartOffset = Original & Mask;
|
|
LimitOffset = ((*Start) + Length - 1) & Mask;
|
|
|
|
if (LimitOffset >= ISABASE) {
|
|
*Start = *Start - StartOffset + ISALIMIT + 1;
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
EFI_STATUS
|
|
InsertResourceNode (
|
|
PCI_RESOURCE_NODE *Bridge,
|
|
PCI_RESOURCE_NODE *ResNode
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function inserts a resource node into the resource list.
|
|
The resource list is sorted in descend order.
|
|
|
|
Arguments:
|
|
|
|
Returns:
|
|
|
|
None
|
|
|
|
--*/
|
|
// TODO: Bridge - add argument and description to function comment
|
|
// TODO: ResNode - add argument and description to function comment
|
|
// TODO: EFI_SUCCESS - add return value to function comment
|
|
{
|
|
LIST_ENTRY *CurrentLink;
|
|
PCI_RESOURCE_NODE *Temp;
|
|
UINT64 ResNodeAlignRest;
|
|
UINT64 TempAlignRest;
|
|
|
|
InsertHeadList (&Bridge->ChildList, &ResNode->Link);
|
|
|
|
CurrentLink = Bridge->ChildList.ForwardLink->ForwardLink;
|
|
while (CurrentLink != &Bridge->ChildList) {
|
|
Temp = RESOURCE_NODE_FROM_LINK (CurrentLink);
|
|
|
|
if (ResNode->Alignment > Temp->Alignment) {
|
|
break;
|
|
} else if (ResNode->Alignment == Temp->Alignment) {
|
|
ResNodeAlignRest = ResNode->Length & ResNode->Alignment;
|
|
TempAlignRest = Temp->Length & Temp->Alignment;
|
|
if ((ResNodeAlignRest == 0) || (ResNodeAlignRest >= TempAlignRest)) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
SwapListEntries (&ResNode->Link, CurrentLink);
|
|
|
|
CurrentLink = ResNode->Link.ForwardLink;
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
EFI_STATUS
|
|
MergeResourceTree (
|
|
PCI_RESOURCE_NODE *Dst,
|
|
PCI_RESOURCE_NODE *Res,
|
|
BOOLEAN TypeMerge
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is used to merge two different resource tree in need of
|
|
resoure degradation. For example, if a upstream PPB doesn't support,
|
|
prefetchable memory decoding, the PCI bus driver will choose to call this function
|
|
to merge prefectchable memory resource list into normal memory list.
|
|
|
|
If the TypeMerge is TRUE, Res resource type is changed to the type of destination resource
|
|
type.
|
|
|
|
Arguments:
|
|
|
|
Returns:
|
|
|
|
None
|
|
|
|
--*/
|
|
// TODO: Dst - add argument and description to function comment
|
|
// TODO: Res - add argument and description to function comment
|
|
// TODO: TypeMerge - add argument and description to function comment
|
|
// TODO: EFI_SUCCESS - add return value to function comment
|
|
{
|
|
|
|
LIST_ENTRY *CurrentLink;
|
|
PCI_RESOURCE_NODE *Temp;
|
|
|
|
while (!IsListEmpty (&Res->ChildList)) {
|
|
CurrentLink = Res->ChildList.ForwardLink;
|
|
|
|
Temp = RESOURCE_NODE_FROM_LINK (CurrentLink);
|
|
|
|
if (TypeMerge) {
|
|
Temp->ResType = Dst->ResType;
|
|
}
|
|
|
|
RemoveEntryList (CurrentLink);
|
|
InsertResourceNode (Dst, Temp);
|
|
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
EFI_STATUS
|
|
CalculateApertureIo16 (
|
|
IN PCI_RESOURCE_NODE *Bridge
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is used to calculate the IO16 aperture
|
|
for a bridge.
|
|
|
|
Arguments:
|
|
|
|
Returns:
|
|
|
|
None
|
|
|
|
--*/
|
|
// TODO: Bridge - add argument and description to function comment
|
|
// TODO: EFI_SUCCESS - add return value to function comment
|
|
// TODO: EFI_SUCCESS - add return value to function comment
|
|
{
|
|
|
|
UINT64 Aperture;
|
|
LIST_ENTRY *CurrentLink;
|
|
PCI_RESOURCE_NODE *Node;
|
|
UINT64 offset;
|
|
BOOLEAN IsaEnable;
|
|
BOOLEAN VGAEnable;
|
|
|
|
//
|
|
// Always assume there is ISA device and VGA device on the platform
|
|
// will be customized later
|
|
//
|
|
IsaEnable = FALSE;
|
|
VGAEnable = FALSE;
|
|
|
|
if (FeaturePcdGet (PcdPciIsaEnable)){
|
|
IsaEnable = TRUE;
|
|
}
|
|
|
|
if (FeaturePcdGet (PcdPciVgaEnable)){
|
|
VGAEnable = TRUE;
|
|
}
|
|
|
|
Aperture = 0;
|
|
|
|
if (!Bridge) {
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
CurrentLink = Bridge->ChildList.ForwardLink;
|
|
|
|
//
|
|
// Assume the bridge is aligned
|
|
//
|
|
while (CurrentLink != &Bridge->ChildList) {
|
|
|
|
Node = RESOURCE_NODE_FROM_LINK (CurrentLink);
|
|
|
|
//
|
|
// Consider the aperture alignment
|
|
//
|
|
offset = Aperture & (Node->Alignment);
|
|
|
|
if (offset) {
|
|
|
|
Aperture = Aperture + (Node->Alignment + 1) - offset;
|
|
|
|
}
|
|
|
|
//
|
|
// IsaEnable and VGAEnable can not be implemented now.
|
|
// If both of them are enabled, then the IO resource would
|
|
// become too limited to meet the requirement of most of devices.
|
|
//
|
|
|
|
if (IsaEnable || VGAEnable) {
|
|
if (!IS_PCI_BRIDGE (&(Node->PciDev->Pci)) && !IS_CARDBUS_BRIDGE (&(Node->PciDev->Pci))) {
|
|
//
|
|
// Check if there is need to support ISA/VGA decoding
|
|
// If so, we need to avoid isa/vga aliasing range
|
|
//
|
|
if (IsaEnable) {
|
|
SkipIsaAliasAperture (
|
|
&Aperture,
|
|
Node->Length
|
|
);
|
|
offset = Aperture & (Node->Alignment);
|
|
if (offset) {
|
|
Aperture = Aperture + (Node->Alignment + 1) - offset;
|
|
}
|
|
} else if (VGAEnable) {
|
|
SkipVGAAperture (
|
|
&Aperture,
|
|
Node->Length
|
|
);
|
|
offset = Aperture & (Node->Alignment);
|
|
if (offset) {
|
|
Aperture = Aperture + (Node->Alignment + 1) - offset;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Node->Offset = Aperture;
|
|
|
|
//
|
|
// Increment aperture by the length of node
|
|
//
|
|
Aperture += Node->Length;
|
|
|
|
CurrentLink = CurrentLink->ForwardLink;
|
|
}
|
|
|
|
//
|
|
// At last, adjust the aperture with the bridge's
|
|
// alignment
|
|
//
|
|
offset = Aperture & (Bridge->Alignment);
|
|
|
|
if (offset) {
|
|
Aperture = Aperture + (Bridge->Alignment + 1) - offset;
|
|
}
|
|
|
|
Bridge->Length = Aperture;
|
|
//
|
|
// At last, adjust the bridge's alignment to the first child's alignment
|
|
// if the bridge has at least one child
|
|
//
|
|
CurrentLink = Bridge->ChildList.ForwardLink;
|
|
if (CurrentLink != &Bridge->ChildList) {
|
|
Node = RESOURCE_NODE_FROM_LINK (CurrentLink);
|
|
if (Node->Alignment > Bridge->Alignment) {
|
|
Bridge->Alignment = Node->Alignment;
|
|
}
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
EFI_STATUS
|
|
CalculateResourceAperture (
|
|
IN PCI_RESOURCE_NODE *Bridge
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is used to calculate the resource aperture
|
|
for a given bridge device
|
|
|
|
Arguments:
|
|
|
|
Returns:
|
|
|
|
None
|
|
|
|
--*/
|
|
// TODO: Bridge - add argument and description to function comment
|
|
// TODO: EFI_SUCCESS - add return value to function comment
|
|
// TODO: EFI_SUCCESS - add return value to function comment
|
|
{
|
|
UINT64 Aperture;
|
|
LIST_ENTRY *CurrentLink;
|
|
PCI_RESOURCE_NODE *Node;
|
|
|
|
UINT64 offset;
|
|
|
|
Aperture = 0;
|
|
|
|
if (!Bridge) {
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
if (Bridge->ResType == PciBarTypeIo16) {
|
|
return CalculateApertureIo16 (Bridge);
|
|
}
|
|
|
|
CurrentLink = Bridge->ChildList.ForwardLink;
|
|
|
|
//
|
|
// Assume the bridge is aligned
|
|
//
|
|
while (CurrentLink != &Bridge->ChildList) {
|
|
|
|
Node = RESOURCE_NODE_FROM_LINK (CurrentLink);
|
|
|
|
//
|
|
// Apply padding resource if available
|
|
//
|
|
|
|
offset = Aperture & (Node->Alignment);
|
|
|
|
if (offset) {
|
|
|
|
Aperture = Aperture + (Node->Alignment + 1) - offset;
|
|
|
|
}
|
|
|
|
//
|
|
// Recode current aperture as a offset
|
|
// this offset will be used in future real allocation
|
|
//
|
|
Node->Offset = Aperture;
|
|
|
|
//
|
|
// Increment aperture by the length of node
|
|
//
|
|
Aperture += Node->Length;
|
|
|
|
//
|
|
// Consider the aperture alignment
|
|
//
|
|
|
|
CurrentLink = CurrentLink->ForwardLink;
|
|
}
|
|
|
|
//
|
|
// At last, adjust the aperture with the bridge's
|
|
// alignment
|
|
//
|
|
offset = Aperture & (Bridge->Alignment);
|
|
if (offset) {
|
|
Aperture = Aperture + (Bridge->Alignment + 1) - offset;
|
|
}
|
|
|
|
//
|
|
// If the bridge has already padded the resource and the
|
|
// amount of padded resource is larger, then keep the
|
|
// padded resource
|
|
//
|
|
if (Bridge->Length < Aperture) {
|
|
Bridge->Length = Aperture;
|
|
}
|
|
|
|
//
|
|
// At last, adjust the bridge's alignment to the first child's alignment
|
|
// if the bridge has at least one child
|
|
//
|
|
CurrentLink = Bridge->ChildList.ForwardLink;
|
|
if (CurrentLink != &Bridge->ChildList) {
|
|
Node = RESOURCE_NODE_FROM_LINK (CurrentLink);
|
|
if (Node->Alignment > Bridge->Alignment) {
|
|
Bridge->Alignment = Node->Alignment;
|
|
}
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
EFI_STATUS
|
|
GetResourceFromDevice (
|
|
PCI_IO_DEVICE *PciDev,
|
|
PCI_RESOURCE_NODE *IoNode,
|
|
PCI_RESOURCE_NODE *Mem32Node,
|
|
PCI_RESOURCE_NODE *PMem32Node,
|
|
PCI_RESOURCE_NODE *Mem64Node,
|
|
PCI_RESOURCE_NODE *PMem64Node
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Returns:
|
|
|
|
None
|
|
|
|
--*/
|
|
// TODO: PciDev - add argument and description to function comment
|
|
// TODO: IoNode - add argument and description to function comment
|
|
// TODO: Mem32Node - add argument and description to function comment
|
|
// TODO: PMem32Node - add argument and description to function comment
|
|
// TODO: Mem64Node - add argument and description to function comment
|
|
// TODO: PMem64Node - add argument and description to function comment
|
|
// TODO: EFI_SUCCESS - add return value to function comment
|
|
{
|
|
|
|
UINT8 Index;
|
|
PCI_RESOURCE_NODE *Node;
|
|
BOOLEAN ResourceRequested;
|
|
|
|
Node = NULL;
|
|
ResourceRequested = FALSE;
|
|
|
|
for (Index = 0; Index < PCI_MAX_BAR; Index++) {
|
|
|
|
switch ((PciDev->PciBar)[Index].BarType) {
|
|
|
|
case PciBarTypeMem32:
|
|
|
|
Node = CreateResourceNode (
|
|
PciDev,
|
|
(PciDev->PciBar)[Index].Length,
|
|
(PciDev->PciBar)[Index].Alignment,
|
|
Index,
|
|
PciBarTypeMem32,
|
|
PciResUsageTypical
|
|
);
|
|
|
|
InsertResourceNode (
|
|
Mem32Node,
|
|
Node
|
|
);
|
|
|
|
ResourceRequested = TRUE;
|
|
break;
|
|
|
|
case PciBarTypeMem64:
|
|
|
|
Node = CreateResourceNode (
|
|
PciDev,
|
|
(PciDev->PciBar)[Index].Length,
|
|
(PciDev->PciBar)[Index].Alignment,
|
|
Index,
|
|
PciBarTypeMem64,
|
|
PciResUsageTypical
|
|
);
|
|
|
|
InsertResourceNode (
|
|
Mem64Node,
|
|
Node
|
|
);
|
|
|
|
ResourceRequested = TRUE;
|
|
break;
|
|
|
|
case PciBarTypePMem64:
|
|
|
|
Node = CreateResourceNode (
|
|
PciDev,
|
|
(PciDev->PciBar)[Index].Length,
|
|
(PciDev->PciBar)[Index].Alignment,
|
|
Index,
|
|
PciBarTypePMem64,
|
|
PciResUsageTypical
|
|
);
|
|
|
|
InsertResourceNode (
|
|
PMem64Node,
|
|
Node
|
|
);
|
|
|
|
ResourceRequested = TRUE;
|
|
break;
|
|
|
|
case PciBarTypePMem32:
|
|
|
|
Node = CreateResourceNode (
|
|
PciDev,
|
|
(PciDev->PciBar)[Index].Length,
|
|
(PciDev->PciBar)[Index].Alignment,
|
|
Index,
|
|
PciBarTypePMem32,
|
|
PciResUsageTypical
|
|
);
|
|
|
|
InsertResourceNode (
|
|
PMem32Node,
|
|
Node
|
|
);
|
|
ResourceRequested = TRUE;
|
|
break;
|
|
|
|
case PciBarTypeIo16:
|
|
case PciBarTypeIo32:
|
|
|
|
Node = CreateResourceNode (
|
|
PciDev,
|
|
(PciDev->PciBar)[Index].Length,
|
|
(PciDev->PciBar)[Index].Alignment,
|
|
Index,
|
|
PciBarTypeIo16,
|
|
PciResUsageTypical
|
|
);
|
|
|
|
InsertResourceNode (
|
|
IoNode,
|
|
Node
|
|
);
|
|
ResourceRequested = TRUE;
|
|
break;
|
|
|
|
case PciBarTypeUnknown:
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// If there is no resource requested from this device,
|
|
// then we indicate this device has been allocated naturally.
|
|
//
|
|
if (!ResourceRequested) {
|
|
PciDev->Allocated = TRUE;
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
PCI_RESOURCE_NODE *
|
|
CreateResourceNode (
|
|
IN PCI_IO_DEVICE *PciDev,
|
|
IN UINT64 Length,
|
|
IN UINT64 Alignment,
|
|
IN UINT8 Bar,
|
|
IN PCI_BAR_TYPE ResType,
|
|
IN PCI_RESOURCE_USAGE ResUsage
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is used to create a resource node
|
|
|
|
Arguments:
|
|
|
|
Returns:
|
|
|
|
None
|
|
|
|
--*/
|
|
// TODO: PciDev - add argument and description to function comment
|
|
// TODO: Length - add argument and description to function comment
|
|
// TODO: Alignment - add argument and description to function comment
|
|
// TODO: Bar - add argument and description to function comment
|
|
// TODO: ResType - add argument and description to function comment
|
|
// TODO: ResUsage - add argument and description to function comment
|
|
{
|
|
PCI_RESOURCE_NODE *Node;
|
|
|
|
Node = NULL;
|
|
|
|
Node = AllocatePool (sizeof (PCI_RESOURCE_NODE));
|
|
if (Node == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
ZeroMem (Node, sizeof (PCI_RESOURCE_NODE));
|
|
|
|
Node->Signature = PCI_RESOURCE_SIGNATURE;
|
|
Node->PciDev = PciDev;
|
|
Node->Length = Length;
|
|
Node->Alignment = Alignment;
|
|
Node->Bar = Bar;
|
|
Node->ResType = ResType;
|
|
Node->Reserved = FALSE;
|
|
Node->ResourceUsage = ResUsage;
|
|
InitializeListHead (&Node->ChildList);
|
|
return Node;
|
|
}
|
|
|
|
EFI_STATUS
|
|
CreateResourceMap (
|
|
IN PCI_IO_DEVICE *Bridge,
|
|
IN PCI_RESOURCE_NODE *IoNode,
|
|
IN PCI_RESOURCE_NODE *Mem32Node,
|
|
IN PCI_RESOURCE_NODE *PMem32Node,
|
|
IN PCI_RESOURCE_NODE *Mem64Node,
|
|
IN PCI_RESOURCE_NODE *PMem64Node
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is used to extract resource request from
|
|
device node list.
|
|
|
|
Arguments:
|
|
|
|
Returns:
|
|
|
|
None
|
|
|
|
--*/
|
|
// TODO: Bridge - add argument and description to function comment
|
|
// TODO: IoNode - add argument and description to function comment
|
|
// TODO: Mem32Node - add argument and description to function comment
|
|
// TODO: PMem32Node - add argument and description to function comment
|
|
// TODO: Mem64Node - add argument and description to function comment
|
|
// TODO: PMem64Node - add argument and description to function comment
|
|
// TODO: EFI_SUCCESS - add return value to function comment
|
|
{
|
|
PCI_IO_DEVICE *Temp;
|
|
PCI_RESOURCE_NODE *IoBridge;
|
|
PCI_RESOURCE_NODE *Mem32Bridge;
|
|
PCI_RESOURCE_NODE *PMem32Bridge;
|
|
PCI_RESOURCE_NODE *Mem64Bridge;
|
|
PCI_RESOURCE_NODE *PMem64Bridge;
|
|
LIST_ENTRY *CurrentLink;
|
|
|
|
CurrentLink = Bridge->ChildList.ForwardLink;
|
|
|
|
while (CurrentLink && CurrentLink != &Bridge->ChildList) {
|
|
|
|
Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
|
|
|
|
//
|
|
// Create resource nodes for this device by scanning the
|
|
// Bar array in the device private data
|
|
// If the upstream bridge doesn't support this device,
|
|
// no any resource node will be created for this device
|
|
//
|
|
GetResourceFromDevice (
|
|
Temp,
|
|
IoNode,
|
|
Mem32Node,
|
|
PMem32Node,
|
|
Mem64Node,
|
|
PMem64Node
|
|
);
|
|
|
|
if (IS_PCI_BRIDGE (&Temp->Pci)) {
|
|
|
|
//
|
|
// If the device has children, create a bridge resource node for this PPB
|
|
// Note: For PPB, memory aperture is aligned with 1MB and IO aperture
|
|
// is aligned with 4KB
|
|
// This device is typically a bridge device like PPB and P2C
|
|
//
|
|
IoBridge = CreateResourceNode (
|
|
Temp,
|
|
0,
|
|
0xFFF,
|
|
PPB_IO_RANGE,
|
|
PciBarTypeIo16,
|
|
PciResUsageTypical
|
|
); //0x1000 aligned
|
|
|
|
Mem32Bridge = CreateResourceNode (
|
|
Temp,
|
|
0,
|
|
0xFFFFF,
|
|
PPB_MEM32_RANGE,
|
|
PciBarTypeMem32,
|
|
PciResUsageTypical
|
|
);
|
|
|
|
PMem32Bridge = CreateResourceNode (
|
|
Temp,
|
|
0,
|
|
0xFFFFF,
|
|
PPB_PMEM32_RANGE,
|
|
PciBarTypePMem32,
|
|
PciResUsageTypical
|
|
);
|
|
|
|
Mem64Bridge = CreateResourceNode (
|
|
Temp,
|
|
0,
|
|
0xFFFFF,
|
|
PPB_MEM64_RANGE,
|
|
PciBarTypeMem64,
|
|
PciResUsageTypical
|
|
);
|
|
|
|
PMem64Bridge = CreateResourceNode (
|
|
Temp,
|
|
0,
|
|
0xFFFFF,
|
|
PPB_PMEM64_RANGE,
|
|
PciBarTypePMem64,
|
|
PciResUsageTypical
|
|
);
|
|
|
|
//
|
|
// Recursively create resouce map on this bridge
|
|
//
|
|
CreateResourceMap (
|
|
Temp,
|
|
IoBridge,
|
|
Mem32Bridge,
|
|
PMem32Bridge,
|
|
Mem64Bridge,
|
|
PMem64Bridge
|
|
);
|
|
|
|
if (ResourceRequestExisted (IoBridge)) {
|
|
InsertResourceNode (
|
|
IoNode,
|
|
IoBridge
|
|
);
|
|
} else {
|
|
gBS->FreePool (IoBridge);
|
|
IoBridge = NULL;
|
|
}
|
|
|
|
//
|
|
// If there is node under this resource bridge,
|
|
// then calculate bridge's aperture of this type
|
|
// and insert it into the respective resource tree.
|
|
// If no, delete this resource bridge
|
|
//
|
|
if (ResourceRequestExisted (Mem32Bridge)) {
|
|
InsertResourceNode (
|
|
Mem32Node,
|
|
Mem32Bridge
|
|
);
|
|
} else {
|
|
gBS->FreePool (Mem32Bridge);
|
|
Mem32Bridge = NULL;
|
|
}
|
|
|
|
//
|
|
// If there is node under this resource bridge,
|
|
// then calculate bridge's aperture of this type
|
|
// and insert it into the respective resource tree.
|
|
// If no, delete this resource bridge
|
|
//
|
|
if (ResourceRequestExisted (PMem32Bridge)) {
|
|
InsertResourceNode (
|
|
PMem32Node,
|
|
PMem32Bridge
|
|
);
|
|
} else {
|
|
gBS->FreePool (PMem32Bridge);
|
|
PMem32Bridge = NULL;
|
|
}
|
|
|
|
//
|
|
// If there is node under this resource bridge,
|
|
// then calculate bridge's aperture of this type
|
|
// and insert it into the respective resource tree.
|
|
// If no, delete this resource bridge
|
|
//
|
|
if (ResourceRequestExisted (Mem64Bridge)) {
|
|
InsertResourceNode (
|
|
Mem64Node,
|
|
Mem64Bridge
|
|
);
|
|
} else {
|
|
gBS->FreePool (Mem64Bridge);
|
|
Mem64Bridge = NULL;
|
|
}
|
|
|
|
//
|
|
// If there is node under this resource bridge,
|
|
// then calculate bridge's aperture of this type
|
|
// and insert it into the respective resource tree.
|
|
// If no, delete this resource bridge
|
|
//
|
|
if (ResourceRequestExisted (PMem64Bridge)) {
|
|
InsertResourceNode (
|
|
PMem64Node,
|
|
PMem64Bridge
|
|
);
|
|
} else {
|
|
gBS->FreePool (PMem64Bridge);
|
|
PMem64Bridge = NULL;
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// If it is P2C, apply hard coded resource padding
|
|
//
|
|
//
|
|
if (IS_CARDBUS_BRIDGE (&Temp->Pci)) {
|
|
ResourcePaddingForCardBusBridge (
|
|
Temp,
|
|
IoNode,
|
|
Mem32Node,
|
|
PMem32Node,
|
|
Mem64Node,
|
|
PMem64Node
|
|
);
|
|
}
|
|
|
|
CurrentLink = CurrentLink->ForwardLink;
|
|
}
|
|
//
|
|
//
|
|
// To do some platform specific resource padding ...
|
|
//
|
|
ResourcePaddingPolicy (
|
|
Bridge,
|
|
IoNode,
|
|
Mem32Node,
|
|
PMem32Node,
|
|
Mem64Node,
|
|
PMem64Node
|
|
);
|
|
|
|
//
|
|
// Degrade resource if necessary
|
|
//
|
|
DegradeResource (
|
|
Bridge,
|
|
Mem32Node,
|
|
PMem32Node,
|
|
Mem64Node,
|
|
PMem64Node
|
|
);
|
|
|
|
//
|
|
// Calculate resource aperture for this bridge device
|
|
//
|
|
CalculateResourceAperture (Mem32Node);
|
|
CalculateResourceAperture (PMem32Node);
|
|
CalculateResourceAperture (Mem64Node);
|
|
CalculateResourceAperture (PMem64Node);
|
|
CalculateResourceAperture (IoNode);
|
|
|
|
return EFI_SUCCESS;
|
|
|
|
}
|
|
|
|
EFI_STATUS
|
|
ResourcePaddingPolicy (
|
|
PCI_IO_DEVICE *PciDev,
|
|
PCI_RESOURCE_NODE *IoNode,
|
|
PCI_RESOURCE_NODE *Mem32Node,
|
|
PCI_RESOURCE_NODE *PMem32Node,
|
|
PCI_RESOURCE_NODE *Mem64Node,
|
|
PCI_RESOURCE_NODE *PMem64Node
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is used to do the resource padding for a specific platform
|
|
|
|
Arguments:
|
|
|
|
PciDev - A pointer to the PCI_IO_DEVICE structrue.
|
|
IoNode - A pointer to the PCI_RESOURCE_NODE structrue.
|
|
Mem32Node - A pointer to the PCI_RESOURCE_NODE structrue.
|
|
PMem32Node - A pointer to the PCI_RESOURCE_NODE structrue.
|
|
Mem64Node - A pointer to the PCI_RESOURCE_NODE structrue.
|
|
PMem64Node - A pointer to the PCI_RESOURCE_NODE structrue.
|
|
|
|
Returns:
|
|
Status code
|
|
|
|
None
|
|
|
|
--*/
|
|
// TODO: EFI_SUCCESS - add return value to function comment
|
|
{
|
|
//
|
|
// Create padding resource node
|
|
//
|
|
if (PciDev->ResourcePaddingDescriptors != NULL) {
|
|
ApplyResourcePadding (
|
|
PciDev,
|
|
IoNode,
|
|
Mem32Node,
|
|
PMem32Node,
|
|
Mem64Node,
|
|
PMem64Node
|
|
);
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
|
|
}
|
|
|
|
EFI_STATUS
|
|
DegradeResource (
|
|
IN PCI_IO_DEVICE *Bridge,
|
|
IN PCI_RESOURCE_NODE *Mem32Node,
|
|
IN PCI_RESOURCE_NODE *PMem32Node,
|
|
IN PCI_RESOURCE_NODE *Mem64Node,
|
|
IN PCI_RESOURCE_NODE *PMem64Node
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is used to degrade resource if the upstream bridge
|
|
doesn't support certain resource. Degradation path is
|
|
PMEM64 -> MEM64 -> MEM32
|
|
PMEM64 -> PMEM32 -> MEM32
|
|
IO32 -> IO16
|
|
|
|
Arguments:
|
|
|
|
Returns:
|
|
|
|
None
|
|
|
|
--*/
|
|
// TODO: Bridge - add argument and description to function comment
|
|
// TODO: Mem32Node - add argument and description to function comment
|
|
// TODO: PMem32Node - add argument and description to function comment
|
|
// TODO: Mem64Node - add argument and description to function comment
|
|
// TODO: PMem64Node - add argument and description to function comment
|
|
// TODO: EFI_SUCCESS - add return value to function comment
|
|
{
|
|
|
|
//
|
|
// If bridge doesn't support Prefetchable
|
|
// memory64, degrade it to Mem64
|
|
//
|
|
if (!BridgeSupportResourceDecode (Bridge, EFI_BRIDGE_PMEM64_DECODE_SUPPORTED)) {
|
|
MergeResourceTree (
|
|
PMem32Node,
|
|
PMem64Node,
|
|
TRUE
|
|
);
|
|
} else {
|
|
//
|
|
// if no PMem32 request, still keep PMem64. Otherwise degrade to PMem32
|
|
//
|
|
if (PMem32Node != NULL) {
|
|
MergeResourceTree (
|
|
PMem32Node,
|
|
PMem64Node,
|
|
TRUE
|
|
);
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// If bridge doesn't support Mem64
|
|
// degrade it to mem32
|
|
//
|
|
if (!BridgeSupportResourceDecode (Bridge, EFI_BRIDGE_MEM64_DECODE_SUPPORTED)) {
|
|
MergeResourceTree (
|
|
Mem32Node,
|
|
Mem64Node,
|
|
TRUE
|
|
);
|
|
}
|
|
|
|
//
|
|
// If bridge doesn't support Pmem32
|
|
// degrade it to mem32
|
|
//
|
|
if (!BridgeSupportResourceDecode (Bridge, EFI_BRIDGE_PMEM32_DECODE_SUPPORTED)) {
|
|
MergeResourceTree (
|
|
Mem32Node,
|
|
PMem32Node,
|
|
TRUE
|
|
);
|
|
}
|
|
|
|
//
|
|
// if bridge supports combined Pmem Mem decoding
|
|
// merge these two type of resource
|
|
//
|
|
if (BridgeSupportResourceDecode (Bridge, EFI_BRIDGE_PMEM_MEM_COMBINE_SUPPORTED)) {
|
|
MergeResourceTree (
|
|
Mem32Node,
|
|
PMem32Node,
|
|
FALSE
|
|
);
|
|
|
|
MergeResourceTree (
|
|
Mem64Node,
|
|
PMem64Node,
|
|
FALSE
|
|
);
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
BOOLEAN
|
|
BridgeSupportResourceDecode (
|
|
IN PCI_IO_DEVICE *Bridge,
|
|
IN UINT32 Decode
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
TODO: Add function description
|
|
|
|
Arguments:
|
|
|
|
Bridge - TODO: add argument description
|
|
Decode - TODO: add argument description
|
|
|
|
Returns:
|
|
|
|
TODO: add return values
|
|
|
|
--*/
|
|
{
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Returns:
|
|
|
|
None
|
|
|
|
--*/
|
|
if ((Bridge->Decodes) & Decode) {
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
EFI_STATUS
|
|
ProgramResource (
|
|
IN UINT64 Base,
|
|
IN PCI_RESOURCE_NODE *Bridge
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is used to program the resource allocated
|
|
for each resource node
|
|
|
|
Arguments:
|
|
|
|
Returns:
|
|
|
|
None
|
|
|
|
--*/
|
|
// TODO: Base - add argument and description to function comment
|
|
// TODO: Bridge - add argument and description to function comment
|
|
// TODO: EFI_OUT_OF_RESOURCES - add return value to function comment
|
|
// TODO: EFI_SUCCESS - add return value to function comment
|
|
{
|
|
LIST_ENTRY *CurrentLink;
|
|
PCI_RESOURCE_NODE *Node;
|
|
EFI_STATUS Status;
|
|
|
|
if (Base == gAllOne) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
CurrentLink = Bridge->ChildList.ForwardLink;
|
|
|
|
while (CurrentLink != &Bridge->ChildList) {
|
|
|
|
Node = RESOURCE_NODE_FROM_LINK (CurrentLink);
|
|
|
|
if (!IS_PCI_BRIDGE (&(Node->PciDev->Pci))) {
|
|
|
|
if (IS_CARDBUS_BRIDGE (&(Node->PciDev->Pci))) {
|
|
ProgramP2C (Base, Node);
|
|
} else {
|
|
ProgramBar (Base, Node);
|
|
}
|
|
} else {
|
|
Status = ProgramResource (Base + Node->Offset, Node);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
ProgramPpbApperture (Base, Node);
|
|
}
|
|
|
|
CurrentLink = CurrentLink->ForwardLink;
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
EFI_STATUS
|
|
ProgramBar (
|
|
IN UINT64 Base,
|
|
IN PCI_RESOURCE_NODE *Node
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Returns:
|
|
|
|
None
|
|
|
|
--*/
|
|
// TODO: Base - add argument and description to function comment
|
|
// TODO: Node - add argument and description to function comment
|
|
// TODO: EFI_SUCCESS - add return value to function comment
|
|
{
|
|
EFI_PCI_IO_PROTOCOL *PciIo;
|
|
UINT64 Address;
|
|
UINT32 Address32;
|
|
|
|
Address = 0;
|
|
PciIo = &(Node->PciDev->PciIo);
|
|
|
|
Address = Base + Node->Offset;
|
|
|
|
//
|
|
// Indicate pci bus driver has allocated
|
|
// resource for this device
|
|
// It might be a temporary solution here since
|
|
// pci device could have multiple bar
|
|
//
|
|
Node->PciDev->Allocated = TRUE;
|
|
|
|
switch ((Node->PciDev->PciBar[Node->Bar]).BarType) {
|
|
|
|
case PciBarTypeIo16:
|
|
case PciBarTypeIo32:
|
|
case PciBarTypeMem32:
|
|
case PciBarTypePMem32:
|
|
|
|
PciIoWrite (
|
|
PciIo,
|
|
EfiPciIoWidthUint32,
|
|
(Node->PciDev->PciBar[Node->Bar]).Offset,
|
|
1,
|
|
&Address
|
|
);
|
|
|
|
Node->PciDev->PciBar[Node->Bar].BaseAddress = Address;
|
|
|
|
break;
|
|
|
|
case PciBarTypeMem64:
|
|
case PciBarTypePMem64:
|
|
|
|
Address32 = (UINT32) (Address & 0x00000000FFFFFFFF);
|
|
|
|
PciIoWrite (
|
|
PciIo,
|
|
EfiPciIoWidthUint32,
|
|
(Node->PciDev->PciBar[Node->Bar]).Offset,
|
|
1,
|
|
&Address32
|
|
);
|
|
|
|
Address32 = (UINT32) RShiftU64 (Address, 32);
|
|
|
|
PciIoWrite (
|
|
PciIo,
|
|
EfiPciIoWidthUint32,
|
|
(UINT8) ((Node->PciDev->PciBar[Node->Bar]).Offset + 4),
|
|
1,
|
|
&Address32
|
|
);
|
|
|
|
Node->PciDev->PciBar[Node->Bar].BaseAddress = Address;
|
|
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
EFI_STATUS
|
|
ProgramPpbApperture (
|
|
IN UINT64 Base,
|
|
IN PCI_RESOURCE_NODE *Node
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Returns:
|
|
|
|
None
|
|
|
|
--*/
|
|
// TODO: Base - add argument and description to function comment
|
|
// TODO: Node - add argument and description to function comment
|
|
// TODO: EFI_SUCCESS - add return value to function comment
|
|
// TODO: EFI_SUCCESS - add return value to function comment
|
|
{
|
|
EFI_PCI_IO_PROTOCOL *PciIo;
|
|
UINT64 Address;
|
|
UINT32 Address32;
|
|
|
|
Address = 0;
|
|
//
|
|
// if no device south of this PPB, return anyway
|
|
// Apperture is set default in the initialization code
|
|
//
|
|
if (Node->Length == 0 || Node->ResourceUsage == PciResUsagePadding) {
|
|
//
|
|
// For padding resource node, just ignore when programming
|
|
//
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
PciIo = &(Node->PciDev->PciIo);
|
|
Address = Base + Node->Offset;
|
|
|
|
//
|
|
// Indicate the PPB resource has been allocated
|
|
//
|
|
Node->PciDev->Allocated = TRUE;
|
|
|
|
switch (Node->Bar) {
|
|
|
|
case PPB_BAR_0:
|
|
case PPB_BAR_1:
|
|
PciIoWrite (
|
|
PciIo,
|
|
EfiPciIoWidthUint32,
|
|
(Node->PciDev->PciBar[Node->Bar]).Offset,
|
|
1,
|
|
&Address
|
|
);
|
|
|
|
Node->PciDev->PciBar[Node->Bar].BaseAddress = Address;
|
|
Node->PciDev->PciBar[Node->Bar].Length = Node->Length;
|
|
|
|
break;
|
|
|
|
case PPB_IO_RANGE:
|
|
|
|
Address32 = ((UINT32) (Address)) >> 8;
|
|
PciIoWrite (
|
|
PciIo,
|
|
EfiPciIoWidthUint8,
|
|
0x1C,
|
|
1,
|
|
&Address32
|
|
);
|
|
|
|
Address32 >>= 8;
|
|
PciIoWrite (
|
|
PciIo,
|
|
EfiPciIoWidthUint16,
|
|
0x30,
|
|
1,
|
|
&Address32
|
|
);
|
|
|
|
Address32 = (UINT32) (Address + Node->Length - 1);
|
|
Address32 = ((UINT32) (Address32)) >> 8;
|
|
PciIoWrite (
|
|
PciIo,
|
|
EfiPciIoWidthUint8,
|
|
0x1D,
|
|
1,
|
|
&Address32
|
|
);
|
|
|
|
Address32 >>= 8;
|
|
PciIoWrite (
|
|
PciIo,
|
|
EfiPciIoWidthUint16,
|
|
0x32,
|
|
1,
|
|
&Address32
|
|
);
|
|
|
|
Node->PciDev->PciBar[Node->Bar].BaseAddress = Address;
|
|
Node->PciDev->PciBar[Node->Bar].Length = Node->Length;
|
|
break;
|
|
|
|
case PPB_MEM32_RANGE:
|
|
|
|
Address32 = ((UINT32) (Address)) >> 16;
|
|
PciIoWrite (
|
|
PciIo,
|
|
EfiPciIoWidthUint16,
|
|
0x20,
|
|
1,
|
|
&Address32
|
|
);
|
|
|
|
Address32 = (UINT32) (Address + Node->Length - 1);
|
|
Address32 = ((UINT32) (Address32)) >> 16;
|
|
PciIoWrite (
|
|
PciIo,
|
|
EfiPciIoWidthUint16,
|
|
0x22,
|
|
1,
|
|
&Address32
|
|
);
|
|
|
|
Node->PciDev->PciBar[Node->Bar].BaseAddress = Address;
|
|
Node->PciDev->PciBar[Node->Bar].Length = Node->Length;
|
|
break;
|
|
|
|
case PPB_PMEM32_RANGE:
|
|
case PPB_PMEM64_RANGE:
|
|
|
|
Address32 = ((UINT32) (Address)) >> 16;
|
|
PciIoWrite (
|
|
PciIo,
|
|
EfiPciIoWidthUint16,
|
|
0x24,
|
|
1,
|
|
&Address32
|
|
);
|
|
|
|
Address32 = (UINT32) (Address + Node->Length - 1);
|
|
Address32 = ((UINT32) (Address32)) >> 16;
|
|
PciIoWrite (
|
|
PciIo,
|
|
EfiPciIoWidthUint16,
|
|
0x26,
|
|
1,
|
|
&Address32
|
|
);
|
|
|
|
Address32 = (UINT32) RShiftU64 (Address, 32);
|
|
PciIoWrite (
|
|
PciIo,
|
|
EfiPciIoWidthUint32,
|
|
0x28,
|
|
1,
|
|
&Address32
|
|
);
|
|
|
|
Address32 = (UINT32) RShiftU64 ((Address + Node->Length - 1), 32);
|
|
PciIoWrite (
|
|
PciIo,
|
|
EfiPciIoWidthUint32,
|
|
0x2C,
|
|
1,
|
|
&Address32
|
|
);
|
|
|
|
Node->PciDev->PciBar[Node->Bar].BaseAddress = Address;
|
|
Node->PciDev->PciBar[Node->Bar].Length = Node->Length;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
EFI_STATUS
|
|
ProgrameUpstreamBridgeForRom (
|
|
IN PCI_IO_DEVICE *PciDevice,
|
|
IN UINT32 OptionRomBase,
|
|
IN BOOLEAN Enable
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Returns:
|
|
|
|
--*/
|
|
// TODO: PciDevice - add argument and description to function comment
|
|
// TODO: OptionRomBase - add argument and description to function comment
|
|
// TODO: Enable - add argument and description to function comment
|
|
// TODO: EFI_SUCCESS - add return value to function comment
|
|
{
|
|
PCI_IO_DEVICE *Parent;
|
|
PCI_RESOURCE_NODE Node;
|
|
//
|
|
// For root bridge, just return.
|
|
//
|
|
Parent = PciDevice->Parent;
|
|
ZeroMem (&Node, sizeof (Node));
|
|
while (Parent) {
|
|
if (!IS_PCI_BRIDGE (&Parent->Pci)) {
|
|
break;
|
|
}
|
|
|
|
Node.PciDev = Parent;
|
|
Node.Length = PciDevice->RomSize;
|
|
Node.Alignment = 0;
|
|
Node.Bar = PPB_MEM32_RANGE;
|
|
Node.ResType = PciBarTypeMem32;
|
|
Node.Offset = 0;
|
|
|
|
//
|
|
// Program PPB to only open a single <= 16<MB apperture
|
|
//
|
|
if (Enable) {
|
|
ProgramPpbApperture (OptionRomBase, &Node);
|
|
PciEnableCommandRegister (Parent, EFI_PCI_COMMAND_MEMORY_SPACE);
|
|
} else {
|
|
InitializePpb (Parent);
|
|
PciDisableCommandRegister (Parent, EFI_PCI_COMMAND_MEMORY_SPACE);
|
|
}
|
|
|
|
Parent = Parent->Parent;
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
BOOLEAN
|
|
ResourceRequestExisted (
|
|
IN PCI_RESOURCE_NODE *Bridge
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Bridge - A pointer to the PCI_RESOURCE_NODE.
|
|
|
|
Returns:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
if (Bridge != NULL) {
|
|
if (!IsListEmpty (&Bridge->ChildList) || Bridge->Length != 0) {
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
EFI_STATUS
|
|
InitializeResourcePool (
|
|
PCI_RESOURCE_NODE *ResourcePool,
|
|
PCI_BAR_TYPE ResourceType
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Returns:
|
|
|
|
None
|
|
|
|
--*/
|
|
// TODO: ResourcePool - add argument and description to function comment
|
|
// TODO: ResourceType - add argument and description to function comment
|
|
// TODO: EFI_SUCCESS - add return value to function comment
|
|
{
|
|
|
|
ZeroMem (ResourcePool, sizeof (PCI_RESOURCE_NODE));
|
|
ResourcePool->ResType = ResourceType;
|
|
ResourcePool->Signature = PCI_RESOURCE_SIGNATURE;
|
|
InitializeListHead (&ResourcePool->ChildList);
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
EFI_STATUS
|
|
GetResourceMap (
|
|
PCI_IO_DEVICE *PciDev,
|
|
PCI_RESOURCE_NODE **IoBridge,
|
|
PCI_RESOURCE_NODE **Mem32Bridge,
|
|
PCI_RESOURCE_NODE **PMem32Bridge,
|
|
PCI_RESOURCE_NODE **Mem64Bridge,
|
|
PCI_RESOURCE_NODE **PMem64Bridge,
|
|
PCI_RESOURCE_NODE *IoPool,
|
|
PCI_RESOURCE_NODE *Mem32Pool,
|
|
PCI_RESOURCE_NODE *PMem32Pool,
|
|
PCI_RESOURCE_NODE *Mem64Pool,
|
|
PCI_RESOURCE_NODE *PMem64Pool
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Returns:
|
|
|
|
None
|
|
|
|
--*/
|
|
// TODO: PciDev - add argument and description to function comment
|
|
// TODO: IoBridge - add argument and description to function comment
|
|
// TODO: Mem32Bridge - add argument and description to function comment
|
|
// TODO: PMem32Bridge - add argument and description to function comment
|
|
// TODO: Mem64Bridge - add argument and description to function comment
|
|
// TODO: PMem64Bridge - add argument and description to function comment
|
|
// TODO: IoPool - add argument and description to function comment
|
|
// TODO: Mem32Pool - add argument and description to function comment
|
|
// TODO: PMem32Pool - add argument and description to function comment
|
|
// TODO: Mem64Pool - add argument and description to function comment
|
|
// TODO: PMem64Pool - add argument and description to function comment
|
|
// TODO: EFI_SUCCESS - add return value to function comment
|
|
{
|
|
|
|
PCI_RESOURCE_NODE *Temp;
|
|
LIST_ENTRY *CurrentLink;
|
|
|
|
CurrentLink = IoPool->ChildList.ForwardLink;
|
|
|
|
//
|
|
// Get Io resource map
|
|
//
|
|
while (CurrentLink != &IoPool->ChildList) {
|
|
|
|
Temp = RESOURCE_NODE_FROM_LINK (CurrentLink);
|
|
|
|
if (Temp->PciDev == PciDev) {
|
|
*IoBridge = Temp;
|
|
}
|
|
|
|
CurrentLink = CurrentLink->ForwardLink;
|
|
}
|
|
|
|
//
|
|
// Get Mem32 resource map
|
|
//
|
|
CurrentLink = Mem32Pool->ChildList.ForwardLink;
|
|
|
|
while (CurrentLink != &Mem32Pool->ChildList) {
|
|
|
|
Temp = RESOURCE_NODE_FROM_LINK (CurrentLink);
|
|
|
|
if (Temp->PciDev == PciDev) {
|
|
*Mem32Bridge = Temp;
|
|
}
|
|
|
|
CurrentLink = CurrentLink->ForwardLink;
|
|
}
|
|
|
|
//
|
|
// Get Pmem32 resource map
|
|
//
|
|
CurrentLink = PMem32Pool->ChildList.ForwardLink;
|
|
|
|
while (CurrentLink != &PMem32Pool->ChildList) {
|
|
|
|
Temp = RESOURCE_NODE_FROM_LINK (CurrentLink);
|
|
|
|
if (Temp->PciDev == PciDev) {
|
|
*PMem32Bridge = Temp;
|
|
}
|
|
|
|
CurrentLink = CurrentLink->ForwardLink;
|
|
}
|
|
|
|
//
|
|
// Get Mem64 resource map
|
|
//
|
|
CurrentLink = Mem64Pool->ChildList.ForwardLink;
|
|
|
|
while (CurrentLink != &Mem64Pool->ChildList) {
|
|
|
|
Temp = RESOURCE_NODE_FROM_LINK (CurrentLink);
|
|
|
|
if (Temp->PciDev == PciDev) {
|
|
*Mem64Bridge = Temp;
|
|
}
|
|
|
|
CurrentLink = CurrentLink->ForwardLink;
|
|
}
|
|
|
|
//
|
|
// Get Pmem64 resource map
|
|
//
|
|
CurrentLink = PMem64Pool->ChildList.ForwardLink;
|
|
|
|
while (CurrentLink != &PMem64Pool->ChildList) {
|
|
|
|
Temp = RESOURCE_NODE_FROM_LINK (CurrentLink);
|
|
|
|
if (Temp->PciDev == PciDev) {
|
|
*PMem64Bridge = Temp;
|
|
}
|
|
|
|
CurrentLink = CurrentLink->ForwardLink;
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
EFI_STATUS
|
|
DestroyResourceTree (
|
|
IN PCI_RESOURCE_NODE *Bridge
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Returns:
|
|
|
|
None
|
|
|
|
--*/
|
|
// TODO: Bridge - add argument and description to function comment
|
|
// TODO: EFI_SUCCESS - add return value to function comment
|
|
{
|
|
PCI_RESOURCE_NODE *Temp;
|
|
LIST_ENTRY *CurrentLink;
|
|
|
|
while (!IsListEmpty (&Bridge->ChildList)) {
|
|
|
|
CurrentLink = Bridge->ChildList.ForwardLink;
|
|
|
|
Temp = RESOURCE_NODE_FROM_LINK (CurrentLink);
|
|
|
|
RemoveEntryList (CurrentLink);
|
|
|
|
if (IS_PCI_BRIDGE (&(Temp->PciDev->Pci))) {
|
|
DestroyResourceTree (Temp);
|
|
}
|
|
|
|
gBS->FreePool (Temp);
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
EFI_STATUS
|
|
RecordReservedResource (
|
|
IN UINT64 Base,
|
|
IN UINT64 Length,
|
|
IN PCI_BAR_TYPE ResType,
|
|
IN PCI_IO_DEVICE *Bridge
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Returns:
|
|
|
|
None
|
|
|
|
--*/
|
|
// TODO: Base - add argument and description to function comment
|
|
// TODO: Length - add argument and description to function comment
|
|
// TODO: ResType - add argument and description to function comment
|
|
// TODO: Bridge - add argument and description to function comment
|
|
// TODO: EFI_OUT_OF_RESOURCES - add return value to function comment
|
|
// TODO: EFI_SUCCESS - add return value to function comment
|
|
{
|
|
PCI_RESERVED_RESOURCE_LIST *ReservedNode;
|
|
|
|
ReservedNode = AllocatePool (sizeof (PCI_RESERVED_RESOURCE_LIST));
|
|
if (ReservedNode == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
ReservedNode->Signature = RESERVED_RESOURCE_SIGNATURE;
|
|
ReservedNode->Node.Base = Base;
|
|
ReservedNode->Node.Length = Length;
|
|
ReservedNode->Node.ResType = ResType;
|
|
|
|
InsertTailList (&Bridge->ReservedResourceList, &(ReservedNode->Link));
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
EFI_STATUS
|
|
ResourcePaddingForCardBusBridge (
|
|
PCI_IO_DEVICE *PciDev,
|
|
PCI_RESOURCE_NODE *IoNode,
|
|
PCI_RESOURCE_NODE *Mem32Node,
|
|
PCI_RESOURCE_NODE *PMem32Node,
|
|
PCI_RESOURCE_NODE *Mem64Node,
|
|
PCI_RESOURCE_NODE *PMem64Node
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Returns:
|
|
|
|
None
|
|
|
|
--*/
|
|
// TODO: PciDev - add argument and description to function comment
|
|
// TODO: IoNode - add argument and description to function comment
|
|
// TODO: Mem32Node - add argument and description to function comment
|
|
// TODO: PMem32Node - add argument and description to function comment
|
|
// TODO: Mem64Node - add argument and description to function comment
|
|
// TODO: PMem64Node - add argument and description to function comment
|
|
// TODO: EFI_SUCCESS - add return value to function comment
|
|
{
|
|
PCI_RESOURCE_NODE *Node;
|
|
|
|
Node = NULL;
|
|
|
|
//
|
|
// Memory Base/Limit Register 0
|
|
// Bar 1 denodes memory range 0
|
|
//
|
|
Node = CreateResourceNode (
|
|
PciDev,
|
|
0x2000000,
|
|
0x1ffffff,
|
|
1,
|
|
PciBarTypeMem32,
|
|
PciResUsagePadding
|
|
);
|
|
|
|
InsertResourceNode (
|
|
Mem32Node,
|
|
Node
|
|
);
|
|
|
|
//
|
|
// Memory Base/Limit Register 1
|
|
// Bar 2 denodes memory range1
|
|
//
|
|
Node = CreateResourceNode (
|
|
PciDev,
|
|
0x2000000,
|
|
0x1ffffff,
|
|
2,
|
|
PciBarTypePMem32,
|
|
PciResUsagePadding
|
|
);
|
|
|
|
InsertResourceNode (
|
|
PMem32Node,
|
|
Node
|
|
);
|
|
|
|
//
|
|
// Io Base/Limit
|
|
// Bar 3 denodes io range 0
|
|
//
|
|
Node = CreateResourceNode (
|
|
PciDev,
|
|
0x100,
|
|
0xff,
|
|
3,
|
|
PciBarTypeIo16,
|
|
PciResUsagePadding
|
|
);
|
|
|
|
InsertResourceNode (
|
|
IoNode,
|
|
Node
|
|
);
|
|
|
|
//
|
|
// Io Base/Limit
|
|
// Bar 4 denodes io range 0
|
|
//
|
|
Node = CreateResourceNode (
|
|
PciDev,
|
|
0x100,
|
|
0xff,
|
|
4,
|
|
PciBarTypeIo16,
|
|
PciResUsagePadding
|
|
);
|
|
|
|
InsertResourceNode (
|
|
IoNode,
|
|
Node
|
|
);
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
EFI_STATUS
|
|
ProgramP2C (
|
|
IN UINT64 Base,
|
|
IN PCI_RESOURCE_NODE *Node
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Returns:
|
|
|
|
None
|
|
|
|
--*/
|
|
// TODO: Base - add argument and description to function comment
|
|
// TODO: Node - add argument and description to function comment
|
|
// TODO: EFI_SUCCESS - add return value to function comment
|
|
{
|
|
EFI_PCI_IO_PROTOCOL *PciIo;
|
|
UINT64 Address;
|
|
UINT64 TempAddress;
|
|
UINT16 BridgeControl;
|
|
|
|
Address = 0;
|
|
PciIo = &(Node->PciDev->PciIo);
|
|
|
|
Address = Base + Node->Offset;
|
|
|
|
//
|
|
// Indicate pci bus driver has allocated
|
|
// resource for this device
|
|
// It might be a temporary solution here since
|
|
// pci device could have multiple bar
|
|
//
|
|
Node->PciDev->Allocated = TRUE;
|
|
|
|
switch (Node->Bar) {
|
|
|
|
case P2C_BAR_0:
|
|
PciIoWrite (
|
|
PciIo,
|
|
EfiPciIoWidthUint32,
|
|
(Node->PciDev->PciBar[Node->Bar]).Offset,
|
|
1,
|
|
&Address
|
|
);
|
|
|
|
Node->PciDev->PciBar[Node->Bar].BaseAddress = Address;
|
|
Node->PciDev->PciBar[Node->Bar].Length = Node->Length;
|
|
break;
|
|
|
|
case P2C_MEM_1:
|
|
PciIoWrite (
|
|
PciIo,
|
|
EfiPciIoWidthUint32,
|
|
0x1c,
|
|
1,
|
|
&Address
|
|
);
|
|
|
|
TempAddress = Address + Node->Length - 1;
|
|
PciIoWrite (
|
|
PciIo,
|
|
EfiPciIoWidthUint32,
|
|
0x20,
|
|
1,
|
|
&TempAddress
|
|
);
|
|
|
|
if (Node->ResType == PciBarTypeMem32) {
|
|
|
|
//
|
|
// Set non-prefetchable bit
|
|
//
|
|
PciIoRead (
|
|
PciIo,
|
|
EfiPciIoWidthUint16,
|
|
0x3e,
|
|
1,
|
|
&BridgeControl
|
|
);
|
|
|
|
BridgeControl &= 0xfeff;
|
|
PciIoWrite (
|
|
PciIo,
|
|
EfiPciIoWidthUint16,
|
|
0x3e,
|
|
1,
|
|
&BridgeControl
|
|
);
|
|
|
|
} else {
|
|
|
|
//
|
|
// Set pre-fetchable bit
|
|
//
|
|
PciIoRead (
|
|
PciIo,
|
|
EfiPciIoWidthUint16,
|
|
0x3e,
|
|
1,
|
|
&BridgeControl
|
|
);
|
|
|
|
BridgeControl |= 0x0100;
|
|
PciIoWrite (
|
|
PciIo,
|
|
EfiPciIoWidthUint16,
|
|
0x3e,
|
|
1,
|
|
&BridgeControl
|
|
);
|
|
}
|
|
|
|
Node->PciDev->PciBar[Node->Bar].BaseAddress = Address;
|
|
Node->PciDev->PciBar[Node->Bar].Length = Node->Length;
|
|
Node->PciDev->PciBar[Node->Bar].BarType = Node->ResType;
|
|
|
|
break;
|
|
|
|
case P2C_MEM_2:
|
|
PciIoWrite (
|
|
PciIo,
|
|
EfiPciIoWidthUint32,
|
|
0x24,
|
|
1,
|
|
&Address
|
|
);
|
|
|
|
TempAddress = Address + Node->Length - 1;
|
|
|
|
PciIoWrite (
|
|
PciIo,
|
|
EfiPciIoWidthUint32,
|
|
0x28,
|
|
1,
|
|
&TempAddress
|
|
);
|
|
|
|
if (Node->ResType == PciBarTypeMem32) {
|
|
|
|
//
|
|
// Set non-prefetchable bit
|
|
//
|
|
PciIoRead (
|
|
PciIo,
|
|
EfiPciIoWidthUint16,
|
|
0x3e,
|
|
1,
|
|
&BridgeControl
|
|
);
|
|
|
|
BridgeControl &= 0xfdff;
|
|
PciIoWrite (
|
|
PciIo,
|
|
EfiPciIoWidthUint16,
|
|
0x3e,
|
|
1,
|
|
&BridgeControl
|
|
);
|
|
} else {
|
|
|
|
//
|
|
// Set pre-fetchable bit
|
|
//
|
|
PciIoRead (
|
|
PciIo,
|
|
EfiPciIoWidthUint16,
|
|
0x3e,
|
|
1,
|
|
&BridgeControl
|
|
);
|
|
|
|
BridgeControl |= 0x0200;
|
|
PciIoWrite (
|
|
PciIo,
|
|
EfiPciIoWidthUint16,
|
|
0x3e,
|
|
1,
|
|
&BridgeControl
|
|
);
|
|
}
|
|
|
|
Node->PciDev->PciBar[Node->Bar].BaseAddress = Address;
|
|
Node->PciDev->PciBar[Node->Bar].Length = Node->Length;
|
|
Node->PciDev->PciBar[Node->Bar].BarType = Node->ResType;
|
|
break;
|
|
|
|
case P2C_IO_1:
|
|
PciIoWrite (
|
|
PciIo,
|
|
EfiPciIoWidthUint32,
|
|
0x2c,
|
|
1,
|
|
&Address
|
|
);
|
|
TempAddress = Address + Node->Length - 1;
|
|
PciIoWrite (
|
|
PciIo,
|
|
EfiPciIoWidthUint32,
|
|
0x30,
|
|
1,
|
|
&TempAddress
|
|
);
|
|
|
|
Node->PciDev->PciBar[Node->Bar].BaseAddress = Address;
|
|
Node->PciDev->PciBar[Node->Bar].Length = Node->Length;
|
|
Node->PciDev->PciBar[Node->Bar].BarType = Node->ResType;
|
|
|
|
break;
|
|
|
|
case P2C_IO_2:
|
|
PciIoWrite (
|
|
PciIo,
|
|
EfiPciIoWidthUint32,
|
|
0x34,
|
|
1,
|
|
&Address
|
|
);
|
|
|
|
TempAddress = Address + Node->Length - 1;
|
|
PciIoWrite (
|
|
PciIo,
|
|
EfiPciIoWidthUint32,
|
|
0x38,
|
|
1,
|
|
&TempAddress
|
|
);
|
|
|
|
Node->PciDev->PciBar[Node->Bar].BaseAddress = Address;
|
|
Node->PciDev->PciBar[Node->Bar].Length = Node->Length;
|
|
Node->PciDev->PciBar[Node->Bar].BarType = Node->ResType;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
EFI_STATUS
|
|
ApplyResourcePadding (
|
|
PCI_IO_DEVICE *PciDev,
|
|
PCI_RESOURCE_NODE *IoNode,
|
|
PCI_RESOURCE_NODE *Mem32Node,
|
|
PCI_RESOURCE_NODE *PMem32Node,
|
|
PCI_RESOURCE_NODE *Mem64Node,
|
|
PCI_RESOURCE_NODE *PMem64Node
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Returns:
|
|
|
|
None
|
|
|
|
--*/
|
|
// TODO: PciDev - add argument and description to function comment
|
|
// TODO: IoNode - add argument and description to function comment
|
|
// TODO: Mem32Node - add argument and description to function comment
|
|
// TODO: PMem32Node - add argument and description to function comment
|
|
// TODO: Mem64Node - add argument and description to function comment
|
|
// TODO: PMem64Node - add argument and description to function comment
|
|
// TODO: EFI_SUCCESS - add return value to function comment
|
|
{
|
|
EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Ptr;
|
|
PCI_RESOURCE_NODE *Node;
|
|
UINT8 DummyBarIndex;
|
|
|
|
DummyBarIndex = 0;
|
|
Ptr = PciDev->ResourcePaddingDescriptors;
|
|
|
|
while (((EFI_ACPI_END_TAG_DESCRIPTOR *) Ptr)->Desc != ACPI_END_TAG_DESCRIPTOR) {
|
|
|
|
if (Ptr->Desc == ACPI_ADDRESS_SPACE_DESCRIPTOR && Ptr->ResType == ACPI_ADDRESS_SPACE_TYPE_IO) {
|
|
if (Ptr->AddrLen != 0) {
|
|
|
|
Node = CreateResourceNode (
|
|
PciDev,
|
|
Ptr->AddrLen,
|
|
Ptr->AddrRangeMax,
|
|
DummyBarIndex,
|
|
PciBarTypeIo16,
|
|
PciResUsagePadding
|
|
);
|
|
InsertResourceNode (
|
|
IoNode,
|
|
Node
|
|
);
|
|
}
|
|
|
|
Ptr++;
|
|
continue;
|
|
}
|
|
|
|
if (Ptr->Desc == ACPI_ADDRESS_SPACE_DESCRIPTOR && Ptr->ResType == ACPI_ADDRESS_SPACE_TYPE_MEM) {
|
|
|
|
if (Ptr->AddrSpaceGranularity == 32) {
|
|
|
|
//
|
|
// prefechable
|
|
//
|
|
if (Ptr->SpecificFlag == 0x6) {
|
|
if (Ptr->AddrLen) {
|
|
Node = CreateResourceNode (
|
|
PciDev,
|
|
Ptr->AddrLen,
|
|
Ptr->AddrRangeMax,
|
|
DummyBarIndex,
|
|
PciBarTypePMem32,
|
|
PciResUsagePadding
|
|
);
|
|
InsertResourceNode (
|
|
PMem32Node,
|
|
Node
|
|
);
|
|
}
|
|
|
|
Ptr++;
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Non-prefechable
|
|
//
|
|
if (Ptr->SpecificFlag == 0) {
|
|
if (Ptr->AddrLen) {
|
|
Node = CreateResourceNode (
|
|
PciDev,
|
|
Ptr->AddrLen,
|
|
Ptr->AddrRangeMax,
|
|
DummyBarIndex,
|
|
PciBarTypeMem32,
|
|
PciResUsagePadding
|
|
);
|
|
InsertResourceNode (
|
|
Mem32Node,
|
|
Node
|
|
);
|
|
}
|
|
|
|
Ptr++;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
if (Ptr->AddrSpaceGranularity == 64) {
|
|
|
|
//
|
|
// prefechable
|
|
//
|
|
if (Ptr->SpecificFlag == 0x6) {
|
|
if (Ptr->AddrLen) {
|
|
Node = CreateResourceNode (
|
|
PciDev,
|
|
Ptr->AddrLen,
|
|
Ptr->AddrRangeMax,
|
|
DummyBarIndex,
|
|
PciBarTypePMem64,
|
|
PciResUsagePadding
|
|
);
|
|
InsertResourceNode (
|
|
PMem64Node,
|
|
Node
|
|
);
|
|
}
|
|
|
|
Ptr++;
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Non-prefechable
|
|
//
|
|
if (Ptr->SpecificFlag == 0) {
|
|
if (Ptr->AddrLen) {
|
|
Node = CreateResourceNode (
|
|
PciDev,
|
|
Ptr->AddrLen,
|
|
Ptr->AddrRangeMax,
|
|
DummyBarIndex,
|
|
PciBarTypeMem64,
|
|
PciResUsagePadding
|
|
);
|
|
InsertResourceNode (
|
|
Mem64Node,
|
|
Node
|
|
);
|
|
}
|
|
|
|
Ptr++;
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
|
|
Ptr++;
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// Light PCI bus driver woundn't support hotplug root device
|
|
// So no need to pad resource for them
|
|
//
|
|
VOID
|
|
GetResourcePaddingPpb (
|
|
IN PCI_IO_DEVICE *PciIoDevice
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Get resource.
|
|
|
|
Arguments:
|
|
|
|
PciIoDevice A pointer to a pci device.
|
|
|
|
Returns:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
if (gPciHotPlugInit) {
|
|
if (PciIoDevice->ResourcePaddingDescriptors == NULL) {
|
|
GetResourcePaddingForHpb (PciIoDevice);
|
|
}
|
|
}
|
|
}
|