/** @file\r
- PCI resouces support functions implemntation for PCI Bus module.\r
+ PCI resources support functions implementation for PCI Bus module.\r
\r
-Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>\r
-This program and the accompanying materials\r
-are licensed and made available under the terms and conditions of the BSD License\r
-which accompanies this distribution. The full text of the license may be found at\r
-http://opensource.org/licenses/bsd-license.php\r
-\r
-THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
-WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>\r
+SPDX-License-Identifier: BSD-2-Clause-Patent\r
\r
**/\r
\r
\r
/**\r
This routine is used to merge two different resource trees in need of\r
- resoure degradation.\r
+ resource degradation.\r
\r
For example, if an upstream PPB doesn't support,\r
prefetchable memory decoding, the PCI bus driver will choose to call this function\r
- to merge prefectchable memory resource list into normal memory list.\r
+ to merge prefetchable memory resource list into normal memory list.\r
\r
If the TypeMerge is TRUE, Res resource type is changed to the type of destination resource\r
type.\r
PCI_RESOURCE_NODE *Node;\r
UINT64 Offset;\r
EFI_PCI_PLATFORM_POLICY PciPolicy;\r
+ UINT64 PaddingAperture;\r
\r
if (!mPolicyDetermined) {\r
//\r
mPolicyDetermined = TRUE;\r
}\r
\r
- Aperture = 0;\r
+ Aperture = 0;\r
+ PaddingAperture = 0;\r
\r
if (Bridge == NULL) {\r
return ;\r
}\r
\r
- CurrentLink = Bridge->ChildList.ForwardLink;\r
-\r
//\r
// Assume the bridge is aligned\r
//\r
- while (CurrentLink != &Bridge->ChildList) {\r
+ for ( CurrentLink = GetFirstNode (&Bridge->ChildList)\r
+ ; !IsNull (&Bridge->ChildList, CurrentLink)\r
+ ; CurrentLink = GetNextNode (&Bridge->ChildList, CurrentLink)\r
+ ) {\r
\r
Node = RESOURCE_NODE_FROM_LINK (CurrentLink);\r
-\r
+ if (Node->ResourceUsage == PciResUsagePadding) {\r
+ ASSERT (PaddingAperture == 0);\r
+ PaddingAperture = Node->Length;\r
+ continue;\r
+ }\r
//\r
// Consider the aperture alignment\r
//\r
// Increment aperture by the length of node\r
//\r
Aperture += Node->Length;\r
-\r
- CurrentLink = CurrentLink->ForwardLink;\r
}\r
\r
//\r
- // At last, adjust the aperture with the bridge's\r
- // alignment\r
+ // Adjust the aperture with the bridge's alignment\r
//\r
Offset = Aperture & (Bridge->Alignment);\r
\r
Bridge->Alignment = Node->Alignment;\r
}\r
}\r
+\r
+ //\r
+ // Hotplug controller needs padding resources.\r
+ // Use the larger one between the padding resource and actual occupied resource.\r
+ //\r
+ Bridge->Length = MAX (Bridge->Length, PaddingAperture);\r
}\r
\r
/**\r
This function is used to calculate the resource aperture\r
for a given bridge device.\r
\r
- @param Bridge PCI resouce node for given bridge device.\r
+ @param Bridge PCI resource node for given bridge device.\r
\r
**/\r
VOID\r
IN PCI_RESOURCE_NODE *Bridge\r
)\r
{\r
- UINT64 Aperture;\r
+ UINT64 Aperture[2];\r
LIST_ENTRY *CurrentLink;\r
PCI_RESOURCE_NODE *Node;\r
\r
- UINT64 Offset;\r
-\r
- Aperture = 0;\r
-\r
if (Bridge == NULL) {\r
return ;\r
}\r
return ;\r
}\r
\r
- CurrentLink = Bridge->ChildList.ForwardLink;\r
-\r
+ Aperture[PciResUsageTypical] = 0;\r
+ Aperture[PciResUsagePadding] = 0;\r
//\r
// Assume the bridge is aligned\r
//\r
- while (CurrentLink != &Bridge->ChildList) {\r
-\r
+ for ( CurrentLink = GetFirstNode (&Bridge->ChildList)\r
+ ; !IsNull (&Bridge->ChildList, CurrentLink)\r
+ ; CurrentLink = GetNextNode (&Bridge->ChildList, CurrentLink)\r
+ ) {\r
Node = RESOURCE_NODE_FROM_LINK (CurrentLink);\r
\r
//\r
- // Apply padding resource if available\r
+ // It's possible for a bridge to contain multiple padding resource\r
+ // nodes due to DegradeResource().\r
//\r
- Offset = Aperture & (Node->Alignment);\r
-\r
- if (Offset != 0) {\r
-\r
- Aperture = Aperture + (Node->Alignment + 1) - Offset;\r
-\r
- }\r
-\r
+ ASSERT ((Node->ResourceUsage == PciResUsageTypical) ||\r
+ (Node->ResourceUsage == PciResUsagePadding));\r
+ ASSERT (Node->ResourceUsage < ARRAY_SIZE (Aperture));\r
//\r
// Recode current aperture as a offset\r
- // this offset will be used in future real allocation\r
- //\r
- Node->Offset = Aperture;\r
-\r
- //\r
- // Increment aperture by the length of node\r
+ // Apply padding resource to meet alignment requirement\r
+ // Node offset will be used in future real allocation\r
//\r
- Aperture += Node->Length;\r
+ Node->Offset = ALIGN_VALUE (Aperture[Node->ResourceUsage], Node->Alignment + 1);\r
\r
//\r
- // Consider the aperture alignment\r
+ // Record the total aperture.\r
//\r
- CurrentLink = CurrentLink->ForwardLink;\r
+ Aperture[Node->ResourceUsage] = Node->Offset + Node->Length;\r
}\r
\r
//\r
- // At last, adjust the aperture with the bridge's\r
- // alignment\r
+ // Adjust the aperture with the bridge's alignment\r
//\r
- Offset = Aperture & (Bridge->Alignment);\r
- if (Offset != 0) {\r
- Aperture = Aperture + (Bridge->Alignment + 1) - Offset;\r
- }\r
+ Aperture[PciResUsageTypical] = ALIGN_VALUE (Aperture[PciResUsageTypical], Bridge->Alignment + 1);\r
+ Aperture[PciResUsagePadding] = ALIGN_VALUE (Aperture[PciResUsagePadding], Bridge->Alignment + 1);\r
\r
//\r
- // If the bridge has already padded the resource and the\r
- // amount of padded resource is larger, then keep the\r
- // padded resource\r
+ // Hotplug controller needs padding resources.\r
+ // Use the larger one between the padding resource and actual occupied resource.\r
//\r
- if (Bridge->Length < Aperture) {\r
- Bridge->Length = Aperture;\r
- }\r
+ Bridge->Length = MAX (Aperture[PciResUsageTypical], Aperture[PciResUsagePadding]);\r
\r
//\r
- // At last, adjust the bridge's alignment to the first child's alignment\r
- // if the bridge has at least one child\r
+ // Adjust the bridge's alignment to the MAX (first) alignment of all children.\r
//\r
CurrentLink = Bridge->ChildList.ForwardLink;\r
if (CurrentLink != &Bridge->ChildList) {\r
}\r
\r
/**\r
- Get IO/Memory resource infor for given PCI device.\r
+ Get IO/Memory resource info for given PCI device.\r
\r
@param PciDev Pci device instance.\r
@param IoNode Resource info node for IO .\r
switch ((PciDev->PciBar)[Index].BarType) {\r
\r
case PciBarTypeMem32:\r
+ case PciBarTypeOpRom:\r
\r
Node = CreateResourceNode (\r
PciDev,\r
(PciDev->PciBar)[Index].Length,\r
(PciDev->PciBar)[Index].Alignment,\r
Index,\r
- PciBarTypeMem32,\r
+ (PciDev->PciBar)[Index].BarType,\r
PciResUsageTypical\r
);\r
\r
);\r
\r
//\r
- // Recursively create resouce map on this bridge\r
+ // Recursively create resource map on this bridge\r
//\r
CreateResourceMap (\r
Temp,\r
IN PCI_RESOURCE_NODE *PMem64Node\r
)\r
{\r
- PCI_IO_DEVICE *Temp;\r
+ PCI_IO_DEVICE *PciIoDevice;\r
LIST_ENTRY *ChildDeviceLink;\r
LIST_ENTRY *ChildNodeLink;\r
LIST_ENTRY *NextChildNodeLink;\r
- PCI_RESOURCE_NODE *TempNode;\r
+ PCI_RESOURCE_NODE *ResourceNode;\r
\r
- //\r
- // If any child device has both option ROM and 64-bit BAR, degrade its PMEM64/MEM64\r
- // requests in case that if a legacy option ROM image can not access 64-bit resources.\r
- //\r
- ChildDeviceLink = Bridge->ChildList.ForwardLink;\r
- while (ChildDeviceLink != NULL && ChildDeviceLink != &Bridge->ChildList) {\r
- Temp = PCI_IO_DEVICE_FROM_LINK (ChildDeviceLink);\r
- if (Temp->RomSize != 0) {\r
- if (!IsListEmpty (&Mem64Node->ChildList)) { \r
- ChildNodeLink = Mem64Node->ChildList.ForwardLink;\r
- while (ChildNodeLink != &Mem64Node->ChildList) {\r
- TempNode = RESOURCE_NODE_FROM_LINK (ChildNodeLink);\r
- NextChildNodeLink = ChildNodeLink->ForwardLink;\r
-\r
- if (TempNode->PciDev == Temp) {\r
- RemoveEntryList (ChildNodeLink);\r
- InsertResourceNode (Mem32Node, TempNode);\r
+ if (FeaturePcdGet (PcdPciDegradeResourceForOptionRom)) {\r
+ //\r
+ // If any child device has both option ROM and 64-bit BAR, degrade its PMEM64/MEM64\r
+ // requests in case that if a legacy option ROM image can not access 64-bit resources.\r
+ //\r
+ ChildDeviceLink = Bridge->ChildList.ForwardLink;\r
+ while (ChildDeviceLink != NULL && ChildDeviceLink != &Bridge->ChildList) {\r
+ PciIoDevice = PCI_IO_DEVICE_FROM_LINK (ChildDeviceLink);\r
+ if (PciIoDevice->RomSize != 0) {\r
+ if (!IsListEmpty (&Mem64Node->ChildList)) {\r
+ ChildNodeLink = Mem64Node->ChildList.ForwardLink;\r
+ while (ChildNodeLink != &Mem64Node->ChildList) {\r
+ ResourceNode = RESOURCE_NODE_FROM_LINK (ChildNodeLink);\r
+ NextChildNodeLink = ChildNodeLink->ForwardLink;\r
+\r
+ if ((ResourceNode->PciDev == PciIoDevice) &&\r
+ (ResourceNode->Virtual || !PciIoDevice->PciBar[ResourceNode->Bar].BarTypeFixed)\r
+ ) {\r
+ RemoveEntryList (ChildNodeLink);\r
+ InsertResourceNode (Mem32Node, ResourceNode);\r
+ }\r
+ ChildNodeLink = NextChildNodeLink;\r
}\r
- ChildNodeLink = NextChildNodeLink;\r
- } \r
- }\r
-\r
- if (!IsListEmpty (&PMem64Node->ChildList)) { \r
- ChildNodeLink = PMem64Node->ChildList.ForwardLink;\r
- while (ChildNodeLink != &PMem64Node->ChildList) {\r
- TempNode = RESOURCE_NODE_FROM_LINK (ChildNodeLink);\r
- NextChildNodeLink = ChildNodeLink->ForwardLink;\r
+ }\r
\r
- if (TempNode->PciDev == Temp) {\r
- RemoveEntryList (ChildNodeLink);\r
- InsertResourceNode (PMem32Node, TempNode);\r
+ if (!IsListEmpty (&PMem64Node->ChildList)) {\r
+ ChildNodeLink = PMem64Node->ChildList.ForwardLink;\r
+ while (ChildNodeLink != &PMem64Node->ChildList) {\r
+ ResourceNode = RESOURCE_NODE_FROM_LINK (ChildNodeLink);\r
+ NextChildNodeLink = ChildNodeLink->ForwardLink;\r
+\r
+ if ((ResourceNode->PciDev == PciIoDevice) &&\r
+ (ResourceNode->Virtual || !PciIoDevice->PciBar[ResourceNode->Bar].BarTypeFixed)\r
+ ) {\r
+ RemoveEntryList (ChildNodeLink);\r
+ InsertResourceNode (PMem32Node, ResourceNode);\r
+ }\r
+ ChildNodeLink = NextChildNodeLink;\r
}\r
- ChildNodeLink = NextChildNodeLink;\r
- } \r
- }\r
+ }\r
\r
+ }\r
+ ChildDeviceLink = ChildDeviceLink->ForwardLink;\r
}\r
- ChildDeviceLink = ChildDeviceLink->ForwardLink;\r
}\r
\r
//\r
PMem64Node,\r
TRUE\r
);\r
- } \r
+ }\r
\r
//\r
// if both PMEM64 and PMEM32 requests from child devices, which can not be satisfied\r
This function is used to program the resource allocated\r
for each resource node under specified bridge.\r
\r
- @param Base Base address of resource to be progammed.\r
+ @param Base Base address of resource to be programmed.\r
@param Bridge PCI resource node for the bridge device.\r
\r
- @retval EFI_SUCCESS Successfully to program all resouces\r
+ @retval EFI_SUCCESS Successfully to program all resources\r
on given PCI bridge device.\r
@retval EFI_OUT_OF_RESOURCES Base is all one.\r
\r
/**\r
Program Bar register for PCI device.\r
\r
- @param Base Base address for PCI device resource to be progammed.\r
- @param Node Point to resoure node structure.\r
+ @param Base Base address for PCI device resource to be programmed.\r
+ @param Node Point to resource node structure.\r
\r
**/\r
VOID\r
1,\r
&Address\r
);\r
+ //\r
+ // Continue to the case PciBarTypeOpRom to set the BaseAddress.\r
+ // PciBarTypeOpRom is a virtual BAR only in root bridge, to capture\r
+ // the MEM32 resource requirement for Option ROM shadow.\r
+ //\r
\r
+ case PciBarTypeOpRom:\r
Node->PciDev->PciBar[Node->Bar].BaseAddress = Address;\r
\r
break;\r
/**\r
Program IOV VF Bar register for PCI device.\r
\r
- @param Base Base address for PCI device resource to be progammed.\r
- @param Node Point to resoure node structure.\r
+ @param Base Base address for PCI device resource to be programmed.\r
+ @param Node Point to resource node structure.\r
\r
**/\r
EFI_STATUS\r
}\r
\r
/**\r
- Program PCI-PCI bridge apperture.\r
+ Program PCI-PCI bridge aperture.\r
\r
@param Base Base address for resource.\r
- @param Node Point to resoure node structure.\r
+ @param Node Point to resource node structure.\r
\r
**/\r
VOID\r
Address = 0;\r
//\r
// If no device resource of this PPB, return anyway\r
- // Apperture is set default in the initialization code\r
+ // Aperture is set default in the initialization code\r
//\r
if (Node->Length == 0 || Node->ResourceUsage == PciResUsagePadding) {\r
//\r
\r
case PPB_BAR_0:\r
case PPB_BAR_1:\r
- PciIo->Pci.Write (\r
+ switch ((Node->PciDev->PciBar[Node->Bar]).BarType) {\r
+\r
+ case PciBarTypeIo16:\r
+ case PciBarTypeIo32:\r
+ case PciBarTypeMem32:\r
+ case PciBarTypePMem32:\r
+\r
+ PciIo->Pci.Write (\r
PciIo,\r
EfiPciIoWidthUint32,\r
(Node->PciDev->PciBar[Node->Bar]).Offset,\r
&Address\r
);\r
\r
- Node->PciDev->PciBar[Node->Bar].BaseAddress = Address;\r
- Node->PciDev->PciBar[Node->Bar].Length = Node->Length;\r
+ Node->PciDev->PciBar[Node->Bar].BaseAddress = Address;\r
+ Node->PciDev->PciBar[Node->Bar].Length = Node->Length;\r
+ break;\r
+\r
+ case PciBarTypeMem64:\r
+ case PciBarTypePMem64:\r
+\r
+ Address32 = (UINT32) (Address & 0x00000000FFFFFFFF);\r
+\r
+ PciIo->Pci.Write (\r
+ PciIo,\r
+ EfiPciIoWidthUint32,\r
+ (Node->PciDev->PciBar[Node->Bar]).Offset,\r
+ 1,\r
+ &Address32\r
+ );\r
\r
+ Address32 = (UINT32) RShiftU64 (Address, 32);\r
+\r
+ PciIo->Pci.Write (\r
+ PciIo,\r
+ EfiPciIoWidthUint32,\r
+ (UINT8) ((Node->PciDev->PciBar[Node->Bar]).Offset + 4),\r
+ 1,\r
+ &Address32\r
+ );\r
+\r
+ Node->PciDev->PciBar[Node->Bar].BaseAddress = Address;\r
+ Node->PciDev->PciBar[Node->Bar].Length = Node->Length;\r
+ break;\r
+\r
+ default:\r
+ break;\r
+ }\r
break;\r
\r
case PPB_IO_RANGE:\r
/**\r
Program parent bridge for Option Rom.\r
\r
- @param PciDevice Pci deivce instance.\r
- @param OptionRomBase Base address for Optiona Rom.\r
+ @param PciDevice Pci device instance.\r
+ @param OptionRomBase Base address for Option Rom.\r
@param Enable Enable or disable PCI memory.\r
\r
**/\r
VOID\r
-ProgrameUpstreamBridgeForRom (\r
+ProgramUpstreamBridgeForRom (\r
IN PCI_IO_DEVICE *PciDevice,\r
IN UINT32 OptionRomBase,\r
IN BOOLEAN Enable\r
)\r
{\r
- PCI_IO_DEVICE *Parent;\r
- PCI_RESOURCE_NODE Node;\r
+ PCI_IO_DEVICE *Parent;\r
+ EFI_PCI_IO_PROTOCOL *PciIo;\r
+ UINT16 Base;\r
+ UINT16 Limit;\r
//\r
// For root bridge, just return.\r
//\r
Parent = PciDevice->Parent;\r
- ZeroMem (&Node, sizeof (Node));\r
while (Parent != NULL) {\r
if (!IS_PCI_BRIDGE (&Parent->Pci)) {\r
break;\r
}\r
\r
- Node.PciDev = Parent;\r
- Node.Length = PciDevice->RomSize;\r
- Node.Alignment = 0;\r
- Node.Bar = PPB_MEM32_RANGE;\r
- Node.ResType = PciBarTypeMem32;\r
- Node.Offset = 0;\r
+ PciIo = &Parent->PciIo;\r
\r
//\r
- // Program PPB to only open a single <= 16MB apperture\r
+ // Program PPB to only open a single <= 16MB aperture\r
//\r
if (Enable) {\r
- ProgramPpbApperture (OptionRomBase, &Node);\r
+ //\r
+ // Only cover MMIO for Option ROM.\r
+ //\r
+ Base = (UINT16) (OptionRomBase >> 16);\r
+ Limit = (UINT16) ((OptionRomBase + PciDevice->RomSize - 1) >> 16);\r
+ PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, OFFSET_OF (PCI_TYPE01, Bridge.MemoryBase), 1, &Base);\r
+ PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, OFFSET_OF (PCI_TYPE01, Bridge.MemoryLimit), 1, &Limit);\r
+\r
PCI_ENABLE_COMMAND_REGISTER (Parent, EFI_PCI_COMMAND_MEMORY_SPACE);\r
} else {\r
- InitializePpb (Parent);\r
+ //\r
+ // Cover 32bit MMIO for devices below the bridge.\r
+ //\r
+ if (Parent->PciBar[PPB_MEM32_RANGE].Length == 0) {\r
+ //\r
+ // When devices under the bridge contains Option ROM and doesn't require 32bit MMIO.\r
+ //\r
+ Base = (UINT16) gAllOne;\r
+ Limit = (UINT16) gAllZero;\r
+ } else {\r
+ Base = (UINT16) ((UINT32) Parent->PciBar[PPB_MEM32_RANGE].BaseAddress >> 16);\r
+ Limit = (UINT16) ((UINT32) (Parent->PciBar[PPB_MEM32_RANGE].BaseAddress\r
+ + Parent->PciBar[PPB_MEM32_RANGE].Length - 1) >> 16);\r
+ }\r
+ PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, OFFSET_OF (PCI_TYPE01, Bridge.MemoryBase), 1, &Base);\r
+ PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, OFFSET_OF (PCI_TYPE01, Bridge.MemoryLimit), 1, &Limit);\r
+\r
PCI_DISABLE_COMMAND_REGISTER (Parent, EFI_PCI_COMMAND_MEMORY_SPACE);\r
}\r
\r
}\r
\r
/**\r
- Destory given resource tree.\r
+ Destroy given resource tree.\r
\r
@param Bridge PCI resource root node of resource tree.\r
\r
\r
//\r
// Memory Base/Limit Register 0\r
- // Bar 1 denodes memory range 0\r
+ // Bar 1 decodes memory range 0\r
//\r
Node = CreateResourceNode (\r
PciDev,\r
\r
//\r
// Memory Base/Limit Register 1\r
- // Bar 2 denodes memory range1\r
+ // Bar 2 decodes memory range1\r
//\r
Node = CreateResourceNode (\r
PciDev,\r
\r
//\r
// Io Base/Limit\r
- // Bar 3 denodes io range 0\r
+ // Bar 3 decodes io range 0\r
//\r
Node = CreateResourceNode (\r
PciDev,\r
\r
//\r
// Io Base/Limit\r
- // Bar 4 denodes io range 0\r
+ // Bar 4 decodes io range 0\r
//\r
Node = CreateResourceNode (\r
PciDev,\r
\r
} else {\r
//\r
- // Set pre-fetchable bit\r
+ // Set prefetchable bit\r
//\r
PciIo->Pci.Read (\r
PciIo,\r
} else {\r
\r
//\r
- // Set pre-fetchable bit\r
+ // Set prefetchable bit\r
//\r
PciIo->Pci.Read (\r
PciIo,\r
if (Ptr->AddrSpaceGranularity == 32) {\r
\r
//\r
- // prefechable\r
+ // prefetchable\r
//\r
if (Ptr->SpecificFlag == 0x6) {\r
if (Ptr->AddrLen != 0) {\r
}\r
\r
//\r
- // Non-prefechable\r
+ // Non-prefetchable\r
//\r
if (Ptr->SpecificFlag == 0) {\r
if (Ptr->AddrLen != 0) {\r
if (Ptr->AddrSpaceGranularity == 64) {\r
\r
//\r
- // prefechable\r
+ // prefetchable\r
//\r
if (Ptr->SpecificFlag == 0x6) {\r
if (Ptr->AddrLen != 0) {\r
}\r
\r
//\r
- // Non-prefechable\r
+ // Non-prefetchable\r
//\r
if (Ptr->SpecificFlag == 0) {\r
if (Ptr->AddrLen != 0) {\r