| /** @file | |
| PCI resources support functions implementation for PCI Bus module. | |
| Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR> | |
| SPDX-License-Identifier: BSD-2-Clause-Patent | |
| **/ | |
| #include "PciBus.h" | |
| // | |
| // The default policy for the PCI bus driver is NOT to reserve I/O ranges for both ISA aliases and VGA aliases. | |
| // | |
| BOOLEAN mReserveIsaAliases = FALSE; | |
| BOOLEAN mReserveVgaAliases = FALSE; | |
| BOOLEAN mPolicyDetermined = FALSE; | |
| /** | |
| The function is used to skip VGA range. | |
| @param Start Returned start address including VGA range. | |
| @param Length The length of VGA range. | |
| **/ | |
| VOID | |
| SkipVGAAperture ( | |
| OUT UINT64 *Start, | |
| IN UINT64 Length | |
| ) | |
| { | |
| UINT64 Original; | |
| UINT64 Mask; | |
| UINT64 StartOffset; | |
| UINT64 LimitOffset; | |
| ASSERT (Start != NULL); | |
| // | |
| // 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; | |
| } | |
| } | |
| /** | |
| This function is used to skip ISA aliasing aperture. | |
| @param Start Returned start address including ISA aliasing aperture. | |
| @param Length The length of ISA aliasing aperture. | |
| **/ | |
| VOID | |
| SkipIsaAliasAperture ( | |
| OUT UINT64 *Start, | |
| IN UINT64 Length | |
| ) | |
| { | |
| UINT64 Original; | |
| UINT64 Mask; | |
| UINT64 StartOffset; | |
| UINT64 LimitOffset; | |
| ASSERT (Start != NULL); | |
| // | |
| // 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; | |
| } | |
| } | |
| /** | |
| This function inserts a resource node into the resource list. | |
| The resource list is sorted in descend order. | |
| @param Bridge PCI resource node for bridge. | |
| @param ResNode Resource node want to be inserted. | |
| **/ | |
| VOID | |
| InsertResourceNode ( | |
| IN OUT PCI_RESOURCE_NODE *Bridge, | |
| IN PCI_RESOURCE_NODE *ResNode | |
| ) | |
| { | |
| LIST_ENTRY *CurrentLink; | |
| PCI_RESOURCE_NODE *Temp; | |
| UINT64 ResNodeAlignRest; | |
| UINT64 TempAlignRest; | |
| ASSERT (Bridge != NULL); | |
| ASSERT (ResNode != NULL); | |
| 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; | |
| } | |
| } | |
| /** | |
| This routine is used to merge two different resource trees in need of | |
| resource degradation. | |
| For example, if an upstream PPB doesn't support, | |
| prefetchable memory decoding, the PCI bus driver will choose to call this function | |
| to merge prefetchable memory resource list into normal memory list. | |
| If the TypeMerge is TRUE, Res resource type is changed to the type of destination resource | |
| type. | |
| If Dst is NULL or Res is NULL, ASSERT (). | |
| @param Dst Point to destination resource tree. | |
| @param Res Point to source resource tree. | |
| @param TypeMerge If the TypeMerge is TRUE, Res resource type is changed to the type of | |
| destination resource type. | |
| **/ | |
| VOID | |
| MergeResourceTree ( | |
| IN PCI_RESOURCE_NODE *Dst, | |
| IN PCI_RESOURCE_NODE *Res, | |
| IN BOOLEAN TypeMerge | |
| ) | |
| { | |
| LIST_ENTRY *CurrentLink; | |
| PCI_RESOURCE_NODE *Temp; | |
| ASSERT (Dst != NULL); | |
| ASSERT (Res != NULL); | |
| 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); | |
| } | |
| } | |
| /** | |
| This function is used to calculate the IO16 aperture | |
| for a bridge. | |
| @param Bridge PCI resource node for bridge. | |
| **/ | |
| VOID | |
| CalculateApertureIo16 ( | |
| IN PCI_RESOURCE_NODE *Bridge | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| UINT64 Aperture; | |
| LIST_ENTRY *CurrentLink; | |
| PCI_RESOURCE_NODE *Node; | |
| UINT64 Offset; | |
| EFI_PCI_PLATFORM_POLICY PciPolicy; | |
| UINT64 PaddingAperture; | |
| if (!mPolicyDetermined) { | |
| // | |
| // Check PciPlatform policy | |
| // | |
| Status = EFI_NOT_FOUND; | |
| PciPolicy = 0; | |
| if (gPciPlatformProtocol != NULL) { | |
| Status = gPciPlatformProtocol->GetPlatformPolicy ( | |
| gPciPlatformProtocol, | |
| &PciPolicy | |
| ); | |
| } | |
| if (EFI_ERROR (Status) && (gPciOverrideProtocol != NULL)) { | |
| Status = gPciOverrideProtocol->GetPlatformPolicy ( | |
| gPciOverrideProtocol, | |
| &PciPolicy | |
| ); | |
| } | |
| if (!EFI_ERROR (Status)) { | |
| if ((PciPolicy & EFI_RESERVE_ISA_IO_ALIAS) != 0) { | |
| mReserveIsaAliases = TRUE; | |
| } | |
| if ((PciPolicy & EFI_RESERVE_VGA_IO_ALIAS) != 0) { | |
| mReserveVgaAliases = TRUE; | |
| } | |
| } | |
| mPolicyDetermined = TRUE; | |
| } | |
| Aperture = 0; | |
| PaddingAperture = 0; | |
| if (Bridge == NULL) { | |
| return; | |
| } | |
| // | |
| // Assume the bridge is aligned | |
| // | |
| for ( CurrentLink = GetFirstNode (&Bridge->ChildList) | |
| ; !IsNull (&Bridge->ChildList, CurrentLink) | |
| ; CurrentLink = GetNextNode (&Bridge->ChildList, CurrentLink) | |
| ) | |
| { | |
| Node = RESOURCE_NODE_FROM_LINK (CurrentLink); | |
| if (Node->ResourceUsage == PciResUsagePadding) { | |
| ASSERT (PaddingAperture == 0); | |
| PaddingAperture = Node->Length; | |
| continue; | |
| } | |
| // | |
| // Consider the aperture alignment | |
| // | |
| Offset = Aperture & (Node->Alignment); | |
| if (Offset != 0) { | |
| 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 (mReserveIsaAliases || mReserveVgaAliases) { | |
| 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 (mReserveIsaAliases) { | |
| SkipIsaAliasAperture ( | |
| &Aperture, | |
| Node->Length | |
| ); | |
| Offset = Aperture & (Node->Alignment); | |
| if (Offset != 0) { | |
| Aperture = Aperture + (Node->Alignment + 1) - Offset; | |
| } | |
| } else if (mReserveVgaAliases) { | |
| SkipVGAAperture ( | |
| &Aperture, | |
| Node->Length | |
| ); | |
| Offset = Aperture & (Node->Alignment); | |
| if (Offset != 0) { | |
| Aperture = Aperture + (Node->Alignment + 1) - Offset; | |
| } | |
| } | |
| } | |
| } | |
| Node->Offset = Aperture; | |
| // | |
| // Increment aperture by the length of node | |
| // | |
| Aperture += Node->Length; | |
| } | |
| // | |
| // Adjust the aperture with the bridge's alignment | |
| // | |
| Offset = Aperture & (Bridge->Alignment); | |
| if (Offset != 0) { | |
| 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; | |
| } | |
| } | |
| // | |
| // Hotplug controller needs padding resources. | |
| // Use the larger one between the padding resource and actual occupied resource. | |
| // | |
| Bridge->Length = MAX (Bridge->Length, PaddingAperture); | |
| } | |
| /** | |
| This function is used to calculate the resource aperture | |
| for a given bridge device. | |
| @param Bridge PCI resource node for given bridge device. | |
| **/ | |
| VOID | |
| CalculateResourceAperture ( | |
| IN PCI_RESOURCE_NODE *Bridge | |
| ) | |
| { | |
| UINT64 Aperture[2]; | |
| LIST_ENTRY *CurrentLink; | |
| PCI_RESOURCE_NODE *Node; | |
| if (Bridge == NULL) { | |
| return; | |
| } | |
| if (Bridge->ResType == PciBarTypeIo16) { | |
| CalculateApertureIo16 (Bridge); | |
| return; | |
| } | |
| Aperture[PciResUsageTypical] = 0; | |
| Aperture[PciResUsagePadding] = 0; | |
| // | |
| // Assume the bridge is aligned | |
| // | |
| for ( CurrentLink = GetFirstNode (&Bridge->ChildList) | |
| ; !IsNull (&Bridge->ChildList, CurrentLink) | |
| ; CurrentLink = GetNextNode (&Bridge->ChildList, CurrentLink) | |
| ) | |
| { | |
| Node = RESOURCE_NODE_FROM_LINK (CurrentLink); | |
| // | |
| // It's possible for a bridge to contain multiple padding resource | |
| // nodes due to DegradeResource(). | |
| // | |
| ASSERT ( | |
| (Node->ResourceUsage == PciResUsageTypical) || | |
| (Node->ResourceUsage == PciResUsagePadding) | |
| ); | |
| ASSERT (Node->ResourceUsage < ARRAY_SIZE (Aperture)); | |
| // | |
| // Recode current aperture as a offset | |
| // Apply padding resource to meet alignment requirement | |
| // Node offset will be used in future real allocation | |
| // | |
| Node->Offset = ALIGN_VALUE (Aperture[Node->ResourceUsage], Node->Alignment + 1); | |
| // | |
| // Record the total aperture. | |
| // | |
| Aperture[Node->ResourceUsage] = Node->Offset + Node->Length; | |
| } | |
| // | |
| // Adjust the aperture with the bridge's alignment | |
| // | |
| Aperture[PciResUsageTypical] = ALIGN_VALUE (Aperture[PciResUsageTypical], Bridge->Alignment + 1); | |
| Aperture[PciResUsagePadding] = ALIGN_VALUE (Aperture[PciResUsagePadding], Bridge->Alignment + 1); | |
| // | |
| // Hotplug controller needs padding resources. | |
| // Use the larger one between the padding resource and actual occupied resource. | |
| // | |
| Bridge->Length = MAX (Aperture[PciResUsageTypical], Aperture[PciResUsagePadding]); | |
| // | |
| // Adjust the bridge's alignment to the MAX (first) alignment of all children. | |
| // | |
| CurrentLink = Bridge->ChildList.ForwardLink; | |
| if (CurrentLink != &Bridge->ChildList) { | |
| Node = RESOURCE_NODE_FROM_LINK (CurrentLink); | |
| if (Node->Alignment > Bridge->Alignment) { | |
| Bridge->Alignment = Node->Alignment; | |
| } | |
| } | |
| } | |
| /** | |
| Get IO/Memory resource info for given PCI device. | |
| @param PciDev Pci device instance. | |
| @param IoNode Resource info node for IO . | |
| @param Mem32Node Resource info node for 32-bit memory. | |
| @param PMem32Node Resource info node for 32-bit Prefetchable Memory. | |
| @param Mem64Node Resource info node for 64-bit memory. | |
| @param PMem64Node Resource info node for 64-bit Prefetchable Memory. | |
| **/ | |
| VOID | |
| GetResourceFromDevice ( | |
| IN PCI_IO_DEVICE *PciDev, | |
| IN OUT PCI_RESOURCE_NODE *IoNode, | |
| IN OUT PCI_RESOURCE_NODE *Mem32Node, | |
| IN OUT PCI_RESOURCE_NODE *PMem32Node, | |
| IN OUT PCI_RESOURCE_NODE *Mem64Node, | |
| IN OUT PCI_RESOURCE_NODE *PMem64Node | |
| ) | |
| { | |
| 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: | |
| case PciBarTypeOpRom: | |
| Node = CreateResourceNode ( | |
| PciDev, | |
| (PciDev->PciBar)[Index].Length, | |
| (PciDev->PciBar)[Index].Alignment, | |
| Index, | |
| (PciDev->PciBar)[Index].BarType, | |
| 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; | |
| } | |
| } | |
| // | |
| // Add VF resource | |
| // | |
| for (Index = 0; Index < PCI_MAX_BAR; Index++) { | |
| switch ((PciDev->VfPciBar)[Index].BarType) { | |
| case PciBarTypeMem32: | |
| Node = CreateVfResourceNode ( | |
| PciDev, | |
| (PciDev->VfPciBar)[Index].Length, | |
| (PciDev->VfPciBar)[Index].Alignment, | |
| Index, | |
| PciBarTypeMem32, | |
| PciResUsageTypical | |
| ); | |
| InsertResourceNode ( | |
| Mem32Node, | |
| Node | |
| ); | |
| break; | |
| case PciBarTypeMem64: | |
| Node = CreateVfResourceNode ( | |
| PciDev, | |
| (PciDev->VfPciBar)[Index].Length, | |
| (PciDev->VfPciBar)[Index].Alignment, | |
| Index, | |
| PciBarTypeMem64, | |
| PciResUsageTypical | |
| ); | |
| InsertResourceNode ( | |
| Mem64Node, | |
| Node | |
| ); | |
| break; | |
| case PciBarTypePMem64: | |
| Node = CreateVfResourceNode ( | |
| PciDev, | |
| (PciDev->VfPciBar)[Index].Length, | |
| (PciDev->VfPciBar)[Index].Alignment, | |
| Index, | |
| PciBarTypePMem64, | |
| PciResUsageTypical | |
| ); | |
| InsertResourceNode ( | |
| PMem64Node, | |
| Node | |
| ); | |
| break; | |
| case PciBarTypePMem32: | |
| Node = CreateVfResourceNode ( | |
| PciDev, | |
| (PciDev->VfPciBar)[Index].Length, | |
| (PciDev->VfPciBar)[Index].Alignment, | |
| Index, | |
| PciBarTypePMem32, | |
| PciResUsageTypical | |
| ); | |
| InsertResourceNode ( | |
| PMem32Node, | |
| Node | |
| ); | |
| break; | |
| case PciBarTypeIo16: | |
| case PciBarTypeIo32: | |
| 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; | |
| } | |
| } | |
| /** | |
| This function is used to create a resource node. | |
| @param PciDev Pci device instance. | |
| @param Length Length of Io/Memory resource. | |
| @param Alignment Alignment of resource. | |
| @param Bar Bar index. | |
| @param ResType Type of resource: IO/Memory. | |
| @param ResUsage Resource usage. | |
| @return PCI resource node created for given PCI device. | |
| NULL means PCI resource node is not created. | |
| **/ | |
| 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 | |
| ) | |
| { | |
| PCI_RESOURCE_NODE *Node; | |
| Node = NULL; | |
| Node = AllocateZeroPool (sizeof (PCI_RESOURCE_NODE)); | |
| ASSERT (Node != NULL); | |
| if (Node == NULL) { | |
| return NULL; | |
| } | |
| 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; | |
| } | |
| /** | |
| This function is used to create a IOV VF resource node. | |
| @param PciDev Pci device instance. | |
| @param Length Length of Io/Memory resource. | |
| @param Alignment Alignment of resource. | |
| @param Bar Bar index. | |
| @param ResType Type of resource: IO/Memory. | |
| @param ResUsage Resource usage. | |
| @return PCI resource node created for given VF PCI device. | |
| NULL means PCI resource node is not created. | |
| **/ | |
| PCI_RESOURCE_NODE * | |
| CreateVfResourceNode ( | |
| IN PCI_IO_DEVICE *PciDev, | |
| IN UINT64 Length, | |
| IN UINT64 Alignment, | |
| IN UINT8 Bar, | |
| IN PCI_BAR_TYPE ResType, | |
| IN PCI_RESOURCE_USAGE ResUsage | |
| ) | |
| { | |
| PCI_RESOURCE_NODE *Node; | |
| Node = CreateResourceNode (PciDev, Length, Alignment, Bar, ResType, ResUsage); | |
| if (Node == NULL) { | |
| return Node; | |
| } | |
| Node->Virtual = TRUE; | |
| return Node; | |
| } | |
| /** | |
| This function is used to extract resource request from | |
| device node list. | |
| @param Bridge Pci device instance. | |
| @param IoNode Resource info node for IO. | |
| @param Mem32Node Resource info node for 32-bit memory. | |
| @param PMem32Node Resource info node for 32-bit Prefetchable Memory. | |
| @param Mem64Node Resource info node for 64-bit memory. | |
| @param PMem64Node Resource info node for 64-bit Prefetchable Memory. | |
| **/ | |
| VOID | |
| CreateResourceMap ( | |
| IN PCI_IO_DEVICE *Bridge, | |
| IN OUT PCI_RESOURCE_NODE *IoNode, | |
| IN OUT PCI_RESOURCE_NODE *Mem32Node, | |
| IN OUT PCI_RESOURCE_NODE *PMem32Node, | |
| IN OUT PCI_RESOURCE_NODE *Mem64Node, | |
| IN OUT PCI_RESOURCE_NODE *PMem64Node | |
| ) | |
| { | |
| 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 != NULL && 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 (smaller alignments may be supported). | |
| // | |
| IoBridge = CreateResourceNode ( | |
| Temp, | |
| 0, | |
| Temp->BridgeIoAlignment, | |
| PPB_IO_RANGE, | |
| PciBarTypeIo16, | |
| PciResUsageTypical | |
| ); | |
| 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 resource map on this bridge | |
| // | |
| CreateResourceMap ( | |
| Temp, | |
| IoBridge, | |
| Mem32Bridge, | |
| PMem32Bridge, | |
| Mem64Bridge, | |
| PMem64Bridge | |
| ); | |
| if (ResourceRequestExisted (IoBridge)) { | |
| InsertResourceNode ( | |
| IoNode, | |
| IoBridge | |
| ); | |
| } else { | |
| 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 { | |
| 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 { | |
| 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 { | |
| 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 { | |
| 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); | |
| } | |
| /** | |
| This function is used to do the resource padding for a specific platform. | |
| @param PciDev Pci device instance. | |
| @param IoNode Resource info node for IO. | |
| @param Mem32Node Resource info node for 32-bit memory. | |
| @param PMem32Node Resource info node for 32-bit Prefetchable Memory. | |
| @param Mem64Node Resource info node for 64-bit memory. | |
| @param PMem64Node Resource info node for 64-bit Prefetchable Memory. | |
| **/ | |
| VOID | |
| ResourcePaddingPolicy ( | |
| IN PCI_IO_DEVICE *PciDev, | |
| 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 | |
| ) | |
| { | |
| // | |
| // Create padding resource node | |
| // | |
| if (PciDev->ResourcePaddingDescriptors != NULL) { | |
| ApplyResourcePadding ( | |
| PciDev, | |
| IoNode, | |
| Mem32Node, | |
| PMem32Node, | |
| Mem64Node, | |
| PMem64Node | |
| ); | |
| } | |
| } | |
| /** | |
| 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. | |
| @param Bridge Pci device instance. | |
| @param Mem32Node Resource info node for 32-bit memory. | |
| @param PMem32Node Resource info node for 32-bit Prefetchable Memory. | |
| @param Mem64Node Resource info node for 64-bit memory. | |
| @param PMem64Node Resource info node for 64-bit Prefetchable Memory. | |
| **/ | |
| VOID | |
| 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 | |
| ) | |
| { | |
| PCI_IO_DEVICE *PciIoDevice; | |
| LIST_ENTRY *ChildDeviceLink; | |
| LIST_ENTRY *ChildNodeLink; | |
| LIST_ENTRY *NextChildNodeLink; | |
| PCI_RESOURCE_NODE *ResourceNode; | |
| if (FeaturePcdGet (PcdPciDegradeResourceForOptionRom)) { | |
| // | |
| // If any child device has both option ROM and 64-bit BAR, degrade its PMEM64/MEM64 | |
| // requests in case that if a legacy option ROM image can not access 64-bit resources. | |
| // | |
| ChildDeviceLink = Bridge->ChildList.ForwardLink; | |
| while (ChildDeviceLink != NULL && ChildDeviceLink != &Bridge->ChildList) { | |
| PciIoDevice = PCI_IO_DEVICE_FROM_LINK (ChildDeviceLink); | |
| if (PciIoDevice->RomSize != 0) { | |
| if (!IsListEmpty (&Mem64Node->ChildList)) { | |
| ChildNodeLink = Mem64Node->ChildList.ForwardLink; | |
| while (ChildNodeLink != &Mem64Node->ChildList) { | |
| ResourceNode = RESOURCE_NODE_FROM_LINK (ChildNodeLink); | |
| NextChildNodeLink = ChildNodeLink->ForwardLink; | |
| if ((ResourceNode->PciDev == PciIoDevice) && | |
| (ResourceNode->Virtual || !PciIoDevice->PciBar[ResourceNode->Bar].BarTypeFixed) | |
| ) | |
| { | |
| RemoveEntryList (ChildNodeLink); | |
| InsertResourceNode (Mem32Node, ResourceNode); | |
| } | |
| ChildNodeLink = NextChildNodeLink; | |
| } | |
| } | |
| if (!IsListEmpty (&PMem64Node->ChildList)) { | |
| ChildNodeLink = PMem64Node->ChildList.ForwardLink; | |
| while (ChildNodeLink != &PMem64Node->ChildList) { | |
| ResourceNode = RESOURCE_NODE_FROM_LINK (ChildNodeLink); | |
| NextChildNodeLink = ChildNodeLink->ForwardLink; | |
| if ((ResourceNode->PciDev == PciIoDevice) && | |
| (ResourceNode->Virtual || !PciIoDevice->PciBar[ResourceNode->Bar].BarTypeFixed) | |
| ) | |
| { | |
| RemoveEntryList (ChildNodeLink); | |
| InsertResourceNode (PMem32Node, ResourceNode); | |
| } | |
| ChildNodeLink = NextChildNodeLink; | |
| } | |
| } | |
| } | |
| ChildDeviceLink = ChildDeviceLink->ForwardLink; | |
| } | |
| } | |
| // | |
| // If firmware is in 32-bit mode, | |
| // then degrade PMEM64/MEM64 requests | |
| // | |
| if (sizeof (UINTN) <= 4) { | |
| MergeResourceTree ( | |
| Mem32Node, | |
| Mem64Node, | |
| TRUE | |
| ); | |
| MergeResourceTree ( | |
| PMem32Node, | |
| PMem64Node, | |
| TRUE | |
| ); | |
| } else { | |
| // | |
| // if the bridge does not support MEM64, degrade MEM64 to MEM32 | |
| // | |
| if (!BridgeSupportResourceDecode (Bridge, EFI_BRIDGE_MEM64_DECODE_SUPPORTED)) { | |
| MergeResourceTree ( | |
| Mem32Node, | |
| Mem64Node, | |
| TRUE | |
| ); | |
| } | |
| // | |
| // if the bridge does not support PMEM64, degrade PMEM64 to PMEM32 | |
| // | |
| if (!BridgeSupportResourceDecode (Bridge, EFI_BRIDGE_PMEM64_DECODE_SUPPORTED)) { | |
| MergeResourceTree ( | |
| PMem32Node, | |
| PMem64Node, | |
| TRUE | |
| ); | |
| } | |
| // | |
| // if both PMEM64 and PMEM32 requests from child devices, which can not be satisfied | |
| // by a P2P bridge simultaneously, keep PMEM64 and degrade PMEM32 to MEM32. | |
| // | |
| if (!IsListEmpty (&PMem64Node->ChildList) && (Bridge->Parent != NULL)) { | |
| MergeResourceTree ( | |
| Mem32Node, | |
| PMem32Node, | |
| TRUE | |
| ); | |
| } | |
| } | |
| // | |
| // If bridge doesn't support Pmem32 | |
| // degrade it to mem32 | |
| // | |
| if (!BridgeSupportResourceDecode (Bridge, EFI_BRIDGE_PMEM32_DECODE_SUPPORTED)) { | |
| MergeResourceTree ( | |
| Mem32Node, | |
| PMem32Node, | |
| TRUE | |
| ); | |
| } | |
| // | |
| // if root 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 | |
| ); | |
| // | |
| // No need to check if to degrade MEM64 after merge, because | |
| // if there are PMEM64 still here, 64-bit decode should be supported | |
| // by the root bride. | |
| // | |
| MergeResourceTree ( | |
| Mem64Node, | |
| PMem64Node, | |
| FALSE | |
| ); | |
| } | |
| } | |
| /** | |
| Test whether bridge device support decode resource. | |
| @param Bridge Bridge device instance. | |
| @param Decode Decode type according to resource type. | |
| @return TRUE The bridge device support decode resource. | |
| @return FALSE The bridge device don't support decode resource. | |
| **/ | |
| BOOLEAN | |
| BridgeSupportResourceDecode ( | |
| IN PCI_IO_DEVICE *Bridge, | |
| IN UINT32 Decode | |
| ) | |
| { | |
| if (((Bridge->Decodes) & Decode) != 0) { | |
| return TRUE; | |
| } | |
| return FALSE; | |
| } | |
| /** | |
| This function is used to program the resource allocated | |
| for each resource node under specified bridge. | |
| @param Base Base address of resource to be programmed. | |
| @param Bridge PCI resource node for the bridge device. | |
| @retval EFI_SUCCESS Successfully to program all resources | |
| on given PCI bridge device. | |
| @retval EFI_OUT_OF_RESOURCES Base is all one. | |
| **/ | |
| EFI_STATUS | |
| ProgramResource ( | |
| IN UINT64 Base, | |
| IN PCI_RESOURCE_NODE *Bridge | |
| ) | |
| { | |
| 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))) { | |
| // | |
| // Program the PCI Card Bus device | |
| // | |
| ProgramP2C (Base, Node); | |
| } else { | |
| // | |
| // Program the PCI device BAR | |
| // | |
| ProgramBar (Base, Node); | |
| } | |
| } else { | |
| // | |
| // Program the PCI devices under this bridge | |
| // | |
| Status = ProgramResource (Base + Node->Offset, Node); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| ProgramPpbApperture (Base, Node); | |
| } | |
| CurrentLink = CurrentLink->ForwardLink; | |
| } | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Program Bar register for PCI device. | |
| @param Base Base address for PCI device resource to be programmed. | |
| @param Node Point to resource node structure. | |
| **/ | |
| VOID | |
| ProgramBar ( | |
| IN UINT64 Base, | |
| IN PCI_RESOURCE_NODE *Node | |
| ) | |
| { | |
| EFI_PCI_IO_PROTOCOL *PciIo; | |
| UINT64 Address; | |
| UINT32 Address32; | |
| ASSERT (Node->Bar < PCI_MAX_BAR); | |
| // | |
| // Check VF BAR | |
| // | |
| if (Node->Virtual) { | |
| ProgramVfBar (Base, Node); | |
| return; | |
| } | |
| 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 | |
| ); | |
| // | |
| // Continue to the case PciBarTypeOpRom to set the BaseAddress. | |
| // PciBarTypeOpRom is a virtual BAR only in root bridge, to capture | |
| // the MEM32 resource requirement for Option ROM shadow. | |
| // | |
| case PciBarTypeOpRom: | |
| 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; | |
| } | |
| } | |
| /** | |
| Program IOV VF Bar register for PCI device. | |
| @param Base Base address for PCI device resource to be programmed. | |
| @param Node Point to resource node structure. | |
| **/ | |
| EFI_STATUS | |
| ProgramVfBar ( | |
| IN UINT64 Base, | |
| IN PCI_RESOURCE_NODE *Node | |
| ) | |
| { | |
| EFI_PCI_IO_PROTOCOL *PciIo; | |
| UINT64 Address; | |
| UINT32 Address32; | |
| ASSERT (Node->Bar < PCI_MAX_BAR); | |
| ASSERT (Node->Virtual); | |
| 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->VfPciBar[Node->Bar]).BarType) { | |
| case PciBarTypeMem32: | |
| case PciBarTypePMem32: | |
| PciIo->Pci.Write ( | |
| PciIo, | |
| EfiPciIoWidthUint32, | |
| (Node->PciDev->VfPciBar[Node->Bar]).Offset, | |
| 1, | |
| &Address | |
| ); | |
| Node->PciDev->VfPciBar[Node->Bar].BaseAddress = Address; | |
| break; | |
| case PciBarTypeMem64: | |
| case PciBarTypePMem64: | |
| Address32 = (UINT32)(Address & 0x00000000FFFFFFFF); | |
| PciIo->Pci.Write ( | |
| PciIo, | |
| EfiPciIoWidthUint32, | |
| (Node->PciDev->VfPciBar[Node->Bar]).Offset, | |
| 1, | |
| &Address32 | |
| ); | |
| Address32 = (UINT32)RShiftU64 (Address, 32); | |
| PciIo->Pci.Write ( | |
| PciIo, | |
| EfiPciIoWidthUint32, | |
| ((Node->PciDev->VfPciBar[Node->Bar]).Offset + 4), | |
| 1, | |
| &Address32 | |
| ); | |
| Node->PciDev->VfPciBar[Node->Bar].BaseAddress = Address; | |
| break; | |
| case PciBarTypeIo16: | |
| case PciBarTypeIo32: | |
| break; | |
| default: | |
| break; | |
| } | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Program PCI-PCI bridge aperture. | |
| @param Base Base address for resource. | |
| @param Node Point to resource node structure. | |
| **/ | |
| VOID | |
| ProgramPpbApperture ( | |
| IN UINT64 Base, | |
| IN PCI_RESOURCE_NODE *Node | |
| ) | |
| { | |
| EFI_PCI_IO_PROTOCOL *PciIo; | |
| UINT64 Address; | |
| UINT32 Address32; | |
| Address = 0; | |
| // | |
| // If no device resource of this PPB, return anyway | |
| // Aperture is set default in the initialization code | |
| // | |
| if ((Node->Length == 0) || (Node->ResourceUsage == PciResUsagePadding)) { | |
| // | |
| // For padding resource node, just ignore when programming | |
| // | |
| return; | |
| } | |
| 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: | |
| 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; | |
| Node->PciDev->PciBar[Node->Bar].Length = Node->Length; | |
| 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; | |
| Node->PciDev->PciBar[Node->Bar].Length = Node->Length; | |
| break; | |
| default: | |
| break; | |
| } | |
| 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; | |
| } | |
| } | |
| /** | |
| Program parent bridge for Option Rom. | |
| @param PciDevice Pci device instance. | |
| @param OptionRomBase Base address for Option Rom. | |
| @param Enable Enable or disable PCI memory. | |
| **/ | |
| VOID | |
| ProgramUpstreamBridgeForRom ( | |
| IN PCI_IO_DEVICE *PciDevice, | |
| IN UINT32 OptionRomBase, | |
| IN BOOLEAN Enable | |
| ) | |
| { | |
| PCI_IO_DEVICE *Parent; | |
| EFI_PCI_IO_PROTOCOL *PciIo; | |
| UINT16 Base; | |
| UINT16 Limit; | |
| // | |
| // For root bridge, just return. | |
| // | |
| Parent = PciDevice->Parent; | |
| while (Parent != NULL) { | |
| if (!IS_PCI_BRIDGE (&Parent->Pci)) { | |
| break; | |
| } | |
| PciIo = &Parent->PciIo; | |
| // | |
| // Program PPB to only open a single <= 16MB aperture | |
| // | |
| if (Enable) { | |
| // | |
| // Only cover MMIO for Option ROM. | |
| // | |
| Base = (UINT16)(OptionRomBase >> 16); | |
| Limit = (UINT16)((OptionRomBase + PciDevice->RomSize - 1) >> 16); | |
| PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, OFFSET_OF (PCI_TYPE01, Bridge.MemoryBase), 1, &Base); | |
| PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, OFFSET_OF (PCI_TYPE01, Bridge.MemoryLimit), 1, &Limit); | |
| PCI_ENABLE_COMMAND_REGISTER (Parent, EFI_PCI_COMMAND_MEMORY_SPACE); | |
| } else { | |
| // | |
| // Cover 32bit MMIO for devices below the bridge. | |
| // | |
| if (Parent->PciBar[PPB_MEM32_RANGE].Length == 0) { | |
| // | |
| // When devices under the bridge contains Option ROM and doesn't require 32bit MMIO. | |
| // | |
| Base = (UINT16)gAllOne; | |
| Limit = (UINT16)gAllZero; | |
| } else { | |
| Base = (UINT16)((UINT32)Parent->PciBar[PPB_MEM32_RANGE].BaseAddress >> 16); | |
| Limit = (UINT16)((UINT32)(Parent->PciBar[PPB_MEM32_RANGE].BaseAddress | |
| + Parent->PciBar[PPB_MEM32_RANGE].Length - 1) >> 16); | |
| } | |
| PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, OFFSET_OF (PCI_TYPE01, Bridge.MemoryBase), 1, &Base); | |
| PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, OFFSET_OF (PCI_TYPE01, Bridge.MemoryLimit), 1, &Limit); | |
| PCI_DISABLE_COMMAND_REGISTER (Parent, EFI_PCI_COMMAND_MEMORY_SPACE); | |
| } | |
| Parent = Parent->Parent; | |
| } | |
| } | |
| /** | |
| Test whether resource exists for a bridge. | |
| @param Bridge Point to resource node for a bridge. | |
| @retval TRUE There is resource on the given bridge. | |
| @retval FALSE There isn't resource on the given bridge. | |
| **/ | |
| BOOLEAN | |
| ResourceRequestExisted ( | |
| IN PCI_RESOURCE_NODE *Bridge | |
| ) | |
| { | |
| if (Bridge != NULL) { | |
| if (!IsListEmpty (&Bridge->ChildList) || (Bridge->Length != 0)) { | |
| return TRUE; | |
| } | |
| } | |
| return FALSE; | |
| } | |
| /** | |
| Initialize resource pool structure. | |
| @param ResourcePool Point to resource pool structure. This pool | |
| is reset to all zero when returned. | |
| @param ResourceType Type of resource. | |
| **/ | |
| VOID | |
| InitializeResourcePool ( | |
| IN OUT PCI_RESOURCE_NODE *ResourcePool, | |
| IN PCI_BAR_TYPE ResourceType | |
| ) | |
| { | |
| ZeroMem (ResourcePool, sizeof (PCI_RESOURCE_NODE)); | |
| ResourcePool->ResType = ResourceType; | |
| ResourcePool->Signature = PCI_RESOURCE_SIGNATURE; | |
| InitializeListHead (&ResourcePool->ChildList); | |
| } | |
| /** | |
| Destroy given resource tree. | |
| @param Bridge PCI resource root node of resource tree. | |
| **/ | |
| VOID | |
| DestroyResourceTree ( | |
| IN PCI_RESOURCE_NODE *Bridge | |
| ) | |
| { | |
| PCI_RESOURCE_NODE *Temp; | |
| LIST_ENTRY *CurrentLink; | |
| while (!IsListEmpty (&Bridge->ChildList)) { | |
| CurrentLink = Bridge->ChildList.ForwardLink; | |
| Temp = RESOURCE_NODE_FROM_LINK (CurrentLink); | |
| ASSERT (Temp); | |
| RemoveEntryList (CurrentLink); | |
| if (IS_PCI_BRIDGE (&(Temp->PciDev->Pci))) { | |
| DestroyResourceTree (Temp); | |
| } | |
| FreePool (Temp); | |
| } | |
| } | |
| /** | |
| Insert resource padding for P2C. | |
| @param PciDev Pci device instance. | |
| @param IoNode Resource info node for IO. | |
| @param Mem32Node Resource info node for 32-bit memory. | |
| @param PMem32Node Resource info node for 32-bit Prefetchable Memory. | |
| @param Mem64Node Resource info node for 64-bit memory. | |
| @param PMem64Node Resource info node for 64-bit Prefetchable Memory. | |
| **/ | |
| VOID | |
| ResourcePaddingForCardBusBridge ( | |
| IN PCI_IO_DEVICE *PciDev, | |
| 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 | |
| ) | |
| { | |
| PCI_RESOURCE_NODE *Node; | |
| Node = NULL; | |
| // | |
| // Memory Base/Limit Register 0 | |
| // Bar 1 decodes memory range 0 | |
| // | |
| Node = CreateResourceNode ( | |
| PciDev, | |
| 0x2000000, | |
| 0x1ffffff, | |
| 1, | |
| PciBarTypeMem32, | |
| PciResUsagePadding | |
| ); | |
| InsertResourceNode ( | |
| Mem32Node, | |
| Node | |
| ); | |
| // | |
| // Memory Base/Limit Register 1 | |
| // Bar 2 decodes memory range1 | |
| // | |
| Node = CreateResourceNode ( | |
| PciDev, | |
| 0x2000000, | |
| 0x1ffffff, | |
| 2, | |
| PciBarTypePMem32, | |
| PciResUsagePadding | |
| ); | |
| InsertResourceNode ( | |
| PMem32Node, | |
| Node | |
| ); | |
| // | |
| // Io Base/Limit | |
| // Bar 3 decodes io range 0 | |
| // | |
| Node = CreateResourceNode ( | |
| PciDev, | |
| 0x100, | |
| 0xff, | |
| 3, | |
| PciBarTypeIo16, | |
| PciResUsagePadding | |
| ); | |
| InsertResourceNode ( | |
| IoNode, | |
| Node | |
| ); | |
| // | |
| // Io Base/Limit | |
| // Bar 4 decodes io range 0 | |
| // | |
| Node = CreateResourceNode ( | |
| PciDev, | |
| 0x100, | |
| 0xff, | |
| 4, | |
| PciBarTypeIo16, | |
| PciResUsagePadding | |
| ); | |
| InsertResourceNode ( | |
| IoNode, | |
| Node | |
| ); | |
| } | |
| /** | |
| Program PCI Card device register for given resource node. | |
| @param Base Base address of PCI Card device to be programmed. | |
| @param Node Given resource node. | |
| **/ | |
| VOID | |
| ProgramP2C ( | |
| IN UINT64 Base, | |
| IN PCI_RESOURCE_NODE *Node | |
| ) | |
| { | |
| 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, | |
| PCI_CARD_MEMORY_BASE_0, | |
| 1, | |
| &Address | |
| ); | |
| TempAddress = Address + Node->Length - 1; | |
| PciIo->Pci.Write ( | |
| PciIo, | |
| EfiPciIoWidthUint32, | |
| PCI_CARD_MEMORY_LIMIT_0, | |
| 1, | |
| &TempAddress | |
| ); | |
| if (Node->ResType == PciBarTypeMem32) { | |
| // | |
| // Set non-prefetchable bit | |
| // | |
| PciIo->Pci.Read ( | |
| PciIo, | |
| EfiPciIoWidthUint16, | |
| PCI_CARD_BRIDGE_CONTROL, | |
| 1, | |
| &BridgeControl | |
| ); | |
| BridgeControl &= (UINT16) ~PCI_CARD_PREFETCHABLE_MEMORY_0_ENABLE; | |
| PciIo->Pci.Write ( | |
| PciIo, | |
| EfiPciIoWidthUint16, | |
| PCI_CARD_BRIDGE_CONTROL, | |
| 1, | |
| &BridgeControl | |
| ); | |
| } else { | |
| // | |
| // Set prefetchable bit | |
| // | |
| PciIo->Pci.Read ( | |
| PciIo, | |
| EfiPciIoWidthUint16, | |
| PCI_CARD_BRIDGE_CONTROL, | |
| 1, | |
| &BridgeControl | |
| ); | |
| BridgeControl |= PCI_CARD_PREFETCHABLE_MEMORY_0_ENABLE; | |
| PciIo->Pci.Write ( | |
| PciIo, | |
| EfiPciIoWidthUint16, | |
| PCI_CARD_BRIDGE_CONTROL, | |
| 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, | |
| PCI_CARD_MEMORY_BASE_1, | |
| 1, | |
| &Address | |
| ); | |
| TempAddress = Address + Node->Length - 1; | |
| PciIo->Pci.Write ( | |
| PciIo, | |
| EfiPciIoWidthUint32, | |
| PCI_CARD_MEMORY_LIMIT_1, | |
| 1, | |
| &TempAddress | |
| ); | |
| if (Node->ResType == PciBarTypeMem32) { | |
| // | |
| // Set non-prefetchable bit | |
| // | |
| PciIo->Pci.Read ( | |
| PciIo, | |
| EfiPciIoWidthUint16, | |
| PCI_CARD_BRIDGE_CONTROL, | |
| 1, | |
| &BridgeControl | |
| ); | |
| BridgeControl &= (UINT16) ~(PCI_CARD_PREFETCHABLE_MEMORY_1_ENABLE); | |
| PciIo->Pci.Write ( | |
| PciIo, | |
| EfiPciIoWidthUint16, | |
| PCI_CARD_BRIDGE_CONTROL, | |
| 1, | |
| &BridgeControl | |
| ); | |
| } else { | |
| // | |
| // Set prefetchable bit | |
| // | |
| PciIo->Pci.Read ( | |
| PciIo, | |
| EfiPciIoWidthUint16, | |
| PCI_CARD_BRIDGE_CONTROL, | |
| 1, | |
| &BridgeControl | |
| ); | |
| BridgeControl |= PCI_CARD_PREFETCHABLE_MEMORY_1_ENABLE; | |
| PciIo->Pci.Write ( | |
| PciIo, | |
| EfiPciIoWidthUint16, | |
| PCI_CARD_BRIDGE_CONTROL, | |
| 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, | |
| PCI_CARD_IO_BASE_0_LOWER, | |
| 1, | |
| &Address | |
| ); | |
| TempAddress = Address + Node->Length - 1; | |
| PciIo->Pci.Write ( | |
| PciIo, | |
| EfiPciIoWidthUint32, | |
| PCI_CARD_IO_LIMIT_0_LOWER, | |
| 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, | |
| PCI_CARD_IO_BASE_1_LOWER, | |
| 1, | |
| &Address | |
| ); | |
| TempAddress = Address + Node->Length - 1; | |
| PciIo->Pci.Write ( | |
| PciIo, | |
| EfiPciIoWidthUint32, | |
| PCI_CARD_IO_LIMIT_1_LOWER, | |
| 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; | |
| } | |
| } | |
| /** | |
| Create padding resource node. | |
| @param PciDev Pci device instance. | |
| @param IoNode Resource info node for IO. | |
| @param Mem32Node Resource info node for 32-bit memory. | |
| @param PMem32Node Resource info node for 32-bit Prefetchable Memory. | |
| @param Mem64Node Resource info node for 64-bit memory. | |
| @param PMem64Node Resource info node for 64-bit Prefetchable Memory. | |
| **/ | |
| VOID | |
| ApplyResourcePadding ( | |
| IN PCI_IO_DEVICE *PciDev, | |
| 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 | |
| ) | |
| { | |
| 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) { | |
| // | |
| // prefetchable | |
| // | |
| if (Ptr->SpecificFlag == 0x6) { | |
| if (Ptr->AddrLen != 0) { | |
| Node = CreateResourceNode ( | |
| PciDev, | |
| Ptr->AddrLen, | |
| Ptr->AddrRangeMax, | |
| DummyBarIndex, | |
| PciBarTypePMem32, | |
| PciResUsagePadding | |
| ); | |
| InsertResourceNode ( | |
| PMem32Node, | |
| Node | |
| ); | |
| } | |
| Ptr++; | |
| continue; | |
| } | |
| // | |
| // Non-prefetchable | |
| // | |
| if (Ptr->SpecificFlag == 0) { | |
| if (Ptr->AddrLen != 0) { | |
| Node = CreateResourceNode ( | |
| PciDev, | |
| Ptr->AddrLen, | |
| Ptr->AddrRangeMax, | |
| DummyBarIndex, | |
| PciBarTypeMem32, | |
| PciResUsagePadding | |
| ); | |
| InsertResourceNode ( | |
| Mem32Node, | |
| Node | |
| ); | |
| } | |
| Ptr++; | |
| continue; | |
| } | |
| } | |
| if (Ptr->AddrSpaceGranularity == 64) { | |
| // | |
| // prefetchable | |
| // | |
| if (Ptr->SpecificFlag == 0x6) { | |
| if (Ptr->AddrLen != 0) { | |
| Node = CreateResourceNode ( | |
| PciDev, | |
| Ptr->AddrLen, | |
| Ptr->AddrRangeMax, | |
| DummyBarIndex, | |
| PciBarTypePMem64, | |
| PciResUsagePadding | |
| ); | |
| InsertResourceNode ( | |
| PMem64Node, | |
| Node | |
| ); | |
| } | |
| Ptr++; | |
| continue; | |
| } | |
| // | |
| // Non-prefetchable | |
| // | |
| if (Ptr->SpecificFlag == 0) { | |
| if (Ptr->AddrLen != 0) { | |
| Node = CreateResourceNode ( | |
| PciDev, | |
| Ptr->AddrLen, | |
| Ptr->AddrRangeMax, | |
| DummyBarIndex, | |
| PciBarTypeMem64, | |
| PciResUsagePadding | |
| ); | |
| InsertResourceNode ( | |
| Mem64Node, | |
| Node | |
| ); | |
| } | |
| Ptr++; | |
| continue; | |
| } | |
| } | |
| } | |
| Ptr++; | |
| } | |
| } | |
| /** | |
| Get padding resource for PCI-PCI bridge. | |
| @param PciIoDevice PCI-PCI bridge device instance. | |
| @note Feature flag PcdPciBusHotplugDeviceSupport determines | |
| whether need to pad resource for them. | |
| **/ | |
| VOID | |
| GetResourcePaddingPpb ( | |
| IN PCI_IO_DEVICE *PciIoDevice | |
| ) | |
| { | |
| if ((gPciHotPlugInit != NULL) && FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) { | |
| if (PciIoDevice->ResourcePaddingDescriptors == NULL) { | |
| GetResourcePaddingForHpb (PciIoDevice); | |
| } | |
| } | |
| } |