EFI_EVENT mIoMmuEvent;\r
VOID *mIoMmuRegistration;\r
\r
+/**\r
+ This routine gets translation offset from a root bridge instance by resource type.\r
+\r
+ @param RootBridge The Root Bridge Instance for the resources.\r
+ @param ResourceType The Resource Type of the translation offset.\r
+\r
+ @retval The Translation Offset of the specified resource.\r
+**/\r
+UINT64\r
+GetTranslationByResourceType (\r
+ IN PCI_ROOT_BRIDGE_INSTANCE *RootBridge,\r
+ IN PCI_RESOURCE_TYPE ResourceType\r
+ )\r
+{\r
+ switch (ResourceType) {\r
+ case TypeIo:\r
+ return RootBridge->Io.Translation;\r
+ case TypeMem32:\r
+ return RootBridge->Mem.Translation;\r
+ case TypePMem32:\r
+ return RootBridge->PMem.Translation;\r
+ case TypeMem64:\r
+ return RootBridge->MemAbove4G.Translation;\r
+ case TypePMem64:\r
+ return RootBridge->PMemAbove4G.Translation;\r
+ case TypeBus:\r
+ return RootBridge->Bus.Translation;\r
+ default:\r
+ ASSERT (FALSE);\r
+ return 0;\r
+ }\r
+}\r
+\r
/**\r
Ensure the compatibility of an IO space descriptor with the IO aperture.\r
\r
UINTN MemApertureIndex;\r
BOOLEAN ResourceAssigned;\r
LIST_ENTRY *Link;\r
+ UINT64 HostAddress;\r
\r
RootBridges = PciHostBridgeGetRootBridges (&RootBridgeCount);\r
if ((RootBridges == NULL) || (RootBridgeCount == 0)) {\r
}\r
\r
if (RootBridges[Index].Io.Base <= RootBridges[Index].Io.Limit) {\r
+ //\r
+ // Base and Limit in PCI_ROOT_BRIDGE_APERTURE are device address.\r
+ // For GCD resource manipulation, we need to use host address.\r
+ //\r
+ HostAddress = TO_HOST_ADDRESS (RootBridges[Index].Io.Base,\r
+ RootBridges[Index].Io.Translation);\r
+\r
Status = AddIoSpace (\r
- RootBridges[Index].Io.Base,\r
+ HostAddress,\r
RootBridges[Index].Io.Limit - RootBridges[Index].Io.Base + 1\r
);\r
ASSERT_EFI_ERROR (Status);\r
EfiGcdIoTypeIo,\r
0,\r
RootBridges[Index].Io.Limit - RootBridges[Index].Io.Base + 1,\r
- &RootBridges[Index].Io.Base,\r
+ &HostAddress,\r
gImageHandle,\r
NULL\r
);\r
\r
for (MemApertureIndex = 0; MemApertureIndex < ARRAY_SIZE (MemApertures); MemApertureIndex++) {\r
if (MemApertures[MemApertureIndex]->Base <= MemApertures[MemApertureIndex]->Limit) {\r
+ //\r
+ // Base and Limit in PCI_ROOT_BRIDGE_APERTURE are device address.\r
+ // For GCD resource manipulation, we need to use host address.\r
+ //\r
+ HostAddress = TO_HOST_ADDRESS (MemApertures[MemApertureIndex]->Base,\r
+ MemApertures[MemApertureIndex]->Translation);\r
Status = AddMemoryMappedIoSpace (\r
- MemApertures[MemApertureIndex]->Base,\r
+ HostAddress,\r
MemApertures[MemApertureIndex]->Limit - MemApertures[MemApertureIndex]->Base + 1,\r
EFI_MEMORY_UC\r
);\r
ASSERT_EFI_ERROR (Status);\r
Status = gDS->SetMemorySpaceAttributes (\r
- MemApertures[MemApertureIndex]->Base,\r
+ HostAddress,\r
MemApertures[MemApertureIndex]->Limit - MemApertures[MemApertureIndex]->Base + 1,\r
EFI_MEMORY_UC\r
);\r
EfiGcdMemoryTypeMemoryMappedIo,\r
0,\r
MemApertures[MemApertureIndex]->Limit - MemApertures[MemApertureIndex]->Base + 1,\r
- &MemApertures[MemApertureIndex]->Base,\r
+ &HostAddress,\r
gImageHandle,\r
NULL\r
);\r
if (BaseAddress < Limit) {\r
//\r
// Have to make sure Aligment is handled since we are doing direct address allocation\r
+ // Strictly speaking, alignment requirement should be applied to device\r
+ // address instead of host address which is used in GCD manipulation below,\r
+ // but as we restrict the alignment of Translation to be larger than any BAR\r
+ // alignment in the root bridge, we can simplify the situation and consider\r
+ // the same alignment requirement is also applied to host address.\r
//\r
BaseAddress = ALIGN_VALUE (BaseAddress, LShiftU64 (1, BitsOfAlignment));\r
\r
PCI_RESOURCE_TYPE Index2;\r
BOOLEAN ResNodeHandled[TypeMax];\r
UINT64 MaxAlignment;\r
+ UINT64 Translation;\r
\r
HostBridge = PCI_HOST_BRIDGE_FROM_THIS (This);\r
\r
BitsOfAlignment = LowBitSet64 (Alignment + 1);\r
BaseAddress = MAX_UINT64;\r
\r
+ //\r
+ // RESTRICTION: To simplify the situation, we require the alignment of\r
+ // Translation must be larger than any BAR alignment in the same root\r
+ // bridge, so that resource allocation alignment can be applied to\r
+ // both device address and host address.\r
+ //\r
+ Translation = GetTranslationByResourceType (RootBridge, Index);\r
+ if ((Translation & Alignment) != 0) {\r
+ DEBUG ((DEBUG_ERROR, "[%a:%d] Translation %lx is not aligned to %lx!\n",\r
+ __FUNCTION__, __LINE__, Translation, Alignment\r
+ ));\r
+ ASSERT ((Translation & Alignment) == 0);\r
+ //\r
+ // This may be caused by too large alignment or too small\r
+ // Translation; pick the 1st possibility and return out of resource,\r
+ // which can also go thru the same process for out of resource\r
+ // outside the loop.\r
+ //\r
+ ReturnStatus = EFI_OUT_OF_RESOURCES;\r
+ continue;\r
+ }\r
+\r
switch (Index) {\r
case TypeIo:\r
+ //\r
+ // Base and Limit in PCI_ROOT_BRIDGE_APERTURE are device address.\r
+ // For AllocateResource is manipulating GCD resource, we need to use\r
+ // host address here.\r
+ //\r
BaseAddress = AllocateResource (\r
FALSE,\r
RootBridge->ResAllocNode[Index].Length,\r
MIN (15, BitsOfAlignment),\r
- ALIGN_VALUE (RootBridge->Io.Base, Alignment + 1),\r
- RootBridge->Io.Limit\r
+ TO_HOST_ADDRESS (ALIGN_VALUE (RootBridge->Io.Base, Alignment + 1),\r
+ RootBridge->Io.Translation),\r
+ TO_HOST_ADDRESS (RootBridge->Io.Limit,\r
+ RootBridge->Io.Translation)\r
);\r
break;\r
\r
TRUE,\r
RootBridge->ResAllocNode[Index].Length,\r
MIN (63, BitsOfAlignment),\r
- ALIGN_VALUE (RootBridge->MemAbove4G.Base, Alignment + 1),\r
- RootBridge->MemAbove4G.Limit\r
+ TO_HOST_ADDRESS (ALIGN_VALUE (RootBridge->MemAbove4G.Base, Alignment + 1),\r
+ RootBridge->MemAbove4G.Translation),\r
+ TO_HOST_ADDRESS (RootBridge->MemAbove4G.Limit,\r
+ RootBridge->MemAbove4G.Translation)\r
);\r
if (BaseAddress != MAX_UINT64) {\r
break;\r
TRUE,\r
RootBridge->ResAllocNode[Index].Length,\r
MIN (31, BitsOfAlignment),\r
- ALIGN_VALUE (RootBridge->Mem.Base, Alignment + 1),\r
- RootBridge->Mem.Limit\r
+ TO_HOST_ADDRESS (ALIGN_VALUE (RootBridge->Mem.Base, Alignment + 1),\r
+ RootBridge->Mem.Translation),\r
+ TO_HOST_ADDRESS (RootBridge->Mem.Limit,\r
+ RootBridge->Mem.Translation)\r
);\r
break;\r
\r
TRUE,\r
RootBridge->ResAllocNode[Index].Length,\r
MIN (63, BitsOfAlignment),\r
- ALIGN_VALUE (RootBridge->PMemAbove4G.Base, Alignment + 1),\r
- RootBridge->PMemAbove4G.Limit\r
+ TO_HOST_ADDRESS (ALIGN_VALUE (RootBridge->PMemAbove4G.Base, Alignment + 1),\r
+ RootBridge->PMemAbove4G.Translation),\r
+ TO_HOST_ADDRESS (RootBridge->PMemAbove4G.Limit,\r
+ RootBridge->PMemAbove4G.Translation)\r
);\r
if (BaseAddress != MAX_UINT64) {\r
break;\r
TRUE,\r
RootBridge->ResAllocNode[Index].Length,\r
MIN (31, BitsOfAlignment),\r
- ALIGN_VALUE (RootBridge->PMem.Base, Alignment + 1),\r
- RootBridge->PMem.Limit\r
+ TO_HOST_ADDRESS (ALIGN_VALUE (RootBridge->PMem.Base, Alignment + 1),\r
+ RootBridge->PMem.Translation),\r
+ TO_HOST_ADDRESS (RootBridge->PMem.Limit,\r
+ RootBridge->PMem.Translation)\r
);\r
break;\r
\r
Descriptor->Desc = ACPI_ADDRESS_SPACE_DESCRIPTOR;\r
Descriptor->Len = sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) - 3;;\r
Descriptor->GenFlag = 0;\r
- Descriptor->AddrRangeMin = RootBridge->ResAllocNode[Index].Base;\r
+ //\r
+ // AddrRangeMin in Resource Descriptor here should be device address\r
+ // instead of host address, or else PCI bus driver cannot set correct\r
+ // address into PCI BAR registers.\r
+ // Base in ResAllocNode is a host address, so conversion is needed.\r
+ //\r
+ Descriptor->AddrRangeMin = TO_DEVICE_ADDRESS (RootBridge->ResAllocNode[Index].Base,\r
+ GetTranslationByResourceType (RootBridge, Index));\r
Descriptor->AddrRangeMax = 0;\r
Descriptor->AddrTranslationOffset = (ResStatus == ResAllocated) ? EFI_RESOURCE_SATISFIED : PCI_RESOURCE_LESS;\r
Descriptor->AddrLen = RootBridge->ResAllocNode[Index].Length;\r