\r
Provides the basic interfaces to abstract a PCI Host Bridge Resource Allocation.\r
\r
-Copyright (c) 1999 - 2016, 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) 1999 - 2018, Intel Corporation. All rights reserved.<BR>\r
+SPDX-License-Identifier: BSD-2-Clause-Patent\r
\r
**/\r
\r
#include "PciRootBridge.h"\r
#include "PciHostResource.h"\r
\r
-\r
-EFI_METRONOME_ARCH_PROTOCOL *mMetronome;\r
EFI_CPU_IO2_PROTOCOL *mCpuIo;\r
\r
GLOBAL_REMOVE_IF_UNREFERENCED CHAR16 *mAcpiAddressSpaceTypeStr[] = {\r
L"I/O", L"Mem", L"PMem", L"Mem64", L"PMem64", L"Bus"\r
};\r
\r
+EDKII_IOMMU_PROTOCOL *mIoMmu;\r
+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
return Status;\r
}\r
\r
+/**\r
+ Event notification that is fired when IOMMU protocol is installed.\r
+\r
+ @param Event The Event that is being processed.\r
+ @param Context Event Context.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+IoMmuProtocolCallback (\r
+ IN EFI_EVENT Event,\r
+ IN VOID *Context\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ Status = gBS->LocateProtocol (&gEdkiiIoMmuProtocolGuid, NULL, (VOID **)&mIoMmu);\r
+ if (!EFI_ERROR(Status)) {\r
+ gBS->CloseEvent (mIoMmuEvent);\r
+ }\r
+}\r
+\r
/**\r
\r
Entry point of this driver.\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
return EFI_UNSUPPORTED;\r
}\r
\r
- Status = gBS->LocateProtocol (&gEfiMetronomeArchProtocolGuid, NULL, (VOID **) &mMetronome);\r
- ASSERT_EFI_ERROR (Status);\r
Status = gBS->LocateProtocol (&gEfiCpuIo2ProtocolGuid, NULL, (VOID **) &mCpuIo);\r
ASSERT_EFI_ERROR (Status);\r
\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
MemApertures[2] = &RootBridges[Index].PMem;\r
MemApertures[3] = &RootBridges[Index].PMemAbove4G;\r
\r
- for (MemApertureIndex = 0; MemApertureIndex < sizeof (MemApertures) / sizeof (MemApertures[0]); MemApertureIndex++) {\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
ASSERT_EFI_ERROR (Status);\r
}\r
PciHostBridgeFreeRootBridges (RootBridges, RootBridgeCount);\r
+\r
+ if (!EFI_ERROR (Status)) {\r
+ mIoMmuEvent = EfiCreateProtocolNotifyEvent (\r
+ &gEdkiiIoMmuProtocolGuid,\r
+ TPL_CALLBACK,\r
+ IoMmuProtocolCallback,\r
+ NULL,\r
+ &mIoMmuRegistration\r
+ );\r
+ }\r
+\r
return Status;\r
}\r
\r
Descriptor->Len = sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) - 3;\r
Descriptor->AddrRangeMin = ResAllocNode->Base;\r
Descriptor->AddrRangeMax = ResAllocNode->Alignment;\r
- Descriptor->AddrLen = ResAllocNode->Length;\r
+ Descriptor->AddrLen = ResAllocNode->Length;\r
+ Descriptor->SpecificFlag = 0;\r
switch (ResAllocNode->Type) {\r
\r
case TypeIo:\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