MdeModulePkg/PciHostBridge: Add IOMMU support.

If IOMMU protocol is installed, PciHostBridge just calls
IOMMU AllocateBuffer/FreeBuffer/Map/Unmap.

PciHostBridge does not set IOMMU access attribute,
because it does not know which device request the DMA.
This work is done by PciBus driver.

Cc: Ruiyu Ni <ruiyu.ni@intel.com>
Cc: Leo Duran <leo.duran@amd.com>
Cc: Brijesh Singh <brijesh.singh@amd.com>
Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>

Previous patch Tested-by: Brijesh Singh <brijesh.singh@amd.com>
Previous patch Tested-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Jiewen Yao <jiewen.yao@intel.com>
Reviewed-by: Ruiyu Ni <ruiyu.ni@intel.com>
Reviewed-by: Leo Duran <leo.duran@amd.com>
This commit is contained in:
Jiewen Yao 2017-04-29 16:23:58 +08:00
parent d1fddc4533
commit c15da8eb35
4 changed files with 102 additions and 0 deletions

View File

@ -28,6 +28,10 @@ GLOBAL_REMOVE_IF_UNREFERENCED CHAR16 *mPciResourceTypeStr[] = {
L"I/O", L"Mem", L"PMem", L"Mem64", L"PMem64", L"Bus"
};
EDKII_IOMMU_PROTOCOL *mIoMmuProtocol;
EFI_EVENT mIoMmuEvent;
VOID *mIoMmuRegistration;
/**
Ensure the compatibility of an IO space descriptor with the IO aperture.
@ -312,6 +316,28 @@ FreeMemorySpaceMap:
return Status;
}
/**
Event notification that is fired when IOMMU protocol is installed.
@param Event The Event that is being processed.
@param Context Event Context.
**/
VOID
EFIAPI
IoMmuProtocolCallback (
IN EFI_EVENT Event,
IN VOID *Context
)
{
EFI_STATUS Status;
Status = gBS->LocateProtocol (&gEdkiiIoMmuProtocolGuid, NULL, (VOID **)&mIoMmuProtocol);
if (!EFI_ERROR(Status)) {
gBS->CloseEvent (mIoMmuEvent);
}
}
/**
Entry point of this driver.
@ -489,6 +515,17 @@ InitializePciHostBridge (
ASSERT_EFI_ERROR (Status);
}
PciHostBridgeFreeRootBridges (RootBridges, RootBridgeCount);
if (!EFI_ERROR (Status)) {
mIoMmuEvent = EfiCreateProtocolNotifyEvent (
&gEdkiiIoMmuProtocolGuid,
TPL_CALLBACK,
IoMmuProtocolCallback,
NULL,
&mIoMmuRegistration
);
}
return Status;
}

View File

@ -41,6 +41,7 @@
BaseMemoryLib
BaseLib
PciSegmentLib
UefiLib
PciHostBridgeLib
[Protocols]
@ -49,6 +50,7 @@
gEfiDevicePathProtocolGuid ## BY_START
gEfiPciRootBridgeIoProtocolGuid ## BY_START
gEfiPciHostBridgeResourceAllocationProtocolGuid ## BY_START
gEdkiiIoMmuProtocolGuid ## SOMETIMES_CONSUMES
[Depex]
gEfiCpuIo2ProtocolGuid AND

View File

@ -27,6 +27,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#include <Protocol/CpuIo2.h>
#include <Protocol/DevicePath.h>
#include <Protocol/PciRootBridgeIo.h>
#include <Protocol/IoMmu.h>
#include <Library/DebugLib.h>
#include <Library/DevicePathLib.h>
#include <Library/BaseMemoryLib.h>
@ -34,6 +35,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#include <Library/UefiBootServicesTableLib.h>
#include <Library/BaseLib.h>
#include <Library/PciSegmentLib.h>
#include <Library/UefiLib.h>
#include "PciHostResource.h"

View File

@ -17,6 +17,8 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
#include "PciRootBridge.h"
#include "PciHostResource.h"
extern EDKII_IOMMU_PROTOCOL *mIoMmuProtocol;
#define NO_MAPPING (VOID *) (UINTN) -1
//
@ -1072,6 +1074,26 @@ RootBridgeIoMap (
RootBridge = ROOT_BRIDGE_FROM_THIS (This);
if (mIoMmuProtocol != NULL) {
if (!RootBridge->DmaAbove4G) {
//
// Clear 64bit support
//
if (Operation > EfiPciOperationBusMasterCommonBuffer) {
Operation = (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_OPERATION) (Operation - EfiPciOperationBusMasterRead64);
}
}
Status = mIoMmuProtocol->Map (
mIoMmuProtocol,
Operation,
HostAddress,
NumberOfBytes,
DeviceAddress,
Mapping
);
return Status;
}
PhysicalAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) HostAddress;
if ((!RootBridge->DmaAbove4G ||
(Operation != EfiPciOperationBusMasterRead64 &&
@ -1194,8 +1216,18 @@ RootBridgeIoUnmap (
MAP_INFO *MapInfo;
LIST_ENTRY *Link;
PCI_ROOT_BRIDGE_INSTANCE *RootBridge;
EFI_STATUS Status;
if (mIoMmuProtocol != NULL) {
Status = mIoMmuProtocol->Unmap (
mIoMmuProtocol,
Mapping
);
return Status;
}
RootBridge = ROOT_BRIDGE_FROM_THIS (This);
//
// See if the Map() operation associated with this Unmap() required a mapping
// buffer. If a mapping buffer was not required, then this function simply
@ -1312,6 +1344,24 @@ RootBridgeIoAllocateBuffer (
RootBridge = ROOT_BRIDGE_FROM_THIS (This);
if (mIoMmuProtocol != NULL) {
if (!RootBridge->DmaAbove4G) {
//
// Clear DUAL_ADDRESS_CYCLE
//
Attributes &= ~EFI_PCI_ATTRIBUTE_DUAL_ADDRESS_CYCLE;
}
Status = mIoMmuProtocol->AllocateBuffer (
mIoMmuProtocol,
Type,
MemoryType,
Pages,
HostAddress,
Attributes
);
return Status;
}
AllocateType = AllocateAnyPages;
if (!RootBridge->DmaAbove4G ||
(Attributes & EFI_PCI_ATTRIBUTE_DUAL_ADDRESS_CYCLE) == 0) {
@ -1356,6 +1406,17 @@ RootBridgeIoFreeBuffer (
OUT VOID *HostAddress
)
{
EFI_STATUS Status;
if (mIoMmuProtocol != NULL) {
Status = mIoMmuProtocol->FreeBuffer (
mIoMmuProtocol,
Pages,
HostAddress
);
return Status;
}
return gBS->FreePages ((EFI_PHYSICAL_ADDRESS) (UINTN) HostAddress, Pages);
}