/*++ | |
Copyright (c) 2006, 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; | |
// | |
// Always assume there is ISA device and VGA device on the platform | |
// will be customized later | |
// | |
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. | |
// | |
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 | |
{ | |
EFI_STATUS Status; | |
PCI_RESOURCE_NODE *Node; | |
Status = 0; | |
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; | |
EFI_STATUS Status; | |
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 | |
// | |
Status = 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 ... | |
// | |
Status = 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: | |
PciIo->Pci.Write ( | |
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); | |
PciIo->Pci.Write ( | |
PciIo, | |
EfiPciIoWidthUint32, | |
(Node->PciDev->PciBar[Node->Bar]).Offset, | |
1, | |
&Address32 | |
); | |
Address32 = (UINT32) RShiftU64 (Address, 32); | |
PciIo->Pci.Write ( | |
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: | |
PciIo->Pci.Write ( | |
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; | |
PciIo->Pci.Write ( | |
PciIo, | |
EfiPciIoWidthUint8, | |
0x1C, | |
1, | |
&Address32 | |
); | |
Address32 >>= 8; | |
PciIo->Pci.Write ( | |
PciIo, | |
EfiPciIoWidthUint16, | |
0x30, | |
1, | |
&Address32 | |
); | |
Address32 = (UINT32) (Address + Node->Length - 1); | |
Address32 = ((UINT32) (Address32)) >> 8; | |
PciIo->Pci.Write ( | |
PciIo, | |
EfiPciIoWidthUint8, | |
0x1D, | |
1, | |
&Address32 | |
); | |
Address32 >>= 8; | |
PciIo->Pci.Write ( | |
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; | |
PciIo->Pci.Write ( | |
PciIo, | |
EfiPciIoWidthUint16, | |
0x20, | |
1, | |
&Address32 | |
); | |
Address32 = (UINT32) (Address + Node->Length - 1); | |
Address32 = ((UINT32) (Address32)) >> 16; | |
PciIo->Pci.Write ( | |
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; | |
PciIo->Pci.Write ( | |
PciIo, | |
EfiPciIoWidthUint16, | |
0x24, | |
1, | |
&Address32 | |
); | |
Address32 = (UINT32) (Address + Node->Length - 1); | |
Address32 = ((UINT32) (Address32)) >> 16; | |
PciIo->Pci.Write ( | |
PciIo, | |
EfiPciIoWidthUint16, | |
0x26, | |
1, | |
&Address32 | |
); | |
Address32 = (UINT32) RShiftU64 (Address, 32); | |
PciIo->Pci.Write ( | |
PciIo, | |
EfiPciIoWidthUint32, | |
0x28, | |
1, | |
&Address32 | |
); | |
Address32 = (UINT32) RShiftU64 ((Address + Node->Length - 1), 32); | |
PciIo->Pci.Write ( | |
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: | |
PciIo->Pci.Write ( | |
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: | |
PciIo->Pci.Write ( | |
PciIo, | |
EfiPciIoWidthUint32, | |
0x1c, | |
1, | |
&Address | |
); | |
TempAddress = Address + Node->Length - 1; | |
PciIo->Pci.Write ( | |
PciIo, | |
EfiPciIoWidthUint32, | |
0x20, | |
1, | |
&TempAddress | |
); | |
if (Node->ResType == PciBarTypeMem32) { | |
// | |
// Set non-prefetchable bit | |
// | |
PciIo->Pci.Read ( | |
PciIo, | |
EfiPciIoWidthUint16, | |
0x3e, | |
1, | |
&BridgeControl | |
); | |
BridgeControl &= 0xfeff; | |
PciIo->Pci.Write ( | |
PciIo, | |
EfiPciIoWidthUint16, | |
0x3e, | |
1, | |
&BridgeControl | |
); | |
} else { | |
// | |
// Set pre-fetchable bit | |
// | |
PciIo->Pci.Read ( | |
PciIo, | |
EfiPciIoWidthUint16, | |
0x3e, | |
1, | |
&BridgeControl | |
); | |
BridgeControl |= 0x0100; | |
PciIo->Pci.Write ( | |
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: | |
PciIo->Pci.Write ( | |
PciIo, | |
EfiPciIoWidthUint32, | |
0x24, | |
1, | |
&Address | |
); | |
TempAddress = Address + Node->Length - 1; | |
PciIo->Pci.Write ( | |
PciIo, | |
EfiPciIoWidthUint32, | |
0x28, | |
1, | |
&TempAddress | |
); | |
if (Node->ResType == PciBarTypeMem32) { | |
// | |
// Set non-prefetchable bit | |
// | |
PciIo->Pci.Read ( | |
PciIo, | |
EfiPciIoWidthUint16, | |
0x3e, | |
1, | |
&BridgeControl | |
); | |
BridgeControl &= 0xfdff; | |
PciIo->Pci.Write ( | |
PciIo, | |
EfiPciIoWidthUint16, | |
0x3e, | |
1, | |
&BridgeControl | |
); | |
} else { | |
// | |
// Set pre-fetchable bit | |
// | |
PciIo->Pci.Read ( | |
PciIo, | |
EfiPciIoWidthUint16, | |
0x3e, | |
1, | |
&BridgeControl | |
); | |
BridgeControl |= 0x0200; | |
PciIo->Pci.Write ( | |
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: | |
PciIo->Pci.Write ( | |
PciIo, | |
EfiPciIoWidthUint32, | |
0x2c, | |
1, | |
&Address | |
); | |
TempAddress = Address + Node->Length - 1; | |
PciIo->Pci.Write ( | |
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: | |
PciIo->Pci.Write ( | |
PciIo, | |
EfiPciIoWidthUint32, | |
0x34, | |
1, | |
&Address | |
); | |
TempAddress = Address + Node->Length - 1; | |
PciIo->Pci.Write ( | |
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); | |
} | |
} | |
} |