[edk2-devel] [PATCH] IntelSiliconPkg/VTd: Support Queued Invalidation Interface

2021-05-26 Thread Sheng Wei
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

2021-05-11 Thread Huang, Jenny
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

2021-04-30 Thread Sheng Wei
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) *