[edk2-devel] [PATCH] IntelSiliconPkg/VTd: Support Queued Invalidation Interface
Add queued invalidation interface support for VTd core driver. For software to invalidate the various caching structures, the architecture supports the following two types of invalidation interfaces. 1. Register-based invalidation interface 2. Queued invalidation interface. BIOS shall check VER_REG to determine if register based invalidation can be used. Only for Major Version 6 or lower can support register based invalidation. For any version newer than that should use queue invalidation interface instead. REF: https://bugzilla.tianocore.org/show_bug.cgi?id=3366 Signed-off-by: Sheng Wei Cc: Jenny Huang Cc: Jiewen Yao Cc: Ray Ni Cc: Rangasai V Chaganty Reviewed-by: Jenny Huang --- .../Feature/VTd/IntelVTdDmarPei/DmarTable.c| 2 + .../Feature/VTd/IntelVTdDmarPei/IntelVTdDmar.c | 560 + .../Feature/VTd/IntelVTdDmarPei/IntelVTdDmarPei.c | 15 + .../Feature/VTd/IntelVTdDmarPei/IntelVTdDmarPei.h | 19 + .../Feature/VTd/IntelVTdDmarPei/TranslationTable.c | 2 - .../Feature/VTd/IntelVTdDxe/DmaProtection.h| 29 ++ .../Feature/VTd/IntelVTdDxe/VtdReg.c | 315 +++- .../IntelSiliconPkg/Include/IndustryStandard/Vtd.h | 57 +++ 8 files changed, 876 insertions(+), 123 deletions(-) diff --git a/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDmarPei/DmarTable.c b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDmarPei/DmarTable.c index d188f917..2154690d 100644 --- a/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDmarPei/DmarTable.c +++ b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDmarPei/DmarTable.c @@ -561,6 +561,8 @@ ProcessDhrd ( DEBUG ((DEBUG_INFO," VTD BaseAddress - 0x%016lx\n", DmarDrhd->RegisterBaseAddress)); VTdUnitInfo->VtdUnitBaseAddress = (UINT32) DmarDrhd->RegisterBaseAddress; + VTdUnitInfo->EnableQueuedInvalidation = 0; + DEBUG ((DEBUG_INFO," VTD Segment - %d\n", DmarDrhd->SegmentNumber)); VTdUnitInfo->Segment = DmarDrhd->SegmentNumber; diff --git a/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDmarPei/IntelVTdDmar.c b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDmarPei/IntelVTdDmar.c index 9ad2a494..c3a939c9 100644 --- a/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDmarPei/IntelVTdDmar.c +++ b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDmarPei/IntelVTdDmar.c @@ -66,30 +66,269 @@ FlushWriteBuffer ( } /** - Invalidate VTd context cache. + Perpare cache invalidation interface. - @param[in] VtdUnitBaseAddressThe base address of the VTd engine. + @param[in] VTdUnitInfo The VTd engine unit information. + + @retval EFI_SUCCESS The operation was successful. + @retval EFI_UNSUPPORTED Invalidation method is not supported. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. **/ EFI_STATUS -InvalidateContextCache ( - IN UINTN VtdUnitBaseAddress +PerpareCacheInvalidationInterface ( + IN VTD_UNIT_INFO *VTdUnitInfo ) { - UINT64Reg64; + UINT16 QueueSize; + UINT64 Reg64; + UINT32 Reg32; + VTD_ECAP_REG ECapReg; + + + if (VTdUnitInfo->VerReg.Bits.Major <= 6) { +VTdUnitInfo->EnableQueuedInvalidation = 0; +DEBUG ((DEBUG_INFO, "Use Register-based Invalidation Interface for engine [0x%x]\n", VTdUnitInfo->VtdUnitBaseAddress)); +return EFI_SUCCESS; + } + + ECapReg.Uint64 = MmioRead64 ((UINTN)VTdUnitInfo->VtdUnitBaseAddress + R_ECAP_REG); + if (ECapReg.Bits.QI == 0) { +DEBUG ((DEBUG_ERROR, "Hardware does not support queued invalidations interface for engine [0x%x]\n", VTdUnitInfo->VtdUnitBaseAddress)); +return EFI_UNSUPPORTED; + } + + VTdUnitInfo->EnableQueuedInvalidation = 1; + DEBUG ((DEBUG_INFO, "Use Queued Invalidation Interface for engine [0x%x]\n", VTdUnitInfo->VtdUnitBaseAddress)); + + Reg32 = MmioRead32 ((UINTN)VTdUnitInfo->VtdUnitBaseAddress + R_GSTS_REG); + if ((Reg32 & B_GSTS_REG_QIES) != 0) { +DEBUG ((DEBUG_INFO,"Queued Invalidation Interface was enabled.\n")); +Reg32 &= (~B_GSTS_REG_QIES); +MmioWrite32 ((UINTN)VTdUnitInfo->VtdUnitBaseAddress + R_GCMD_REG, Reg32); +do { + Reg32 = MmioRead32 ((UINTN)VTdUnitInfo->VtdUnitBaseAddress + R_GSTS_REG); +} while ((Reg32 & B_GSTS_REG_QIES) != 0); +MmioWrite64 ((UINTN)VTdUnitInfo->VtdUnitBaseAddress + R_IQA_REG, 0); + +if (VTdUnitInfo->QiDesc != NULL) { + FreePages(VTdUnitInfo->QiDesc, EFI_SIZE_TO_PAGES(sizeof(QI_DESC) * VTdUnitInfo->QiDescLength)); + VTdUnitInfo->QiDesc = NULL; + VTdUnitInfo->QiDescLength = 0; +} + } + + // + // Initialize the Invalidation Queue Tail Register to zero. + // + MmioWrite64 ((UINTN)VTdUnitInfo->VtdUnitBaseAddress + R_IQT_REG, 0); + + // + // Setup the IQ address, size and descriptor width through the Invalidation Queue Address Register + // + QueueSize = 0; + VTdUnitInfo->QiDescLength = 1 << (QueueSize + 8); + VTdUnitInfo->QiDesc = (QI_DESC *) AllocatePages
Re: [edk2-devel] [PATCH] IntelSiliconPkg/VTd: Support queued invalidation interface
Reviewed by Jenny Huang. -Original Message- From: Sheng, W Sent: Thursday, April 29, 2021 11:55 PM To: devel@edk2.groups.io Cc: Huang, Jenny ; Yao, Jiewen ; Ni, Ray ; Chaganty, Rangasai V Subject: [PATCH] IntelSiliconPkg/VTd: Support queued invalidation interface Add queued invalidation interface support for VTd core driver. For software to invalidate the various caching structures, the architecture supports the following two types of invalidation interfaces. 1. Register-based invalidation interface 2. Queued invalidation interface. BIOS shall check VER_REG to determine if register based invalidation can be used. Only for Major Version 6 or lower can support register based invalidation. For any version newer than that should use queue invalidation interface instead. REF: https://bugzilla.tianocore.org/show_bug.cgi?id=3366 Signed-off-by: Sheng Wei Cc: Jenny Huang Cc: Jiewen Yao Cc: Ray Ni Cc: Rangasai V Chaganty --- .../Feature/VTd/IntelVTdDmarPei/DmarTable.c| 2 + .../Feature/VTd/IntelVTdDmarPei/IntelVTdDmar.c | 443 +++-- .../Feature/VTd/IntelVTdDmarPei/IntelVTdDmarPei.c | 15 + .../Feature/VTd/IntelVTdDmarPei/IntelVTdDmarPei.h | 19 + .../Feature/VTd/IntelVTdDmarPei/TranslationTable.c | 2 - .../Feature/VTd/IntelVTdDxe/DmaProtection.h| 29 ++ .../Feature/VTd/IntelVTdDxe/VtdReg.c | 313 +-- .../IntelSiliconPkg/Include/IndustryStandard/Vtd.h | 57 +++ 8 files changed, 813 insertions(+), 67 deletions(-) diff --git a/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDmarPei/DmarTable.c b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDmarPei/DmarTable.c index d188f917..2154690d 100644 --- a/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDmarPei/DmarTable.c +++ b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDmarPei/DmarTabl +++ e.c @@ -561,6 +561,8 @@ ProcessDhrd ( DEBUG ((DEBUG_INFO," VTD BaseAddress - 0x%016lx\n", DmarDrhd->RegisterBaseAddress)); VTdUnitInfo->VtdUnitBaseAddress = (UINT32) DmarDrhd->RegisterBaseAddress; + VTdUnitInfo->EnableQueuedInvalidation = 0; + DEBUG ((DEBUG_INFO," VTD Segment - %d\n", DmarDrhd->SegmentNumber)); VTdUnitInfo->Segment = DmarDrhd->SegmentNumber; diff --git a/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDmarPei/IntelVTdDmar.c b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDmarPei/IntelVTdDmar.c index 9ad2a494..f0bd7dc6 100644 --- a/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDmarPei/IntelVTdDmar.c +++ b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDmarPei/IntelVTd +++ Dmar.c @@ -66,30 +66,269 @@ FlushWriteBuffer ( } /** - Invalidate VTd context cache. + Perpare cache invalidation interface. - @param[in] VtdUnitBaseAddressThe base address of the VTd engine. + @param[in] VTdUnitInfo The VTd engine unit information. + + @retval EFI_SUCCESS The operation was successful. + @retval EFI_UNSUPPORTED Invalidation method is not supported. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. **/ EFI_STATUS -InvalidateContextCache ( - IN UINTN VtdUnitBaseAddress +PerpareCacheInvalidationInterface ( + IN VTD_UNIT_INFO *VTdUnitInfo ) { - UINT64Reg64; + UINT16 QueueSize; + UINT64 Reg64; + UINT32 Reg32; + VTD_ECAP_REG ECapReg; + + + if (VTdUnitInfo->VerReg.Bits.Major <= 6) { +VTdUnitInfo->EnableQueuedInvalidation = 0; +DEBUG ((DEBUG_INFO, "Use Register-based Invalidation Interface for engine [0x%x]\n", VTdUnitInfo->VtdUnitBaseAddress)); +return EFI_SUCCESS; + } + + ECapReg.Uint64 = MmioRead64 ((UINTN)VTdUnitInfo->VtdUnitBaseAddress + + R_ECAP_REG); if (ECapReg.Bits.QI == 0) { +DEBUG ((DEBUG_ERROR, "Hardware does not support queued invalidations interface for engine [0x%x]\n", VTdUnitInfo->VtdUnitBaseAddress)); +return EFI_UNSUPPORTED; + } + + VTdUnitInfo->EnableQueuedInvalidation = 1; DEBUG ((DEBUG_INFO, "Use + Queued Invalidation Interface for engine [0x%x]\n", + VTdUnitInfo->VtdUnitBaseAddress)); + + Reg32 = MmioRead32 ((UINTN)VTdUnitInfo->VtdUnitBaseAddress + + R_GSTS_REG); if ((Reg32 & B_GSTS_REG_QIES) != 0) { +DEBUG ((DEBUG_INFO,"Queued Invalidation Interface was enabled.\n")); +Reg32 &= (~B_GSTS_REG_QIES); +MmioWrite32 ((UINTN)VTdUnitInfo->VtdUnitBaseAddress + R_GCMD_REG, Reg32); +do { + Reg32 = MmioRead32 ((UINTN)VTdUnitInfo->VtdUnitBaseAddress + R_GSTS_REG); +} while ((Reg32 & B_GSTS_REG_QIES) != 0); +MmioWrite64 ((UINTN)VTdUnitInfo->VtdUnitBaseAddress + R_IQA_REG, + 0); + +if (VTdUnitInfo->QiDesc != NULL) { + FreePages(VTdUnitInfo->QiDesc, EFI_SIZE_TO_PAGES(sizeof(QI_DESC) * VTdUnitInfo->QiDescLength)); + VTdUnitInfo->QiDesc = NULL; + VTdUnitInfo->QiDescLength = 0; +} + } + + // + // Initialize the Invalidation Queue Tail Register to zero. + // + MmioWrite64
[edk2-devel] [PATCH] IntelSiliconPkg/VTd: Support queued invalidation interface
Add queued invalidation interface support for VTd core driver. For software to invalidate the various caching structures, the architecture supports the following two types of invalidation interfaces. 1. Register-based invalidation interface 2. Queued invalidation interface. BIOS shall check VER_REG to determine if register based invalidation can be used. Only for Major Version 6 or lower can support register based invalidation. For any version newer than that should use queue invalidation interface instead. REF: https://bugzilla.tianocore.org/show_bug.cgi?id=3366 Signed-off-by: Sheng Wei Cc: Jenny Huang Cc: Jiewen Yao Cc: Ray Ni Cc: Rangasai V Chaganty --- .../Feature/VTd/IntelVTdDmarPei/DmarTable.c| 2 + .../Feature/VTd/IntelVTdDmarPei/IntelVTdDmar.c | 443 +++-- .../Feature/VTd/IntelVTdDmarPei/IntelVTdDmarPei.c | 15 + .../Feature/VTd/IntelVTdDmarPei/IntelVTdDmarPei.h | 19 + .../Feature/VTd/IntelVTdDmarPei/TranslationTable.c | 2 - .../Feature/VTd/IntelVTdDxe/DmaProtection.h| 29 ++ .../Feature/VTd/IntelVTdDxe/VtdReg.c | 313 +-- .../IntelSiliconPkg/Include/IndustryStandard/Vtd.h | 57 +++ 8 files changed, 813 insertions(+), 67 deletions(-) diff --git a/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDmarPei/DmarTable.c b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDmarPei/DmarTable.c index d188f917..2154690d 100644 --- a/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDmarPei/DmarTable.c +++ b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDmarPei/DmarTable.c @@ -561,6 +561,8 @@ ProcessDhrd ( DEBUG ((DEBUG_INFO," VTD BaseAddress - 0x%016lx\n", DmarDrhd->RegisterBaseAddress)); VTdUnitInfo->VtdUnitBaseAddress = (UINT32) DmarDrhd->RegisterBaseAddress; + VTdUnitInfo->EnableQueuedInvalidation = 0; + DEBUG ((DEBUG_INFO," VTD Segment - %d\n", DmarDrhd->SegmentNumber)); VTdUnitInfo->Segment = DmarDrhd->SegmentNumber; diff --git a/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDmarPei/IntelVTdDmar.c b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDmarPei/IntelVTdDmar.c index 9ad2a494..f0bd7dc6 100644 --- a/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDmarPei/IntelVTdDmar.c +++ b/Silicon/Intel/IntelSiliconPkg/Feature/VTd/IntelVTdDmarPei/IntelVTdDmar.c @@ -66,30 +66,269 @@ FlushWriteBuffer ( } /** - Invalidate VTd context cache. + Perpare cache invalidation interface. - @param[in] VtdUnitBaseAddressThe base address of the VTd engine. + @param[in] VTdUnitInfo The VTd engine unit information. + + @retval EFI_SUCCESS The operation was successful. + @retval EFI_UNSUPPORTED Invalidation method is not supported. + @retval EFI_OUT_OF_RESOURCES A memory allocation failed. **/ EFI_STATUS -InvalidateContextCache ( - IN UINTN VtdUnitBaseAddress +PerpareCacheInvalidationInterface ( + IN VTD_UNIT_INFO *VTdUnitInfo ) { - UINT64Reg64; + UINT16 QueueSize; + UINT64 Reg64; + UINT32 Reg32; + VTD_ECAP_REG ECapReg; + + + if (VTdUnitInfo->VerReg.Bits.Major <= 6) { +VTdUnitInfo->EnableQueuedInvalidation = 0; +DEBUG ((DEBUG_INFO, "Use Register-based Invalidation Interface for engine [0x%x]\n", VTdUnitInfo->VtdUnitBaseAddress)); +return EFI_SUCCESS; + } + + ECapReg.Uint64 = MmioRead64 ((UINTN)VTdUnitInfo->VtdUnitBaseAddress + R_ECAP_REG); + if (ECapReg.Bits.QI == 0) { +DEBUG ((DEBUG_ERROR, "Hardware does not support queued invalidations interface for engine [0x%x]\n", VTdUnitInfo->VtdUnitBaseAddress)); +return EFI_UNSUPPORTED; + } + + VTdUnitInfo->EnableQueuedInvalidation = 1; + DEBUG ((DEBUG_INFO, "Use Queued Invalidation Interface for engine [0x%x]\n", VTdUnitInfo->VtdUnitBaseAddress)); + + Reg32 = MmioRead32 ((UINTN)VTdUnitInfo->VtdUnitBaseAddress + R_GSTS_REG); + if ((Reg32 & B_GSTS_REG_QIES) != 0) { +DEBUG ((DEBUG_INFO,"Queued Invalidation Interface was enabled.\n")); +Reg32 &= (~B_GSTS_REG_QIES); +MmioWrite32 ((UINTN)VTdUnitInfo->VtdUnitBaseAddress + R_GCMD_REG, Reg32); +do { + Reg32 = MmioRead32 ((UINTN)VTdUnitInfo->VtdUnitBaseAddress + R_GSTS_REG); +} while ((Reg32 & B_GSTS_REG_QIES) != 0); +MmioWrite64 ((UINTN)VTdUnitInfo->VtdUnitBaseAddress + R_IQA_REG, 0); + +if (VTdUnitInfo->QiDesc != NULL) { + FreePages(VTdUnitInfo->QiDesc, EFI_SIZE_TO_PAGES(sizeof(QI_DESC) * VTdUnitInfo->QiDescLength)); + VTdUnitInfo->QiDesc = NULL; + VTdUnitInfo->QiDescLength = 0; +} + } + + // + // Initialize the Invalidation Queue Tail Register to zero. + // + MmioWrite64 ((UINTN)VTdUnitInfo->VtdUnitBaseAddress + R_IQT_REG, 0); + + // + // Setup the IQ address, size and descriptor width through the Invalidation Queue Address Register + // + QueueSize = 0; + VTdUnitInfo->QiDescLength = 1 << (QueueSize + 8); + VTdUnitInfo->QiDesc = (QI_DESC *) AllocatePages (EFI_SIZE_TO_PAGES(sizeof(QI_DESC) *