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
(Bridge->AllocationAttributes & EFI_PCI_HOST_BRIDGE_COMBINE_MEM_PMEM) != 0 ? L"CombineMemPMem " : L"",\r
(Bridge->AllocationAttributes & EFI_PCI_HOST_BRIDGE_MEM64_DECODE) != 0 ? L"Mem64Decode" : L""\r
));\r
- DEBUG ((EFI_D_INFO, " Bus: %lx - %lx\n", Bridge->Bus.Base, Bridge->Bus.Limit));\r
- DEBUG ((EFI_D_INFO, " Io: %lx - %lx\n", Bridge->Io.Base, Bridge->Io.Limit));\r
- DEBUG ((EFI_D_INFO, " Mem: %lx - %lx\n", Bridge->Mem.Base, Bridge->Mem.Limit));\r
- DEBUG ((EFI_D_INFO, " MemAbove4G: %lx - %lx\n", Bridge->MemAbove4G.Base, Bridge->MemAbove4G.Limit));\r
- DEBUG ((EFI_D_INFO, " PMem: %lx - %lx\n", Bridge->PMem.Base, Bridge->PMem.Limit));\r
- DEBUG ((EFI_D_INFO, " PMemAbove4G: %lx - %lx\n", Bridge->PMemAbove4G.Base, Bridge->PMemAbove4G.Limit));\r
+ DEBUG ((\r
+ EFI_D_INFO, " Bus: %lx - %lx Translation=%lx\n",\r
+ Bridge->Bus.Base, Bridge->Bus.Limit, Bridge->Bus.Translation\r
+ ));\r
+ //\r
+ // Translation for bus is not supported.\r
+ //\r
+ ASSERT (Bridge->Bus.Translation == 0);\r
+ if (Bridge->Bus.Translation != 0) {\r
+ return NULL;\r
+ }\r
+\r
+ DEBUG ((\r
+ DEBUG_INFO, " Io: %lx - %lx Translation=%lx\n",\r
+ Bridge->Io.Base, Bridge->Io.Limit, Bridge->Io.Translation\r
+ ));\r
+ DEBUG ((\r
+ DEBUG_INFO, " Mem: %lx - %lx Translation=%lx\n",\r
+ Bridge->Mem.Base, Bridge->Mem.Limit, Bridge->Mem.Translation\r
+ ));\r
+ DEBUG ((\r
+ DEBUG_INFO, " MemAbove4G: %lx - %lx Translation=%lx\n",\r
+ Bridge->MemAbove4G.Base, Bridge->MemAbove4G.Limit, Bridge->MemAbove4G.Translation\r
+ ));\r
+ DEBUG ((\r
+ DEBUG_INFO, " PMem: %lx - %lx Translation=%lx\n",\r
+ Bridge->PMem.Base, Bridge->PMem.Limit, Bridge->PMem.Translation\r
+ ));\r
+ DEBUG ((\r
+ DEBUG_INFO, " PMemAbove4G: %lx - %lx Translation=%lx\n",\r
+ Bridge->PMemAbove4G.Base, Bridge->PMemAbove4G.Limit, Bridge->PMemAbove4G.Translation\r
+ ));\r
\r
//\r
// Make sure Mem and MemAbove4G apertures are valid\r
}\r
RootBridge->ResAllocNode[Index].Type = Index;\r
if (Bridge->ResourceAssigned && (Aperture->Limit >= Aperture->Base)) {\r
- RootBridge->ResAllocNode[Index].Base = Aperture->Base;\r
+ //\r
+ // Base in ResAllocNode is a host address, while Base in Aperture is a\r
+ // device address.\r
+ //\r
+ RootBridge->ResAllocNode[Index].Base = TO_HOST_ADDRESS (Aperture->Base,\r
+ Aperture->Translation);\r
RootBridge->ResAllocNode[Index].Length = Aperture->Limit - Aperture->Base + 1;\r
RootBridge->ResAllocNode[Index].Status = ResAllocated;\r
} else {\r
return EFI_SUCCESS;\r
}\r
\r
+/**\r
+ Use address to match apertures of memory type and then get the corresponding\r
+ translation.\r
+\r
+ @param RootBridge The root bridge instance.\r
+ @param Address The address used to match aperture.\r
+ @param Translation Pointer containing the output translation.\r
+\r
+ @return EFI_SUCCESS Get translation successfully.\r
+ @return EFI_INVALID_PARAMETER No matched memory aperture; the input Address\r
+ must be invalid.\r
+**/\r
+EFI_STATUS\r
+RootBridgeIoGetMemTranslationByAddress (\r
+ IN PCI_ROOT_BRIDGE_INSTANCE *RootBridge,\r
+ IN UINT64 Address,\r
+ IN OUT UINT64 *Translation\r
+ )\r
+{\r
+ if (Address >= RootBridge->Mem.Base && Address <= RootBridge->Mem.Limit) {\r
+ *Translation = RootBridge->Mem.Translation;\r
+ } else if (Address >= RootBridge->PMem.Base && Address <= RootBridge->PMem.Limit) {\r
+ *Translation = RootBridge->PMem.Translation;\r
+ } else if (Address >= RootBridge->MemAbove4G.Base && Address <= RootBridge->MemAbove4G.Limit) {\r
+ *Translation = RootBridge->MemAbove4G.Translation;\r
+ } else if (Address >= RootBridge->PMemAbove4G.Base && Address <= RootBridge->PMemAbove4G.Limit) {\r
+ *Translation = RootBridge->PMemAbove4G.Translation;\r
+ } else {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
/**\r
Polls an address in memory mapped I/O space until an exit condition is met,\r
or a timeout occurs.\r
)\r
{\r
EFI_STATUS Status;\r
+ PCI_ROOT_BRIDGE_INSTANCE *RootBridge;\r
+ UINT64 Translation;\r
\r
Status = RootBridgeIoCheckParameter (This, MemOperation, Width, Address,\r
Count, Buffer);\r
if (EFI_ERROR (Status)) {\r
return Status;\r
}\r
- return mCpuIo->Mem.Read (mCpuIo, (EFI_CPU_IO_PROTOCOL_WIDTH) Width, Address, Count, Buffer);\r
+\r
+ RootBridge = ROOT_BRIDGE_FROM_THIS (This);\r
+ Status = RootBridgeIoGetMemTranslationByAddress (RootBridge, Address, &Translation);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ // Address passed to CpuIo->Mem.Read needs to be a host address instead of\r
+ // device address.\r
+ return mCpuIo->Mem.Read (mCpuIo, (EFI_CPU_IO_PROTOCOL_WIDTH) Width,\r
+ TO_HOST_ADDRESS (Address, Translation), Count, Buffer);\r
}\r
\r
/**\r
)\r
{\r
EFI_STATUS Status;\r
+ PCI_ROOT_BRIDGE_INSTANCE *RootBridge;\r
+ UINT64 Translation;\r
\r
Status = RootBridgeIoCheckParameter (This, MemOperation, Width, Address,\r
Count, Buffer);\r
if (EFI_ERROR (Status)) {\r
return Status;\r
}\r
- return mCpuIo->Mem.Write (mCpuIo, (EFI_CPU_IO_PROTOCOL_WIDTH) Width, Address, Count, Buffer);\r
+\r
+ RootBridge = ROOT_BRIDGE_FROM_THIS (This);\r
+ Status = RootBridgeIoGetMemTranslationByAddress (RootBridge, Address, &Translation);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ // Address passed to CpuIo->Mem.Write needs to be a host address instead of\r
+ // device address.\r
+ return mCpuIo->Mem.Write (mCpuIo, (EFI_CPU_IO_PROTOCOL_WIDTH) Width,\r
+ TO_HOST_ADDRESS (Address, Translation), Count, Buffer);\r
}\r
\r
/**\r
)\r
{\r
EFI_STATUS Status;\r
+ PCI_ROOT_BRIDGE_INSTANCE *RootBridge;\r
+\r
Status = RootBridgeIoCheckParameter (\r
This, IoOperation, Width,\r
Address, Count, Buffer\r
if (EFI_ERROR (Status)) {\r
return Status;\r
}\r
- return mCpuIo->Io.Read (mCpuIo, (EFI_CPU_IO_PROTOCOL_WIDTH) Width, Address, Count, Buffer);\r
+\r
+ RootBridge = ROOT_BRIDGE_FROM_THIS (This);\r
+\r
+ // Address passed to CpuIo->Io.Read needs to be a host address instead of\r
+ // device address.\r
+ return mCpuIo->Io.Read (mCpuIo, (EFI_CPU_IO_PROTOCOL_WIDTH) Width,\r
+ TO_HOST_ADDRESS (Address, RootBridge->Io.Translation), Count, Buffer);\r
}\r
\r
/**\r
)\r
{\r
EFI_STATUS Status;\r
+ PCI_ROOT_BRIDGE_INSTANCE *RootBridge;\r
+\r
Status = RootBridgeIoCheckParameter (\r
This, IoOperation, Width,\r
Address, Count, Buffer\r
if (EFI_ERROR (Status)) {\r
return Status;\r
}\r
- return mCpuIo->Io.Write (mCpuIo, (EFI_CPU_IO_PROTOCOL_WIDTH) Width, Address, Count, Buffer);\r
+\r
+ RootBridge = ROOT_BRIDGE_FROM_THIS (This);\r
+\r
+ // Address passed to CpuIo->Io.Write needs to be a host address instead of\r
+ // device address.\r
+ return mCpuIo->Io.Write (mCpuIo, (EFI_CPU_IO_PROTOCOL_WIDTH) Width,\r
+ TO_HOST_ADDRESS (Address, RootBridge->Io.Translation), Count, Buffer);\r
}\r
\r
/**\r
\r
Descriptor->Desc = ACPI_ADDRESS_SPACE_DESCRIPTOR;\r
Descriptor->Len = sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) - 3;\r
+ // According to UEFI 2.7, RootBridgeIo->Configuration should return address\r
+ // range in CPU view (host address), and ResAllocNode->Base is already a CPU\r
+ // view address (host address).\r
Descriptor->AddrRangeMin = ResAllocNode->Base;\r
Descriptor->AddrRangeMax = ResAllocNode->Base + ResAllocNode->Length - 1;\r
Descriptor->AddrLen = ResAllocNode->Length;\r
+ Descriptor->AddrTranslationOffset = GetTranslationByResourceType (\r
+ RootBridge,\r
+ ResAllocNode->Type\r
+ );\r
+\r
switch (ResAllocNode->Type) {\r
\r
case TypeIo:\r